public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/7] ELF: Omit section header on ELF objects
@ 2020-03-10  0:12 H.J. Lu
  2020-03-10  0:12 ` [PATCH 1/7] ELF: Omit section header in " H.J. Lu
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: H.J. Lu @ 2020-03-10  0:12 UTC (permalink / raw)
  To: binutils

Section header isn't mandatory on ELF executable nor shared library.
This patch adds a new linker option, -z nosectionheader, to omit ELF
section header when building an executable or shared library, an
objcopy and strip option, --remove-section-header, to remove ELF
section header from an executable or shared library.

When there is no section header in an executable or shared library, we
reconstruct dynamic symbol table from the PT_DYNAMIC segment, which
contains DT_HASH/DT_GNU_HASH/DT_MIPS_XHASH, DT_STRTAB, DT_SYMTAB,
DT_STRSZ and DT_SYMENT entries, to improve nm and objdump.

H.J. Lu (5):
  bfd: Improve nm and objdump without section header
  readelf: Compute dynamic symbol table size from hash table
  binutils: Add --remove-section-header tests
  ld: Add tests for -z nosectionheader and --remove-section-header
  ld: Add -z nosectionheader test to bootstrap.exp

Kaylee Blake (2):
  ELF: Omit section header in ELF objects
  ld: Add a simple test for -z nosectionheader

 bfd/bfd-in2.h                                 |   8 +-
 bfd/bfd.c                                     |   8 +-
 bfd/elf-bfd.h                                 |  10 +
 bfd/elf.c                                     | 497 ++++++++++++++++++
 bfd/elfcode.h                                 |  83 ++-
 bfd/elflink.c                                 |  12 +
 bfd/elfxx-target.h                            |   6 +-
 binutils/NEWS                                 |   3 +
 binutils/doc/binutils.texi                    |  12 +
 binutils/objcopy.c                            |  54 +-
 binutils/readelf.c                            | 226 ++++----
 binutils/testsuite/binutils-all/objcopy.exp   |  13 +
 .../testsuite/binutils-all/remove-header-1.d  |   8 +
 ld/NEWS                                       |   3 +
 ld/emultempl/elf.em                           |   4 +
 ld/ld.h                                       |   3 +
 ld/ld.texi                                    |   6 +
 ld/ldlang.c                                   |   4 +
 ld/lexsup.c                                   |  12 +
 ld/testsuite/ld-bootstrap/bootstrap.exp       |  10 +-
 ld/testsuite/ld-elf/hash.d                    |   8 +-
 ld/testsuite/ld-elf/no-section-header.exp     | 374 +++++++++++++
 ld/testsuite/ld-elf/nosectionheader.d         |  12 +
 ld/testsuite/ld-elf/pr13195.d                 |   2 +-
 ld/testsuite/ld-elf/pr25617-1-no-sec-hdr.nd   |   3 +
 ld/testsuite/ld-elf/pr25617-1-no-sec-hdr.rd   |  20 +
 .../ld-elf/pr25617-1-static-no-sec-hdr.rd     |  12 +
 ld/testsuite/ld-elf/pr25617-1a-no-sec-hdr.nd  |   3 +
 ld/testsuite/ld-elf/pr25617-1a-no-sec-hdr.rd  |  20 +
 ld/testsuite/ld-elf/pr25617-1a-sec-hdr.rd     |  19 +
 ld/testsuite/ld-elf/pr25617-1a.c              |  11 +
 ld/testsuite/ld-elf/pr25617-1b.c              |  15 +
 ld/testsuite/ld-elf/start-noheader.rd         |  11 +
 .../ld-elf/start-shared-noheader-gnu.rd       |  22 +
 .../ld-elf/start-shared-noheader-sysv.rd      |  22 +
 ld/testsuite/ld-elf/start-shared-noheader.nd  |   5 +
 ld/testsuite/ld-elfvsb/hidden2.d              |   2 +-
 ld/testsuite/ld-mips-elf/hash2.d              |   8 +-
 38 files changed, 1406 insertions(+), 145 deletions(-)
 create mode 100644 binutils/testsuite/binutils-all/remove-header-1.d
 create mode 100644 ld/testsuite/ld-elf/no-section-header.exp
 create mode 100644 ld/testsuite/ld-elf/nosectionheader.d
 create mode 100644 ld/testsuite/ld-elf/pr25617-1-no-sec-hdr.nd
 create mode 100644 ld/testsuite/ld-elf/pr25617-1-no-sec-hdr.rd
 create mode 100644 ld/testsuite/ld-elf/pr25617-1-static-no-sec-hdr.rd
 create mode 100644 ld/testsuite/ld-elf/pr25617-1a-no-sec-hdr.nd
 create mode 100644 ld/testsuite/ld-elf/pr25617-1a-no-sec-hdr.rd
 create mode 100644 ld/testsuite/ld-elf/pr25617-1a-sec-hdr.rd
 create mode 100644 ld/testsuite/ld-elf/pr25617-1a.c
 create mode 100644 ld/testsuite/ld-elf/pr25617-1b.c
 create mode 100644 ld/testsuite/ld-elf/start-noheader.rd
 create mode 100644 ld/testsuite/ld-elf/start-shared-noheader-gnu.rd
 create mode 100644 ld/testsuite/ld-elf/start-shared-noheader-sysv.rd
 create mode 100644 ld/testsuite/ld-elf/start-shared-noheader.nd

-- 
2.24.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/7] ELF: Omit section header in ELF objects
  2020-03-10  0:12 [PATCH 0/7] ELF: Omit section header on ELF objects H.J. Lu
@ 2020-03-10  0:12 ` H.J. Lu
  2020-03-10  0:12 ` [PATCH 1/7] ELF: Omit section header on " H.J. Lu
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: H.J. Lu @ 2020-03-10  0:12 UTC (permalink / raw)
  To: binutils; +Cc: Kaylee Blake

From: Kaylee Blake <klkblake@gmail.com>

Section header isn't mandatory on ELF executable nor shared library.
This patch adds a new linker option, -z nosectionheader, to omit ELF
section header when building an executable or shared library, an
objcopy and strip option, --remove-section-header, to remove ELF
section header from an executable or shared library.

bfd/

2020-03-XX  H.J. Lu  <hongjiu.lu@intel.com>
	    Kaylee Blake  <klkblake@gmail.com>

	PR ld/25617
	* bfd.c (BFD_NO_SECTION_HEADER): New.
	(BFD_FLAGS_SAVED): Add BFD_NO_SECTION_HEADER.
	(BFD_FLAGS_FOR_BFD_USE_MASK): Likewise.
	* elfcode.h (elf_swap_ehdr_out): Omit section header on
	non-relocatable output with BFD_NO_SECTION_HEADER.
	(elf_write_shdrs_and_ehdr): Likewise.
	* elfxx-target.h (TARGET_BIG_SYM): Add BFD_NO_SECTION_HEADER
	to object_flags.
	(TARGET_LITTLE_SYM): Likewise.
	* bfd-in2.h: Regenerated.

binutils/

2020-03-XX  H.J. Lu  <hongjiu.lu@intel.com>

	PR ld/25617
	* NEWS: Mention --remove-section-header for objcopy and strip.
	* doc/binutils.texi: Document --remove-section-header for objcopy
	and strip.
	* objcopy.c (remove_section_header): New.
	(command_line_switch): Add OPTION_REMOVE_SECTION_HEADER.
	(strip_options): Add --remove-section-header.
	(copy_options): Likewise.
	(copy_usage): Add --remove-section-header.
	(strip_usage): Likewise.
	(copy_object): Renamed to ...
	(copy_object_1): This.  Issue a warning for
	--remove-section-header on non-ELF targets.
	(copy_object): New.
	(strip_main): Handle OPTION_REMOVE_SECTION_HEADER.
	(copy_main): Likewise.

ld/

2020-03-XX  H.J. Lu  <hongjiu.lu@intel.com>
	    Kaylee Blake  <klkblake@gmail.com>

	PR ld/25617
	* NEWS: Mention -z nosectionheader.
	* emultempl/elf.em: Support -z sectionheader and
	-z nosectionheader.
	* ld.h (ld_config_type): Add no_section_header.
	* ld.texi: Document -z sectionheader and -z nosectionheader.
	* ldlang.c (ldlang_open_output): Handle
	config.no_section_header.
	* lexsup.c (parse_args): Disallow -z nosectionheader with -r.
	(elf_static_list_options): Add -z sectionheader and
	-z nosectionheader.
---
 bfd/bfd-in2.h              |  8 ++++--
 bfd/bfd.c                  |  8 ++++--
 bfd/elfcode.h              | 41 ++++++++++++++++++++++-------
 bfd/elfxx-target.h         |  6 +++--
 binutils/NEWS              |  3 +++
 binutils/doc/binutils.texi | 12 +++++++++
 binutils/objcopy.c         | 54 ++++++++++++++++++++++++++++++++++++--
 ld/NEWS                    |  3 +++
 ld/emultempl/elf.em        |  4 +++
 ld/ld.h                    |  3 +++
 ld/ld.texi                 |  6 +++++
 ld/ldlang.c                |  4 +++
 ld/lexsup.c                | 12 +++++++++
 13 files changed, 146 insertions(+), 18 deletions(-)

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 37114607b5..d81d0e20dd 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -6588,17 +6588,21 @@ struct bfd
   /* Put pathnames into archives (non-POSIX).  */
 #define BFD_ARCHIVE_FULL_PATH  0x100000
 
+  /* Don't generate ELF section header.  */
+#define BFD_NO_SECTION_HEADER  0x200000
+
   /* Flags bits to be saved in bfd_preserve_save.  */
 #define BFD_FLAGS_SAVED \
   (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
    | BFD_PLUGIN | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON \
-   | BFD_USE_ELF_STT_COMMON)
+   | BFD_USE_ELF_STT_COMMON | BFD_NO_SECTION_HEADER)
 
   /* Flags bits which are for BFD use only.  */
 #define BFD_FLAGS_FOR_BFD_USE_MASK \
   (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
    | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT \
-   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON)
+   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON \
+   | BFD_NO_SECTION_HEADER)
 
   /* The format which belongs to the BFD. (object, core, etc.)  */
   ENUM_BITFIELD (bfd_format) format : 3;
diff --git a/bfd/bfd.c b/bfd/bfd.c
index 1c1238c036..366e662592 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -176,17 +176,21 @@ CODE_FRAGMENT
 .  {* Put pathnames into archives (non-POSIX).  *}
 .#define BFD_ARCHIVE_FULL_PATH  0x100000
 .
+.  {* Don't generate ELF section header.  *}
+.#define BFD_NO_SECTION_HEADER	0x200000
+.
 .  {* Flags bits to be saved in bfd_preserve_save.  *}
 .#define BFD_FLAGS_SAVED \
 .  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
 .   | BFD_PLUGIN | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON \
-.   | BFD_USE_ELF_STT_COMMON)
+.   | BFD_USE_ELF_STT_COMMON | BFD_NO_SECTION_HEADER)
 .
 .  {* Flags bits which are for BFD use only.  *}
 .#define BFD_FLAGS_FOR_BFD_USE_MASK \
 .  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
 .   | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT \
-.   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON)
+.   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON \
+.   | BFD_NO_SECTION_HEADER)
 .
 .  {* The format which belongs to the BFD. (object, core, etc.)  *}
 .  ENUM_BITFIELD (bfd_format) format : 3;
diff --git a/bfd/elfcode.h b/bfd/elfcode.h
index 18a6dac64e..4dde24e02a 100644
--- a/bfd/elfcode.h
+++ b/bfd/elfcode.h
@@ -266,6 +266,10 @@ elf_swap_ehdr_out (bfd *abfd,
 {
   unsigned int tmp;
   int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma;
+  /* Relocatable object must have section header.  */
+  bfd_boolean no_section_header
+    = ((abfd->flags & BFD_NO_SECTION_HEADER) != 0
+       && (abfd->flags & (EXEC_P | DYNAMIC)) != 0);
   memcpy (dst->e_ident, src->e_ident, EI_NIDENT);
   /* note that all elements of dst are *arrays of unsigned char* already...  */
   H_PUT_16 (abfd, src->e_type, dst->e_type);
@@ -276,7 +280,10 @@ elf_swap_ehdr_out (bfd *abfd,
   else
     H_PUT_WORD (abfd, src->e_entry, dst->e_entry);
   H_PUT_WORD (abfd, src->e_phoff, dst->e_phoff);
-  H_PUT_WORD (abfd, src->e_shoff, dst->e_shoff);
+  if (no_section_header)
+    H_PUT_WORD (abfd, 0, dst->e_shoff);
+  else
+    H_PUT_WORD (abfd, src->e_shoff, dst->e_shoff);
   H_PUT_32 (abfd, src->e_flags, dst->e_flags);
   H_PUT_16 (abfd, src->e_ehsize, dst->e_ehsize);
   H_PUT_16 (abfd, src->e_phentsize, dst->e_phentsize);
@@ -284,15 +291,24 @@ elf_swap_ehdr_out (bfd *abfd,
   if (tmp > PN_XNUM)
     tmp = PN_XNUM;
   H_PUT_16 (abfd, tmp, dst->e_phnum);
-  H_PUT_16 (abfd, src->e_shentsize, dst->e_shentsize);
-  tmp = src->e_shnum;
-  if (tmp >= (SHN_LORESERVE & 0xffff))
-    tmp = SHN_UNDEF;
-  H_PUT_16 (abfd, tmp, dst->e_shnum);
-  tmp = src->e_shstrndx;
-  if (tmp >= (SHN_LORESERVE & 0xffff))
-    tmp = SHN_XINDEX & 0xffff;
-  H_PUT_16 (abfd, tmp, dst->e_shstrndx);
+  if (no_section_header)
+    {
+      H_PUT_16 (abfd, 0, dst->e_shentsize);
+      H_PUT_16 (abfd, 0, dst->e_shnum);
+      H_PUT_16 (abfd, 0, dst->e_shstrndx);
+    }
+  else
+    {
+      H_PUT_16 (abfd, src->e_shentsize, dst->e_shentsize);
+      tmp = src->e_shnum;
+      if (tmp >= (SHN_LORESERVE & 0xffff))
+        tmp = SHN_UNDEF;
+      H_PUT_16 (abfd, tmp, dst->e_shnum);
+      tmp = src->e_shstrndx;
+      if (tmp >= (SHN_LORESERVE & 0xffff))
+        tmp = SHN_XINDEX & 0xffff;
+      H_PUT_16 (abfd, tmp, dst->e_shstrndx);
+    }
 }
 
 /* Translate an ELF section header table entry in external format into an
@@ -1041,6 +1057,11 @@ elf_write_shdrs_and_ehdr (bfd *abfd)
       || bfd_bwrite (&x_ehdr, amt, abfd) != amt)
     return FALSE;
 
+  /* Relocatable object must have section header.  */
+   if ((abfd->flags & BFD_NO_SECTION_HEADER) != 0
+       && (abfd->flags & (EXEC_P | DYNAMIC)) != 0)
+    return TRUE;
+
   /* Some fields in the first section header handle overflow of ehdr
      fields.  */
   if (i_ehdrp->e_phnum >= PN_XNUM)
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 1ae17f45ee..8d25c84e80 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -970,7 +970,8 @@ const bfd_target TARGET_BIG_SYM =
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS
    | DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS
-   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON),
+   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON
+   | BFD_NO_SECTION_HEADER),
 
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY
@@ -1071,7 +1072,8 @@ const bfd_target TARGET_LITTLE_SYM =
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS
    | DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS
-   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON),
+   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON
+   | BFD_NO_SECTION_HEADER),
 
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY
diff --git a/binutils/NEWS b/binutils/NEWS
index 1650a3ac93..5116e2eedc 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* Add command-line option, --remove-section-header, to objcopy and strip
+  to remove ELF section header from an executable or shared library.
+
 Changes in 2.34:
 
 * Binutils now supports debuginfod, an HTTP server for distributing
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index de3f1babb2..ece82e9e39 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -1186,6 +1186,7 @@ objcopy [@option{-F} @var{bfdname}|@option{--target=}@var{bfdname}]
         [@option{-R} @var{sectionpattern}|@option{--remove-section=}@var{sectionpattern}]
         [@option{--keep-section=}@var{sectionpattern}]
         [@option{--remove-relocations=}@var{sectionpattern}]
+        [@option{--remove-section-header}]
         [@option{-p}|@option{--preserve-dates}]
         [@option{-D}|@option{--enable-deterministic-archives}]
         [@option{-U}|@option{--disable-deterministic-archives}]
@@ -1403,6 +1404,11 @@ will remove all relocations for sections matching the pattern
 '.text.*', but will not remove relocations for the section
 '.text.foo'.
 
+@item --remove-section-header
+Remove section header from an ELF executable or shared object.  This
+option is specific to ELF files and is ignored on relocatable object
+files.  Implies @option{--strip-all} and @option{--merge-notes}.
+
 @item -S
 @itemx --strip-all
 Do not copy relocation and symbol information from the source file.
@@ -3262,6 +3268,7 @@ strip [@option{-F} @var{bfdname} |@option{--target=}@var{bfdname}]
       [@option{-R} @var{sectionname} |@option{--remove-section=}@var{sectionname}]
       [@option{--keep-section=}@var{sectionpattern}]
       [@option{--remove-relocations=}@var{sectionpattern}]
+      [@option{--remove-section-header}]
       [@option{-o} @var{file}] [@option{-p}|@option{--preserve-dates}]
       [@option{-D}|@option{--enable-deterministic-archives}]
       [@option{-U}|@option{--disable-deterministic-archives}]
@@ -3363,6 +3370,11 @@ will remove all relocations for sections matching the pattern
 '.text.*', but will not remove relocations for the section
 '.text.foo'.
 
+@item --remove-section-header
+Remove section header from an ELF executable or shared object.  This
+option is specific to ELF files and is ignored on relocatable object
+files.  Implies @option{--strip-all} and @option{--merge-notes}.
+
 @item -s
 @itemx --strip-all
 Remove all symbols.
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index 09facf0061..10891bc3f0 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -96,6 +96,9 @@ static bfd_boolean preserve_dates;	/* Preserve input file timestamp.  */
 static int deterministic = -1;		/* Enable deterministic archives.  */
 static int status = 0;			/* Exit status.  */
 
+/* Remove section header.  */
+static bfd_boolean remove_section_header = FALSE;
+
 static bfd_boolean    merge_notes = FALSE;	/* Merge note sections.  */
 
 typedef struct merged_note_section
@@ -352,6 +355,7 @@ enum command_line_switch
   OPTION_REDEFINE_SYMS,
   OPTION_REMOVE_LEADING_CHAR,
   OPTION_REMOVE_RELOCS,
+  OPTION_REMOVE_SECTION_HEADER,
   OPTION_RENAME_SECTION,
   OPTION_REVERSE_BYTES,
   OPTION_PE_SECTION_ALIGNMENT,
@@ -399,6 +403,7 @@ static struct option strip_options[] =
   {"preserve-dates", no_argument, 0, 'p'},
   {"remove-section", required_argument, 0, 'R'},
   {"remove-relocations", required_argument, 0, OPTION_REMOVE_RELOCS},
+  {"remove-section-header", no_argument, 0, OPTION_REMOVE_SECTION_HEADER},
   {"strip-all", no_argument, 0, 's'},
   {"strip-debug", no_argument, 0, 'S'},
   {"strip-dwo", no_argument, 0, OPTION_STRIP_DWO},
@@ -487,6 +492,7 @@ static struct option copy_options[] =
   {"remove-leading-char", no_argument, 0, OPTION_REMOVE_LEADING_CHAR},
   {"remove-section", required_argument, 0, 'R'},
   {"remove-relocations", required_argument, 0, OPTION_REMOVE_RELOCS},
+  {"remove-section-header", no_argument, 0, OPTION_REMOVE_SECTION_HEADER},
   {"rename-section", required_argument, 0, OPTION_RENAME_SECTION},
   {"reverse-bytes", required_argument, 0, OPTION_REVERSE_BYTES},
   {"section-alignment", required_argument, 0, OPTION_PE_SECTION_ALIGNMENT},
@@ -582,6 +588,7 @@ copy_usage (FILE *stream, int exit_status)
      --add-gnu-debuglink=<file>    Add section .gnu_debuglink linking to <file>\n\
   -R --remove-section <name>       Remove section <name> from the output\n\
      --remove-relocations <name>   Remove relocations from section <name>\n\
+     --remove-section-header       Remove section header from the output\n\
   -S --strip-all                   Remove all symbol and relocation information\n\
   -g --strip-debug                 Remove all debugging symbols & sections\n\
      --strip-dwo                   Remove all DWO sections\n\
@@ -719,6 +726,7 @@ strip_usage (FILE *stream, int exit_status)
   fprintf (stream, _("\
   -R --remove-section=<name>       Also remove section <name> from the output\n\
      --remove-relocations <name>   Remove relocations from section <name>\n\
+     --remove-section-header       Remove section header from the output\n\
   -s --strip-all                   Remove all symbol and relocation information\n\
   -g -S -d --strip-debug           Remove all debugging symbols & sections\n\
      --strip-dwo                   Remove all DWO sections\n\
@@ -2583,7 +2591,7 @@ check_new_section_flags (flagword flags, bfd * abfd, const char * secname)
    Returns TRUE upon success, FALSE otherwise.  */
 
 static bfd_boolean
-copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
+copy_object_1 (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
 {
   bfd_vma start;
   long symcount;
@@ -2637,6 +2645,13 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
 		     bfd_get_archive_filename (ibfd));
 	  return FALSE;
 	}
+
+      if (remove_section_header)
+	{
+	  non_fatal (_("--remove_section_header is unsupported on `%s'"),
+		     bfd_get_archive_filename (ibfd));
+	  return FALSE;
+	}
     }
 
   if (verbose)
