diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp index dd0dc83189d26..076176ebc9a4c 100644 --- a/lld/ELF/Arch/X86_64.cpp +++ b/lld/ELF/Arch/X86_64.cpp @@ -401,6 +401,7 @@ RelExpr X86_64::getRelExpr(RelType type, const Symbol &s, case R_X86_64_CODE_4_GOTPCRELX: case R_X86_64_GOTTPOFF: case R_X86_64_CODE_4_GOTTPOFF: + case R_X86_64_CODE_6_GOTTPOFF: return R_GOT_PC; case R_X86_64_GOTOFF64: return R_GOTPLTREL; @@ -562,8 +563,9 @@ void X86_64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, } } -// In some conditions, R_X86_64_GOTTPOFF/R_X86_64_CODE_4_GOTTPOFF relocation can -// be optimized to R_X86_64_TPOFF32 so that it does not use GOT. +// In some conditions, +// R_X86_64_GOTTPOFF/R_X86_64_CODE_4_GOTTPOFF/R_X86_64_CODE_6_GOTTPOFF +// relocation can be optimized to R_X86_64_TPOFF32 so that it does not use GOT. void X86_64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const { uint8_t *inst = loc - 3; @@ -605,7 +607,7 @@ void X86_64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, } else if (rel.type == R_X86_64_CODE_4_GOTTPOFF) { if (loc[-4] != 0xd5) { Err(ctx) << getErrorLoc(ctx, loc - 4) - << "Invalid prefix with R_X86_64_CODE_4_GOTTPOFF!"; + << "invalid prefix with R_X86_64_CODE_4_GOTTPOFF!"; return; } const uint8_t rex = loc[-3]; @@ -623,6 +625,41 @@ void X86_64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, << "R_X86_64_CODE_4_GOTTPOFF must be used in MOVQ or ADDQ " "instructions only"; } + } else if (rel.type == R_X86_64_CODE_6_GOTTPOFF) { + if (loc[-6] != 0x62) { + Err(ctx) << getErrorLoc(ctx, loc - 6) + << "invalid prefix with R_X86_64_CODE_6_GOTTPOFF!"; + return; + } + // Check bits are satisfied: + // loc[-5]: X==1 (inverted polarity), (loc[-5] & 0x7) == 0x4 + // loc[-4]: W==1, X2==1 (inverted polarity), pp==0b00(NP) + // loc[-3]: NF==1 or ND==1 + // loc[-2]: opcode==0x1 or opcode==0x3 + // loc[-1]: Mod==0b00, RM==0b101 + if (((loc[-5] & 0x47) == 0x44) && ((loc[-4] & 0x87) == 0x84) && + ((loc[-3] & 0x14) != 0) && (loc[-2] == 0x1 || loc[-2] == 0x3) && + ((loc[-1] & 0xc7) == 0x5)) { + // "addq %reg1, foo@GOTTPOFF(%rip), %reg2" -> "addq $foo, %reg1, %reg2" + // "addq foo@GOTTPOFF(%rip), %reg1, %reg2" -> "addq $foo, %reg1, %reg2" + // "{nf} addq %reg1, foo@GOTTPOFF(%rip), %reg2" + // -> "{nf} addq $foo, %reg1, %reg2" + // "{nf} addq name@GOTTPOFF(%rip), %reg1, %reg2" + // -> "{nf} addq $foo, %reg1, %reg2" + // "{nf} addq name@GOTTPOFF(%rip), %reg" -> "{nf} addq $foo, %reg" + loc[-2] = 0x81; + // Move R bits to B bits in EVEX payloads and ModRM byte. + const uint8_t evexPayload0 = loc[-5]; + if ((evexPayload0 & (1 << 7)) == 0) + loc[-5] = (evexPayload0 | (1 << 7)) & ~(1 << 5); + if ((evexPayload0 & (1 << 4)) == 0) + loc[-5] = evexPayload0 | (1 << 4) | (1 << 3); + *regSlot = 0xc0 | reg; + } else { + Err(ctx) << getErrorLoc(ctx, loc - 6) + << "R_X86_64_CODE_6_GOTTPOFF must be used in ADDQ instructions " + "with NDD/NF/NDD+NF only"; + } } else { llvm_unreachable("Unsupported relocation type!"); } @@ -782,6 +819,7 @@ int64_t X86_64::getImplicitAddend(const uint8_t *buf, RelType type) const { case R_X86_64_PC32: case R_X86_64_GOTTPOFF: case R_X86_64_CODE_4_GOTTPOFF: + case R_X86_64_CODE_6_GOTTPOFF: case R_X86_64_PLT32: case R_X86_64_TLSGD: case R_X86_64_TLSLD: @@ -893,6 +931,7 @@ void X86_64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { break; case R_X86_64_GOTTPOFF: case R_X86_64_CODE_4_GOTTPOFF: + case R_X86_64_CODE_6_GOTTPOFF: if (rel.expr == R_RELAX_TLS_IE_TO_LE) { relaxTlsIeToLe(loc, rel, val); } else { diff --git a/lld/test/ELF/invalid/broken-relaxation-x64.test b/lld/test/ELF/invalid/broken-relaxation-x64.test index 97a977e2c03ac..daa0b38ec3971 100644 --- a/lld/test/ELF/invalid/broken-relaxation-x64.test +++ b/lld/test/ELF/invalid/broken-relaxation-x64.test @@ -1,15 +1,15 @@ # REQUIRES: x86 -# RUN: yaml2obj %s -o %t.o -# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s -# ERR: R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only -# ERR: R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only +# RUN: yaml2obj --docnum=1 %s -o %t1.o +# RUN: not ld.lld %t1.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s +# ERR: error: {{.*}}: R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only +# ERR: error: {{.*}}: R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only ## YAML below contains 2 relocations of type R_X86_64_GOTTPOFF, and a .text ## with fake content filled by 0xFF. That means instructions for relaxation are ## "broken", so they does not match any known valid relaxations. We also generate ## .tls section because we need it for correct processing of STT_TLS symbol. -!ELF +--- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB @@ -44,4 +44,131 @@ Symbols: Value: 0x12345 Size: 4 Binding: STB_GLOBAL - + + +# RUN: yaml2obj --docnum=2 %s -o %t2.o +# RUN: not ld.lld %t2.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR2 %s +# ERR2: error: {{.*}}: invalid prefix with R_X86_64_CODE_4_GOTTPOFF! +# ERR2: error: {{.*}}: invalid prefix with R_X86_64_CODE_6_GOTTPOFF! + +## YAML below contains 2 relocations of +## R_X86_64_CODE_4_GOTTPOFF/R_X86_64_CODE_6_GOTTPOFF type, and a .text with +## fake content filled by 0xFF. It's expected to get "invalid prefix" error +## message as above. +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + OSABI: ELFOSABI_FREEBSD + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Type: SHT_PROGBITS + Name: .text + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x04 + Content: "FFFFFFFFFFFFFFFFFFFF" + - Type: SHT_PROGBITS + Name: .tls + Flags: [ SHF_ALLOC, SHF_TLS ] + - Type: SHT_REL + Name: .rel.text + Link: .symtab + Info: .text + AddressAlign: 0x04 + Relocations: + - Offset: 4 + Symbol: foo + Type: R_X86_64_CODE_4_GOTTPOFF + - Offset: 6 + Symbol: foo + Type: R_X86_64_CODE_6_GOTTPOFF +Symbols: + - Name: foo + Type: STT_TLS + Section: .text + Value: 0x12345 + Size: 4 + Binding: STB_GLOBAL + + +# RUN: yaml2obj --docnum=3 %s -o %t3.o +# RUN: not ld.lld %t3.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR3 %s +# ERR3: error: {{.*}}: R_X86_64_CODE_4_GOTTPOFF must be used in MOVQ or ADDQ instructions only + +## YAML below contains R_X86_64_CODE_4_GOTTPOFF relocation type, and a .text +## with fake content filled by 0xd5, 0xFF, ... and 0xFF. It's expected to get +## the error message as above. +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + OSABI: ELFOSABI_FREEBSD + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Type: SHT_PROGBITS + Name: .text + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x04 + Content: "d5FFFFFFFFFFFFFFFFFF" + - Type: SHT_PROGBITS + Name: .tls + Flags: [ SHF_ALLOC, SHF_TLS ] + - Type: SHT_REL + Name: .rel.text + Link: .symtab + Info: .text + AddressAlign: 0x04 + Relocations: + - Offset: 4 + Symbol: foo + Type: R_X86_64_CODE_4_GOTTPOFF +Symbols: + - Name: foo + Type: STT_TLS + Section: .text + Value: 0x12345 + Size: 4 + Binding: STB_GLOBAL + + +# RUN: yaml2obj --docnum=4 %s -o %t4.o +# RUN: not ld.lld %t4.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR4 %s +# ERR4: error: {{.*}}: R_X86_64_CODE_6_GOTTPOFF must be used in ADDQ instructions with NDD/NF/NDD+NF only + +## YAML below contains R_X86_64_CODE_6_GOTTPOFF relocation type, and a .text +## with fake content filled by 0x62, 0xFF, ... and 0xFF. It's expected to get +## the error message as above. +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + OSABI: ELFOSABI_FREEBSD + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Type: SHT_PROGBITS + Name: .text + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x04 + Content: "62FFFFFFFFFFFFFFFFFF" + - Type: SHT_PROGBITS + Name: .tls + Flags: [ SHF_ALLOC, SHF_TLS ] + - Type: SHT_REL + Name: .rel.text + Link: .symtab + Info: .text + AddressAlign: 0x04 + Relocations: + - Offset: 6 + Symbol: foo + Type: R_X86_64_CODE_6_GOTTPOFF +Symbols: + - Name: foo + Type: STT_TLS + Section: .text + Value: 0x12345 + Size: 4 + Binding: STB_GLOBAL diff --git a/lld/test/ELF/pack-dyn-relocs-tls-x86-64.s b/lld/test/ELF/pack-dyn-relocs-tls-x86-64.s index c6464b4bece09..c54d6f705080d 100644 --- a/lld/test/ELF/pack-dyn-relocs-tls-x86-64.s +++ b/lld/test/ELF/pack-dyn-relocs-tls-x86-64.s @@ -13,6 +13,7 @@ foo: movq tlsvar@GOTTPOFF(%rip), %rcx movq tlsvar2@GOTTPOFF(%rip), %r31 + addq tlsvar3@GOTTPOFF(%rip), %rcx, %r16 .section .tdata,"awT",@progbits @@ -21,7 +22,11 @@ tlsvar: .word 42 tlsvar2: .word 42 +tlsvar3: + .word 42 + // CHECK: Section ({{.+}}) .rela.dyn { // CHECK-NEXT: R_X86_64_TPOFF64 - 0x1234 // CHECK-NEXT: R_X86_64_TPOFF64 - 0x1236 +// CHECK-NEXT: R_X86_64_TPOFF64 - 0x1238 // CHECK-NEXT: } diff --git a/lld/test/ELF/tls-opt.s b/lld/test/ELF/tls-opt.s index 818203ee19cb7..08cc52afd6411 100644 --- a/lld/test/ELF/tls-opt.s +++ b/lld/test/ELF/tls-opt.s @@ -20,12 +20,25 @@ // DISASM-NEXT: leaq -4(%r15), %r15 // DISASM-NEXT: addq $-4, %rsp // DISASM-NEXT: addq $-4, %r12 +# EGPR // DISASM-NEXT: movq $-8, %r16 // DISASM-NEXT: movq $-8, %r20 // DISASM-NEXT: movq $-4, %r16 // DISASM-NEXT: addq $-8, %r16 // DISASM-NEXT: addq $-8, %r28 // DISASM-NEXT: addq $-4, %r16 +# NDD +// DISASM-NEXT: addq $-10, %r16, %r16 +// DISASM-NEXT: addq $-10, %r16, %r20 +// DISASM-NEXT: addq $-10, %r16, %rax +// DISASM-NEXT: addq $-10, %rax, %r16 +// DISASM-NEXT: addq $-10, %r8, %r16 +// DISASM-NEXT: addq $-10, %rax, %r12 +# NDD + NF +// DISASM-NEXT: {nf} addq $-10, %r8, %r16 +// DISASM-NEXT: {nf} addq $-10, %rax, %r12 +# NF +// DISASM-NEXT: {nf} addq $-10, %r12 // LD to LE: // DISASM-NEXT: movq %fs:0, %rax @@ -82,6 +95,18 @@ _start: addq tls0@GOTTPOFF(%rip), %r16 addq tls0@GOTTPOFF(%rip), %r28 addq tls1@GOTTPOFF(%rip), %r16 + # NDD + addq tls0@GOTTPOFF(%rip), %r16, %r16 + addq tls0@GOTTPOFF(%rip), %r16, %r20 + addq tls0@GOTTPOFF(%rip), %r16, %rax + addq tls0@GOTTPOFF(%rip), %rax, %r16 + addq %r8, tls0@GOTTPOFF(%rip), %r16 + addq tls0@GOTTPOFF(%rip), %rax, %r12 + # NDD + NF + {nf} addq %r8, tls0@GOTTPOFF(%rip), %r16 + {nf} addq tls0@GOTTPOFF(%rip), %rax, %r12 + # NF + {nf} addq tls0@GOTTPOFF(%rip), %r12 // LD to LE leaq tls0@tlsld(%rip), %rdi diff --git a/lld/test/ELF/x86-64-tls-ie-err.s b/lld/test/ELF/x86-64-tls-ie-err.s new file mode 100644 index 0000000000000..3cc7cb0d41737 --- /dev/null +++ b/lld/test/ELF/x86-64-tls-ie-err.s @@ -0,0 +1,35 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck -DFILE=%t.o %s + +# CHECK: error: [[FILE]]:(.text+0x2): invalid prefix with R_X86_64_CODE_4_GOTTPOFF! +# CHECK-NEXT: error: [[FILE]]:(.text+0x8): invalid prefix with R_X86_64_CODE_6_GOTTPOFF! +# CHECK-NEXT: error: [[FILE]]:(.text+0x12): R_X86_64_CODE_4_GOTTPOFF must be used in MOVQ or ADDQ instructions only +# CHECK-NEXT: error: [[FILE]]:(.text+0x1a): R_X86_64_CODE_6_GOTTPOFF must be used in ADDQ instructions with NDD/NF/NDD+NF only + +## These negative tests are to check if the invalid prefix and unsupported +## instructions for TLS relocation types with APX instructions are handled as +## errors. + +.type tls0,@object +.section .tbss,"awT",@nobits +.globl tls0 +.align 4 +tls0: + .long 0 + .size tls0, 4 + +.text +.globl _start +_start: + addq 0(%rip), %rax, %r16 + .reloc .-4, R_X86_64_CODE_4_GOTTPOFF, tls0-4 + + movq 0(%rip), %r16 + .reloc .-4, R_X86_64_CODE_6_GOTTPOFF, tls0-4 + + andq 0(%rip), %r16 + .reloc .-4, R_X86_64_CODE_4_GOTTPOFF, tls0-4 + + andq 0(%rip), %rax, %r16 + .reloc .-4, R_X86_64_CODE_6_GOTTPOFF, tls0-4 diff --git a/lld/test/ELF/x86-64-tls-ie-local.s b/lld/test/ELF/x86-64-tls-ie-local.s index 340a654ef9c28..0a104e7d67277 100644 --- a/lld/test/ELF/x86-64-tls-ie-local.s +++ b/lld/test/ELF/x86-64-tls-ie-local.s @@ -5,29 +5,47 @@ # RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=REL %s # RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn %t.so | FileCheck %s -# SEC: .got PROGBITS 0000000000002348 000348 000010 00 WA 0 0 8 +# SEC: .got PROGBITS 0000000000002378 000378 000010 00 WA 0 0 8 ## Dynamic relocations for non-preemptable symbols in a shared object have section index 0. # REL: .rela.dyn { -# REL-NEXT: 0x2348 R_X86_64_TPOFF64 - 0x0 -# REL-NEXT: 0x2350 R_X86_64_TPOFF64 - 0x4 +# REL-NEXT: 0x2378 R_X86_64_TPOFF64 - 0x0 +# REL-NEXT: 0x2380 R_X86_64_TPOFF64 - 0x4 # REL-NEXT: } -## &.got[0] - 0x127f = 0x2348 - 0x127f = 4297 -## &.got[1] - 0x1286 = 0x2350 - 0x1286 = 4298 -## &.got[2] - 0x128e = 0x2348 - 0x128e = 4282 -## &.got[3] - 0x1296 = 0x2350 - 0x1296 = 4282 +## &.got[0] - 0x127f = 0x2378 - 0x127f = 4345 +## &.got[1] - 0x1286 = 0x2380 - 0x1286 = 4346 +## &.got[2] - 0x128e = 0x2378 - 0x128e = 4330 +## &.got[3] - 0x1296 = 0x2380 - 0x1296 = 4330 +## &.got[0] - 0x12a0 = 0x2376 - 0x12a0 = 4310 +## &.got[1] - 0x12aa = 0x237e - 0x12aa = 4308 +## &.got[0] - 0x12b4 = 0x2376 - 0x12b4 = 4290 +## &.got[1] - 0x12be = 0x237e - 0x12be = 4288 +## &.got[0] - 0x12c8 = 0x2376 - 0x12c8 = 4270 -# CHECK: 1278: addq 4297(%rip), %rax -# CHECK-NEXT: 127f: addq 4298(%rip), %rax -# CHECK-NEXT: 1286: addq 4282(%rip), %r16 -# CHECK-NEXT: 128e: addq 4282(%rip), %r16 +# CHECK: 1278: addq 4345(%rip), %rax +# CHECK-NEXT: 127f: addq 4346(%rip), %rax +# CHECK-NEXT: 1286: addq 4330(%rip), %r16 +# CHECK-NEXT: 128e: addq 4330(%rip), %r16 +# CHECK-NEXT: 1296: addq %r8, 4310(%rip), %r16 +# CHECK-NEXT: 12a0: addq 4308(%rip), %rax, %r12 +# CHECK-NEXT: 12aa: {nf} addq %r8, 4290(%rip), %r16 +# CHECK-NEXT: 12b4: {nf} addq 4288(%rip), %rax, %r12 +# CHECK-NEXT: 12be: {nf} addq 4270(%rip), %r12 addq foo@GOTTPOFF(%rip), %rax addq bar@GOTTPOFF(%rip), %rax +# EGPR addq foo@GOTTPOFF(%rip), %r16 addq bar@GOTTPOFF(%rip), %r16 - +# NDD +addq %r8, foo@GOTTPOFF(%rip), %r16 +addq bar@GOTTPOFF(%rip), %rax, %r12 +# NDD + NF +{nf} addq %r8, foo@GOTTPOFF(%rip), %r16 +{nf} addq bar@GOTTPOFF(%rip), %rax, %r12 +# NF +{nf} addq foo@GOTTPOFF(%rip), %r12 .section .tbss,"awT",@nobits foo: