Skip to content

Commit 1d4f291

Browse files
committed
[X86][LLD] Handle R_X86_64_CODE_6_GOTTPOFF relocation type
For add %reg1, name@GOTTPOFF(%rip), %reg2 add name@GOTTPOFF(%rip), %reg1, %reg2 {nf} add %reg1, name@GOTTPOFF(%rip), %reg2 {nf} add name@GOTTPOFF(%rip), %reg1, %reg2 {nf} add name@GOTTPOFF(%rip), %reg add R_X86_64_CODE_6_GOTTPOFF = 50 in llvm#117277. Linker can treat R_X86_64_CODE_6_GOTTPOFF as R_X86_64_GOTTPOFF or convert the instructions above to add $name@tpoff, %reg1, %reg2 add $name@tpoff, %reg1, %reg2 {nf} add $name@tpoff, %reg1, %reg2 {nf} add $name@tpoff, %reg1, %reg2 {nf} add $name@tpoff, %reg if the first byte of the instruction at the relocation offset - 6 is 0x62 (namely, encoded w/EVEX prefix) when possible. Binutils patch: bminor/binutils-gdb@5bc71c2 Binutils mailthread: https://sourceware.org/pipermail/binutils/2024-February/132351.html ABI discussion: https://groups.google.com/g/x86-64-abi/c/FhEZjCtDLFw/m/VHDjN4orAgAJ Blog: https://kanrobert.github.io/rfc/All-about-APX-relocation
1 parent 2ed8c5d commit 1d4f291

File tree

2 files changed

+75
-31
lines changed

2 files changed

+75
-31
lines changed

lld/ELF/Arch/X86_64.cpp

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ RelExpr X86_64::getRelExpr(RelType type, const Symbol &s,
396396
case R_X86_64_REX_GOTPCRELX:
397397
case R_X86_64_CODE_4_GOTPCRELX:
398398
case R_X86_64_GOTTPOFF:
399+
case R_X86_64_CODE_6_GOTTPOFF:
399400
return R_GOT_PC;
400401
case R_X86_64_GOTOFF64:
401402
return R_GOTPLTREL;
@@ -547,44 +548,68 @@ void X86_64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
547548
}
548549
}
549550

