diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2023-06-09 13:50:22 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2023-12-28 08:47:17 -0800 |
commit | a533c8df598b5ef99c54a13e2b137c98b34b043c (patch) | |
tree | cb019f462896604b2b48bb1f40dfe01bc0437051 /bfd | |
parent | 4a54cb06585f568031dfd291d0fe45979ad75e98 (diff) | |
download | gdb-a533c8df598b5ef99c54a13e2b137c98b34b043c.zip gdb-a533c8df598b5ef99c54a13e2b137c98b34b043c.tar.gz gdb-a533c8df598b5ef99c54a13e2b137c98b34b043c.tar.bz2 |
x86-64: Add R_X86_64_CODE_4_GOTTPOFF/R_X86_64_CODE_4_GOTPC32_TLSDESC
For
add name@gottpoff(%rip), %reg
mov name@gottpoff(%rip), %reg
add
# define R_X86_64_CODE_4_GOTTPOFF 44
and for
lea name@tlsdesc(%rip), %reg
add
# define R_X86_64_CODE_4_GOTPC32_TLSDESC 45
if the instruction starts at 4 bytes before the relocation offset.
They are similar to R_X86_64_GOTTPOFF and R_X86_64_GOTPC32_TLSDESC,
respectively. Linker can covert GOTTPOFF to
add $name@tpoff, %reg
mov $name@tpoff, %reg
and GOTPC32_TLSDESC to
mov $name@tpoff, %reg
mov name@gottpoff(%rip), %reg
if the instruction is encoded with the REX2 prefix when possible.
bfd/
* elf64-x86-64.c (x86_64_elf_howto_table): Add
R_X86_64_CODE_4_GOTTPOFF and R_X86_64_CODE_4_GOTPC32_TLSDESC.
(R_X86_64_standard): Updated.
(x86_64_reloc_map): Add BFD_RELOC_X86_64_CODE_4_GOTTPOFF
and BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC.
(elf_x86_64_check_tls_transition): Handle R_X86_64_CODE_4_GOTTPOFF
and R_X86_64_CODE_4_GOTPC32_TLSDESC.
(elf_x86_64_tls_transition): Likewise.
(elf_x86_64_scan_relocs): Likewise.
(elf_x86_64_relocate_section): Likewise.
* reloc.c (bfd_reloc_code_real): Add
BFD_RELOC_X86_64_CODE_4_GOTTPOFF and
BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC.
* bfd-in2.h: Regenerated.
* libbfd.h: Likewise.
gas/
* config/tc-i386.c (tc_i386_fix_adjustable): Handle
BFD_RELOC_X86_64_CODE_4_GOTTPOFF and
BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC.
(md_assemble): Handle BFD_RELOC_X86_64_CODE_4_GOTTPOFF.
(output_insn): Don't add empty REX prefix with REX2 prefix.
(output_disp): Handle BFD_RELOC_X86_64_CODE_4_GOTTPOFF and
BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC.
(md_apply_fix): Likewise.
(i386_validate_fix): Generate BFD_RELOC_X86_64_CODE_4_GOTTPOFF or
BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC if ixp->fx_tcbit3 is set.
(tc_gen_reloc): Handle BFD_RELOC_X86_64_CODE_4_GOTTPOFF and
BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC.
* testsuite/gas/i386/x86-64-gottpoff.d: New file.
* testsuite/gas/i386/x86-64-gottpoff.s: Likewise.
* testsuite/gas/i386/x86-64-tlsdesc.d: Likewise.
* testsuite/gas/i386/x86-64-tlsdesc.s: Likewise.
include/
* elf/x86-64.h (elf_x86_64_reloc_type): Add
R_X86_64_CODE_4_GOTTPOFF and R_X86_64_CODE_4_GOTPC32_TLSDESC
ld/
* testsuite/ld-x86-64/tlsbindesc.d: Updated.
* testsuite/ld-x86-64/tlsbindesc.rd: Likewise.
* testsuite/ld-x86-64/tlsbindesc.s: Add R_X86_64_CODE_4_GOTTPOFF
and R_X86_64_CODE_4_GOTPC32_TLSDESC tests.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/bfd-in2.h | 2 | ||||
-rw-r--r-- | bfd/elf64-x86-64.c | 125 | ||||
-rw-r--r-- | bfd/libbfd.h | 2 | ||||
-rw-r--r-- | bfd/reloc.c | 4 |
4 files changed, 130 insertions, 3 deletions
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 96709da..550704a 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -3892,6 +3892,8 @@ enum bfd_reloc_code_real BFD_RELOC_X86_64_GOTPCRELX, BFD_RELOC_X86_64_REX_GOTPCRELX, BFD_RELOC_X86_64_CODE_4_GOTPCRELX, + BFD_RELOC_X86_64_CODE_4_GOTTPOFF, + BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC, /* ns32k relocations. */ BFD_RELOC_NS32K_IMM_8, diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index a2d1b6f..3406bc8 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -173,12 +173,18 @@ static reloc_howto_type x86_64_elf_howto_table[] = HOWTO(R_X86_64_CODE_4_GOTPCRELX, 0, 4, 32, true, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_CODE_4_GOTPCRELX", false, 0, 0xffffffff, true), + HOWTO(R_X86_64_CODE_4_GOTTPOFF, 0, 4, 32, true, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_CODE_4_GOTTPOFF", false, 0, 0xffffffff, + true), + HOWTO(R_X86_64_CODE_4_GOTPC32_TLSDESC, 0, 4, 32, true, 0, + complain_overflow_bitfield, bfd_elf_generic_reloc, + "R_X86_64_CODE_4_GOTPC32_TLSDESC", false, 0, 0xffffffff, true), /* We have a gap in the reloc numbers here. R_X86_64_standard counts the number up to this point, and R_X86_64_vt_offset is the value to subtract from a reloc type of R_X86_64_GNU_VT* to form an index into this table. */ -#define R_X86_64_standard (R_X86_64_CODE_4_GOTPCRELX + 1) +#define R_X86_64_standard (R_X86_64_CODE_4_GOTPC32_TLSDESC + 1) #define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard) /* GNU extension to record C++ vtable hierarchy. */ @@ -248,6 +254,8 @@ static const struct elf_reloc_map x86_64_reloc_map[] = { BFD_RELOC_X86_64_GOTPCRELX, R_X86_64_GOTPCRELX, }, { BFD_RELOC_X86_64_REX_GOTPCRELX, R_X86_64_REX_GOTPCRELX, }, { BFD_RELOC_X86_64_CODE_4_GOTPCRELX, R_X86_64_CODE_4_GOTPCRELX, }, + { BFD_RELOC_X86_64_CODE_4_GOTTPOFF, R_X86_64_CODE_4_GOTTPOFF, }, + { BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC, R_X86_64_CODE_4_GOTPC32_TLSDESC, }, { BFD_RELOC_VTABLE_INHERIT, R_X86_64_GNU_VTINHERIT, }, { BFD_RELOC_VTABLE_ENTRY, R_X86_64_GNU_VTENTRY, }, }; @@ -1262,6 +1270,19 @@ elf_x86_64_check_tls_transition (bfd *abfd, return (r_type == R_X86_64_PC32 || r_type == R_X86_64_PLT32); } + case R_X86_64_CODE_4_GOTTPOFF: + /* Check transition from IE access model: + mov foo@gottpoff(%rip), %reg + add foo@gottpoff(%rip), %reg + where reg is one of r16 to r31. */ + + if (offset < 4 + || (offset + 4) > sec->size + || contents[offset - 4] != 0xd5) + return false; + + goto check_gottpoff; + case R_X86_64_GOTTPOFF: /* Check transition from IE access model: mov foo@gottpoff(%rip), %reg @@ -1288,6 +1309,7 @@ elf_x86_64_check_tls_transition (bfd *abfd, return false; } + check_gottpoff: val = bfd_get_8 (abfd, contents + offset - 2); if (val != 0x8b && val != 0x03) return false; @@ -1295,6 +1317,18 @@ elf_x86_64_check_tls_transition (bfd *abfd, val = bfd_get_8 (abfd, contents + offset - 1); return (val & 0xc7) == 5; + case R_X86_64_CODE_4_GOTPC32_TLSDESC: + /* Check transition from GDesc access model: + lea x@tlsdesc(%rip), %reg + where reg is one of r16 to r31. */ + + if (offset < 4 + || (offset + 4) > sec->size + || contents[offset - 4] != 0xd5) + return false; + + goto check_tlsdesc; + case R_X86_64_GOTPC32_TLSDESC: /* Check transition from GDesc access model: leaq x@tlsdesc(%rip), %rax <--- LP64 mode. @@ -1312,6 +1346,7 @@ elf_x86_64_check_tls_transition (bfd *abfd, if (val != 0x48 && (ABI_64_P (abfd) || val != 0x40)) return false; + check_tlsdesc: if (bfd_get_8 (abfd, contents + offset - 2) != 0x8d) return false; @@ -1378,8 +1413,10 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd, { case R_X86_64_TLSGD: case R_X86_64_GOTPC32_TLSDESC: + case R_X86_64_CODE_4_GOTPC32_TLSDESC: case R_X86_64_TLSDESC_CALL: case R_X86_64_GOTTPOFF: + case R_X86_64_CODE_4_GOTTPOFF: if (bfd_link_executable (info)) { if (h == NULL) @@ -1399,6 +1436,7 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd, if (to_type == R_X86_64_TLSGD || to_type == R_X86_64_GOTPC32_TLSDESC + || to_type == R_X86_64_CODE_4_GOTPC32_TLSDESC || to_type == R_X86_64_TLSDESC_CALL) { if (tls_type == GOT_TLS_IE) @@ -1424,7 +1462,9 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd, } /* Return TRUE if there is no transition. */ - if (from_type == to_type) + if (from_type == to_type + || (from_type == R_X86_64_CODE_4_GOTTPOFF + && to_type == R_X86_64_GOTTPOFF)) return true; /* Check if the transition can be performed. */ @@ -2132,6 +2172,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info, break; case R_X86_64_GOTTPOFF: + case R_X86_64_CODE_4_GOTTPOFF: if (!bfd_link_executable (info)) info->flags |= DF_STATIC_TLS; /* Fall through */ @@ -2146,6 +2187,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info, case R_X86_64_GOTPCREL64: case R_X86_64_GOTPLT64: case R_X86_64_GOTPC32_TLSDESC: + case R_X86_64_CODE_4_GOTPC32_TLSDESC: case R_X86_64_TLSDESC_CALL: /* This symbol requires a global offset table entry. */ { @@ -2167,9 +2209,11 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info, tls_type = GOT_TLS_GD; break; case R_X86_64_GOTTPOFF: + case R_X86_64_CODE_4_GOTTPOFF: tls_type = GOT_TLS_IE; break; case R_X86_64_GOTPC32_TLSDESC: + case R_X86_64_CODE_4_GOTPC32_TLSDESC: case R_X86_64_TLSDESC_CALL: tls_type = GOT_TLS_GDESC; break; @@ -3518,8 +3562,10 @@ elf_x86_64_relocate_section (bfd *output_bfd, case R_X86_64_TLSGD: case R_X86_64_GOTPC32_TLSDESC: + case R_X86_64_CODE_4_GOTPC32_TLSDESC: case R_X86_64_TLSDESC_CALL: case R_X86_64_GOTTPOFF: + case R_X86_64_CODE_4_GOTTPOFF: tls_type = GOT_UNKNOWN; if (h == NULL && local_got_offsets) tls_type = elf_x86_local_got_tls_type (input_bfd) [r_symndx]; @@ -3660,6 +3706,37 @@ elf_x86_64_relocate_section (bfd *output_bfd, contents + roff); continue; } + else if (r_type == R_X86_64_CODE_4_GOTPC32_TLSDESC) + { + /* GDesc -> LE transition. + It's originally something like: + lea x@tlsdesc(%rip), %reg + + Change it to: + mov $x@tpoff, %reg + where reg is one of r16 to r31. */ + + unsigned int val, rex2; + unsigned int rex2_mask = REX_R | REX_R << 4; + + if (roff < 4) + goto corrupt_input; + rex2 = bfd_get_8 (input_bfd, contents + roff - 3); + val = bfd_get_8 (input_bfd, contents + roff - 1); + /* Move the R bits to the B bits in REX2 payload + byte. */ + bfd_put_8 (output_bfd, + ((rex2 & ~rex2_mask) + | (rex2 & rex2_mask) >> 2), + contents + roff - 3); + bfd_put_8 (output_bfd, 0xc7, contents + roff - 2); + bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7), + contents + roff - 1); + bfd_put_32 (output_bfd, + elf_x86_64_tpoff (info, relocation), + contents + roff); + continue; + } else if (r_type == R_X86_64_TLSDESC_CALL) { /* GDesc -> LE transition. @@ -3799,6 +3876,46 @@ elf_x86_64_relocate_section (bfd *output_bfd, contents + roff); continue; } + else if (r_type == R_X86_64_CODE_4_GOTTPOFF) + { + /* IE->LE transition: + Originally it can be one of: + mov foo@gottpoff(%rip), %reg + add foo@gottpoff(%rip), %reg + We change it into: + mov $foo@tpoff, %reg + add $foo@tpoff, %reg + where reg is one of r16 to r31. */ + + unsigned int rex2, type, reg; + unsigned int rex2_mask = REX_R | REX_R << 4; + + if (roff < 4) + goto corrupt_input; + + rex2 = bfd_get_8 (input_bfd, contents + roff - 3); + type = bfd_get_8 (input_bfd, contents + roff - 2); + reg = bfd_get_8 (input_bfd, contents + roff - 1); + reg >>= 3; + /* Move the R bits to the B bits in REX2 payload + byte. */ + if (type == 0x8b) + type = 0xc7; + else + type = 0x81; + bfd_put_8 (output_bfd, + ((rex2 & ~rex2_mask) + | (rex2 & rex2_mask) >> 2), + contents + roff - 3); + bfd_put_8 (output_bfd, type, + contents + roff - 2); + bfd_put_8 (output_bfd, 0xc0 | reg, + contents + roff - 1); + bfd_put_32 (output_bfd, + elf_x86_64_tpoff (info, relocation), + contents + roff); + continue; + } else BFD_ASSERT (false); } @@ -3905,6 +4022,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, if (r_type_tls == r_type) { if (r_type == R_X86_64_GOTPC32_TLSDESC + || r_type == R_X86_64_CODE_4_GOTPC32_TLSDESC || r_type == R_X86_64_TLSDESC_CALL) relocation = htab->elf.sgotplt->output_section->vma + htab->elf.sgotplt->output_offset @@ -4000,7 +4118,8 @@ elf_x86_64_relocate_section (bfd *output_bfd, wrel++; continue; } - else if (r_type == R_X86_64_GOTPC32_TLSDESC) + else if (r_type == R_X86_64_GOTPC32_TLSDESC + || r_type == R_X86_64_CODE_4_GOTPC32_TLSDESC) { /* GDesc -> IE transition. It's originally something like: diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 8873faf..196e7e5 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1461,6 +1461,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_X86_64_GOTPCRELX", "BFD_RELOC_X86_64_REX_GOTPCRELX", "BFD_RELOC_X86_64_CODE_4_GOTPCRELX", + "BFD_RELOC_X86_64_CODE_4_GOTTPOFF", + "BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC", "BFD_RELOC_NS32K_IMM_8", "BFD_RELOC_NS32K_IMM_16", "BFD_RELOC_NS32K_IMM_32", diff --git a/bfd/reloc.c b/bfd/reloc.c index 56d852d..30852b1 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -2477,6 +2477,10 @@ ENUMX BFD_RELOC_X86_64_REX_GOTPCRELX ENUMX BFD_RELOC_X86_64_CODE_4_GOTPCRELX +ENUMX + BFD_RELOC_X86_64_CODE_4_GOTTPOFF +ENUMX + BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC ENUMDOC x86-64/elf relocations. |