* elf.c (bfd_elf_set_group_contents): Assign sh_info for ld -r when
	the signature symbol is global.
	* elflink.c (elf_link_input_bfd): Ensure group signature symbol
	is output when ld -r.  Set group sh_info when local.
	* linker.c (default_indirect_link_order): Handle group sections
	specially.
ld/
	* ldemul.c (ldemul_place_orphan): Add "name" param.
	* ldemul.h (ldemul_place_orphan): Update prototype.
	(struct ld_emulation_xfer_struct <place_orphan>): Likewise.
	* ldlang.c (lang_place_orphans): Generate unique section names here..
	* emultempl/elf32.em (place_orphan): ..rather than here.  Don't
	directly use an existing output section statement that has no
	bfd section.
	* emultempl/pe.em (place_orphan): Likewise.
	* emultempl/pep.em (place_orphan): Likewise.
	* emultempl/beos.em (place_orphan): Adjust.
	* emultempl/spuelf.em (spu_place_special_section): Adjust
	place_orphan call.
	* emultempl/genelf.em (gld${EMULATION_NAME}_after_open): New function.
	(LDEMUL_AFTER_OPEN): Define.
This commit is contained in:
Alan Modra 2008-10-03 09:40:49 +00:00
parent 81ab4297b7
commit bcacc0f587
14 changed files with 238 additions and 130 deletions

View File

@ -1,3 +1,12 @@
2008-10-03 Alan Modra <amodra@bigpond.net.au>
* elf.c (bfd_elf_set_group_contents): Assign sh_info for ld -r when
the signature symbol is global.
* elflink.c (elf_link_input_bfd): Ensure group signature symbol
is output when ld -r. Set group sh_info when local.
* linker.c (default_indirect_link_order): Handle group sections
specially.
2008-09-30 Wesley W. Terpstra <wesley@terpstra.ca>
Nick Clifton <nickc@redhat.com>

View File

@ -2681,13 +2681,15 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
*failedptr = TRUE;
}
/* Fill in the contents of a SHT_GROUP section. */
/* Fill in the contents of a SHT_GROUP section. Called from
_bfd_elf_compute_section_file_positions for gas, objcopy, and
when ELF targets use the generic linker, ld. Called for ld -r
from bfd_elf_final_link. */
void
bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
{
bfd_boolean *failedptr = failedptrarg;
unsigned long symindx;
asection *elt, *first;
unsigned char *loc;
bfd_boolean gas;
@ -2698,20 +2700,49 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
|| *failedptr)
return;
symindx = 0;
if (elf_group_id (sec) != NULL)
symindx = elf_group_id (sec)->udata.i;
if (symindx == 0)
if (elf_section_data (sec)->this_hdr.sh_info == 0)
{
/* If called from the assembler, swap_out_syms will have set up
elf_section_syms; If called for "ld -r", use target_index. */
if (elf_section_syms (abfd) != NULL)
symindx = elf_section_syms (abfd)[sec->index]->udata.i;
else
symindx = sec->target_index;
unsigned long symindx = 0;
/* elf_group_id will have been set up by objcopy and the
generic linker. */
if (elf_group_id (sec) != NULL)
symindx = elf_group_id (sec)->udata.i;
if (symindx == 0)
{
/* If called from the assembler, swap_out_syms will have set up
elf_section_syms. */
BFD_ASSERT (elf_section_syms (abfd) != NULL);
symindx = elf_section_syms (abfd)[sec->index]->udata.i;
}
elf_section_data (sec)->this_hdr.sh_info = symindx;
}
else if (elf_section_data (sec)->this_hdr.sh_info == (unsigned int) -2)
{
/* The ELF backend linker sets sh_info to -2 when the group
signature symbol is global, and thus the index can't be
set until all local symbols are output. */
asection *igroup = elf_sec_group (elf_next_in_group (sec));
struct bfd_elf_section_data *sec_data = elf_section_data (igroup);
unsigned long symndx = sec_data->this_hdr.sh_info;
unsigned long extsymoff = 0;
struct elf_link_hash_entry *h;
if (!elf_bad_symtab (igroup->owner))
{
Elf_Internal_Shdr *symtab_hdr;
symtab_hdr = &elf_tdata (igroup->owner)->symtab_hdr;
extsymoff = symtab_hdr->sh_info;
}
h = elf_sym_hashes (igroup->owner)[symndx - extsymoff];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
elf_section_data (sec)->this_hdr.sh_info = h->indx;
}
elf_section_data (sec)->this_hdr.sh_info = symindx;
/* The contents won't be allocated for "ld -r" or objcopy. */
gas = TRUE;

