X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf64-x86-64.c;h=0502e581b88baa09016677be7785bf5140829f4c;hb=3b22753a67cf616514de804ef6d5ed5e90a7d883;hp=a24616b7880fb82632c4aaeddbbf6560236af145;hpb=eea6121ac0cb22524c627017191ca09825e3d702;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index a24616b788..0502e581b8 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -1,5 +1,6 @@ /* X86-64 specific support for 64-bit ELF - Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. Contributed by Jan Hubicka . This file is part of BFD, the Binary File Descriptor library. @@ -16,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "bfd.h" #include "sysdep.h" @@ -72,9 +73,9 @@ static reloc_howto_type x86_64_elf_howto_table[] = FALSE), HOWTO(R_X86_64_16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_X86_64_16", FALSE, 0xffff, 0xffff, FALSE), - HOWTO(R_X86_64_PC16,0, 1, 16, TRUE, 0, complain_overflow_bitfield, + HOWTO(R_X86_64_PC16,0, 1, 16, TRUE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_PC16", FALSE, 0xffff, 0xffff, TRUE), - HOWTO(R_X86_64_8, 0, 0, 8, FALSE, 0, complain_overflow_signed, + HOWTO(R_X86_64_8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_X86_64_8", FALSE, 0xff, 0xff, FALSE), HOWTO(R_X86_64_PC8, 0, 0, 8, TRUE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_PC8", FALSE, 0xff, 0xff, TRUE), @@ -93,7 +94,7 @@ static reloc_howto_type x86_64_elf_howto_table[] = HOWTO(R_X86_64_TLSLD, 0, 2, 32, TRUE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_TLSLD", FALSE, 0xffffffff, 0xffffffff, TRUE), - HOWTO(R_X86_64_DTPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + HOWTO(R_X86_64_DTPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_DTPOFF32", FALSE, 0xffffffff, 0xffffffff, FALSE), HOWTO(R_X86_64_GOTTPOFF, 0, 2, 32, TRUE, 0, complain_overflow_signed, @@ -102,6 +103,15 @@ static reloc_howto_type x86_64_elf_howto_table[] = HOWTO(R_X86_64_TPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_TPOFF32", FALSE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_X86_64_PC64, 0, 4, 64, TRUE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_X86_64_PC64", FALSE, MINUS_ONE, MINUS_ONE, + TRUE), + HOWTO(R_X86_64_GOTOFF64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_X86_64_GOTOFF64", + FALSE, MINUS_ONE, MINUS_ONE, FALSE), + HOWTO(R_X86_64_GOTPC32, 0, 2, 32, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_GOTPC32", + FALSE, 0xffffffff, 0xffffffff, TRUE), /* GNU extension to record C++ vtable hierarchy. */ HOWTO (R_X86_64_GNU_VTINHERIT, 0, 4, 0, FALSE, 0, complain_overflow_dont, @@ -146,6 +156,9 @@ static const struct elf_reloc_map x86_64_reloc_map[] = { BFD_RELOC_X86_64_DTPOFF32, R_X86_64_DTPOFF32, }, { BFD_RELOC_X86_64_GOTTPOFF, R_X86_64_GOTTPOFF, }, { BFD_RELOC_X86_64_TPOFF32, R_X86_64_TPOFF32, }, + { BFD_RELOC_64_PCREL, R_X86_64_PC64, }, + { BFD_RELOC_X86_64_GOTOFF64, R_X86_64_GOTOFF64, }, + { BFD_RELOC_X86_64_GOTPC32, R_X86_64_GOTPC32, }, { BFD_RELOC_VTABLE_INHERIT, R_X86_64_GNU_VTINHERIT, }, { BFD_RELOC_VTABLE_ENTRY, R_X86_64_GNU_VTENTRY, }, }; @@ -176,16 +189,19 @@ elf64_x86_64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, unsigned r_type, i; r_type = ELF64_R_TYPE (dst->r_info); - if (r_type < (unsigned int) R_X86_64_GNU_VTINHERIT) + if (r_type < (unsigned int) R_X86_64_GNU_VTINHERIT + || r_type >= (unsigned int) R_X86_64_max) { - BFD_ASSERT (r_type <= (unsigned int) R_X86_64_TPOFF32); + if (r_type > (unsigned int) R_X86_64_GOTPC32) + { + (*_bfd_error_handler) (_("%B: invalid relocation type %d"), + abfd, (int) r_type); + r_type = R_X86_64_NONE; + } i = r_type; } else - { - BFD_ASSERT (r_type < (unsigned int) R_X86_64_max); - i = r_type - ((unsigned int) R_X86_64_GNU_VTINHERIT - R_X86_64_TPOFF32 - 1); - } + i = r_type - ((unsigned int) R_X86_64_GNU_VTINHERIT - R_X86_64_GOTPC32 - 1); cache_ptr->howto = &x86_64_elf_howto_table[i]; BFD_ASSERT (r_type == cache_ptr->howto->type); } @@ -458,12 +474,13 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info) if (!htab->sgot || !htab->sgotplt) abort (); - htab->srelgot = bfd_make_section (dynobj, ".rela.got"); + htab->srelgot = bfd_make_section_with_flags (dynobj, ".rela.got", + (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY)); if (htab->srelgot == NULL - || ! bfd_set_section_flags (dynobj, htab->srelgot, - (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED - | SEC_READONLY)) || ! bfd_set_section_alignment (dynobj, htab->srelgot, 3)) return FALSE; return TRUE; @@ -553,16 +570,17 @@ elf64_x86_64_copy_indirect_symbol (const struct elf_backend_data *bed, if (ELIMINATE_COPY_RELOCS && ind->root.type != bfd_link_hash_indirect - && (dir->elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) != 0) - /* If called to transfer flags for a weakdef during processing - of elf_adjust_dynamic_symbol, don't copy ELF_LINK_NON_GOT_REF. - We clear it ourselves for ELIMINATE_COPY_RELOCS. */ - dir->elf_link_hash_flags |= - (ind->elf_link_hash_flags & (ELF_LINK_HASH_REF_DYNAMIC - | ELF_LINK_HASH_REF_REGULAR - | ELF_LINK_HASH_REF_REGULAR_NONWEAK - | ELF_LINK_HASH_NEEDS_PLT - | ELF_LINK_POINTER_EQUALITY_NEEDED)); + && dir->dynamic_adjusted) + { + /* If called to transfer flags for a weakdef during processing + of elf_adjust_dynamic_symbol, don't copy non_got_ref. + We clear it ourselves for ELIMINATE_COPY_RELOCS. */ + dir->ref_dynamic |= ind->ref_dynamic; + dir->ref_regular |= ind->ref_regular; + dir->ref_regular_nonweak |= ind->ref_regular_nonweak; + dir->needs_plt |= ind->needs_plt; + dir->pointer_equality_needed |= ind->pointer_equality_needed; + } else _bfd_elf_link_hash_copy_indirect (bed, dir, ind); } @@ -641,16 +659,20 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) { - (*_bfd_error_handler) (_("%s: bad symbol index: %d"), - bfd_archive_filename (abfd), - r_symndx); + (*_bfd_error_handler) (_("%B: bad symbol index: %d"), + abfd, r_symndx); return FALSE; } if (r_symndx < symtab_hdr->sh_info) h = NULL; else - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + } r_type = elf64_x86_64_tls_transition (info, r_type, h == NULL); switch (r_type) @@ -663,9 +685,10 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, if (info->shared) { (*_bfd_error_handler) - (_("%s: relocation %s can not be used when making a shared object; recompile with -fPIC"), - bfd_archive_filename (abfd), - x86_64_elf_howto_table[r_type].name); + (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), + abfd, + x86_64_elf_howto_table[r_type].name, + (h) ? h->root.root.string : "a local symbol"); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -730,9 +753,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, else { (*_bfd_error_handler) - (_("%s: %s' accessed both as normal and thread local symbol"), - bfd_archive_filename (abfd), - h ? h->root.root.string : ""); + (_("%B: %s' accessed both as normal and thread local symbol"), + abfd, h ? h->root.root.string : ""); return FALSE; } } @@ -747,7 +769,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, } /* Fall through */ - //case R_X86_64_GOTPCREL: + case R_X86_64_GOTOFF64: + case R_X86_64_GOTPC32: create_got: if (htab->sgot == NULL) { @@ -771,7 +794,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, if (h == NULL) continue; - h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + h->needs_plt = 1; h->plt.refcount += 1; break; @@ -788,9 +811,10 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, && (sec->flags & SEC_READONLY) != 0) { (*_bfd_error_handler) - (_("%s: relocation %s can not be used when making a shared object; recompile with -fPIC"), - bfd_archive_filename (abfd), - x86_64_elf_howto_table[r_type].name); + (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), + abfd, + x86_64_elf_howto_table[r_type].name, + (h) ? h->root.root.string : "a local symbol"); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -799,6 +823,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, case R_X86_64_PC8: case R_X86_64_PC16: case R_X86_64_PC32: + case R_X86_64_PC64: case R_X86_64_64: if (h != NULL && !info->shared) { @@ -808,13 +833,13 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, sections have not yet been mapped to output sections. Tentatively set the flag for now, and correct in adjust_dynamic_symbol. */ - h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF; + h->non_got_ref = 1; /* We may need a .plt entry if the function this reloc refers to is in a shared lib. */ h->plt.refcount += 1; - if (r_type != R_X86_64_PC32) - h->elf_link_hash_flags |= ELF_LINK_POINTER_EQUALITY_NEEDED; + if (r_type != R_X86_64_PC32 && r_type != R_X86_64_PC64) + h->pointer_equality_needed = 1; } /* If we are creating a shared library, and this is a reloc @@ -842,19 +867,18 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, && (sec->flags & SEC_ALLOC) != 0 && (((r_type != R_X86_64_PC8) && (r_type != R_X86_64_PC16) - && (r_type != R_X86_64_PC32)) + && (r_type != R_X86_64_PC32) + && (r_type != R_X86_64_PC64)) || (h != NULL && (! info->symbolic || h->root.type == bfd_link_hash_defweak - || (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0)))) + || !h->def_regular)))) || (ELIMINATE_COPY_RELOCS && !info->shared && (sec->flags & SEC_ALLOC) != 0 && h != NULL && (h->root.type == bfd_link_hash_defweak - || (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0))) + || !h->def_regular))) { struct elf64_x86_64_dyn_relocs *p; struct elf64_x86_64_dyn_relocs **head; @@ -879,8 +903,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, name + 5) != 0) { (*_bfd_error_handler) - (_("%s: bad relocation section name `%s\'"), - bfd_archive_filename (abfd), name); + (_("%B: bad relocation section name `%s\'"), + abfd, name); } if (htab->elf.dynobj == NULL) @@ -893,13 +917,14 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, { flagword flags; - sreloc = bfd_make_section (dynobj, name); flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_IN_MEMORY | SEC_LINKER_CREATED); if ((sec->flags & SEC_ALLOC) != 0) flags |= SEC_ALLOC | SEC_LOAD; + sreloc = bfd_make_section_with_flags (dynobj, + name, + flags); if (sreloc == NULL - || ! bfd_set_section_flags (dynobj, sreloc, flags) || ! bfd_set_section_alignment (dynobj, sreloc, 3)) return FALSE; } @@ -946,7 +971,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, p->count += 1; if (r_type == R_X86_64_PC8 || r_type == R_X86_64_PC16 - || r_type == R_X86_64_PC32) + || r_type == R_X86_64_PC32 + || r_type == R_X86_64_PC64) p->pc_count += 1; } break; @@ -1044,6 +1070,9 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, struct elf64_x86_64_dyn_relocs *p; h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; eh = (struct elf64_x86_64_link_hash_entry *) h; for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) @@ -1088,6 +1117,7 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, case R_X86_64_PC8: case R_X86_64_PC16: case R_X86_64_PC32: + case R_X86_64_PC64: if (info->shared) break; /* Fall thru */ @@ -1126,7 +1156,7 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, will fill in the contents of the procedure linkage table later, when we know the address of the .got section. */ if (h->type == STT_FUNC - || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) + || h->needs_plt) { if (h->plt.refcount <= 0 || SYMBOL_CALLS_LOCAL (info, h) @@ -1139,7 +1169,7 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, such a case, we don't actually need to build a procedure linkage table, and we can just do a PC32 reloc instead. */ h->plt.offset = (bfd_vma) -1; - h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + h->needs_plt = 0; } return TRUE; @@ -1155,16 +1185,14 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, /* If this is a weak symbol, and there is a real definition, the processor independent code will have arranged for us to see the real definition first, and we can just use the same value. */ - if (h->weakdef != NULL) + if (h->u.weakdef != NULL) { - BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined - || h->weakdef->root.type == bfd_link_hash_defweak); - h->root.u.def.section = h->weakdef->root.u.def.section; - h->root.u.def.value = h->weakdef->root.u.def.value; + BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined + || h->u.weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->u.weakdef->root.u.def.section; + h->root.u.def.value = h->u.weakdef->root.u.def.value; if (ELIMINATE_COPY_RELOCS || info->nocopyreloc) - h->elf_link_hash_flags - = ((h->elf_link_hash_flags & ~ELF_LINK_NON_GOT_REF) - | (h->weakdef->elf_link_hash_flags & ELF_LINK_NON_GOT_REF)); + h->non_got_ref = h->u.weakdef->non_got_ref; return TRUE; } @@ -1180,13 +1208,13 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, /* If there are no references to this symbol that do not use the GOT, we don't need to generate a copy reloc. */ - if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0) + if (!h->non_got_ref) return TRUE; /* If -z nocopyreloc was given, we won't generate them either. */ if (info->nocopyreloc) { - h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF; + h->non_got_ref = 0; return TRUE; } @@ -1207,7 +1235,7 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, we'll be keeping the dynamic relocs and avoiding the copy reloc. */ if (p == NULL) { - h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF; + h->non_got_ref = 0; return TRUE; } } @@ -1230,7 +1258,7 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) { htab->srelbss->size += sizeof (Elf64_External_Rela); - h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY; + h->needs_copy = 1; } /* We need to figure out the alignment required for this symbol. I @@ -1287,7 +1315,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ if (h->dynindx == -1 - && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + && !h->forced_local) { if (! bfd_elf_link_record_dynamic_symbol (info, h)) return FALSE; @@ -1311,7 +1339,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) pointers compare as equal between the normal executable and the shared library. */ if (! info->shared - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + && !h->def_regular) { h->root.u.def.section = s; h->root.u.def.value = h->plt.offset; @@ -1330,13 +1358,13 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) else { h->plt.offset = (bfd_vma) -1; - h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + h->needs_plt = 0; } } else { h->plt.offset = (bfd_vma) -1; - h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + h->needs_plt = 0; } /* If R_X86_64_GOTTPOFF symbol is now local to the binary, @@ -1355,7 +1383,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ if (h->dynindx == -1 - && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + && !h->forced_local) { if (! bfd_elf_link_record_dynamic_symbol (info, h)) return FALSE; @@ -1430,9 +1458,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) symbols which turn out to need copy relocs or are not dynamic. */ - if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0 - && (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + if (!h->non_got_ref + && ((h->def_dynamic + && !h->def_regular) || (htab->elf.dynamic_sections_created && (h->root.type == bfd_link_hash_undefweak || h->root.type == bfd_link_hash_undefined)))) @@ -1440,7 +1468,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ if (h->dynindx == -1 - && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + && !h->forced_local) { if (! bfd_elf_link_record_dynamic_symbol (info, h)) return FALSE; @@ -1621,7 +1649,8 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (s == htab->splt || s == htab->sgot - || s == htab->sgotplt) + || s == htab->sgotplt + || s == htab->sdynbss) { /* Strip this section if we don't need it; see the comment below. */ @@ -1653,10 +1682,13 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, function which decides whether anything needs to go into these sections. */ - _bfd_strip_section_from_output (info, s); + s->flags |= SEC_EXCLUDE; continue; } + if ((s->flags & SEC_HAS_CONTENTS) == 0) + continue; + /* Allocate memory for the section contents. We use bfd_zalloc here in case unused entries are not reclaimed before the section's contents are written out. This should not happen, @@ -1744,6 +1776,24 @@ tpoff (struct bfd_link_info *info, bfd_vma address) return address - htab->tls_size - htab->tls_sec->vma; } +/* Is the instruction before OFFSET in CONTENTS a 32bit relative + branch? */ + +static bfd_boolean +is_32bit_relative_branch (bfd_byte *contents, bfd_vma offset) +{ + /* Opcode Instruction + 0xe8 call + 0xe9 jump + 0x0f 0x8x conditional jump */ + return ((offset > 0 + && (contents [offset - 1] == 0xe8 + || contents [offset - 1] == 0xe9)) + || (offset > 1 + && contents [offset - 2] == 0x0f + && (contents [offset - 1] & 0xf0) == 0x80)); +} + /* Relocate an x86_64 ELF section. */ static bfd_boolean @@ -1919,6 +1969,42 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, break; + case R_X86_64_GOTOFF64: + /* Relocation is relative to the start of the global offset + table. */ + + /* Check to make sure it isn't a protected function symbol + for shared library since it may not be local when used + as function address. */ + if (info->shared + && h + && h->def_regular + && h->type == STT_FUNC + && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) + { + (*_bfd_error_handler) + (_("%B: relocation R_X86_64_GOTOFF64 against protected function `%s' can not be used when making a shared object"), + input_bfd, h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + /* Note that sgot is not involved in this + calculation. We always want the start of .got.plt. If we + defined _GLOBAL_OFFSET_TABLE_ in a different way, as is + permitted by the ABI, we might have to change this + calculation. */ + relocation -= htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset; + break; + + case R_X86_64_GOTPC32: + /* Use global offset table as symbol value. */ + relocation = htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset; + unresolved_reloc = FALSE; + break; + case R_X86_64_PLT32: /* Relocation is to the entry for this symbol in the procedure linkage table. */ @@ -1946,9 +2032,38 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, case R_X86_64_PC8: case R_X86_64_PC16: case R_X86_64_PC32: + if (info->shared + && !SYMBOL_REFERENCES_LOCAL (info, h) + && (input_section->flags & SEC_ALLOC) != 0 + && (input_section->flags & SEC_READONLY) != 0 + && (!h->def_regular + || r_type != R_X86_64_PC32 + || h->type != STT_FUNC + || ELF_ST_VISIBILITY (h->other) != STV_PROTECTED + || !is_32bit_relative_branch (contents, + rel->r_offset))) + { + if (h->def_regular + && r_type == R_X86_64_PC32 + && h->type == STT_FUNC + && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) + (*_bfd_error_handler) + (_("%B: relocation R_X86_64_PC32 against protected function `%s' can not be used when making a shared object"), + input_bfd, h->root.root.string); + else + (*_bfd_error_handler) + (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), + input_bfd, x86_64_elf_howto_table[r_type].name, + h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + /* Fall through. */ + case R_X86_64_8: case R_X86_64_16: case R_X86_64_32: + case R_X86_64_PC64: case R_X86_64_64: /* FIXME: The ABI says the linker should make sure the value is the same when it's zeroextended to 64 bit. */ @@ -1966,17 +2081,16 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, || h->root.type != bfd_link_hash_undefweak) && ((r_type != R_X86_64_PC8 && r_type != R_X86_64_PC16 - && r_type != R_X86_64_PC32) + && r_type != R_X86_64_PC32 + && r_type != R_X86_64_PC64) || !SYMBOL_CALLS_LOCAL (info, h))) || (ELIMINATE_COPY_RELOCS && !info->shared && h != NULL && h->dynindx != -1 - && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0 - && (((h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_DYNAMIC) != 0 - && (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0) + && !h->non_got_ref + && ((h->def_dynamic + && !h->def_regular) || h->root.type == bfd_link_hash_undefweak || h->root.type == bfd_link_hash_undefined))) { @@ -2012,10 +2126,10 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, && (r_type == R_X86_64_PC8 || r_type == R_X86_64_PC16 || r_type == R_X86_64_PC32 + || r_type == R_X86_64_PC64 || !info->shared || !info->symbolic - || (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0)) + || !h->def_regular)) { outrel.r_info = ELF64_R_INFO (h->dynindx, r_type); outrel.r_addend = rel->r_addend; @@ -2389,11 +2503,11 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, not process them. */ if (unresolved_reloc && !((input_section->flags & SEC_DEBUGGING) != 0 - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)) + && h->def_dynamic)) (*_bfd_error_handler) - (_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"), - bfd_archive_filename (input_bfd), - bfd_get_section_name (input_bfd, input_section), + (_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"), + input_bfd, + input_section, (long) rel->r_offset, h->root.root.string); @@ -2427,16 +2541,16 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, continue; if (! ((*info->callbacks->reloc_overflow) - (info, name, howto->name, (bfd_vma) 0, - input_bfd, input_section, rel->r_offset))) + (info, (h ? &h->root : NULL), name, howto->name, + (bfd_vma) 0, input_bfd, input_section, + rel->r_offset))) return FALSE; } else { (*_bfd_error_handler) - (_("%s(%s+0x%lx): reloc against `%s': error %d"), - bfd_archive_filename (input_bfd), - bfd_get_section_name (input_bfd, input_section), + (_("%B(%A+0x%lx): reloc against `%s': error %d"), + input_bfd, input_section, (long) rel->r_offset, name, (int) r); return FALSE; } @@ -2526,7 +2640,7 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd, loc = htab->srelplt->contents + plt_index * sizeof (Elf64_External_Rela); bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); - if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + if (!h->def_regular) { /* Mark the symbol as undefined, rather than as defined in the .plt section. Leave the value if there were any @@ -2537,7 +2651,7 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd, called from a binary, there is no need to slow down shared libraries because of that. */ sym->st_shndx = SHN_UNDEF; - if ((h->elf_link_hash_flags & ELF_LINK_POINTER_EQUALITY_NEEDED) == 0) + if (!h->pointer_equality_needed) sym->st_value = 0; } } @@ -2586,7 +2700,7 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd, bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); } - if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0) + if (h->needs_copy) { Elf_Internal_Rela rela; bfd_byte *loc; @@ -2774,6 +2888,199 @@ elf64_x86_64_plt_sym_val (bfd_vma i, const asection *plt, return plt->vma + (i + 1) * PLT_ENTRY_SIZE; } +/* Handle an x86-64 specific section when reading an object file. This + is called when elfcode.h finds a section with an unknown type. */ + +static bfd_boolean +elf64_x86_64_section_from_shdr (bfd *abfd, + Elf_Internal_Shdr *hdr, + const char *name, + int shindex) +{ + if (hdr->sh_type != SHT_X86_64_UNWIND) + return FALSE; + + if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) + return FALSE; + + return TRUE; +} + +/* Hook called by the linker routine which adds symbols from an object + file. We use it to put SHN_X86_64_LCOMMON items in .lbss, instead + of .bss. */ + +static bfd_boolean +elf64_x86_64_add_symbol_hook (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + Elf_Internal_Sym *sym, + const char **namep ATTRIBUTE_UNUSED, + flagword *flagsp ATTRIBUTE_UNUSED, + asection **secp, bfd_vma *valp) +{ + asection *lcomm; + + switch (sym->st_shndx) + { + case SHN_X86_64_LCOMMON: + lcomm = bfd_get_section_by_name (abfd, "LARGE_COMMON"); + if (lcomm == NULL) + { + lcomm = bfd_make_section_with_flags (abfd, + "LARGE_COMMON", + (SEC_ALLOC + | SEC_IS_COMMON + | SEC_LINKER_CREATED)); + if (lcomm == NULL) + return FALSE; + elf_section_flags (lcomm) |= SHF_X86_64_LARGE; + } + *secp = lcomm; + *valp = sym->st_size; + break; + } + return TRUE; +} + + +/* Given a BFD section, try to locate the corresponding ELF section + index. */ + +static bfd_boolean +elf64_x86_64_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec, int *index) +{ + if (sec == &_bfd_elf_large_com_section) + { + *index = SHN_X86_64_LCOMMON; + return TRUE; + } + return FALSE; +} + +/* Process a symbol. */ + +static void +elf64_x86_64_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, + asymbol *asym) +{ + elf_symbol_type *elfsym = (elf_symbol_type *) asym; + + switch (elfsym->internal_elf_sym.st_shndx) + { + case SHN_X86_64_LCOMMON: + asym->section = &_bfd_elf_large_com_section; + asym->value = elfsym->internal_elf_sym.st_size; + /* Common symbol doesn't set BSF_GLOBAL. */ + asym->flags &= ~BSF_GLOBAL; + break; + } +} + +static bfd_boolean +elf64_x86_64_common_definition (Elf_Internal_Sym *sym) +{ + return (sym->st_shndx == SHN_COMMON + || sym->st_shndx == SHN_X86_64_LCOMMON); +} + +static unsigned int +elf64_x86_64_common_section_index (asection *sec) +{ + if ((elf_section_flags (sec) & SHF_X86_64_LARGE) == 0) + return SHN_COMMON; + else + return SHN_X86_64_LCOMMON; +} + +static asection * +elf64_x86_64_common_section (asection *sec) +{ + if ((elf_section_flags (sec) & SHF_X86_64_LARGE) == 0) + return bfd_com_section_ptr; + else + return &_bfd_elf_large_com_section; +} + +static bfd_boolean +elf64_x86_64_merge_symbol (struct bfd_link_info *info ATTRIBUTE_UNUSED, + struct elf_link_hash_entry **sym_hash ATTRIBUTE_UNUSED, + struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym, + asection **psec ATTRIBUTE_UNUSED, + bfd_vma *pvalue ATTRIBUTE_UNUSED, + unsigned int *pold_alignment ATTRIBUTE_UNUSED, + bfd_boolean *skip ATTRIBUTE_UNUSED, + bfd_boolean *override ATTRIBUTE_UNUSED, + bfd_boolean *type_change_ok ATTRIBUTE_UNUSED, + bfd_boolean *size_change_ok ATTRIBUTE_UNUSED, + bfd_boolean *newdef ATTRIBUTE_UNUSED, + bfd_boolean *newdyn, + bfd_boolean *newdyncommon ATTRIBUTE_UNUSED, + bfd_boolean *newweak ATTRIBUTE_UNUSED, + bfd *abfd ATTRIBUTE_UNUSED, + asection **sec, + bfd_boolean *olddef ATTRIBUTE_UNUSED, + bfd_boolean *olddyn, + bfd_boolean *olddyncommon ATTRIBUTE_UNUSED, + bfd_boolean *oldweak ATTRIBUTE_UNUSED, + bfd *oldbfd ATTRIBUTE_UNUSED, + asection **oldsec) +{ + /* A normal common symbol and a large common symbol result in a + normal common symbol. If we see the normal symbol first, we + do nothing since the first one will be used. If we see the + large common symbol first, we need to change the large common + symbol to the normal common symbol. */ + if (!*olddyn + && h->root.type == bfd_link_hash_common + && !*newdyn + && bfd_is_com_section (*sec) + && *oldsec != *sec + && sym->st_shndx == SHN_COMMON + && (elf_section_flags (*oldsec) & SHF_X86_64_LARGE) != 0) + { + h->root.u.c.p->section = bfd_make_section_old_way (abfd, + "COMMON"); + h->root.u.c.p->section->flags = SEC_ALLOC; + } + + return TRUE; +} + +static int +elf64_x86_64_additional_program_headers (bfd *abfd) +{ + asection *s; + int count = 0; + + /* Check to see if we need a large readonly segment. */ + s = bfd_get_section_by_name (abfd, ".lrodata"); + if (s && (s->flags & SEC_LOAD)) + count++; + + /* Check to see if we need a large data segment. Since .lbss sections + is placed right after the .bss section, there should be no need for + a large data segment just because of .lbss. */ + s = bfd_get_section_by_name (abfd, ".ldata"); + if (s && (s->flags & SEC_LOAD)) + count++; + + return count; +} + +static const struct bfd_elf_special_section + elf64_x86_64_special_sections[]= +{ + { ".gnu.linkonce.lb", 16, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE}, + { ".gnu.linkonce.lr", 16, -2, SHT_PROGBITS, SHF_ALLOC + SHF_X86_64_LARGE}, + { ".gnu.linkonce.lt", 16, -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR + SHF_X86_64_LARGE}, + { ".lbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE}, + { ".ldata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE}, + { ".lrodata", 8, -2, SHT_PROGBITS, SHF_ALLOC + SHF_X86_64_LARGE}, + { NULL, 0, 0, 0, 0 } +}; + #define TARGET_LITTLE_SYM bfd_elf64_x86_64_vec #define TARGET_LITTLE_NAME "elf64-x86-64" #define ELF_ARCH bfd_arch_i386 @@ -2811,4 +3118,26 @@ elf64_x86_64_plt_sym_val (bfd_vma i, const asection *plt, #define elf_backend_object_p elf64_x86_64_elf_object_p #define bfd_elf64_mkobject elf64_x86_64_mkobject +#define elf_backend_section_from_shdr \ + elf64_x86_64_section_from_shdr + +#define elf_backend_section_from_bfd_section \ + elf64_x86_64_elf_section_from_bfd_section +#define elf_backend_add_symbol_hook \ + elf64_x86_64_add_symbol_hook +#define elf_backend_symbol_processing \ + elf64_x86_64_symbol_processing +#define elf_backend_common_section_index \ + elf64_x86_64_common_section_index +#define elf_backend_common_section \ + elf64_x86_64_common_section +#define elf_backend_common_definition \ + elf64_x86_64_common_definition +#define elf_backend_merge_symbol \ + elf64_x86_64_merge_symbol +#define elf_backend_special_sections \ + elf64_x86_64_special_sections +#define elf_backend_additional_program_headers \ + elf64_x86_64_additional_program_headers + #include "elf64-target.h"