Use strtab with GC and suffix merging for .strtab

This patch uses ELF strtab with GC and suffix merging support to create
ELF .strtab section.  There is some small memory overhead to use ELF
strtab:

==14928== HEAP SUMMARY:
==14928==     in use at exit: 3,276,318 bytes in 679 blocks
==14928==   total heap usage: 1,544 allocs, 865 frees, 15,259,146 bytes allocated

vs.

==14936== HEAP SUMMARY:
==14936==     in use at exit: 3,276,318 bytes in 679 blocks
==14936==   total heap usage: 1,532 allocs, 853 frees, 15,026,402 bytes allocated

when running:

./ld-new -m elf_x86_64 -o tmpdir/ld-partial.o -r ldgram.o ldlex-wrapper.o lexsup.o ldlang.o mri.o ldctor.o ldmain.o plugin.o ldwrite.o ldexp.o ldemul.o ldver.o ldmisc.o ldfile.o ldcref.o eelf_x86_64.o eelf32_x86_64.o eelf_i386.o eelf_iamcu.o ei386linux.o eelf_l1om.o eelf_k1om.o ldbuildid.o

The results are

  [32] .strtab STRTAB 0+ 3beff8 00407a 00 0 0 1

vs

  [32] .strtab STRTAB 0+ 3beff8 0041d8 00 0 0 1

It reduces the .strtab size by 350 bytes, about 2%

Saving on libc.so from glibc is much more since libc.so has many alias
symbols with the same suffix.  For x32 glibc,

 [82] .strtab STRTAB 0+ 81b348 0159e7 00 0 0 1

vs

 [82] .strtab STRTAB 0+ 81b8bc 019e72 00 0 0 1

It reduces the .strtab size by 17547 bytes, about 16%.

bfd/

	PR gas/18451
	* elf-bfd.h (elf_sym_strtab): New.
	(elf_link_hash_table): Add strtabcount, strtabsize and
	strtab.
	(_bfd_elf_stringtab_init): Removed.
	* elf.c (_bfd_elf_stringtab_init): Removed.
	(_bfd_elf_compute_section_file_positions): Replace
	bfd_strtab_hash/_bfd_elf_stringtab_init/_bfd_stringtab_free/
	_bfd_stringtab_size with
	elf_strtab_hash/_bfd_elf_strtab_init/_bfd_elf_strtab_free/
	_bfd_elf_strtab_size.  Use _bfd_elf_strtab_add,
	_bfd_elf_strtab_finalize and _bfd_elf_strtab_offset to get
	st_name.
	(swap_out_syms): Likewise.
	* elflink.c (elf_final_link_info): Replace bfd_strtab_hash
	with elf_strtab_hash.  Remove symbuf, symbuf_count,
	symbuf_size and shndxbuf_size.
	(elf_link_flush_output_syms): Removed.
	(elf_link_output_sym): Renamed to ...
	(elf_link_output_symstrtab): This.  Replace _bfd_stringtab_add
	with _bfd_elf_strtab_add.  Don't flush symbols to the file nor
	swap out symbols.
	(elf_link_swap_symbols_out): New.
	(elf_link_output_extsym): Replace elf_link_output_sym with
	elf_link_output_symstrtab.
	(elf_link_input_bfd): Likewise.
	(elf_final_link_free): Replace _bfd_stringtab_free with
	_bfd_elf_strtab_free.  Remove symbuf.
	(bfd_elf_final_link): Replace _bfd_elf_stringtab_init with
	_bfd_elf_strtab_init.  Don't set symbuf, symbuf_count,
	symbuf_size nor shndxbuf_size.  Initialize strtabsize and
	strtab.  Initialize symshndxbuf to -1 when number of sections
	>= 64K.  Replace elf_link_output_sym/elf_link_output_sym with
	elf_link_output_symstrtab/elf_link_output_symstrtab. Don't
	call elf_link_flush_output_syms.  Call _bfd_elf_strtab_finalize
	and elf_link_swap_symbols_out.  Replace _bfd_stringtab_size
	and _bfd_stringtab_emit with _bfd_elf_strtab_size and
	_bfd_elf_strtab_emit.

gas/testsuite/

	PR gas/18451
	* gas/elf/elf.exp: Run strtab.
	* gas/elf/strtab.d: New file.
	* gas/elf/strtab.s: Likewise.

ld/testsuite/

	PR gas/18451
	* ld-elf/strtab.d: New file.
	* ld-elf/strtab.s: Likewise.
