X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf64-x86-64.c;h=183c8083464efee694695f6ed5d9695255326bb4;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-2020-04-01;hp=2f6923927f998d8d03d31495bab82198de4f7b15;hpb=9a7f0679fd3b9815b8eb938bfdad3934b8435419;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 2f6923927f..183c808346 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-2019 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) \ @@ -1223,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 @@ -1233,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) @@ -1244,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; @@ -1494,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; @@ -1501,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; @@ -1544,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) { @@ -1554,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) @@ -1571,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) @@ -1647,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)". */ @@ -1713,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 @@ -1772,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) @@ -1864,7 +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 do_check_pic; + bfd_boolean no_dynreloc; r_symndx = htab->r_sym (rel->r_info); r_type = ELF32_R_TYPE (rel->r_info); @@ -1951,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; @@ -1973,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, @@ -2019,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) @@ -2140,13 +2197,6 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, size_reloc = TRUE; goto do_size; - case R_X86_64_PC8: - case R_X86_64_PC16: - case R_X86_64_PC32: - case R_X86_64_PC32_BND: - do_check_pic = TRUE; - goto check_pic; - case R_X86_64_32: if (!ABI_64_P (abfd)) goto pointer; @@ -2170,11 +2220,13 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, &x86_64_elf_howto_table[r_type]); /* Fall through. */ + case R_X86_64_PC8: + case R_X86_64_PC16: + case R_X86_64_PC32: + case R_X86_64_PC32_BND: case R_X86_64_PC64: case R_X86_64_64: -pointer: - do_check_pic = FALSE; -check_pic: + pointer: if (eh != NULL && (sec->flags & SEC_CODE) != 0) eh->zero_undefweak |= 0x2; /* We are called after all symbols have been resolved. Only @@ -2238,73 +2290,11 @@ check_pic: } } - if (do_check_pic) - { - /* Don't complain about -fPIC if the symbol is undefined - when building executable unless it is unresolved weak - symbol, references a dynamic definition in PIE or - -z nocopyreloc is used. */ - bfd_boolean 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 ((sec->flags & SEC_ALLOC) != 0 - && (sec->flags & SEC_READONLY) != 0 - && h != NULL - && ((bfd_link_executable (info) - && ((h->root.type == bfd_link_hash_undefweak - && (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; - if (SYMBOL_REFERENCES_LOCAL_P (info, h)) - { - /* Symbol is referenced locally. Make sure it is - defined locally. */ - fail = !SYMBOL_DEFINED_NON_SHARED_P (h); - } - else if (bfd_link_pie (info)) - { - /* 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, abfd, sec, h, - symtab_hdr, isym, - &x86_64_elf_howto_table[r_type]); - } - } - size_reloc = FALSE; -do_size: - if (NEED_DYNAMIC_RELOCATION_P (info, TRUE, 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; @@ -2325,7 +2315,7 @@ do_size: /* If this is a global symbol, we count the number of relocations we need for this symbol. */ if (h != NULL) - head = &eh->dyn_relocs; + head = &h->dyn_relocs; else { /* Track dynamic relocs needed for local syms too. @@ -2352,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)); @@ -2409,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; @@ -2501,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 @@ -2735,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 @@ -2759,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) @@ -2845,7 +2836,7 @@ do_ifunc_pointer: } } -skip_ifunc: + skip_ifunc: resolved_to_zero = (eh != NULL && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh)); @@ -2937,7 +2928,14 @@ skip_ifunc: 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; } } @@ -3104,7 +3102,7 @@ skip_ifunc: break; } -use_plt: + use_plt: if (h->plt.offset != (bfd_vma) -1) { if (htab->plt_second != NULL) @@ -3141,14 +3139,73 @@ use_plt: case R_X86_64_PC16: 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, + 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 + && (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; + if (SYMBOL_REFERENCES_LOCAL_P (info, h)) + { + /* Symbol is referenced locally. Make sure it is + defined locally. */ + fail = !SYMBOL_DEFINED_NON_SHARED_P (h); + } + else if (bfd_link_pie (info)) + { + /* 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. */ - if (h != NULL - && (input_section->flags & SEC_CODE) == 0 - && bfd_link_pie (info) - && h->type == STT_FUNC - && !h->def_regular - && h->def_dynamic) + 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. */ @@ -3160,7 +3217,7 @@ use_plt: /* 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; @@ -3173,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)) { @@ -3371,7 +3428,7 @@ direct: if (roff < 3 || (roff - 3 + 22) > input_section->size) { -corrupt_input: + corrupt_input: info->callbacks->einfo (_("%F%P: corrupt input: %pB\n"), input_bfd); @@ -3414,10 +3471,13 @@ corrupt_input: { /* 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; @@ -3425,7 +3485,8 @@ corrupt_input: 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), @@ -3439,11 +3500,30 @@ corrupt_input: { /* 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) @@ -3754,13 +3834,18 @@ corrupt_input: { /* 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) @@ -3781,13 +3866,32 @@ corrupt_input: { /* 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 @@ -3982,12 +4086,12 @@ corrupt_input: } } -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; @@ -4002,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) @@ -4410,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); @@ -5442,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 @@ -5496,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. */