[lld] r190633 - [PECOFF] Handle weak external symbols.
Rui Ueyama
ruiu at google.com
Thu Sep 12 14:42:52 PDT 2013
Author: ruiu
Date: Thu Sep 12 16:42:52 2013
New Revision: 190633
URL: http://llvm.org/viewvc/llvm-project?rev=190633&view=rev
Log:
[PECOFF] Handle weak external symbols.
Used the fallback mechanism to implement COFF weak external symbols.
Added:
lld/trunk/test/pecoff/Inputs/weak-externals.asm
lld/trunk/test/pecoff/Inputs/weak-externals.obj.yaml
lld/trunk/test/pecoff/weak-external.test
Modified:
lld/trunk/lib/Core/Resolver.cpp
lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h
lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
Modified: lld/trunk/lib/Core/Resolver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/Resolver.cpp?rev=190633&r1=190632&r2=190633&view=diff
==============================================================================
--- lld/trunk/lib/Core/Resolver.cpp (original)
+++ lld/trunk/lib/Core/Resolver.cpp Thu Sep 12 16:42:52 2013
@@ -211,9 +211,11 @@ void Resolver::resolveUndefines() {
// If the undefined symbol has an alternative name, try to resolve the
// symbol with the name to give it a second chance. This feature is used
// for COFF "weak external" symbol.
- if (const UndefinedAtom *fallbackUndefAtom = undefAtom->fallback()) {
- _symbolTable.addReplacement(undefAtom, fallbackUndefAtom);
- _symbolTable.add(*fallbackUndefAtom);
+ if (!_symbolTable.isDefined(undefName)) {
+ if (const UndefinedAtom *fallbackUndefAtom = undefAtom->fallback()) {
+ _symbolTable.addReplacement(undefAtom, fallbackUndefAtom);
+ _symbolTable.add(*fallbackUndefAtom);
+ }
}
}
// search libraries for overrides of common symbols
@@ -351,6 +353,10 @@ bool Resolver::checkUndefines(bool final
if (isa<SharedLibraryFile>(f) && _context.allowShlibUndefines())
continue;
+ // If the undefine is coalesced away, skip over it.
+ if (_symbolTable.replacement(undefAtom) != undefAtom)
+ continue;
+
// Seems like this symbol is undefined. Warn that.
foundUndefines = true;
if (_context.printRemainingUndefines()) {
Modified: lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h?rev=190633&r1=190632&r2=190633&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h Thu Sep 12 16:42:52 2013
@@ -71,16 +71,19 @@ private:
class COFFUndefinedAtom : public UndefinedAtom {
public:
- COFFUndefinedAtom(const File &f, StringRef n)
- : _owningFile(f), _name(n) {}
+ COFFUndefinedAtom(const File &file, StringRef name,
+ const UndefinedAtom *fallback = nullptr)
+ : _owningFile(file), _name(name), _fallback(fallback) {}
virtual const File &file() const { return _owningFile; }
virtual StringRef name() const { return _name; }
virtual CanBeNull canBeNull() const { return CanBeNull::canBeNullNever; }
+ virtual const UndefinedAtom *fallback() const { return _fallback; }
private:
const File &_owningFile;
StringRef _name;
+ const UndefinedAtom *_fallback;
};
/// The base class of all COFF defined atoms. A derived class of
Modified: lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp?rev=190633&r1=190632&r2=190633&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp Thu Sep 12 16:42:52 2013
@@ -30,6 +30,7 @@
#include "llvm/Support/system_error.h"
#include <map>
+#include <set>
#include <vector>
using std::vector;
@@ -40,6 +41,7 @@ using lld::coff::COFFDefinedFileAtom;
using lld::coff::COFFReference;
using lld::coff::COFFUndefinedAtom;
using llvm::object::coff_aux_section_definition;
+using llvm::object::coff_aux_weak_external;
using llvm::object::coff_relocation;
using llvm::object::coff_section;
using llvm::object::coff_symbol;
@@ -147,7 +149,8 @@ public:
return;
createAbsoluteAtoms(symbols, _absoluteAtoms._atoms);
- createUndefinedAtoms(symbols, _undefinedAtoms._atoms);
+ if ((ec = createUndefinedAtoms(symbols, _undefinedAtoms._atoms)))
+ return;
if ((ec = createDefinedSymbols(symbols, _definedAtoms._atoms)))
return;
@@ -230,17 +233,61 @@ private:
}
}
- /// Create atoms for the undefined symbols.
- void createUndefinedAtoms(const SymbolVectorT &symbols,
- vector<const UndefinedAtom *> &result) {
+ /// Create atoms for the undefined symbols. This code is bit complicated
+ /// because it supports "weak externals" mechanism of COFF. If an undefined
+ /// symbol (sym1) has auxiliary data, the data contains a symbol table index
+ /// at which the "second symbol" (sym2) for sym1 exists. If sym1 is resolved,
+ /// it's linked normally. If not, sym1 is resolved as if it has sym2's
+ /// name. This relationship between sym1 and sym2 is represented using
+ /// fallback mechanism of undefined symbol.
+ error_code createUndefinedAtoms(const SymbolVectorT &symbols,
+ vector<const UndefinedAtom *> &result) {
+ // Sort out undefined symbols from all symbols.
+ std::set<const coff_symbol *> undefines;
+ std::map<const coff_symbol *, const coff_symbol *> weakExternal;
for (const coff_symbol *sym : symbols) {
- if (sym->SectionNumber != llvm::COFF::IMAGE_SYM_UNDEFINED ||
- sym->Value != 0)
+ if (sym->SectionNumber != llvm::COFF::IMAGE_SYM_UNDEFINED)
+ continue;
+ undefines.insert(sym);
+
+ // Create a mapping from sym1 to sym2, if the undefined symbol has
+ // auxiliary data.
+ auto iter = _auxSymbol.find(sym);
+ if (iter == _auxSymbol.end())
continue;
- auto *atom = new (_alloc) COFFUndefinedAtom(*this, _symbolName[sym]);
+ const coff_aux_weak_external *aux = reinterpret_cast<
+ const coff_aux_weak_external *>(iter->second);
+ const coff_symbol *sym2;
+ if (error_code ec = _obj->getSymbol(aux->TagIndex, sym2))
+ return ec;
+ weakExternal[sym] = sym2;
+ }
+
+ // Sort out sym1s from sym2s. Sym2s shouldn't be added to the undefined atom
+ // list because they shouldn't be resolved unless sym1 is failed to
+ // be resolved.
+ for (auto i : weakExternal)
+ undefines.erase(i.second);
+
+ // Create atoms for the undefined symbols.
+ for (const coff_symbol *sym : undefines) {
+ // If the symbol has sym2, create an undefiend atom for sym2, so that we
+ // can pass it as a fallback atom.
+ UndefinedAtom *fallback = nullptr;
+ auto iter = weakExternal.find(sym);
+ if (iter != weakExternal.end()) {
+ const coff_symbol *sym2 = iter->second;
+ fallback = new (_alloc) COFFUndefinedAtom(*this, _symbolName[sym2]);
+ _symbolAtom[sym2] = fallback;
+ }
+
+ // Create an atom for the symbol.
+ auto *atom = new (_alloc) COFFUndefinedAtom(
+ *this, _symbolName[sym], fallback);
result.push_back(atom);
_symbolAtom[sym] = atom;
}
+ return error_code::success();
}
/// Create atoms for the defined symbols. This pass is a bit complicated than
Added: lld/trunk/test/pecoff/Inputs/weak-externals.asm
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/Inputs/weak-externals.asm?rev=190633&view=auto
==============================================================================
--- lld/trunk/test/pecoff/Inputs/weak-externals.asm (added)
+++ lld/trunk/test/pecoff/Inputs/weak-externals.asm Thu Sep 12 16:42:52 2013
@@ -0,0 +1,25 @@
+.386
+.model flat
+
+;; val1 should be linked normally. no_such_symbol1 should be ignored.
+extern _no_such_symbol1 : PROC
+extern _val1 (_no_such_symbol1): PROC
+
+;; no_such_symbol2 should be linked as val2.
+extern _val2 : PROC
+extern _no_such_symbol2 (_val2) : PROC
+
+;; no_such_symbol3 should fail to link.
+extern _no_such_symbol3 : PROC
+
+public _fn1
+.code
+_fn1:
+ push ebp
+ mov ebp, esp
+ call _val1
+ call _no_such_symbol2
+ call _no_such_symbol3
+ pop ebp
+ ret 0
+end _fn1
Added: lld/trunk/test/pecoff/Inputs/weak-externals.obj.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/Inputs/weak-externals.obj.yaml?rev=190633&view=auto
==============================================================================
--- lld/trunk/test/pecoff/Inputs/weak-externals.obj.yaml (added)
+++ lld/trunk/test/pecoff/Inputs/weak-externals.obj.yaml Thu Sep 12 16:42:52 2013
@@ -0,0 +1,81 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 558BECE800000000E800000000E8000000005DC3
+ Relocations:
+ - VirtualAddress: 4
+ SymbolName: _val1
+ Type: IMAGE_REL_I386_REL32
+ - VirtualAddress: 9
+ SymbolName: _no_such_symbol2
+ Type: IMAGE_REL_I386_REL32
+ - VirtualAddress: 14
+ SymbolName: _no_such_symbol3
+ Type: IMAGE_REL_I386_REL32
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: ""
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ NumberOfAuxSymbols: 1
+ AuxiliaryData: 140000000300000000000000000000000000
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ NumberOfAuxSymbols: 1
+ AuxiliaryData: 000000000000000000000000000000000000
+ - Name: _no_such_symbol1
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _val2
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _no_such_symbol3
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _val1
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_WEAK_EXTERNAL
+ NumberOfAuxSymbols: 1
+ AuxiliaryData: 040000000200000000000000000000000000
+ - Name: _no_such_symbol2
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_WEAK_EXTERNAL
+ NumberOfAuxSymbols: 1
+ AuxiliaryData: 050000000200000000000000000000000000
+ - Name: _fn1
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
Added: lld/trunk/test/pecoff/weak-external.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/weak-external.test?rev=190633&view=auto
==============================================================================
--- lld/trunk/test/pecoff/weak-external.test (added)
+++ lld/trunk/test/pecoff/weak-external.test Thu Sep 12 16:42:52 2013
@@ -0,0 +1,9 @@
+# RUN: yaml2obj %p/Inputs/weak-externals.obj.yaml > %t.obj
+
+# RUN: lld -flavor link /force /out:%t.exe /subsystem:console /opt:noref \
+# RUN: /entry:fn -- %t.obj %p/Inputs/static.lib 2> %t2.out
+# RUN: FileCheck %s < %t2.out
+
+CHECK-NOT: _no_such_symbol1
+CHECK-NOT: _no_such_symbol2
+CHECK: _no_such_symbol3
More information about the llvm-commits
mailing list