+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>
*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;
|| *failedptr)
return;
- symindx = 0;
- if (elf_group_id (sec) != NULL)
- symindx = elf_group_id (sec)->udata.i;
+ if (elf_section_data (sec)->this_hdr.sh_info == 0)
+ {
+ 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 (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)
{
- /* 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;
+ /* 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;
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;
}
}
- /* 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);
+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
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;
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 == '\$')
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
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[] =
{
};
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))
}
}
- 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);
+
+ 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)))
{
- /* 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;
- }
+ /* 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)
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,
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;
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
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;
}
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. */
->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);
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;
}
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. */
->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);
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;
}
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;
}
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
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. */
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);
+ }
}
}
}