aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2023-06-09 13:50:22 -0700
committerH.J. Lu <hjl.tools@gmail.com>2023-12-28 08:47:17 -0800
commita533c8df598b5ef99c54a13e2b137c98b34b043c (patch)
treecb019f462896604b2b48bb1f40dfe01bc0437051 /bfd
parent4a54cb06585f568031dfd291d0fe45979ad75e98 (diff)
downloadgdb-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.h2
-rw-r--r--bfd/elf64-x86-64.c125
-rw-r--r--bfd/libbfd.h2
-rw-r--r--bfd/reloc.c4
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.