* elf-bfd.h (eh_cie_fde): Add u.fde.next_for_section and
	u.cie.gc_mark.
	(bfd_elf_section_data): Add fde_list.
	(elf_fde_list): New macro.
	(elf_obj_tdata): Add eh_frame_section.
	(elf_eh_frame_section): New macro.
	(_bfd_elf_gc_mark_reloc): Remove last parameter.
	(_bfd_elf_gc_mark_fdes): Declare.
	* elf-eh-frame.c (_bfd_elf_get_eh_frame_sec_info): Chain the FDEs
	for each input section.
	(mark_entry, _bfd_elf_gc_mark_fdes): New functions.
	* elflink.c (_bfd_elf_gc_mark_reloc): Remove is_eh parameter.
	(_bfd_elf_gc_mark): Update call accordingly.  Mark the relocations
	againts the section's FDEs.  Don't mark the bfd's elf_eh_frame_section.
	(bfd_elf_gc_sections): Parse each input bfd's .eh_frame before
	marking any input sections.  Remove the current EH handling.
	* section.c (bfd_section): Remove gc_mark_from_eh.
	* ecoff.c (bfd_debug_section): Update initializer accordingly.
This commit is contained in:
Richard Sandiford 2007-12-15 09:34:48 +00:00
parent ca92cecbbe
commit 9d0a14d3f3
6 changed files with 145 additions and 79 deletions

View File

@ -1,3 +1,24 @@
2007-12-15 Richard Sandiford <rsandifo@nildram.co.uk>
* elf-bfd.h (eh_cie_fde): Add u.fde.next_for_section and
u.cie.gc_mark.
(bfd_elf_section_data): Add fde_list.
(elf_fde_list): New macro.
(elf_obj_tdata): Add eh_frame_section.
(elf_eh_frame_section): New macro.
(_bfd_elf_gc_mark_reloc): Remove last parameter.
(_bfd_elf_gc_mark_fdes): Declare.
* elf-eh-frame.c (_bfd_elf_get_eh_frame_sec_info): Chain the FDEs
for each input section.
(mark_entry, _bfd_elf_gc_mark_fdes): New functions.
* elflink.c (_bfd_elf_gc_mark_reloc): Remove is_eh parameter.
(_bfd_elf_gc_mark): Update call accordingly. Mark the relocations
againts the section's FDEs. Don't mark the bfd's elf_eh_frame_section.
(bfd_elf_gc_sections): Parse each input bfd's .eh_frame before
marking any input sections. Remove the current EH handling.
* section.c (bfd_section): Remove gc_mark_from_eh.
* ecoff.c (bfd_debug_section): Update initializer accordingly.
2007-12-15 Richard Sandiford <rsandifo@nildram.co.uk>
* elf-bfd.h (eh_cie_fde): Add u.cie. Document how u.fde.cie_inf

View File