This commit is contained in:
H.J. Lu
2015-06-25 08:16:00 -07:00
parent f8773be1be
commit ef10c3ace0
11 changed files with 326 additions and 176 deletions

122
bfd/elf.c
View File

@@ -51,7 +51,7 @@ SECTION
static int elf_sort_sections (const void *, const void *);
static bfd_boolean assign_file_positions_except_relocs (bfd *, struct bfd_link_info *);
static bfd_boolean prep_headers (bfd *);
static bfd_boolean swap_out_syms (bfd *, struct bfd_strtab_hash **, int) ;
static bfd_boolean swap_out_syms (bfd *, struct elf_strtab_hash **, int) ;
static bfd_boolean elf_read_notes (bfd *, file_ptr, bfd_size_type) ;
static bfd_boolean elf_parse_notes (bfd *abfd, char *buf, size_t size,
file_ptr offset);
@@ -1610,29 +1610,6 @@ bfd_elf_print_symbol (bfd *abfd,
break;
}
}
/* Allocate an ELF string table--force the first byte to be zero. */
struct bfd_strtab_hash *
_bfd_elf_stringtab_init (void)
{
struct bfd_strtab_hash *ret;
ret = _bfd_stringtab_init ();
if (ret != NULL)
{
bfd_size_type loc;
loc = _bfd_stringtab_add (ret, "", TRUE, FALSE);
BFD_ASSERT (loc == 0 || loc == (bfd_size_type) -1);
if (loc == (bfd_size_type) -1)
{
_bfd_stringtab_free (ret);
ret = NULL;
}
}
return ret;
}
/* ELF .o/exec file reading */
@@ -3742,7 +3719,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd,
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct fake_section_arg fsargs;
bfd_boolean failed;
struct bfd_strtab_hash *strtab = NULL;
struct elf_strtab_hash *strtab = NULL;
Elf_Internal_Shdr *shstrtab_hdr;
bfd_boolean need_symtab;
@@ -3827,9 +3804,9 @@ _bfd_elf_compute_section_file_positions (bfd *abfd,
/* Now that we know where the .strtab section goes, write it
out. */
if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
|| ! _bfd_stringtab_emit (abfd, strtab))
|| ! _bfd_elf_strtab_emit (abfd, strtab))
return FALSE;
_bfd_stringtab_free (strtab);
_bfd_elf_strtab_free (strtab);
}
abfd->output_has_begun = TRUE;
@@ -7065,18 +7042,21 @@ _bfd_elf_copy_private_symbol_data (bfd *ibfd,
static bfd_boolean
swap_out_syms (bfd *abfd,
struct bfd_strtab_hash **sttp,
struct elf_strtab_hash **sttp,
int relocatable_p)
{
const struct elf_backend_data *bed;
int symcount;
asymbol **syms;
struct bfd_strtab_hash *stt;
struct elf_strtab_hash *stt;
Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Shdr *symtab_shndx_hdr;
Elf_Internal_Shdr *symstrtab_hdr;
struct elf_sym_strtab *symstrtab;
bfd_byte *outbound_syms;
bfd_byte *outbound_shndx;
unsigned long outbound_syms_index;
unsigned long outbound_shndx_index;
int idx;
unsigned int num_locals;
bfd_size_type amt;
@@ -7086,7 +7066,7 @@ swap_out_syms (bfd *abfd,
return FALSE;
/* Dump out the symtabs. */
stt = _bfd_elf_stringtab_init ();
stt = _bfd_elf_strtab_init ();
if (stt == NULL)
return FALSE;
@@ -7102,16 +7082,29 @@ swap_out_syms (bfd *abfd,
symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
symstrtab_hdr->sh_type = SHT_STRTAB;
/* Allocate buffer to swap out the .strtab section. */
symstrtab = (struct elf_sym_strtab *) bfd_malloc ((symcount + 1)
* sizeof (*symstrtab));
if (symstrtab == NULL)
{
_bfd_elf_strtab_free (stt);
return FALSE;
}
outbound_syms = (bfd_byte *) bfd_alloc2 (abfd, 1 + symcount,
bed->s->sizeof_sym);
if (outbound_syms == NULL)
{
_bfd_stringtab_free (stt);
error_return:
_bfd_elf_strtab_free (stt);
free (symstrtab);
return FALSE;
}
symtab_hdr->contents = outbound_syms;
outbound_syms_index = 0;
outbound_shndx = NULL;
outbound_shndx_index = 0;
symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
if (symtab_shndx_hdr->sh_name != 0)
{
@@ -7119,10 +7112,7 @@ swap_out_syms (bfd *abfd,
outbound_shndx = (bfd_byte *)
bfd_zalloc2 (abfd, 1 + symcount, sizeof (Elf_External_Sym_Shndx));
if (outbound_shndx == NULL)
{
_bfd_stringtab_free (stt);
return FALSE;
}
goto error_return;
symtab_shndx_hdr->contents = outbound_shndx;
symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX;
@@ -7142,10 +7132,12 @@ swap_out_syms (bfd *abfd,
sym.st_other = 0;
sym.st_shndx = SHN_UNDEF;
sym.st_target_internal = 0;
bed->s->swap_symbol_out (abfd, &sym, outbound_syms, outbound_shndx);
outbound_syms += bed->s->sizeof_sym;
symstrtab[0].sym = sym;
symstrtab[0].dest_index = outbound_syms_index;
symstrtab[0].destshndx_index = outbound_shndx_index;
outbound_syms_index++;
if (outbound_shndx != NULL)
outbound_shndx += sizeof (Elf_External_Sym_Shndx);
outbound_shndx_index++;
}
name_local_sections
@@ -7153,7 +7145,7 @@ swap_out_syms (bfd *abfd,
&& bed->elf_backend_name_local_section_symbols (abfd));
syms = bfd_get_outsymbols (abfd);
for (idx = 0; idx < symcount; idx++)
for (idx = 0; idx < symcount;)
{
Elf_Internal_Sym sym;
bfd_vma value = syms[idx]->value;
@@ -7165,18 +7157,17 @@ swap_out_syms (bfd *abfd,
&& (flags & (BSF_SECTION_SYM | BSF_GLOBAL)) == BSF_SECTION_SYM)
{
/* Local section symbols have no name. */
sym.st_name = 0;
sym.st_name = (unsigned long) -1;
}
else
{
sym.st_name = (unsigned long) _bfd_stringtab_add (stt,
syms[idx]->name,
TRUE, FALSE);
/* Call _bfd_elf_strtab_offset after _bfd_elf_strtab_finalize
to get the final offset for st_name. */
sym.st_name
= (unsigned long) _bfd_elf_strtab_add (stt, syms[idx]->name,
FALSE);
if (sym.st_name == (unsigned long) -1)
{
_bfd_stringtab_free (stt);
return FALSE;
}
goto error_return;
}
type_ptr = elf_symbol_from (abfd, syms[idx]);
@@ -7266,8 +7257,7 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
syms[idx]->name ? syms[idx]->name : "<Local sym>",
sec->name);
bfd_set_error (bfd_error_invalid_operation);
_bfd_stringtab_free (stt);
return FALSE;
goto error_return;
}
shndx = _bfd_elf_section_from_bfd_section (abfd, sec2);
@@ -7353,14 +7343,40 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
sym.st_target_internal = 0;
}
bed->s->swap_symbol_out (abfd, &sym, outbound_syms, outbound_shndx);
outbound_syms += bed->s->sizeof_sym;
idx++;
symstrtab[idx].sym = sym;
symstrtab[idx].dest_index = outbound_syms_index;
symstrtab[idx].destshndx_index = outbound_shndx_index;
outbound_syms_index++;
if (outbound_shndx != NULL)
outbound_shndx += sizeof (Elf_External_Sym_Shndx);
outbound_shndx_index++;
}
/* Finalize the .strtab section. */
_bfd_elf_strtab_finalize (stt);
/* Swap out the .strtab section. */
for (idx = 0; idx <= symcount; idx++)
{
struct elf_sym_strtab *elfsym = &symstrtab[idx];
if (elfsym->sym.st_name == (unsigned long) -1)
elfsym->sym.st_name = 0;
else
elfsym->sym.st_name = _bfd_elf_strtab_offset (stt,
elfsym->sym.st_name);
bed->s->swap_symbol_out (abfd, &elfsym->sym,
(outbound_syms
+ (elfsym->dest_index
* bed->s->sizeof_sym)),
(outbound_shndx
+ (elfsym->destshndx_index
* sizeof (Elf_External_Sym_Shndx))));
}
free (symstrtab);
*sttp = stt;
symstrtab_hdr->sh_size = _bfd_stringtab_size (stt);
symstrtab_hdr->sh_size = _bfd_elf_strtab_size (stt);
symstrtab_hdr->sh_type = SHT_STRTAB;
symstrtab_hdr->sh_flags = 0;