diff --git a/llvm/lib/MC/WinCOFFObjectWriter.cpp b/llvm/lib/MC/WinCOFFObjectWriter.cpp index cb5998437b0a..ac4a5bdcd500 100644 --- a/llvm/lib/MC/WinCOFFObjectWriter.cpp +++ b/llvm/lib/MC/WinCOFFObjectWriter.cpp @@ -155,6 +155,8 @@ public: object_t *createCOFFEntity(StringRef Name, list_t &List); void defineSection(MCSectionCOFF const &Sec); + + COFFSymbol *getLinkedSymbol(const MCSymbol &Symbol); void DefineSymbol(const MCSymbol &Symbol, MCAssembler &Assembler, const MCAsmLayout &Layout); @@ -353,6 +355,21 @@ static uint64_t getSymbolValue(const MCSymbol &Symbol, return Res; } +COFFSymbol *WinCOFFObjectWriter::getLinkedSymbol(const MCSymbol &Symbol) { + if (!Symbol.isVariable()) + return nullptr; + + const MCSymbolRefExpr *SymRef = + dyn_cast(Symbol.getVariableValue()); + if (!SymRef) + return nullptr; + + const MCSymbol &Aliasee = SymRef->getSymbol(); + if (!Aliasee.isUndefined()) + return nullptr; + return GetOrCreateCOFFSymbol(&Aliasee); +} + /// This function takes a symbol data object from the assembler /// and creates the associated COFF symbol staging object. void WinCOFFObjectWriter::DefineSymbol(const MCSymbol &Symbol, @@ -367,32 +384,23 @@ void WinCOFFObjectWriter::DefineSymbol(const MCSymbol &Symbol, report_fatal_error("conflicting sections for symbol"); } + COFFSymbol *Local = nullptr; if (cast(Symbol).isWeakExternal()) { coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL; - if (Symbol.isVariable()) { - const MCSymbolRefExpr *SymRef = - dyn_cast(Symbol.getVariableValue()); - - if (!SymRef) - report_fatal_error("Weak externals may only alias symbols"); - - coff_symbol->Other = GetOrCreateCOFFSymbol(&SymRef->getSymbol()); - } else { + COFFSymbol *WeakDefault = getLinkedSymbol(Symbol); + if (!WeakDefault) { std::string WeakName = (".weak." + Symbol.getName() + ".default").str(); - COFFSymbol *WeakDefault = createSymbol(WeakName); - + WeakDefault = createSymbol(WeakName); if (!Sec) WeakDefault->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE; else WeakDefault->Section = Sec; - - WeakDefault->Data.StorageClass = COFF::IMAGE_SYM_CLASS_EXTERNAL; - WeakDefault->Data.Type = 0; - WeakDefault->Data.Value = getSymbolValue(Symbol, Layout); - coff_symbol->Other = WeakDefault; + Local = WeakDefault; } + coff_symbol->Other = WeakDefault; + // Setup the Weak External auxiliary symbol. coff_symbol->Aux.resize(1); memset(&coff_symbol->Aux[0], 0, sizeof(coff_symbol->Aux[0])); @@ -400,32 +408,32 @@ void WinCOFFObjectWriter::DefineSymbol(const MCSymbol &Symbol, coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = 0; coff_symbol->Aux[0].Aux.WeakExternal.Characteristics = COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY; - - coff_symbol->MC = &Symbol; } else { - coff_symbol->Data.Value = getSymbolValue(Symbol, Layout); - - const MCSymbolCOFF &SymbolCOFF = cast(Symbol); - coff_symbol->Data.Type = SymbolCOFF.getType(); - coff_symbol->Data.StorageClass = SymbolCOFF.getClass(); - - // If no storage class was specified in the streamer, define it here. - if (coff_symbol->Data.StorageClass == COFF::IMAGE_SYM_CLASS_NULL) { - bool IsExternal = Symbol.isExternal() || - (!Symbol.getFragment() && !Symbol.isVariable()); - - coff_symbol->Data.StorageClass = IsExternal - ? COFF::IMAGE_SYM_CLASS_EXTERNAL - : COFF::IMAGE_SYM_CLASS_STATIC; - } - if (!Base) coff_symbol->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE; else coff_symbol->Section = Sec; - - coff_symbol->MC = &Symbol; + Local = coff_symbol; } + + if (Local) { + Local->Data.Value = getSymbolValue(Symbol, Layout); + + const MCSymbolCOFF &SymbolCOFF = cast(Symbol); + Local->Data.Type = SymbolCOFF.getType(); + Local->Data.StorageClass = SymbolCOFF.getClass(); + + // If no storage class was specified in the streamer, define it here. + if (Local->Data.StorageClass == COFF::IMAGE_SYM_CLASS_NULL) { + bool IsExternal = Symbol.isExternal() || + (!Symbol.getFragment() && !Symbol.isVariable()); + + Local->Data.StorageClass = IsExternal ? COFF::IMAGE_SYM_CLASS_EXTERNAL + : COFF::IMAGE_SYM_CLASS_STATIC; + } + } + + coff_symbol->MC = &Symbol; } // Maximum offsets for different string table entry encodings. diff --git a/llvm/test/MC/COFF/weak-alias-local.s b/llvm/test/MC/COFF/weak-alias-local.s new file mode 100644 index 000000000000..01f2ac390a59 --- /dev/null +++ b/llvm/test/MC/COFF/weak-alias-local.s @@ -0,0 +1,43 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-win32 %s -o %t.o +// RUN: llvm-readobj -t %t.o | FileCheck %s + +// test that we create an external symbol for a to point to. + + .data + .long 123 +b: + .long 42 + .weak a +a=b + +// CHECK: Symbol { +// CHECK: Name: b +// CHECK-NEXT: Value: 4 +// CHECK-NEXT: Section: .data (2) +// CHECK-NEXT: BaseType: Null (0x0) +// CHECK-NEXT: ComplexType: Null (0x0) +// CHECK-NEXT: StorageClass: Static (0x3) +// CHECK-NEXT: AuxSymbolCount: 0 +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: a +// CHECK-NEXT: Value: 0 +// CHECK-NEXT: Section: IMAGE_SYM_UNDEFINED (0) +// CHECK-NEXT: BaseType: Null (0x0) +// CHECK-NEXT: ComplexType: Null (0x0) +// CHECK-NEXT: StorageClass: WeakExternal (0x69) +// CHECK-NEXT: AuxSymbolCount: 1 +// CHECK-NEXT: AuxWeakExternal { +// CHECK-NEXT: Linked: .weak.a.default (9) +// CHECK-NEXT: Search: Library (0x2) +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: .weak.a.default +// CHECK-NEXT: Value: 4 +// CHECK-NEXT: Section: .data (2) +// CHECK-NEXT: BaseType: Null (0x0) +// CHECK-NEXT: ComplexType: Null (0x0) +// CHECK-NEXT: StorageClass: External (0x2) +// CHECK-NEXT: AuxSymbolCount: 0 +// CHECK-NEXT: } diff --git a/llvm/test/MC/COFF/weak.s b/llvm/test/MC/COFF/weak.s index 6086749d80de..e0d077840f15 100644 --- a/llvm/test/MC/COFF/weak.s +++ b/llvm/test/MC/COFF/weak.s @@ -34,6 +34,16 @@ LBB0_2: # %return // CHECK: Symbols [ +// CHECK: Symbol { +// CHECK: Name: _main +// CHECK-NEXT: Value: 0 +// CHECK-NEXT: Section: .text +// CHECK-NEXT: BaseType: Null +// CHECK-NEXT: ComplexType: Function +// CHECK-NEXT: StorageClass: External +// CHECK-NEXT: AuxSymbolCount: 0 +// CHECK-NEXT: } + // CHECK: Symbol { // CHECK: Name: _test_weak // CHECK-NEXT: Value: 0 @@ -67,7 +77,17 @@ LBB0_2: # %return // CHECK-NEXT: StorageClass: WeakExternal // CHECK-NEXT: AuxSymbolCount: 1 // CHECK-NEXT: AuxWeakExternal { -// CHECK-NEXT: Linked: _main +// CHECK-NEXT: Linked: .weak._test_weak_alias.default // CHECK-NEXT: Search: Library // CHECK-NEXT: } // CHECK-NEXT: } + +// CHECK: Symbol { +// CHECK: Name: .weak._test_weak_alias.default +// CHECK-NEXT: Value: 0 +// CHECK-NEXT: Section: .text +// CHECK-NEXT: BaseType: Null +// CHECK-NEXT: ComplexType: Null +// CHECK-NEXT: StorageClass: External +// CHECK-NEXT: AuxSymbolCount: 0 +// CHECK-NEXT: }