View File

@ -9062,6 +9062,63 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
continue;
}
if (finfo->info->relocatable
&& (o->flags & (SEC_LINKER_CREATED | SEC_GROUP)) == SEC_GROUP)
{
/* Deal with the group signature symbol. */
struct bfd_elf_section_data *sec_data = elf_section_data (o);
unsigned long symndx = sec_data->this_hdr.sh_info;
asection *osec = o->output_section;
if (symndx >= locsymcount
|| (elf_bad_symtab (input_bfd)
&& finfo->sections[symndx] == NULL))
{
struct elf_link_hash_entry *h = sym_hashes[symndx - extsymoff];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
/* Arrange for symbol to be output. */
h->indx = -2;
elf_section_data (osec)->this_hdr.sh_info = -2;
}
else if (ELF_ST_TYPE (isymbuf[symndx].st_info) == STT_SECTION)
{
/* We'll use the output section target_index. */
asection *sec = finfo->sections[symndx]->output_section;
elf_section_data (osec)->this_hdr.sh_info = sec->target_index;
}
else
{
if (finfo->indices[symndx] == -1)
{
/* Otherwise output the local symbol now. */
Elf_Internal_Sym sym = isymbuf[symndx];
asection *sec = finfo->sections[symndx]->output_section;
const char *name;
name = bfd_elf_string_from_elf_section (input_bfd,
symtab_hdr->sh_link,
sym.st_name);
if (name == NULL)
return FALSE;
sym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd,
sec);
if (sym.st_shndx == SHN_BAD)
return FALSE;
sym.st_value += o->output_offset;
finfo->indices[symndx] = bfd_get_symcount (output_bfd);
if (! elf_link_output_sym (finfo, name, &sym, o, NULL))
return FALSE;
}
elf_section_data (osec)->this_hdr.sh_info
= finfo->indices[symndx];
}
}
if ((o->flags & SEC_HAS_CONTENTS) == 0
|| (o->size == 0 && (o->flags & SEC_RELOC) == 0))
continue;

View File

@ -2796,18 +2796,36 @@ default_indirect_link_order (bfd *output_bfd,
}
}
/* Get and relocate the section contents. */
sec_size = (input_section->rawsize > input_section->size
? input_section->rawsize
: input_section->size);
contents = bfd_malloc (sec_size);
if (contents == NULL && sec_size != 0)
goto error_return;
new_contents = (bfd_get_relocated_section_contents
(output_bfd, info, link_order, contents, info->relocatable,
_bfd_generic_link_get_symbols (input_bfd)));
if (!new_contents)
goto error_return;
if ((output_section->flags & (SEC_GROUP | SEC_LINKER_CREATED)) == SEC_GROUP
&& input_section->size != 0)
{
/* Group section contents are set by bfd_elf_set_group_contents. */
if (!output_bfd->output_has_begun)
{
/* FIXME: This hack ensures bfd_elf_set_group_contents is called. */
if (!bfd_set_section_contents (output_bfd, output_section, "", 0, 1))
goto error_return;
}
new_contents = output_section->contents;
BFD_ASSERT (new_contents != NULL);
BFD_ASSERT (input_section->output_offset == 0);
}
else
{
/* Get and relocate the section contents. */
sec_size = (input_section->rawsize > input_section->size
? input_section->rawsize
: input_section->size);
contents = bfd_malloc (sec_size);
if (contents == NULL && sec_size != 0)
goto error_return;
new_contents = (bfd_get_relocated_section_contents
(output_bfd, info, link_order, contents,
info->relocatable,
_bfd_generic_link_get_symbols (input_bfd)));
if (!new_contents)
goto error_return;
}
/* Output the section contents. */
loc = input_section->output_offset * bfd_octets_per_byte (output_bfd);

View File

@ -1,3 +1,20 @@
2008-10-03 Alan Modra <amodra@bigpond.net.au>
* ldemul.c (ldemul_place_orphan): Add "name" param.
* ldemul.h (ldemul_place_orphan): Update prototype.
(struct ld_emulation_xfer_struct <place_orphan>): Likewise.
* ldlang.c (lang_place_orphans): Generate unique section names here..
* emultempl/elf32.em (place_orphan): ..rather than here. Don't
directly use an existing output section statement that has no
bfd section.
* emultempl/pe.em (place_orphan): Likewise.
* emultempl/pep.em (place_orphan): Likewise.
* emultempl/beos.em (place_orphan): Adjust.
* emultempl/spuelf.em (spu_place_special_section): Adjust
place_orphan call.
* emultempl/genelf.em (gld${EMULATION_NAME}_after_open): New function.
(LDEMUL_AFTER_OPEN): Define.
2008-09-30 Joseph Myers <joseph@codesourcery.com>
* emulparams/elf64ppc.sh (OTHER_GOT_RELOC_SECTIONS): Add .rela.opd