550-
// In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to
551-
// R_X86_64_TPOFF32 so that it does not use GOT.
551+
// In some conditions, R_X86_64_GOTTPOFF/R_X86_64_CODE_6_GOTTPOFF relocation can
552+
// be optimized to R_X86_64_TPOFF32 so that it does not use GOT.
552553
void X86_64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
553554
uint64_t val) const {
554555
uint8_t *inst = loc - 3;
555556
uint8_t reg = loc[-1] >> 3;
556557
uint8_t *regSlot = loc - 1;
557558

558-
// Note that ADD with RSP or R12 is converted to ADD instead of LEA
559-
// because LEA with these registers needs 4 bytes to encode and thus
560-
// wouldn't fit the space.
561-
562-
if (memcmp(inst, "\x48\x03\x25", 3) == 0) {
563-
// "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp"
564-
memcpy(inst, "\x48\x81\xc4", 3);
565-
} else if (memcmp(inst, "\x4c\x03\x25", 3) == 0) {
566-
// "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12"
567-
memcpy(inst, "\x49\x81\xc4", 3);
568-
} else if (memcmp(inst, "\x4c\x03", 2) == 0) {
569-
// "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]"
570-
memcpy(inst, "\x4d\x8d", 2);
571-
*regSlot = 0x80 | (reg << 3) | reg;
572-
} else if (memcmp(inst, "\x48\x03", 2) == 0) {
573-
// "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg"
574-
memcpy(inst, "\x48\x8d", 2);
575-
*regSlot = 0x80 | (reg << 3) | reg;
576-
} else if (memcmp(inst, "\x4c\x8b", 2) == 0) {
577-
// "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]"
578-
memcpy(inst, "\x49\xc7", 2);
579-
*regSlot = 0xc0 | reg;
580-
} else if (memcmp(inst, "\x48\x8b", 2) == 0) {
581-
// "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg"
582-
memcpy(inst, "\x48\xc7", 2);
583-
*regSlot = 0xc0 | reg;
559+
if (rel.type == R_X86_64_GOTTPOFF) {
560+
// Note that ADD with RSP or R12 is converted to ADD instead of LEA
561+
// because LEA with these registers needs 4 bytes to encode and thus
562+
// wouldn't fit the space.
563+
564+
if (memcmp(inst, "\x48\x03\x25", 3) == 0) {
565+
// "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp"
566+
memcpy(inst, "\x48\x81\xc4", 3);
567+
} else if (memcmp(inst, "\x4c\x03\x25", 3) == 0) {
568+
// "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12"
569+
memcpy(inst, "\x49\x81\xc4", 3);
570+
} else if (memcmp(inst, "\x4c\x03", 2) == 0) {
571+
// "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]"
572+
memcpy(inst, "\x4d\x8d", 2);
573+
*regSlot = 0x80 | (reg << 3) | reg;
574+
} else if (memcmp(inst, "\x48\x03", 2) == 0) {
575+
// "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg"
576+
memcpy(inst, "\x48\x8d", 2);
577+
*regSlot = 0x80 | (reg << 3) | reg;
578+
} else if (memcmp(inst, "\x4c\x8b", 2) == 0) {
579+
// "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]"
580+
memcpy(inst, "\x49\xc7", 2);
581+
*regSlot = 0xc0 | reg;
582+
} else if (memcmp(inst, "\x48\x8b", 2) == 0) {
583+
// "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg"
584+
memcpy(inst, "\x48\xc7", 2);
585+
*regSlot = 0xc0 | reg;
586+
} else {
587+
ErrAlways(ctx)
588+
<< getErrorLoc(ctx, loc - 3)
589+
<< "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only";
590+
}
591+
} else if (rel.type == R_X86_64_CODE_6_GOTTPOFF) {
592+
if (loc[-6] != 0x62) {
593+
Err(ctx) << getErrorLoc(ctx, loc - 6)
594+
<< "Invalid prefix with R_X86_64_CODE_6_GOTTPOFF!";
595+
return;
596+
}
597+
if (loc[-2] == 0x3 || loc[-2] == 0x1) {
598+
// "addq foo@gottpoff(%rip), %reg1, %reg2" -> "addq $foo, %reg1, %reg2"
599+
loc[-2] = 0x81;
600+
// Move R bits to B bits in EVEX payloads and ModRM byte.
601+
if ((loc[-5] & (1 << 7)) == 0)
602+
loc[-5] = (loc[-5] | (1 << 7)) & ~(1 << 5);
603+
if ((loc[-5] & (1 << 4)) == 0)
604+
loc[-5] = loc[-5] | (1 << 4) | (1 << 3);
605+
*regSlot = 0xc0 | reg;
606+
} else {
607+
Err(ctx)
608+
<< getErrorLoc(ctx, loc - 6)
609+
<< "R_X86_64_CODE_6_GOTTPOFF must be used in ADDQ instructions only";
610+
}
584611
} else {
585-
ErrAlways(ctx)
586-
<< getErrorLoc(ctx, loc - 3)
587-
<< "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only";
612+
llvm_unreachable("Unsupported relocation type!");
588613
}
589614

590615
// The original code used a PC relative relocation.
@@ -741,6 +766,7 @@ int64_t X86_64::getImplicitAddend(const uint8_t *buf, RelType type) const {
741766
case R_X86_64_CODE_4_GOTPCRELX:
742767
case R_X86_64_PC32:
743768
case R_X86_64_GOTTPOFF:
769+
case R_X86_64_CODE_6_GOTTPOFF:
744770
case R_X86_64_PLT32:
745771
case R_X86_64_TLSGD:
746772
case R_X86_64_TLSLD:
@@ -850,6 +876,7 @@ void X86_64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
850876
}
851877
break;
852878
case R_X86_64_GOTTPOFF:
879+
case R_X86_64_CODE_6_GOTTPOFF:
853880
if (rel.expr == R_RELAX_TLS_IE_TO_LE) {
854881
relaxTlsIeToLe(loc, rel, val);
855882
} else {

lld/test/ELF/tls-opt.s

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@
2020
// DISASM-NEXT: leaq -4(%r15), %r15
2121
// DISASM-NEXT: addq $-4, %rsp
2222
// DISASM-NEXT: addq $-4, %r12
23+
// DISASM-NEXT: addq $-10, %r16, %r16
24+
// DISASM-NEXT: addq $-10, %r16, %r20
25+
// DISASM-NEXT: addq $-10, %r16, %rax
26+
// DISASM-NEXT: addq $-10, %rax, %r16
27+
// DISASM-NEXT: addq $-10, %r8, %r16
28+
// DISASM-NEXT: addq $-10, %rax, %r12
29+
// DISASM-NEXT: {nf} addq $-10, %r8, %r16
30+
// DISASM-NEXT: {nf} addq $-10, %rax, %r12
2331

2432
// LD to LE:
2533
// DISASM-NEXT: movq %fs:0, %rax
@@ -69,6 +77,15 @@ _start:
6977
addq tls1@GOTTPOFF(%rip), %r15
7078
addq tls1@GOTTPOFF(%rip), %rsp
7179
addq tls1@GOTTPOFF(%rip), %r12
80+
# NDD
81+
addq tls0@GOTTPOFF(%rip), %r16, %r16
82+
addq tls0@GOTTPOFF(%rip), %r16, %r20
83+
addq tls0@GOTTPOFF(%rip), %r16, %rax
84+
addq tls0@GOTTPOFF(%rip), %rax, %r16
85+
addq %r8, tls0@GOTTPOFF(%rip), %r16
86+
addq tls0@GOTTPOFF(%rip), %rax, %r12
87+
{nf} addq %r8, tls0@GOTTPOFF(%rip), %r16
88+
{nf} addq tls0@GOTTPOFF(%rip), %rax, %r12
7289

7390
// LD to LE
7491
leaq tls0@tlsld(%rip), %rdi

0 commit comments

Comments
 (0)