@@ -3360,7 +3375,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
 	  free (merged);
 	}
     }
-  else if (merge_notes && ! is_strip)
+  else if (merge_notes && ! is_strip && ! remove_section_header)
     non_fatal (_("%s: Could not find any mergeable note sections"),
 	       bfd_get_filename (ibfd));
 
@@ -3458,6 +3473,34 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
   return TRUE;
 }
 
+/* Copy object file IBFD onto OBFD, preserve strip_symbols and
+ * saved_merge_notes, which may be changed by --remove-section-header.
+   Returns TRUE upon success, FALSE otherwise.  */
+
+static bfd_boolean
+copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
+{
+  enum strip_action saved_strip_symbols = strip_symbols;
+  bfd_boolean saved_merge_notes = merge_notes;
+  bfd_boolean res;
+
+  if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour
+      && remove_section_header
+      && (ibfd->flags & (EXEC_P | DYNAMIC)) != 0)
+    {
+      ibfd->flags |= BFD_NO_SECTION_HEADER;
+      strip_symbols = STRIP_ALL;
+      merge_notes = TRUE;
+    }
+
+  res = copy_object_1 (ibfd, obfd, input_arch);
+
+  strip_symbols = saved_strip_symbols;
+  merge_notes = saved_merge_notes;
+
+  return res;
+}
+
 /* Read each archive element in turn from IBFD, copy the
    contents to temp file, and keep the temp file handle.
    If 'force_output_target' is TRUE then make sure that
@@ -4671,6 +4714,9 @@ strip_main (int argc, char *argv[])
 	case OPTION_REMOVE_RELOCS:
 	  handle_remove_relocations_option (optarg);
 	  break;
+	case OPTION_REMOVE_SECTION_HEADER:
+	  remove_section_header = TRUE;
+	  break;
 	case 's':
 	  strip_symbols = STRIP_ALL;
 	  break;
@@ -5102,6 +5148,10 @@ copy_main (int argc, char *argv[])
 	  handle_remove_relocations_option (optarg);
 	  break;
 
+	case OPTION_REMOVE_SECTION_HEADER:
+	  remove_section_header = TRUE;
+	  break;
+
 	case 'S':
 	  strip_symbols = STRIP_ALL;
 	  break;
diff --git a/ld/NEWS b/ld/NEWS
index 7734d23d5b..79cad101a6 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* Add command-line option, -z nosectionheader, to omit ELF section header
+  when building an executable or shared library.
+
 Changes in 2.34:
 
 * The ld check for "PHDR segment not covered by LOAD segment" is more
diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
index bb7e537530..1ce1af1236 100644
--- a/ld/emultempl/elf.em
+++ b/ld/emultempl/elf.em
@@ -752,6 +752,10 @@ fragment <<EOF
 	{
 	  link_info.flags_1 |= DF_1_GLOBAUDIT;
 	}
+      else if (strcmp (optarg, "sectionheader") == 0)
+	config.no_section_header = FALSE;
+      else if (strcmp (optarg, "nosectionheader") == 0)
+	config.no_section_header = TRUE;
 EOF
 
 if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
diff --git a/ld/ld.h b/ld/ld.h
index 71fd781267..4c07604e5d 100644
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -280,6 +280,9 @@ typedef struct
   /* If set, code and non-code sections should never be in one segment.  */
   bfd_boolean separate_code;
 
+  /* If set, generation of ELF section header should be suppressed.  */
+  bfd_boolean no_section_header;
+
   /* The rpath separation character.  Usually ':'.  */
   char rpath_separator;
 
diff --git a/ld/ld.texi b/ld/ld.texi
index 27343c798f..54ba174cc2 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1295,6 +1295,12 @@ relocation, if supported.  Specifying @samp{common-page-size} smaller
 than the system page size will render this protection ineffective.
 Don't create an ELF @code{PT_GNU_RELRO} segment if @samp{norelro}.
 
+@item sectionheader
+@itemx nosectionheader
+Generate section header when building an executable or shared library.
+Don't generate section header if @samp{sectionheader} is used.
+@option{sectionheader} is the default.
+
 @item separate-code
 @itemx noseparate-code
 Create separate code @code{PT_LOAD} segment header in the object.  This
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 63f9d182ea..df187c21bf 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -3432,6 +3432,10 @@ ldlang_open_output (lang_statement_union_type *statement)
 	link_info.output_bfd->flags |= BFD_TRADITIONAL_FORMAT;
       else
 	link_info.output_bfd->flags &= ~BFD_TRADITIONAL_FORMAT;
+      if (config.no_section_header)
+	link_info.output_bfd->flags |= BFD_NO_SECTION_HEADER;
+      else
+	link_info.output_bfd->flags &= ~BFD_NO_SECTION_HEADER;
       break;
 
     case lang_target_statement_enum:
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 3d15cc491d..621c8d6605 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -1676,6 +1676,14 @@ parse_args (unsigned argc, char **argv)
       break;
     }
 
+  if (config.no_section_header)
+    {
+      if (link_info.type == type_relocatable)
+	einfo (_("%F%P: -r and -z nosectionheader may not be used together\n"));
+      /* -z nosectionheader implies --strip-all.  */
+      link_info.strip = strip_all;
+    }
+
   if (!bfd_link_dll (&link_info))
     {
       if (command_line.filter_shlib)
@@ -1879,6 +1887,10 @@ elf_static_list_options (FILE *file)
   -z noexecstack              Mark executable as not requiring executable stack\n"));
   fprintf (file, _("\
   -z globalaudit              Mark executable requiring global auditing\n"));
+  fprintf (file, _("\
+  -z sectionheader            Generate section header (default)\n"));
+  fprintf (file, _("\
+  -z nosectionheader          Do not generate section header\n"));
 }
 
 static void
-- 
2.24.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/7] ELF: Omit section header on ELF objects
  2020-03-10  0:12 [PATCH 0/7] ELF: Omit section header on ELF objects H.J. Lu
  2020-03-10  0:12 ` [PATCH 1/7] ELF: Omit section header in " H.J. Lu
@ 2020-03-10  0:12 ` H.J. Lu
  2020-03-20  7:11   ` Alan Modra
  2020-03-10  0:12 ` [PATCH 2/7] bfd: Improve nm and objdump without section header H.J. Lu
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: H.J. Lu @ 2020-03-10  0:12 UTC (permalink / raw)
  To: binutils; +Cc: Kaylee Blake

From: Kaylee Blake <klkblake@gmail.com>

Section header isn't mandatory on ELF executable nor shared library.
This patch adds a new linker option, -z nosectionheader, to omit ELF
section header when building an executable or shared library, an
objcopy and strip option, --remove-section-header, to remove ELF
section header from an executable or shared library.

bfd/

2020-03-XX  H.J. Lu  <hongjiu.lu@intel.com>
	    Kaylee Blake  <klkblake@gmail.com>

	PR ld/25617
	* bfd.c (BFD_NO_SECTION_HEADER): New.
	(BFD_FLAGS_SAVED): Add BFD_NO_SECTION_HEADER.
	(BFD_FLAGS_FOR_BFD_USE_MASK): Likewise.
	* elfcode.h (elf_swap_ehdr_out): Omit section header on
	non-relocatable output with BFD_NO_SECTION_HEADER.
	(elf_write_shdrs_and_ehdr): Likewise.
	* elfxx-target.h (TARGET_BIG_SYM): Add BFD_NO_SECTION_HEADER
	to object_flags.
	(TARGET_LITTLE_SYM): Likewise.
	* bfd-in2.h: Regenerated.

binutils/

2020-03-XX  H.J. Lu  <hongjiu.lu@intel.com>

	PR ld/25617
	* NEWS: Mention --remove-section-header for objcopy and strip.
	* doc/binutils.texi: Document --remove-section-header for objcopy
	and strip.
	* objcopy.c (remove_section_header): New.
	(command_line_switch): Add OPTION_REMOVE_SECTION_HEADER.
	(strip_options): Add --remove-section-header.
	(copy_options): Likewise.
	(copy_usage): Add --remove-section-header.
	(strip_usage): Likewise.
	(copy_object): Renamed to ...
	(copy_object_1): This.  Issue a warning for
	--remove-section-header on non-ELF targets.
	(copy_object): New.
	(strip_main): Handle OPTION_REMOVE_SECTION_HEADER.
	(copy_main): Likewise.

ld/

2020-03-XX  H.J. Lu  <hongjiu.lu@intel.com>
	    Kaylee Blake  <klkblake@gmail.com>

	PR ld/25617
	* NEWS: Mention -z nosectionheader.
	* emultempl/elf.em: Support -z sectionheader and
	-z nosectionheader.
	* ld.h (ld_config_type): Add no_section_header.
	* ld.texi: Document -z sectionheader and -z nosectionheader.
	* ldlang.c (ldlang_open_output): Handle
	config.no_section_header.
	* lexsup.c (parse_args): Disallow -z nosectionheader with -r.
	(elf_static_list_options): Add -z sectionheader and
	-z nosectionheader.
---
 bfd/bfd-in2.h              |  8 ++++--
 bfd/bfd.c                  |  8 ++++--
 bfd/elfcode.h              | 41 ++++++++++++++++++++++-------
 bfd/elfxx-target.h         |  6 +++--
 binutils/NEWS              |  3 +++
 binutils/doc/binutils.texi | 12 +++++++++
 binutils/objcopy.c         | 54 ++++++++++++++++++++++++++++++++++++--
 ld/NEWS                    |  3 +++
 ld/emultempl/elf.em        |  4 +++
 ld/ld.h                    |  3 +++
 ld/ld.texi                 |  6 +++++
 ld/ldlang.c                |  4 +++
 ld/lexsup.c                | 12 +++++++++
 13 files changed, 146 insertions(+), 18 deletions(-)

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 37114607b5..d81d0e20dd 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -6588,17 +6588,21 @@ struct bfd
   /* Put pathnames into archives (non-POSIX).  */
 #define BFD_ARCHIVE_FULL_PATH  0x100000
 
+  /* Don't generate ELF section header.  */
+#define BFD_NO_SECTION_HEADER  0x200000
+
   /* Flags bits to be saved in bfd_preserve_save.  */
 #define BFD_FLAGS_SAVED \
   (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
    | BFD_PLUGIN | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON \
-   | BFD_USE_ELF_STT_COMMON)
+   | BFD_USE_ELF_STT_COMMON | BFD_NO_SECTION_HEADER)
 
   /* Flags bits which are for BFD use only.  */
 #define BFD_FLAGS_FOR_BFD_USE_MASK \
   (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
    | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT \
-   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON)
+   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON \
+   | BFD_NO_SECTION_HEADER)
 
   /* The format which belongs to the BFD. (object, core, etc.)  */
   ENUM_BITFIELD (bfd_format) format : 3;
diff --git a/bfd/bfd.c b/bfd/bfd.c
index 1c1238c036..366e662592 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -176,17 +176,21 @@ CODE_FRAGMENT
 .  {* Put pathnames into archives (non-POSIX).  *}
 .#define BFD_ARCHIVE_FULL_PATH  0x100000
 .
+.  {* Don't generate ELF section header.  *}
+.#define BFD_NO_SECTION_HEADER	0x200000
+.
 .  {* Flags bits to be saved in bfd_preserve_save.  *}
 .#define BFD_FLAGS_SAVED \
 .  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
 .   | BFD_PLUGIN | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON \
-.   | BFD_USE_ELF_STT_COMMON)
+.   | BFD_USE_ELF_STT_COMMON | BFD_NO_SECTION_HEADER)
 .
 .  {* Flags bits which are for BFD use only.  *}
 .#define BFD_FLAGS_FOR_BFD_USE_MASK \
 .  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
 .   | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT \
-.   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON)
+.   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON \
+.   | BFD_NO_SECTION_HEADER)
 .
 .  {* The format which belongs to the BFD. (object, core, etc.)  *}
 .  ENUM_BITFIELD (bfd_format) format : 3;
diff --git a/bfd/elfcode.h b/bfd/elfcode.h
index 18a6dac64e..4dde24e02a 100644
--- a/bfd/elfcode.h
+++ b/bfd/elfcode.h
@@ -266,6 +266,10 @@ elf_swap_ehdr_out (bfd *abfd,
 {
   unsigned int tmp;
   int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma;
+  /* Relocatable object must have section header.  */
+  bfd_boolean no_section_header
+    = ((abfd->flags & BFD_NO_SECTION_HEADER) != 0
+       && (abfd->flags & (EXEC_P | DYNAMIC)) != 0);
   memcpy (dst->e_ident, src->e_ident, EI_NIDENT);
   /* note that all elements of dst are *arrays of unsigned char* already...  */
   H_PUT_16 (abfd, src->e_type, dst->e_type);
@@ -276,7 +280,10 @@ elf_swap_ehdr_out (bfd *abfd,
   else
     H_PUT_WORD (abfd, src->e_entry, dst->e_entry);
   H_PUT_WORD (abfd, src->e_phoff, dst->e_phoff);
-  H_PUT_WORD (abfd, src->e_shoff, dst->e_shoff);
+  if (no_section_header)
+    H_PUT_WORD (abfd, 0, dst->e_shoff);
+  else
+    H_PUT_WORD (abfd, src->e_shoff, dst->e_shoff);
   H_PUT_32 (abfd, src->e_flags, dst->e_flags);
   H_PUT_16 (abfd, src->e_ehsize, dst->e_ehsize);
   H_PUT_16 (abfd, src->e_phentsize, dst->e_phentsize);
@@ -284,15 +291,24 @@ elf_swap_ehdr_out (bfd *abfd,
   if (tmp > PN_XNUM)
     tmp = PN_XNUM;
   H_PUT_16 (abfd, tmp, dst->e_phnum);
-  H_PUT_16 (abfd, src->e_shentsize, dst->e_shentsize);
-  tmp = src->e_shnum;
-  if (tmp >= (SHN_LORESERVE & 0xffff))
-    tmp = SHN_UNDEF;
-  H_PUT_16 (abfd, tmp, dst->e_shnum);
-  tmp = src->e_shstrndx;
-  if (tmp >= (SHN_LORESERVE & 0xffff))
-    tmp = SHN_XINDEX & 0xffff;
-  H_PUT_16 (abfd, tmp, dst->e_shstrndx);
+  if (no_section_header)
+    {
+      H_PUT_16 (abfd, 0, dst->e_shentsize);
+      H_PUT_16 (abfd, 0, dst->e_shnum);
+      H_PUT_16 (abfd, 0, dst->e_shstrndx);
+    }
+  else
+    {
+      H_PUT_16 (abfd, src->e_shentsize, dst->e_shentsize);
+      tmp = src->e_shnum;
+      if (tmp >= (SHN_LORESERVE & 0xffff))
+        tmp = SHN_UNDEF;
+      H_PUT_16 (abfd, tmp, dst->e_shnum);
+      tmp = src->e_shstrndx;
+      if (tmp >= (SHN_LORESERVE & 0xffff))
+        tmp = SHN_XINDEX & 0xffff;
+      H_PUT_16 (abfd, tmp, dst->e_shstrndx);
+    }
 }
 
 /* Translate an ELF section header table entry in external format into an
@@ -1041,6 +1057,11 @@ elf_write_shdrs_and_ehdr (bfd *abfd)
       || bfd_bwrite (&x_ehdr, amt, abfd) != amt)
     return FALSE;
 
+  /* Relocatable object must have section header.  */
+   if ((abfd->flags & BFD_NO_SECTION_HEADER) != 0
+       && (abfd->flags & (EXEC_P | DYNAMIC)) != 0)
+    return TRUE;
+
   /* Some fields in the first section header handle overflow of ehdr
      fields.  */
   if (i_ehdrp->e_phnum >= PN_XNUM)
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 1ae17f45ee..8d25c84e80 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -970,7 +970,8 @@ const bfd_target TARGET_BIG_SYM =
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS
    | DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS
-   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON),
+   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON
+   | BFD_NO_SECTION_HEADER),
 
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY
@@ -1071,7 +1072,8 @@ const bfd_target TARGET_LITTLE_SYM =
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS
    | DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS
-   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON),
+   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON
+   | BFD_NO_SECTION_HEADER),
 
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY
diff --git a/binutils/NEWS b/binutils/NEWS
index 1650a3ac93..5116e2eedc 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* Add command-line option, --remove-section-header, to objcopy and strip
+  to remove ELF section header from an executable or shared library.
+
 Changes in 2.34:
 
 * Binutils now supports debuginfod, an HTTP server for distributing
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index de3f1babb2..ece82e9e39 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -1186,6 +1186,7 @@ objcopy [@option{-F} @var{bfdname}|@option{--target=}@var{bfdname}]
         [@option{-R} @var{sectionpattern}|@option{--remove-section=}@var{sectionpattern}]
         [@option{--keep-section=}@var{sectionpattern}]
         [@option{--remove-relocations=}@var{sectionpattern}]
+        [@option{--remove-section-header}]
         [@option{-p}|@option{--preserve-dates}]
         [@option{-D}|@option{--enable-deterministic-archives}]
         [@option{-U}|@option{--disable-deterministic-archives}]
@@ -1403,6 +1404,11 @@ will remove all relocations for sections matching the pattern
 '.text.*', but will not remove relocations for the section
 '.text.foo'.
 
+@item --remove-section-header
+Remove section header from an ELF executable or shared object.  This
+option is specific to ELF files and is ignored on relocatable object
+files.  Implies @option{--strip-all} and @option{--merge-notes}.
+
 @item -S
 @itemx --strip-all
 Do not copy relocation and symbol information from the source file.
@@ -3262,6 +3268,7 @@ strip [@option{-F} @var{bfdname} |@option{--target=}@var{bfdname}]
       [@option{-R} @var{sectionname} |@option{--remove-section=}@var{sectionname}]
       [@option{--keep-section=}@var{sectionpattern}]
       [@option{--remove-relocations=}@var{sectionpattern}]
+      [@option{--remove-section-header}]
       [@option{-o} @var{file}] [@option{-p}|@option{--preserve-dates}]
       [@option{-D}|@option{--enable-deterministic-archives}]
       [@option{-U}|@option{--disable-deterministic-archives}]
@@ -3363,6 +3370,11 @@ will remove all relocations for sections matching the pattern
 '.text.*', but will not remove relocations for the section
 '.text.foo'.
 
+@item --remove-section-header
+Remove section header from an ELF executable or shared object.  This
+option is specific to ELF files and is ignored on relocatable object
+files.  Implies @option{--strip-all} and @option{--merge-notes}.
+
 @item -s
 @itemx --strip-all
 Remove all symbols.
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index 09facf0061..10891bc3f0 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -96,6 +96,9 @@ static bfd_boolean preserve_dates;	/* Preserve input file timestamp.  */
 static int deterministic = -1;		/* Enable deterministic archives.  */
 static int status = 0;			/* Exit status.  */
 
+/* Remove section header.  */
+static bfd_boolean remove_section_header = FALSE;
+
 static bfd_boolean    merge_notes = FALSE;	/* Merge note sections.  */
 
 typedef struct merged_note_section
@@ -352,6 +355,7 @@ enum command_line_switch
   OPTION_REDEFINE_SYMS,
   OPTION_REMOVE_LEADING_CHAR,
   OPTION_REMOVE_RELOCS,
+  OPTION_REMOVE_SECTION_HEADER,
   OPTION_RENAME_SECTION,
   OPTION_REVERSE_BYTES,
   OPTION_PE_SECTION_ALIGNMENT,
@@ -399,6 +403,7 @@ static struct option strip_options[] =
   {"preserve-dates", no_argument, 0, 'p'},
   {"remove-section", required_argument, 0, 'R'},
   {"remove-relocations", required_argument, 0, OPTION_REMOVE_RELOCS},
+  {"remove-section-header", no_argument, 0, OPTION_REMOVE_SECTION_HEADER},
   {"strip-all", no_argument, 0, 's'},
   {"strip-debug", no_argument, 0, 'S'},
   {"strip-dwo", no_argument, 0, OPTION_STRIP_DWO},
@@ -487,6 +492,7 @@ static struct option copy_options[] =
   {"remove-leading-char", no_argument, 0, OPTION_REMOVE_LEADING_CHAR},
   {"remove-section", required_argument, 0, 'R'},
   {"remove-relocations", required_argument, 0, OPTION_REMOVE_RELOCS},
+  {"remove-section-header", no_argument, 0, OPTION_REMOVE_SECTION_HEADER},
   {"rename-section", required_argument, 0, OPTION_RENAME_SECTION},
   {"reverse-bytes", required_argument, 0, OPTION_REVERSE_BYTES},
   {"section-alignment", required_argument, 0, OPTION_PE_SECTION_ALIGNMENT},
