forked from OSchip/llvm-project
[X86] Support -fno-plt __tls_get_addr calls
In general dynamic/local dynamic TLS models, with -fno-plt, * x86: emit `calll *___tls_get_addr@GOT(%ebx)` instead of `calll ___tls_get_addr@PLT` Note, on x86, if we can get rid of %ebx as the PIC register, it may be better to use a register not preserved across function calls. * x86_64: emit `callq *__tls_get_addr@GOTPCREL(%rip)` instead of `callq __tls_get_addr@PLT` Reorganize the code by separating 32-bit and 64-bit. Reviewed By: rnk Differential Revision: https://reviews.llvm.org/D62106 llvm-svn: 361453
This commit is contained in:
parent
eac9a7830b
commit
86c9ca48c3
|
@ -683,16 +683,9 @@ void X86MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
|
|||
|
||||
void X86AsmPrinter::LowerTlsAddr(X86MCInstLower &MCInstLowering,
|
||||
const MachineInstr &MI) {
|
||||
|
||||
bool is64Bits = MI.getOpcode() == X86::TLS_addr64 ||
|
||||
bool Is64Bits = MI.getOpcode() == X86::TLS_addr64 ||
|
||||
MI.getOpcode() == X86::TLS_base_addr64;
|
||||
|
||||
bool needsPadding = MI.getOpcode() == X86::TLS_addr64;
|
||||
|
||||
MCContext &context = OutStreamer->getContext();
|
||||
|
||||
if (needsPadding)
|
||||
EmitAndCountInstruction(MCInstBuilder(X86::DATA16_PREFIX));
|
||||
MCContext &Ctx = OutStreamer->getContext();
|
||||
|
||||
MCSymbolRefExpr::VariantKind SRVK;
|
||||
switch (MI.getOpcode()) {
|
||||
|
@ -710,51 +703,79 @@ void X86AsmPrinter::LowerTlsAddr(X86MCInstLower &MCInstLowering,
|
|||
llvm_unreachable("unexpected opcode");
|
||||
}
|
||||
|
||||
MCSymbol *sym = MCInstLowering.GetSymbolFromOperand(MI.getOperand(3));
|
||||
const MCSymbolRefExpr *symRef = MCSymbolRefExpr::create(sym, SRVK, context);
|
||||
const MCSymbolRefExpr *Sym = MCSymbolRefExpr::create(
|
||||
MCInstLowering.GetSymbolFromOperand(MI.getOperand(3)), SRVK, Ctx);
|
||||
bool UseGot = MMI->getModule()->getRtLibUseGOT();
|
||||
|
||||
MCInst LEA;
|
||||
if (is64Bits) {
|
||||
LEA.setOpcode(X86::LEA64r);
|
||||
LEA.addOperand(MCOperand::createReg(X86::RDI)); // dest
|
||||
LEA.addOperand(MCOperand::createReg(X86::RIP)); // base
|
||||
LEA.addOperand(MCOperand::createImm(1)); // scale
|
||||
LEA.addOperand(MCOperand::createReg(0)); // index
|
||||
LEA.addOperand(MCOperand::createExpr(symRef)); // disp
|
||||
LEA.addOperand(MCOperand::createReg(0)); // seg
|
||||
} else if (SRVK == MCSymbolRefExpr::VK_TLSLDM) {
|
||||
LEA.setOpcode(X86::LEA32r);
|
||||
LEA.addOperand(MCOperand::createReg(X86::EAX)); // dest
|
||||
LEA.addOperand(MCOperand::createReg(X86::EBX)); // base
|
||||
LEA.addOperand(MCOperand::createImm(1)); // scale
|
||||
LEA.addOperand(MCOperand::createReg(0)); // index
|
||||
LEA.addOperand(MCOperand::createExpr(symRef)); // disp
|
||||
LEA.addOperand(MCOperand::createReg(0)); // seg
|
||||
if (Is64Bits) {
|
||||
bool NeedsPadding = SRVK == MCSymbolRefExpr::VK_TLSGD;
|
||||
if (NeedsPadding)
|
||||
EmitAndCountInstruction(MCInstBuilder(X86::DATA16_PREFIX));
|
||||
EmitAndCountInstruction(MCInstBuilder(X86::LEA64r)
|
||||
.addReg(X86::RDI)
|
||||
.addReg(X86::RIP)
|
||||
.addImm(1)
|
||||
.addReg(0)
|
||||
.addExpr(Sym)
|
||||
.addReg(0));
|
||||
const MCSymbol *TlsGetAddr = Ctx.getOrCreateSymbol("__tls_get_addr");
|
||||
if (NeedsPadding) {
|
||||
if (!UseGot)
|
||||
EmitAndCountInstruction(MCInstBuilder(X86::DATA16_PREFIX));
|
||||
EmitAndCountInstruction(MCInstBuilder(X86::DATA16_PREFIX));
|
||||
EmitAndCountInstruction(MCInstBuilder(X86::REX64_PREFIX));
|
||||
}
|
||||
if (UseGot) {
|
||||
const MCExpr *Expr = MCSymbolRefExpr::create(
|
||||
TlsGetAddr, MCSymbolRefExpr::VK_GOTPCREL, Ctx);
|
||||
EmitAndCountInstruction(MCInstBuilder(X86::CALL64m)
|
||||
.addReg(X86::RIP)
|
||||
.addImm(1)
|
||||
.addReg(0)
|
||||
.addExpr(Expr)
|
||||
.addReg(0));
|
||||
} else {
|
||||
EmitAndCountInstruction(
|
||||
MCInstBuilder(X86::CALL64pcrel32)
|
||||
.addExpr(MCSymbolRefExpr::create(TlsGetAddr,
|
||||
MCSymbolRefExpr::VK_PLT, Ctx)));
|
||||
}
|
||||
} else {
|
||||
LEA.setOpcode(X86::LEA32r);
|
||||
LEA.addOperand(MCOperand::createReg(X86::EAX)); // dest
|
||||
LEA.addOperand(MCOperand::createReg(0)); // base
|
||||
LEA.addOperand(MCOperand::createImm(1)); // scale
|
||||
LEA.addOperand(MCOperand::createReg(X86::EBX)); // index
|
||||
LEA.addOperand(MCOperand::createExpr(symRef)); // disp
|
||||
LEA.addOperand(MCOperand::createReg(0)); // seg
|
||||
if (SRVK == MCSymbolRefExpr::VK_TLSGD && !UseGot) {
|
||||
EmitAndCountInstruction(MCInstBuilder(X86::LEA32r)
|
||||
.addReg(X86::EAX)
|
||||
.addReg(0)
|
||||
.addImm(1)
|
||||
.addReg(X86::EBX)
|
||||
.addExpr(Sym)
|
||||
.addReg(0));
|
||||
} else {
|
||||
EmitAndCountInstruction(MCInstBuilder(X86::LEA32r)
|
||||
.addReg(X86::EAX)
|
||||
.addReg(X86::EBX)
|
||||
.addImm(1)
|
||||
.addReg(0)
|
||||
.addExpr(Sym)
|
||||
.addReg(0));
|
||||
}
|
||||
|
||||
const MCSymbol *TlsGetAddr = Ctx.getOrCreateSymbol("___tls_get_addr");
|
||||
if (UseGot) {
|
||||
const MCExpr *Expr =
|
||||
MCSymbolRefExpr::create(TlsGetAddr, MCSymbolRefExpr::VK_GOT, Ctx);
|
||||
EmitAndCountInstruction(MCInstBuilder(X86::CALL32m)
|
||||
.addReg(X86::EBX)
|
||||
.addImm(1)
|
||||
.addReg(0)
|
||||
.addExpr(Expr)
|
||||
.addReg(0));
|
||||
} else {
|
||||
EmitAndCountInstruction(
|
||||
MCInstBuilder(X86::CALLpcrel32)
|
||||
.addExpr(MCSymbolRefExpr::create(TlsGetAddr,
|
||||
MCSymbolRefExpr::VK_PLT, Ctx)));
|
||||
}
|
||||
}
|
||||
EmitAndCountInstruction(LEA);
|
||||
|
||||
if (needsPadding) {
|
||||
EmitAndCountInstruction(MCInstBuilder(X86::DATA16_PREFIX));
|
||||
EmitAndCountInstruction(MCInstBuilder(X86::DATA16_PREFIX));
|
||||
EmitAndCountInstruction(MCInstBuilder(X86::REX64_PREFIX));
|
||||
}
|
||||
|
||||
StringRef name = is64Bits ? "__tls_get_addr" : "___tls_get_addr";
|
||||
MCSymbol *tlsGetAddr = context.getOrCreateSymbol(name);
|
||||
const MCSymbolRefExpr *tlsRef =
|
||||
MCSymbolRefExpr::create(tlsGetAddr, MCSymbolRefExpr::VK_PLT, context);
|
||||
|
||||
EmitAndCountInstruction(
|
||||
MCInstBuilder(is64Bits ? X86::CALL64pcrel32 : X86::CALLpcrel32)
|
||||
.addExpr(tlsRef));
|
||||
}
|
||||
|
||||
/// Emit the largest nop instruction smaller than or equal to \p NumBytes
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
; RUN: llc < %s -mtriple=i386-linux-musl -relocation-model=pic | FileCheck --check-prefixes=CHECK,X86 %s
|
||||
; RUN: llc < %s -mtriple=x86_64-linux-musl -relocation-model=pic | FileCheck --check-prefixes=CHECK,X64 %s
|
||||
|
||||
@gd = thread_local global i32 0
|
||||
@ld = internal thread_local global i32 0
|
||||
|
||||
define i32* @get_gd() {
|
||||
entry:
|
||||
; CHECK-LABEL: get_gd:
|
||||
; X86: leal gd@TLSGD(%ebx), %eax
|
||||
; X86: calll *___tls_get_addr@GOT(%ebx)
|
||||
|
||||
; X64: leaq gd@TLSGD(%rip), %rdi
|
||||
; X64: callq *__tls_get_addr@GOTPCREL(%rip)
|
||||
ret i32* @gd
|
||||
}
|
||||
|
||||
define i32* @get_ld() {
|
||||
; FIXME: This function uses a single thread-local variable, we might want to fall back to general-dynamic.
|
||||
; CHECK-LABEL: get_ld:
|
||||
; X86: leal ld@TLSLDM(%ebx), %eax
|
||||
; X86: calll *___tls_get_addr@GOT(%ebx)
|
||||
|
||||
; X64: leaq ld@TLSLD(%rip), %rdi
|
||||
; X64: callq *__tls_get_addr@GOTPCREL(%rip)
|
||||
ret i32* @ld
|
||||
}
|
||||
|
||||
!llvm.module.flags = !{!1}
|
||||
!1 = !{i32 7, !"RtLibUseGOT", i32 1}
|
Loading…
Reference in New Issue