@ -55,8 +55,8 @@ static asection bfd_debug_section =
{
/* name, id, index, next, prev, flags, user_set_vma, */
"*DEBUG*", 0, 0, NULL, NULL, 0, 0,
/* linker_mark, linker_has_input, gc_mark, gc_mark_from_eh, */
0, 0, 1, 0,
/* linker_mark, linker_has_input, gc_mark, */
0, 0, 1,
/* segment_mark, sec_info_type, use_rela_p, has_tls_reloc, */
0, 0, 0, 0,
/* has_gp_reloc, need_finalize_relax, reloc_done, */

View File

@ -273,6 +273,7 @@ struct eh_cie_fde
the output FDE. The CIE's REMOVED field is also 0, but the CIE
might belong to a different .eh_frame input section from the FDE. */
struct eh_cie_fde *cie_inf;
struct eh_cie_fde *next_for_section;
} fde;
struct {
/* In general, equivalent CIEs are grouped together, with one CIE
@ -281,6 +282,9 @@ struct eh_cie_fde
following this pointer brings us "closer" to the CIE's group
representative, and reapplying always gives the representative. */
struct eh_cie_fde *merged;
/* True if we have marked relocations associated with this CIE. */
unsigned int gc_mark : 1;
} cie;
} u;
unsigned int reloc_index;
@ -1243,6 +1247,10 @@ struct bfd_elf_section_data
the linker. For the SHT_GROUP section, points at first member. */
asection *next_in_group;
/* The FDEs associated with this section. The u.fde.next_in_section
field acts as a chain pointer. */
struct eh_cie_fde *fde_list;
/* A pointer used for various section optimizations. */
void *sec_info;
};
@ -1254,6 +1262,7 @@ struct bfd_elf_section_data
#define elf_group_name(sec) (elf_section_data(sec)->group.name)
#define elf_group_id(sec) (elf_section_data(sec)->group.id)
#define elf_next_in_group(sec) (elf_section_data(sec)->next_in_group)
#define elf_fde_list(sec) (elf_section_data(sec)->fde_list)
#define elf_sec_group(sec) (elf_section_data(sec)->sec_group)
#define xvec_get_elf_backend_data(xvec) \
@ -1459,6 +1468,9 @@ struct elf_obj_tdata
asection *elf_data_section;
asection *elf_text_section;
/* A pointer to the .eh_frame section. */
asection *eh_frame_section;
/* Whether a dyanmic object was specified normally on the linker
command line, or was specified when --as-needed was in effect,
or was found via a DT_NEEDED entry. */
@ -1504,6 +1516,8 @@ struct elf_obj_tdata
#define elf_dynversym(bfd) (elf_tdata(bfd) -> dynversym_section)
#define elf_dynverdef(bfd) (elf_tdata(bfd) -> dynverdef_section)
#define elf_dynverref(bfd) (elf_tdata(bfd) -> dynverref_section)
#define elf_eh_frame_section(bfd) \
(elf_tdata(bfd) -> eh_frame_section)
#define elf_num_locals(bfd) (elf_tdata(bfd) -> num_locals)
#define elf_num_globals(bfd) (elf_tdata(bfd) -> num_globals)
#define elf_section_syms(bfd) (elf_tdata(bfd) -> section_syms)
@ -2004,7 +2018,11 @@ extern asection *_bfd_elf_gc_mark_rsec
extern bfd_boolean _bfd_elf_gc_mark_reloc
(struct bfd_link_info *, asection *, elf_gc_mark_hook_fn,
struct elf_reloc_cookie *, bfd_boolean);
struct elf_reloc_cookie *);
extern bfd_boolean _bfd_elf_gc_mark_fdes
(struct bfd_link_info *, asection *, asection *, elf_gc_mark_hook_fn,
struct elf_reloc_cookie *);
extern bfd_boolean _bfd_elf_gc_mark
(struct bfd_link_info *, asection *, elf_gc_mark_hook_fn);

View File

