aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2023-06-08 10:01:03 -0700
committerH.J. Lu <hjl.tools@gmail.com>2023-12-28 08:47:17 -0800
commit3d5a60de52556f6a53d71d7e607c6696450ae3e4 (patch)
treecf1a1b08ee6c9814716b5f6e5953cf9d6686f47b /bfd
parent5e2f0c9a5f3d467a341a0c3d579d9c6ee6daa4d1 (diff)
downloadgdb-3d5a60de52556f6a53d71d7e607c6696450ae3e4.zip
gdb-3d5a60de52556f6a53d71d7e607c6696450ae3e4.tar.gz
gdb-3d5a60de52556f6a53d71d7e607c6696450ae3e4.tar.bz2
x86-64: Add R_X86_64_CODE_4_GOTPCRELX
For mov name@GOTPCREL(%rip), %reg test %reg, name@GOTPCREL(%rip) binop name@GOTPCREL(%rip), %reg where binop is one of adc, add, add, cmp, or, sbb, sub, xor instructions, add # define R_X86_64_CODE_4_GOTPCRELX 43 if the instruction starts at 4 bytes before the relocation offset. It similar to R_X86_64_GOTPCRELX. Linker can treat R_X86_64_CODE_4_GOTPCRELX as R_X86_64_GOTPCREL or convert the above instructions to lea name(%rip), %reg mov $name, %reg test $name, %reg binop $name, %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_GOTPCRELX. (R_X86_64_standard): Updated. (x86_64_reloc_map): Add BFD_RELOC_X86_64_CODE_4_GOTPCRELX. (elf_x86_64_convert_load_reloc): Handle R_X86_64_CODE_4_GOTPCRELX. (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_GOTPCRELX. * bfd-in2.h: Regenerated. * libbfd.h: Likewise. gas/ * write.h (fix): Add fx_tcbit3. Change fx_unused to 1 bit. * config/tc-i386.c (tc_i386_fix_adjustable): Handle BFD_RELOC_X86_64_CODE_4_GOTPCRELX. (tc_gen_reloc): Likewise. (output_disp): Set fixP->fx_tcbit3 for REX2 prefix. (i386_validate_fix): Generate BFD_RELOC_X86_64_CODE_4_GOTPCRELX if fixp->fx_tcbit3 is set. * config/tc-i386.h (TC_FORCE_RELOCATION_LOCAL): Add BFD_RELOC_X86_64_CODE_4_GOTPCRELX. (TC_FORCE_RELOCATION_ABS): Likewise. * testsuite/gas/i386/x86-64-gotpcrel.s: Add tests for R_X86_64_CODE_4_GOTPCRELX. * testsuite/gas/i386/x86-64-localpic.s: Likewise. * testsuite/gas/i386/x86-64-gotpcrel.d: Updated. * testsuite/gas/i386/x86-64-localpic.d: Likewise. * testsuite/gas/i386/ilp32/x86-64-localpic.d: Likewise. include/ * elf/x86-64.h (elf_x86_64_reloc_type): Add R_X86_64_CODE_4_GOTPCRELX. ld/ * testsuite/ld-x86-64/apx-load1.s: New file. * testsuite/ld-x86-64/apx-load1a.d: Likewise. * testsuite/ld-x86-64/apx-load1b.d: Likewise. * testsuite/ld-x86-64/apx-load1c.d: Likewise. * testsuite/ld-x86-64/apx-load1d.d: Likewise. * testsuite/ld-x86-64/x86-64.exp: Run apx-load1a, apx-load1b, apx-load1c and apx-load1d.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/bfd-in2.h1
-rw-r--r--bfd/elf64-x86-64.c73
-rw-r--r--bfd/libbfd.h1
-rw-r--r--bfd/reloc.c2
4 files changed, 59 insertions, 18 deletions
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 7828459..96709da 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3891,6 +3891,7 @@ enum bfd_reloc_code_real
BFD_RELOC_X86_64_PLT32_BND,
BFD_RELOC_X86_64_GOTPCRELX,
BFD_RELOC_X86_64_REX_GOTPCRELX,
+ BFD_RELOC_X86_64_CODE_4_GOTPCRELX,
/* ns32k relocations. */
BFD_RELOC_NS32K_IMM_8,
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 3b7a8ae..a2d1b6f 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -170,12 +170,15 @@ static reloc_howto_type x86_64_elf_howto_table[] =
HOWTO(R_X86_64_REX_GOTPCRELX, 0, 4, 32, true, 0, complain_overflow_signed,
bfd_elf_generic_reloc, "R_X86_64_REX_GOTPCRELX", false, 0, 0xffffffff,
true),
+ 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),
/* 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_REX_GOTPCRELX + 1)
+#define R_X86_64_standard (R_X86_64_CODE_4_GOTPCRELX + 1)
#define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard)
/* GNU extension to record C++ vtable hierarchy. */
@@ -244,6 +247,7 @@ static const struct elf_reloc_map x86_64_reloc_map[] =
{ BFD_RELOC_X86_64_PLT32_BND, R_X86_64_PLT32_BND, },
{ 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_VTABLE_INHERIT, R_X86_64_GNU_VTINHERIT, },
{ BFD_RELOC_VTABLE_ENTRY, R_X86_64_GNU_VTENTRY, },
};
@@ -1586,7 +1590,8 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
bfd_vma roff = irel->r_offset;
bfd_vma abs_relocation;
- if (roff < (r_type == R_X86_64_REX_GOTPCRELX ? 3 : 2))
+ if (roff < (r_type == R_X86_64_CODE_4_GOTPCRELX
+ ? 4 : (r_type == R_X86_64_REX_GOTPCRELX ? 3 : 2)))
return true;
raddend = irel->r_addend;
@@ -1597,8 +1602,18 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
htab = elf_x86_hash_table (link_info, X86_64_ELF_DATA);
is_pic = bfd_link_pic (link_info);
- relocx = (r_type == R_X86_64_GOTPCRELX
- || r_type == R_X86_64_REX_GOTPCRELX);
+ if (r_type == R_X86_64_CODE_4_GOTPCRELX)
+ {
+ /* Skip if this isn't a REX2 instruction. */
+ opcode = bfd_get_8 (abfd, contents + roff - 4);
+ if (opcode != 0xd5)
+ return true;
+
+ relocx = true;
+ }
+ else
+ relocx = (r_type == R_X86_64_GOTPCRELX
+ || r_type == R_X86_64_REX_GOTPCRELX);
/* TRUE if --no-relax is used. */
no_overflow = link_info->disable_target_specific_optimizations > 1;
@@ -1610,9 +1625,9 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
/* Convert mov to lea since it has been done for a while. */
if (opcode != 0x8b)
{
- /* Only convert R_X86_64_GOTPCRELX and R_X86_64_REX_GOTPCRELX
- for call, jmp or one of adc, add, and, cmp, or, sbb, sub,
- test, xor instructions. */
+ /* Only convert R_X86_64_GOTPCRELX, R_X86_64_REX_GOTPCRELX
+ and R_X86_64_CODE_4_GOTPCRELX for call, jmp or one of adc,
+ add, and, cmp, or, sbb, sub, test, xor instructions. */
if (!relocx)
return true;
}
@@ -1797,13 +1812,22 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
}
else
{
- unsigned int rex;
+ unsigned int rex = 0;
unsigned int rex_mask = REX_R;
+ unsigned int rex2 = 0;
+ unsigned int rex2_mask = REX_R | REX_R << 4;
+ bool rex_w = false;
- if (r_type == R_X86_64_REX_GOTPCRELX)
- rex = bfd_get_8 (abfd, contents + roff - 3);
- else
- rex = 0;
+ if (r_type == R_X86_64_CODE_4_GOTPCRELX)
+ {
+ rex2 = bfd_get_8 (abfd, contents + roff - 3);
+ rex_w = (rex2 & REX_W) != 0;
+ }
+ else if (r_type == R_X86_64_REX_GOTPCRELX)
+ {
+ rex = bfd_get_8 (abfd, contents + roff - 3);
+ rex_w = (rex & REX_W) != 0;
+ }
if (opcode == 0x8b)
{
@@ -1824,8 +1848,7 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
opcode = 0xc7;
modrm = bfd_get_8 (abfd, contents + roff - 1);
modrm = 0xc0 | (modrm & 0x38) >> 3;
- if ((rex & REX_W) != 0
- && ABI_64_P (link_info->output_bfd))
+ if (rex_w && ABI_64_P (link_info->output_bfd))
{
/* Keep the REX_W bit in REX byte for LP64. */
r_type = R_X86_64_32S;
@@ -1837,8 +1860,9 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
use R_X86_64_32 and clear the W bit to avoid
sign-extend imm32 to imm64. */
r_type = R_X86_64_32;
- /* Clear the W bit in REX byte. */
+ /* Clear the W bit in REX byte and REX2 payload. */
rex_mask |= REX_W;
+ rex2_mask |= REX_W;
goto rewrite_modrm_rex;
}
}
@@ -1867,7 +1891,7 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
/* Use R_X86_64_32 with 32-bit operand to avoid relocation
overflow when sign-extending imm32 to imm64. */
- r_type = (rex & REX_W) != 0 ? R_X86_64_32S : R_X86_64_32;
+ r_type = rex_w ? R_X86_64_32S : R_X86_64_32;
rewrite_modrm_rex:
if (abs_relocation)
@@ -1893,6 +1917,13 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
rex = (rex & ~rex_mask) | (rex & REX_R) >> 2;
bfd_put_8 (abfd, rex, contents + roff - 3);
}
+ else if (rex2)
+ {
+ /* Move the R bits to the B bits in REX2 payload byte. */
+ rex2 = ((rex2 & ~rex2_mask)
+ | (rex2 & (REX_R | REX_R << 4)) >> 2);
+ bfd_put_8 (abfd, rex2, contents + roff - 3);
+ }
/* No addend for R_X86_64_32/R_X86_64_32S relocations. */
irel->r_addend = 0;
@@ -2058,7 +2089,8 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
converted_reloc = false;
if ((r_type == R_X86_64_GOTPCREL
|| r_type == R_X86_64_GOTPCRELX
- || r_type == R_X86_64_REX_GOTPCRELX)
+ || r_type == R_X86_64_REX_GOTPCRELX
+ || r_type == R_X86_64_CODE_4_GOTPCRELX)
&& (h == NULL || h->type != STT_GNU_IFUNC))
{
Elf_Internal_Rela *irel = (Elf_Internal_Rela *) rel;
@@ -2108,6 +2140,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
case R_X86_64_REX_GOTPCRELX:
+ case R_X86_64_CODE_4_GOTPCRELX:
case R_X86_64_TLSGD:
case R_X86_64_GOT64:
case R_X86_64_GOTPCREL64:
@@ -2710,6 +2743,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
case R_X86_64_REX_GOTPCRELX:
+ case R_X86_64_CODE_4_GOTPCRELX:
case R_X86_64_GOTPCREL64:
base_got = htab->elf.sgot;
off = h->got.offset;
@@ -2935,6 +2969,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
case R_X86_64_REX_GOTPCRELX:
+ case R_X86_64_CODE_4_GOTPCRELX:
case R_X86_64_GOTPCREL64:
/* Use global offset table entry as symbol value. */
case R_X86_64_GOTPLT64:
@@ -3025,7 +3060,8 @@ elf_x86_64_relocate_section (bfd *output_bfd,
&& !(sym->st_shndx == SHN_ABS
&& (r_type == R_X86_64_GOTPCREL
|| r_type == R_X86_64_GOTPCRELX
- || r_type == R_X86_64_REX_GOTPCRELX)))
+ || r_type == R_X86_64_REX_GOTPCRELX
+ || r_type == R_X86_64_CODE_4_GOTPCRELX)))
relative_reloc = true;
}
}
@@ -3063,6 +3099,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
if (r_type != R_X86_64_GOTPCREL
&& r_type != R_X86_64_GOTPCRELX
&& r_type != R_X86_64_REX_GOTPCRELX
+ && r_type != R_X86_64_CODE_4_GOTPCRELX
&& r_type != R_X86_64_GOTPCREL64)
relocation -= htab->elf.sgotplt->output_section->vma
- htab->elf.sgotplt->output_offset;
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 8dab441..8873faf 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1460,6 +1460,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_X86_64_PLT32_BND",
"BFD_RELOC_X86_64_GOTPCRELX",
"BFD_RELOC_X86_64_REX_GOTPCRELX",
+ "BFD_RELOC_X86_64_CODE_4_GOTPCRELX",
"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 6fd0f1f..56d852d 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2475,6 +2475,8 @@ ENUMX
BFD_RELOC_X86_64_GOTPCRELX
ENUMX
BFD_RELOC_X86_64_REX_GOTPCRELX
+ENUMX
+ BFD_RELOC_X86_64_CODE_4_GOTPCRELX
ENUMDOC
x86-64/elf relocations.