[llvm-branch-commits] [llvm] 25d8502 - [PPC32] Parse bl __tls_get_addr(x at tlsgd)@plt+32768

Tobias Hieta via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Aug 8 23:59:25 PDT 2023


Author: Fangrui Song
Date: 2023-08-09T08:56:03+02:00
New Revision: 25d8502b7802404c1544a99020def3e29e6cf96e

URL: https://github.com/llvm/llvm-project/commit/25d8502b7802404c1544a99020def3e29e6cf96e
DIFF: https://github.com/llvm/llvm-project/commit/25d8502b7802404c1544a99020def3e29e6cf96e.diff

LOG: [PPC32] Parse bl __tls_get_addr(x at tlsgd)@plt+32768

PPC32 -fpic/-fPIC generates `bl __tls_get_addr(x at tlsgd)@PLT` or
`bl __tls_get_addr(x at tlsgd)@PLT+32768`.
`powerpc-linux-gnu-gcc -fPIC` generates `bl __tls_get_addr+32668(x at tlsgd)@plt`.

These expressions can be parsed by GNU assembler but not by the integrated
assembler. Add the support.

Differential Revision: https://reviews.llvm.org/D153206

(cherry picked from commit 6e07e90890d61b1be19d3f5fbf00ea7430068325)

Added: 
    llvm/test/MC/PowerPC/ppc32-tls.s

Modified: 
    llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
    llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
