summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2016-05-26 20:31:00 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2016-05-26 20:31:00 +0000
commit732eeaf2a930ad2755cb4eb5d99a3deae0de4a72 (patch)
treee3c17fbda3987873d62eabe95a436a4008be21c9
parent4b92326b17498df278addf968818c145034019ed (diff)
downloadbcm5719-llvm-732eeaf2a930ad2755cb4eb5d99a3deae0de4a72.tar.gz
bcm5719-llvm-732eeaf2a930ad2755cb4eb5d99a3deae0de4a72.zip
coff: fix weak alias to local.
We were creating a weak external that tried to reference a static symbol. That would always fail to link with link.exe. We now create an external symbol in the same position as the local and refer to that. This works with link.exe and matches what gas does. llvm-svn: 270906
-rw-r--r--llvm/lib/MC/WinCOFFObjectWriter.cpp72
-rw-r--r--llvm/test/MC/COFF/weak-alias-local.s43
-rw-r--r--llvm/test/MC/COFF/weak.s22
3 files changed, 104 insertions, 33 deletions
diff --git a/llvm/lib/MC/WinCOFFObjectWriter.cpp b/llvm/lib/MC/WinCOFFObjectWriter.cpp
index cb5998437b0..ac4a5bdcd50 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<MCSymbolRefExpr>(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<MCSymbolCOFF>(Symbol).isWeakExternal()) {
coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL;
- if (Symbol.isVariable()) {
- const MCSymbolRefExpr *SymRef =
- dyn_cast<MCSymbolRefExpr>(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);
+ if (!Base)
+ coff_symbol->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE;
+ else
+ coff_symbol->Section = Sec;
+ Local = coff_symbol;
+ }
+
+ if (Local) {
+ Local->Data.Value = getSymbolValue(Symbol, Layout);
const MCSymbolCOFF &SymbolCOFF = cast<MCSymbolCOFF>(Symbol);
- coff_symbol->Data.Type = SymbolCOFF.getType();
- coff_symbol->Data.StorageClass = SymbolCOFF.getClass();
+ Local->Data.Type = SymbolCOFF.getType();
+ Local->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) {
+ if (Local->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;
+ Local->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;
}
+
+ 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 00000000000..01f2ac390a5
--- /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 6086749d80d..e0d077840f1 100644
--- a/llvm/test/MC/COFF/weak.s
+++ b/llvm/test/MC/COFF/weak.s
@@ -35,6 +35,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
// CHECK-NEXT: Section: IMAGE_SYM_UNDEFINED (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: }
OpenPOWER on IntegriCloud