Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -231,7 +231,9 @@ OutStreamer.EmitSymbolAttribute(GVSym, MCSA_WeakDefinition); else OutStreamer.EmitSymbolAttribute(GVSym, MCSA_WeakDefAutoPrivate); - } else if (MAI->getLinkOnceDirective() != 0) { + } else if (MAI->getLinkOnceDirective() != 0 && + (GlobalValue::LinkageTypes)Linkage == + GlobalValue::LinkOnceODRLinkage) { // .globl _foo OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global); //NOTE: linkonce is handled by the section the symbol was assigned to. Index: lib/MC/WinCOFFObjectWriter.cpp =================================================================== --- lib/MC/WinCOFFObjectWriter.cpp +++ lib/MC/WinCOFFObjectWriter.cpp @@ -178,6 +178,13 @@ MCValue Target, uint64_t &FixedValue); + virtual bool + IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const LLVM_OVERRIDE; + void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout); }; } @@ -416,28 +423,16 @@ COFFSymbol *coff_symbol = GetOrCreateCOFFSymbol(&Symbol); SymbolMap[&Symbol] = coff_symbol; - if (SymbolData.getFlags() & COFF::SF_WeakExternal) { - coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL; - - if (Symbol.isVariable()) { - const MCSymbolRefExpr *SymRef = - dyn_cast(Symbol.getVariableValue()); + if ((SymbolData.getFlags() & COFF::SF_WeakExternal) && Symbol.isVariable()) { + const MCSymbolRefExpr *SymRef = + dyn_cast(Symbol.getVariableValue()); - if (!SymRef) - report_fatal_error("Weak externals may only alias symbols"); + if (!SymRef) + report_fatal_error("Weak externals may only alias symbols"); - coff_symbol->Other = GetOrCreateCOFFSymbol(&SymRef->getSymbol()); - } else { - std::string WeakName = std::string(".weak.") - + Symbol.getName().str() - + ".default"; - COFFSymbol *WeakDefault = createSymbol(WeakName); - WeakDefault->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE; - WeakDefault->Data.StorageClass = COFF::IMAGE_SYM_CLASS_EXTERNAL; - WeakDefault->Data.Type = 0; - WeakDefault->Data.Value = 0; - coff_symbol->Other = WeakDefault; - } + coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL; + coff_symbol->MCData = &SymbolData; + coff_symbol->Other = GetOrCreateCOFFSymbol(&SymRef->getSymbol()); // Setup the Weak External auxiliary symbol. coff_symbol->Aux.resize(1); @@ -445,9 +440,7 @@ coff_symbol->Aux[0].AuxType = ATWeakExternal; coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = 0; coff_symbol->Aux[0].Aux.WeakExternal.Characteristics = - COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY; - - coff_symbol->MCData = &SymbolData; + COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS; } else { const MCSymbolData &ResSymData = Assembler.getSymbolData(Symbol.AliasedSymbol()); @@ -641,7 +634,12 @@ assert(Target.getSymA() != NULL && "Relocation must reference a symbol!"); const MCSymbol &Symbol = Target.getSymA()->getSymbol(); - const MCSymbol &A = Symbol.AliasedSymbol(); + const MCSymbolData &SymbolData = Asm.getSymbolData(Symbol); + // For a weak external the relocation must not use the aliased symbol to allow + // replacing it at link time. + const MCSymbol &A = SymbolData.isExternal() && + (SymbolData.getFlags() & COFF::SF_WeakExternal) + ? Symbol : Symbol.AliasedSymbol(); MCSymbolData &A_SD = Asm.getSymbolData(A); MCSectionData const *SectionData = Fragment->getParent(); @@ -740,6 +738,41 @@ } if (coff_symbol->should_keep()) { + if ((SymbolData != NULL) && + (SymbolData->getFlags() & COFF::SF_WeakExternal) && + !SymbolData->getSymbol().isVariable()) { + // Create the default symbol ".weak..default" linked to the weak + // external. + MCSymbol *DefSymbol = Asm.getContext().GetOrCreateSymbol( + Twine(".weak.") + + SymbolData->getSymbol().getName() + ".default"); + COFFSymbol *DefSym = new COFFSymbol(DefSymbol->getName()); + i = Symbols.insert(i, DefSym); + e = Symbols.end(); + ++i; + + // Use the original symbol data for the default symbol. + DefSym->Data = coff_symbol->Data; + + MakeSymbolReal(*DefSym, Header.NumberOfSymbols++); + DefSym->Data.NumberOfAuxSymbols = DefSym->Aux.size(); + Header.NumberOfSymbols += DefSym->Data.NumberOfAuxSymbols; + + // Now make the original symbol into a weak external. + COFFSymbol *WeakSym = coff_symbol; + WeakSym->Other = DefSym; + WeakSym->Data.Value = 0; + WeakSym->Data.SectionNumber = COFF::IMAGE_SYM_UNDEFINED; + WeakSym->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL; + WeakSym->Data.Type = COFF::IMAGE_SYM_TYPE_NULL; + WeakSym->Aux.resize(1); + memset(&WeakSym->Aux[0], 0, sizeof(WeakSym->Aux[0])); + WeakSym->Aux[0].AuxType = ATWeakExternal; + WeakSym->Aux[0].Aux.WeakExternal.TagIndex = 0; + WeakSym->Aux[0].Aux.WeakExternal.Characteristics = + COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS; + } + MakeSymbolReal(*coff_symbol, Header.NumberOfSymbols++); // Update auxiliary symbol info. @@ -917,6 +950,19 @@ OS.write((char const *)&Strings.Data.front(), Strings.Data.size()); } +bool +WinCOFFObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl( + const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const { + if (DataA.getFlags() & COFF::SF_WeakExternal) + return false; + return MCObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl( + Asm, DataA, FB,InSet, IsPCRel); +} + MCWinCOFFObjectTargetWriter::MCWinCOFFObjectTargetWriter(unsigned Machine_) : Machine(Machine_) { } Index: test/MC/COFF/alias.s =================================================================== --- test/MC/COFF/alias.s +++ test/MC/COFF/alias.s @@ -23,7 +23,7 @@ // CHECK: 0x0 IMAGE_REL_I386_DIR32 local1 // CHECK: 0x4 IMAGE_REL_I386_DIR32 external1 // CHECK: 0x8 IMAGE_REL_I386_DIR32 local2 -// CHECK: 0xC IMAGE_REL_I386_DIR32 external2 +// CHECK: 0xC IMAGE_REL_I386_DIR32 weak_aliased_to_external // CHECK: ] // CHECK: Symbols [ // CHECK-NEXT: Symbol { @@ -90,7 +90,7 @@ // CHECK-NEXT: AuxSymbolCount: 1 // CHECK-NEXT: AuxWeakExternal { // CHECK-NEXT: Linked: external2 (9) -// CHECK-NEXT: Search: Library (0x2) +// CHECK-NEXT: Search: Alias (0x3) // CHECK-NEXT: Unused: (00 00 00 00 00 00 00 00 00 00) // CHECK-NEXT: } // CHECK-NEXT: } Index: test/MC/COFF/weak-symbol.ll =================================================================== --- test/MC/COFF/weak-symbol.ll +++ test/MC/COFF/weak-symbol.ll @@ -10,11 +10,11 @@ ; Mangled function ; X86: .section .text$_Z3foo ; X86: .linkonce discard -; X86: .globl __Z3foo +; X86: .weak __Z3foo ; ; X64: .section .text$_Z3foo ; X64: .linkonce discard -; X64: .globl _Z3foo +; X64: .weak _Z3foo define weak void @_Z3foo() { ret void } @@ -22,11 +22,11 @@ ; Unmangled function ; X86: .section .sect$f ; X86: .linkonce discard -; X86: .globl _f +; X86: .weak _f ; ; X64: .section .sect$f ; X64: .linkonce discard -; X64: .globl f +; X64: .weak f define weak void @f() section ".sect" { ret void } @@ -34,11 +34,11 @@ ; Weak global ; X86: .section .data$a ; X86: .linkonce discard -; X86: .globl _a +; X86: .weak _a ; X86: .zero 12 ; ; X64: .section .data$a ; X64: .linkonce discard -; X64: .globl a +; X64: .weak a ; X64: .zero 12 @a = weak unnamed_addr constant { i32, i32, i32 } { i32 0, i32 0, i32 0}, section ".data" Index: test/MC/COFF/weak.s =================================================================== --- test/MC/COFF/weak.s +++ test/MC/COFF/weak.s @@ -1,8 +1,8 @@ // This tests that default-null weak symbols (a GNU extension) are created // properly via the .weak directive. -// RUN: llvm-mc -filetype=obj -triple i686-pc-win32 %s | llvm-readobj -t | FileCheck %s -// RUN: llvm-mc -filetype=obj -triple x86_64-pc-win32 %s | llvm-readobj -t | FileCheck %s +// RUN: llvm-mc -filetype=obj -triple i686-pc-win32 %s | llvm-readobj -s -sr -t | FileCheck %s +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-win32 %s | llvm-readobj -s -sr -t | FileCheck %s .def _main; .scl 2; @@ -28,13 +28,43 @@ ret .weak _test_weak +_test_weak: + ret .weak _test_weak_alias _test_weak_alias=_main +.section .text$fwd + .globl fwd +fwd: + call _test_weak + call _test_weak_alias + ret + + +// CHECK: Sections [ +// CHECK: Section { +// CHECK: Name: .text$fwd +// CHECK: Relocations [ +// CHECK-NEXT: _test_weak +// CHECK-NEXT: _test_weak_alias +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK: ] + // CHECK: Symbols [ // CHECK: Symbol { +// CHECK: Name: .weak._test_weak.default +// CHECK-NEXT: Value: 32 +// CHECK-NEXT: Section: .text +// CHECK-NEXT: BaseType: Null +// CHECK-NEXT: ComplexType: Null +// CHECK-NEXT: StorageClass: External +// CHECK-NEXT: AuxSymbolCount: 0 +// CHECK-NEXT: } + +// CHECK: Symbol { // CHECK: Name: _test_weak // CHECK-NEXT: Value: 0 // CHECK-NEXT: Section: (0) @@ -44,22 +74,12 @@ // CHECK-NEXT: AuxSymbolCount: 1 // CHECK-NEXT: AuxWeakExternal { // CHECK-NEXT: Linked: .weak._test_weak.default -// CHECK-NEXT: Search: Library +// CHECK-NEXT: Search: Alias // CHECK-NEXT: Unused: (00 00 00 00 00 00 00 00 00 00) // CHECK-NEXT: } // CHECK-NEXT: } // CHECK: Symbol { -// CHECK: Name: .weak._test_weak.default -// CHECK-NEXT: Value: 0 -// CHECK-NEXT: Section: (-1) -// CHECK-NEXT: BaseType: Null -// CHECK-NEXT: ComplexType: Null -// CHECK-NEXT: StorageClass: External -// CHECK-NEXT: AuxSymbolCount: 0 -// CHECK-NEXT: } - -// CHECK: Symbol { // CHECK: Name: _test_weak_alias // CHECK-NEXT: Value: 0 // CHECK-NEXT: Section: (0) @@ -69,7 +89,7 @@ // CHECK-NEXT: AuxSymbolCount: 1 // CHECK-NEXT: AuxWeakExternal { // CHECK-NEXT: Linked: _main -// CHECK-NEXT: Search: Library +// CHECK-NEXT: Search: Alias // CHECK-NEXT: Unused: (00 00 00 00 00 00 00 00 00 00) // CHECK-NEXT: } // CHECK-NEXT: }