@@ -582,6 +588,7 @@ copy_usage (FILE *stream, int exit_status)
      --add-gnu-debuglink=<file>    Add section .gnu_debuglink linking to <file>\n\
   -R --remove-section <name>       Remove section <name> from the output\n\
      --remove-relocations <name>   Remove relocations from section <name>\n\
+     --remove-section-header       Remove section header from the output\n\
   -S --strip-all                   Remove all symbol and relocation information\n\
   -g --strip-debug                 Remove all debugging symbols & sections\n\
      --strip-dwo                   Remove all DWO sections\n\
@@ -719,6 +726,7 @@ strip_usage (FILE *stream, int exit_status)
   fprintf (stream, _("\
   -R --remove-section=<name>       Also remove section <name> from the output\n\
      --remove-relocations <name>   Remove relocations from section <name>\n\
+     --remove-section-header       Remove section header from the output\n\
   -s --strip-all                   Remove all symbol and relocation information\n\
   -g -S -d --strip-debug           Remove all debugging symbols & sections\n\
      --strip-dwo                   Remove all DWO sections\n\
@@ -2583,7 +2591,7 @@ check_new_section_flags (flagword flags, bfd * abfd, const char * secname)
    Returns TRUE upon success, FALSE otherwise.  */
 
 static bfd_boolean
-copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
+copy_object_1 (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
 {
   bfd_vma start;
   long symcount;
@@ -2637,6 +2645,13 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
 		     bfd_get_archive_filename (ibfd));
 	  return FALSE;
 	}
+
+      if (remove_section_header)
+	{
+	  non_fatal (_("--remove_section_header is unsupported on `%s'"),
+		     bfd_get_archive_filename (ibfd));
+	  return FALSE;
+	}
     }
 
   if (verbose)
@@ -3360,7 +3375,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
 	  free (merged);
 	}
     }
-  else if (merge_notes && ! is_strip)
+  else if (merge_notes && ! is_strip && ! remove_section_header)
     non_fatal (_("%s: Could not find any mergeable note sections"),
 	       bfd_get_filename (ibfd));
 
@@ -3458,6 +3473,34 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
   return TRUE;
 }
 
+/* Copy object file IBFD onto OBFD, preserve strip_symbols and
+ * saved_merge_notes, which may be changed by --remove-section-header.
+   Returns TRUE upon success, FALSE otherwise.  */
+
+static bfd_boolean
+copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
+{
+  enum strip_action saved_strip_symbols = strip_symbols;
+  bfd_boolean saved_merge_notes = merge_notes;
+  bfd_boolean res;
+
+  if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour
+      && remove_section_header
+      && (ibfd->flags & (EXEC_P | DYNAMIC)) != 0)
+    {
+      ibfd->flags |= BFD_NO_SECTION_HEADER;
+      strip_symbols = STRIP_ALL;
+      merge_notes = TRUE;
+    }
+
+  res = copy_object_1 (ibfd, obfd, input_arch);
+
+  strip_symbols = saved_strip_symbols;
+  merge_notes = saved_merge_notes;
+
+  return res;
+}
+
 /* Read each archive element in turn from IBFD, copy the
    contents to temp file, and keep the temp file handle.
    If 'force_output_target' is TRUE then make sure that
@@ -4671,6 +4714,9 @@ strip_main (int argc, char *argv[])
 	case OPTION_REMOVE_RELOCS:
 	  handle_remove_relocations_option (optarg);
 	  break;
+	case OPTION_REMOVE_SECTION_HEADER:
+	  remove_section_header = TRUE;
+	  break;
 	case 's':
 	  strip_symbols = STRIP_ALL;
 	  break;
@@ -5102,6 +5148,10 @@ copy_main (int argc, char *argv[])
 	  handle_remove_relocations_option (optarg);
 	  break;
 
+	case OPTION_REMOVE_SECTION_HEADER:
+	  remove_section_header = TRUE;
+	  break;
+
 	case 'S':
 	  strip_symbols = STRIP_ALL;
 	  break;
diff --git a/ld/NEWS b/ld/NEWS
index 7734d23d5b..79cad101a6 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* Add command-line option, -z nosectionheader, to omit ELF section header
+  when building an executable or shared library.
+
 Changes in 2.34:
 
 * The ld check for "PHDR segment not covered by LOAD segment" is more
diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
index bb7e537530..1ce1af1236 100644
--- a/ld/emultempl/elf.em
+++ b/ld/emultempl/elf.em
@@ -752,6 +752,10 @@ fragment <<EOF
 	{
 	  link_info.flags_1 |= DF_1_GLOBAUDIT;
 	}
+      else if (strcmp (optarg, "sectionheader") == 0)
+	config.no_section_header = FALSE;
+      else if (strcmp (optarg, "nosectionheader") == 0)
+	config.no_section_header = TRUE;
 EOF
 
 if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
diff --git a/ld/ld.h b/ld/ld.h
index 71fd781267..4c07604e5d 100644
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -280,6 +280,9 @@ typedef struct
   /* If set, code and non-code sections should never be in one segment.  */
   bfd_boolean separate_code;
 
+  /* If set, generation of ELF section header should be suppressed.  */
+  bfd_boolean no_section_header;
+
   /* The rpath separation character.  Usually ':'.  */
   char rpath_separator;
 
diff --git a/ld/ld.texi b/ld/ld.texi
index 27343c798f..54ba174cc2 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1295,6 +1295,12 @@ relocation, if supported.  Specifying @samp{common-page-size} smaller
 than the system page size will render this protection ineffective.
 Don't create an ELF @code{PT_GNU_RELRO} segment if @samp{norelro}.
 
+@item sectionheader
+@itemx nosectionheader
+Generate section header when building an executable or shared library.
+Don't generate section header if @samp{sectionheader} is used.
+@option{sectionheader} is the default.
+
 @item separate-code
 @itemx noseparate-code
 Create separate code @code{PT_LOAD} segment header in the object.  This
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 63f9d182ea..df187c21bf 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -3432,6 +3432,10 @@ ldlang_open_output (lang_statement_union_type *statement)
 	link_info.output_bfd->flags |= BFD_TRADITIONAL_FORMAT;
       else
 	link_info.output_bfd->flags &= ~BFD_TRADITIONAL_FORMAT;
+      if (config.no_section_header)
+	link_info.output_bfd->flags |= BFD_NO_SECTION_HEADER;
+      else
+	link_info.output_bfd->flags &= ~BFD_NO_SECTION_HEADER;
       break;
 
     case lang_target_statement_enum:
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 3d15cc491d..621c8d6605 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -1676,6 +1676,14 @@ parse_args (unsigned argc, char **argv)
       break;
     }
 
+  if (config.no_section_header)
+    {
+      if (link_info.type == type_relocatable)
+	einfo (_("%F%P: -r and -z nosectionheader may not be used together\n"));
+      /* -z nosectionheader implies --strip-all.  */
+      link_info.strip = strip_all;
+    }
+
   if (!bfd_link_dll (&link_info))
     {
       if (command_line.filter_shlib)
@@ -1879,6 +1887,10 @@ elf_static_list_options (FILE *file)
   -z noexecstack              Mark executable as not requiring executable stack\n"));
   fprintf (file, _("\
   -z globalaudit              Mark executable requiring global auditing\n"));
+  fprintf (file, _("\
+  -z sectionheader            Generate section header (default)\n"));
+  fprintf (file, _("\
+  -z nosectionheader          Do not generate section header\n"));
 }
 
 static void
-- 
2.24.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 2/7] bfd: Improve nm and objdump without section header
  2020-03-10  0:12 [PATCH 0/7] ELF: Omit section header on ELF objects H.J. Lu
  2020-03-10  0:12 ` [PATCH 1/7] ELF: Omit section header in " H.J. Lu
  2020-03-10  0:12 ` [PATCH 1/7] ELF: Omit section header on " H.J. Lu
