Index: include/llvm/MC/MCContext.h =================================================================== --- include/llvm/MC/MCContext.h +++ include/llvm/MC/MCContext.h @@ -308,6 +308,9 @@ /// APIs. const SymbolTable &getSymbols() const { return Symbols; } + /// dumpSymbols - Dump the symbols to stderr. + void dumpSymbols() const; + /// @} /// \name Section Management Index: include/llvm/MC/MCSymbol.h =================================================================== --- include/llvm/MC/MCSymbol.h +++ include/llvm/MC/MCSymbol.h @@ -19,6 +19,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/MC/MCFragment.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" namespace llvm { class MCAsmInfo; Index: include/llvm/MC/MCSymbolCOFF.h =================================================================== --- include/llvm/MC/MCSymbolCOFF.h +++ include/llvm/MC/MCSymbolCOFF.h @@ -58,6 +58,14 @@ } static bool classof(const MCSymbol *S) { return S->isCOFF(); } + + void dump() const { + dbgs() << ": Format: COFF, Type: " << Type; + if (isSafeSEH()) + dbgs() << ", SafeSEH"; + if (isWeakExternal()) + dbgs() << ", Weak External"; + } }; } Index: include/llvm/MC/MCSymbolELF.h =================================================================== --- include/llvm/MC/MCSymbolELF.h +++ include/llvm/MC/MCSymbolELF.h @@ -46,6 +46,8 @@ static bool classof(const MCSymbol *S) { return S->isELF(); } + void dump() const; + private: void setIsBindingSet() const; }; Index: include/llvm/MC/MCSymbolMachO.h =================================================================== --- include/llvm/MC/MCSymbolMachO.h +++ include/llvm/MC/MCSymbolMachO.h @@ -129,6 +129,10 @@ return Flags; } + void dump() const { + dbgs() << ": Format: MachO"; + } + static bool classof(const MCSymbol *S) { return S->isMachO(); } }; } Index: lib/MC/MCContext.cpp =================================================================== --- lib/MC/MCContext.cpp +++ lib/MC/MCContext.cpp @@ -260,6 +260,23 @@ return Symbols.lookup(NameRef); } +void MCContext::dumpSymbols() const { + dbgs() << "Symbol table:\n"; + for (const auto &TableEntry : getSymbols()) { + MCSymbol *Sym = TableEntry.getValue(); + Sym->dump(); + if (Sym->isELF()) { + cast(Sym)->dump(); + } else if (Sym->isMachO()) { + cast(Sym)->dump(); + } else if (Sym->isCOFF()) { + cast(Sym)->dump(); + } else { + dbgs() << "Type: Unset?"; + } + dbgs() << "\n"; + } +} //===----------------------------------------------------------------------===// // Section Management //===----------------------------------------------------------------------===// Index: lib/MC/MCParser/AsmParser.cpp =================================================================== --- lib/MC/MCParser/AsmParser.cpp +++ lib/MC/MCParser/AsmParser.cpp @@ -45,6 +45,7 @@ #include "llvm/MC/MCValue.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" @@ -73,6 +74,9 @@ "asm-macro-max-nesting-depth", cl::init(20), cl::Hidden, cl::desc("The maximum nesting depth allowed for assembly macros.")); +static cl::opt ShowAsmSymbols("asm-show-symbol-table", cl::init(false), + cl::Hidden, cl::desc("Display the internal symbol table after parsing.")); + namespace { /// \brief Helper types for tracking macro definitions. @@ -801,6 +805,9 @@ if (!HadError && !NoFinalize) Out.Finish(); + // Display the internal symbol table if requested. + if (ShowAsmSymbols) { getContext().dumpSymbols(); } + return HadError || getContext().hadError(); } Index: lib/MC/MCParser/ELFAsmParser.cpp =================================================================== --- lib/MC/MCParser/ELFAsmParser.cpp +++ lib/MC/MCParser/ELFAsmParser.cpp @@ -166,6 +166,12 @@ MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + if (Attr == MCSA_Local) { + cast(Sym)->setBinding(ELF::STB_LOCAL); + } else if (Attr == MCSA_Weak) { + cast(Sym)->setBinding(ELF::STB_WEAK); + } + getStreamer().EmitSymbolAttribute(Sym, Attr); if (getLexer().is(AsmToken::EndOfStatement)) Index: lib/MC/MCSymbolELF.cpp =================================================================== --- lib/MC/MCSymbolELF.cpp +++ lib/MC/MCSymbolELF.cpp @@ -198,4 +198,48 @@ bool MCSymbolELF::isBindingSet() const { return getFlags() & (0x1 << ELF_BindingSet_Shift); } + +LLVM_DUMP_METHOD void MCSymbolELF::dump() const { + dbgs() << ": Format: ELF, Type: "; + switch (getType()) { + case ELF::STT_NOTYPE: + dbgs() << "STT_NOTYPE"; + break; + case ELF::STT_OBJECT: + dbgs() << "STT_OBJECT"; + break; + case ELF::STT_FUNC: + dbgs() << "STT_FUNC"; + break; + case ELF::STT_SECTION: + dbgs() << "STT_SECTION"; + break; + case ELF::STT_COMMON: + dbgs() << "STT_COMMON"; + break; + case ELF::STT_TLS: + dbgs() << "STT_TLS"; + break; + case ELF::STT_GNU_IFUNC: + dbgs() << "STT_GNU_IFUNC"; + break; + } + + if (isBindingSet()) { + switch (getBinding()) { + case ELF::STB_LOCAL: + dbgs() << ", Binding: STB_LOCAL"; + break; + case ELF::STB_GLOBAL: + dbgs() << ", Binding: STB_GLOBAL"; + break; + case ELF::STB_WEAK: + dbgs() << ", Binding: STB_WEAK"; + break; + case ELF::STB_GNU_UNIQUE: + dbgs() << ", Binding: STB_GNU_UNIQUE"; + break; + } + } +} } Index: test/MC/ELF/common.s =================================================================== --- test/MC/ELF/common.s +++ test/MC/ELF/common.s @@ -1,4 +1,5 @@ -// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -t | FileCheck %s +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -t | FileCheck -check-prefix=OBJ %s +// RUN: llvm-mc -triple x86_64-pc-linux-gnu %s -o - -asm-show-symbol-table 2>&1 | FileCheck -check-prefix=ASM %s .text @@ -8,60 +9,63 @@ .local common1 .comm common1,1,1 -// CHECK: Symbol { -// CHECK: Name: common1 -// CHECK-NEXT: Value: 0x0 -// CHECK-NEXT: Size: 1 -// CHECK-NEXT: Binding: Local -// CHECK-NEXT: Type: Object -// CHECK-NEXT: Other: 0 -// CHECK-NEXT: Section: -// CHECK-NEXT: } +// OBJ: Symbol { +// OBJ: Name: common1 +// OBJ-NEXT: Value: 0x0 +// OBJ-NEXT: Size: 1 +// OBJ-NEXT: Binding: Local +// OBJ-NEXT: Type: Object +// OBJ-NEXT: Other: 0 +// OBJ-NEXT: Section: +// OBJ-NEXT: } +// ASM: common1: Format: ELF, Type: STT_NOTYPE, Binding: STB_LOCAL // Same as common1, but with directives in a different order. .local common2 .type common2,@object .comm common2,1,1 -// CHECK: Symbol { -// CHECK: Name: common2 -// CHECK-NEXT: Value: 0x1 -// CHECK-NEXT: Size: 1 -// CHECK-NEXT: Binding: Local -// CHECK-NEXT: Type: Object -// CHECK-NEXT: Other: 0 -// CHECK-NEXT: Section: -// CHECK-NEXT: } +// OBJ: Symbol { +// OBJ: Name: common2 +// OBJ-NEXT: Value: 0x1 +// OBJ-NEXT: Size: 1 +// OBJ-NEXT: Binding: Local +// OBJ-NEXT: Type: Object +// OBJ-NEXT: Other: 0 +// OBJ-NEXT: Section: +// OBJ-NEXT: } +// ASM: common2: Format: ELF, Type: STT_NOTYPE, Binding: STB_LOCAL .local common6 .comm common6,8,16 -// CHECK: Symbol { -// CHECK: Name: common6 -// CHECK-NEXT: Value: 0x10 -// CHECK-NEXT: Size: 8 -// CHECK-NEXT: Binding: Local -// CHECK-NEXT: Type: Object -// CHECK-NEXT: Other: 0 -// CHECK-NEXT: Section: .bss -// CHECK-NEXT: } +// OBJ: Symbol { +// OBJ: Name: common6 +// OBJ-NEXT: Value: 0x10 +// OBJ-NEXT: Size: 8 +// OBJ-NEXT: Binding: Local +// OBJ-NEXT: Type: Object +// OBJ-NEXT: Other: 0 +// OBJ-NEXT: Section: .bss +// OBJ-NEXT: } +// ASM: common6: Format: ELF, Type: STT_NOTYPE, Binding: STB_LOCAL // Test that without an explicit .local we produce a global. .type common3,@object .comm common3,4,4 -// CHECK: Symbol { -// CHECK: Name: common3 -// CHECK-NEXT: Value: 0x4 -// CHECK-NEXT: Size: 4 -// CHECK-NEXT: Binding: Global -// CHECK-NEXT: Type: Object -// CHECK-NEXT: Other: 0 -// CHECK-NEXT: Section: Common (0xFFF2) -// CHECK-NEXT: } +// OBJ: Symbol { +// OBJ: Name: common3 +// OBJ-NEXT: Value: 0x4 +// OBJ-NEXT: Size: 4 +// OBJ-NEXT: Binding: Global +// OBJ-NEXT: Type: Object +// OBJ-NEXT: Other: 0 +// OBJ-NEXT: Section: Common (0xFFF2) +// OBJ-NEXT: } // Test that without an explicit .local we produce a global, even if the first @@ -75,25 +79,25 @@ .type common4,@object .comm common4,40,16 -// CHECK: Symbol { -// CHECK: Name: common4 -// CHECK-NEXT: Value: 0x10 -// CHECK-NEXT: Size: 40 -// CHECK-NEXT: Binding: Global -// CHECK-NEXT: Type: Object -// CHECK-NEXT: Other: 0 -// CHECK-NEXT: Section: Common (0xFFF2) -// CHECK-NEXT: } +// OBJ: Symbol { +// OBJ: Name: common4 +// OBJ-NEXT: Value: 0x10 +// OBJ-NEXT: Size: 40 +// OBJ-NEXT: Binding: Global +// OBJ-NEXT: Type: Object +// OBJ-NEXT: Other: 0 +// OBJ-NEXT: Section: Common (0xFFF2) +// OBJ-NEXT: } .comm common5,4,4 -// CHECK: Symbol { -// CHECK: Name: common5 -// CHECK-NEXT: Value: 0x4 -// CHECK-NEXT: Size: 4 -// CHECK-NEXT: Binding: Global -// CHECK-NEXT: Type: Object -// CHECK-NEXT: Other: 0 -// CHECK-NEXT: Section: Common (0xFFF2) -// CHECK-NEXT: } +// OBJ: Symbol { +// OBJ: Name: common5 +// OBJ-NEXT: Value: 0x4 +// OBJ-NEXT: Size: 4 +// OBJ-NEXT: Binding: Global +// OBJ-NEXT: Type: Object +// OBJ-NEXT: Other: 0 +// OBJ-NEXT: Section: Common (0xFFF2) +// OBJ-NEXT: } Index: test/MC/ELF/common2.s =================================================================== --- test/MC/ELF/common2.s +++ test/MC/ELF/common2.s @@ -1,4 +1,7 @@ -// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -s | FileCheck %s +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -s | FileCheck -check-prefix=OBJ %s +// RUN: llvm-mc -triple x86_64-pc-linux-gnu %s -o - -asm-show-symbol-table 2>&1 | FileCheck -check-prefix=ASM %s + + // Test local common construction. // Unlike gas, common symbols are created when found, not at the end of .bss. @@ -10,16 +13,18 @@ .zero 1 .align 8 -// CHECK: Section { -// CHECK: Name: .bss -// CHECK-NEXT: Type: -// CHECK-NEXT: Flags [ -// CHECK: ] -// CHECK-NEXT: Address: -// CHECK-NEXT: Offset: -// CHECK-NEXT: Size: 8 -// CHECK-NEXT: Link: -// CHECK-NEXT: Info: -// CHECK-NEXT: AddressAlignment: -// CHECK-NEXT: EntrySize: -// CHECK-NEXT: } +// OBJ: Section { +// OBJ: Name: .bss +// OBJ-NEXT: Type: +// OBJ-NEXT: Flags [ +// OBJ: ] +// OBJ-NEXT: Address: +// OBJ-NEXT: Offset: +// OBJ-NEXT: Size: 8 +// OBJ-NEXT: Link: +// OBJ-NEXT: Info: +// OBJ-NEXT: AddressAlignment: +// OBJ-NEXT: EntrySize: +// OBJ-NEXT: } + +// ASM: vimvardict: Format: ELF, Type: STT_NOTYPE, Binding: STB_LOCAL Index: test/MC/ELF/weak.s =================================================================== --- test/MC/ELF/weak.s +++ test/MC/ELF/weak.s @@ -1,4 +1,5 @@ -// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -t | FileCheck %s +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -t | FileCheck -check-prefix=OBJ %s +// RUN: llvm-mc -triple x86_64-pc-linux-gnu %s -o - -asm-show-symbol-table 2>&1 | FileCheck -check-prefix=ASM %s // Test that this produces a weak undefined symbol. @@ -9,22 +10,27 @@ .weak bar bar: -// CHECK: Symbol { -// CHECK: Name: bar -// CHECK-NEXT: Value: 0x4 -// CHECK-NEXT: Size: 0 -// CHECK-NEXT: Binding: Weak -// CHECK-NEXT: Type: None -// CHECK-NEXT: Other: 0 -// CHECK-NEXT: Section: .text -// CHECK-NEXT: } -// CHECK: Symbol { -// CHECK: Name: foo -// CHECK-NEXT: Value: 0x0 -// CHECK-NEXT: Size: 0 -// CHECK-NEXT: Binding: Weak -// CHECK-NEXT: Type: None -// CHECK-NEXT: Other: 0 -// CHECK-NEXT: Section: Undefined (0x0) -// CHECK-NEXT: } -// CHECK-NEXT: ] +// OBJ: Symbol { +// OBJ: Name: bar +// OBJ-NEXT: Value: 0x4 +// OBJ-NEXT: Size: 0 +// OBJ-NEXT: Binding: Weak +// OBJ-NEXT: Type: None +// OBJ-NEXT: Other: 0 +// OBJ-NEXT: Section: .text +// OBJ-NEXT: } +// OBJ: Symbol { +// OBJ: Name: foo +// OBJ-NEXT: Value: 0x0 +// OBJ-NEXT: Size: 0 +// OBJ-NEXT: Binding: Weak +// OBJ-NEXT: Type: None +// OBJ-NEXT: Other: 0 +// OBJ-NEXT: Section: Undefined (0x0) +// OBJ-NEXT: } +// OBJ-NEXT: ] + +// Test that the symbols have the correct bindings. + +// ASM: foo: Format: ELF, Type: STT_NOTYPE, Binding: STB_WEAK +// ASM: bar: Format: ELF, Type: STT_NOTYPE, Binding: STB_WEAK