diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 46e90c1277..91b48bce80 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2007-12-15 Richard Sandiford + + * 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. + 2007-12-15 Richard Sandiford * elf-bfd.h (eh_cie_fde): Move add_fde_encoding and diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 4b6c1af705..918eec31ce 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -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; @@ -355,7 +364,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. */ diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c index 5827a24743..f8386d340e 100644 --- a/bfd/elf-eh-frame.c +++ b/bfd/elf-eh-frame.c @@ -935,7 +935,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, } 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_info *info, asection *sec, /* 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_discard_section_eh_frame 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 *output_bfd ATTRIBUTE_UNUSED, 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 *output_bfd ATTRIBUTE_UNUSED, 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 *abfd, 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 *abfd, 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 *abfd, 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 *abfd, /* 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 *abfd, 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 *abfd, { 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 *abfd, 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 *abfd, 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); } }