summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/COFF/Config.h7
-rw-r--r--lld/COFF/DLL.cpp2
-rw-r--r--lld/COFF/Driver.cpp20
-rw-r--r--lld/COFF/DriverUtils.cpp86
-rw-r--r--lld/COFF/ModuleDef.cpp12
-rw-r--r--lld/test/COFF/dll.test12
-rw-r--r--lld/test/COFF/export32.test6
7 files changed, 89 insertions, 56 deletions
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 4fb02c50f8c..aa1c226ec50 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -36,14 +36,17 @@ static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386;
struct Export {
StringRef Name; // N in /export:N or /export:E=N
StringRef ExtName; // E in /export:E=N
- StringRef ExtDLLName; // Symbol name written to a DLL export table
- StringRef ExtLibName; // Symbol name written to a import library
Undefined *Sym = nullptr;
uint16_t Ordinal = 0;
bool Noname = false;
bool Data = false;
bool Private = false;
+ // True if this /export option was in .drectves section.
+ bool Directives = false;
+ StringRef SymbolName;
+ StringRef ExportName; // Name in DLL
+
bool operator==(const Export &E) {
return (Name == E.Name && ExtName == E.ExtName &&
Ordinal == E.Ordinal && Noname == E.Noname &&
diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp
index f71801d97fc..5da0fca3c71 100644
--- a/lld/COFF/DLL.cpp
+++ b/lld/COFF/DLL.cpp
@@ -539,7 +539,7 @@ EdataContents::EdataContents() {
std::vector<Chunk *> Names;
for (Export &E : Config->Exports)
if (!E.Noname)
- Names.push_back(new StringChunk(E.ExtDLLName));
+ Names.push_back(new StringChunk(E.ExportName));
auto *NameTab = new NamePointersChunk(Names);
auto *OrdinalTab = new ExportOrdinalChunk(Names.size());
auto *Dir = new ExportDirectoryChunk(MaxOrdinal, Names.size(), DLLName,
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 6781ccf5f29..96139aa03a8 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -81,6 +81,10 @@ static std::unique_ptr<InputFile> createFile(MemoryBufferRef MB) {
return std::unique_ptr<InputFile>(new ObjectFile(MB));
}
+static bool isDecorated(StringRef Sym) {
+ return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?");
+}
+
// Parses .drectve section contents and returns a list of files
// specified by /defaultlib.
void LinkerDriver::parseDirectives(StringRef S) {
@@ -99,8 +103,7 @@ void LinkerDriver::parseDirectives(StringRef S) {
break;
case OPT_export: {
Export E = parseExport(Arg->getValue());
- if (Config->Machine == I386 && E.ExtName.startswith("_"))
- E.ExtName = E.ExtName.substr(1);
+ E.Directives = true;
Config->Exports.push_back(E);
break;
}
@@ -520,8 +523,12 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
// Handle /export
for (auto *Arg : Args.filtered(OPT_export)) {
Export E = parseExport(Arg->getValue());
- if (Config->Machine == I386 && !E.Name.startswith("_@?"))
- E.Name = mangle(E.Name);
+ if (Config->Machine == I386) {
+ if (!isDecorated(E.Name))
+ E.Name = Alloc.save("_" + E.Name);
+ if (!E.ExtName.empty() && !isDecorated(E.ExtName))
+ E.ExtName = Alloc.save("_" + E.ExtName);
+ }
Config->Exports.push_back(E);
}
@@ -574,7 +581,8 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
// Windows specific -- Make sure we resolve all dllexported symbols.
for (Export &E : Config->Exports) {
E.Sym = addUndefined(E.Name);
- Symtab.mangleMaybe(E.Sym);
+ if (!E.Directives)
+ Symtab.mangleMaybe(E.Sym);
}
// Add weak aliases. Weak aliases is a mechanism to give remaining
@@ -626,7 +634,7 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
// Windows specific -- when we are creating a .dll file, we also
// need to create a .lib file.
- if (!Config->Exports.empty()) {
+ if (Config->DLL) {
fixupExports();
writeImportLibrary();
assignExportOrdinals();
diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp
index 6304e48a791..e6a4950c01f 100644
--- a/lld/COFF/DriverUtils.cpp
+++ b/lld/COFF/DriverUtils.cpp
@@ -370,6 +370,12 @@ err:
error(Twine("invalid /export: ") + Arg);
}
+static StringRef undecorate(StringRef Sym) {
+ if (Config->Machine != I386)
+ return Sym;
+ return Sym.startswith("_") ? Sym.substr(1) : Sym;
+}
+
// Performs error checking on all /export arguments.
// It also sets ordinals.
void fixupExports() {
@@ -379,30 +385,25 @@ void fixupExports() {
if (E.Ordinal == 0)
continue;
if (!Ords.insert(E.Ordinal).second)
- error(Twine("duplicate export ordinal: ") + E.Name);
+ error("duplicate export ordinal: " + E.Name);
}
for (Export &E : Config->Exports) {
- if (!E.ExtName.empty()) {
- E.ExtDLLName = E.ExtName;
- E.ExtLibName = E.ExtName;
- continue;
- }
- StringRef S = E.Sym->repl()->getName();
- if (Config->Machine == I386 && S.startswith("_")) {
- E.ExtDLLName = S.substr(1).split('@').first;
- E.ExtLibName = S.substr(1);
- continue;
+ if (Undefined *U = cast_or_null<Undefined>(E.Sym->WeakAlias)) {
+ E.SymbolName = U->getName();
+ } else {
+ E.SymbolName = E.Sym->getName();
}
- E.ExtDLLName = S;
- E.ExtLibName = S;
}
+ for (Export &E : Config->Exports)
+ E.ExportName = undecorate(E.ExtName.empty() ? E.Name : E.ExtName);
+
// Uniquefy by name.
std::map<StringRef, Export *> Map;
std::vector<Export> V;
for (Export &E : Config->Exports) {
- auto Pair = Map.insert(std::make_pair(E.ExtLibName, &E));
+ auto Pair = Map.insert(std::make_pair(E.ExportName, &E));
bool Inserted = Pair.second;
if (Inserted) {
V.push_back(E);
@@ -418,7 +419,7 @@ void fixupExports() {
// Sort by name.
std::sort(Config->Exports.begin(), Config->Exports.end(),
[](const Export &A, const Export &B) {
- return A.ExtDLLName < B.ExtDLLName;
+ return A.ExportName < B.ExportName;
});
}
@@ -535,12 +536,8 @@ class ShortImportCreator {
public:
ShortImportCreator(object::Archive *A, StringRef S) : Parent(A), DLLName(S) {}
- NewArchiveIterator create(const Export &E) {
- std::string Sym = E.ExtLibName;
- bool Decorated =
- E.ExtLibName.startswith("?") || E.ExtLibName.startswith("@");
- if (Config->Machine == I386 && !Decorated)
- Sym = (Twine("_") + Sym).str();
+ NewArchiveIterator create(StringRef Sym, uint16_t Ordinal,
+ ImportNameType NameType, bool isData) {
size_t ImpSize = DLLName.size() + Sym.size() + 2; // +2 for NULs
size_t Size = sizeof(object::ArchiveMemberHeader) +
sizeof(coff_import_header) + ImpSize;
@@ -564,22 +561,16 @@ public:
Imp->Sig2 = 0xFFFF;
Imp->Machine = Config->Machine;
Imp->SizeOfData = ImpSize;
- if (E.Ordinal > 0)
- Imp->OrdinalHint = E.Ordinal;
- Imp->TypeInfo = (E.Data ? IMPORT_DATA : IMPORT_CODE);
+ if (Ordinal > 0)
+ Imp->OrdinalHint = Ordinal;
+ Imp->TypeInfo = (isData ? IMPORT_DATA : IMPORT_CODE);
Imp->TypeInfo = IMPORT_CODE;
- if (E.Noname) {
- Imp->TypeInfo |= IMPORT_ORDINAL << 2;
- } else if (Decorated) {
- Imp->TypeInfo |= IMPORT_NAME << 2;
- } else {
- Imp->TypeInfo |= IMPORT_NAME_NOPREFIX << 2;
- }
+ Imp->TypeInfo |= NameType << 2;
// Write symbol name and DLL name.
- sprintf(P, Sym.data(), Sym.size());
+ memcpy(P, Sym.data(), Sym.size());
P += Sym.size() + 1;
- sprintf(P, DLLName.data(), DLLName.size());
+ memcpy(P, DLLName.data(), DLLName.size());
object::Archive::Child C(Parent, Buf);
return NewArchiveIterator(C, nextFilename());
@@ -598,6 +589,20 @@ private:
int Idx = 1;
};
+static ImportNameType getNameType(StringRef Sym, StringRef ExtName) {
+ if (Sym != ExtName)
+ return IMPORT_NAME_UNDECORATE;
+ if (Config->Machine == I386 && Sym.startswith("_"))
+ return IMPORT_NAME_NOPREFIX;
+ return IMPORT_NAME;
+}
+
+static std::string replace(StringRef S, StringRef From, StringRef To) {
+ size_t Pos = S.find(From);
+ assert(Pos != StringRef::npos);
+ return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
+}
+
// Creates an import library for a DLL. In this function, we first
// create an empty import library using lib.exe and then adds short
// import files to that file.
@@ -610,9 +615,18 @@ void writeImportLibrary() {
std::string DLLName = llvm::sys::path::filename(Config->OutputFile);
ShortImportCreator ShortImport(&Archive, DLLName);
- for (Export &E : Config->Exports)
- if (!E.Private)
- Members.push_back(ShortImport.create(E));
+ for (Export &E : Config->Exports) {
+ if (E.Private)
+ continue;
+ if (E.ExtName.empty()) {
+ Members.push_back(ShortImport.create(
+ E.SymbolName, E.Ordinal, getNameType(E.SymbolName, E.Name), E.Data));
+ } else {
+ Members.push_back(ShortImport.create(
+ replace(E.SymbolName, E.Name, E.ExtName), E.Ordinal,
+ getNameType(E.SymbolName, E.Name), E.Data));
+ }
+ }
std::string Path = getImplibPath();
std::pair<StringRef, std::error_code> Result =
diff --git a/lld/COFF/ModuleDef.cpp b/lld/COFF/ModuleDef.cpp
index fab3e4a1852..1ccca01b899 100644
--- a/lld/COFF/ModuleDef.cpp
+++ b/lld/COFF/ModuleDef.cpp
@@ -54,6 +54,10 @@ struct Token {
StringRef Value;
};
+static bool isDecorated(StringRef Sym) {
+ return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?");
+}
+
class Lexer {
public:
explicit Lexer(StringRef S) : Buf(S) {}
@@ -191,8 +195,12 @@ private:
unget();
}
- if (Config->Machine == I386 && !E.Name.startswith("_@?"))
- E.Name = Alloc->save("_" + E.Name);
+ if (Config->Machine == I386) {
+ if (!isDecorated(E.Name))
+ E.Name = Alloc->save("_" + E.Name);
+ if (!E.ExtName.empty() && !isDecorated(E.ExtName))
+ E.ExtName = Alloc->save("_" + E.ExtName);
+ }
for (;;) {
read();
diff --git a/lld/test/COFF/dll.test b/lld/test/COFF/dll.test
index b702f2e563a..bafd3c233c8 100644
--- a/lld/test/COFF/dll.test
+++ b/lld/test/COFF/dll.test
@@ -10,10 +10,10 @@ EXPORT: Export Table:
EXPORT: DLL name: dll.test.tmp.dll
EXPORT: Ordinal RVA Name
EXPORT-NEXT: 0 0
-EXPORT-NEXT: 1 0x1010 ?mangled@@YAHXZ
-EXPORT-NEXT: 2 0x1008 exportfn1
-EXPORT-NEXT: 3 0x1010 exportfn2
-EXPORT-NEXT: 4 0x1010 exportfn3
+EXPORT-NEXT: 1 0x1008 exportfn1
+EXPORT-NEXT: 2 0x1010 exportfn2
+EXPORT-NEXT: 3 0x1010 exportfn3
+EXPORT-NEXT: 4 0x1010 mangled
# RUN: yaml2obj < %p/Inputs/export2.yaml > %t5.obj
# RUN: rm -f %t5.lib
@@ -25,8 +25,8 @@ EXPORT2: Export Table:
EXPORT2: DLL name: dll.test.tmp5.dll
EXPORT2: Ordinal RVA Name
EXPORT2-NEXT: 0 0
-EXPORT2-NEXT: 1 0x101c ?mangled2@@YAHXZ
-EXPORT2-NEXT: 2 0x1010 exportfn3
+EXPORT2-NEXT: 1 0x1010 exportfn3
+EXPORT2-NEXT: 2 0x101c mangled2
# RUN: llvm-as -o %t.lto.obj %p/Inputs/export.ll
# RUN: lld-link /out:%t.lto.dll /dll %t.lto.obj /export:exportfn1 /export:exportfn2
diff --git a/lld/test/COFF/export32.test b/lld/test/COFF/export32.test
index 5c1ddc91bd5..5d7b2708dcb 100644
--- a/lld/test/COFF/export32.test
+++ b/lld/test/COFF/export32.test
@@ -24,9 +24,9 @@
# CHECK2-NEXT: 3 0
# CHECK2-NEXT: 4 0
# CHECK2-NEXT: 5 0x1008 exportfn1
-# CHECK2-NEXT: 6 0x1010 ?mangled@@YAHXZ
-# CHECK2-NEXT: 7 0x1010 exportfn2
-# CHECK2-NEXT: 8 0x1010 exportfn3
+# CHECK2-NEXT: 6 0x1010 exportfn2
+# CHECK2-NEXT: 7 0x1010 exportfn3
+# CHECK2-NEXT: 8 0x1010 mangled
# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1,@5,noname /export:exportfn2
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK3 %s
OpenPOWER on IntegriCloud