@ 2020-03-10  0:12 ` H.J. Lu
  2020-03-12  3:11   ` Fangrui Song
  2020-03-10  0:12 ` [PATCH 3/7] readelf: Compute dynamic symbol table size from hash table H.J. Lu
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: H.J. Lu @ 2020-03-10  0:12 UTC (permalink / raw)
  To: binutils

When there is no section header in an executable or shared library, we
reconstruct dynamic symbol table from the PT_DYNAMIC segment, which
contains DT_HASH/DT_GNU_HASH/DT_MIPS_XHASH, DT_STRTAB, DT_SYMTAB,
DT_STRSZ and DT_SYMENT entries, to improve nm and objdump.  For DT_HASH,
the number of dynamic symbol table entries equals the number of chains.
For DT_GNU_HASH/DT_MIPS_XHASH, only defined symbols with non-STB_LOCAL
indings are in hash table.  Since DT_GNU_HASH/DT_MIPS_XHASH place all
symbols with STB_LOCAL binding before symbols with other bindings and
all undefined symbols defined ones in dynamic symbol table, the highest
symbol index in DT_GNU_HASH/DT_MIPS_XHASH is the highest dynamic symbol
table index.

dt_symtab, dt_symtab_count and dt_strtab are added to elf_obj_tdata to
store dynamic symbol table information.

	PR ld/25617
	* elf-bfd.h (elf_obj_tdata): Add dt_symtab, dt_symtab_count and
	dt_strtab.
	(elf_use_dt_symtab_p): New.
	(_bfd_elf_get_dynamic_symbols): Likewise.
	(_bfd_elf_get_section_from_dynamic_symbol): Likewise.
	* elf.c (bfd_elf_get_elf_syms): Use dynamic symbol table if
	neeeded.
	(_bfd_elf_get_dynamic_symtab_upper_bound): Likewise.
	(offset_from_vma): New function.
	(get_hash_table_data): Likewise.
	(_bfd_elf_get_dynamic_symbols): Likewise.
	(_bfd_elf_get_section_from_dynamic_symbol): Likewise.
	* elfcode.h (elf_object_p): Call _bfd_elf_get_dynamic_symbols
	to reconstruct dynamic symbol table from PT_DYNAMIC segment if
	there is no section header.
	(elf_slurp_symbol_table): Use dynamic symbol table if neeeded.
	Don't free isymbuf when dynamic symbol table is used.
	* elflink.c (elf_link_is_defined_archive_symbol): Return wrong
	format error when dynamic symbol table is used.
	(elf_link_add_object_symbols): Likewise.
---
 bfd/elf-bfd.h |  10 +
 bfd/elf.c     | 497 ++++++++++++++++++++++++++++++++++++++++++++++++++
 bfd/elfcode.h |  42 ++++-
 bfd/elflink.c |  12 ++
 4 files changed, 557 insertions(+), 4 deletions(-)

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 5d9e0fedcd..09692b155a 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1876,6 +1876,9 @@ struct elf_obj_tdata
   Elf_Internal_Shdr dynversym_hdr;
   Elf_Internal_Shdr dynverref_hdr;
   Elf_Internal_Shdr dynverdef_hdr;
+  Elf_Internal_Sym *dt_symtab;
+  bfd_size_type dt_symtab_count;
+  char *dt_strtab;
   elf_section_list * symtab_shndx_list;
   bfd_vma gp;				/* The gp value */
   unsigned int gp_size;			/* The gp size */
@@ -2030,6 +2033,7 @@ struct elf_obj_tdata
 #define elf_dyn_lib_class(bfd)	(elf_tdata(bfd) -> dyn_lib_class)
 #define elf_bad_symtab(bfd)	(elf_tdata(bfd) -> bad_symtab)
 #define elf_flags_init(bfd)	(elf_tdata(bfd) -> o->flags_init)
+#define elf_use_dt_symtab_p(bfd) (elf_tdata(bfd) -> dt_symtab_count != 0)
 #define elf_known_obj_attributes(bfd) (elf_tdata (bfd) -> known_obj_attributes)
 #define elf_other_obj_attributes(bfd) (elf_tdata (bfd) -> other_obj_attributes)
 #define elf_known_obj_attributes_proc(bfd) \
@@ -2403,6 +2407,12 @@ extern bfd_reloc_status_type bfd_elf_perform_complex_relocation
 extern bfd_boolean _bfd_elf_setup_sections
   (bfd *);
 
+extern bfd_boolean _bfd_elf_get_dynamic_symbols
+  (bfd *, Elf_Internal_Phdr *, Elf_Internal_Phdr *, size_t,
+   bfd_size_type);
+extern asection *_bfd_elf_get_section_from_dynamic_symbol
+  (bfd *, Elf_Internal_Sym *);
+
 extern struct bfd_link_hash_entry *bfd_elf_define_start_stop
   (struct bfd_link_info *, const char *, asection *);
 
diff --git a/bfd/elf.c b/bfd/elf.c
index e6db2ff64d..aa689dcab3 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -405,6 +405,17 @@ bfd_elf_get_elf_syms (bfd *ibfd,
   if (symcount == 0)
     return intsym_buf;
 
+  if (elf_use_dt_symtab_p (ibfd))
+    {
+      /* Use dynamic symbol table.  */
+      if (elf_tdata (ibfd)->dt_symtab_count != (symcount + symoffset))
+	{
+	  bfd_set_error (bfd_error_invalid_operation);
+	  return NULL;
+	}
+      return elf_tdata (ibfd)->dt_symtab + symoffset;
+    }
+
   /* Normal syms might have section extension entries.  */
   shndx_hdr = NULL;
   if (elf_symtab_shndx_list (ibfd) != NULL)
@@ -1881,6 +1892,485 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
   return FALSE;
 }
 
+/* Find the file offset corresponding to VMA by using the program
+   headers.  */
+
+static file_ptr
+offset_from_vma (Elf_Internal_Phdr *phdrs, size_t phnum, bfd_vma vma,
+		 bfd_vma size)
+{
+  Elf_Internal_Phdr *seg;
+  size_t i;
+
+  for (seg = phdrs, i = 0; i < phnum; ++seg, ++i)
+    if (seg->p_type == PT_LOAD
+	&& vma >= (seg->p_vaddr & -seg->p_align)
+	&& vma + size <= seg->p_vaddr + seg->p_filesz)
+      return (file_ptr) (vma - seg->p_vaddr + seg->p_offset);
+
+  bfd_set_error (bfd_error_invalid_operation);
+  return (file_ptr) -1;
+}
+
+/* Convert hash table to internal form.  */
+
+static bfd_vma *
+get_hash_table_data (bfd *abfd, bfd_size_type number,
+		     unsigned int ent_size, bfd_size_type filesize)
+{
+  unsigned char *e_data = NULL;
+  bfd_vma *i_data = NULL;
+  bfd_size_type size;
+
+  if (ent_size != 4 && ent_size != 8)
+    return NULL;
+
+  /* If the size_t type is smaller than the bfd_size_type, eg because
+     you are building a 32-bit tool on a 64-bit host, then make sure
+     that when (number) is cast to (size_t) no information is lost.  */
+  if (sizeof (size_t) < sizeof (bfd_size_type)
+      && (bfd_size_type) ((size_t) number) != number)
+    {
+      bfd_set_error (bfd_error_file_too_big);
+      return NULL;
+    }
+
+  size = ent_size * number;
+  /* Be kind to memory checkers (eg valgrind, address sanitizer) by not
+     attempting to allocate memory when the read is bound to fail.  */
+  if (size > filesize
+      || number >= ~(size_t) 0 / ent_size
+      || number >= ~(size_t) 0 / sizeof (*i_data))
+    {
+      bfd_set_error (bfd_error_file_too_big);
+      return NULL;
+    }
+
+  e_data = _bfd_malloc_and_read (abfd, size, size);
+  if (e_data == NULL)
+    return NULL;
+
+  i_data = (bfd_vma *) bfd_malloc (number * sizeof (*i_data));
+  if (i_data == NULL)
+    {
+      free (e_data);
+      return NULL;
+    }
+
+  if (ent_size == 4)
+    while (number--)
+      i_data[number] = bfd_get_32 (abfd, e_data + number * ent_size);
+  else
+    while (number--)
+      i_data[number] = bfd_get_64 (abfd, e_data + number * ent_size);
+
+  free (e_data);
+  return i_data;
+}
+
+/* Address of .MIPS.xhash section.  FIXME: What is the best way to
+   support DT_MIPS_XHASH?  */
+#define DT_MIPS_XHASH	       0x70000036
+
+/* Reconstruct dynamic symbol table from PT_DYNAMIC segment.  */
+
+bfd_boolean
+_bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr,
+			      Elf_Internal_Phdr *phdrs, size_t phnum,
+			      bfd_size_type filesize)
+{
+  bfd_byte *extdyn, *extdynend;
+  size_t extdynsize;
+  void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
+  bfd_boolean (*swap_symbol_in) (bfd *, const void *, const void *,
+				 Elf_Internal_Sym *);
+  Elf_Internal_Dyn dyn;
+  bfd_vma dt_hash = 0;
+  bfd_vma dt_gnu_hash = 0;
+  bfd_vma dt_mips_xhash = 0;
+  bfd_vma dt_strtab = 0;
+  bfd_vma dt_symtab = 0;
+  bfd_vma dt_strsz = 0;
+  bfd_byte *dynbuf = NULL;
+  char *strbuf = NULL;
+  bfd_vma *gnubuckets = NULL;
+  bfd_vma *gnuchains = NULL;
+  bfd_vma *mipsxlat = NULL;
+  file_ptr saved_filepos, filepos;
+  bfd_boolean res = FALSE;
+  bfd_size_type amt;
+  bfd_byte *esymbuf = NULL, *esym;
+  bfd_size_type symcount;
+  Elf_Internal_Sym *isymbuf = NULL;
+  Elf_Internal_Sym *isym, *isymend;
+  size_t extsym_size;
+  const struct elf_backend_data *bed;
+
+  /* Return TRUE if symbol table is bad.  */
+  if (elf_bad_symtab (abfd))
+    return TRUE;
+
+  /* Return TRUE if DT_HASH/DT_GNU_HASH have bee processed before.  */
+  if (elf_tdata (abfd)->dt_strtab != NULL)
+    return TRUE;
+
+  bed = get_elf_backend_data (abfd);
+
+  /* Save file position for elf_object_p.  */
+  saved_filepos = bfd_tell (abfd);
+
+  if (bfd_seek (abfd, phdr->p_offset, SEEK_SET) != 0)
+    goto error_return;
+
+  dynbuf = _bfd_malloc_and_read (abfd, phdr->p_filesz, phdr->p_filesz);
+  if (dynbuf == NULL)
+    goto error_return;
+
+  extsym_size = bed->s->sizeof_sym;
+  extdynsize = bed->s->sizeof_dyn;
+  swap_dyn_in = bed->s->swap_dyn_in;
+
+  extdyn = dynbuf;
+  if (phdr->p_filesz < extdynsize)
+    goto error_return;
+  extdynend = extdyn + phdr->p_filesz;
+  for (; extdyn <= (extdynend - extdynsize); extdyn += extdynsize)
+    {
+      swap_dyn_in (abfd, extdyn, &dyn);
+
+      if (dyn.d_tag == DT_NULL)
+	break;
+
+      switch (dyn.d_tag)
+	{
+	case DT_HASH:
+	  dt_hash = dyn.d_un.d_val;
+	  break;
+	case DT_GNU_HASH:
+	  if (bed->elf_machine_code != EM_MIPS
+	      && bed->elf_machine_code != EM_MIPS_RS3_LE)
+	    dt_gnu_hash = dyn.d_un.d_val;
+	  break;
+	case DT_STRTAB:
+	  dt_strtab = dyn.d_un.d_val;
+	  break;
+	case DT_SYMTAB:
+	  dt_symtab = dyn.d_un.d_val;
+	  break;
+	case DT_STRSZ:
+	  dt_strsz = dyn.d_un.d_val;
+	  break;
+	case DT_SYMENT:
+	  if (dyn.d_un.d_val != extsym_size)
+	    goto error_return;
+	  break;
+	default:
+	  if (dyn.d_tag == DT_MIPS_XHASH
+	      && (bed->elf_machine_code == EM_MIPS
+		  || bed->elf_machine_code == EM_MIPS_RS3_LE))
+	    {
+	      dt_gnu_hash = dyn.d_un.d_val;
+	      dt_mips_xhash = dyn.d_un.d_val;
+	    }
+	  break;
+	}
+    }
+
+  /* Check if we can reconstruct dynamic symbol table from PT_DYNAMIC
+     segment.  */
+  if ((!dt_hash && !dt_gnu_hash)
+      || !dt_strtab
+      || !dt_symtab
+      || !dt_strsz)
+    goto error_return;
+
+  /* Get dynamic string table.  */
+  filepos = offset_from_vma (phdrs, phnum, dt_strtab, dt_strsz);
+  if (filepos == (file_ptr) -1
+      || bfd_seek (abfd, filepos, SEEK_SET) != 0)
+    goto error_return;
+
+  /* Dynamic string table must be valid until ABFD is closed.  */
+  strbuf = (char *) _bfd_alloc_and_read (abfd, dt_strsz, dt_strsz);
+  if (strbuf == NULL)
+    goto error_return;
+
+  /* Get the real symbol count from DT_HASH or DT_GNU_HASH.  Prefer
+     DT_HASH since it is simpler than DT_GNU_HASH.  */
+  if (dt_hash)
+    {
+      unsigned char nb[16];
+      unsigned int hash_ent_size;
+
+      switch (bed->elf_machine_code)
+	{
+	case EM_ALPHA:
+	case EM_S390:
+	case EM_S390_OLD:
+	  if (bed->s->elfclass == ELFCLASS64)
+	    {
+	      hash_ent_size = 8;
+	      break;
+	    }
+	  /* FALLTHROUGH */
+	default:
+	  hash_ent_size = 4;
+	  break;
+	}
+
+      filepos = offset_from_vma (phdrs, phnum, dt_hash, sizeof (nb));
+      if (filepos == (file_ptr) -1
+	  || bfd_seek (abfd, filepos, SEEK_SET) != 0
+	  || (bfd_bread (nb, 2 * hash_ent_size, abfd)
+	      != (2 * hash_ent_size)))
+	goto error_return;
+
+      /* The number of dynamic symbol table entries equals the number
+	 of chains.  */
+      if (hash_ent_size == 8)
+	symcount = bfd_get_64 (abfd, nb + hash_ent_size);
+      else
+	symcount = bfd_get_32 (abfd, nb + hash_ent_size);
+    }
+  else
+    {
+      /* For DT_GNU_HASH, only defined symbols with non-STB_LOCAL
+	 bindings are in hash table.  Since in dynamic symbol table,
+	 all symbols with STB_LOCAL binding are placed before symbols
+	 with other bindings and all undefined symbols are placed
+	 before defined ones, the highest symbol index in DT_GNU_HASH
+	 is the highest dynamic symbol table index.  */
+      unsigned char nb[16];
+      bfd_vma ngnubuckets;
+      bfd_vma gnusymidx;
+      size_t i, ngnuchains;
+      bfd_vma maxchain = 0xffffffff, bitmaskwords;
+      bfd_vma buckets_vma;
+
+      filepos = offset_from_vma (phdrs, phnum, dt_gnu_hash,
+				 sizeof (nb));
+      if (filepos == (file_ptr) -1
+	  || bfd_seek (abfd, filepos, SEEK_SET) != 0
+	  || bfd_bread (nb, sizeof (nb), abfd) != sizeof (nb))
+	goto error_return;
+
+      ngnubuckets = bfd_get_32 (abfd, nb);
+      gnusymidx = bfd_get_32 (abfd, nb + 4);
+      bitmaskwords = bfd_get_32 (abfd, nb + 8);
+      buckets_vma = dt_gnu_hash + 16;
+      if (bed->s->elfclass == ELFCLASS32)
+	buckets_vma += bitmaskwords * 4;
+      else
+	buckets_vma += bitmaskwords * 8;
+      filepos = offset_from_vma (phdrs, phnum, buckets_vma, 4);
+      if (filepos == (file_ptr) -1
+	  || bfd_seek (abfd, filepos, SEEK_SET) != 0)
+	goto error_return;
+
+      gnubuckets = get_hash_table_data (abfd, ngnubuckets, 4, filesize);
+      if (gnubuckets == NULL)
+	goto error_return;
+
+      for (i = 0; i < ngnubuckets; i++)
+	if (gnubuckets[i] != 0)
+	  {
+	    if (gnubuckets[i] < gnusymidx)
+	      goto error_return;
+
+	    if (maxchain == 0xffffffff || gnubuckets[i] > maxchain)
+	      maxchain = gnubuckets[i];
+	  }
+
+      if (maxchain == 0xffffffff)
+	goto error_return;
+
+      maxchain -= gnusymidx;
+      filepos = offset_from_vma (phdrs, phnum,
+				 (buckets_vma +
+				  4 * (ngnubuckets + maxchain)),
+				 4);
+      if (filepos == (file_ptr) -1
+	  || bfd_seek (abfd, filepos, SEEK_SET) != 0)
+	goto error_return;
+
+      do
+	{
+	  if (bfd_bread (nb, 4, abfd) != 4)
+	    goto error_return;
+	  ++maxchain;
+	  if (maxchain == 0)
+	    goto error_return;
+	}
+      while ((bfd_get_32 (abfd, nb) & 1) == 0);
+
+      filepos = offset_from_vma (phdrs, phnum,
+				 (buckets_vma + 4 * ngnubuckets),
+				 4);
+      if (filepos == (file_ptr) -1
+	  || bfd_seek (abfd, filepos, SEEK_SET) != 0)
+	goto error_return;
+
+      gnuchains = get_hash_table_data (abfd, maxchain, 4, filesize);
+      if (gnubuckets == NULL)
+	goto error_return;
+      ngnuchains = maxchain;
+
+      if (dt_mips_xhash)
+	{
+	  filepos = offset_from_vma (phdrs, phnum,
+				     (buckets_vma
+				      + 4 * (ngnubuckets + maxchain)),
+				     4);
+	  if (filepos == (file_ptr) -1
+	      || bfd_seek (abfd, filepos, SEEK_SET) != 0)
+	    goto error_return;
+
+	  mipsxlat = get_hash_table_data (abfd, maxchain, 4, filesize);
+	  if (mipsxlat == NULL)
+	    goto error_return;
+	}
+
+      symcount = 0;
+      for (i = 0; i < ngnubuckets; ++i)
+	if (gnubuckets[i] != 0)
+	  {
+	    bfd_vma si = gnubuckets[i];
+	    bfd_vma off = si - gnusymidx;
+	    do
+	      {
+		if (mipsxlat)
+		  {
+		    if (mipsxlat[off] >= symcount)
+		      symcount = mipsxlat[off] + 1;
+		  }
+		else
+		  {
+		    if (si >= symcount)
+		      symcount = si + 1;
+		  }
+		si++;
+	      }
+	    while (off < ngnuchains && (gnuchains[off++] & 1) == 0);
+	  }
+    }
+
+  /* Swap in dynamic symbol table.  */
+  if (_bfd_mul_overflow (symcount, extsym_size, &amt))
+    {
+      bfd_set_error (bfd_error_file_too_big);
+      goto error_return;
+    }
+
+  filepos = offset_from_vma (phdrs, phnum, dt_symtab, amt);
+  if (filepos == (file_ptr) -1
+      || bfd_seek (abfd, filepos, SEEK_SET) != 0)
+    goto error_return;
+  esymbuf = _bfd_malloc_and_read (abfd, amt, amt);
+  if (esymbuf == NULL)
+    goto error_return;
+
+  if (_bfd_mul_overflow (symcount, sizeof (Elf_Internal_Sym), &amt))
+    {
+      bfd_set_error (bfd_error_file_too_big);
+      goto error_return;
+    }
+
+  /* Dynamic symbol table must be valid until ABFD is closed.  */
+  isymbuf = (Elf_Internal_Sym *) bfd_alloc (abfd, amt);
+  if (isymbuf == NULL)
+    goto error_return;
+
+  swap_symbol_in = bed->s->swap_symbol_in;
+
+  /* Convert the symbols to internal form.  */
+  isymend = isymbuf + symcount;
+  for (esym = esymbuf, isym = isymbuf;
+       isym < isymend;
+       esym += extsym_size, isym++)
+    if (!swap_symbol_in (abfd, esym, NULL, isym)
+	|| isym->st_name >= dt_strsz)
+      {
+	bfd_set_error (bfd_error_invalid_operation);
+	goto error_return;
+      }
+
+  elf_tdata (abfd)->dt_strtab = strbuf;
+  elf_tdata (abfd)->dt_symtab = isymbuf;
+  elf_tdata (abfd)->dt_symtab_count = symcount;
+
+  res = TRUE;
+
+ error_return:
+  /* Restore file position for elf_object_p.  */
+  if (bfd_seek (abfd, saved_filepos, SEEK_SET) != 0)
+    res = FALSE;
+  if (dynbuf != NULL)
+    free (dynbuf);
+  if (esymbuf != NULL)
+    free (esymbuf);
+  if (gnubuckets != NULL)
+    free (gnubuckets);
+  if (gnuchains != NULL)
+    free (gnuchains);
+  if (mipsxlat != NULL)
+    free (mipsxlat);
+  return res;
+}
+
+/* Reconstruct section from dynamic symbol.  */
+
+asection *
+_bfd_elf_get_section_from_dynamic_symbol (bfd *abfd,
+					  Elf_Internal_Sym *isym)
+{
+  asection *sec;
+  flagword flags;
+
+  if (!elf_use_dt_symtab_p (abfd))
+    return NULL;
+
+  flags = SEC_ALLOC | SEC_LOAD;
+  switch (ELF_ST_TYPE (isym->st_info))
+    {
+    case STT_FUNC:
+    case STT_GNU_IFUNC:
+      sec = bfd_get_section_by_name (abfd, ".text");
+      if (sec == NULL)
+	sec = bfd_make_section_with_flags (abfd,
+					   ".text",
+					   flags | SEC_CODE);
+      break;
+    case STT_COMMON:
+      sec = bfd_com_section_ptr;
+      break;
+    case STT_OBJECT:
+      sec = bfd_get_section_by_name (abfd, ".data");
+      if (sec == NULL)
+	sec = bfd_make_section_with_flags (abfd,
+					   ".data",
+					   flags | SEC_DATA);
+      break;
+    case STT_TLS:
+      sec = bfd_get_section_by_name (abfd, ".tdata");
+      if (sec == NULL)
+	sec = bfd_make_section_with_flags (abfd,
+					   ".tdata",
+					   (flags
+					    | SEC_DATA
+					    | SEC_THREAD_LOCAL));
+      break;
+    default:
+      sec = bfd_abs_section_ptr;
+      break;
+    }
+
+  /* NB: Don't place this section in output.  */
+  if (sec && 0)
+    sec->output_section = bfd_abs_section_ptr;
+
+  return sec;
+}
+
 /* Get version string.  */
 
 const char *
@@ -8415,6 +8905,11 @@ _bfd_elf_get_dynamic_symtab_upper_bound (bfd *abfd)
 
   if (elf_dynsymtab (abfd) == 0)
     {
+      /* Check if there is dynamic symbol table.  */
+      symcount = elf_tdata (abfd)->dt_symtab_count;
+      if (symcount)
+	goto compute_symtab_size;
+
       bfd_set_error (bfd_error_invalid_operation);
       return -1;
     }
@@ -8425,6 +8920,8 @@ _bfd_elf_get_dynamic_symtab_upper_bound (bfd *abfd)
       bfd_set_error (bfd_error_file_too_big);
       return -1;
     }
+
+ compute_symtab_size:
   symtab_size = (symcount + 1) * (sizeof (asymbol *));
   if (symcount > 0)
     symtab_size -= sizeof (asymbol *);
diff --git a/bfd/elfcode.h b/bfd/elfcode.h
index 4dde24e02a..9124015a3e 100644
--- a/bfd/elfcode.h
+++ b/bfd/elfcode.h
@@ -820,6 +820,21 @@ elf_object_p (bfd *abfd)
 	  if (bfd_bread (&x_phdr, sizeof x_phdr, abfd) != sizeof x_phdr)
 	    goto got_no_match;
 	  elf_swap_phdr_in (abfd, &x_phdr, i_phdr);
+	  if (i_phdr->p_filesz != 0)
+	    {
+	      if ((i_phdr->p_offset + i_phdr->p_filesz) > filesize)
+		goto got_no_match;
+	      /* Try to reconstruct dynamic symbol table from PT_DYNAMIC
+		 segment if there is no section header.  */
+	      if (i_phdr->p_type == PT_DYNAMIC
+		  && i_ehdrp->e_shstrndx == 0
+		  && i_ehdrp->e_shoff == 0
+		  && !_bfd_elf_get_dynamic_symbols (abfd, i_phdr,
+						    elf_tdata (abfd)->phdr,
+						    i_ehdrp->e_phnum,
+						    filesize))
+		goto got_no_match;
+	    }
 	}
     }
 
@@ -1223,7 +1238,9 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
     }
 
   ebd = get_elf_backend_data (abfd);
-  symcount = hdr->sh_size / sizeof (Elf_External_Sym);
+  symcount = elf_tdata (abfd)->dt_symtab_count;
+  if (symcount == 0)
+    symcount = hdr->sh_size / sizeof (Elf_External_Sym);
   if (symcount == 0)
     sym = symbase = NULL;
   else
@@ -1279,7 +1296,11 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
 	  memcpy (&sym->internal_elf_sym, isym, sizeof (Elf_Internal_Sym));
 
 	  sym->symbol.the_bfd = abfd;
-	  sym->symbol.name = bfd_elf_sym_name (abfd, hdr, isym, NULL);
+	  if (elf_use_dt_symtab_p (abfd))
+	    sym->symbol.name = (elf_tdata (abfd)->dt_strtab
+				+ isym->st_name);
+	  else
+	    sym->symbol.name = bfd_elf_sym_name (abfd, hdr, isym, NULL);
 	  sym->symbol.value = isym->st_value;
 
 	  if (isym->st_shndx == SHN_UNDEF)
@@ -1313,6 +1334,15 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
 		 moment) about the alignment.  */
 	      sym->symbol.value = isym->st_size;
 	    }
+	  else if (elf_use_dt_symtab_p (abfd))
+	    {
+	      asection *sec;
+	      sec = _bfd_elf_get_section_from_dynamic_symbol (abfd,
+							      isym);
+	      if (sec == NULL)
+		goto error_return;
+	      sym->symbol.section = sec;
+	    }
 	  else
 	    {
 	      sym->symbol.section
@@ -1426,14 +1456,18 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
 
   if (xverbuf != NULL)
     free (xverbuf);
-  if (isymbuf != NULL && hdr->contents != (unsigned char *) isymbuf)
+  if (isymbuf != NULL
+      && hdr->contents != (unsigned char *) isymbuf
+      && !elf_use_dt_symtab_p (abfd))
     free (isymbuf);
   return symcount;
 
  error_return:
   if (xverbuf != NULL)
     free (xverbuf);
-  if (isymbuf != NULL && hdr->contents != (unsigned char *) isymbuf)
+  if (isymbuf != NULL
+      && hdr->contents != (unsigned char *) isymbuf
+      && !elf_use_dt_symtab_p (abfd))
     free (isymbuf);
   return -1;
 }
diff --git a/bfd/elflink.c b/bfd/elflink.c
index c04712a10f..ee047889c5 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -3394,6 +3394,12 @@ elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
   if (! bfd_check_format (abfd, bfd_object))
     return FALSE;
 
+  if (elf_use_dt_symtab_p (abfd))
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return FALSE;
+    }
+
   /* Select the appropriate symbol table.  If we don't know if the
      object file is an IR object, give linker LTO plugin a chance to
      get the correct symbol table.  */
@@ -3927,6 +3933,12 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
   htab = elf_hash_table (info);
   bed = get_elf_backend_data (abfd);
 
+  if (elf_use_dt_symtab_p (abfd))
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return FALSE;
+    }
+
   if ((abfd->flags & DYNAMIC) == 0)
     dynamic = FALSE;
   else
-- 
2.24.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 3/7] readelf: Compute dynamic symbol table size from hash table
  2020-03-10  0:12 [PATCH 0/7] ELF: Omit section header on ELF objects H.J. Lu
                   ` (2 preceding siblings ...)
  2020-03-10  0:12 ` [PATCH 2/7] bfd: Improve nm and objdump without section header H.J. Lu
@ 2020-03-10  0:12 ` H.J. Lu
  2020-03-10  0:12 ` [PATCH 4/7] ld: Add a simple test for -z nosectionheader H.J. Lu
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: H.J. Lu @ 2020-03-10  0:12 UTC (permalink / raw)
  To: binutils

When reconstructing dynamic symbol table from the PT_DYNAMIC segment,
compute dynamic symbol table size from hash table.  For DT_HASH, the
number of dynamic symbol table entries equals the number of chains.
For DT_GNU_HASH/DT_MIPS_XHASH, only defined symbols with non-STB_LOCAL
indings are in hash table.  Since in dynamic symbol table, all symbols
with STB_LOCAL binding are placed before symbols with other bindings
and all undefined symbols are placed before defined ones, the highest
symbol index in DT_GNU_HASH and DT_MIPS_XHASH is the highest dynamic
symbol table index.

Also iterate dynamic symbol table to print each entry so that output
of "readelf -D -s" without section header is similar to "readelf -s"
with section header.
`
binutils/

	PR ld/25617
	* readelf.c (process_dynamic_section): Use DT_SYMTAB and DT_SYMENT
	to reconstruct dynamic symbol table, assuming dynamic symbol table
	ends at the end of PT_LOAD segment.  Use DT_STRTAB and DT_STRSZ to
	reconstruct dynamic string table.  Set dynamic_info_DT_MIPS_XHASH
	and dynamic_info_DT_GNU_HASH for -D.
	(get_symbol_index_type): Don't print "bad section index" when
	there is no section header.
	(print_dynamic_symbol): Don't print bucket number.
	(process_symbol_table): Compute dynamic symbol table size from
	hash table and iterate dynamic symbol table to print each entry.

ld/

	PR ld/25617
	* testsuite/ld-elf/hash.d: Updated.
	* testsuite/ld-elf/pr13195.d: Likewise.
	* testsuite/ld-elfvsb/hidden2.d: Likewise.
	* testsuite/ld-mips-elf/hash2.d: Likewise.
---
 binutils/readelf.c               | 226 ++++++++++++++++---------------
 ld/testsuite/ld-elf/hash.d       |   8 +-
 ld/testsuite/ld-elf/pr13195.d    |   2 +-
 ld/testsuite/ld-elfvsb/hidden2.d |   2 +-
 ld/testsuite/ld-mips-elf/hash2.d |   8 +-
 5 files changed, 125 insertions(+), 121 deletions(-)

diff --git a/binutils/readelf.c b/binutils/readelf.c
index 260ea33ba4..7ae6201c55 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -9863,102 +9863,103 @@ process_dynamic_section (Filedata * filedata)
 
   /* Find the appropriate symbol table.  */
   if (dynamic_symbols == NULL)
-    {
-      for (entry = dynamic_section;
-	   entry < dynamic_section + dynamic_nent;
-	   ++entry)
-	{
-	  Elf_Internal_Shdr section;
+    for (entry = dynamic_section;
+	 entry < dynamic_section + dynamic_nent;
+	 ++entry)
+      {
+	if (entry->d_tag == DT_SYMTAB)
+	  dynamic_info[DT_SYMTAB] = entry->d_un.d_val;
 
-	  if (entry->d_tag != DT_SYMTAB)
-	    continue;
+	if (entry->d_tag == DT_SYMENT)
+	  dynamic_info[DT_SYMENT] = entry->d_un.d_val;
 
-	  dynamic_info[DT_SYMTAB] = entry->d_un.d_val;
+	if (dynamic_info[DT_SYMTAB] && dynamic_info[DT_SYMENT])
+	  {
+	    Elf_Internal_Phdr *seg;
+	    bfd_vma vma = dynamic_info[DT_SYMTAB];
 
-	  /* Since we do not know how big the symbol table is,
-	     we default to reading in the entire file (!) and
-	     processing that.  This is overkill, I know, but it
-	     should work.  */
-	  section.sh_offset = offset_from_vma (filedata, entry->d_un.d_val, 0);
-	  if ((bfd_size_type) section.sh_offset > filedata->file_size)
-	    {
-	      /* See PR 21379 for a reproducer.  */
-	      error (_("Invalid DT_SYMTAB entry: %lx\n"),
-		     (long) section.sh_offset);
-	      return FALSE;
-	    }
+	    if (! get_program_headers (filedata))
+	      {
+		warn (_("Cannot interpret virtual addresses without program headers.\n"));
+		break;
+	      }
 
-	  if (archive_file_offset != 0)
-	    section.sh_size = archive_file_size - section.sh_offset;
-	  else
-	    section.sh_size = filedata->file_size - section.sh_offset;
+	    for (seg = filedata->program_headers;
+		 seg < filedata->program_headers + filedata->file_header.e_phnum;
+		 ++seg)
+	      {
+		if (seg->p_type != PT_LOAD)
+		  continue;
 
-	  if (is_32bit_elf)
-	    section.sh_entsize = sizeof (Elf32_External_Sym);
-	  else
-	    section.sh_entsize = sizeof (Elf64_External_Sym);
-	  section.sh_name = filedata->string_table_length;
+		if ((seg->p_offset + seg->p_filesz)
+		    > filedata->file_size)
+		  {
+		    /* See PR 21379 for a reproducer.  */
+		    error (_("Invalid PT_LOAD entry\n"));
+		    return FALSE;
+		  }
 
-	  if (dynamic_symbols != NULL)
-	    {
-	      error (_("Multiple dynamic symbol table sections found\n"));
-	      free (dynamic_symbols);
-	    }
-	  dynamic_symbols = GET_ELF_SYMBOLS (filedata, &section, & num_dynamic_syms);
-	  if (num_dynamic_syms < 1)
-	    {
-	      error (_("Unable to determine the number of symbols to load\n"));
-	      continue;
-	    }
-	}
-    }
+		if (vma >= (seg->p_vaddr & -seg->p_align)
+		    && vma <= seg->p_vaddr + seg->p_filesz)
+		  {
+		    /* Since we do not know how big the symbol table is,
+		       we default to reading in up to the end of PT_LOAD
+		       segment and processing that.  This is overkill, I
+		       know, but it should work.  */
+		    Elf_Internal_Shdr section;
+		    bfd_size_type offset = (vma - seg->p_vaddr
+					    + seg->p_offset);
+		    bfd_size_type max_symtab_size
+		      = seg->p_offset + seg->p_filesz - offset;
+		    section.sh_offset = offset;
+		    section.sh_size = max_symtab_size;
+		    section.sh_entsize = dynamic_info[DT_SYMENT];
+		    section.sh_name = filedata->string_table_length;
+		    dynamic_symbols = GET_ELF_SYMBOLS (filedata,
+						       &section,
+						       & num_dynamic_syms);
+		    if (dynamic_symbols == NULL)
+		      error (_("Corrupt DT_SYMTAB dynamic entry\n"));
+		  }
+	      }
+
+	    break;
+	  }
+      }
 
   /* Similarly find a string table.  */
   if (dynamic_strings == NULL)
