[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