X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf64-x86-64.c;h=4c9ad78dd74a600a3da7a45f8fbf2e7d2d2b5cca;hb=7b958a48e1322880f23cdb0a1c35643dd27d3ddb;hp=ad66840eacff196196bc7537859772203b7326d3;hpb=3b4c384407ebbdd9ed4ad5057080b3be038b8748;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index ad66840eac..4c9ad78dd7 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -1,5 +1,5 @@ /* X86-64 specific support for ELF - Copyright (C) 2000-2018 Free Software Foundation, Inc. + Copyright (C) 2000-2020 Free Software Foundation, Inc. Contributed by Jan Hubicka . This file is part of BFD, the Binary File Descriptor library. @@ -196,9 +196,6 @@ static reloc_howto_type x86_64_elf_howto_table[] = FALSE) }; -/* Set if a relocation is converted from a GOTPCREL relocation. */ -#define R_X86_64_converted_reloc_bit (1 << 7) - #define X86_PCREL_TYPE_P(TYPE) \ ( ((TYPE) == R_X86_64_PC8) \ || ((TYPE) == R_X86_64_PC16) \ @@ -282,9 +279,10 @@ elf_x86_64_rtype_to_howto (bfd *abfd, unsigned r_type) if (r_type >= (unsigned int) R_X86_64_standard) { /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid relocation type %d"), - abfd, (int) r_type); - r_type = R_X86_64_NONE; + _bfd_error_handler (_("%pB: unsupported relocation type %#x"), + abfd, r_type); + bfd_set_error (bfd_error_bad_value); + return NULL; } i = r_type; } @@ -336,19 +334,18 @@ elf_x86_64_reloc_name_lookup (bfd *abfd, /* Given an x86_64 ELF reloc type, fill in an arelent structure. */ -static void -elf_x86_64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, +static bfd_boolean +elf_x86_64_info_to_howto (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) { unsigned r_type; r_type = ELF32_R_TYPE (dst->r_info); - if (r_type != (unsigned int) R_X86_64_GNU_VTINHERIT - && r_type != (unsigned int) R_X86_64_GNU_VTENTRY) - r_type &= ~R_X86_64_converted_reloc_bit; cache_ptr->howto = elf_x86_64_rtype_to_howto (abfd, r_type); - + if (cache_ptr->howto == NULL) + return FALSE; BFD_ASSERT (r_type == cache_ptr->howto->type || cache_ptr->howto->type == R_X86_64_NONE); + return TRUE; } /* Support for core dump NOTE sections. */ @@ -439,6 +436,10 @@ elf_x86_64_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) } #ifdef CORE_HEADER +# if GCC_VERSION >= 8000 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wstringop-truncation" +# endif static char * elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...) @@ -524,6 +525,9 @@ elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz, } /* NOTREACHED */ } +# if GCC_VERSION >= 8000 +# pragma GCC diagnostic pop +# endif #endif /* Functions for the x86-64 ELF linker. */ @@ -653,6 +657,14 @@ static const bfd_byte elf_x32_non_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] = 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 /* nopw 0x0(%rax,%rax,1) */ }; +/* The TLSDESC entry in a lazy procedure linkage table. */ +static const bfd_byte elf_x86_64_tlsdesc_plt_entry[LAZY_PLT_ENTRY_SIZE] = +{ + 0xf3, 0x0f, 0x1e, 0xfa, /* endbr64 */ + 0xff, 0x35, 8, 0, 0, 0, /* pushq GOT+8(%rip) */ + 0xff, 0x25, 16, 0, 0, 0 /* jmpq *GOT+TDG(%rip) */ +}; + /* .eh_frame covering the lazy .plt section. */ static const bfd_byte elf_x86_64_eh_frame_lazy_plt[] = @@ -827,6 +839,12 @@ static const struct elf_x86_lazy_plt_layout elf_x86_64_lazy_plt = LAZY_PLT_ENTRY_SIZE, /* plt0_entry_size */ elf_x86_64_lazy_plt_entry, /* plt_entry */ LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ + elf_x86_64_tlsdesc_plt_entry, /* plt_tlsdesc_entry */ + LAZY_PLT_ENTRY_SIZE, /* plt_tlsdesc_entry_size */ + 6, /* plt_tlsdesc_got1_offset */ + 12, /* plt_tlsdesc_got2_offset */ + 10, /* plt_tlsdesc_got1_insn_end */ + 16, /* plt_tlsdesc_got2_insn_end */ 2, /* plt0_got1_offset */ 8, /* plt0_got2_offset */ 12, /* plt0_got2_insn_end */ @@ -859,6 +877,12 @@ static const struct elf_x86_lazy_plt_layout elf_x86_64_lazy_bnd_plt = LAZY_PLT_ENTRY_SIZE, /* plt0_entry_size */ elf_x86_64_lazy_bnd_plt_entry, /* plt_entry */ LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ + elf_x86_64_tlsdesc_plt_entry, /* plt_tlsdesc_entry */ + LAZY_PLT_ENTRY_SIZE, /* plt_tlsdesc_entry_size */ + 6, /* plt_tlsdesc_got1_offset */ + 12, /* plt_tlsdesc_got2_offset */ + 10, /* plt_tlsdesc_got1_insn_end */ + 16, /* plt_tlsdesc_got2_insn_end */ 2, /* plt0_got1_offset */ 1+8, /* plt0_got2_offset */ 1+12, /* plt0_got2_insn_end */ @@ -891,6 +915,12 @@ static const struct elf_x86_lazy_plt_layout elf_x86_64_lazy_ibt_plt = LAZY_PLT_ENTRY_SIZE, /* plt0_entry_size */ elf_x86_64_lazy_ibt_plt_entry, /* plt_entry */ LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ + elf_x86_64_tlsdesc_plt_entry, /* plt_tlsdesc_entry */ + LAZY_PLT_ENTRY_SIZE, /* plt_tlsdesc_entry_size */ + 6, /* plt_tlsdesc_got1_offset */ + 12, /* plt_tlsdesc_got2_offset */ + 10, /* plt_tlsdesc_got1_insn_end */ + 16, /* plt_tlsdesc_got2_insn_end */ 2, /* plt0_got1_offset */ 1+8, /* plt0_got2_offset */ 1+12, /* plt0_got2_insn_end */ @@ -912,6 +942,12 @@ static const struct elf_x86_lazy_plt_layout elf_x32_lazy_ibt_plt = LAZY_PLT_ENTRY_SIZE, /* plt0_entry_size */ elf_x32_lazy_ibt_plt_entry, /* plt_entry */ LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ + elf_x86_64_tlsdesc_plt_entry, /* plt_tlsdesc_entry */ + LAZY_PLT_ENTRY_SIZE, /* plt_tlsdesc_entry_size */ + 6, /* plt_tlsdesc_got1_offset */ + 12, /* plt_tlsdesc_got2_offset */ + 10, /* plt_tlsdesc_got1_insn_end */ + 16, /* plt_tlsdesc_got2_insn_end */ 2, /* plt0_got1_offset */ 8, /* plt0_got2_offset */ 12, /* plt0_got2_insn_end */ @@ -1184,7 +1220,8 @@ elf_x86_64_check_tls_transition (bfd *abfd, case R_X86_64_GOTPC32_TLSDESC: /* Check transition from GDesc access model: - leaq x@tlsdesc(%rip), %rax + leaq x@tlsdesc(%rip), %rax <--- LP64 mode. + rex leal x@tlsdesc(%rip), %eax <--- X32 mode. Make sure it's a leaq adding rip to a 32-bit offset into any register, although it's probably almost always @@ -1194,7 +1231,8 @@ elf_x86_64_check_tls_transition (bfd *abfd, return FALSE; val = bfd_get_8 (abfd, contents + offset - 3); - if ((val & 0xfb) != 0x48) + val &= 0xfb; + if (val != 0x48 && (ABI_64_P (abfd) || val != 0x40)) return FALSE; if (bfd_get_8 (abfd, contents + offset - 2) != 0x8d) @@ -1205,13 +1243,26 @@ elf_x86_64_check_tls_transition (bfd *abfd, case R_X86_64_TLSDESC_CALL: /* Check transition from GDesc access model: - call *x@tlsdesc(%rax) + call *x@tlsdesc(%rax) <--- LP64 mode. + call *x@tlsdesc(%eax) <--- X32 mode. */ if (offset + 2 <= sec->size) { - /* Make sure that it's a call *x@tlsdesc(%rax). */ + unsigned int prefix; call = contents + offset; - return call[0] == 0xff && call[1] == 0x10; + prefix = 0; + if (!ABI_64_P (abfd)) + { + /* Check for call *x@tlsdesc(%eax). */ + if (call[0] == 0x67) + { + prefix = 1; + if (offset + 3 > sec->size) + return FALSE; + } + } + /* Make sure that it's a call *x@tlsdesc(%rax). */ + return call[prefix] == 0xff && call[1 + prefix] == 0x10; } return FALSE; @@ -1311,6 +1362,9 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd, from = elf_x86_64_rtype_to_howto (abfd, from_type); to = elf_x86_64_rtype_to_howto (abfd, to_type); + if (from == NULL || to == NULL) + return FALSE; + if (h) name = h->root.root.string; else @@ -1332,9 +1386,9 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd, _bfd_error_handler /* xgettext:c-format */ - (_("%B: TLS transition from %s to %s against `%s' at %#Lx " - "in section `%A' failed"), - abfd, from->name, to->name, name, rel->r_offset, sec); + (_("%pB: TLS transition from %s to %s against `%s' at %#" PRIx64 + " in section `%pA' failed"), + abfd, from->name, to->name, name, (uint64_t) rel->r_offset, sec); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -1380,28 +1434,37 @@ elf_x86_64_need_pic (struct bfd_link_info *info, v = _("protected symbol "); else v = _("symbol "); - pic = _("; recompile with -fPIC"); + pic = NULL; break; } - if (!h->def_regular && !h->def_dynamic) + if (!SYMBOL_DEFINED_NON_SHARED_P (h) && !h->def_dynamic) und = _("undefined "); } else { name = bfd_elf_sym_name (input_bfd, symtab_hdr, isym, NULL); - pic = _("; recompile with -fPIC"); + pic = NULL; } if (bfd_link_dll (info)) - object = _("a shared object"); - else if (bfd_link_pie (info)) - object = _("a PIE object"); + { + object = _("a shared object"); + if (!pic) + pic = _("; recompile with -fPIC"); + } else - object = _("a PDE object"); + { + if (bfd_link_pie (info)) + object = _("a PIE object"); + else + object = _("a PDE object"); + if (!pic) + pic = _("; recompile with -fPIE"); + } /* xgettext:c-format */ - _bfd_error_handler (_("%B: relocation %s against %s%s`%s' can " + _bfd_error_handler (_("%pB: relocation %s against %s%s`%s' can " "not be used when making %s%s"), input_bfd, howto->name, und, v, name, object, pic); @@ -1443,6 +1506,8 @@ elf_x86_64_convert_load_reloc (bfd *abfd, bfd_boolean no_overflow; bfd_boolean relocx; bfd_boolean to_reloc_pc32; + bfd_boolean abs_symbol; + bfd_boolean local_ref; asection *tsec; bfd_signed_vma raddend; unsigned int opcode; @@ -1450,6 +1515,7 @@ elf_x86_64_convert_load_reloc (bfd *abfd, unsigned int r_type = *r_type_p; unsigned int r_symndx; bfd_vma roff = irel->r_offset; + bfd_vma abs_relocation; if (roff < (r_type == R_X86_64_REX_GOTPCRELX ? 3 : 2)) return TRUE; @@ -1493,6 +1559,9 @@ elf_x86_64_convert_load_reloc (bfd *abfd, || no_overflow || is_pic); + abs_symbol = FALSE; + abs_relocation = 0; + /* Get the symbol referred to by the reloc. */ if (h == NULL) { @@ -1503,8 +1572,13 @@ elf_x86_64_convert_load_reloc (bfd *abfd, if (isym->st_shndx == SHN_UNDEF) return TRUE; + local_ref = TRUE; if (isym->st_shndx == SHN_ABS) - tsec = bfd_abs_section_ptr; + { + tsec = bfd_abs_section_ptr; + abs_symbol = TRUE; + abs_relocation = isym->st_value; + } else if (isym->st_shndx == SHN_COMMON) tsec = bfd_com_section_ptr; else if (isym->st_shndx == SHN_X86_64_LCOMMON) @@ -1520,9 +1594,11 @@ elf_x86_64_convert_load_reloc (bfd *abfd, GOTPCRELX relocations since we need to modify REX byte. It is OK convert mov with R_X86_64_GOTPCREL to R_X86_64_PC32. */ - bfd_boolean local_ref; struct elf_x86_link_hash_entry *eh = elf_x86_hash_entry (h); + abs_symbol = ABS_SYMBOL_P (h); + abs_relocation = h->root.u.def.value; + /* NB: Also set linker_def via SYMBOL_REFERENCES_LOCAL_P. */ local_ref = SYMBOL_REFERENCES_LOCAL_P (link_info, h); if ((relocx || opcode == 0x8b) @@ -1596,7 +1672,7 @@ elf_x86_64_convert_load_reloc (bfd *abfd, if (no_overflow) return TRUE; -convert: + convert: if (opcode == 0xff) { /* We have "call/jmp *foo@GOTPCREL(%rip)". */ @@ -1634,8 +1710,8 @@ convert: } else { - nop = link_info->call_nop_byte; - if (link_info->call_nop_as_suffix) + nop = htab->params->call_nop_byte; + if (htab->params->call_nop_as_suffix) { nop_offset = irel->r_offset + 3; disp = bfd_get_32 (abfd, contents + irel->r_offset); @@ -1662,6 +1738,9 @@ convert: if (opcode == 0x8b) { + if (abs_symbol && local_ref) + to_reloc_pc32 = FALSE; + if (to_reloc_pc32) { /* Convert "mov foo@GOTPCREL(%rip), %reg" to @@ -1721,7 +1800,22 @@ convert: overflow when sign-extending imm32 to imm64. */ r_type = (rex & REX_W) != 0 ? R_X86_64_32S : R_X86_64_32; -rewrite_modrm_rex: + rewrite_modrm_rex: + if (abs_relocation) + { + /* Check if R_X86_64_32S/R_X86_64_32 fits. */ + if (r_type == R_X86_64_32S) + { + if ((abs_relocation + 0x80000000) > 0xffffffff) + return TRUE; + } + else + { + if (abs_relocation > 0xffffffff) + return TRUE; + } + } + bfd_put_8 (abfd, modrm, contents + roff - 1); if (rex) @@ -1813,6 +1907,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, const char *name; bfd_boolean size_reloc; bfd_boolean converted_reloc; + bfd_boolean no_dynreloc; r_symndx = htab->r_sym (rel->r_info); r_type = ELF32_R_TYPE (rel->r_info); @@ -1820,7 +1915,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) { /* xgettext:c-format */ - _bfd_error_handler (_("%B: bad symbol index: %d"), + _bfd_error_handler (_("%pB: bad symbol index: %d"), abfd, r_symndx); goto error_return; } @@ -1886,7 +1981,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, NULL); _bfd_error_handler /* xgettext:c-format */ - (_("%B: relocation %s against symbol `%s' isn't " + (_("%pB: relocation %s against symbol `%s' isn't " "supported in x32 mode"), abfd, x86_64_elf_howto_table[r_type].name, name); bfd_set_error (bfd_error_bad_value); @@ -1899,10 +1994,6 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, { /* It is referenced by a non-shared object. */ h->ref_regular = 1; - - if (h->type == STT_GNU_IFUNC) - elf_tdata (info->output_bfd)->has_gnu_symbols - |= elf_gnu_symbol_ifunc; } converted_reloc = FALSE; @@ -1921,6 +2012,10 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, converted = TRUE; } + if (!_bfd_elf_x86_valid_reloc_p (sec, info, htab, rel, h, isym, + symtab_hdr, &no_dynreloc)) + return FALSE; + if (! elf_x86_64_tls_transition (info, abfd, sec, contents, symtab_hdr, sym_hashes, &r_type, GOT_UNKNOWN, @@ -1967,12 +2062,26 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, switch (r_type) { - default: tls_type = GOT_NORMAL; break; - case R_X86_64_TLSGD: tls_type = GOT_TLS_GD; break; - case R_X86_64_GOTTPOFF: tls_type = GOT_TLS_IE; break; + default: + tls_type = GOT_NORMAL; + if (h) + { + if (ABS_SYMBOL_P (h)) + tls_type = GOT_ABS; + } + else if (isym->st_shndx == SHN_ABS) + tls_type = GOT_ABS; + break; + case R_X86_64_TLSGD: + tls_type = GOT_TLS_GD; + break; + case R_X86_64_GOTTPOFF: + tls_type = GOT_TLS_IE; + break; case R_X86_64_GOTPC32_TLSDESC: case R_X86_64_TLSDESC_CALL: - tls_type = GOT_TLS_GDESC; break; + tls_type = GOT_TLS_GDESC; + break; } if (h != NULL) @@ -2028,7 +2137,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, isym, NULL); _bfd_error_handler /* xgettext:c-format */ - (_("%B: '%s' accessed both as normal and" + (_("%pB: '%s' accessed both as normal and" " thread local symbol"), abfd, name); bfd_set_error (bfd_error_bad_value); @@ -2099,7 +2208,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, run-time relocation overflow. Don't error out for sections we don't care about, such as debug sections or when relocation overflow check is disabled. */ - if (!info->no_reloc_overflow_check + if (!htab->params->no_reloc_overflow_check && !converted_reloc && (bfd_link_pic (info) || (bfd_link_executable (info) @@ -2117,7 +2226,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_X86_64_PC32_BND: case R_X86_64_PC64: case R_X86_64_64: -pointer: + pointer: if (eh != NULL && (sec->flags & SEC_CODE) != 0) eh->zero_undefweak |= 0x2; /* We are called after all symbols have been resolved. Only @@ -2135,7 +2244,17 @@ pointer: as pointer, make sure that PLT is used if foo is a function defined in a shared library. */ if ((sec->flags & SEC_CODE) == 0) - h->pointer_equality_needed = 1; + { + h->pointer_equality_needed = 1; + if (bfd_link_pie (info) + && h->type == STT_FUNC + && !h->def_regular + && h->def_dynamic) + { + h->needs_plt = 1; + h->plt.refcount = 1; + } + } } else if (r_type != R_X86_64_PC32_BND && r_type != R_X86_64_PC64) @@ -2172,9 +2291,10 @@ pointer: } size_reloc = FALSE; -do_size: - if (NEED_DYNAMIC_RELOCATION_P (info, h, sec, r_type, - htab->pointer_r_type)) + do_size: + if (!no_dynreloc + && NEED_DYNAMIC_RELOCATION_P (info, TRUE, h, sec, r_type, + htab->pointer_r_type)) { struct elf_dyn_relocs *p; struct elf_dyn_relocs **head; @@ -2222,7 +2342,7 @@ do_size: p = *head; if (p == NULL || p->sec != sec) { - bfd_size_type amt = sizeof *p; + size_t amt = sizeof *p; p = ((struct elf_dyn_relocs *) bfd_alloc (htab->elf.dynobj, amt)); @@ -2252,9 +2372,7 @@ do_size: /* This relocation describes which C++ vtable entries are actually used. Record for later use during GC. */ case R_X86_64_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) + if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) goto error_return; break; @@ -2281,7 +2399,7 @@ do_size: return TRUE; -error_return: + error_return: if (elf_section_data (sec)->this_hdr.contents != contents) free (contents); sec->check_relocs_failed = 1; @@ -2307,24 +2425,6 @@ elf_x86_64_tpoff (struct bfd_link_info *info, bfd_vma address) return address - static_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 @@ -2355,7 +2455,11 @@ elf_x86_64_relocate_section (bfd *output_bfd, if (htab == NULL) return FALSE; - BFD_ASSERT (is_x86_elf (input_bfd, htab)); + if (!is_x86_elf (input_bfd, htab)) + { + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } plt_entry_size = htab->plt.plt_entry_size; symtab_hdr = &elf_symtab_hdr (input_bfd); @@ -2387,6 +2491,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, bfd_boolean relative_reloc; bfd_boolean converted_reloc; bfd_boolean need_copy_reloc_in_pie; + bfd_boolean no_copyreloc_p; r_type = ELF32_R_TYPE (rel->r_info); if (r_type == (int) R_X86_64_GNU_VTINHERIT @@ -2397,19 +2502,18 @@ elf_x86_64_relocate_section (bfd *output_bfd, continue; } + r_symndx = htab->r_sym (rel->r_info); converted_reloc = (r_type & R_X86_64_converted_reloc_bit) != 0; - r_type &= ~R_X86_64_converted_reloc_bit; + if (converted_reloc) + { + r_type &= ~R_X86_64_converted_reloc_bit; + rel->r_info = htab->r_info (r_symndx, r_type); + } - if (r_type >= (int) R_X86_64_standard) + howto = elf_x86_64_rtype_to_howto (input_bfd, r_type); + if (howto == NULL) return _bfd_unrecognized_reloc (input_bfd, input_section, r_type); - if (r_type != (int) R_X86_64_32 - || ABI_64_P (output_bfd)) - howto = x86_64_elf_howto_table + r_type; - else - howto = (x86_64_elf_howto_table - + ARRAY_SIZE (x86_64_elf_howto_table) - 1); - r_symndx = htab->r_sym (rel->r_info); h = NULL; sym = NULL; sec = NULL; @@ -2452,7 +2556,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, if (sec != NULL && discarded_section (sec)) { _bfd_clear_contents (howto, input_bfd, input_section, - contents + rel->r_offset); + contents, rel->r_offset); wrel->r_offset = rel->r_offset; wrel->r_info = 0; wrel->r_addend = 0; @@ -2505,6 +2609,10 @@ elf_x86_64_relocate_section (bfd *output_bfd, if ((input_section->flags & SEC_ALLOC) == 0) { + /* If this is a SHT_NOTE section without SHF_ALLOC, treat + STT_GNU_IFUNC symbol as STT_FUNC. */ + if (elf_section_type (input_section) == SHT_NOTE) + goto skip_ifunc; /* Dynamic relocs are not propagated for SEC_DEBUGGING sections because such sections are not SEC_ALLOC and thus ld.so will not process them. */ @@ -2618,7 +2726,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, switch (r_type) { default: -bad_ifunc_reloc: + bad_ifunc_reloc: if (h->root.root.string) name = h->root.root.string; else @@ -2626,7 +2734,7 @@ bad_ifunc_reloc: NULL); _bfd_error_handler /* xgettext:c-format */ - (_("%B: relocation %s against STT_GNU_IFUNC " + (_("%pB: relocation %s against STT_GNU_IFUNC " "symbol `%s' isn't supported"), input_bfd, howto->name, name); bfd_set_error (bfd_error_bad_value); @@ -2642,7 +2750,7 @@ bad_ifunc_reloc: goto do_relocation; /* FALLTHROUGH */ case R_X86_64_64: -do_ifunc_pointer: + do_ifunc_pointer: if (rel->r_addend != 0) { if (h->root.root.string) @@ -2652,9 +2760,9 @@ do_ifunc_pointer: sym, NULL); _bfd_error_handler /* xgettext:c-format */ - (_("%B: relocation %s against STT_GNU_IFUNC " - "symbol `%s' has non-zero addend: %Ld"), - input_bfd, howto->name, name, rel->r_addend); + (_("%pB: relocation %s against STT_GNU_IFUNC " + "symbol `%s' has non-zero addend: %" PRId64), + input_bfd, howto->name, name, (int64_t) rel->r_addend); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -2683,7 +2791,7 @@ do_ifunc_pointer: if (POINTER_LOCAL_IFUNC_P (info, h)) { - info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"), + info->callbacks->minfo (_("Local IFUNC function `%s' in %pB\n"), h->root.root.string, h->root.u.def.section->owner); @@ -2728,6 +2836,7 @@ do_ifunc_pointer: } } + skip_ifunc: resolved_to_zero = (eh != NULL && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh)); @@ -2819,7 +2928,14 @@ do_ifunc_pointer: base_got->contents + off); local_got_offsets[r_symndx] |= 1; - if (bfd_link_pic (info)) + /* NB: GOTPCREL relocations against local absolute + symbol store relocation value in the GOT slot + without relative relocation. */ + if (bfd_link_pic (info) + && !(sym->st_shndx == SHN_ABS + && (r_type == R_X86_64_GOTPCREL + || r_type == R_X86_64_GOTPCRELX + || r_type == R_X86_64_REX_GOTPCRELX))) relative_reloc = TRUE; } } @@ -2889,7 +3005,7 @@ do_ifunc_pointer: _bfd_error_handler /* xgettext:c-format */ - (_("%B: relocation R_X86_64_GOTOFF64 against undefined %s" + (_("%pB: relocation R_X86_64_GOTOFF64 against undefined %s" " `%s' can not be used when making a shared object"), input_bfd, v, h->root.root.string); bfd_set_error (bfd_error_bad_value); @@ -2902,14 +3018,14 @@ do_ifunc_pointer: && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) { _bfd_error_handler - /* xgettext:c-format */ - (_("%B: relocation R_X86_64_GOTOFF64 against protected %s" + /* xgettext:c-format */ + (_("%pB: relocation R_X86_64_GOTOFF64 against protected %s" " `%s' can not be used when making a shared object"), input_bfd, h->type == STT_FUNC ? "function" : "data", h->root.root.string); bfd_set_error (bfd_error_bad_value); - return FALSE; + return FALSE; } } @@ -2986,6 +3102,7 @@ do_ifunc_pointer: break; } + use_plt: if (h->plt.offset != (bfd_vma) -1) { if (htab->plt_second != NULL) @@ -3023,48 +3140,73 @@ do_ifunc_pointer: case R_X86_64_PC32: case R_X86_64_PC32_BND: /* Don't complain about -fPIC if the symbol is undefined when - building executable unless it is unresolved weak symbol or - -z nocopyreloc is used. */ + building executable unless it is unresolved weak symbol, + references a dynamic definition in PIE or -z nocopyreloc + is used. */ + no_copyreloc_p + = (info->nocopyreloc + || (h != NULL + && !h->root.linker_def + && !h->root.ldscript_def + && eh->def_protected + && elf_has_no_copy_on_protected (h->root.u.def.section->owner))); + if ((input_section->flags & SEC_ALLOC) != 0 && (input_section->flags & SEC_READONLY) != 0 && h != NULL && ((bfd_link_executable (info) && ((h->root.type == bfd_link_hash_undefweak - && !resolved_to_zero) - || ((info->nocopyreloc - || (eh->def_protected - && elf_has_no_copy_on_protected (h->root.u.def.section->owner))) + && (eh == NULL + || !UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, + eh))) + || (bfd_link_pie (info) + && !SYMBOL_DEFINED_NON_SHARED_P (h) + && h->def_dynamic) + || (no_copyreloc_p && h->def_dynamic && !(h->root.u.def.section->flags & SEC_CODE)))) || bfd_link_dll (info))) { bfd_boolean fail = FALSE; - bfd_boolean branch - = ((r_type == R_X86_64_PC32 - || r_type == R_X86_64_PC32_BND) - && is_32bit_relative_branch (contents, rel->r_offset)); - if (SYMBOL_REFERENCES_LOCAL_P (info, h)) { /* Symbol is referenced locally. Make sure it is - defined locally or for a branch. */ - fail = (!(h->def_regular || ELF_COMMON_DEF_P (h)) - && !branch); + defined locally. */ + fail = !SYMBOL_DEFINED_NON_SHARED_P (h); } - else if (!(bfd_link_pie (info) - && (h->needs_copy || eh->needs_copy))) + else if (bfd_link_pie (info)) { - /* Symbol doesn't need copy reloc and isn't referenced - locally. We only allow branch to symbol with - non-default visibility. */ - fail = (!branch - || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT); + /* We can only use PC-relative relocations in PIE + from non-code sections. */ + if (h->type == STT_FUNC + && (sec->flags & SEC_CODE) != 0) + fail = TRUE; + } + else if (no_copyreloc_p || bfd_link_dll (info)) + { + /* Symbol doesn't need copy reloc and isn't + referenced locally. Don't allow PC-relative + relocations against default and protected + symbols since address of protected function + and location of protected data may not be in + the shared object. */ + fail = (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || ELF_ST_VISIBILITY (h->other) == STV_PROTECTED); } if (fail) return elf_x86_64_need_pic (info, input_bfd, input_section, h, NULL, NULL, howto); } + /* Since x86-64 has PC-relative PLT, we can use PLT in PIE + as function address. */ + else if (h != NULL + && (input_section->flags & SEC_CODE) == 0 + && bfd_link_pie (info) + && h->type == STT_FUNC + && !h->def_regular + && h->def_dynamic) + goto use_plt; /* Fall through. */ case R_X86_64_8: @@ -3075,7 +3217,7 @@ do_ifunc_pointer: /* FIXME: The ABI says the linker should make sure the value is the same when it's zeroextended to 64 bit. */ -direct: + direct: if ((input_section->flags & SEC_ALLOC) == 0) break; @@ -3088,7 +3230,7 @@ direct: && (X86_PCREL_TYPE_P (r_type) || X86_SIZE_TYPE_P (r_type))); - if (GENERATE_DYNAMIC_RELOCATION_P (info, eh, r_type, + if (GENERATE_DYNAMIC_RELOCATION_P (info, eh, r_type, sec, need_copy_reloc_in_pie, resolved_to_zero, FALSE)) { @@ -3128,7 +3270,7 @@ direct: convert R_X86_64_32 to dynamic R_X86_64_RELATIVE. */ if (r_type == htab->pointer_r_type || (r_type == R_X86_64_32 - && info->no_reloc_overflow_check)) + && htab->params->no_reloc_overflow_check)) { relocate = TRUE; outrel.r_info = htab->r_info (0, R_X86_64_RELATIVE); @@ -3154,11 +3296,12 @@ direct: sym, NULL); _bfd_error_handler /* xgettext:c-format */ - (_("%B: addend %s%#x in relocation %s against " - "symbol `%s' at %#Lx in section `%A' is " - "out of range"), + (_("%pB: addend %s%#x in relocation %s against " + "symbol `%s' at %#" PRIx64 + " in section `%pA' is out of range"), input_bfd, addend < 0 ? "-" : "", addend, - howto->name, name, rel->r_offset, input_section); + howto->name, name, (uint64_t) rel->r_offset, + input_section); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -3282,20 +3425,39 @@ direct: { if (contents[roff + 5] == 0xb8) { + if (roff < 3 + || (roff - 3 + 22) > input_section->size) + { + corrupt_input: + info->callbacks->einfo + (_("%F%P: corrupt input: %pB\n"), + input_bfd); + return FALSE; + } memcpy (contents + roff - 3, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80" "\0\0\0\0\x66\x0f\x1f\x44\0", 22); largepic = 1; } else - memcpy (contents + roff - 4, - "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0", - 16); + { + if (roff < 4 + || (roff - 4 + 16) > input_section->size) + goto corrupt_input; + memcpy (contents + roff - 4, + "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0", + 16); + } } else - memcpy (contents + roff - 3, - "\x64\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0", - 15); + { + if (roff < 3 + || (roff - 3 + 15) > input_section->size) + goto corrupt_input; + memcpy (contents + roff - 3, + "\x64\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0", + 15); + } bfd_put_32 (output_bfd, elf_x86_64_tpoff (info, relocation), contents + roff + 8 + largepic); @@ -3309,16 +3471,22 @@ direct: { /* GDesc -> LE transition. It's originally something like: - leaq x@tlsdesc(%rip), %rax + leaq x@tlsdesc(%rip), %rax <--- LP64 mode. + rex leal x@tlsdesc(%rip), %eax <--- X32 mode. Change it to: - movl $x@tpoff, %rax. */ + movq $x@tpoff, %rax <--- LP64 mode. + rex movl $x@tpoff, %eax <--- X32 mode. + */ unsigned int val, type; + if (roff < 3) + goto corrupt_input; type = bfd_get_8 (input_bfd, contents + roff - 3); val = bfd_get_8 (input_bfd, contents + roff - 1); - bfd_put_8 (output_bfd, 0x48 | ((type >> 2) & 1), + bfd_put_8 (output_bfd, + (type & 0x48) | ((type >> 2) & 1), contents + roff - 3); bfd_put_8 (output_bfd, 0xc7, contents + roff - 2); bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7), @@ -3332,11 +3500,30 @@ direct: { /* GDesc -> LE transition. It's originally: - call *(%rax) + call *(%rax) <--- LP64 mode. + call *(%eax) <--- X32 mode. Turn it into: - xchg %ax,%ax. */ - bfd_put_8 (output_bfd, 0x66, contents + roff); - bfd_put_8 (output_bfd, 0x90, contents + roff + 1); + xchg %ax,%ax <-- LP64 mode. + nopl (%rax) <-- X32 mode. + */ + unsigned int prefix = 0; + if (!ABI_64_P (input_bfd)) + { + /* Check for call *x@tlsdesc(%eax). */ + if (contents[roff] == 0x67) + prefix = 1; + } + if (prefix) + { + bfd_put_8 (output_bfd, 0x0f, contents + roff); + bfd_put_8 (output_bfd, 0x1f, contents + roff + 1); + bfd_put_8 (output_bfd, 0x00, contents + roff + 2); + } + else + { + bfd_put_8 (output_bfd, 0x66, contents + roff); + bfd_put_8 (output_bfd, 0x90, contents + roff + 1); + } continue; } else if (r_type == R_X86_64_GOTTPOFF) @@ -3362,7 +3549,11 @@ direct: if (roff >= 3) val = bfd_get_8 (input_bfd, contents + roff - 3); else - val = 0; + { + if (roff < 2) + goto corrupt_input; + val = 0; + } type = bfd_get_8 (input_bfd, contents + roff - 2); reg = bfd_get_8 (input_bfd, contents + roff - 1); reg >>= 3; @@ -3370,11 +3561,19 @@ direct: { /* movq */ if (val == 0x4c) - bfd_put_8 (output_bfd, 0x49, - contents + roff - 3); + { + if (roff < 3) + goto corrupt_input; + bfd_put_8 (output_bfd, 0x49, + contents + roff - 3); + } else if (!ABI_64_P (output_bfd) && val == 0x44) - bfd_put_8 (output_bfd, 0x41, - contents + roff - 3); + { + if (roff < 3) + goto corrupt_input; + bfd_put_8 (output_bfd, 0x41, + contents + roff - 3); + } bfd_put_8 (output_bfd, 0xc7, contents + roff - 2); bfd_put_8 (output_bfd, 0xc0 | reg, @@ -3385,11 +3584,19 @@ direct: /* addq/addl -> addq/addl - addressing with %rsp/%r12 is special */ if (val == 0x4c) - bfd_put_8 (output_bfd, 0x49, - contents + roff - 3); + { + if (roff < 3) + goto corrupt_input; + bfd_put_8 (output_bfd, 0x49, + contents + roff - 3); + } else if (!ABI_64_P (output_bfd) && val == 0x44) - bfd_put_8 (output_bfd, 0x41, - contents + roff - 3); + { + if (roff < 3) + goto corrupt_input; + bfd_put_8 (output_bfd, 0x41, + contents + roff - 3); + } bfd_put_8 (output_bfd, 0x81, contents + roff - 2); bfd_put_8 (output_bfd, 0xc0 | reg, @@ -3399,11 +3606,19 @@ direct: { /* addq/addl -> leaq/leal */ if (val == 0x4c) - bfd_put_8 (output_bfd, 0x4d, - contents + roff - 3); + { + if (roff < 3) + goto corrupt_input; + bfd_put_8 (output_bfd, 0x4d, + contents + roff - 3); + } else if (!ABI_64_P (output_bfd) && val == 0x44) - bfd_put_8 (output_bfd, 0x45, - contents + roff - 3); + { + if (roff < 3) + goto corrupt_input; + bfd_put_8 (output_bfd, 0x45, + contents + roff - 3); + } bfd_put_8 (output_bfd, 0x8d, contents + roff - 2); bfd_put_8 (output_bfd, 0x80 | reg | (reg << 3), @@ -3573,20 +3788,33 @@ direct: { if (contents[roff + 5] == 0xb8) { + if (roff < 3 + || (roff - 3 + 22) > input_section->size) + goto corrupt_input; memcpy (contents + roff - 3, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05" "\0\0\0\0\x66\x0f\x1f\x44\0", 22); largepic = 1; } else - memcpy (contents + roff - 4, - "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0", - 16); + { + if (roff < 4 + || (roff - 4 + 16) > input_section->size) + goto corrupt_input; + memcpy (contents + roff - 4, + "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0", + 16); + } } else - memcpy (contents + roff - 3, - "\x64\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0", - 15); + { + if (roff < 3 + || (roff - 3 + 15) > input_section->size) + goto corrupt_input; + memcpy (contents + roff - 3, + "\x64\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0", + 15); + } relocation = (htab->elf.sgot->output_section->vma + htab->elf.sgot->output_offset + off @@ -3606,15 +3834,22 @@ direct: { /* GDesc -> IE transition. It's originally something like: - leaq x@tlsdesc(%rip), %rax + leaq x@tlsdesc(%rip), %rax <--- LP64 mode. + rex leal x@tlsdesc(%rip), %eax <--- X32 mode. Change it to: - movq x@gottpoff(%rip), %rax # before xchg %ax,%ax. */ + # before xchg %ax,%ax in LP64 mode. + movq x@gottpoff(%rip), %rax + # before nopl (%rax) in X32 mode. + rex movl x@gottpoff(%rip), %eax + */ /* Now modify the instruction as appropriate. To - turn a leaq into a movq in the form we use it, it + turn a lea into a mov in the form we use it, it suffices to change the second byte from 0x8d to 0x8b. */ + if (roff < 2) + goto corrupt_input; bfd_put_8 (output_bfd, 0x8b, contents + roff - 2); bfd_put_32 (output_bfd, @@ -3631,13 +3866,32 @@ direct: { /* GDesc -> IE transition. It's originally: - call *(%rax) + call *(%rax) <--- LP64 mode. + call *(%eax) <--- X32 mode. Change it to: - xchg %ax, %ax. */ + xchg %ax, %ax <-- LP64 mode. + nopl (%rax) <-- X32 mode. + */ - bfd_put_8 (output_bfd, 0x66, contents + roff); - bfd_put_8 (output_bfd, 0x90, contents + roff + 1); + unsigned int prefix = 0; + if (!ABI_64_P (input_bfd)) + { + /* Check for call *x@tlsdesc(%eax). */ + if (contents[roff] == 0x67) + prefix = 1; + } + if (prefix) + { + bfd_put_8 (output_bfd, 0x0f, contents + roff); + bfd_put_8 (output_bfd, 0x1f, contents + roff + 1); + bfd_put_8 (output_bfd, 0x00, contents + roff + 2); + } + else + { + bfd_put_8 (output_bfd, 0x66, contents + roff); + bfd_put_8 (output_bfd, 0x90, contents + roff + 1); + } continue; } else @@ -3683,28 +3937,58 @@ direct: BFD_ASSERT (r_type == R_X86_64_TPOFF32); if (ABI_64_P (output_bfd)) { + if ((rel->r_offset + 5) >= input_section->size) + goto corrupt_input; if (contents[rel->r_offset + 5] == 0xb8) - memcpy (contents + rel->r_offset - 3, - "\x66\x66\x66\x66\x2e\x0f\x1f\x84\0\0\0\0\0" - "\x64\x48\x8b\x04\x25\0\0\0", 22); + { + if (rel->r_offset < 3 + || (rel->r_offset - 3 + 22) > input_section->size) + goto corrupt_input; + memcpy (contents + rel->r_offset - 3, + "\x66\x66\x66\x66\x2e\x0f\x1f\x84\0\0\0\0\0" + "\x64\x48\x8b\x04\x25\0\0\0", 22); + } else if (contents[rel->r_offset + 4] == 0xff || contents[rel->r_offset + 4] == 0x67) - memcpy (contents + rel->r_offset - 3, - "\x66\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", - 13); + { + if (rel->r_offset < 3 + || (rel->r_offset - 3 + 13) > input_section->size) + goto corrupt_input; + memcpy (contents + rel->r_offset - 3, + "\x66\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", + 13); + + } else - memcpy (contents + rel->r_offset - 3, - "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12); + { + if (rel->r_offset < 3 + || (rel->r_offset - 3 + 12) > input_section->size) + goto corrupt_input; + memcpy (contents + rel->r_offset - 3, + "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12); + } } else { + if ((rel->r_offset + 4) >= input_section->size) + goto corrupt_input; if (contents[rel->r_offset + 4] == 0xff) - memcpy (contents + rel->r_offset - 3, - "\x66\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", - 13); + { + if (rel->r_offset < 3 + || (rel->r_offset - 3 + 13) > input_section->size) + goto corrupt_input; + memcpy (contents + rel->r_offset - 3, + "\x66\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", + 13); + } else - memcpy (contents + rel->r_offset - 3, - "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", 12); + { + if (rel->r_offset < 3 + || (rel->r_offset - 3 + 12) > input_section->size) + goto corrupt_input; + memcpy (contents + rel->r_offset - 3, + "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", 12); + } } /* Skip R_X86_64_PC32, R_X86_64_PLT32, R_X86_64_GOTPCRELX and R_X86_64_PLTOFF64. */ @@ -3791,22 +4075,23 @@ direct: default: _bfd_error_handler /* xgettext:c-format */ - (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), + (_("%pB(%pA+%#" PRIx64 "): " + "unresolvable %s relocation against symbol `%s'"), input_bfd, input_section, - rel->r_offset, + (uint64_t) rel->r_offset, howto->name, h->root.root.string); return FALSE; } } -do_relocation: + do_relocation: r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, relocation, rel->r_addend); -check_relocation_error: + check_relocation_error: if (r != bfd_reloc_ok) { const char *name; @@ -3821,7 +4106,7 @@ check_relocation_error: if (name == NULL) return FALSE; if (*name == '\0') - name = bfd_section_name (input_bfd, sec); + name = bfd_section_name (sec); } if (r == bfd_reloc_overflow) @@ -3840,9 +4125,9 @@ check_relocation_error: { _bfd_error_handler /* xgettext:c-format */ - (_("%B(%A+%#Lx): reloc against `%s': error %d"), + (_("%pB(%pA+%#" PRIx64 "): reloc against `%s': error %d"), input_bfd, input_section, - rel->r_offset, name, (int) r); + (uint64_t) rel->r_offset, name, (int) r); return FALSE; } } @@ -3987,7 +4272,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, /* Check PC-relative offset overflow in PLT entry. */ if ((plt_got_pcrel_offset + 0x80000000) > 0xffffffff) /* xgettext:c-format */ - info->callbacks->einfo (_("%F%B: PC-relative offset overflow in PLT entry for `%s'\n"), + info->callbacks->einfo (_("%F%pB: PC-relative offset overflow in PLT entry for `%s'\n"), output_bfd, h->root.root.string); bfd_put_32 (output_bfd, plt_got_pcrel_offset, @@ -4013,7 +4298,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, + got_offset); if (PLT_LOCAL_IFUNC_P (info, h)) { - info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"), + info->callbacks->minfo (_("Local IFUNC function `%s' in %pB\n"), h->root.root.string, h->root.u.def.section->owner); @@ -4050,7 +4335,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, will overflow first. */ if (plt0_offset > 0x80000000) /* xgettext:c-format */ - info->callbacks->einfo (_("%F%B: branch displacement overflow in PLT entry for `%s'\n"), + info->callbacks->einfo (_("%F%pB: branch displacement overflow in PLT entry for `%s'\n"), output_bfd, h->root.root.string); bfd_put_32 (output_bfd, - plt0_offset, (plt->contents + h->plt.offset @@ -4103,7 +4388,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, if ((got_after_plt && got_pcrel_offset < 0) || (!got_after_plt && got_pcrel_offset > 0)) /* xgettext:c-format */ - info->callbacks->einfo (_("%F%B: PC-relative offset overflow in GOT PLT entry for `%s'\n"), + info->callbacks->einfo (_("%F%pB: PC-relative offset overflow in GOT PLT entry for `%s'\n"), output_bfd, h->root.root.string); bfd_put_32 (output_bfd, got_pcrel_offset, @@ -4129,6 +4414,8 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, sym->st_value = 0; } + _bfd_x86_elf_link_fixup_ifunc_symbol (info, htab, h, sym); + /* Don't generate dynamic GOT relocation against undefined weak symbol in executable. */ if (h->got.offset != (bfd_vma) -1 @@ -4167,7 +4454,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, } if (SYMBOL_REFERENCES_LOCAL_P (info, h)) { - info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"), + info->callbacks->minfo (_("Local IFUNC function `%s' in %pB\n"), h->root.root.string, h->root.u.def.section->owner); @@ -4216,7 +4503,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, else if (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL_P (info, h)) { - if (!(h->def_regular || ELF_COMMON_DEF_P (h))) + if (!SYMBOL_DEFINED_NON_SHARED_P (h)) return FALSE; BFD_ASSERT((h->got.offset & 1) != 0); rela.r_info = htab->r_info (0, R_X86_64_RELATIVE); @@ -4227,7 +4514,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, else { BFD_ASSERT((h->got.offset & 1) == 0); -do_glob_dat: + do_glob_dat: bfd_put_64 (output_bfd, (bfd_vma) 0, htab->elf.sgot->contents + h->got.offset); rela.r_info = htab->r_info (h->dynindx, R_X86_64_GLOB_DAT); @@ -4401,11 +4688,12 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, htab->elf.sgot->contents + htab->tlsdesc_got); memcpy (htab->elf.splt->contents + htab->tlsdesc_plt, - htab->lazy_plt->plt0_entry, - htab->lazy_plt->plt0_entry_size); + htab->lazy_plt->plt_tlsdesc_entry, + htab->lazy_plt->plt_tlsdesc_entry_size); - /* Add offset for pushq GOT+8(%rip), since the - instruction uses 6 bytes subtract this value. */ + /* Add offset for pushq GOT+8(%rip), since ENDBR64 uses 4 + bytes and the instruction uses 6 bytes, subtract these + values. */ bfd_put_32 (output_bfd, (htab->elf.sgotplt->output_section->vma + htab->elf.sgotplt->output_offset @@ -4413,14 +4701,13 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, - htab->elf.splt->output_section->vma - htab->elf.splt->output_offset - htab->tlsdesc_plt - - 6), + - htab->lazy_plt->plt_tlsdesc_got1_insn_end), (htab->elf.splt->contents + htab->tlsdesc_plt - + htab->lazy_plt->plt0_got1_offset)); - /* Add offset for the PC-relative instruction accessing - GOT+TDG, where TDG stands for htab->tlsdesc_got, - subtracting the offset to the end of that - instruction. */ + + htab->lazy_plt->plt_tlsdesc_got1_offset)); + /* Add offset for indirect branch via GOT+TDG, where TDG + stands for htab->tlsdesc_got, subtracting the offset + to the end of that instruction. */ bfd_put_32 (output_bfd, (htab->elf.sgot->output_section->vma + htab->elf.sgot->output_offset @@ -4428,10 +4715,10 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, - htab->elf.splt->output_section->vma - htab->elf.splt->output_offset - htab->tlsdesc_plt - - htab->lazy_plt->plt0_got2_insn_end), + - htab->lazy_plt->plt_tlsdesc_got2_insn_end), (htab->elf.splt->contents + htab->tlsdesc_plt - + htab->lazy_plt->plt0_got2_offset)); + + htab->lazy_plt->plt_tlsdesc_got2_offset)); } } @@ -4872,7 +5159,13 @@ elf_x86_64_link_setup_gnu_properties (struct bfd_link_info *info) if (get_elf_x86_backend_data (info->output_bfd)->target_os != is_nacl) { - if (info->bndplt) + const struct elf_backend_data *bed + = get_elf_backend_data (info->output_bfd); + struct elf_x86_link_hash_table *htab + = elf_x86_hash_table (info, bed->target_id); + if (!htab) + abort (); + if (htab->params->bndplt) { init_table.lazy_plt = &elf_x86_64_lazy_bnd_plt; init_table.non_lazy_plt = &elf_x86_64_non_lazy_bnd_plt; @@ -4933,7 +5226,11 @@ elf_x86_64_special_sections[]= #define ELF_ARCH bfd_arch_i386 #define ELF_TARGET_ID X86_64_ELF_DATA #define ELF_MACHINE_CODE EM_X86_64 -#define ELF_MAXPAGESIZE 0x200000 +#if DEFAULT_LD_Z_SEPARATE_CODE +# define ELF_MAXPAGESIZE 0x1000 +#else +# define ELF_MAXPAGESIZE 0x200000 +#endif #define ELF_MINPAGESIZE 0x1000 #define ELF_COMMONPAGESIZE 0x1000 @@ -4999,6 +5296,9 @@ elf_x86_64_special_sections[]= #define elf_backend_hide_symbol \ _bfd_x86_elf_hide_symbol +#undef elf64_bed +#define elf64_bed elf64_x86_64_bed + #include "elf64-target.h" /* CloudABI support. */ @@ -5213,6 +5513,12 @@ static const struct elf_x86_lazy_plt_layout elf_x86_64_nacl_plt = NACL_PLT_ENTRY_SIZE, /* plt0_entry_size */ elf_x86_64_nacl_plt_entry, /* plt_entry */ NACL_PLT_ENTRY_SIZE, /* plt_entry_size */ + elf_x86_64_nacl_plt0_entry, /* plt_tlsdesc_entry */ + NACL_PLT_ENTRY_SIZE, /* plt_tlsdesc_entry_size */ + 2, /* plt_tlsdesc_got1_offset */ + 9, /* plt_tlsdesc_got2_offset */ + 6, /* plt_tlsdesc_got1_insn_end */ + 13, /* plt_tlsdesc_got2_insn_end */ 2, /* plt0_got1_offset */ 9, /* plt0_got2_offset */ 13, /* plt0_got2_insn_end */ @@ -5240,8 +5546,8 @@ static const struct elf_x86_backend_data elf_x86_64_nacl_arch_bed = #define elf_backend_object_p elf64_x86_64_nacl_elf_object_p #undef elf_backend_modify_segment_map #define elf_backend_modify_segment_map nacl_modify_segment_map -#undef elf_backend_modify_program_headers -#define elf_backend_modify_program_headers nacl_modify_program_headers +#undef elf_backend_modify_headers +#define elf_backend_modify_headers nacl_modify_headers #undef elf_backend_final_write_processing #define elf_backend_final_write_processing nacl_final_write_processing @@ -5283,6 +5589,9 @@ elf32_x86_64_nacl_elf_object_p (bfd *abfd) #define elf_backend_size_info \ _bfd_elf32_size_info +#undef elf32_bed +#define elf32_bed elf32_x86_64_bed + #include "elf32-target.h" /* Restore defaults. */ @@ -5291,7 +5600,7 @@ elf32_x86_64_nacl_elf_object_p (bfd *abfd) #undef elf_backend_bfd_from_remote_memory #undef elf_backend_size_info #undef elf_backend_modify_segment_map -#undef elf_backend_modify_program_headers +#undef elf_backend_modify_headers #undef elf_backend_final_write_processing /* Intel L1OM support. */ @@ -5326,7 +5635,11 @@ elf64_l1om_elf_object_p (bfd *abfd) #undef ELF_MAXPAGESIZE #undef ELF_MINPAGESIZE #undef ELF_COMMONPAGESIZE -#define ELF_MAXPAGESIZE 0x200000 +#if DEFAULT_LD_Z_SEPARATE_CODE +# define ELF_MAXPAGESIZE 0x1000 +#else +# define ELF_MAXPAGESIZE 0x200000 +#endif #define ELF_MINPAGESIZE 0x1000 #define ELF_COMMONPAGESIZE 0x1000 #undef elf_backend_plt_alignment