@ -475,6 +475,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
unsigned int ptr_size;
unsigned int num_cies;
unsigned int num_entries;
elf_gc_mark_hook_fn gc_mark_hook;
htab = elf_hash_table (info);
hdr_info = &htab->eh_info;
@ -577,6 +578,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
buf = ehbuf;
ecie_count = 0;
gc_mark_hook = get_elf_backend_data (abfd)->gc_mark_hook;
while ((bfd_size_type) (buf - ehbuf) != sec->size)
{
char *aug;
@ -821,6 +823,8 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
}
else
{
asection *rsec;
/* Find the corresponding CIE. */
unsigned int cie_offset = this_inf->offset + 4 - hdr_id;
for (ecie = ecies; ecie < ecies + ecie_count; ++ecie)
@ -836,6 +840,12 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
ENSURE_NO_RELOCS (buf);
REQUIRE (GET_RELOC (buf));
/* Chain together the FDEs for each section. */
rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
REQUIRE (rsec && rsec->owner == abfd);
this_inf->u.fde.next_for_section = elf_fde_list (rsec);
elf_fde_list (rsec) = this_inf;
/* Skip the initial location and address range. */
start = buf;
length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size);
@ -976,6 +986,55 @@ _bfd_elf_end_eh_frame_parsing (struct bfd_link_info *info)
hdr_info->parsed_eh_frames = TRUE;
}
/* Mark all relocations against CIE or FDE ENT, which occurs in
.eh_frame section SEC. COOKIE describes the relocations in SEC;
its "rel" field can be changed freely. */
static bfd_boolean
mark_entry (struct bfd_link_info *info, asection *sec,
struct eh_cie_fde *ent, elf_gc_mark_hook_fn gc_mark_hook,
struct elf_reloc_cookie *cookie)
{
for (cookie->rel = cookie->rels + ent->reloc_index;
cookie->rel < cookie->relend
&& cookie->rel->r_offset < ent->offset + ent->size;
cookie->rel++)
if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, cookie))
return FALSE;
return TRUE;
}
/* Mark all the relocations against FDEs that relate to code in input
section SEC. The FDEs belong to .eh_frame section EH_FRAME, whose
relocations are described by COOKIE. */
bfd_boolean
_bfd_elf_gc_mark_fdes (struct bfd_link_info *info, asection *sec,
asection *eh_frame, elf_gc_mark_hook_fn gc_mark_hook,
struct elf_reloc_cookie *cookie)
{
struct eh_cie_fde *fde, *cie, *merged;
for (fde = elf_fde_list (sec); fde; fde = fde->u.fde.next_for_section)
{
if (!mark_entry (info, eh_frame, fde, gc_mark_hook, cookie))
return FALSE;
/* At this stage, all cie_inf fields point to local CIEs, so we
can use the same cookie to refer to them. */
cie = fde->u.fde.cie_inf;
merged = cie->u.cie.merged;
if (!merged->u.cie.gc_mark)
{
merged->u.cie.gc_mark = 1;
if (!mark_entry (info, eh_frame, cie, gc_mark_hook, cookie))
return FALSE;
}
}
return TRUE;
}
/* This function is called for each input file before the .eh_frame
section is relocated. It discards duplicate CIEs and FDEs for discarded
functions. The function returns TRUE iff any entries have been

View File

@ -11137,15 +11137,13 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
/* COOKIE->rel describes a relocation against section SEC, which is
a section we've decided to keep. Mark the section that contains
the relocation symbol. IS_EH is true if the mark comes from
.eh_frame. */
the relocation symbol. */
bfd_boolean
_bfd_elf_gc_mark_reloc (struct bfd_link_info *info,
asection *sec,
elf_gc_mark_hook_fn gc_mark_hook,
struct elf_reloc_cookie *cookie,
bfd_boolean is_eh)
struct elf_reloc_cookie *cookie)
{
asection *rsec;
@ -11154,8 +11152,6 @@ _bfd_elf_gc_mark_reloc (struct bfd_link_info *info,
{
if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
rsec->gc_mark = 1;
else if (is_eh)
rsec->gc_mark_from_eh = 1;
else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
return FALSE;
}
@ -11172,8 +11168,7 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
elf_gc_mark_hook_fn gc_mark_hook)
{
bfd_boolean ret;
bfd_boolean is_eh;
asection *group_sec;
asection *group_sec, *eh_frame;
sec->gc_mark = 1;
@ -11185,8 +11180,10 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
/* Look through the section relocs. */
ret = TRUE;
is_eh = strcmp (sec->name, ".eh_frame") == 0;
if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0)
eh_frame = elf_eh_frame_section (sec->owner);
if ((sec->flags & SEC_RELOC) != 0
&& sec->reloc_count > 0
&& sec != eh_frame)
{
struct elf_reloc_cookie cookie;
@ -11195,8 +11192,7 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
else
{
for (; cookie.rel < cookie.relend; cookie.rel++)
if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook,
&cookie, is_eh))
if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, &cookie))
{
ret = FALSE;
break;
@ -11204,6 +11200,22 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
fini_reloc_cookie_for_section (&cookie, sec);
}
}
if (ret && eh_frame && elf_fde_list (sec))
{
struct elf_reloc_cookie cookie;
if (!init_reloc_cookie_for_section (&cookie, info, eh_frame))
ret = FALSE;
else
{
if (!_bfd_elf_gc_mark_fdes (info, sec, eh_frame,
gc_mark_hook, &cookie))
ret = FALSE;
fini_reloc_cookie_for_section (&cookie, eh_frame);
}
}
return ret;
}
@ -11469,6 +11481,25 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
return TRUE;
}
/* Try to parse each bfd's .eh_frame section. Point elf_eh_frame_section
at the .eh_frame section if we can mark the FDEs individually. */
_bfd_elf_begin_eh_frame_parsing (info);
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
{
asection *sec;
struct elf_reloc_cookie cookie;
sec = bfd_get_section_by_name (sub, ".eh_frame");
if (sec && init_reloc_cookie_for_section (&cookie, info, sec))
{
_bfd_elf_parse_eh_frame (sub, info, sec, &cookie);
if (elf_section_data (sec)->sec_info)
elf_eh_frame_section (sub) = sec;
fini_reloc_cookie_for_section (&cookie, sec);
}
}
_bfd_elf_end_eh_frame_parsing (info);
/* Apply transitive closure to the vtable entry usage info. */
elf_link_hash_traverse (elf_hash_table (info),
elf_gc_propagate_vtable_entries_used,
@ -11508,68 +11539,6 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
if (bed->gc_mark_extra_sections)
bed->gc_mark_extra_sections(info, gc_mark_hook);
/* ... again for sections marked from eh_frame. */
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
{
asection *o;
if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
continue;
/* Keep .gcc_except_table.* if the associated .text.* (or the
associated .gnu.linkonce.t.* if .text.* doesn't exist) is
marked. This isn't very nice, but the proper solution,
splitting .eh_frame up and using comdat doesn't pan out
easily due to needing special relocs to handle the
difference of two symbols in separate sections.
Don't keep code sections referenced by .eh_frame. */
#define TEXT_PREFIX ".text."
#define TEXT_PREFIX2 ".gnu.linkonce.t."
#define GCC_EXCEPT_TABLE_PREFIX ".gcc_except_table."
for (o = sub->sections; o != NULL; o = o->next)
if (!o->gc_mark && o->gc_mark_from_eh && (o->flags & SEC_CODE) == 0)
{
if (CONST_STRNEQ (o->name, GCC_EXCEPT_TABLE_PREFIX))
{
char *fn_name;
const char *sec_name;
asection *fn_text;
unsigned o_name_prefix_len , fn_name_prefix_len, tmp;
o_name_prefix_len = strlen (GCC_EXCEPT_TABLE_PREFIX);
sec_name = o->name + o_name_prefix_len;
fn_name_prefix_len = strlen (TEXT_PREFIX);
tmp = strlen (TEXT_PREFIX2);
if (tmp > fn_name_prefix_len)
fn_name_prefix_len = tmp;
fn_name
= bfd_malloc (fn_name_prefix_len + strlen (sec_name) + 1);
if (fn_name == NULL)
return FALSE;
/* Try the first prefix. */
sprintf (fn_name, "%s%s", TEXT_PREFIX, sec_name);
fn_text = bfd_get_section_by_name (sub, fn_name);
/* Try the second prefix. */
if (fn_text == NULL)
{
sprintf (fn_name, "%s%s", TEXT_PREFIX2, sec_name);
fn_text = bfd_get_section_by_name (sub, fn_name);
}
free (fn_name);
if (fn_text == NULL || !fn_text->gc_mark)
continue;
}
/* If not using specially named exception table section,
then keep whatever we are using. */
if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
return FALSE;
}
}
/* ... and mark SEC_EXCLUDE for those that go. */
return elf_gc_sweep (abfd, info);
}

View File

@ -357,9 +357,8 @@ CODE_FRAGMENT
. output sections that have an input section. *}
. unsigned int linker_has_input : 1;
.
. {* Mark flags used by some linker backends for garbage collection. *}
. {* Mark flag used by some linker backends for garbage collection. *}
. unsigned int gc_mark : 1;
. unsigned int gc_mark_from_eh : 1;
.
. {* The following flags are used by the ELF linker. *}
.