-    {
-      for (entry = dynamic_section;
-	   entry < dynamic_section + dynamic_nent;
-	   ++entry)
-	{
-	  unsigned long offset;
-	  long str_tab_len;
-
-	  if (entry->d_tag != DT_STRTAB)
-	    continue;
-
+    for (entry = dynamic_section;
+	 entry < dynamic_section + dynamic_nent;
+	 ++entry)
+      {
+	if (entry->d_tag == DT_STRTAB)
 	  dynamic_info[DT_STRTAB] = entry->d_un.d_val;
 
-	  /* Since we do not know how big the string table is,
-	     we default to reading in the entire file (!) and
-	     processing that.  This is overkill, I know, but it
-	     should work.  */
+	if (entry->d_tag == DT_STRSZ)
+	  dynamic_info[DT_STRSZ] = entry->d_un.d_val;
 
-	  offset = offset_from_vma (filedata, entry->d_un.d_val, 0);
-
-	  if (archive_file_offset != 0)
-	    str_tab_len = archive_file_size - offset;
-	  else
-	    str_tab_len = filedata->file_size - offset;
-
-	  if (str_tab_len < 1)
-	    {
-	      error
-		(_("Unable to determine the length of the dynamic string table\n"));
-	      continue;
-	    }
-
-	  if (dynamic_strings != NULL)
-	    {
-	      error (_("Multiple dynamic string tables found\n"));
-	      free (dynamic_strings);
-	    }
+	if (dynamic_info[DT_STRTAB] && dynamic_info[DT_STRSZ])
+	  {
+	    unsigned long offset;
+	    bfd_size_type str_tab_len = dynamic_info[DT_STRSZ];
+
+	    offset = offset_from_vma (filedata,
+				      dynamic_info[DT_STRTAB],
+				      str_tab_len);
+	    dynamic_strings = (char *) get_data (NULL, filedata, offset, 1,
+						 str_tab_len,
+						 _("dynamic string table"));
+	    if (dynamic_strings == NULL)
+	      {
+		error (_("Corrupt DT_STRTAB dynamic entry\n"));
+		break;
+	      }
 
-	  dynamic_strings = (char *) get_data (NULL, filedata, offset, 1,
-                                               str_tab_len,
-                                               _("dynamic string table"));
-	  dynamic_strings_length = dynamic_strings == NULL ? 0 : str_tab_len;
-	}
-    }
+	    dynamic_strings_length = str_tab_len;
+	    break;
+	  }
+      }
 
   /* And find the syminfo section if available.  */
   if (dynamic_syminfo == NULL)
@@ -10515,6 +10516,14 @@ process_dynamic_section (Filedata * filedata)
 		  putchar ('\n');
 		}
 	    }
+	  else if (do_using_dynamic
+		   && (filedata->file_header.e_machine == EM_MIPS
+		       || filedata->file_header.e_machine == EM_MIPS_RS3_LE)
+		   && entry->d_tag == DT_MIPS_XHASH)
+	    {
+	      dynamic_info_DT_MIPS_XHASH = entry->d_un.d_val;
+	      dynamic_info_DT_GNU_HASH = entry->d_un.d_val;
+	    }
 	  break;
 	}
     }
@@ -11401,7 +11410,8 @@ get_symbol_index_type (Filedata * filedata, unsigned int type)
 	sprintf (buff, "OS [0x%04x]", type & 0xffff);
       else if (type >= SHN_LORESERVE)
 	sprintf (buff, "RSV[0x%04x]", type & 0xffff);
-      else if (type >= filedata->file_header.e_shnum)
+      else if (filedata->file_header.e_shnum != 0
+	       && type >= filedata->file_header.e_shnum)
 	sprintf (buff, _("bad section index[%3d]"), type);
       else
 	sprintf (buff, "%3d", type);
@@ -11471,7 +11481,7 @@ get_dynamic_data (Filedata * filedata, bfd_size_type number, unsigned int ent_si
 }
 
 static void
-print_dynamic_symbol (Filedata * filedata, bfd_vma si, unsigned long hn)
+print_dynamic_symbol (Filedata * filedata, bfd_vma si)
 {
   Elf_Internal_Sym * psym;
   int n;
@@ -11479,7 +11489,7 @@ print_dynamic_symbol (Filedata * filedata, bfd_vma si, unsigned long hn)
   n = print_vma (si, DEC_5);
   if (n < 5)
     fputs (&"     "[n], stdout);
-  printf (" %3lu: ", hn);
+  fputs (": ", stdout);
 
   if (dynamic_symbols == NULL || si >= num_dynamic_syms)
     {
@@ -11915,41 +11925,26 @@ process_symbol_table (Filedata * filedata)
 
       if (dynamic_info[DT_HASH])
 	{
-	  bfd_vma si;
-	  char *visited;
-
 	  printf (_("\nSymbol table for image:\n"));
 	  if (is_32bit_elf)
-	    printf (_("  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name\n"));
+	    printf (_("  Num:    Value  Size Type    Bind   Vis     Ndx Name\n"));
 	  else
-	    printf (_("  Num Buc:    Value          Size   Type   Bind Vis      Ndx Name\n"));
+	    printf (_("  Num:    Value          Size Type    Bind   Vis     Ndx Name\n"));
 
-	  visited = xcmalloc (nchains, 1);
-	  memset (visited, 0, nchains);
-	  for (hn = 0; hn < nbuckets; hn++)
-	    {
-	      for (si = buckets[hn]; si > 0; si = chains[si])
-		{
-		  print_dynamic_symbol (filedata, si, hn);
-		  if (si >= nchains || visited[si])
-		    {
-		      error (_("histogram chain is corrupt\n"));
-		      break;
-		    }
-		  visited[si] = 1;
-		}
-	    }
-	  free (visited);
+	  for (hn = 0; hn < nchains; hn++)
+	    print_dynamic_symbol (filedata, hn);
 	}
 
       if (dynamic_info_DT_GNU_HASH)
 	{
+	  unsigned long num_of_syms = 0;
+
 	  printf (_("\nSymbol table of `%s' for image:\n"),
 		  GNU_HASH_SECTION_NAME);
 	  if (is_32bit_elf)
-	    printf (_("  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name\n"));
+	    printf (_("  Num:    Value  Size Type    Bind   Vis     Ndx Name\n"));
 	  else
-	    printf (_("  Num Buc:    Value          Size   Type   Bind Vis      Ndx Name\n"));
+	    printf (_("  Num:    Value          Size Type    Bind   Vis     Ndx Name\n"));
 
 	  for (hn = 0; hn < ngnubuckets; ++hn)
 	    if (gnubuckets[hn] != 0)
@@ -11960,13 +11955,22 @@ process_symbol_table (Filedata * filedata)
 		do
 		  {
 		    if (dynamic_info_DT_MIPS_XHASH)
-		      print_dynamic_symbol (filedata, mipsxlat[off], hn);
+		      {
+			if (mipsxlat[off] >= num_of_syms)
+			  num_of_syms = mipsxlat[off] + 1;
+		      }
 		    else
-		      print_dynamic_symbol (filedata, si, hn);
+		      {
+			if (si >= num_of_syms)
+			  num_of_syms = si + 1;
+		      }
 		    si++;
 		  }
 		while (off < ngnuchains && (gnuchains[off++] & 1) == 0);
 	      }
+
+	  for (hn = 0; hn < num_of_syms; hn++)
+	    print_dynamic_symbol (filedata, hn);
 	}
     }
   else if ((do_dyn_syms || (do_syms && !do_using_dynamic))
diff --git a/ld/testsuite/ld-elf/hash.d b/ld/testsuite/ld-elf/hash.d
index efe675e0c7..a0bebb0b00 100644
--- a/ld/testsuite/ld-elf/hash.d
+++ b/ld/testsuite/ld-elf/hash.d
@@ -9,11 +9,11 @@
 #...
  +0x[0-9a-z]+ +\(GNU_HASH\) +0x[0-9a-z]+
 #...
- +[0-9]+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +NOTYPE +GLOBAL +DEFAULT +[1-9] _start
+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +NOTYPE +GLOBAL +DEFAULT +[1-9] _start
 #...
- +[0-9]+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +NOTYPE +GLOBAL +DEFAULT +[1-9] main
+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +NOTYPE +GLOBAL +DEFAULT +[1-9] main
 #...
- +[0-9]+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +NOTYPE +GLOBAL +DEFAULT +[1-9] start
+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +NOTYPE +GLOBAL +DEFAULT +[1-9] start
 #...
- +[0-9]+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +NOTYPE +GLOBAL +DEFAULT +[1-9] __start
+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +NOTYPE +GLOBAL +DEFAULT +[1-9] __start
 #...
diff --git a/ld/testsuite/ld-elf/pr13195.d b/ld/testsuite/ld-elf/pr13195.d
index 8a0f9bd805..fb02e22afa 100644
--- a/ld/testsuite/ld-elf/pr13195.d
+++ b/ld/testsuite/ld-elf/pr13195.d
@@ -5,5 +5,5 @@
 # generic linker targets don't support --gc-sections, nor do a bunch of others
 
 #...
- +[0-9]+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +FUNC +GLOBAL +DEFAULT +[1-9]+ foo
+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +FUNC +GLOBAL +DEFAULT +[1-9]+ foo
 #pass
diff --git a/ld/testsuite/ld-elfvsb/hidden2.d b/ld/testsuite/ld-elfvsb/hidden2.d
index 72a42d57bc..8fe2da65b9 100644
--- a/ld/testsuite/ld-elfvsb/hidden2.d
+++ b/ld/testsuite/ld-elfvsb/hidden2.d
@@ -5,5 +5,5 @@
 
 Symbol table for image:
 #...
-[ 	]*[0-9]+ +[0-9]+: [0-9a-fA-F]* +0 +OBJECT +LOCAL +DEFAULT .* foo
+[ 	]*[0-9]+: [0-9a-fA-F]* +0 +OBJECT +LOCAL +DEFAULT .* foo
 #pass
diff --git a/ld/testsuite/ld-mips-elf/hash2.d b/ld/testsuite/ld-mips-elf/hash2.d
index 122edb80e1..a0fe4266f2 100644
--- a/ld/testsuite/ld-mips-elf/hash2.d
+++ b/ld/testsuite/ld-mips-elf/hash2.d
@@ -6,11 +6,11 @@
 #...
  +0x[0-9a-z]+ +\(MIPS_XHASH\) +0x[0-9a-z]+
 #...
- +[0-9]+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +FUNC +GLOBAL +DEFAULT +([1-9]|PRC) _start
+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +FUNC +GLOBAL +DEFAULT +([1-9]|PRC) __start
 #...
- +[0-9]+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +FUNC +GLOBAL +DEFAULT +([1-9]|PRC) main
+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +FUNC +GLOBAL +DEFAULT +([1-9]|PRC) _start
 #...
- +[0-9]+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +FUNC +GLOBAL +DEFAULT +([1-9]|PRC) start
+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +FUNC +GLOBAL +DEFAULT +([1-9]|PRC) main
 #...
- +[0-9]+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +FUNC +GLOBAL +DEFAULT +([1-9]|PRC) __start
+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +FUNC +GLOBAL +DEFAULT +([1-9]|PRC) start
 #...
-- 
2.24.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 4/7] ld: Add a simple test for -z nosectionheader
  2020-03-10  0:12 [PATCH 0/7] ELF: Omit section header on ELF objects H.J. Lu
                   ` (3 preceding siblings ...)
  2020-03-10  0:12 ` [PATCH 3/7] readelf: Compute dynamic symbol table size from hash table H.J. Lu
@ 2020-03-10  0:12 ` H.J. Lu
  2020-03-10  0:12 ` [PATCH 5/7] binutils: Add --remove-section-header tests H.J. Lu
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: H.J. Lu @ 2020-03-10  0:12 UTC (permalink / raw)
  To: binutils; +Cc: Kaylee Blake

From: Kaylee Blake <klkblake@gmail.com>

2020-03-XX  Kaylee Blake  <klkblake@gmail.com>

	PR ld/25617
	* testsuite/ld-elf/nosectionheader.d: New file.
---
 ld/testsuite/ld-elf/nosectionheader.d | 12 ++++++++++++
 1 file changed, 12 insertions(+)
 create mode 100644 ld/testsuite/ld-elf/nosectionheader.d

diff --git a/ld/testsuite/ld-elf/nosectionheader.d b/ld/testsuite/ld-elf/nosectionheader.d
new file mode 100644
index 0000000000..7154e095e1
--- /dev/null
+++ b/ld/testsuite/ld-elf/nosectionheader.d
@@ -0,0 +1,12 @@
+#source: start.s
+#ld: -z nosectionheader
+#readelf: -h -S
+
+#...
+  Start of section headers:[ \t]+0 \(bytes into file\)
+#...
+  Size of section headers:[ \t]+0 \(bytes\)
+  Number of section headers:[ \t]+0
+  Section header string table index:[ \t]+0
+
+There are no sections in this file.
-- 
2.24.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 5/7] binutils: Add --remove-section-header tests
  2020-03-10  0:12 [PATCH 0/7] ELF: Omit section header on ELF objects H.J. Lu
                   ` (4 preceding siblings ...)
  2020-03-10  0:12 ` [PATCH 4/7] ld: Add a simple test for -z nosectionheader H.J. Lu
