This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH 7/7] Fix --gc-sections for C++ MIPS ELF
- From: Richard Sandiford <rsandifo at nildram dot co dot uk>
- To: binutils at sourceware dot org
- Date: Sun, 02 Dec 2007 20:39:10 +0000
- Subject: [PATCH 7/7] Fix --gc-sections for C++ MIPS ELF
- References: <87r6i4svjg.fsf@firetop.home>
The u.cie.merged field is only really useful when REMOVED == 1;
it is basically spare space if we have decided to keep the CIE.
We know when setting REMOVED to 0 what the CIE's section is,
so if we store it in this spare space, we could avoid the need
for offsets_adjusted.
Richard
bfd/
* elf-bfd.h (eh_cie_fde): Replace u.cie.merged with a union of
a merged field and a sec field.
(eh_frame_hdr_info): Remove offsets_adjusted.
* elf-eh-frame.c (_bfd_elf_parse_eh_frame): Update accesses to
the CIE merged field.
(_bfd_elf_gc_mark_fdes): Likewise.
(_bfd_elf_discard_section_eh_frame): Likewise. Set u.cie.u.sec
when clearing the removed flag.
(_bfd_elf_eh_frame_section_offset): Remove offsets_adjusted handling.
(_bfd_elf_write_section_eh_frame): Likewise. Apply output_offsets
where appropriate.
Index: bfd/elf-bfd.h
===================================================================
--- bfd/elf-bfd.h 2007-12-02 17:46:04.000000000 +0000
+++ bfd/elf-bfd.h 2007-12-02 17:57:08.000000000 +0000
@@ -277,11 +277,20 @@ struct eh_cie_fde
} fde;
struct {
/* In general, equivalent CIEs are grouped together, with one CIE
- representing all the others in a group. If REMOVED == 0,
- this CIE is the group representative. If REMOVED == 1,
- following this pointer brings us "closer" to the CIE's group
- representative, and reapplying always gives the representative. */
- struct eh_cie_fde *merged;
+ representing all the others in a group.
+
+ If REMOVED == 0, this CIE is the group representative, and
+ U.SEC points to the .eh_frame section that contains the CIE.
+
+ If REMOVED == 1, this CIE is the group representative if
+ U.MERGED is a self pointer. Otherwise, following U.MERGED
+ brings us "closer" to the CIE's group representative;
+ if U.MERGED is not the group representative, then
+ U.MERGED->U.MERGED is. */
+ union {
+ struct eh_cie_fde *merged;
+ asection *sec;
+ } u;
/* True if we have marked relocations associated with this CIE. */
unsigned int gc_mark : 1;
@@ -352,7 +361,6 @@ struct eh_frame_hdr_info
We build it if we successfully read all .eh_frame input sections
and recognize them. */
bfd_boolean table;
- bfd_boolean offsets_adjusted;
};
/* ELF linker hash table. */
Index: bfd/elf-eh-frame.c
===================================================================
--- bfd/elf-eh-frame.c 2007-12-02 17:45:12.000000000 +0000
+++ bfd/elf-eh-frame.c 2007-12-02 17:56:21.000000000 +0000
@@ -935,7 +935,7 @@ #define GET_RELOC(buf) \
}
cie = (struct cie *) *loc;
}
- this_inf->u.cie.merged = cie->cie_inf;
+ this_inf->u.cie.u.merged = cie->cie_inf;
ecies[ecie_count].cie = cie;
ecies[ecie_count++].local_cie = this_inf;
}
@@ -1019,7 +1019,7 @@ _bfd_elf_gc_mark_fdes (struct bfd_link_i
/* 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;
+ merged = cie->u.cie.u.merged;
if (!merged->u.cie.gc_mark)
{
merged->u.cie.gc_mark = 1;
@@ -1079,19 +1079,20 @@ _bfd_elf_gc_mark_fdes (struct bfd_link_i
cie = ent->u.fde.cie_inf;
if (cie->removed)
{
- merged = cie->u.cie.merged;
+ merged = cie->u.cie.u.merged;
if (!merged->removed)
/* We have decided to keep the group representative. */
ent->u.fde.cie_inf = merged;
- else if (merged->u.cie.merged != merged)
+ else if (merged->u.cie.u.merged != merged)
/* We didn't keep the original group representative,
but we did keep an alternative. */
- ent->u.fde.cie_inf = merged->u.cie.merged;
+ ent->u.fde.cie_inf = merged->u.cie.u.merged;
else
{
/* Make the local CIE represent the merged group. */
- merged->u.cie.merged = cie;
+ merged->u.cie.u.merged = cie;
cie->removed = 0;
+ cie->u.cie.u.sec = sec;
cie->u.cie.make_lsda_relative
= merged->u.cie.make_lsda_relative;
}
@@ -1211,8 +1212,6 @@ _bfd_elf_eh_frame_section_offset (bfd *o
htab = elf_hash_table (info);
hdr_info = &htab->eh_info;
- if (hdr_info->offsets_adjusted)
- offset += sec->output_offset;
lo = 0;
hi = sec_info->count;
@@ -1265,8 +1264,6 @@ _bfd_elf_eh_frame_section_offset (bfd *o
return (bfd_vma) -2;
}
- if (hdr_info->offsets_adjusted)
- offset -= sec->output_offset;
/* Any new augmentation bytes go before the first relocation. */
return (offset + sec_info->entry[mid].new_offset
- sec_info->entry[mid].offset
@@ -1301,38 +1298,6 @@ _bfd_elf_write_section_eh_frame (bfd *ab
htab = elf_hash_table (info);
hdr_info = &htab->eh_info;
- /* First convert all offsets to output section offsets, so that a
- CIE offset is valid if the CIE is used by a FDE from some other
- section. This can happen when duplicate CIEs are deleted in
- _bfd_elf_discard_section_eh_frame. We do all sections here because
- this function might not be called on sections in the same order as
- _bfd_elf_discard_section_eh_frame. */
- if (!hdr_info->offsets_adjusted)
- {
- bfd *ibfd;
- asection *eh;
- struct eh_frame_sec_info *eh_inf;
-
- for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
- {
- if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
- || (ibfd->flags & DYNAMIC) != 0)
- continue;
-
- eh = bfd_get_section_by_name (ibfd, ".eh_frame");
- if (eh == NULL || eh->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
- continue;
-
- eh_inf = elf_section_data (eh)->sec_info;
- for (ent = eh_inf->entry; ent < eh_inf->entry + eh_inf->count; ++ent)
- {
- ent->offset += eh->output_offset;
- ent->new_offset += eh->output_offset;
- }
- }
- hdr_info->offsets_adjusted = TRUE;
- }
-
if (hdr_info->table && hdr_info->array == NULL)
hdr_info->array
= bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array));
@@ -1346,13 +1311,11 @@ _bfd_elf_write_section_eh_frame (bfd *ab
not reordered */
for (ent = sec_info->entry + sec_info->count; ent-- != sec_info->entry;)
if (!ent->removed && ent->new_offset > ent->offset)
- memmove (contents + ent->new_offset - sec->output_offset,
- contents + ent->offset - sec->output_offset, ent->size);
+ memmove (contents + ent->new_offset, contents + ent->offset, ent->size);
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
if (!ent->removed && ent->new_offset < ent->offset)
- memmove (contents + ent->new_offset - sec->output_offset,
- contents + ent->offset - sec->output_offset, ent->size);
+ memmove (contents + ent->new_offset, contents + ent->offset, ent->size);
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
{
@@ -1369,7 +1332,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
continue;
}
- buf = contents + ent->new_offset - sec->output_offset;
+ buf = contents + ent->new_offset;
end = buf + ent->size;
new_size = size_of_output_cie_fde (ent, ptr_size);
@@ -1495,7 +1458,8 @@ _bfd_elf_write_section_eh_frame (bfd *ab
/* Skip length. */
cie = ent->u.fde.cie_inf;
buf += 4;
- value = ent->new_offset + 4 - cie->new_offset;
+ value = ((ent->new_offset + sec->output_offset + 4)
+ - (cie->new_offset + cie->u.cie.u.sec->output_offset));
bfd_put_32 (abfd, value, buf);
buf += 4;
width = get_DW_EH_PE_width (ent->fde_encoding, ptr_size);
@@ -1520,11 +1484,15 @@ _bfd_elf_write_section_eh_frame (bfd *ab
break;
case DW_EH_PE_pcrel:
value += ent->offset - ent->new_offset;
- address += sec->output_section->vma + ent->offset + 8;
+ address += (sec->output_section->vma
+ + sec->output_offset
+ + ent->offset + 8);
break;
}
if (ent->make_relative)
- value -= sec->output_section->vma + ent->new_offset + 8;
+ value -= (sec->output_section->vma
+ + sec->output_offset
+ + ent->new_offset + 8);
write_value (abfd, buf, value, width);
}
@@ -1534,7 +1502,9 @@ _bfd_elf_write_section_eh_frame (bfd *ab
{
hdr_info->array[hdr_info->array_count].initial_loc = address;
hdr_info->array[hdr_info->array_count++].fde
- = sec->output_section->vma + ent->new_offset;
+ = (sec->output_section->vma
+ + sec->output_offset
+ + ent->new_offset);
}
if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel
@@ -1549,8 +1519,9 @@ _bfd_elf_write_section_eh_frame (bfd *ab
if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel)
value += ent->offset - ent->new_offset;
else if (cie->u.cie.make_lsda_relative)
- value -= (sec->output_section->vma + ent->new_offset + 8
- + ent->lsda_offset);
+ value -= (sec->output_section->vma
+ + sec->output_offset
+ + ent->new_offset + 8 + ent->lsda_offset);
write_value (abfd, buf, value, width);
}
}
@@ -1587,8 +1558,9 @@ _bfd_elf_write_section_eh_frame (bfd *ab
if ((ent->fde_encoding & 0xf0) == DW_EH_PE_pcrel)
value += ent->offset + 8 - new_offset;
if (ent->make_relative)
- value -= sec->output_section->vma + new_offset
- + ent->set_loc[cnt];
+ value -= (sec->output_section->vma
+ + sec->output_offset
+ + new_offset + ent->set_loc[cnt]);
write_value (abfd, buf, value, width);
}
}