| 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, <oTextSection.section); |
| +SectionChunk ltoDataSectionChunk(nullptr, <oDataSection.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 = <oTextSectionChunk; |
| + else |
| + fakeSC = <oDataSectionChunk; |
| 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 |
| |