@ 2020-03-10  0:12 ` H.J. Lu
  2020-03-10  0:12 ` [PATCH 6/7] ld: Add tests for -z nosectionheader and --remove-section-header H.J. Lu
  2020-03-10  0:12 ` [PATCH 7/7] ld: Add -z nosectionheader test to bootstrap.exp H.J. Lu
  7 siblings, 0 replies; 11+ messages in thread
From: H.J. Lu @ 2020-03-10  0:12 UTC (permalink / raw)
  To: binutils

Verify --remove-section-header with objcopy and strip is ignored for
relocatable file.

	PR ld/25617
	* testsuite/binutils-all/objcopy.exp: Verify
	--remove-section-header ignored for relocatable file.
	* testsuite/binutils-all/remove-header-1.d: New file.
---
 binutils/testsuite/binutils-all/objcopy.exp       | 13 +++++++++++++
 binutils/testsuite/binutils-all/remove-header-1.d |  8 ++++++++
 2 files changed, 21 insertions(+)
 create mode 100644 binutils/testsuite/binutils-all/remove-header-1.d

diff --git a/binutils/testsuite/binutils-all/objcopy.exp b/binutils/testsuite/binutils-all/objcopy.exp
index 549b064e96..11bb8fea84 100644
--- a/binutils/testsuite/binutils-all/objcopy.exp
+++ b/binutils/testsuite/binutils-all/objcopy.exp
@@ -1115,6 +1115,13 @@ if [is_elf_format] {
 	run_dump_test "note-6-32"
     }
     run_dump_test "note-5"
+
+    set saved_OBJCOPYFLAGS $OBJCOPYFLAGS
+    append OBJCOPYFLAGS " --remove-section-header"
+
+    objcopy_test "simple copy with --remove-section-header" bintest.s
+
+    set OBJCOPYFLAGS $saved_OBJCOPYFLAGS
 }
 
 run_dump_test "copy-2"
@@ -1231,6 +1238,12 @@ if [is_elf_format] {
         verbose [file rootname $t]
         run_dump_test [file rootname $t]
     }
+
+    # Test --remove-section-header
+    run_dump_test "remove-header-1" \
+			[list \
+			  [list source strip-15${reloc_format}.s] \
+			  [list as "${elf64} --defsym RELOC=${reloc}"]]
 }
 run_dump_test "localize-hidden-2"
 
diff --git a/binutils/testsuite/binutils-all/remove-header-1.d b/binutils/testsuite/binutils-all/remove-header-1.d
new file mode 100644
index 0000000000..60a9c407af
--- /dev/null
+++ b/binutils/testsuite/binutils-all/remove-header-1.d
@@ -0,0 +1,8 @@
+#PROG: strip
+#strip: -g --remove-section-header
+#readelf: -r
+
+Relocation section '\.rela?\.text' at offset .* contains 2 entries:
+ *Offset * Info * Type * Sym\. *Value * Sym\. *Name(?: * \+ * Addend)?
+0+00 * 0+0(?:1|b|32|103) * R_[^ ]* *(?: * 55aa)?
+#pass
-- 
2.24.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 6/7] ld: Add tests for -z nosectionheader and --remove-section-header
  2020-03-10  0:12 [PATCH 0/7] ELF: Omit section header on ELF objects H.J. Lu
                   ` (5 preceding siblings ...)
  2020-03-10  0:12 ` [PATCH 5/7] binutils: Add --remove-section-header tests H.J. Lu
@ 2020-03-10  0:12 ` H.J. Lu
  2020-03-10  0:12 ` [PATCH 7/7] ld: Add -z nosectionheader test to bootstrap.exp H.J. Lu
  7 siblings, 0 replies; 11+ messages in thread
From: H.J. Lu @ 2020-03-10  0:12 UTC (permalink / raw)
  To: binutils

Add tests to verify that the linker option, -z nosectionheader and
objcopy and strip option, --remove-section-header, work correctly
as well as linker issues an error when dynamic symbol table from
PT_DYNAMIC segment is used.

	PR ld/25617
	* testsuite/ld-elf/no-section-header.exp: New file.
	* testsuite/ld-elf/pr25617-1-no-sec-hdr.nd: Likewise.
	* testsuite/ld-elf/pr25617-1-no-sec-hdr.rd: Likewise.
	* testsuite/ld-elf/pr25617-1-static-no-sec-hdr.rd: Likewise.
	* testsuite/ld-elf/pr25617-1a-no-sec-hdr.nd: Likewise.
	* testsuite/ld-elf/pr25617-1a-no-sec-hdr.rd: Likewise.
	* testsuite/ld-elf/pr25617-1a-sec-hdr.rd: Likewise.
	* testsuite/ld-elf/pr25617-1a.c: Likewise.
	* testsuite/ld-elf/pr25617-1b.c: Likewise.
	* testsuite/ld-elf/start-noheader.rd: Likewise.
	* testsuite/ld-elf/start-shared-noheader-gnu.rd: Likewise.
	* testsuite/ld-elf/start-shared-noheader-sysv.rd: Likewise.
	* testsuite/ld-elf/start-shared-noheader.nd: Likewise.
---
 ld/testsuite/ld-elf/no-section-header.exp     | 374 ++++++++++++++++++
 ld/testsuite/ld-elf/pr25617-1-no-sec-hdr.nd   |   3 +
 ld/testsuite/ld-elf/pr25617-1-no-sec-hdr.rd   |  20 +
 .../ld-elf/pr25617-1-static-no-sec-hdr.rd     |  12 +
 ld/testsuite/ld-elf/pr25617-1a-no-sec-hdr.nd  |   3 +
 ld/testsuite/ld-elf/pr25617-1a-no-sec-hdr.rd  |  20 +
 ld/testsuite/ld-elf/pr25617-1a-sec-hdr.rd     |  19 +
 ld/testsuite/ld-elf/pr25617-1a.c              |  11 +
 ld/testsuite/ld-elf/pr25617-1b.c              |  15 +
 ld/testsuite/ld-elf/start-noheader.rd         |  11 +
 .../ld-elf/start-shared-noheader-gnu.rd       |  22 ++
 .../ld-elf/start-shared-noheader-sysv.rd      |  22 ++
 ld/testsuite/ld-elf/start-shared-noheader.nd  |   5 +
 13 files changed, 537 insertions(+)
 create mode 100644 ld/testsuite/ld-elf/no-section-header.exp
 create mode 100644 ld/testsuite/ld-elf/pr25617-1-no-sec-hdr.nd
 create mode 100644 ld/testsuite/ld-elf/pr25617-1-no-sec-hdr.rd
 create mode 100644 ld/testsuite/ld-elf/pr25617-1-static-no-sec-hdr.rd
 create mode 100644 ld/testsuite/ld-elf/pr25617-1a-no-sec-hdr.nd
 create mode 100644 ld/testsuite/ld-elf/pr25617-1a-no-sec-hdr.rd
 create mode 100644 ld/testsuite/ld-elf/pr25617-1a-sec-hdr.rd
 create mode 100644 ld/testsuite/ld-elf/pr25617-1a.c
 create mode 100644 ld/testsuite/ld-elf/pr25617-1b.c
 create mode 100644 ld/testsuite/ld-elf/start-noheader.rd
 create mode 100644 ld/testsuite/ld-elf/start-shared-noheader-gnu.rd
 create mode 100644 ld/testsuite/ld-elf/start-shared-noheader-sysv.rd
 create mode 100644 ld/testsuite/ld-elf/start-shared-noheader.nd

diff --git a/ld/testsuite/ld-elf/no-section-header.exp b/ld/testsuite/ld-elf/no-section-header.exp
new file mode 100644
index 0000000000..5211fc54d9
--- /dev/null
+++ b/ld/testsuite/ld-elf/no-section-header.exp
@@ -0,0 +1,374 @@
+# Expect script for --remove-section-header tests
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Written by H.J. Lu (hongjiu.lu@intel.com)
+#
+
+# Make sure that binutils can correctly handle ld output in ELF.
+
+if { ![istarget *-*-linux*] } {
+    return
+}
+
+proc binutils_test { prog_name ld_options test readelf_expected nm_expected} {
+    global as
+    global ld
+    global READELF
+    global NM
+    global objcopy
+    global strip
+    global srcdir
+    global subdir
+    global link_output
+
+    eval set prog \$$prog_name
+
+    set test_name "$prog_name --remove-section-header $ld_options ($test)"
+
+    if { ![ld_assemble $as $srcdir/$subdir/$test.s tmpdir/$test.o ] } {
+	unresolved "$test_name"
+	return
+    }
+
+    append ld_options " -z separate-code -z stack-size=0"
+    if { ![ld_link $ld tmpdir/$test "$ld_options tmpdir/$test.o"] } {
+	if { [string match "*not supported*" $link_output]
+	     || [string match "*unrecognized option*" $link_output]
+	     || [string match "*-z .* ignored*" $link_output] } {
+	    unsupported "$ld_options is not supported by this target"
+	} else {
+	    unresolved "$test_name"
+	}
+	return
+    }
+
+    send_log "$prog --remove-section-header tmpdir/$test\n"
+    set got [remote_exec host "$prog --remove-section-header tmpdir/$test"]
+    if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+	send_log "$got\n"
+	fail "$test_name"
+	return
+    }
+
+    send_log "$READELF -lSDs --wide tmpdir/$test > tmpdir/$test.out\n"
+    set got [remote_exec host "$READELF -lSDs --wide tmpdir/$test" "" "/dev/null" "tmpdir/$test.out"]
+    if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+	send_log "$got\n"
+	unresolved "$test_name"
+	return
+    }
+
+    if { [regexp_diff "tmpdir/$test.out" "$srcdir/$subdir/$readelf_expected"] } then {
+	fail "$test_name"
+	return
+    }
+
+    if { [string match "*-shared *" $ld_options] } {
+	send_log "$NM -D tmpdir/$test > tmpdir/$test.out\n"
+	set got [remote_exec host "$NM -D tmpdir/$test" "" "/dev/null" "tmpdir/$test.out"]
+	if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+	    send_log "$got\n"
+	    unresolved "$test_name"
+	    return
+	}
+
+	if { [regexp_diff "tmpdir/$test.out" "$srcdir/$subdir/$nm_expected"] } then {
+	    fail "$test_name"
+	    return
+	}
+    }
+
+    pass "$test_name"
+}
+
+if { [istarget "mips*-*-*"] } {
+    set gnu_hash_style "sysv"
+} else {
+    set gnu_hash_style "gnu"
+}
+
+binutils_test objcopy "--hash-style=both" start start-noheader.rd \
+	start-noheader.nd
+binutils_test objcopy "--hash-style=gnu" start start-noheader.rd \
+	start-noheader.nd
+binutils_test objcopy "--hash-style=sysv" start start-noheader.rd \
+	start-noheader.nd
+binutils_test objcopy "--hash-style=both -shared" start \
+	start-shared-noheader-$gnu_hash_style.rd start-shared-noheader.nd
+binutils_test objcopy "--hash-style=gnu -shared" start \
+	start-shared-noheader-$gnu_hash_style.rd start-shared-noheader.nd
+binutils_test objcopy "--hash-style=sysv -shared" start \
+	start-shared-noheader-sysv.rd start-shared-noheader.nd
+binutils_test strip "--hash-style=both" start start-noheader.rd \
+	start-noheader.nd
+binutils_test strip "--hash-style=gnu" start start-noheader.rd \
+	start-noheader.nd
+binutils_test strip "--hash-style=sysv" start start-noheader.rd \
+	start-noheader.nd
+binutils_test strip "--hash-style=both -shared" start \
+	start-shared-noheader-$gnu_hash_style.rd start-shared-noheader.nd
+binutils_test strip "--hash-style=gnu -shared" start \
+	start-shared-noheader-$gnu_hash_style.rd start-shared-noheader.nd
+binutils_test strip "--hash-style=sysv -shared" start \
+	start-shared-noheader-sysv.rd start-shared-noheader.nd
+
+# Skip non-native targets or -shared is not supported.
+if { ![isnative] || ![check_shared_lib_support] } {
+    return
+}
+
+proc binutils_run_test { prog } {
+    global CC
+    global gcc_B_opt
+    global READELF
+    global NM
+    global objcopy
+    global strip
+    global srcdir
+    global subdir
+    # Add $NOPIE_CFLAGS and $NOPIE_LDFLAGS if non-PIE is required.
+    global NOPIE_CFLAGS NOPIE_LDFLAGS
+
+    set sec_hdr "sec-hdr"
+    if { "$prog" == "" } {
+	set prog_name none
+    } else {
+	set prog_name $prog
+	set ld_options ""
+	switch -- $prog {
+	    objcopy
+	        { set prog $objcopy }
+	    strip
+	        { set prog $strip }
+	    default
+		{
+		    fail "Build pr25617-1a-no-sec-hdr.so ($prog_name)"
+		    break
+		}
+	}
+    }
+
+    run_cc_link_tests [list \
+	[list \
+	    "Build pr25617-1a-no-sec-hdr.so ($prog_name)" \
+	    "-shared -Wl,-z,separate-code,--hash-style=sysv" \
+	    "-fPIC" \
+	    {pr25617-1a.c} \
+	    [list \
+		[list "readelf" "-lWSDs" "pr25617-1a-$sec_hdr.rd"] \
+		[list "nm" "-Ds" "pr25617-1a-no-sec-hdr.nd"] \
+	    ]\
+	    "pr25617-1a-no-sec-hdr.so" \
+	] \
+	[list \
+	    "Build pr25617-1a-now-no-sec-hdr.so ($prog_name)" \
+	    "-shared -Wl,-z,separate-code,-z,now,--hash-style=gnu" \
+	    "-fPIC" \
+	    {pr25617-1a.c} \
+	    [list \
+		[list "readelf" "-lWSDs" "pr25617-1a-$sec_hdr.rd"] \
+		[list "nm" "-Ds" "pr25617-1a-no-sec-hdr.nd"] \
+	    ]\
+	    "pr25617-1a-now-no-sec-hdr.so" \
+	] \
+	[list \
+	    "Build pr25617-1 (-z nosectionheader, $prog_name)" \
+	    "$NOPIE_LDFLAGS -Wl,-z,separate-code,--no-as-needed \
+	     -Wl,--hash-style=sysv -Wl,-z,nosectionheader \
+	     tmpdir/pr25617-1a-no-sec-hdr.so" \
+	    "$NOPIE_CFLAGS" \
+	    {pr25617-1b.c} \
+	    {{readelf -lWSDs pr25617-1-no-sec-hdr.rd} \
+	     {nm -Ds pr25617-1-no-sec-hdr.nd}} \
+	    "pr25617-1-no-sec-hdr" \
+	] \
+	[list \
+	    "Build pr25617-1 (PIE, -z nosectionheader, $prog_name)" \
+	    "-pie -Wl,-z,separate-code,--no-as-needed,--hash-style=gnu \
+	     -Wl,-z,nosectionheader tmpdir/pr25617-1a-now-no-sec-hdr.so" \
+	    "-fPIE" \
+	    {pr25617-1b.c} \
+	    {{readelf -lWSDs pr25617-1-no-sec-hdr.rd} \
+	     {nm -Ds pr25617-1-no-sec-hdr.nd}} \
+	    "pr25617-1-pie-no-sec-hdr" \
+	] \
+	[list \
+	    "Build pr25617-1 (static, -z nosectionheader, $prog_name)" \
+	    "-static -Wl,-z,separate-code -Wl,-z,nosectionheader" \
+	    "" \
+	    {pr25617-1a.c pr25617-1b.c} \
+	    {{readelf -lSWDs pr25617-1-static-no-sec-hdr.rd}} \
+	    "pr25617-1-static-no-sec-hdr" \
+	] \
+    ]
+
+    run_ld_link_exec_tests [list \
+	[list \
+	    "Run pr25617-1 (-z nosectionheader, $prog_name)" \
+	    "$NOPIE_LDFLAGS -Wl,-z,separate-code,--no-as-needed \
+	     -Wl,--hash-style=sysv -Wl,-z,nosectionheader \
+	     tmpdir/pr25617-1a-no-sec-hdr.so" \
+	    "" \
+	    {pr25617-1b.c} \
+	    "pr25617-1-no-sec-hdr" \
+	    "pass.out" \
+	    "$NOPIE_CFLAGS" \
+	] \
+	[list \
+	    "Run pr25617-1 (PIE, -z nosectionheader, $prog_name)" \
+	    "-pie -Wl,-z,separate-code,--no-as-needed,--hash-style=gnu \
+	     -Wl,-z,nosectionheader tmpdir/pr25617-1a-now-no-sec-hdr.so" \
+	    "" \
+	    {pr25617-1b.c} \
+	    "pr25617-1-pie-no-sec-hdr" \
+	    "pass.out" \
+	    "-fPIE" \
+	] \
+	[list \
+	    "Run pr25617-1 (static, -z nosectionheader, $prog_name)" \
+	    "-static -Wl,-z,separate-code -Wl,-z,nosectionheader" \
+	    "" \
+	    {pr25617-1a.c pr25617-1b.c} \
+	    "pr25617-1-static-no-sec-hdr" \
+	    "pass.out" \
+	] \
+    ]
+
+    if { "$prog_name" != "none" } {
+	send_log "$prog --remove-section-header tmpdir/pr25617-1a-no-sec-hdr.so\n"
+	set got [remote_exec host "$prog --remove-section-header tmpdir/pr25617-1a-no-sec-hdr.so"]
+	if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+	    send_log "$got\n"
+	    fail "Update pr25617-1a-no-sec-hdr.so ($prog_name)"
+	    return
+	}
+
+	send_log "$READELF -lWSDs tmpdir/pr25617-1a-no-sec-hdr.so > tmpdir/dump.out\n"
+	set got [remote_exec host "$READELF -lWSDs tmpdir/pr25617-1a-no-sec-hdr.so" "" "/dev/null" "tmpdir/dump.out"]
+	if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+	    send_log "$got\n"
+	    unresolved "Update pr25617-1a-no-sec-hdr.so ($prog_name)"
+	    return
+	}
+
+	if { [regexp_diff "tmpdir/dump.out" "$srcdir/$subdir/pr25617-1a-no-sec-hdr.rd"] } then {
+	    unresolved "Update pr25617-1a-no-sec-hdr.so ($prog_name)"
+	    return
+	}
+
+	send_log "$NM -Ds tmpdir/pr25617-1a-no-sec-hdr.so > tmpdir/dump.out\n"
+	set got [remote_exec host "$NM -Ds tmpdir/pr25617-1a-no-sec-hdr.so" "" "/dev/null" "tmpdir/dump.out"]
+	if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+	    send_log "$got\n"
+	    unresolved "Update pr25617-1a-no-sec-hdr.so ($prog_name)"
+	    return
+	}
+
+	if { [regexp_diff "tmpdir/dump.out" "$srcdir/$subdir/pr25617-1a-no-sec-hdr.nd"] } then {
+	    unresolved "Update pr25617-1a-no-sec-hdr.so ($prog_name)"
+	    return
+	}
+
+	send_log "tmpdir/pr25617-1-no-sec-hdr > tmpdir/pr25617-1.out\n"
+	catch "exec tmpdir/pr25617-1-no-sec-hdr > tmpdir/pr25617-1.out" got
+	if ![string match "" $got] then {
+	    send_log "$got\n"
+	    unresolved "Update pr25617-1a-no-sec-hdr.so ($prog_name)"
+	    return
+	}
+
+	send_log "diff tmpdir/pr25617-1.out $srcdir/$subdir/pass.out\n"
+	catch "exec diff tmpdir/pr25617-1.out $srcdir/$subdir/pass.out" got
+	if ![string match "" $got] then {
+	    send_log "$got\n"
+	    fail "Update pr25617-1a-no-sec-hdr.so ($prog_name)"
+	    return
+	}
+
+	pass "Update pr25617-1a-no-sec-hdr.so ($prog_name)"
+
+	send_log "$prog --remove-section-header tmpdir/pr25617-1a-now-no-sec-hdr.so\n"
+	set got [remote_exec host "$prog --remove-section-header tmpdir/pr25617-1a-now-no-sec-hdr.so"]
+	if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+	    send_log "$got\n"
+	    fail "Update pr25617-1a-now-no-sec-hdr.so ($prog_name)"
+	    return
+	}
+
+	send_log "$READELF -lWSDs tmpdir/pr25617-1a-now-no-sec-hdr.so > tmpdir/dump.out\n"
+	set got [remote_exec host "$READELF -lWSDs tmpdir/pr25617-1a-now-no-sec-hdr.so" "" "/dev/null" "tmpdir/dump.out"]
+	if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+	    send_log "$got\n"
+	    unresolved "Update pr25617-1a-now-no-sec-hdr.so ($prog_name)"
+	    return
+	}
+
+	if { [regexp_diff "tmpdir/dump.out" "$srcdir/$subdir/pr25617-1a-no-sec-hdr.rd"] } then {
+	    unresolved "Update pr25617-1a-now-no-sec-hdr.so ($prog_name)"
+	    return
+	}
+
+	send_log "$NM -Ds tmpdir/pr25617-1a-now-no-sec-hdr.so > tmpdir/dump.out\n"
+	set got [remote_exec host "$NM -Ds tmpdir/pr25617-1a-now-no-sec-hdr.so" "" "/dev/null" "tmpdir/dump.out"]
+	if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+	    send_log "$got\n"
+	    unresolved "Update pr25617-1a-now-no-sec-hdr.so ($prog_name)"
+	    return
+	}
+
+	if { [regexp_diff "tmpdir/dump.out" "$srcdir/$subdir/pr25617-1a-no-sec-hdr.nd"] } then {
+	    unresolved "Update pr25617-1a-now-no-sec-hdr.so ($prog_name)"
+	    return
+	}
+
+	send_log "tmpdir/pr25617-1-pie-no-sec-hdr > tmpdir/pr25617-1-pie.out\n"
+	catch "exec tmpdir/pr25617-1-pie-no-sec-hdr > tmpdir/pr25617-1-pie.out" got
+	if ![string match "" $got] then {
+	    send_log "$got\n"
+	    unresolved "Update pr25617-1a-now-no-sec-hdr.so ($prog_name)"
+	    return
+	}
+
+	send_log "diff tmpdir/pr25617-1-pie.out $srcdir/$subdir/pass.out\n"
+	catch "exec diff tmpdir/pr25617-1-pie.out $srcdir/$subdir/pass.out" got
+	if ![string match "" $got] then {
+	    send_log "$got\n"
+	    fail "Update pr25617-1a-now-no-sec-hdr.so ($prog_name)"
+	    return
+	}
+
+	send_log "$CC $gcc_B_opt -o tmpdir/pr25617-1 tmpdir/pr25617-1b.o tmpdir/pr25617-1a-now-no-sec-hdr.so\n"
+	catch "exec $CC $gcc_B_opt -o tmpdir/pr25617-1 tmpdir/pr25617-1b.o tmpdir/pr25617-1a-now-no-sec-hdr.so" got
+	if ![string match "*pr25617-1a-now-no-sec-hdr.so*file in wrong format*" $got] then {
+	    send_log "$got\n"
+	    fail "Update pr25617-1a-now-no-sec-hdr.so ($prog_name)"
+	}
+
+	pass "Update pr25617-1a-now-no-sec-hdr.so ($prog_name)"
+     }
+}
+
+if { [istarget *-*-linux*]
+     || [istarget *-*-nacl*]
+     || [istarget *-*-gnu*] } {
+    binutils_run_test ""
+    binutils_run_test objcopy
+    binutils_run_test strip
+}
diff --git a/ld/testsuite/ld-elf/pr25617-1-no-sec-hdr.nd b/ld/testsuite/ld-elf/pr25617-1-no-sec-hdr.nd
new file mode 100644
index 0000000000..6a96f5b55a
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr25617-1-no-sec-hdr.nd
@@ -0,0 +1,3 @@
+#...
+[a-f0-9 ]+ [DU] _?protected
+ + U _?test
diff --git a/ld/testsuite/ld-elf/pr25617-1-no-sec-hdr.rd b/ld/testsuite/ld-elf/pr25617-1-no-sec-hdr.rd
new file mode 100644
index 0000000000..5287139af7
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr25617-1-no-sec-hdr.rd
@@ -0,0 +1,20 @@
+#readelf: -lWSDs
+
+There are no sections in this file.
+
+#...
+Program Headers:
+  Type +Offset +VirtAddr.*
+# On MIPS, the first segment is for .reginfo.
+#...
+  LOAD .*
+#...
+  DYNAMIC .*
+#...
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 +NOTYPE +LOCAL +DEFAULT +UND +
+#...
+ +[0-9]+: +[a-f0-9]+ +0 +FUNC +GLOBAL +DEFAULT +UND +__libc_start_main
+#...
+ +[0-9]+: +[a-f0-9]+ +0+ +FUNC +GLOBAL +DEFAULT +UND +_?test
+#pass
diff --git a/ld/testsuite/ld-elf/pr25617-1-static-no-sec-hdr.rd b/ld/testsuite/ld-elf/pr25617-1-static-no-sec-hdr.rd
new file mode 100644
index 0000000000..92b1dc9ead
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr25617-1-static-no-sec-hdr.rd
@@ -0,0 +1,12 @@
+#readelf: -lWSDs
+
+There are no sections in this file.
+
+#...
+Program Headers:
+  Type +Offset +VirtAddr.*
+# On MIPS, the first segment is for .reginfo.
+#...
+  LOAD .*
+#...
+Dynamic symbol information is not available for displaying symbols\.
diff --git a/ld/testsuite/ld-elf/pr25617-1a-no-sec-hdr.nd b/ld/testsuite/ld-elf/pr25617-1a-no-sec-hdr.nd
new file mode 100644
index 0000000000..86fcc624af
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr25617-1a-no-sec-hdr.nd
@@ -0,0 +1,3 @@
+#...
+ + U _?puts
+[0-9a-z]+ T _?test
diff --git a/ld/testsuite/ld-elf/pr25617-1a-no-sec-hdr.rd b/ld/testsuite/ld-elf/pr25617-1a-no-sec-hdr.rd
new file mode 100644
index 0000000000..65fffba478
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr25617-1a-no-sec-hdr.rd
@@ -0,0 +1,20 @@
+#readelf: -lWSDs
+
+There are no sections in this file.
+
+#...
+Program Headers:
+  Type +Offset +VirtAddr.*
+# On MIPS, the first segment is for .reginfo.
+#...
+  LOAD .*
+#...
+  DYNAMIC .*
+#...
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 +NOTYPE +LOCAL +DEFAULT +UND +
+#...
+ +[0-9]+: +[a-f0-9]+ +0 +FUNC +GLOBAL +DEFAULT +UND +_?puts
+#...
+ +[0-9]+: +[a-f0-9]+ +[0-9]+ +FUNC +GLOBAL +DEFAULT +[0-9]+ +_?test
+#pass
diff --git a/ld/testsuite/ld-elf/pr25617-1a-sec-hdr.rd b/ld/testsuite/ld-elf/pr25617-1a-sec-hdr.rd
new file mode 100644
index 0000000000..b244c8b1a5
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr25617-1a-sec-hdr.rd
@@ -0,0 +1,19 @@
+#readelf: -lWSDs
+
+There are [0-9]+ section headers, starting at offset 0x[a-f0-9]+:
+#...
+Program Headers:
+  Type +Offset +VirtAddr.*
+# On MIPS, the first segment is for .reginfo.
+#...
+  LOAD .*
+#...
+  DYNAMIC .*
+#...
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 +NOTYPE +LOCAL +DEFAULT +UND +
+#...
+ +[0-9]+: +[a-f0-9]+ +0 +FUNC +GLOBAL +DEFAULT +UND +_?puts
+#...
+ +[0-9]+: +[a-f0-9]+ +[0-9]+ +FUNC +GLOBAL +DEFAULT +[0-9]+ +_?test
+#pass
diff --git a/ld/testsuite/ld-elf/pr25617-1a.c b/ld/testsuite/ld-elf/pr25617-1a.c
new file mode 100644
index 0000000000..e8fdfde5f6
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr25617-1a.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+int protected __attribute__ ((visibility ("protected"))) = 42;
+extern int *get_protected_ptr (void);
+
+void
+test()
+{
+  if (&protected == get_protected_ptr ())
+    printf ("PASS\n");
+}
diff --git a/ld/testsuite/ld-elf/pr25617-1b.c b/ld/testsuite/ld-elf/pr25617-1b.c
new file mode 100644
index 0000000000..1fd6ef45d7
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr25617-1b.c
@@ -0,0 +1,15 @@
+void test(void);
+
+extern int protected;
+
+int *
+get_protected_ptr (void)
+{
+  return &protected;
+}
+
+int main()
+{
+  test();
+  return 0;
+}
diff --git a/ld/testsuite/ld-elf/start-noheader.rd b/ld/testsuite/ld-elf/start-noheader.rd
new file mode 100644
index 0000000000..2479e34087
--- /dev/null
+++ b/ld/testsuite/ld-elf/start-noheader.rd
@@ -0,0 +1,11 @@
+#readelf: -SlDs --wide
+
+There are no sections in this file.
+
+#...
+Program Headers:
+  Type +Offset +VirtAddr.*
+# On MIPS, the first segment is for .reginfo.
+#...
+  LOAD .*
+#pass
diff --git a/ld/testsuite/ld-elf/start-shared-noheader-gnu.rd b/ld/testsuite/ld-elf/start-shared-noheader-gnu.rd
new file mode 100644
index 0000000000..3397a576ba
--- /dev/null
+++ b/ld/testsuite/ld-elf/start-shared-noheader-gnu.rd
@@ -0,0 +1,22 @@
+#readelf: -SlDs --wide
+
+There are no sections in this file.
+
+#...
+Program Headers:
+  Type +Offset +VirtAddr.*
+# On MIPS, the first segment is for .reginfo.
+#...
+  LOAD .*
+#...
+  DYNAMIC .*
+#...
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 +NOTYPE +LOCAL +DEFAULT +UND +
+#...
+ +[0-9]+: +[a-f0-9]+ +0 +NOTYPE +GLOBAL +DEFAULT +[0-9]+ +_start
+ +[0-9]+: +[a-f0-9]+ +0 +NOTYPE +GLOBAL +DEFAULT +[0-9]+ +main
+ +[0-9]+: +[a-f0-9]+ +0 +NOTYPE +GLOBAL +DEFAULT +[0-9]+ +start
+ +[0-9]+: +[a-f0-9]+ +0 +NOTYPE +GLOBAL +DEFAULT +[0-9]+ +_main
+ +[0-9]+: +[a-f0-9]+ +0 +NOTYPE +GLOBAL +DEFAULT +[0-9]+ +__start
+#pass
diff --git a/ld/testsuite/ld-elf/start-shared-noheader-sysv.rd b/ld/testsuite/ld-elf/start-shared-noheader-sysv.rd
new file mode 100644
index 0000000000..23a87f98bc
--- /dev/null
+++ b/ld/testsuite/ld-elf/start-shared-noheader-sysv.rd
@@ -0,0 +1,22 @@
+#readelf: -SlDs --wide
+
+There are no sections in this file.
+
+#...
+Program Headers:
+  Type +Offset +VirtAddr.*
+# On MIPS, the first segment is for .reginfo.
+#...
+  LOAD .*
+#...
+  DYNAMIC .*
+#...
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 +NOTYPE +LOCAL +DEFAULT +UND +
+#...
+ +[0-9]+: +[a-f0-9]+ +0 +NOTYPE +GLOBAL +DEFAULT +[0-9]+ +__start
+ +[0-9]+: +[a-f0-9]+ +0 +NOTYPE +GLOBAL +DEFAULT +[0-9]+ +_start
+ +[0-9]+: +[a-f0-9]+ +0 +NOTYPE +GLOBAL +DEFAULT +[0-9]+ +main
+ +[0-9]+: +[a-f0-9]+ +0 +NOTYPE +GLOBAL +DEFAULT +[0-9]+ +start
+ +[0-9]+: +[a-f0-9]+ +0 +NOTYPE +GLOBAL +DEFAULT +[0-9]+ +_main
+#pass
diff --git a/ld/testsuite/ld-elf/start-shared-noheader.nd b/ld/testsuite/ld-elf/start-shared-noheader.nd
new file mode 100644
index 0000000000..2d3ba70e53
--- /dev/null
+++ b/ld/testsuite/ld-elf/start-shared-noheader.nd
@@ -0,0 +1,5 @@
+[0-9a-z]+ A __start
+[0-9a-z]+ A _main
+[0-9a-z]+ A _start
+[0-9a-z]+ A main
+[0-9a-z]+ A start
-- 
2.24.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 7/7] ld: Add -z nosectionheader test to bootstrap.exp
  2020-03-10  0:12 [PATCH 0/7] ELF: Omit section header on ELF objects H.J. Lu
                   ` (6 preceding siblings ...)
  2020-03-10  0:12 ` [PATCH 6/7] ld: Add tests for -z nosectionheader and --remove-section-header H.J. Lu
@ 2020-03-10  0:12 ` H.J. Lu
  7 siblings, 0 replies; 11+ messages in thread
