ARM IAS: properly handle function entries in .thumb
authorSaleem Abdulrasool <compnerd@compnerd.org>
Sat, 22 Mar 2014 19:26:18 +0000 (19:26 +0000)
committerSaleem Abdulrasool <compnerd@compnerd.org>
Sat, 22 Mar 2014 19:26:18 +0000 (19:26 +0000)
When a label is parsed, check if there is type information available for the
label.  If so, check if the symbol is a function.  If the symbol is a function
and we are in thumb mode and no explicit thumb_func has been emitted, adjust the
symbol data to indicate that the function definition is a thumb function.

The application of this inferencing is improved value handling in the object
file (the required thumb bit is set on symbols which are thumb functions).  It
also helps improve compatibility with binutils.

The one complication that arises from this handling is the MCAsmStreamer.  The
default implementation of getOrCreateSymbolData in MCStreamer does not support
tracking the symbol data.  In order to support the semantics of thumb functions,
track symbol data in assembly streamer.  Although O(n) in number of labels in
the TU, this is already done in various other streamers and as such the memory
overhead is not a practical concern in this scenario.

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

lib/MC/MCAsmStreamer.cpp
lib/Target/ARM/AsmParser/ARMAsmParser.cpp
test/MC/ARM/thumb-types.s [new file with mode: 0644]
test/MC/ARM/thumb_set.s

index 759058efcba700b4655e21796685964f36dabb45..85d4dd79b30db82af91ca64ba5517c0b04007d25 100644 (file)
@@ -57,6 +57,8 @@ private:
                        EHPrivateExtern  = 1 << 2 };
   DenseMap<const MCSymbol*, unsigned> FlagMap;
 
+  DenseMap<const MCSymbol*, MCSymbolData*> SymbolMap;
+
   bool needsSet(const MCExpr *Value);
 
   void EmitRegisterName(int64_t Register);
@@ -252,6 +254,8 @@ public:
   void EmitRawTextImpl(StringRef String) override;
 
   void FinishImpl() override;
+
+  virtual MCSymbolData &getOrCreateSymbolData(const MCSymbol *Symbol) override;
 };
 
 } // end anonymous namespace.
@@ -1417,6 +1421,15 @@ void MCAsmStreamer::FinishImpl() {
     EmitFrames(AsmBackend.get(), false);
 }
 
+MCSymbolData &MCAsmStreamer::getOrCreateSymbolData(const MCSymbol *Symbol) {
+  MCSymbolData *&Entry = SymbolMap[Symbol];
+
+  if (!Entry)
+    Entry = new MCSymbolData(*Symbol, 0, 0, 0);
+
+  return *Entry;
+}
+
 MCStreamer *llvm::createAsmStreamer(MCContext &Context,
                                     formatted_raw_ostream &OS,
                                     bool isVerboseAsm, bool useCFI,
index ccb1c641efeb725ad3c3d1a4ca8e6484628f57a4..1a153522796307b1913b99f04d2838cf05ef6225 100644 (file)
@@ -25,7 +25,9 @@
 #include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDisassembler.h"
+#include "llvm/MC/MCELF.h"
 #include "llvm/MC/MCELFStreamer.h"
+#include "llvm/MC/MCELFSymbolFlags.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCInstrDesc.h"
@@ -8085,6 +8087,7 @@ bool ARMAsmParser::parseDirectiveThumb(SMLoc L) {
 
   if (!isThumb())
     SwitchMode();
+
   getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16);
   return false;
 }
@@ -8105,6 +8108,7 @@ bool ARMAsmParser::parseDirectiveARM(SMLoc L) {
 
   if (isThumb())
     SwitchMode();
+
   getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32);
   return false;
 }
