summaryrefslogtreecommitdiff
path: root/bfd/elf.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@bigpond.net.au>2002-06-04 01:05:21 +0000
committerAlan Modra <amodra@bigpond.net.au>2002-06-04 01:05:21 +0000
commit85289e194a25eefc38b9bbd76375d04385a00751 (patch)
tree8930eb7e80c089b4af80edaf08d89c2d15f5a378 /bfd/elf.c
parent28d6676c8a48b6c8b842b91150634833fa121d97 (diff)
downloadgdb-85289e194a25eefc38b9bbd76375d04385a00751.tar.gz
* elf.c (setup_group): Set SEC_LINK_ONCE on GRP_COMDAT groups.
(bfd_section_from_shdr): Likewise. Set section name of group sections from signature. (group_signature): Split out from setup_group. Ensure symbol table is available. (bfd_elf_discard_group): New function. (_bfd_elf_make_section_from_shdr): Don't set SEC_LINK_ONCE on .gnu.linkonce* sections if they are members of a group. (set_group_contents): Set GRP_COMDAT flag. * section.c (bfd_discard_group): New function. * bfd-in.h (bfd_elf_discard_group): Declare. * bfd-in2.h: Regenerate. * elf-bfd.h (struct bfd_elf_section_data): Add linkonce_p field. (elf_linkonce_p): Define.
Diffstat (limited to 'bfd/elf.c')
-rw-r--r--bfd/elf.c87
1 files changed, 68 insertions, 19 deletions
diff --git a/bfd/elf.c b/bfd/elf.c
index a92827ff03b..e1e929f2750 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -50,6 +50,7 @@ static boolean prep_headers PARAMS ((bfd *));
static boolean swap_out_syms PARAMS ((bfd *, struct bfd_strtab_hash **, int));
static boolean copy_private_bfd_data PARAMS ((bfd *, bfd *));
static char *elf_read PARAMS ((bfd *, file_ptr, bfd_size_type));
+static const char *group_signature PARAMS ((bfd *, Elf_Internal_Shdr *));
static boolean setup_group PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
static void merge_sections_remove_hook PARAMS ((bfd *, asection *));
static void elf_fake_sections PARAMS ((bfd *, asection *, PTR));
@@ -361,6 +362,35 @@ typedef union elf_internal_group {
unsigned int flags;
} Elf_Internal_Group;
+/* Return the name of the group signature symbol. Why isn't the
+ signature just a string? */
+
+static const char *
+group_signature (abfd, ghdr)
+ bfd *abfd;
+ Elf_Internal_Shdr *ghdr;
+{
+ struct elf_backend_data *bed;
+ file_ptr pos;
+ unsigned char ename[4];
+ unsigned long iname;
+
+ /* First we need to ensure the symbol table is available. */
+ if (! bfd_section_from_shdr (abfd, ghdr->sh_link))
+ return NULL;
+
+ /* Fortunately, the name index is at the same place in the external
+ symbol for both 32 and 64 bit ELF. */
+ bed = get_elf_backend_data (abfd);
+ pos = elf_tdata (abfd)->symtab_hdr.sh_offset;
+ pos += ghdr->sh_info * bed->s->sizeof_sym;
+ if (bfd_seek (abfd, pos, SEEK_SET) != 0
+ || bfd_bread (ename, (bfd_size_type) 4, abfd) != 4)
+ return NULL;
+ iname = H_GET_32 (abfd, ename);
+ return elf_string_from_elf_strtab (abfd, iname);
+}
+
/* Set next_in_group list pointer, and group name for NEWSECT. */
static boolean
@@ -440,6 +470,9 @@ setup_group (abfd, hdr, newsect)
if (src == shdr->contents)
{
dest->flags = idx;
+ if (shdr->bfd_section != NULL && (idx & GRP_COMDAT))
+ shdr->bfd_section->flags
+ |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
break;
}
if (idx >= shnum)
@@ -492,32 +525,20 @@ setup_group (abfd, hdr, newsect)
}
else
{
- struct elf_backend_data *bed;
- file_ptr pos;
- unsigned char ename[4];
- unsigned long iname;
const char *gname;
- /* Humbug. Get the name from the group signature
- symbol. Why isn't the signature just a string?
- Fortunately, the name index is at the same
- place in the external symbol for both 32 and 64
- bit ELF. */
- bed = get_elf_backend_data (abfd);
- pos = elf_tdata (abfd)->symtab_hdr.sh_offset;
- pos += shdr->sh_info * bed->s->sizeof_sym;
- if (bfd_seek (abfd, pos, SEEK_SET) != 0
- || bfd_bread (ename, (bfd_size_type) 4, abfd) != 4)
+ gname = group_signature (abfd, shdr);
+ if (gname == NULL)
return false;
- iname = H_GET_32 (abfd, ename);
- gname = elf_string_from_elf_strtab (abfd, iname);
elf_group_name (newsect) = gname;
/* Start a circular list with one element. */
elf_next_in_group (newsect) = newsect;
}
+
if (shdr->bfd_section != NULL)
elf_next_in_group (shdr->bfd_section) = newsect;
+
i = num_group - 1;
break;
}
@@ -532,6 +553,24 @@ setup_group (abfd, hdr, newsect)
return true;
}
+void
+bfd_elf_discard_group (abfd, group)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ asection *group;
+{
+ asection *first = elf_next_in_group (group);
+ asection *s = first;
+
+ while (s != NULL)
+ {
+ s->output_section = bfd_abs_section_ptr;
+ s = elf_next_in_group (s);
+ /* These lists are circular. */
+ if (s == first)
+ break;
+ }
+}
+
/* Make a BFD section from an ELF section. We store a pointer to the
BFD section in the bfd_section field of the header. */
@@ -620,7 +659,8 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name)
The symbols will be defined as weak, so that multiple definitions
are permitted. The GNU linker extension is to actually discard
all but one of the sections. */
- if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0)
+ if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0
+ && elf_next_in_group (newsect) == NULL)
flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
bed = get_elf_backend_data (abfd);
@@ -1820,7 +1860,12 @@ bfd_section_from_shdr (abfd, shindex)
return true;
case SHT_GROUP:
- /* Make a section for objcopy and relocatable links. */
+ /* We need a BFD section for objcopy and relocatable linking,
+ and it's handy to have the signature available as the section
+ name. */
+ name = group_signature (abfd, hdr);
+ if (name == NULL)
+ return false;
if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name))
return false;
if (hdr->contents != NULL)
@@ -1829,6 +1874,10 @@ bfd_section_from_shdr (abfd, shindex)
unsigned int n_elt = hdr->sh_size / 4;
asection *s;
+ if (idx->flags & GRP_COMDAT)
+ hdr->bfd_section->flags
+ |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
+
while (--n_elt != 0)
if ((s = (++idx)->shdr->bfd_section) != NULL
&& elf_next_in_group (s) != NULL)
@@ -2369,7 +2418,7 @@ set_group_contents (abfd, sec, failedptrarg)
while (elt != elf_next_in_group (l->u.indirect.section));
loc -= 4;
- H_PUT_32 (abfd, 0, loc);
+ H_PUT_32 (abfd, sec->flags & SEC_LINK_ONCE ? GRP_COMDAT : 0, loc);
BFD_ASSERT (loc == sec->contents);
}