From: H.J. Lu @ 2020-03-10  0:12 UTC (permalink / raw)
  To: binutils

	PR ld/25617
	* testsuite/ld-bootstrap/bootstrap.exp: Add -z nosectionheader
	test.
---
 ld/testsuite/ld-bootstrap/bootstrap.exp | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/ld/testsuite/ld-bootstrap/bootstrap.exp b/ld/testsuite/ld-bootstrap/bootstrap.exp
index ba51e50a02..5d74caf2d6 100644
--- a/ld/testsuite/ld-bootstrap/bootstrap.exp
+++ b/ld/testsuite/ld-bootstrap/bootstrap.exp
@@ -55,6 +55,9 @@ set test_flags {"" "strip" "--static" "-Wl,--traditional-format"
 if { [istarget "powerpc-*-*"] } {
     lappend test_flags "-Wl,--ppc476-workaround"
 }
+if { [is_elf_format] && ![is_bad_symtab] } {
+    lappend test_flags "-Wl,-z,nosectionheader"
+}
 
 set gcc_B_opt_save $gcc_B_opt
 
@@ -80,9 +83,12 @@ foreach flags $test_flags {
 	set testname "bootstrap"
     }}
 
-    # --static is meaningless and --relax is incompatible with -r.
+    # --static is meaningless.  --relax and -z nosectionheader are
+    # incompatible with -r.
     regsub -- "-Wl," $flags "" partial_flags
-    if { "$partial_flags" == "--static" || "$partial_flags" == "--relax" } {
+    if { "$partial_flags" == "--static" \
+         || "$partial_flags" == "--relax" \
+	 || [string match "*nosectionheader*" "$partial_flags"] } {
 	set partial_flags ""
     }
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/7] bfd: Improve nm and objdump without section header
  2020-03-10  0:12 ` [PATCH 2/7] bfd: Improve nm and objdump without section header H.J. Lu
@ 2020-03-12  3:11   ` Fangrui Song
  0 siblings, 0 replies; 11+ messages in thread
From: Fangrui Song @ 2020-03-12  3:11 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Mihailo Stojanovic, binutils

On 2020-03-09, H.J. Lu wrote:
>When there is no section header in an executable or shared library, we
>reconstruct dynamic symbol table from the PT_DYNAMIC segment, which
>contains DT_HASH/DT_GNU_HASH/DT_MIPS_XHASH, DT_STRTAB, DT_SYMTAB,
>DT_STRSZ and DT_SYMENT entries, to improve nm and objdump.  For DT_HASH,
>the number of dynamic symbol table entries equals the number of chains.
>For DT_GNU_HASH/DT_MIPS_XHASH, only defined symbols with non-STB_LOCAL
>indings are in hash table.  Since DT_GNU_HASH/DT_MIPS_XHASH place all
>symbols with STB_LOCAL binding before symbols with other bindings and
>all undefined symbols defined ones in dynamic symbol table, the highest
>symbol index in DT_GNU_HASH/DT_MIPS_XHASH is the highest dynamic symbol
>table index.
>
>dt_symtab, dt_symtab_count and dt_strtab are added to elf_obj_tdata to
>store dynamic symbol table information.
>
>	PR ld/25617
>	* elf-bfd.h (elf_obj_tdata): Add dt_symtab, dt_symtab_count and
>	dt_strtab.
>	(elf_use_dt_symtab_p): New.
>	(_bfd_elf_get_dynamic_symbols): Likewise.
>	(_bfd_elf_get_section_from_dynamic_symbol): Likewise.
>	* elf.c (bfd_elf_get_elf_syms): Use dynamic symbol table if
>	neeeded.
>	(_bfd_elf_get_dynamic_symtab_upper_bound): Likewise.
>	(offset_from_vma): New function.
>	(get_hash_table_data): Likewise.
>	(_bfd_elf_get_dynamic_symbols): Likewise.
>	(_bfd_elf_get_section_from_dynamic_symbol): Likewise.
>	* elfcode.h (elf_object_p): Call _bfd_elf_get_dynamic_symbols
>	to reconstruct dynamic symbol table from PT_DYNAMIC segment if
>	there is no section header.
>	(elf_slurp_symbol_table): Use dynamic symbol table if neeeded.
>	Don't free isymbuf when dynamic symbol table is used.
>	* elflink.c (elf_link_is_defined_archive_symbol): Return wrong
>	format error when dynamic symbol table is used.
>	(elf_link_add_object_symbols): Likewise.
>---
> bfd/elf-bfd.h |  10 +
> bfd/elf.c     | 497 ++++++++++++++++++++++++++++++++++++++++++++++++++
> bfd/elfcode.h |  42 ++++-
> bfd/elflink.c |  12 ++
> 4 files changed, 557 insertions(+), 4 deletions(-)
>
>diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
>index 5d9e0fedcd..09692b155a 100644
>--- a/bfd/elf-bfd.h
>+++ b/bfd/elf-bfd.h
>@@ -1876,6 +1876,9 @@ struct elf_obj_tdata
>   Elf_Internal_Shdr dynversym_hdr;
>   Elf_Internal_Shdr dynverref_hdr;
>   Elf_Internal_Shdr dynverdef_hdr;
>+  Elf_Internal_Sym *dt_symtab;
>+  bfd_size_type dt_symtab_count;
>+  char *dt_strtab;
>   elf_section_list * symtab_shndx_list;
>   bfd_vma gp;				/* The gp value */
>   unsigned int gp_size;			/* The gp size */
>@@ -2030,6 +2033,7 @@ struct elf_obj_tdata
> #define elf_dyn_lib_class(bfd)	(elf_tdata(bfd) -> dyn_lib_class)
> #define elf_bad_symtab(bfd)	(elf_tdata(bfd) -> bad_symtab)
> #define elf_flags_init(bfd)	(elf_tdata(bfd) -> o->flags_init)
>+#define elf_use_dt_symtab_p(bfd) (elf_tdata(bfd) -> dt_symtab_count != 0)
> #define elf_known_obj_attributes(bfd) (elf_tdata (bfd) -> known_obj_attributes)
> #define elf_other_obj_attributes(bfd) (elf_tdata (bfd) -> other_obj_attributes)
> #define elf_known_obj_attributes_proc(bfd) \
>@@ -2403,6 +2407,12 @@ extern bfd_reloc_status_type bfd_elf_perform_complex_relocation
> extern bfd_boolean _bfd_elf_setup_sections
>   (bfd *);
>
>+extern bfd_boolean _bfd_elf_get_dynamic_symbols
>+  (bfd *, Elf_Internal_Phdr *, Elf_Internal_Phdr *, size_t,
>+   bfd_size_type);
>+extern asection *_bfd_elf_get_section_from_dynamic_symbol
>+  (bfd *, Elf_Internal_Sym *);
>+
> extern struct bfd_link_hash_entry *bfd_elf_define_start_stop
>   (struct bfd_link_info *, const char *, asection *);
>
>diff --git a/bfd/elf.c b/bfd/elf.c
>index e6db2ff64d..aa689dcab3 100644
>--- a/bfd/elf.c
>+++ b/bfd/elf.c
>@@ -405,6 +405,17 @@ bfd_elf_get_elf_syms (bfd *ibfd,
>   if (symcount == 0)
>     return intsym_buf;
>
>+  if (elf_use_dt_symtab_p (ibfd))
>+    {
>+      /* Use dynamic symbol table.  */
>+      if (elf_tdata (ibfd)->dt_symtab_count != (symcount + symoffset))
>+	{
>+	  bfd_set_error (bfd_error_invalid_operation);
>+	  return NULL;
>+	}
>+      return elf_tdata (ibfd)->dt_symtab + symoffset;
>+    }
>+
>   /* Normal syms might have section extension entries.  */
>   shndx_hdr = NULL;
>   if (elf_symtab_shndx_list (ibfd) != NULL)
>@@ -1881,6 +1892,485 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
>   return FALSE;
> }
>
>+/* Find the file offset corresponding to VMA by using the program
>+   headers.  */
>+
>+static file_ptr
>+offset_from_vma (Elf_Internal_Phdr *phdrs, size_t phnum, bfd_vma vma,
>+		 bfd_vma size)
>+{
>+  Elf_Internal_Phdr *seg;
>+  size_t i;
>+
>+  for (seg = phdrs, i = 0; i < phnum; ++seg, ++i)
>+    if (seg->p_type == PT_LOAD
>+	&& vma >= (seg->p_vaddr & -seg->p_align)
>+	&& vma + size <= seg->p_vaddr + seg->p_filesz)
>+      return (file_ptr) (vma - seg->p_vaddr + seg->p_offset);
>+
>+  bfd_set_error (bfd_error_invalid_operation);
>+  return (file_ptr) -1;
>+}
>+
>+/* Convert hash table to internal form.  */
>+
>+static bfd_vma *
>+get_hash_table_data (bfd *abfd, bfd_size_type number,
>+		     unsigned int ent_size, bfd_size_type filesize)
>+{
>+  unsigned char *e_data = NULL;
>+  bfd_vma *i_data = NULL;
>+  bfd_size_type size;
>+
>+  if (ent_size != 4 && ent_size != 8)
>+    return NULL;
>+
>+  /* If the size_t type is smaller than the bfd_size_type, eg because
>+     you are building a 32-bit tool on a 64-bit host, then make sure
>+     that when (number) is cast to (size_t) no information is lost.  */
>+  if (sizeof (size_t) < sizeof (bfd_size_type)
>+      && (bfd_size_type) ((size_t) number) != number)
>+    {
>+      bfd_set_error (bfd_error_file_too_big);
>+      return NULL;
>+    }
>+
>+  size = ent_size * number;
>+  /* Be kind to memory checkers (eg valgrind, address sanitizer) by not
>+     attempting to allocate memory when the read is bound to fail.  */
>+  if (size > filesize
>+      || number >= ~(size_t) 0 / ent_size
>+      || number >= ~(size_t) 0 / sizeof (*i_data))
>+    {
>+      bfd_set_error (bfd_error_file_too_big);
>+      return NULL;
>+    }
>+
>+  e_data = _bfd_malloc_and_read (abfd, size, size);
>+  if (e_data == NULL)
>+    return NULL;
>+
>+  i_data = (bfd_vma *) bfd_malloc (number * sizeof (*i_data));
>+  if (i_data == NULL)
>+    {
>+      free (e_data);
>+      return NULL;
>+    }
>+
>+  if (ent_size == 4)
>+    while (number--)
>+      i_data[number] = bfd_get_32 (abfd, e_data + number * ent_size);
>+  else
>+    while (number--)
>+      i_data[number] = bfd_get_64 (abfd, e_data + number * ent_size);
>+
>+  free (e_data);
>+  return i_data;
>+}
>+
>+/* Address of .MIPS.xhash section.  FIXME: What is the best way to
>+   support DT_MIPS_XHASH?  */
>+#define DT_MIPS_XHASH	       0x70000036
>+

If DT_MIPS_XHASH support turns out to be tricky, maybe that part can be
deferred.

I am waiting for DT_MIPS_XHASH stakeholders to prove it is worth it and
should not be reverted instead.

https://sourceware.org/pipermail/binutils/2019-December/108886.html 
https://sourceware.org/pipermail/binutils/2020-January/109362.html