@@ -8113,6 +8117,32 @@ void ARMAsmParser::onLabelParsed(MCSymbol *Symbol) {
   if (NextSymbolIsThumb) {
     getParser().getStreamer().EmitThumbFunc(Symbol);
     NextSymbolIsThumb = false;
+    return;
+  }
+
+  if (!isThumb())
+    return;
+
+  const MCObjectFileInfo::Environment Format =
+    getContext().getObjectFileInfo()->getObjectFileType();
+  switch (Format) {
+  case MCObjectFileInfo::IsCOFF: {
+    const MCSymbolData &SD =
+      getParser().getStreamer().getOrCreateSymbolData(Symbol);
+    char Type = COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT;
+    if (SD.getFlags() & (Type << COFF::SF_TypeShift))
+      getParser().getStreamer().EmitThumbFunc(Symbol);
+    break;
+  }
+  case MCObjectFileInfo::IsELF: {
+    const MCSymbolData &SD =
+      getParser().getStreamer().getOrCreateSymbolData(Symbol);
+    if (MCELF::GetType(SD) & (ELF::STT_FUNC << ELF_STT_Shift))
+      getParser().getStreamer().EmitThumbFunc(Symbol);
+    break;
+  }
+  case MCObjectFileInfo::IsMachO:
+    break;
   }
 }
 
diff --git a/test/MC/ARM/thumb-types.s b/test/MC/ARM/thumb-types.s
new file mode 100644 (file)
index 0000000..2fd7152
--- /dev/null
@@ -0,0 +1,82 @@
+@ RUN: llvm-mc -triple armv7-elf -filetype obj -o - %s | llvm-readobj -t \
+@ RUN:    | FileCheck %s
+
+       .syntax unified
+
+       .thumb
+
+       .type implicit_function,%function
+implicit_function:
+       nop
+
+       .type implicit_data,%object
+implicit_data:
+       .long 0
+
+       .arm
+       .type arm_function,%function
+arm_function:
+       nop
+
+       .thumb
+
+       .text
+
+untyped_text_label:
+       nop
+
+       .type explicit_function,%function
+explicit_function:
+       nop
+
+       .data
+
+untyped_data_label:
+       nop
+
+       .type explicit_data,%object
+explicit_data:
+       .long 0
+
+@ CHECK: Symbol {
+@ CHECK:   Name: arm_function
+@ CHECK:   Value: 0x6
+@ CHECK:   Type: Function
+@ CHECK: }
+
+@ CHECK: Symbol {
+@ CHECK:   Name: explicit_data
+@ CHECK:   Value: 0x2
+@ CHECK:   Type: Object
+@ CHECK: }
+
+@ CHECK: Symbol {
+@ CHECK:   Name: explicit_function
+@ CHECK:   Value: 0xD
+@ CHECK:   Type: Function
+@ CHECK: }
+
+@ CHECK: Symbol {
+@ CHECK:   Name: implicit_data
+@ CHECK:   Value: 0x2
+@ CHECK:   Type: Object
+@ CHECK: }
+
+@ CHECK: Symbol {
+@ CHECK:   Name: implicit_function
+@ CHECK:   Value: 0x1
+@ CHECK:   Type: Function
+@ CHECK: }
+
+@ CHECK: Symbol {
+@ CHECK:   Name: untyped_data_label
+@ CHECK:   Value: 0x0
+@ CHECK:   Type: None
+@ CHECK: }
+
+@ CHECK: Symbol {
+@ CHECK:   Name: untyped_text_label
+@ CHECK:   Value: 0xA
+@ CHECK:   Type: None
+@ CHECK: }
+
index 7381a98134d8269f8b8a9835034187438efe956a..d0bc9858ddc09f9decf0021f9e9432cd9abe20d2 100644 (file)
@@ -79,8 +79,7 @@ beta:
 
 @ CHECK: Symbol {
 @ CHECK:   Name: alpha
-@ CHECK:   Value: 0x6
-@ XFAIL-CHECK:   Value: 0x7
+@ CHECK:   Value: 0x7
 @ CHECK:   Type: Function
 @ CHECK: }