index 56fdf19a0720c3..4f93cdaaa13764 100644
--- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
+++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
@@ -1544,24 +1544,58 @@ bool PPCAsmParser::ParseOperand(OperandVector &Operands) {
   Operands.push_back(PPCOperand::CreateFromMCExpr(EVal, S, E, isPPC64()));
 
   // Check whether this is a TLS call expression
-  bool TLSCall = false;
-  if (const MCSymbolRefExpr *Ref = dyn_cast<MCSymbolRefExpr>(EVal))
-    TLSCall = Ref->getSymbol().getName() == "__tls_get_addr";
+  const char TlsGetAddr[] = "__tls_get_addr";
+  bool TlsCall = false;
+  const MCExpr *TlsCallAddend = nullptr;
+  if (auto *Ref = dyn_cast<MCSymbolRefExpr>(EVal)) {
+    TlsCall = Ref->getSymbol().getName() == TlsGetAddr;
+  } else if (auto *Bin = dyn_cast<MCBinaryExpr>(EVal);
+             Bin && Bin->getOpcode() == MCBinaryExpr::Add) {
+    if (auto *Ref = dyn_cast<MCSymbolRefExpr>(Bin->getLHS())) {
+      TlsCall = Ref->getSymbol().getName() == TlsGetAddr;
+      TlsCallAddend = Bin->getRHS();
+    }
+  }
 
-  if (TLSCall && parseOptionalToken(AsmToken::LParen)) {
+  if (TlsCall && parseOptionalToken(AsmToken::LParen)) {
     const MCExpr *TLSSym;
-    S = Parser.getTok().getLoc();
+    const SMLoc S2 = Parser.getTok().getLoc();
     if (ParseExpression(TLSSym))
-      return Error(S, "invalid TLS call expression");
+      return Error(S2, "invalid TLS call expression");
+    E = Parser.getTok().getLoc();
     if (parseToken(AsmToken::RParen, "expected ')'"))
       return true;
-    E = Parser.getTok().getLoc();
+    // PPC32 allows bl __tls_get_addr[+a](x at tlsgd)@plt+b. Parse "@plt[+b]".
+    if (!isPPC64() && parseOptionalToken(AsmToken::At)) {
+      AsmToken Tok = getTok();
+      if (!(parseOptionalToken(AsmToken::Identifier) &&
+            Tok.getString().compare_insensitive("plt") == 0))
+        return Error(Tok.getLoc(), "expected 'plt'");
+      EVal = MCSymbolRefExpr::create(TlsGetAddr, MCSymbolRefExpr::VK_PLT,
+                                     getContext());
+      if (parseOptionalToken(AsmToken::Plus)) {
+        const MCExpr *Addend = nullptr;
+        SMLoc EndLoc;
+        if (parsePrimaryExpr(Addend, EndLoc))
+          return true;
+        if (TlsCallAddend) // __tls_get_addr+a(x at tlsgd)@plt+b
+          TlsCallAddend =
+              MCBinaryExpr::createAdd(TlsCallAddend, Addend, getContext());
+        else // __tls_get_addr(x at tlsgd)@plt+b
+          TlsCallAddend = Addend;
+      }
+      if (TlsCallAddend)
+        EVal = MCBinaryExpr::createAdd(EVal, TlsCallAddend, getContext());
+      // Add a __tls_get_addr operand with addend a, b, or a+b.
+      Operands.back() = PPCOperand::CreateFromMCExpr(
+          EVal, S, Parser.getTok().getLoc(), false);
+    }
 
     Operands.push_back(PPCOperand::CreateFromMCExpr(TLSSym, S, E, isPPC64()));
   }
 
   // Otherwise, check for D-form memory operands
-  if (!TLSCall && parseOptionalToken(AsmToken::LParen)) {
+  if (!TlsCall && parseOptionalToken(AsmToken::LParen)) {
     S = Parser.getTok().getLoc();
 
     int64_t IntVal;

diff  --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
index dbdfb6e906bbee..13480da4e7317e 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
@@ -564,10 +564,10 @@ void PPCInstPrinter::printTLSCall(const MCInst *MI, unsigned OpNo,
   // come at the _end_ of the expression.
   const MCOperand &Op = MI->getOperand(OpNo);
   const MCSymbolRefExpr *RefExp = nullptr;
-  const MCConstantExpr *ConstExp = nullptr;
+  const MCExpr *Rhs = nullptr;
   if (const MCBinaryExpr *BinExpr = dyn_cast<MCBinaryExpr>(Op.getExpr())) {
     RefExp = cast<MCSymbolRefExpr>(BinExpr->getLHS());
-    ConstExp = cast<MCConstantExpr>(BinExpr->getRHS());
+    Rhs = BinExpr->getRHS();
   } else
     RefExp = cast<MCSymbolRefExpr>(Op.getExpr());
 
@@ -584,8 +584,14 @@ void PPCInstPrinter::printTLSCall(const MCInst *MI, unsigned OpNo,
   if (RefExp->getKind() != MCSymbolRefExpr::VK_None &&
       RefExp->getKind() != MCSymbolRefExpr::VK_PPC_NOTOC)
     O << '@' << MCSymbolRefExpr::getVariantKindName(RefExp->getKind());
-  if (ConstExp != nullptr)
-    O << '+' << ConstExp->getValue();
+  if (Rhs) {
+    SmallString<0> Buf;
+    raw_svector_ostream Tmp(Buf);
+    Rhs->print(Tmp, &MAI);
+    if (isdigit(Buf[0]))
+      O << '+';
+    O << Buf;
+  }
 }
 
 /// showRegistersWithPercentPrefix - Check if this register name should be

diff  --git a/llvm/test/MC/PowerPC/ppc32-tls.s b/llvm/test/MC/PowerPC/ppc32-tls.s
new file mode 100644
index 00000000000000..3acf40e57f7f3d
--- /dev/null
+++ b/llvm/test/MC/PowerPC/ppc32-tls.s
@@ -0,0 +1,53 @@
+# RUN: llvm-mc -triple=powerpc %s | FileCheck %s --check-prefix=ASM
+# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s
+
+# RUN: not llvm-mc -triple=powerpc --defsym ERR=1 %s 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error:
+
+# ASM: bl __tls_get_addr(a at tlsgd)
+# ASM: bl __tls_get_addr(b at tlsld)
+# ASM: bl __tls_get_addr(c at tlsgd)@PLT
+# ASM: bl __tls_get_addr(d at tlsld)@PLT+32768
+# ASM: bl __tls_get_addr(e at tlsld)@PLT+32768
+bl __tls_get_addr(a at tlsgd)
+bl __tls_get_addr(b at tlsld)
+bl __tls_get_addr(c at tlsgd)@plt
+bl __tls_get_addr(d at tlsld)@PLT+32768
+bl __tls_get_addr+32768(e at tlsld)@plt  # gcc -fPIC
+
+## These are not present in the wild, but just to test we can parse them.
+# ASM: bl __tls_get_addr(f at tlsld)@PLT+1+(-2)
+bl __tls_get_addr+1(f at tlsld)@PLT+-2
+# ASM: bl __tls_get_addr(g at tlsld)@PLT+1+(y-x)
+x:
+bl __tls_get_addr+1(g at tlsld)@PLT+(y-x)
+y:
+
+# CHECK:      .rela.text {
+# CHECK-NEXT:   0x0 R_PPC_TLSGD a 0x0
+# CHECK-NEXT:   0x0 R_PPC_REL24 __tls_get_addr 0x0
+# CHECK-NEXT:   0x4 R_PPC_TLSLD b 0x0
+# CHECK-NEXT:   0x4 R_PPC_REL24 __tls_get_addr 0x0
+# CHECK-NEXT:   0x8 R_PPC_TLSGD c 0x0
+# CHECK-NEXT:   0x8 R_PPC_PLTREL24 __tls_get_addr 0x0
+# CHECK-NEXT:   0xC R_PPC_TLSLD d 0x0
+# CHECK-NEXT:   0xC R_PPC_PLTREL24 __tls_get_addr 0x8000
+# CHECK-NEXT:   0x10 R_PPC_TLSLD e 0x0
+# CHECK-NEXT:   0x10 R_PPC_PLTREL24 __tls_get_addr 0x8000
+# CHECK-NEXT:   0x14 R_PPC_TLSLD f 0x0
+# CHECK-NEXT:   0x14 R_PPC_PLTREL24 __tls_get_addr 0xFFFFFFFF
+# CHECK-NEXT:   0x18 R_PPC_TLSLD g 0x0
+# CHECK-NEXT:   0x18 R_PPC_PLTREL24 __tls_get_addr 0x5
+# CHECK-NEXT: }
+
+.ifdef ERR
+# ERR: :[[#@LINE+1]]:27: error: unexpected token
+bl __tls_get_addr(d at tlsld)plt
+# ERR: :[[#@LINE+1]]:28: error: expected 'plt'
+bl __tls_get_addr(d at tlsld)@invalid
+# ERR: :[[#@LINE+1]]:31: error: unexpected token
+bl __tls_get_addr(d at tlsld)@plt-32768
+
+# ERR: :[[#@LINE+1]]:21: error: invalid memory operand
+bl __tls_get_addr-1(f at tlsld)@plt
+.endif


        


More information about the llvm-branch-commits mailing list