>+/* Reconstruct dynamic symbol table from PT_DYNAMIC segment.  */
>+
>+bfd_boolean
>+_bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr,
>+			      Elf_Internal_Phdr *phdrs, size_t phnum,
>+			      bfd_size_type filesize)
>+{
>+  bfd_byte *extdyn, *extdynend;
>+  size_t extdynsize;
>+  void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
>+  bfd_boolean (*swap_symbol_in) (bfd *, const void *, const void *,
>+				 Elf_Internal_Sym *);
>+  Elf_Internal_Dyn dyn;
>+  bfd_vma dt_hash = 0;
>+  bfd_vma dt_gnu_hash = 0;
>+  bfd_vma dt_mips_xhash = 0;
>+  bfd_vma dt_strtab = 0;
>+  bfd_vma dt_symtab = 0;
>+  bfd_vma dt_strsz = 0;
>+  bfd_byte *dynbuf = NULL;
>+  char *strbuf = NULL;
>+  bfd_vma *gnubuckets = NULL;
>+  bfd_vma *gnuchains = NULL;
>+  bfd_vma *mipsxlat = NULL;
>+  file_ptr saved_filepos, filepos;
>+  bfd_boolean res = FALSE;
>+  bfd_size_type amt;
>+  bfd_byte *esymbuf = NULL, *esym;
>+  bfd_size_type symcount;
>+  Elf_Internal_Sym *isymbuf = NULL;
>+  Elf_Internal_Sym *isym, *isymend;
>+  size_t extsym_size;
>+  const struct elf_backend_data *bed;
>+
>+  /* Return TRUE if symbol table is bad.  */
>+  if (elf_bad_symtab (abfd))
>+    return TRUE;
>+
>+  /* Return TRUE if DT_HASH/DT_GNU_HASH have bee processed before.  */
>+  if (elf_tdata (abfd)->dt_strtab != NULL)
>+    return TRUE;
>+
>+  bed = get_elf_backend_data (abfd);
>+
>+  /* Save file position for elf_object_p.  */
>+  saved_filepos = bfd_tell (abfd);
>+
>+  if (bfd_seek (abfd, phdr->p_offset, SEEK_SET) != 0)
>+    goto error_return;
>+
>+  dynbuf = _bfd_malloc_and_read (abfd, phdr->p_filesz, phdr->p_filesz);
>+  if (dynbuf == NULL)
>+    goto error_return;
>+
>+  extsym_size = bed->s->sizeof_sym;
>+  extdynsize = bed->s->sizeof_dyn;
>+  swap_dyn_in = bed->s->swap_dyn_in;
>+
>+  extdyn = dynbuf;
>+  if (phdr->p_filesz < extdynsize)
>+    goto error_return;
>+  extdynend = extdyn + phdr->p_filesz;
>+  for (; extdyn <= (extdynend - extdynsize); extdyn += extdynsize)
>+    {
>+      swap_dyn_in (abfd, extdyn, &dyn);
>+
>+      if (dyn.d_tag == DT_NULL)
>+	break;
>+
>+      switch (dyn.d_tag)
>+	{
>+	case DT_HASH:
>+	  dt_hash = dyn.d_un.d_val;
>+	  break;
>+	case DT_GNU_HASH:
>+	  if (bed->elf_machine_code != EM_MIPS
>+	      && bed->elf_machine_code != EM_MIPS_RS3_LE)
>+	    dt_gnu_hash = dyn.d_un.d_val;
>+	  break;
>+	case DT_STRTAB:
>+	  dt_strtab = dyn.d_un.d_val;
>+	  break;
>+	case DT_SYMTAB:
>+	  dt_symtab = dyn.d_un.d_val;
>+	  break;
>+	case DT_STRSZ:
>+	  dt_strsz = dyn.d_un.d_val;
>+	  break;
>+	case DT_SYMENT:
>+	  if (dyn.d_un.d_val != extsym_size)
>+	    goto error_return;
>+	  break;
>+	default:
>+	  if (dyn.d_tag == DT_MIPS_XHASH
>+	      && (bed->elf_machine_code == EM_MIPS
>+		  || bed->elf_machine_code == EM_MIPS_RS3_LE))
>+	    {
>+	      dt_gnu_hash = dyn.d_un.d_val;
>+	      dt_mips_xhash = dyn.d_un.d_val;
>+	    }
>+	  break;
>+	}
>+    }
>+
>+  /* Check if we can reconstruct dynamic symbol table from PT_DYNAMIC
>+     segment.  */
>+  if ((!dt_hash && !dt_gnu_hash)
>+      || !dt_strtab
>+      || !dt_symtab
>+      || !dt_strsz)
>+    goto error_return;
>+
>+  /* Get dynamic string table.  */
>+  filepos = offset_from_vma (phdrs, phnum, dt_strtab, dt_strsz);
>+  if (filepos == (file_ptr) -1
>+      || bfd_seek (abfd, filepos, SEEK_SET) != 0)
>+    goto error_return;
>+
>+  /* Dynamic string table must be valid until ABFD is closed.  */
>+  strbuf = (char *) _bfd_alloc_and_read (abfd, dt_strsz, dt_strsz);
>+  if (strbuf == NULL)
>+    goto error_return;
>+
>+  /* Get the real symbol count from DT_HASH or DT_GNU_HASH.  Prefer
>+     DT_HASH since it is simpler than DT_GNU_HASH.  */
>+  if (dt_hash)
>+    {
>+      unsigned char nb[16];
>+      unsigned int hash_ent_size;
>+
>+      switch (bed->elf_machine_code)
>+	{
>+	case EM_ALPHA:
>+	case EM_S390:
>+	case EM_S390_OLD:
>+	  if (bed->s->elfclass == ELFCLASS64)
>+	    {
>+	      hash_ent_size = 8;
>+	      break;
>+	    }
>+	  /* FALLTHROUGH */
>+	default:
>+	  hash_ent_size = 4;
>+	  break;
>+	}
>+
>+      filepos = offset_from_vma (phdrs, phnum, dt_hash, sizeof (nb));
>+      if (filepos == (file_ptr) -1
>+	  || bfd_seek (abfd, filepos, SEEK_SET) != 0
>+	  || (bfd_bread (nb, 2 * hash_ent_size, abfd)
>+	      != (2 * hash_ent_size)))
>+	goto error_return;
>+
>+      /* The number of dynamic symbol table entries equals the number
>+	 of chains.  */
>+      if (hash_ent_size == 8)
>+	symcount = bfd_get_64 (abfd, nb + hash_ent_size);
>+      else
>+	symcount = bfd_get_32 (abfd, nb + hash_ent_size);
>+    }
>+  else
>+    {
>+      /* For DT_GNU_HASH, only defined symbols with non-STB_LOCAL
>+	 bindings are in hash table.  Since in dynamic symbol table,
>+	 all symbols with STB_LOCAL binding are placed before symbols
>+	 with other bindings and all undefined symbols are placed
>+	 before defined ones, the highest symbol index in DT_GNU_HASH
>+	 is the highest dynamic symbol table index.  */
>+      unsigned char nb[16];
>+      bfd_vma ngnubuckets;
>+      bfd_vma gnusymidx;
>+      size_t i, ngnuchains;
>+      bfd_vma maxchain = 0xffffffff, bitmaskwords;
>+      bfd_vma buckets_vma;
>+
>+      filepos = offset_from_vma (phdrs, phnum, dt_gnu_hash,
>+				 sizeof (nb));
>+      if (filepos == (file_ptr) -1
>+	  || bfd_seek (abfd, filepos, SEEK_SET) != 0
>+	  || bfd_bread (nb, sizeof (nb), abfd) != sizeof (nb))
>+	goto error_return;
>+
>+      ngnubuckets = bfd_get_32 (abfd, nb);
>+      gnusymidx = bfd_get_32 (abfd, nb + 4);
>+      bitmaskwords = bfd_get_32 (abfd, nb + 8);
>+      buckets_vma = dt_gnu_hash + 16;
>+      if (bed->s->elfclass == ELFCLASS32)
>+	buckets_vma += bitmaskwords * 4;
>+      else
>+	buckets_vma += bitmaskwords * 8;
>+      filepos = offset_from_vma (phdrs, phnum, buckets_vma, 4);
>+      if (filepos == (file_ptr) -1
>+	  || bfd_seek (abfd, filepos, SEEK_SET) != 0)
>+	goto error_return;
>+
>+      gnubuckets = get_hash_table_data (abfd, ngnubuckets, 4, filesize);
>+      if (gnubuckets == NULL)
>+	goto error_return;
>+
>+      for (i = 0; i < ngnubuckets; i++)
>+	if (gnubuckets[i] != 0)
>+	  {
>+	    if (gnubuckets[i] < gnusymidx)
>+	      goto error_return;
>+
>+	    if (maxchain == 0xffffffff || gnubuckets[i] > maxchain)
>+	      maxchain = gnubuckets[i];
>+	  }
>+
>+      if (maxchain == 0xffffffff)
>+	goto error_return;
>+
>+      maxchain -= gnusymidx;
>+      filepos = offset_from_vma (phdrs, phnum,
>+				 (buckets_vma +
>+				  4 * (ngnubuckets + maxchain)),
>+				 4);
>+      if (filepos == (file_ptr) -1
>+	  || bfd_seek (abfd, filepos, SEEK_SET) != 0)
>+	goto error_return;
>+
>+      do
>+	{
>+	  if (bfd_bread (nb, 4, abfd) != 4)
>+	    goto error_return;
>+	  ++maxchain;
>+	  if (maxchain == 0)
>+	    goto error_return;
>+	}
>+      while ((bfd_get_32 (abfd, nb) & 1) == 0);
>+
>+      filepos = offset_from_vma (phdrs, phnum,
>+				 (buckets_vma + 4 * ngnubuckets),
>+				 4);
>+      if (filepos == (file_ptr) -1
>+	  || bfd_seek (abfd, filepos, SEEK_SET) != 0)
>+	goto error_return;
>+
>+      gnuchains = get_hash_table_data (abfd, maxchain, 4, filesize);
>+      if (gnubuckets == NULL)
>+	goto error_return;
>+      ngnuchains = maxchain;
>+
>+      if (dt_mips_xhash)
>+	{
>+	  filepos = offset_from_vma (phdrs, phnum,
>+				     (buckets_vma
>+				      + 4 * (ngnubuckets + maxchain)),
>+				     4);
>+	  if (filepos == (file_ptr) -1
>+	      || bfd_seek (abfd, filepos, SEEK_SET) != 0)
>+	    goto error_return;
>+
>+	  mipsxlat = get_hash_table_data (abfd, maxchain, 4, filesize);
>+	  if (mipsxlat == NULL)
>+	    goto error_return;
>+	}
>+
>+      symcount = 0;
>+      for (i = 0; i < ngnubuckets; ++i)
>+	if (gnubuckets[i] != 0)
>+	  {
>+	    bfd_vma si = gnubuckets[i];
>+	    bfd_vma off = si - gnusymidx;
>+	    do
>+	      {
>+		if (mipsxlat)
>+		  {
>+		    if (mipsxlat[off] >= symcount)
>+		      symcount = mipsxlat[off] + 1;
>+		  }
>+		else
>+		  {
>+		    if (si >= symcount)
>+		      symcount = si + 1;
>+		  }
>+		si++;
>+	      }
>+	    while (off < ngnuchains && (gnuchains[off++] & 1) == 0);
>+	  }
>+    }
>+
>+  /* Swap in dynamic symbol table.  */
>+  if (_bfd_mul_overflow (symcount, extsym_size, &amt))
>+    {
>+      bfd_set_error (bfd_error_file_too_big);
>+      goto error_return;
>+    }
>+
>+  filepos = offset_from_vma (phdrs, phnum, dt_symtab, amt);
>+  if (filepos == (file_ptr) -1
>+      || bfd_seek (abfd, filepos, SEEK_SET) != 0)
>+    goto error_return;
>+  esymbuf = _bfd_malloc_and_read (abfd, amt, amt);
>+  if (esymbuf == NULL)
>+    goto error_return;
>+
>+  if (_bfd_mul_overflow (symcount, sizeof (Elf_Internal_Sym), &amt))
>+    {
>+      bfd_set_error (bfd_error_file_too_big);
>+      goto error_return;
>+    }
>+
>+  /* Dynamic symbol table must be valid until ABFD is closed.  */
>+  isymbuf = (Elf_Internal_Sym *) bfd_alloc (abfd, amt);
>+  if (isymbuf == NULL)
>+    goto error_return;
>+
>+  swap_symbol_in = bed->s->swap_symbol_in;
>+
>+  /* Convert the symbols to internal form.  */
>+  isymend = isymbuf + symcount;
>+  for (esym = esymbuf, isym = isymbuf;
>+       isym < isymend;
>+       esym += extsym_size, isym++)
>+    if (!swap_symbol_in (abfd, esym, NULL, isym)
>+	|| isym->st_name >= dt_strsz)
>+      {
>+	bfd_set_error (bfd_error_invalid_operation);
>+	goto error_return;
>+      }
>+
>+  elf_tdata (abfd)->dt_strtab = strbuf;
>+  elf_tdata (abfd)->dt_symtab = isymbuf;
>+  elf_tdata (abfd)->dt_symtab_count = symcount;
>+
>+  res = TRUE;
>+
>+ error_return:
>+  /* Restore file position for elf_object_p.  */
>+  if (bfd_seek (abfd, saved_filepos, SEEK_SET) != 0)
>+    res = FALSE;
>+  if (dynbuf != NULL)
>+    free (dynbuf);
>+  if (esymbuf != NULL)
>+    free (esymbuf);
>+  if (gnubuckets != NULL)
>+    free (gnubuckets);
>+  if (gnuchains != NULL)
>+    free (gnuchains);
>+  if (mipsxlat != NULL)
>+    free (mipsxlat);
>+  return res;
>+}
>+
>+/* Reconstruct section from dynamic symbol.  */
>+
>+asection *
>+_bfd_elf_get_section_from_dynamic_symbol (bfd *abfd,
>+					  Elf_Internal_Sym *isym)
>+{
>+  asection *sec;
>+  flagword flags;
>+
>+  if (!elf_use_dt_symtab_p (abfd))
>+    return NULL;
>+
>+  flags = SEC_ALLOC | SEC_LOAD;
>+  switch (ELF_ST_TYPE (isym->st_info))
>+    {
>+    case STT_FUNC:
>+    case STT_GNU_IFUNC:
>+      sec = bfd_get_section_by_name (abfd, ".text");
>+      if (sec == NULL)
>+	sec = bfd_make_section_with_flags (abfd,
>+					   ".text",
>+					   flags | SEC_CODE);
>+      break;
>+    case STT_COMMON:
>+      sec = bfd_com_section_ptr;
>+      break;
>+    case STT_OBJECT:
>+      sec = bfd_get_section_by_name (abfd, ".data");
>+      if (sec == NULL)
>+	sec = bfd_make_section_with_flags (abfd,
>+					   ".data",
>+					   flags | SEC_DATA);
>+      break;
>+    case STT_TLS:
>+      sec = bfd_get_section_by_name (abfd, ".tdata");
>+      if (sec == NULL)
>+	sec = bfd_make_section_with_flags (abfd,
>+					   ".tdata",
>+					   (flags
>+					    | SEC_DATA
>+					    | SEC_THREAD_LOCAL));
>+      break;
>+    default:
>+      sec = bfd_abs_section_ptr;
>+      break;
>+    }
>+
>+  /* NB: Don't place this section in output.  */
>+  if (sec && 0)
>+    sec->output_section = bfd_abs_section_ptr;
>+
>+  return sec;
>+}
>+
> /* Get version string.  */
>
> const char *
>@@ -8415,6 +8905,11 @@ _bfd_elf_get_dynamic_symtab_upper_bound (bfd *abfd)
>
>   if (elf_dynsymtab (abfd) == 0)
>     {
>+      /* Check if there is dynamic symbol table.  */
>+      symcount = elf_tdata (abfd)->dt_symtab_count;
>+      if (symcount)
>+	goto compute_symtab_size;
>+
>       bfd_set_error (bfd_error_invalid_operation);
>       return -1;
>     }
>@@ -8425,6 +8920,8 @@ _bfd_elf_get_dynamic_symtab_upper_bound (bfd *abfd)
>       bfd_set_error (bfd_error_file_too_big);
>       return -1;
>     }
>+
>+ compute_symtab_size:
>   symtab_size = (symcount + 1) * (sizeof (asymbol *));
>   if (symcount > 0)
>     symtab_size -= sizeof (asymbol *);
>diff --git a/bfd/elfcode.h b/bfd/elfcode.h
>index 4dde24e02a..9124015a3e 100644
>--- a/bfd/elfcode.h
>+++ b/bfd/elfcode.h
>@@ -820,6 +820,21 @@ elf_object_p (bfd *abfd)
> 	  if (bfd_bread (&x_phdr, sizeof x_phdr, abfd) != sizeof x_phdr)
> 	    goto got_no_match;
> 	  elf_swap_phdr_in (abfd, &x_phdr, i_phdr);
>+	  if (i_phdr->p_filesz != 0)
>+	    {
>+	      if ((i_phdr->p_offset + i_phdr->p_filesz) > filesize)
>+		goto got_no_match;
>+	      /* Try to reconstruct dynamic symbol table from PT_DYNAMIC
>+		 segment if there is no section header.  */
>+	      if (i_phdr->p_type == PT_DYNAMIC
>+		  && i_ehdrp->e_shstrndx == 0
>+		  && i_ehdrp->e_shoff == 0
>+		  && !_bfd_elf_get_dynamic_symbols (abfd, i_phdr,
>+						    elf_tdata (abfd)->phdr,
>+						    i_ehdrp->e_phnum,
>+						    filesize))
>+		goto got_no_match;
>+	    }
> 	}
>     }
>
>@@ -1223,7 +1238,9 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
>     }
>
>   ebd = get_elf_backend_data (abfd);
>-  symcount = hdr->sh_size / sizeof (Elf_External_Sym);
>+  symcount = elf_tdata (abfd)->dt_symtab_count;
>+  if (symcount == 0)
>+    symcount = hdr->sh_size / sizeof (Elf_External_Sym);
>   if (symcount == 0)
>     sym = symbase = NULL;
>   else
>@@ -1279,7 +1296,11 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
> 	  memcpy (&sym->internal_elf_sym, isym, sizeof (Elf_Internal_Sym));
>
> 	  sym->symbol.the_bfd = abfd;
>-	  sym->symbol.name = bfd_elf_sym_name (abfd, hdr, isym, NULL);
>+	  if (elf_use_dt_symtab_p (abfd))
>+	    sym->symbol.name = (elf_tdata (abfd)->dt_strtab
>+				+ isym->st_name);
>+	  else
>+	    sym->symbol.name = bfd_elf_sym_name (abfd, hdr, isym, NULL);
> 	  sym->symbol.value = isym->st_value;
>
> 	  if (isym->st_shndx == SHN_UNDEF)
>@@ -1313,6 +1334,15 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
> 		 moment) about the alignment.  */
> 	      sym->symbol.value = isym->st_size;
> 	    }
>+	  else if (elf_use_dt_symtab_p (abfd))
>+	    {
>+	      asection *sec;
>+	      sec = _bfd_elf_get_section_from_dynamic_symbol (abfd,
>+							      isym);
>+	      if (sec == NULL)
>+		goto error_return;
>+	      sym->symbol.section = sec;
>+	    }
> 	  else
> 	    {
> 	      sym->symbol.section
>@@ -1426,14 +1456,18 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
>
>   if (xverbuf != NULL)
>     free (xverbuf);
>-  if (isymbuf != NULL && hdr->contents != (unsigned char *) isymbuf)
>+  if (isymbuf != NULL
>+      && hdr->contents != (unsigned char *) isymbuf
>+      && !elf_use_dt_symtab_p (abfd))
>     free (isymbuf);
>   return symcount;
>
>  error_return:
>   if (xverbuf != NULL)
>     free (xverbuf);
>-  if (isymbuf != NULL && hdr->contents != (unsigned char *) isymbuf)
>+  if (isymbuf != NULL
>+      && hdr->contents != (unsigned char *) isymbuf
>+      && !elf_use_dt_symtab_p (abfd))
>     free (isymbuf);
>   return -1;
> }
>diff --git a/bfd/elflink.c b/bfd/elflink.c
>index c04712a10f..ee047889c5 100644
>--- a/bfd/elflink.c
>+++ b/bfd/elflink.c
>@@ -3394,6 +3394,12 @@ elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
>   if (! bfd_check_format (abfd, bfd_object))
>     return FALSE;
>
>+  if (elf_use_dt_symtab_p (abfd))
>+    {
>+      bfd_set_error (bfd_error_wrong_format);
>+      return FALSE;
>+    }
>+
>   /* Select the appropriate symbol table.  If we don't know if the
>      object file is an IR object, give linker LTO plugin a chance to
>      get the correct symbol table.  */
>@@ -3927,6 +3933,12 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
>   htab = elf_hash_table (info);
>   bed = get_elf_backend_data (abfd);
>
>+  if (elf_use_dt_symtab_p (abfd))
>+    {
>+      bfd_set_error (bfd_error_wrong_format);
>+      return FALSE;
>+    }
>+
>   if ((abfd->flags & DYNAMIC) == 0)
>     dynamic = FALSE;
>   else
>-- 
>2.24.1
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/7] ELF: Omit section header on ELF objects
  2020-03-10  0:12 ` [PATCH 1/7] ELF: Omit section header on " H.J. Lu
@ 2020-03-20  7:11   ` Alan Modra
  0 siblings, 0 replies; 11+ messages in thread
From: Alan Modra @ 2020-03-20  7:11 UTC (permalink / raw)
  To: H.J. Lu; +Cc: binutils, Kaylee Blake

On Mon, Mar 09, 2020 at 05:12:18PM -0700, H.J. Lu wrote:
> From: Kaylee Blake <klkblake@gmail.com>
> 
> Section header isn't mandatory on ELF executable nor shared library.
> This patch adds a new linker option, -z nosectionheader, to omit ELF
> section header when building an executable or shared library, an
> objcopy and strip option, --remove-section-header, to remove ELF
> section header from an executable or shared library.
> 
> bfd/
> 
> 2020-03-XX  H.J. Lu  <hongjiu.lu@intel.com>
> 	    Kaylee Blake  <klkblake@gmail.com>
> 
> 	PR ld/25617
> 	* bfd.c (BFD_NO_SECTION_HEADER): New.
> 	(BFD_FLAGS_SAVED): Add BFD_NO_SECTION_HEADER.
> 	(BFD_FLAGS_FOR_BFD_USE_MASK): Likewise.
> 	* elfcode.h (elf_swap_ehdr_out): Omit section header on
> 	non-relocatable output with BFD_NO_SECTION_HEADER.
> 	(elf_write_shdrs_and_ehdr): Likewise.
> 	* elfxx-target.h (TARGET_BIG_SYM): Add BFD_NO_SECTION_HEADER
> 	to object_flags.
> 	(TARGET_LITTLE_SYM): Likewise.
> 	* bfd-in2.h: Regenerated.
> 
> binutils/
> 
> 2020-03-XX  H.J. Lu  <hongjiu.lu@intel.com>
> 
> 	PR ld/25617
> 	* NEWS: Mention --remove-section-header for objcopy and strip.
> 	* doc/binutils.texi: Document --remove-section-header for objcopy
> 	and strip.
> 	* objcopy.c (remove_section_header): New.
> 	(command_line_switch): Add OPTION_REMOVE_SECTION_HEADER.
> 	(strip_options): Add --remove-section-header.
> 	(copy_options): Likewise.
> 	(copy_usage): Add --remove-section-header.
> 	(strip_usage): Likewise.
> 	(copy_object): Renamed to ...
> 	(copy_object_1): This.  Issue a warning for
> 	--remove-section-header on non-ELF targets.
> 	(copy_object): New.
> 	(strip_main): Handle OPTION_REMOVE_SECTION_HEADER.
> 	(copy_main): Likewise.
> 
> ld/
> 
> 2020-03-XX  H.J. Lu  <hongjiu.lu@intel.com>
> 	    Kaylee Blake  <klkblake@gmail.com>
> 
> 	PR ld/25617
> 	* NEWS: Mention -z nosectionheader.
> 	* emultempl/elf.em: Support -z sectionheader and
> 	-z nosectionheader.
> 	* ld.h (ld_config_type): Add no_section_header.
> 	* ld.texi: Document -z sectionheader and -z nosectionheader.
> 	* ldlang.c (ldlang_open_output): Handle
> 	config.no_section_header.
> 	* lexsup.c (parse_args): Disallow -z nosectionheader with -r.
> 	(elf_static_list_options): Add -z sectionheader and
> 	-z nosectionheader.

This looks mostly OK to me.  The only nit I have to pick is the
copy_object_1 extraction from copy_object.  That seems unnecessary to
me since it looks like --remove-section-header on a non-ELF object
results in an error and the output file being deleted.  So you could
do without the new function and just set strip_symbols and merge_notes
when decoding the new option.  Also, I wouldn't restrict the operation
to (EXEC_P | DYNAMIC) objects.  Someone might find a reason to use
--remove-section-header on a relocatable object.  Allow people to
shoot themselves in the foot if they so desire..  (Unless supporting
--remove-section-header on a relocatable object requires more work.)

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2020-03-20  7:11 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-10  0:12 [PATCH 0/7] ELF: Omit section header on ELF objects H.J. Lu
2020-03-10  0:12 ` [PATCH 1/7] ELF: Omit section header in " H.J. Lu
2020-03-10  0:12 ` [PATCH 1/7] ELF: Omit section header on " H.J. Lu
2020-03-20  7:11   ` Alan Modra
2020-03-10  0:12 ` [PATCH 2/7] bfd: Improve nm and objdump without section header H.J. Lu
2020-03-12  3:11   ` Fangrui Song
2020-03-10  0:12 ` [PATCH 3/7] readelf: Compute dynamic symbol table size from hash table H.J. Lu
2020-03-10  0:12 ` [PATCH 4/7] ld: Add a simple test for -z nosectionheader H.J. Lu
2020-03-10  0:12 ` [PATCH 5/7] binutils: Add --remove-section-header tests H.J. Lu
2020-03-10  0:12 ` [PATCH 6/7] ld: Add tests for -z nosectionheader and --remove-section-header H.J. Lu
2020-03-10  0:12 ` [PATCH 7/7] ld: Add -z nosectionheader test to bootstrap.exp H.J. Lu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).