* 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.
This commit is contained in:
Alan Modra 2002-06-04 01:05:21 +00:00
parent 90937f86aa
commit b885599bed
6 changed files with 117 additions and 19 deletions

View file

@ -1,3 +1,20 @@
2002-06-04 Alan Modra <amodra@bigpond.net.au>
* 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.
2002-06-04 Alan Modra <amodra@bigpond.net.au>
* elf.c (bfd_section_from_shdr): Make "name" const.

View file

@ -657,6 +657,8 @@ extern boolean bfd_elf32_discard_info
PARAMS ((bfd *, struct bfd_link_info *));
extern boolean bfd_elf64_discard_info
PARAMS ((bfd *, struct bfd_link_info *));
extern void bfd_elf_discard_group
PARAMS ((bfd *, struct sec *));
/* Return an upper bound on the number of bytes required to store a
copy of ABFD's program header table entries. Return -1 if an error

View file

@ -663,6 +663,8 @@ extern boolean bfd_elf32_discard_info
PARAMS ((bfd *, struct bfd_link_info *));
extern boolean bfd_elf64_discard_info
PARAMS ((bfd *, struct bfd_link_info *));
extern void bfd_elf_discard_group
PARAMS ((bfd *, struct sec *));
/* Return an upper bound on the number of bytes required to store a
copy of ABFD's program header table entries. Return -1 if an error
@ -1450,6 +1452,9 @@ bfd_copy_private_section_data PARAMS ((bfd *ibfd, asection *isec,
void
_bfd_strip_section_from_output PARAMS ((struct bfd_link_info *info, asection *section));
void
bfd_discard_group PARAMS ((bfd *abfd, asection *group));
enum bfd_architecture
{
bfd_arch_unknown, /* File arch not known. */

View file

@ -926,11 +926,15 @@ struct bfd_elf_section_data
/* Nonzero if this section uses RELA relocations, rather than REL. */
unsigned int use_rela_p:1;
/* Nonzero when a group is COMDAT. */
unsigned int linkonce_p:1;
};
#define elf_section_data(sec) ((struct bfd_elf_section_data*)sec->used_by_bfd)
#define elf_group_name(sec) (elf_section_data(sec)->group_name)
#define elf_next_in_group(sec) (elf_section_data(sec)->next_in_group)
#define elf_linkonce_p(sec) (elf_section_data(sec)->linkonce_p)
/* Return true if section has been discarded. */
#define elf_discarded_section(sec) \

View file

@ -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);
}

View file

@ -1375,3 +1375,24 @@ _bfd_strip_section_from_output (info, s)
s->flags |= SEC_EXCLUDE;
}
/*
FUNCTION
bfd_discard_group
SYNOPSIS
void bfd_discard_group (bfd *abfd, asection *group);
DESCRIPTION
Remove all members of @var{group} from the output.
*/
void
bfd_discard_group (abfd, group)
bfd *abfd;
asection *group;
{
if ((group->flags & SEC_GROUP) != 0
&& abfd->xvec->flavour == bfd_target_elf_flavour)
bfd_elf_discard_group (abfd, group);
}