X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bfd%2Felf64-x86-64.c;h=3881f60fd3da2f46c4d6e517841c51769888ddca;hb=e609377629a12f6518eaf100c1983e23c80fecc1;hp=8eac635dfdfad7c77a3cd28bb53366947c6c0e98;hpb=c33205431ae179ed500f2840759a7624af1a23d4;p=platform%2Fupstream%2Fbinutils.git diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 8eac635..3881f60 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -1,7 +1,5 @@ /* X86-64 specific support for ELF - Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, - 2010, 2011, 2012, 2013 - Free Software Foundation, Inc. + Copyright (C) 2000-2014 Free Software Foundation, Inc. Contributed by Jan Hubicka . This file is part of BFD, the Binary File Descriptor library. @@ -562,6 +560,56 @@ static const bfd_byte elf_x86_64_plt_entry[PLT_ENTRY_SIZE] = 0, 0, 0, 0 /* replaced with offset to start of .plt0. */ }; +/* The first entry in a procedure linkage table with BND relocations + like this. */ + +static const bfd_byte elf_x86_64_bnd_plt0_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0x35, 8, 0, 0, 0, /* pushq GOT+8(%rip) */ + 0xf2, 0xff, 0x25, 16, 0, 0, 0, /* bnd jmpq *GOT+16(%rip) */ + 0x0f, 0x1f, 0 /* nopl (%rax) */ +}; + +/* Subsequent entries for legacy branches in a procedure linkage table + with BND relocations look like this. */ + +static const bfd_byte elf_x86_64_legacy_plt_entry[PLT_ENTRY_SIZE] = +{ + 0x68, 0, 0, 0, 0, /* pushq immediate */ + 0xe9, 0, 0, 0, 0, /* jmpq relative */ + 0x66, 0x0f, 0x1f, 0x44, 0, 0 /* nopw (%rax,%rax,1) */ +}; + +/* Subsequent entries for branches with BND prefx in a procedure linkage + table with BND relocations look like this. */ + +static const bfd_byte elf_x86_64_bnd_plt_entry[PLT_ENTRY_SIZE] = +{ + 0x68, 0, 0, 0, 0, /* pushq immediate */ + 0xf2, 0xe9, 0, 0, 0, 0, /* bnd jmpq relative */ + 0x0f, 0x1f, 0x44, 0, 0 /* nopl 0(%rax,%rax,1) */ +}; + +/* Entries for legacy branches in the second procedure linkage table + look like this. */ + +static const bfd_byte elf_x86_64_legacy_plt2_entry[8] = +{ + 0xff, 0x25, /* jmpq *name@GOTPC(%rip) */ + 0, 0, 0, 0, /* replaced with offset to this symbol in .got. */ + 0x66, 0x90 /* xchg %ax,%ax */ +}; + +/* Entries for branches with BND prefix in the second procedure linkage + table look like this. */ + +static const bfd_byte elf_x86_64_bnd_plt2_entry[8] = +{ + 0xf2, 0xff, 0x25, /* bnd jmpq *name@GOTPC(%rip) */ + 0, 0, 0, 0, /* replaced with offset to this symbol in .got. */ + 0x90 /* nop */ +}; + /* .eh_frame covering the .plt section. */ static const bfd_byte elf_x86_64_eh_frame_plt[] = @@ -665,6 +713,24 @@ static const struct elf_x86_64_backend_data elf_x86_64_arch_bed = sizeof (elf_x86_64_eh_frame_plt), /* eh_frame_plt_size */ }; +static const struct elf_x86_64_backend_data elf_x86_64_bnd_arch_bed = + { + elf_x86_64_bnd_plt0_entry, /* plt0_entry */ + elf_x86_64_bnd_plt_entry, /* plt_entry */ + sizeof (elf_x86_64_bnd_plt_entry), /* plt_entry_size */ + 2, /* plt0_got1_offset */ + 1+8, /* plt0_got2_offset */ + 1+12, /* plt0_got2_insn_end */ + 1+2, /* plt_got_offset */ + 1, /* plt_reloc_offset */ + 7, /* plt_plt_offset */ + 1+6, /* plt_got_insn_size */ + 11, /* plt_plt_insn_end */ + 0, /* plt_lazy_offset */ + elf_x86_64_eh_frame_plt, /* eh_frame_plt */ + sizeof (elf_x86_64_eh_frame_plt), /* eh_frame_plt_size */ + }; + #define elf_backend_arch_data &elf_x86_64_arch_bed /* x86-64 ELF linker hash entry. */ @@ -691,6 +757,13 @@ struct elf_x86_64_link_hash_entry (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type)) unsigned char tls_type; + /* TRUE if symbol has at least one BND relocation. */ + bfd_boolean has_bnd_reloc; + + /* Information about the second PLT entry. Filled when has_bnd_reloc is + set. */ + union gotplt_union plt_bnd; + /* Offset of the GOTPLT entry reserved for the TLS descriptor, starting at the end of the jump table. */ bfd_vma tlsdesc_got; @@ -741,6 +814,7 @@ struct elf_x86_64_link_hash_table asection *sdynbss; asection *srelbss; asection *plt_eh_frame; + asection *plt_bnd; union { @@ -818,6 +892,8 @@ elf_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry, eh = (struct elf_x86_64_link_hash_entry *) entry; eh->dyn_relocs = NULL; eh->tls_type = GOT_UNKNOWN; + eh->has_bnd_reloc = FALSE; + eh->plt_bnd.offset = (bfd_vma) -1; eh->tlsdesc_got = (bfd_vma) -1; } @@ -891,6 +967,21 @@ elf_x86_64_get_local_sym_hash (struct elf_x86_64_link_hash_table *htab, return &ret->elf; } +/* Destroy an X86-64 ELF linker hash table. */ + +static void +elf_x86_64_link_hash_table_free (bfd *obfd) +{ + struct elf_x86_64_link_hash_table *htab + = (struct elf_x86_64_link_hash_table *) obfd->link.hash; + + if (htab->loc_hash_table) + htab_delete (htab->loc_hash_table); + if (htab->loc_hash_memory) + objalloc_free ((struct objalloc *) htab->loc_hash_memory); + _bfd_elf_link_hash_table_free (obfd); +} + /* Create an X86-64 ELF linker hash table. */ static struct bfd_link_hash_table * @@ -936,28 +1027,14 @@ elf_x86_64_link_hash_table_create (bfd *abfd) ret->loc_hash_memory = objalloc_create (); if (!ret->loc_hash_table || !ret->loc_hash_memory) { - free (ret); + elf_x86_64_link_hash_table_free (abfd); return NULL; } + ret->elf.root.hash_table_free = elf_x86_64_link_hash_table_free; return &ret->elf.root; } -/* Destroy an X86-64 ELF linker hash table. */ - -static void -elf_x86_64_link_hash_table_free (struct bfd_link_hash_table *hash) -{ - struct elf_x86_64_link_hash_table *htab - = (struct elf_x86_64_link_hash_table *) hash; - - if (htab->loc_hash_table) - htab_delete (htab->loc_hash_table); - if (htab->loc_hash_memory) - objalloc_free ((struct objalloc *) htab->loc_hash_memory); - _bfd_elf_link_hash_table_free (hash); -} - /* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and .rela.bss sections in DYNOBJ, and set up shortcuts to them in our hash table. */ @@ -1011,6 +1088,9 @@ elf_x86_64_copy_indirect_symbol (struct bfd_link_info *info, edir = (struct elf_x86_64_link_hash_entry *) dir; eind = (struct elf_x86_64_link_hash_entry *) ind; + if (!edir->has_bnd_reloc) + edir->has_bnd_reloc = eind->has_bnd_reloc; + if (eind->dyn_relocs != NULL) { if (edir->dyn_relocs != NULL) @@ -1547,14 +1627,60 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, default: break; - case R_X86_64_32S: + case R_X86_64_PC32_BND: + case R_X86_64_PLT32_BND: + case R_X86_64_PC32: + case R_X86_64_PLT32: case R_X86_64_32: case R_X86_64_64: - case R_X86_64_PC32: - case R_X86_64_PC32_BND: + /* MPX PLT is supported only if elf_x86_64_arch_bed + is used in 64-bit mode. */ + if (ABI_64_P (abfd) + && info->bndplt + && (get_elf_x86_64_backend_data (abfd) + == &elf_x86_64_arch_bed)) + { + elf_x86_64_hash_entry (h)->has_bnd_reloc = TRUE; + + /* Create the second PLT for Intel MPX support. */ + if (htab->plt_bnd == NULL) + { + unsigned int plt_bnd_align; + const struct elf_backend_data *bed; + + bed = get_elf_backend_data (info->output_bfd); + switch (sizeof (elf_x86_64_bnd_plt2_entry)) + { + case 8: + plt_bnd_align = 3; + break; + case 16: + plt_bnd_align = 4; + break; + default: + abort (); + } + + if (htab->elf.dynobj == NULL) + htab->elf.dynobj = abfd; + htab->plt_bnd + = bfd_make_section_anyway_with_flags (htab->elf.dynobj, + ".plt.bnd", + (bed->dynamic_sec_flags + | SEC_ALLOC + | SEC_CODE + | SEC_LOAD + | SEC_READONLY)); + if (htab->plt_bnd == NULL + || !bfd_set_section_alignment (htab->elf.dynobj, + htab->plt_bnd, + plt_bnd_align)) + return FALSE; + } + } + + case R_X86_64_32S: case R_X86_64_PC64: - case R_X86_64_PLT32: - case R_X86_64_PLT32_BND: case R_X86_64_GOTPCREL: case R_X86_64_GOTPCREL64: if (htab->elf.dynobj == NULL) @@ -2310,11 +2436,28 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) here if it is defined and referenced in a non-shared object. */ if (h->type == STT_GNU_IFUNC && h->def_regular) - return _bfd_elf_allocate_ifunc_dyn_relocs (info, h, - &eh->dyn_relocs, - plt_entry_size, - plt_entry_size, - GOT_ENTRY_SIZE); + { + if (_bfd_elf_allocate_ifunc_dyn_relocs (info, h, + &eh->dyn_relocs, + plt_entry_size, + plt_entry_size, + GOT_ENTRY_SIZE)) + { + asection *s = htab->plt_bnd; + if (h->plt.offset != (bfd_vma) -1 && s != NULL) + { + /* Use the .plt.bnd section if it is created. */ + eh->plt_bnd.offset = s->size; + + /* Make room for this entry in the .plt.bnd section. */ + s->size += sizeof (elf_x86_64_legacy_plt2_entry); + } + + return TRUE; + } + else + return FALSE; + } else if (htab->elf.dynamic_sections_created && h->plt.refcount > 0) { @@ -2331,6 +2474,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) { asection *s = htab->elf.splt; + asection *bnd_s = htab->plt_bnd; /* If this is the first .plt entry, make room for the special first entry. */ @@ -2338,6 +2482,8 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) s->size = plt_entry_size; h->plt.offset = s->size; + if (bnd_s) + eh->plt_bnd.offset = bnd_s->size; /* If this symbol is not defined in a regular file, and we are not generating a shared library, then set the symbol to this @@ -2347,12 +2493,28 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) if (! info->shared && !h->def_regular) { - h->root.u.def.section = s; - h->root.u.def.value = h->plt.offset; + if (bnd_s) + { + /* We need to make a call to the entry of the second + PLT instead of regular PLT entry. */ + h->root.u.def.section = bnd_s; + h->root.u.def.value = eh->plt_bnd.offset; + } + else + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } } /* Make room for this entry. */ s->size += plt_entry_size; + if (bnd_s) + { + BFD_ASSERT (sizeof (elf_x86_64_bnd_plt2_entry) + == sizeof (elf_x86_64_legacy_plt2_entry)); + bnd_s->size += sizeof (elf_x86_64_legacy_plt2_entry); + } /* We also need to make an entry in the .got.plt section, which will be placed in the .got section by the linker script. */ @@ -2616,7 +2778,7 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec, /* Nothing to do if there are no codes, no relocations or no output. */ if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC) || sec->reloc_count == 0 - || discarded_section (sec)) + || bfd_is_abs_section (sec->output_section)) return TRUE; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; @@ -2775,7 +2937,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, /* Set up .got offsets for local syms, and space for local dynamic relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { bfd_signed_vma *local_got; bfd_signed_vma *end_local_got; @@ -2976,6 +3138,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, || s == htab->elf.sgotplt || s == htab->elf.iplt || s == htab->elf.igotplt + || s == htab->plt_bnd || s == htab->plt_eh_frame || s == htab->sdynbss) { @@ -3254,14 +3417,15 @@ elf_x86_64_relocate_section (bfd *output_bfd, reloc_howto_type *howto; unsigned long r_symndx; struct elf_link_hash_entry *h; + struct elf_x86_64_link_hash_entry *eh; Elf_Internal_Sym *sym; asection *sec; - bfd_vma off, offplt; + bfd_vma off, offplt, plt_offset; bfd_vma relocation; bfd_boolean unresolved_reloc; bfd_reloc_status_type r; int tls_type; - asection *base_got; + asection *base_got, *resolved_plt; bfd_vma st_size; r_type = ELF32_R_TYPE (rel->r_info); @@ -3349,13 +3513,14 @@ elf_x86_64_relocate_section (bfd *output_bfd, } } + eh = (struct elf_x86_64_link_hash_entry *) h; + /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it here if it is defined in a non-shared object. */ if (h != NULL && h->type == STT_GNU_IFUNC && h->def_regular) { - asection *plt; bfd_vma plt_index; const char *name; @@ -3364,9 +3529,27 @@ elf_x86_64_relocate_section (bfd *output_bfd, abort (); /* STT_GNU_IFUNC symbol must go through PLT. */ - plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt; - relocation = (plt->output_section->vma - + plt->output_offset + h->plt.offset); + if (htab->elf.splt != NULL) + { + if (htab->plt_bnd != NULL) + { + resolved_plt = htab->plt_bnd; + plt_offset = eh->plt_bnd.offset; + } + else + { + resolved_plt = htab->elf.splt; + plt_offset = h->plt.offset; + } + } + else + { + resolved_plt = htab->elf.iplt; + plt_offset = h->plt.offset; + } + + relocation = (resolved_plt->output_section->vma + + resolved_plt->output_offset + plt_offset); switch (r_type) { @@ -3695,9 +3878,20 @@ elf_x86_64_relocate_section (bfd *output_bfd, && h->plt.offset != (bfd_vma) -1 && htab->elf.splt != NULL) { - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset); + if (htab->plt_bnd != NULL) + { + resolved_plt = htab->plt_bnd; + plt_offset = eh->plt_bnd.offset; + } + else + { + resolved_plt = htab->elf.splt; + plt_offset = h->plt.offset; + } + + relocation = (resolved_plt->output_section->vma + + resolved_plt->output_offset + + plt_offset); unresolved_reloc = FALSE; } @@ -3724,9 +3918,20 @@ elf_x86_64_relocate_section (bfd *output_bfd, break; } - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset); + if (htab->plt_bnd != NULL) + { + resolved_plt = htab->plt_bnd; + plt_offset = eh->plt_bnd.offset; + } + else + { + resolved_plt = htab->elf.splt; + plt_offset = h->plt.offset; + } + + relocation = (resolved_plt->output_section->vma + + resolved_plt->output_offset + + plt_offset); unresolved_reloc = FALSE; break; @@ -4077,17 +4282,27 @@ direct: else if (ELF32_R_TYPE (rel->r_info) == R_X86_64_GOTTPOFF) { /* IE->LE transition: - Originally it can be one of: + For 64bit, originally it can be one of: movq foo@gottpoff(%rip), %reg addq foo@gottpoff(%rip), %reg We change it into: movq $foo, %reg leaq foo(%reg), %reg - addq $foo, %reg. */ + addq $foo, %reg. + For 32bit, originally it can be one of: + movq foo@gottpoff(%rip), %reg + addl foo@gottpoff(%rip), %reg + We change it into: + movq $foo, %reg + leal foo(%reg), %reg + addl $foo, %reg. */ unsigned int val, type, reg; - val = bfd_get_8 (input_bfd, contents + roff - 3); + if (roff >= 3) + val = bfd_get_8 (input_bfd, contents + roff - 3); + else + val = 0; type = bfd_get_8 (input_bfd, contents + roff - 2); reg = bfd_get_8 (input_bfd, contents + roff - 1); reg >>= 3; @@ -4107,8 +4322,8 @@ direct: } else if (reg == 4) { - /* addq -> addq - addressing with %rsp/%r12 is - special */ + /* addq/addl -> addq/addl - addressing with %rsp/%r12 + is special */ if (val == 0x4c) bfd_put_8 (output_bfd, 0x49, contents + roff - 3); @@ -4122,7 +4337,7 @@ direct: } else { - /* addq -> leaq */ + /* addq/addl -> leaq/leal */ if (val == 0x4c) bfd_put_8 (output_bfd, 0x4d, contents + roff - 3); @@ -4524,20 +4739,28 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, Elf_Internal_Sym *sym ATTRIBUTE_UNUSED) { struct elf_x86_64_link_hash_table *htab; - const struct elf_x86_64_backend_data *const abed - = get_elf_x86_64_backend_data (output_bfd); + const struct elf_x86_64_backend_data *abed; + bfd_boolean use_plt_bnd; htab = elf_x86_64_hash_table (info); if (htab == NULL) return FALSE; + /* Use MPX backend data in case of BND relocation. Use .plt_bnd + section only if there is .plt section. */ + use_plt_bnd = htab->elf.splt != NULL && htab->plt_bnd != NULL; + abed = (use_plt_bnd + ? &elf_x86_64_bnd_arch_bed + : get_elf_x86_64_backend_data (output_bfd)); + if (h->plt.offset != (bfd_vma) -1) { bfd_vma plt_index; - bfd_vma got_offset; + bfd_vma got_offset, plt_offset, plt_plt_offset, plt_got_offset; + bfd_vma plt_plt_insn_end, plt_got_insn_size; Elf_Internal_Rela rela; bfd_byte *loc; - asection *plt, *gotplt, *relplt; + asection *plt, *gotplt, *relplt, *resolved_plt; const struct elf_backend_data *bed; /* When building a static executable, use .iplt, .igot.plt and @@ -4588,9 +4811,56 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, got_offset = got_offset * GOT_ENTRY_SIZE; } - /* Fill in the entry in the procedure linkage table. */ - memcpy (plt->contents + h->plt.offset, abed->plt_entry, - abed->plt_entry_size); + plt_plt_insn_end = abed->plt_plt_insn_end; + plt_plt_offset = abed->plt_plt_offset; + plt_got_insn_size = abed->plt_got_insn_size; + plt_got_offset = abed->plt_got_offset; + if (use_plt_bnd) + { + /* Use the second PLT with BND relocations. */ + const bfd_byte *plt_entry, *plt2_entry; + struct elf_x86_64_link_hash_entry *eh + = (struct elf_x86_64_link_hash_entry *) h; + + if (eh->has_bnd_reloc) + { + plt_entry = elf_x86_64_bnd_plt_entry; + plt2_entry = elf_x86_64_bnd_plt2_entry; + } + else + { + plt_entry = elf_x86_64_legacy_plt_entry; + plt2_entry = elf_x86_64_legacy_plt2_entry; + + /* Subtract 1 since there is no BND prefix. */ + plt_plt_insn_end -= 1; + plt_plt_offset -= 1; + plt_got_insn_size -= 1; + plt_got_offset -= 1; + } + + BFD_ASSERT (sizeof (elf_x86_64_bnd_plt_entry) + == sizeof (elf_x86_64_legacy_plt_entry)); + + /* Fill in the entry in the procedure linkage table. */ + memcpy (plt->contents + h->plt.offset, + plt_entry, sizeof (elf_x86_64_legacy_plt_entry)); + /* Fill in the entry in the second PLT. */ + memcpy (htab->plt_bnd->contents + eh->plt_bnd.offset, + plt2_entry, sizeof (elf_x86_64_legacy_plt2_entry)); + + resolved_plt = htab->plt_bnd; + plt_offset = eh->plt_bnd.offset; + } + else + { + /* Fill in the entry in the procedure linkage table. */ + memcpy (plt->contents + h->plt.offset, abed->plt_entry, + abed->plt_entry_size); + + resolved_plt = plt; + plt_offset = h->plt.offset; + } /* Insert the relocation positions of the plt section. */ @@ -4600,11 +4870,11 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, (gotplt->output_section->vma + gotplt->output_offset + got_offset - - plt->output_section->vma - - plt->output_offset - - h->plt.offset - - abed->plt_got_insn_size), - plt->contents + h->plt.offset + abed->plt_got_offset); + - resolved_plt->output_section->vma + - resolved_plt->output_offset + - plt_offset + - plt_got_insn_size), + resolved_plt->contents + plt_offset + plt_got_offset); /* Fill in the entry in the global offset table, initially this points to the second part of the PLT entry. */ @@ -4646,8 +4916,8 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, bfd_put_32 (output_bfd, plt_index, plt->contents + h->plt.offset + abed->plt_reloc_offset); /* Put offset for jmp .PLT0. */ - bfd_put_32 (output_bfd, - (h->plt.offset + abed->plt_plt_insn_end), - plt->contents + h->plt.offset + abed->plt_plt_offset); + bfd_put_32 (output_bfd, - (h->plt.offset + plt_plt_insn_end), + plt->contents + h->plt.offset + plt_plt_offset); } bed = get_elf_backend_data (output_bfd); @@ -4809,13 +5079,18 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, struct elf_x86_64_link_hash_table *htab; bfd *dynobj; asection *sdyn; - const struct elf_x86_64_backend_data *const abed - = get_elf_x86_64_backend_data (output_bfd); + const struct elf_x86_64_backend_data *abed; htab = elf_x86_64_hash_table (info); if (htab == NULL) return FALSE; + /* Use MPX backend data in case of BND relocation. Use .plt_bnd + section only if there is .plt section. */ + abed = (htab->elf.splt != NULL && htab->plt_bnd != NULL + ? &elf_x86_64_bnd_arch_bed + : get_elf_x86_64_backend_data (output_bfd)); + dynobj = htab->elf.dynobj; sdyn = bfd_get_linker_section (dynobj, ".dynamic"); @@ -4956,6 +5231,10 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, } } + if (htab->plt_bnd != NULL) + elf_section_data (htab->plt_bnd->output_section) + ->this_hdr.sh_entsize = sizeof (elf_x86_64_bnd_plt2_entry); + if (htab->elf.sgotplt) { if (bfd_is_abs_section (htab->elf.sgotplt->output_section)) @@ -5024,24 +5303,208 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, return TRUE; } -/* Return address for Ith PLT stub in section PLT, for relocation REL - or (bfd_vma) -1 if it should not be included. */ +/* Return address in section PLT for the Ith GOTPLT relocation, for + relocation REL or (bfd_vma) -1 if it should not be included. */ static bfd_vma elf_x86_64_plt_sym_val (bfd_vma i, const asection *plt, - const arelent *rel ATTRIBUTE_UNUSED) + const arelent *rel) { - return plt->vma + (i + 1) * GET_PLT_ENTRY_SIZE (plt->owner); + bfd *abfd; + const struct elf_x86_64_backend_data *bed; + bfd_vma plt_offset; + + /* Only match R_X86_64_JUMP_SLOT and R_X86_64_IRELATIVE. */ + if (rel->howto->type != R_X86_64_JUMP_SLOT + && rel->howto->type != R_X86_64_IRELATIVE) + return (bfd_vma) -1; + + abfd = plt->owner; + bed = get_elf_x86_64_backend_data (abfd); + plt_offset = bed->plt_entry_size; + + if (elf_elfheader (abfd)->e_ident[EI_OSABI] != ELFOSABI_GNU) + return plt->vma + (i + 1) * plt_offset; + + while (plt_offset < plt->size) + { + bfd_vma reloc_index; + bfd_byte reloc_index_raw[4]; + + if (!bfd_get_section_contents (abfd, (asection *) plt, + reloc_index_raw, + plt_offset + bed->plt_reloc_offset, + sizeof (reloc_index_raw))) + return (bfd_vma) -1; + + reloc_index = H_GET_32 (abfd, reloc_index_raw); + if (reloc_index == i) + return plt->vma + plt_offset; + plt_offset += bed->plt_entry_size; + } + + abort (); +} + +/* Return offset in .plt.bnd section for the Ith GOTPLT relocation with + PLT section, or (bfd_vma) -1 if it should not be included. */ + +static bfd_vma +elf_x86_64_plt_sym_val_offset_plt_bnd (bfd_vma i, const asection *plt) +{ + const struct elf_x86_64_backend_data *bed = &elf_x86_64_bnd_arch_bed; + bfd *abfd = plt->owner; + bfd_vma plt_offset = bed->plt_entry_size; + + if (elf_elfheader (abfd)->e_ident[EI_OSABI] != ELFOSABI_GNU) + return i * sizeof (elf_x86_64_legacy_plt2_entry); + + while (plt_offset < plt->size) + { + bfd_vma reloc_index; + bfd_byte reloc_index_raw[4]; + + if (!bfd_get_section_contents (abfd, (asection *) plt, + reloc_index_raw, + plt_offset + bed->plt_reloc_offset, + sizeof (reloc_index_raw))) + return (bfd_vma) -1; + + reloc_index = H_GET_32 (abfd, reloc_index_raw); + if (reloc_index == i) + { + /* This is the index in .plt section. */ + long plt_index = plt_offset / bed->plt_entry_size; + /* Return the offset in .plt.bnd section. */ + return (plt_index - 1) * sizeof (elf_x86_64_legacy_plt2_entry); + } + plt_offset += bed->plt_entry_size; + } + + abort (); +} + +/* Similar to _bfd_elf_get_synthetic_symtab, with .plt.bnd section + support. */ + +static long +elf_x86_64_get_synthetic_symtab (bfd *abfd, + long symcount, + asymbol **syms, + long dynsymcount, + asymbol **dynsyms, + asymbol **ret) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + asection *relplt; + asymbol *s; + bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); + arelent *p; + long count, i, n; + size_t size; + Elf_Internal_Shdr *hdr; + char *names; + asection *plt, *plt_push; + + plt_push = bfd_get_section_by_name (abfd, ".plt"); + if (plt_push == NULL) + return 0; + + plt = bfd_get_section_by_name (abfd, ".plt.bnd"); + /* Use the generic ELF version if there is no .plt.bnd section. */ + if (plt == NULL) + return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms, + dynsymcount, dynsyms, ret); + + *ret = NULL; + + if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0) + return 0; + + if (dynsymcount <= 0) + return 0; + + relplt = bfd_get_section_by_name (abfd, ".rela.plt"); + if (relplt == NULL) + return 0; + + hdr = &elf_section_data (relplt)->this_hdr; + if (hdr->sh_link != elf_dynsymtab (abfd) + || (hdr->sh_type != SHT_REL && hdr->sh_type != SHT_RELA)) + return 0; + + slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; + if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) + return -1; + + count = relplt->size / hdr->sh_entsize; + size = count * sizeof (asymbol); + p = relplt->relocation; + for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel) + { + size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt"); + if (p->addend != 0) + size += sizeof ("+0x") - 1 + 8 + 8; + } + + s = *ret = (asymbol *) bfd_malloc (size); + if (s == NULL) + return -1; + + names = (char *) (s + count); + p = relplt->relocation; + n = 0; + for (i = 0; i < count; i++, p++) + { + bfd_vma offset; + size_t len; + + if (p->howto->type != R_X86_64_JUMP_SLOT + && p->howto->type != R_X86_64_IRELATIVE) + continue; + + offset = elf_x86_64_plt_sym_val_offset_plt_bnd (i, plt_push); + + *s = **p->sym_ptr_ptr; + /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since + we are defining a symbol, ensure one of them is set. */ + if ((s->flags & BSF_LOCAL) == 0) + s->flags |= BSF_GLOBAL; + s->flags |= BSF_SYNTHETIC; + s->section = plt; + s->value = offset; + s->name = names; + s->udata.p = NULL; + len = strlen ((*p->sym_ptr_ptr)->name); + memcpy (names, (*p->sym_ptr_ptr)->name, len); + names += len; + if (p->addend != 0) + { + char buf[30], *a; + + memcpy (names, "+0x", sizeof ("+0x") - 1); + names += sizeof ("+0x") - 1; + bfd_sprintf_vma (abfd, buf, p->addend); + for (a = buf; *a == '0'; ++a) + ; + len = strlen (a); + memcpy (names, a, len); + names += len; + } + memcpy (names, "@plt", sizeof ("@plt")); + names += sizeof ("@plt"); + ++s, ++n; + } + + return n; } /* 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 -elf_x86_64_section_from_shdr (bfd *abfd, - Elf_Internal_Shdr *hdr, - const char *name, - int shindex) +elf_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; @@ -5087,9 +5550,10 @@ elf_x86_64_add_symbol_hook (bfd *abfd, return TRUE; } - if ((abfd->flags & DYNAMIC) == 0 - && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC - || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)) + if ((ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC + || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE) + && (abfd->flags & DYNAMIC) == 0 + && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; return TRUE; @@ -5246,7 +5710,7 @@ static const struct bfd_elf_special_section { NULL, 0, 0, 0, 0 } }; -#define TARGET_LITTLE_SYM bfd_elf64_x86_64_vec +#define TARGET_LITTLE_SYM x86_64_elf64_vec #define TARGET_LITTLE_NAME "elf64-x86-64" #define ELF_ARCH bfd_arch_i386 #define ELF_TARGET_ID X86_64_ELF_DATA @@ -5268,8 +5732,6 @@ static const struct bfd_elf_special_section #define bfd_elf64_bfd_link_hash_table_create \ elf_x86_64_link_hash_table_create -#define bfd_elf64_bfd_link_hash_table_free \ - elf_x86_64_link_hash_table_free #define bfd_elf64_bfd_reloc_type_lookup elf_x86_64_reloc_type_lookup #define bfd_elf64_bfd_reloc_name_lookup \ elf_x86_64_reloc_name_lookup @@ -5296,6 +5758,7 @@ static const struct bfd_elf_special_section #define elf_backend_plt_sym_val elf_x86_64_plt_sym_val #define elf_backend_object_p elf64_x86_64_elf_object_p #define bfd_elf64_mkobject elf_x86_64_mkobject +#define bfd_elf64_get_synthetic_symtab elf_x86_64_get_synthetic_symtab #define elf_backend_section_from_shdr \ elf_x86_64_section_from_shdr @@ -5321,14 +5784,12 @@ static const struct bfd_elf_special_section #define elf_backend_hash_symbol \ elf_x86_64_hash_symbol -#define elf_backend_post_process_headers _bfd_elf_set_osabi - #include "elf64-target.h" /* FreeBSD support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf64_x86_64_freebsd_vec +#define TARGET_LITTLE_SYM x86_64_elf64_fbsd_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf64-x86-64-freebsd" @@ -5343,7 +5804,7 @@ static const struct bfd_elf_special_section /* Solaris 2 support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf64_x86_64_sol2_vec +#define TARGET_LITTLE_SYM x86_64_elf64_sol2_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf64-x86-64-sol2" @@ -5368,6 +5829,8 @@ static const struct bfd_elf_special_section #include "elf64-target.h" +#undef bfd_elf64_get_synthetic_symtab + /* Native Client support. */ static bfd_boolean @@ -5379,7 +5842,7 @@ elf64_x86_64_nacl_elf_object_p (bfd *abfd) } #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf64_x86_64_nacl_vec +#define TARGET_LITTLE_SYM x86_64_elf64_nacl_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf64-x86-64-nacl" #undef elf64_bed @@ -5532,7 +5995,7 @@ elf32_x86_64_nacl_elf_object_p (bfd *abfd) } #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf32_x86_64_nacl_vec +#define TARGET_LITTLE_SYM x86_64_elf32_nacl_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-x86-64-nacl" #undef elf32_bed @@ -5540,8 +6003,6 @@ elf32_x86_64_nacl_elf_object_p (bfd *abfd) #define bfd_elf32_bfd_link_hash_table_create \ elf_x86_64_link_hash_table_create -#define bfd_elf32_bfd_link_hash_table_free \ - elf_x86_64_link_hash_table_free #define bfd_elf32_bfd_reloc_type_lookup \ elf_x86_64_reloc_type_lookup #define bfd_elf32_bfd_reloc_name_lookup \ @@ -5583,7 +6044,7 @@ elf64_l1om_elf_object_p (bfd *abfd) } #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf64_l1om_vec +#define TARGET_LITTLE_SYM l1om_elf64_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf64-l1om" #undef ELF_ARCH @@ -5617,7 +6078,7 @@ elf64_l1om_elf_object_p (bfd *abfd) /* FreeBSD L1OM support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf64_l1om_freebsd_vec +#define TARGET_LITTLE_SYM l1om_elf64_fbsd_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf64-l1om-freebsd" @@ -5640,7 +6101,7 @@ elf64_k1om_elf_object_p (bfd *abfd) } #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf64_k1om_vec +#define TARGET_LITTLE_SYM k1om_elf64_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf64-k1om" #undef ELF_ARCH @@ -5667,7 +6128,7 @@ elf64_k1om_elf_object_p (bfd *abfd) /* FreeBSD K1OM support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf64_k1om_freebsd_vec +#define TARGET_LITTLE_SYM k1om_elf64_fbsd_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf64-k1om-freebsd" @@ -5682,7 +6143,7 @@ elf64_k1om_elf_object_p (bfd *abfd) /* 32bit x86-64 support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf32_x86_64_vec +#define TARGET_LITTLE_SYM x86_64_elf32_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-x86-64" #undef elf32_bed