ARM: suuport .tlsdescseq directive
authorSaleem Abdulrasool <compnerd@compnerd.org>
Thu, 30 Jan 2014 04:02:47 +0000 (04:02 +0000)
committerSaleem Abdulrasool <compnerd@compnerd.org>
Thu, 30 Jan 2014 04:02:47 +0000 (04:02 +0000)
This enhances the ARMAsmParser to handle .tlsdescseq directives.  This is a
slightly special relocation.  We must be able to generate them, but not consume
them in assembly.  The relocation is meant to assist the linker in generating a
TLS descriptor sequence.  The ELF target streamer is enhanced to append
additional fixups into the current segment and that is used to emit the new
R_ARM_TLS_DESCSEQ relocations.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@200448 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/MC/MCExpr.h
include/llvm/MC/MCStreamer.h
lib/MC/MCExpr.cpp
lib/Target/ARM/AsmParser/ARMAsmParser.cpp
lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
test/MC/ARM/directive-tlsdescseq-diagnostics.s [new file with mode: 0644]
test/MC/ARM/directive-tlsdescseq.s [new file with mode: 0644]

index 13f3ad0570b23bdce24b26a52990375364790868..133bd5280d7cb9def0e081f84c32ea0b22adc56c 100644 (file)
@@ -168,6 +168,7 @@ public:
     VK_ARM_TLSLDO,         // symbol(tlsldo)
     VK_ARM_TLSCALL,        // symbol(tlscall)
     VK_ARM_TLSDESC,        // symbol(tlsdesc)
+    VK_ARM_TLSDESCSEQ,
 
     VK_PPC_LO,             // symbol@l
     VK_PPC_HI,             // symbol@h
index 3eb5446f5309afe6dd9e2903ddec9afde36f81cf..bb4adfcf86233816f89d0d55767873c183265f79 100644 (file)
@@ -33,6 +33,7 @@ class MCInstPrinter;
 class MCSection;
 class MCStreamer;
 class MCSymbol;
+class MCSymbolRefExpr;
 class MCSubtargetInfo;
 class StringRef;
 class Twine;
@@ -107,6 +108,8 @@ public:
   virtual void emitArch(unsigned Arch) = 0;
   virtual void finishAttributeSection() = 0;
   virtual void emitInst(uint32_t Inst, char Suffix = '\0') = 0;
+
+  virtual void AnnotateTLSDescriptorSequence(const MCSymbolRefExpr *SRE) = 0;
 };
 
 /// MCStreamer - Streaming machine code generation interface.  This interface
