diff options
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 34 | ||||
-rw-r--r-- | bfd/elf-eh-frame.c | 56 | ||||
-rw-r--r-- | bfd/elf32-i386.c | 95 | ||||
-rw-r--r-- | bfd/elf64-x86-64.c | 94 |
4 files changed, 260 insertions, 19 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 9536f022ae..327f83b062 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,37 @@ +2011-06-20 Jakub Jelinek <jakub@redhat.com> + + PR ld/12570 + * elf-eh-frame.c (_bfd_elf_parse_eh_frame): Allow no relocations + at all for linker created .eh_frame sections. + (_bfd_elf_discard_section_eh_frame): Handle linker created + .eh_frame sections with no relocations. + * elf64-x86-64.c: Include dwarf2.h. + (elf_x86_64_eh_frame_plt): New variable. + (PLT_CIE_LENGTH, PLT_FDE_LENGTH, PLT_FDE_START_OFFSET, + PLT_FDE_LEN_OFFSET): Define. + (struct elf_x86_64_link_hash_table): Add plt_eh_frame field. + (elf_x86_64_create_dynamic_sections): Create and fill in + .eh_frame section for .plt section. + (elf_x86_64_size_dynamic_sections): Write .plt section size + into .eh_frame FDE covering .plt section. + (elf_x86_64_finish_dynamic_sections): Write .plt section + start into .eh_frame FDE covering .plt section. Call + _bfd_elf_write_section_eh_frame on htab->plt_eh_frame section. + (elf_backend_plt_alignment): Define to 4. + * elf32-i386.c: Include dwarf2.h. + (elf_i386_eh_frame_plt): New variable. + (PLT_CIE_LENGTH, PLT_FDE_LENGTH, PLT_FDE_START_OFFSET, + PLT_FDE_LEN_OFFSET): Define. + (struct elf_i386_link_hash_table): Add plt_eh_frame field. + (elf_i386_create_dynamic_sections): Create and fill in + .eh_frame section for .plt section. + (elf_i386_size_dynamic_sections): Write .plt section size + into .eh_frame FDE covering .plt section. + (elf_i386_finish_dynamic_sections): Write .plt section + start into .eh_frame FDE covering .plt section. Call + _bfd_elf_write_section_eh_frame on htab->plt_eh_frame section. + (elf_backend_plt_alignment): Define to 4. + 2011-06-19 H.J. Lu <hongjiu.lu@intel.com> * elf64-x86-64.c (elf_backend_post_process_headers): Defined diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c index 21041a5b40..54142b2952 100644 --- a/bfd/elf-eh-frame.c +++ b/bfd/elf-eh-frame.c @@ -778,8 +778,6 @@ _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 (cie = local_cies; cie < local_cies + cie_count; cie++) @@ -795,17 +793,22 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, = cie->cie_inf->add_augmentation_size; 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); - /* RSEC will be NULL if FDE was cleared out as it was belonging to - a discarded SHT_GROUP. */ - if (rsec) + if ((sec->flags & SEC_LINKER_CREATED) == 0 || cookie->rels != NULL) { - REQUIRE (rsec->owner == abfd); - this_inf->u.fde.next_for_section = elf_fde_list (rsec); - elf_fde_list (rsec) = this_inf; + asection *rsec; + + REQUIRE (GET_RELOC (buf)); + + /* Chain together the FDEs for each section. */ + rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie); + /* RSEC will be NULL if FDE was cleared out as it was belonging to + a discarded SHT_GROUP. */ + if (rsec) + { + REQUIRE (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. */ @@ -1141,6 +1144,9 @@ _bfd_elf_discard_section_eh_frame if (sec_info == NULL) return FALSE; + ptr_size = (get_elf_backend_data (sec->owner) + ->elf_backend_eh_frame_address_size (sec->owner, sec)); + hdr_info = &elf_hash_table (info)->eh_info; for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) if (ent->size == 4) @@ -1149,11 +1155,25 @@ _bfd_elf_discard_section_eh_frame ent->removed = sec->map_head.s != NULL; else if (!ent->cie) { - cookie->rel = cookie->rels + ent->reloc_index; - /* FIXME: octets_per_byte. */ - BFD_ASSERT (cookie->rel < cookie->relend - && cookie->rel->r_offset == ent->offset + 8); - if (!(*reloc_symbol_deleted_p) (ent->offset + 8, cookie)) + bfd_boolean keep; + if ((sec->flags & SEC_LINKER_CREATED) != 0 && cookie->rels == NULL) + { + unsigned int width + = get_DW_EH_PE_width (ent->fde_encoding, ptr_size); + bfd_vma value + = read_value (abfd, sec->contents + ent->offset + 8 + width, + width, get_DW_EH_PE_signed (ent->fde_encoding)); + keep = value != 0; + } + else + { + cookie->rel = cookie->rels + ent->reloc_index; + /* FIXME: octets_per_byte. */ + BFD_ASSERT (cookie->rel < cookie->relend + && cookie->rel->r_offset == ent->offset + 8); + keep = !(*reloc_symbol_deleted_p) (ent->offset + 8, cookie); + } + if (keep) { if (info->shared && (((ent->fde_encoding & 0x70) == DW_EH_PE_absptr @@ -1182,8 +1202,6 @@ _bfd_elf_discard_section_eh_frame sec_info->cies = NULL; } - ptr_size = (get_elf_backend_data (sec->owner) - ->elf_backend_eh_frame_address_size (sec->owner, sec)); offset = 0; for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) if (!ent->removed) diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 05962a07f7..581272fa7c 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -29,6 +29,7 @@ #include "bfd_stdint.h" #include "objalloc.h" #include "hashtab.h" +#include "dwarf2.h" /* 386 uses REL relocations instead of RELA. */ #define USE_REL 1 @@ -574,6 +575,45 @@ static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] = 0, 0, 0, 0 /* replaced with offset to start of .plt. */ }; +/* .eh_frame covering the .plt section. */ + +static const bfd_byte elf_i386_eh_frame_plt[] = +{ +#define PLT_CIE_LENGTH 20 +#define PLT_FDE_LENGTH 36 +#define PLT_FDE_START_OFFSET 4 + PLT_CIE_LENGTH + 8 +#define PLT_FDE_LEN_OFFSET 4 + PLT_CIE_LENGTH + 12 + PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ + 0, 0, 0, 0, /* CIE ID */ + 1, /* CIE version */ + 'z', 'R', 0, /* Augmentation string */ + 1, /* Code alignment factor */ + 0x7c, /* Data alignment factor */ + 8, /* Return address column */ + 1, /* Augmentation size */ + DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ + DW_CFA_def_cfa, 4, 4, /* DW_CFA_def_cfa: r4 (esp) ofs 4 */ + DW_CFA_offset + 8, 1, /* DW_CFA_offset: r8 (eip) at cfa-4 */ + DW_CFA_nop, DW_CFA_nop, + + PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */ + PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */ + 0, 0, 0, 0, /* R_386_PC32 .plt goes here */ + 0, 0, 0, 0, /* .plt size goes here */ + 0, /* Augmentation size */ + DW_CFA_def_cfa_offset, 8, /* DW_CFA_def_cfa_offset: 8 */ + DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */ + DW_CFA_def_cfa_offset, 12, /* DW_CFA_def_cfa_offset: 12 */ + DW_CFA_advance_loc + 10, /* DW_CFA_advance_loc: 10 to __PLT__+16 */ + DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */ + 11, /* Block length */ + DW_OP_breg4, 4, /* DW_OP_breg4 (esp): 4 */ + DW_OP_breg8, 0, /* DW_OP_breg8 (eip): 0 */ + DW_OP_lit15, DW_OP_and, DW_OP_lit11, DW_OP_ge, + DW_OP_lit3, DW_OP_shl, DW_OP_plus, + DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop +}; + /* On VxWorks, the .rel.plt.unloaded section has absolute relocations for the PLTResolve stub and then for each PLT entry. */ #define PLTRESOLVE_RELOCS_SHLIB 0 @@ -655,6 +695,7 @@ struct elf_i386_link_hash_table /* Short-cuts to get to dynamic linker sections. */ asection *sdynbss; asection *srelbss; + asection *plt_eh_frame; union { @@ -887,6 +928,25 @@ elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) &htab->srelplt2)) return FALSE; + if (!info->no_ld_generated_unwind_info + && bfd_get_section_by_name (dynobj, ".eh_frame") == NULL + && htab->elf.splt != NULL) + { + flagword flags = get_elf_backend_data (dynobj)->dynamic_sec_flags; + htab->plt_eh_frame + = bfd_make_section_with_flags (dynobj, ".eh_frame", + flags | SEC_READONLY); + if (htab->plt_eh_frame == NULL + || !bfd_set_section_alignment (dynobj, htab->plt_eh_frame, 2)) + return FALSE; + + htab->plt_eh_frame->size = sizeof (elf_i386_eh_frame_plt); + htab->plt_eh_frame->contents + = bfd_alloc (dynobj, htab->plt_eh_frame->size); + memcpy (htab->plt_eh_frame->contents, elf_i386_eh_frame_plt, + sizeof (elf_i386_eh_frame_plt)); + } + return TRUE; } @@ -2667,6 +2727,13 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, return FALSE; } + if (htab->plt_eh_frame != NULL + && htab->elf.splt != NULL + && htab->elf.splt->size != 0 + && (htab->elf.splt->flags & SEC_EXCLUDE) == 0) + bfd_put_32 (dynobj, htab->elf.splt->size, + htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET); + if (htab->elf.dynamic_sections_created) { /* Add some entries to the .dynamic section. We fill in the @@ -4667,6 +4734,33 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, elf_section_data (htab->elf.sgotplt->output_section)->this_hdr.sh_entsize = 4; } + /* Adjust .eh_frame for .plt section. */ + if (htab->plt_eh_frame != NULL) + { + if (htab->elf.splt != NULL + && htab->elf.splt->size != 0 + && (htab->elf.splt->flags & SEC_EXCLUDE) == 0 + && htab->elf.splt->output_section != NULL + && htab->plt_eh_frame->output_section != NULL) + { + bfd_vma plt_start = htab->elf.splt->output_section->vma; + bfd_vma eh_frame_start = htab->plt_eh_frame->output_section->vma + + htab->plt_eh_frame->output_offset + + PLT_FDE_START_OFFSET; + bfd_put_signed_32 (dynobj, plt_start - eh_frame_start, + htab->plt_eh_frame->contents + + PLT_FDE_START_OFFSET); + } + if (htab->plt_eh_frame->sec_info_type + == ELF_INFO_TYPE_EH_FRAME) + { + if (! _bfd_elf_write_section_eh_frame (output_bfd, info, + htab->plt_eh_frame, + htab->plt_eh_frame->contents)) + return FALSE; + } + } + if (htab->elf.sgot && htab->elf.sgot->size > 0) elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 4; @@ -4734,6 +4828,7 @@ elf_i386_add_symbol_hook (bfd * abfd, #define elf_backend_plt_readonly 1 #define elf_backend_want_plt_sym 0 #define elf_backend_got_header_size 12 +#define elf_backend_plt_alignment 4 /* Support RELA for objdump of prelink objects. */ #define elf_info_to_howto elf_i386_info_to_howto_rel diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index a929797296..37349f9fd2 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -29,6 +29,7 @@ #include "bfd_stdint.h" #include "objalloc.h" #include "hashtab.h" +#include "dwarf2.h" #include "elf/x86-64.h" @@ -528,6 +529,45 @@ static const bfd_byte elf_x86_64_plt_entry[PLT_ENTRY_SIZE] = 0, 0, 0, 0 /* replaced with offset to start of .plt0. */ }; +/* .eh_frame covering the .plt section. */ + +static const bfd_byte elf_x86_64_eh_frame_plt[] = +{ +#define PLT_CIE_LENGTH 20 +#define PLT_FDE_LENGTH 36 +#define PLT_FDE_START_OFFSET 4 + PLT_CIE_LENGTH + 8 +#define PLT_FDE_LEN_OFFSET 4 + PLT_CIE_LENGTH + 12 + PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ + 0, 0, 0, 0, /* CIE ID */ + 1, /* CIE version */ + 'z', 'R', 0, /* Augmentation string */ + 1, /* Code alignment factor */ + 0x78, /* Data alignment factor */ + 16, /* Return address column */ + 1, /* Augmentation size */ + DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ + DW_CFA_def_cfa, 7, 8, /* DW_CFA_def_cfa: r7 (rsp) ofs 8 */ + DW_CFA_offset + 16, 1, /* DW_CFA_offset: r16 (rip) at cfa-8 */ + DW_CFA_nop, DW_CFA_nop, + + PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */ + PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */ + 0, 0, 0, 0, /* R_X86_64_PC32 .plt goes here */ + 0, 0, 0, 0, /* .plt size goes here */ + 0, /* Augmentation size */ + DW_CFA_def_cfa_offset, 16, /* DW_CFA_def_cfa_offset: 16 */ + DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */ + DW_CFA_def_cfa_offset, 24, /* DW_CFA_def_cfa_offset: 24 */ + DW_CFA_advance_loc + 10, /* DW_CFA_advance_loc: 10 to __PLT__+16 */ + DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */ + 11, /* Block length */ + DW_OP_breg7, 8, /* DW_OP_breg7 (rsp): 8 */ + DW_OP_breg16, 0, /* DW_OP_breg16 (rip): 0 */ + DW_OP_lit15, DW_OP_and, DW_OP_lit11, DW_OP_ge, + DW_OP_lit3, DW_OP_shl, DW_OP_plus, + DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop +}; + /* x86-64 ELF linker hash entry. */ struct elf_x86_64_link_hash_entry @@ -601,6 +641,7 @@ struct elf_x86_64_link_hash_table /* Short-cuts to get to dynamic linker sections. */ asection *sdynbss; asection *srelbss; + asection *plt_eh_frame; union { @@ -847,6 +888,24 @@ elf_x86_64_create_dynamic_sections (bfd *dynobj, || (!info->shared && !htab->srelbss)) abort (); + if (!info->no_ld_generated_unwind_info + && bfd_get_section_by_name (dynobj, ".eh_frame") == NULL + && htab->elf.splt != NULL) + { + flagword flags = get_elf_backend_data (dynobj)->dynamic_sec_flags; + htab->plt_eh_frame + = bfd_make_section_with_flags (dynobj, ".eh_frame", + flags | SEC_READONLY); + if (htab->plt_eh_frame == NULL + || !bfd_set_section_alignment (dynobj, htab->plt_eh_frame, 3)) + return FALSE; + + htab->plt_eh_frame->size = sizeof (elf_x86_64_eh_frame_plt); + htab->plt_eh_frame->contents + = bfd_alloc (dynobj, htab->plt_eh_frame->size); + memcpy (htab->plt_eh_frame->contents, elf_x86_64_eh_frame_plt, + sizeof (elf_x86_64_eh_frame_plt)); + } return TRUE; } @@ -2721,6 +2780,13 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, return FALSE; } + if (htab->plt_eh_frame != NULL + && htab->elf.splt != NULL + && htab->elf.splt->size != 0 + && (htab->elf.splt->flags & SEC_EXCLUDE) == 0) + bfd_put_32 (dynobj, htab->elf.splt->size, + htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET); + if (htab->elf.dynamic_sections_created) { /* Add some entries to the .dynamic section. We fill in the @@ -4521,6 +4587,33 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, GOT_ENTRY_SIZE; } + /* Adjust .eh_frame for .plt section. */ + if (htab->plt_eh_frame != NULL) + { + if (htab->elf.splt != NULL + && htab->elf.splt->size != 0 + && (htab->elf.splt->flags & SEC_EXCLUDE) == 0 + && htab->elf.splt->output_section != NULL + && htab->plt_eh_frame->output_section != NULL) + { + bfd_vma plt_start = htab->elf.splt->output_section->vma; + bfd_vma eh_frame_start = htab->plt_eh_frame->output_section->vma + + htab->plt_eh_frame->output_offset + + PLT_FDE_START_OFFSET; + bfd_put_signed_32 (dynobj, plt_start - eh_frame_start, + htab->plt_eh_frame->contents + + PLT_FDE_START_OFFSET); + } + if (htab->plt_eh_frame->sec_info_type + == ELF_INFO_TYPE_EH_FRAME) + { + if (! _bfd_elf_write_section_eh_frame (output_bfd, info, + htab->plt_eh_frame, + htab->plt_eh_frame->contents)) + return FALSE; + } + } + if (htab->elf.sgot && htab->elf.sgot->size > 0) elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = GOT_ENTRY_SIZE; @@ -4787,6 +4880,7 @@ static const struct bfd_elf_special_section #define elf_backend_want_plt_sym 0 #define elf_backend_got_header_size (GOT_ENTRY_SIZE*3) #define elf_backend_rela_normal 1 +#define elf_backend_plt_alignment 4 #define elf_info_to_howto elf_x86_64_info_to_howto |