blob: c2f82160b7b08abb3db92e384edd1f97bd27fa1a [file] [log] [blame]
From 33b71ec9c6719d3b6429f121dcf1f6f7c7f5abef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
Date: Thu, 29 Apr 2021 14:06:24 +0300
Subject: [PATCH] [LLD] [COFF] Fix automatic export of symbols from LTO objects
Differential Revision: https://reviews.llvm.org/D101569
---
COFF/Chunks.cpp | 14 ++++++++++----
COFF/Driver.cpp | 13 ++++++++-----
COFF/InputFiles.cpp | 24 ++++++++++++++++++++++--
test/COFF/export-all-lto.ll | 23 +++++++++++++++++++++++
4 files changed, 63 insertions(+), 11 deletions(-)
create mode 100644 test/COFF/export-all-lto.ll
diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp
index 35fe61f18fa8..f344df042317 100644
--- a/COFF/Chunks.cpp
+++ b/COFF/Chunks.cpp
@@ -32,12 +32,15 @@ namespace coff {
SectionChunk::SectionChunk(ObjFile *f, const coff_section *h)
: Chunk(SectionKind), file(f), header(h), repl(this) {
// Initialize relocs.
- setRelocs(file->getCOFFObj()->getRelocations(header));
+ if (file)
+ setRelocs(file->getCOFFObj()->getRelocations(header));
// Initialize sectionName.
StringRef sectionName;
- if (Expected<StringRef> e = file->getCOFFObj()->getSectionName(header))
- sectionName = *e;
+ if (file) {
+ if (Expected<StringRef> e = file->getCOFFObj()->getSectionName(header))
+ sectionName = *e;
+ }
sectionNameData = sectionName.data();
sectionNameSize = sectionName.size();
@@ -49,7 +52,10 @@ SectionChunk::SectionChunk(ObjFile *f, const coff_section *h)
// enabled, treat non-comdat sections as roots. Generally optimized object
// files will be built with -ffunction-sections or /Gy, so most things worth
// stripping will be in a comdat.
- live = !config->doGC || !isCOMDAT();
+ if (config)
+ live = !config->doGC || !isCOMDAT();
+ else
+ live = true;
}
// SectionChunk is one of the most frequently allocated classes, so it is
diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp
index 029148c4722b..03db71cc9082 100644
--- a/COFF/Driver.cpp
+++ b/COFF/Driver.cpp
@@ -1220,6 +1220,7 @@ void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) {
if (Chunk *c = def->getChunk())
if (!(c->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
e.data = true;
+ s->isUsedInRegularObj = true;
config->exports.push_back(e);
});
}
@@ -2117,6 +2118,13 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (errorCount())
return;
+ config->hadExplicitExports = !config->exports.empty();
+ if (config->mingw) {
+ // In MinGW, all symbols are automatically exported if no symbols
+ // are chosen to be exported.
+ maybeExportMinGWSymbols(args);
+ }
+
// Do LTO by compiling bitcode input files to a set of native COFF files then
// link those files (unless -thinlto-index-only was given, in which case we
// resolve symbols and write indices, but don't generate native code or link).
@@ -2141,12 +2149,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (errorCount())
return;
- config->hadExplicitExports = !config->exports.empty();
if (config->mingw) {
- // In MinGW, all symbols are automatically exported if no symbols
- // are chosen to be exported.
- maybeExportMinGWSymbols(args);
-
// Make sure the crtend.o object is the last object file. This object
// file can contain terminating section chunks that need to be placed
// last. GNU ld processes files and static libraries explicitly in the
diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp
index c7b75badbfe2..9900903bfe7c 100644
--- a/COFF/InputFiles.cpp
+++ b/COFF/InputFiles.cpp
@@ -1042,6 +1042,21 @@ BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
BitcodeFile::~BitcodeFile() = default;
+namespace {
+// Convenience class for initializing a coff_section with specific flags.
+class FakeSection {
+public:
+ FakeSection(int c) { section.Characteristics = c; }
+
+ coff_section section;
+};
+
+FakeSection ltoTextSection(IMAGE_SCN_MEM_EXECUTE);
+FakeSection ltoDataSection(IMAGE_SCN_CNT_INITIALIZED_DATA);
+SectionChunk ltoTextSectionChunk(nullptr, &ltoTextSection.section);
+SectionChunk ltoDataSectionChunk(nullptr, &ltoDataSection.section);
+} // namespace
+
void BitcodeFile::parse() {
std::vector<std::pair<Symbol *, bool>> comdat(obj->getComdatTable().size());
for (size_t i = 0; i != obj->getComdatTable().size(); ++i)
@@ -1052,6 +1067,11 @@ void BitcodeFile::parse() {
StringRef symName = saver.save(objSym.getName());
int comdatIndex = objSym.getComdatIndex();
Symbol *sym;
+ SectionChunk *fakeSC = nullptr;
+ if (objSym.isExecutable())
+ fakeSC = &ltoTextSectionChunk;
+ else
+ fakeSC = &ltoDataSectionChunk;
if (objSym.isUndefined()) {
sym = symtab->addUndefined(symName, this, false);
} else if (objSym.isCommon()) {
@@ -1066,11 +1086,11 @@ void BitcodeFile::parse() {
if (symName == obj->getComdatTable()[comdatIndex])
sym = comdat[comdatIndex].first;
else if (comdat[comdatIndex].second)
- sym = symtab->addRegular(this, symName);
+ sym = symtab->addRegular(this, symName, nullptr, fakeSC);
else
sym = symtab->addUndefined(symName, this, false);
} else {
- sym = symtab->addRegular(this, symName);
+ sym = symtab->addRegular(this, symName, nullptr, fakeSC);
}
symbols.push_back(sym);
if (objSym.isUsed())
diff --git a/test/COFF/export-all-lto.ll b/test/COFF/export-all-lto.ll
new file mode 100644
index 000000000000..9d68809a77e0
--- /dev/null
+++ b/test/COFF/export-all-lto.ll
@@ -0,0 +1,23 @@
+; REQUIRES: x86
+
+; RUN: llvm-as %s -o %t.bc
+
+; RUN: lld-link -lldmingw -dll -out:%t.dll %t.bc -noentry -output-def:%t.def
+; RUN: llvm-readobj --coff-exports %t.dll | grep Name: | FileCheck %s
+; RUN: cat %t.def | FileCheck --check-prefix=IMPLIB %s
+
+; CHECK: Name: MyExtData
+; CHECK: Name: MyLibFunc
+
+; IMPLIB: MyExtData @1 DATA
+; IMPLIB: MyLibFunc @2{{$}}
+
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-w64-windows-gnu"
+
+@MyExtData = dso_local global i32 42, align 4
+
+define dso_local void @MyLibFunc() {
+entry:
+ ret void
+}
--
2.31.1.windows.1