[llvm] 2aae213 - [X86] Add REX prefix for GOTTPOFF/TLSDESC relocs in x32 mode

Harald van Dijk via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 15 15:07:44 PST 2020


Author: Harald van Dijk
Date: 2020-12-15T23:07:34Z
New Revision: 2aae2136d5c6b2da69787934f5963a6b3486e5fe

URL: https://github.com/llvm/llvm-project/commit/2aae2136d5c6b2da69787934f5963a6b3486e5fe
DIFF: https://github.com/llvm/llvm-project/commit/2aae2136d5c6b2da69787934f5963a6b3486e5fe.diff

LOG: [X86] Add REX prefix for GOTTPOFF/TLSDESC relocs in x32 mode

The REX prefix is needed to allow linker relaxations: even if the
instruction we emit may not need it, the linker may change it to a
different instruction which does need it.

Added: 
    llvm/test/MC/X86/tlsdesc-x32.s

Modified: 
    llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
index 4e5e45f03925..59860cad01f7 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
@@ -93,7 +93,8 @@ class X86MCCodeEmitter : public MCCodeEmitter {
   bool emitOpcodePrefix(int MemOperand, const MCInst &MI,
                         const MCSubtargetInfo &STI, raw_ostream &OS) const;
 
-  bool emitREXPrefix(int MemOperand, const MCInst &MI, raw_ostream &OS) const;
+  bool emitREXPrefix(int MemOperand, const MCInst &MI,
+                     const MCSubtargetInfo &STI, raw_ostream &OS) const;
 };
 
 } // end anonymous namespace
@@ -1201,6 +1202,7 @@ void X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
 ///
 /// \returns true if REX prefix is used, otherwise returns false.
 bool X86MCCodeEmitter::emitREXPrefix(int MemOperand, const MCInst &MI,
+                                     const MCSubtargetInfo &STI,
                                      raw_ostream &OS) const {
   uint8_t REX = [&, MemOperand]() {
     uint8_t REX = 0;
@@ -1221,15 +1223,28 @@ bool X86MCCodeEmitter::emitREXPrefix(int MemOperand, const MCInst &MI,
     // If it accesses SPL, BPL, SIL, or DIL, then it requires a 0x40 REX prefix.
     for (unsigned i = CurOp; i != NumOps; ++i) {
       const MCOperand &MO = MI.getOperand(i);
-      if (!MO.isReg())
-        continue;
-      unsigned Reg = MO.getReg();
-      if (Reg == X86::AH || Reg == X86::BH || Reg == X86::CH || Reg == X86::DH)
-        UsesHighByteReg = true;
-      if (X86II::isX86_64NonExtLowByteReg(Reg))
-        // FIXME: The caller of determineREXPrefix slaps this prefix onto
-        // anything that returns non-zero.
-        REX |= 0x40; // REX fixed encoding prefix
+      if (MO.isReg()) {
+        unsigned Reg = MO.getReg();
+        if (Reg == X86::AH || Reg == X86::BH || Reg == X86::CH ||
+            Reg == X86::DH)
+          UsesHighByteReg = true;
+        if (X86II::isX86_64NonExtLowByteReg(Reg))
+          // FIXME: The caller of determineREXPrefix slaps this prefix onto
+          // anything that returns non-zero.
+          REX |= 0x40; // REX fixed encoding prefix
+      } else if (MO.isExpr() &&
+                 STI.getTargetTriple().getEnvironment() == Triple::GNUX32) {
+        // GOTTPOFF and TLSDESC relocations require a REX prefix to allow
+        // linker optimizations: even if the instructions we see may not require
+        // any prefix, they may be replaced by instructions that do. This is
+        // handled as a special case here so that it also works for hand-written
+        // assembly without the user needing to write REX, as with GNU as.
+        const auto *Ref = dyn_cast<MCSymbolRefExpr>(MO.getExpr());
+        if (Ref && (Ref->getKind() == MCSymbolRefExpr::VK_GOTTPOFF ||
+                    Ref->getKind() == MCSymbolRefExpr::VK_TLSDESC)) {
+          REX |= 0x40; // REX fixed encoding prefix
+        }
+      }
     }
 
     switch (TSFlags & X86II::FormMask) {
@@ -1352,7 +1367,7 @@ bool X86MCCodeEmitter::emitOpcodePrefix(int MemOperand, const MCInst &MI,
   assert((STI.hasFeature(X86::Mode64Bit) || !(TSFlags & X86II::REX_W)) &&
          "REX.W requires 64bit mode.");
   bool HasREX = STI.hasFeature(X86::Mode64Bit)
-                    ? emitREXPrefix(MemOperand, MI, OS)
+                    ? emitREXPrefix(MemOperand, MI, STI, OS)
                     : false;
 
   // 0x0F escape code must be emitted just before the opcode.

diff  --git a/llvm/test/MC/X86/tlsdesc-x32.s b/llvm/test/MC/X86/tlsdesc-x32.s
new file mode 100644
index 000000000000..a9884fb5e2ee
--- /dev/null
+++ b/llvm/test/MC/X86/tlsdesc-x32.s
@@ -0,0 +1,20 @@
+# RUN: llvm-mc -triple x86_64-pc-linux-gnux32 %s | FileCheck --check-prefix=PRINT %s
+
+# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnux32 %s -o %t
+# RUN: llvm-readelf -s %t | FileCheck --check-prefix=SYM %s
+# RUN: llvm-objdump -d -r %t | FileCheck --match-full-lines %s
+
+# PRINT:      leal a at tlsdesc(%rip), %eax
+# PRINT-NEXT: callq *a at tlscall(%eax)
+
+# SYM: TLS GLOBAL DEFAULT UND a
+
+# CHECK:      0: 40 8d 05 00 00 00 00  leal (%rip), %eax  # 7 <{{.*}}>
+# CHECK-NEXT:   00000003: R_X86_64_GOTPC32_TLSDESC a-0x4
+# CHECK-NEXT: 7: 67 ff 10              callq *(%eax)
+# CHECK-NEXT:   00000007: R_X86_64_TLSDESC_CALL a
+# CHECK-NEXT: a: 8d 05 34 12 00 00     leal 4660(%rip), %eax # {{.*}}
+
+lea a at tlsdesc(%rip), %eax
+call *a at tlscall(%eax)
+lea 0x1234(%rip), %eax


        


More information about the llvm-commits mailing list