View File

@ -665,9 +665,8 @@ gld_${EMULATION_NAME}_before_allocation (void)
which are not mentioned in the linker script. */
static bfd_boolean
gld${EMULATION_NAME}_place_orphan (asection *s)
gld${EMULATION_NAME}_place_orphan (asection *s, const char *secname)
{
const char *secname;
char *output_secname, *ps;
lang_output_section_statement_type *os;
lang_statement_union_type *l;
@ -682,8 +681,6 @@ gld${EMULATION_NAME}_place_orphan (asection *s)
if (link_info.relocatable)
return FALSE;
secname = bfd_get_section_name (s->owner, s);
/* Everything from the '\$' on gets deleted so don't allow '\$' as the
first character. */
if (*secname == '\$')

View File

@ -62,7 +62,7 @@ fragment <<EOF
static void gld${EMULATION_NAME}_before_parse (void);
static void gld${EMULATION_NAME}_after_open (void);
static void gld${EMULATION_NAME}_before_allocation (void);
static bfd_boolean gld${EMULATION_NAME}_place_orphan (asection *s);
static bfd_boolean gld${EMULATION_NAME}_place_orphan (asection *, const char *);
static void gld${EMULATION_NAME}_finish (void);
EOF
@ -1635,7 +1635,7 @@ output_rel_find (asection *sec, int isdyn)
sections in the right segment. */
static bfd_boolean
gld${EMULATION_NAME}_place_orphan (asection *s)
gld${EMULATION_NAME}_place_orphan (asection *s, const char *secname)
{
static struct orphan_save hold[] =
{
@ -1673,15 +1673,12 @@ gld${EMULATION_NAME}_place_orphan (asection *s)
};
static int orphan_init_done = 0;
struct orphan_save *place;
const char *secname;
lang_output_section_statement_type *after;
lang_output_section_statement_type *os;
int isdyn = 0;
int iself = s->owner->xvec->flavour == bfd_target_elf_flavour;
unsigned int sh_type = iself ? elf_section_type (s) : SHT_NULL;
secname = bfd_get_section_name (s->owner, s);
if (! link_info.relocatable
&& link_info.combreloc
&& (s->flags & SEC_ALLOC))
@ -1707,28 +1704,24 @@ gld${EMULATION_NAME}_place_orphan (asection *s)
}
}
if (isdyn || (!config.unique_orphan_sections && !unique_section_p (s)))
{
/* Look through the script to see where to place this section. */
os = lang_output_section_find (secname);
/* Look through the script to see where to place this section. */
os = lang_output_section_find (secname);
if (os != NULL
&& (os->bfd_section == NULL
|| os->bfd_section->flags == 0
|| (_bfd_elf_match_sections_by_type (link_info.output_bfd,
os->bfd_section,
s->owner, s)
&& ((s->flags ^ os->bfd_section->flags)
& (SEC_LOAD | SEC_ALLOC)) == 0)))
{
/* We already have an output section statement with this
name, and its bfd section, if any, has compatible flags.
If the section already exists but does not have any flags
set, then it has been created by the linker, probably as a
result of a --section-start command line switch. */
lang_add_section (&os->children, s, os);
return TRUE;
}
if (os != NULL
&& os->bfd_section != NULL
&& (os->bfd_section->flags == 0
|| (_bfd_elf_match_sections_by_type (link_info.output_bfd,
os->bfd_section, s->owner, s)
&& ((s->flags ^ os->bfd_section->flags)
& (SEC_LOAD | SEC_ALLOC)) == 0)))
{
/* We already have an output section statement with this
name, and its bfd section has compatible flags.
If the section already exists but does not have any flags
set, then it has been created by the linker, probably as a
result of a --section-start command line switch. */
lang_add_section (&os->children, s, os);
return TRUE;
}
if (!orphan_init_done)
@ -1748,7 +1741,7 @@ gld${EMULATION_NAME}_place_orphan (asection *s)
sections into the .text section to get them out of the way. */
if (link_info.executable
&& ! link_info.relocatable
&& CONST_STRNEQ (secname, ".gnu.warning.")
&& CONST_STRNEQ (s->name, ".gnu.warning.")
&& hold[orphan_text].os != NULL)
{
lang_add_section (&hold[orphan_text].os->children, s,
@ -1803,18 +1796,6 @@ gld${EMULATION_NAME}_place_orphan (asection *s)
after = &lang_output_section_statement.head->output_section_statement;
}
/* Choose a unique name for the section. This will be needed if the
same section name appears in the input file with different
loadable or allocatable characteristics. */
if (bfd_get_section_by_name (link_info.output_bfd, secname) != NULL)
{
static int count = 1;
secname = bfd_get_unique_section_name (link_info.output_bfd,
secname, &count);
if (secname == NULL)
einfo ("%F%P: place_orphan failed: %E\n");
}
lang_insert_orphan (s, secname, after, place, NULL, NULL);
return TRUE;

View File

@ -34,7 +34,27 @@ gld${EMULATION_NAME}_finish (void)
gld${EMULATION_NAME}_map_segments (FALSE);
finish_default ();
}
static void
gld${EMULATION_NAME}_after_open (void)
{
bfd *ibfd;
asection *sec;
asymbol **syms;
if (link_info.relocatable)
for (ibfd = link_info.input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
if ((syms = bfd_get_outsymbols (ibfd)) != NULL
&& bfd_get_flavour (ibfd) == bfd_target_elf_flavour)
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
if ((sec->flags & (SEC_GROUP | SEC_LINKER_CREATED)) == SEC_GROUP)
{
struct bfd_elf_section_data *sec_data = elf_section_data (sec);
elf_group_id (sec) = syms[sec_data->this_hdr.sh_info - 1];
}
}
EOF
# Put these extra routines in ld_${EMULATION_NAME}_emulation
#
LDEMUL_FINISH=gld${EMULATION_NAME}_finish
LDEMUL_AFTER_OPEN=gld${EMULATION_NAME}_after_open

View File

@ -1613,24 +1613,20 @@ gld_${EMULATION_NAME}_finish (void)
sort_sections. */
static bfd_boolean
gld_${EMULATION_NAME}_place_orphan (asection *s)
gld_${EMULATION_NAME}_place_orphan (asection *s, const char *secname)
{
const char *secname;
const char *orig_secname;
const char *orig_secname = secname;
char *dollar = NULL;
lang_output_section_statement_type *os;
lang_statement_list_type add_child;
secname = bfd_get_section_name (s->owner, s);
/* Look through the script to see where to place this section. */
orig_secname = secname;
if (!link_info.relocatable
&& (dollar = strchr (secname, '$')) != NULL)
{
size_t len = dollar - orig_secname;
size_t len = dollar - secname;
char *newname = xmalloc (len + 1);
memcpy (newname, orig_secname, len);
memcpy (newname, secname, len);
newname[len] = '\0';
secname = newname;
}
@ -1640,13 +1636,13 @@ gld_${EMULATION_NAME}_place_orphan (asection *s)
lang_list_init (&add_child);
if (os != NULL
&& (os->bfd_section == NULL
|| os->bfd_section->flags == 0
&& os->bfd_section != NULL
&& (os->bfd_section->flags == 0
|| ((s->flags ^ os->bfd_section->flags)
& (SEC_LOAD | SEC_ALLOC)) == 0))
{
/* We already have an output section statement with this
name, and its bfd section, if any, has compatible flags.
name, and its bfd section has compatible flags.
If the section already exists but does not have any flags set,
then it has been created by the linker, probably as a result of
a --section-start command line switch. */
@ -1723,18 +1719,6 @@ gld_${EMULATION_NAME}_place_orphan (asection *s)
->output_section_statement);
}
/* Choose a unique name for the section. This will be needed if the
same section name appears in the input file with different
loadable or allocatable characteristics. */
if (bfd_get_section_by_name (link_info.output_bfd, secname) != NULL)
{
static int count = 1;
secname = bfd_get_unique_section_name (link_info.output_bfd,
secname, &count);
if (secname == NULL)
einfo ("%F%P: place_orphan failed: %E\n");
}
/* All sections in an executable must be aligned to a page boundary. */
address = exp_unop (ALIGN_K, exp_nameop (NAME, "__section_alignment__"));
os = lang_insert_orphan (s, secname, after, place, address, &add_child);

View File

@ -1372,24 +1372,20 @@ gld_${EMULATION_NAME}_finish (void)
sort_sections. */
static bfd_boolean
gld_${EMULATION_NAME}_place_orphan (asection *s)
gld_${EMULATION_NAME}_place_orphan (asection *s, const char *secname)
{
const char *secname;
const char *orig_secname;
const char *orig_secname = secname;
char *dollar = NULL;
lang_output_section_statement_type *os;
lang_statement_list_type add_child;
secname = bfd_get_section_name (s->owner, s);
/* Look through the script to see where to place this section. */
orig_secname = secname;
if (!link_info.relocatable
&& (dollar = strchr (secname, '$')) != NULL)
{
size_t len = dollar - orig_secname;
size_t len = dollar - secname;
char *newname = xmalloc (len + 1);
memcpy (newname, orig_secname, len);
memcpy (newname, secname, len);
newname[len] = '\0';
secname = newname;
}
@ -1399,13 +1395,13 @@ gld_${EMULATION_NAME}_place_orphan (asection *s)
lang_list_init (&add_child);
if (os != NULL
&& (os->bfd_section == NULL
|| os->bfd_section->flags == 0
&& os->bfd_section != NULL
&& (os->bfd_section->flags == 0
|| ((s->flags ^ os->bfd_section->flags)
& (SEC_LOAD | SEC_ALLOC)) == 0))
{
/* We already have an output section statement with this
name, and its bfd section, if any, has compatible flags.
name, and its bfd section has compatible flags.
If the section already exists but does not have any flags set,
then it has been created by the linker, probably as a result of
a --section-start command line switch. */
@ -1482,18 +1478,6 @@ gld_${EMULATION_NAME}_place_orphan (asection *s)
->output_section_statement);
}
/* Choose a unique name for the section. This will be needed if the
same section name appears in the input file with different
loadable or allocatable characteristics. */
if (bfd_get_section_by_name (link_info.output_bfd, secname) != NULL)
{
static int count = 1;
secname = bfd_get_unique_section_name (link_info.output_bfd,
secname, &count);
if (secname == NULL)
einfo ("%F%P: place_orphan failed: %E\n");
}
/* All sections in an executable must be aligned to a page boundary. */
address = exp_unop (ALIGN_K, exp_nameop (NAME, "__section_alignment__"));
os = lang_insert_orphan (s, secname, after, place, address, &add_child);

View File

@ -114,12 +114,7 @@ spu_place_special_section (asection *s, asection *o, const char *output_name)
os = lang_output_section_find (o != NULL ? o->name : output_name);
if (os == NULL)
{
const char *save = s->name;
s->name = output_name;
gld${EMULATION_NAME}_place_orphan (s);
s->name = save;
}
gld${EMULATION_NAME}_place_orphan (s, output_name);
else if (o != NULL && os->children.head != NULL)
{
lang_statement_list_type add;

View File

@ -120,10 +120,10 @@ ldemul_open_dynamic_archive (const char *arch, search_dirs_type *search,
}
bfd_boolean
ldemul_place_orphan (asection *s)
ldemul_place_orphan (asection *s, const char *name)
{
if (ld_emulation->place_orphan)
return (*ld_emulation->place_orphan) (s);
return (*ld_emulation->place_orphan) (s, name);
return FALSE;
}

View File

@ -59,7 +59,7 @@ extern void ldemul_set_symbols
extern void ldemul_create_output_section_statements
(void);
extern bfd_boolean ldemul_place_orphan
(asection *);
(asection *, const char *);
extern bfd_boolean ldemul_parse_args
(int, char **);
extern void ldemul_add_options
@ -152,7 +152,7 @@ typedef struct ld_emulation_xfer_struct {
the default action should be taken. This field may be NULL, in
which case the default action will always be taken. */
bfd_boolean (*place_orphan)
(asection *);
(asection *, const char *);
/* Run after assigning parsing with the args, but before
reading the script. Used to initialize symbols used in the script. */

View File

@ -5652,14 +5652,29 @@ lang_place_orphans (void)
default_common_section);
}
}
else if (ldemul_place_orphan (s))
;
else
{
lang_output_section_statement_type *os;
const char *name = s->name;
os = lang_output_section_statement_lookup (s->name, 0, TRUE);
lang_add_section (&os->children, s, os);
if ((config.unique_orphan_sections
|| unique_section_p (s))
&& bfd_get_section_by_name (link_info.output_bfd,
name) != NULL)
{
static int count = 1;
name = bfd_get_unique_section_name (link_info.output_bfd,
name, &count);
if (name == NULL)
einfo ("%F%P: place_orphan failed: %E\n");
}
if (!ldemul_place_orphan (s, name))
{
lang_output_section_statement_type *os;
os = lang_output_section_statement_lookup (name, 0,
TRUE);
lang_add_section (&os->children, s, os);
}
}
}
}