index d402e6d896b81b08039d839bc3fd2cee9110e7f1..75bde8ed36be4be3736132628bdf3f16acc406ac 100644 (file)
@@ -187,6 +187,7 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) {
   case VK_ARM_TLSLDO: return "tlsldo";
   case VK_ARM_TLSCALL: return "tlscall";
   case VK_ARM_TLSDESC: return "tlsdesc";
+  case VK_ARM_TLSDESCSEQ: return "tlsdescseq";
   case VK_PPC_LO: return "l";
   case VK_PPC_HI: return "h";
   case VK_PPC_HA: return "ha";
index 2f9a12f2c77eaeef2ac46411af0e682d8b048be6..2b4eaf0f15c90ce935980f4e77bf9f5230d8a214 100644 (file)
@@ -296,6 +296,7 @@ class ARMAsmParser : public MCTargetAsmParser {
   bool parseDirectiveEven(SMLoc L);
   bool parseDirectivePersonalityIndex(SMLoc L);
   bool parseDirectiveUnwindRaw(SMLoc L);
+  bool parseDirectiveTLSDescSeq(SMLoc L);
 
   StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode,
                           bool &CarrySetting, unsigned &ProcessorIMod,
@@ -8084,6 +8085,8 @@ bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) {
     return parseDirectivePersonalityIndex(DirectiveID.getLoc());
   else if (IDVal == ".unwind_raw")
     return parseDirectiveUnwindRaw(DirectiveID.getLoc());
+  else if (IDVal == ".tlsdescseq")
+    return parseDirectiveTLSDescSeq(DirectiveID.getLoc());
   return true;
 }
 
@@ -9001,6 +9004,30 @@ bool ARMAsmParser::parseDirectiveUnwindRaw(SMLoc L) {
   return false;
 }
 
+/// parseDirectiveTLSDescSeq
+///   ::= .tlsdescseq tls-variable
+bool ARMAsmParser::parseDirectiveTLSDescSeq(SMLoc L) {
+  if (getLexer().isNot(AsmToken::Identifier)) {
+    TokError("expected variable after '.tlsdescseq' directive");
+    Parser.eatToEndOfStatement();
+    return false;
+  }
+
+  const MCSymbolRefExpr *SRE =
+    MCSymbolRefExpr::Create(Parser.getTok().getIdentifier(),
+                            MCSymbolRefExpr::VK_ARM_TLSDESCSEQ, getContext());
+  Lex();
+
+  if (getLexer().isNot(AsmToken::EndOfStatement)) {
+    Error(Parser.getTok().getLoc(), "unexpected token");
+    Parser.eatToEndOfStatement();
+    return false;
+  }
+
+  getTargetStreamer().AnnotateTLSDescriptorSequence(SRE);
+  return false;
+}
+
 /// Force static initialization.
 extern "C" void LLVMInitializeARMAsmParser() {
   RegisterMCAsmParser<ARMAsmParser> X(TheARMTarget);
index 5f719d5bb7c7277a842db4a56c065f4fbaf4852a..d9a1453cc35186e30e013d306467d22299a768e6 100644 (file)
@@ -269,6 +269,9 @@ unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
       case MCSymbolRefExpr::VK_ARM_TLSDESC:
         Type = ELF::R_ARM_TLS_GOTDESC;
         break;
+      case MCSymbolRefExpr::VK_ARM_TLSDESCSEQ:
+        Type = ELF::R_ARM_TLS_DESCSEQ;
+        break;
       }
       break;
     case ARM::fixup_arm_ldst_pcrel_12:
index efee318a0471993e209ee101ee13b2e8d6c7fa79..c2e3503278bba645c0a2a81ba03bf20da050f376 100644 (file)
@@ -139,6 +139,8 @@ class ARMTargetAsmStreamer : public ARMTargetStreamer {
   virtual void emitInst(uint32_t Inst, char Suffix = '\0');
   virtual void finishAttributeSection();
 
+  virtual void AnnotateTLSDescriptorSequence(const MCSymbolRefExpr *SRE);
+
 public:
   ARMTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS,
                        MCInstPrinter &InstPrinter, bool VerboseAsm);
@@ -241,6 +243,10 @@ void ARMTargetAsmStreamer::emitFPU(unsigned FPU) {
 }
 void ARMTargetAsmStreamer::finishAttributeSection() {
 }
+void
+ARMTargetAsmStreamer::AnnotateTLSDescriptorSequence(const MCSymbolRefExpr *S) {
+  OS << "\t.tlsdescseq\t" << S->getSymbol().getName();
+}
 
 void ARMTargetAsmStreamer::emitInst(uint32_t Inst, char Suffix) {
   OS << "\t.inst";
@@ -397,6 +403,8 @@ private:
   virtual void emitInst(uint32_t Inst, char Suffix = '\0');
   virtual void finishAttributeSection();
 
+  virtual void AnnotateTLSDescriptorSequence(const MCSymbolRefExpr *SRE);
+
   size_t calculateContentSize() const;
 
 public:
@@ -605,6 +613,8 @@ private:
   void SwitchToExTabSection(const MCSymbol &FnStart);
   void SwitchToExIdxSection(const MCSymbol &FnStart);
 
+  void EmitFixup(const MCExpr *Expr, MCFixupKind Kind);
+
   bool IsThumb;
   int64_t MappingSymbolCounter;
 
@@ -953,6 +963,10 @@ void ARMTargetELFStreamer::finishAttributeSection() {
   Contents.clear();
   FPU = ARM::INVALID_FPU;
 }
+void
+ARMTargetELFStreamer::AnnotateTLSDescriptorSequence(const MCSymbolRefExpr *S) {
+  getStreamer().EmitFixup(S, FK_Data_4);
+}
 void ARMTargetELFStreamer::emitInst(uint32_t Inst, char Suffix) {
   getStreamer().emitInst(Inst, Suffix);
 }
@@ -1011,6 +1025,11 @@ inline void ARMELFStreamer::SwitchToExIdxSection(const MCSymbol &FnStart) {
                     SectionKind::getDataRel(),
                     FnStart);
 }
+void ARMELFStreamer::EmitFixup(const MCExpr *Expr, MCFixupKind Kind) {
+  MCDataFragment *Frag = getOrCreateDataFragment();
+  Frag->getFixups().push_back(MCFixup::Create(Frag->getContents().size(), Expr,
+                                              Kind));
+}
 
 void ARMELFStreamer::Reset() {
   ExTab = NULL;
diff --git a/test/MC/ARM/directive-tlsdescseq-diagnostics.s b/test/MC/ARM/directive-tlsdescseq-diagnostics.s
new file mode 100644 (file)
index 0000000..0d33b58
--- /dev/null
@@ -0,0 +1,35 @@
+@ RUN: not llvm-mc -triple armv7-linux-gnu -filetype asm -o /dev/null %s 2>&1 \
+@ RUN:   | FileCheck %s
+
+       .type missing_variable,%function
+missing_variable:
+.tlsdescseq
+
+@ CHECK: error: expected variable after '.tlsdescseq' directive
+@ CHECK:       .tlsdescseq
+@ CHECK:                   ^
+
+       .type bad_expression,%function
+bad_expression:
+.tlsdescseq variable(tlsdesc)
+
+@ CHECK: error: unexpected token
+@ CHECK:       .tlsdescseq variable(tlsdesc)
+@ CHECK:                            ^
+
+       .type trailing_garbage,%function
+trailing_garbage:
+.tlsdescseq variable,
+
+@ CHECK: error: unexpected token
+@ CHECK:       .tlsdescseq variable,
+@ CHECK:                            ^
+
+       .type invalid_use,%function
+invalid_use:
+       blx invalid(tlsdescseq)
+
+@ CHECK: error: invalid variant 'tlsdescseq'
+@ CHECK:       blx invalid(tlsdescseq)
+@ CHECK:                    ^
+
diff --git a/test/MC/ARM/directive-tlsdescseq.s b/test/MC/ARM/directive-tlsdescseq.s
new file mode 100644 (file)
index 0000000..12db058
--- /dev/null
@@ -0,0 +1,33 @@
+@ RUN: llvm-mc -triple armv7-linux-gnu -filetype obj -o - %s | llvm-readobj -r \
+@ RUN:   | FileCheck %s
+@ RUN: llvm-mc -triple armv7-linux-gnu -filetype asm -o - %s \
+@ RUN:   | FileCheck -check-prefix CHECK-ASM %s
+
+       .type tlsdescseq,%function
+tlsdescseq:
+       ldr r1, [pc, #8]
+1:
+.tlsdescseq variable
+       add r2, pc, r1
+.tlsdescseq variable
+       ldr r3, [r1, #4]
+.tlsdescseq variable
+       blx r3
+2:
+       .word variable(tlsdesc) + (. - 1b)
+
+@ CHECK: Relocations [
+@ CHECK:     0x4 R_ARM_TLS_DESCSEQ variable 0x0
+@ CHECK:     0x8 R_ARM_TLS_DESCSEQ variable 0x0
+@ CHECK:     0xC R_ARM_TLS_DESCSEQ variable 0x0
+@ CHECK:     0x10 R_ARM_TLS_GOTDESC variable 0x0
+@ CHECK: ]
+
+@ CHECK-ASM: ldr r1, [pc, #8]
+@ CHECK-ASM: .tlsdescseq variable
+@ CHECK-ASM: add r2, pc, r1
+@ CHECK-ASM: .tlsdescseq variable
+@ CHECK-ASM: ldr r3, [r1, #4]
+@ CHECK-ASM: .tlsdescseq variable
+@ CHECK-ASM: blx r3
+