Skip to content

[LLD][COFF] Separate EC and native exports for ARM64X #123652

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions lld/COFF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,6 @@ struct Configuration {
bool dll = false;
StringRef implib;
bool noimplib = false;
std::vector<Export> exports;
bool hadExplicitExports;
std::set<std::string> delayLoads;
std::map<std::string, int> dllOrder;
Symbol *delayLoadHelper = nullptr;
Expand Down
34 changes: 18 additions & 16 deletions lld/COFF/DLL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -639,22 +639,22 @@ class ExportDirectoryChunk : public NonSectionChunk {

class AddressTableChunk : public NonSectionChunk {
public:
explicit AddressTableChunk(COFFLinkerContext &ctx, size_t baseOrdinal,
explicit AddressTableChunk(SymbolTable &symtab, size_t baseOrdinal,
size_t maxOrdinal)
: baseOrdinal(baseOrdinal), size((maxOrdinal - baseOrdinal) + 1),
ctx(ctx) {}
symtab(symtab) {}
size_t getSize() const override { return size * 4; }

void writeTo(uint8_t *buf) const override {
memset(buf, 0, getSize());

for (const Export &e : ctx.config.exports) {
for (const Export &e : symtab.exports) {
assert(e.ordinal >= baseOrdinal && "Export symbol has invalid ordinal");
// Subtract the OrdinalBase to get the index.
uint8_t *p = buf + (e.ordinal - baseOrdinal) * 4;
uint32_t bit = 0;
// Pointer to thumb code must have the LSB set, so adjust it.
if (ctx.config.machine == ARMNT && !e.data)
if (symtab.machine == ARMNT && !e.data)
bit = 1;
if (e.forwardChunk) {
write32le(p, e.forwardChunk->getRVA() | bit);
Expand All @@ -669,7 +669,7 @@ class AddressTableChunk : public NonSectionChunk {
private:
size_t baseOrdinal;
size_t size;
const COFFLinkerContext &ctx;
const SymbolTable &symtab;
};

class NamePointersChunk : public NonSectionChunk {
Expand All @@ -690,13 +690,13 @@ class NamePointersChunk : public NonSectionChunk {

class ExportOrdinalChunk : public NonSectionChunk {
public:
explicit ExportOrdinalChunk(const COFFLinkerContext &ctx, size_t baseOrdinal,
explicit ExportOrdinalChunk(const SymbolTable &symtab, size_t baseOrdinal,
size_t tableSize)
: baseOrdinal(baseOrdinal), size(tableSize), ctx(ctx) {}
: baseOrdinal(baseOrdinal), size(tableSize), symtab(symtab) {}
size_t getSize() const override { return size * 2; }

void writeTo(uint8_t *buf) const override {
for (const Export &e : ctx.config.exports) {
for (const Export &e : symtab.exports) {
if (e.noname)
continue;
assert(e.ordinal >= baseOrdinal && "Export symbol has invalid ordinal");
Expand All @@ -709,7 +709,7 @@ class ExportOrdinalChunk : public NonSectionChunk {
private:
size_t baseOrdinal;
size_t size;
const COFFLinkerContext &ctx;
const SymbolTable &symtab;
};

} // anonymous namespace
Expand Down Expand Up @@ -920,33 +920,35 @@ Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *s,
}
}

void createEdataChunks(COFFLinkerContext &ctx, std::vector<Chunk *> &chunks) {
void createEdataChunks(SymbolTable &symtab, std::vector<Chunk *> &chunks) {
unsigned baseOrdinal = 1 << 16, maxOrdinal = 0;
for (Export &e : ctx.config.exports) {
for (Export &e : symtab.exports) {
baseOrdinal = std::min(baseOrdinal, (unsigned)e.ordinal);
maxOrdinal = std::max(maxOrdinal, (unsigned)e.ordinal);
}
// Ordinals must start at 1 as suggested in:
// https://learn.microsoft.com/en-us/cpp/build/reference/export-exports-a-function?view=msvc-170
assert(baseOrdinal >= 1);

auto *dllName = make<StringChunk>(sys::path::filename(ctx.config.outputFile));
auto *addressTab = make<AddressTableChunk>(ctx, baseOrdinal, maxOrdinal);
auto *dllName =
make<StringChunk>(sys::path::filename(symtab.ctx.config.outputFile));
auto *addressTab = make<AddressTableChunk>(symtab, baseOrdinal, maxOrdinal);
std::vector<Chunk *> names;
for (Export &e : ctx.config.exports)
for (Export &e : symtab.exports)
if (!e.noname)
names.push_back(make<StringChunk>(e.exportName));

std::vector<Chunk *> forwards;
for (Export &e : ctx.config.exports) {
for (Export &e : symtab.exports) {
if (e.forwardTo.empty())
continue;
e.forwardChunk = make<StringChunk>(e.forwardTo);
forwards.push_back(e.forwardChunk);
}

auto *nameTab = make<NamePointersChunk>(names);
auto *ordinalTab = make<ExportOrdinalChunk>(ctx, baseOrdinal, names.size());
auto *ordinalTab =
make<ExportOrdinalChunk>(symtab, baseOrdinal, names.size());
auto *dir =
make<ExportDirectoryChunk>(baseOrdinal, maxOrdinal, names.size(), dllName,
addressTab, nameTab, ordinalTab);
Expand Down
2 changes: 1 addition & 1 deletion lld/COFF/DLL.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class DelayLoadContents {
};

// Create all chunks for the DLL export table.
void createEdataChunks(COFFLinkerContext &ctx, std::vector<Chunk *> &chunks);
void createEdataChunks(SymbolTable &symtab, std::vector<Chunk *> &chunks);

} // namespace lld::coff

Expand Down
59 changes: 32 additions & 27 deletions lld/COFF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ void LinkerDriver::parseDirectives(InputFile *file) {
// declarations, many object files may end up with having the
// same /EXPORT options. In order to save cost of parsing them,
// we dedup them first.
if (!directivesExports.insert(e).second)
if (!file->symtab.directivesExports.insert(e).second)
continue;

Export exp = parseExport(e);
Expand All @@ -469,7 +469,7 @@ void LinkerDriver::parseDirectives(InputFile *file) {
exp.extName = saver().save("_" + exp.extName);
}
exp.source = ExportSource::Directives;
ctx.config.exports.push_back(exp);
file->symtab.exports.push_back(exp);
}

// Handle /include: in bulk.
Expand Down Expand Up @@ -956,7 +956,7 @@ std::string LinkerDriver::getImportName(bool asLib) {
void LinkerDriver::createImportLibrary(bool asLib) {
llvm::TimeTraceScope timeScope("Create import library");
std::vector<COFFShortExport> exports;
for (Export &e1 : ctx.config.exports) {
for (Export &e1 : ctx.symtab.exports) {
COFFShortExport e2;
e2.Name = std::string(e1.name);
e2.SymbolName = std::string(e1.symbolName);
Expand Down Expand Up @@ -1069,7 +1069,7 @@ void LinkerDriver::parseModuleDefs(StringRef path) {
e2.isPrivate = e1.Private;
e2.constant = e1.Constant;
e2.source = ExportSource::ModuleDefinition;
ctx.config.exports.push_back(e2);
ctx.symtab.exports.push_back(e2);
}
}

Expand Down Expand Up @@ -1222,8 +1222,10 @@ static void findKeepUniqueSections(COFFLinkerContext &ctx) {

// Exported symbols could be address-significant in other executables or DSOs,
// so we conservatively mark them as address-significant.
for (Export &r : ctx.config.exports)
markAddrsig(r.sym);
ctx.forEachSymtab([](SymbolTable &symtab) {
for (Export &r : symtab.exports)
markAddrsig(r.sym);
});

// Visit the address-significance table in each object file and mark each
// referenced symbol as address-significant.
Expand Down Expand Up @@ -1376,13 +1378,13 @@ void LinkerDriver::maybeCreateECExportThunk(StringRef name, Symbol *&sym) {
void LinkerDriver::createECExportThunks() {
// Check if EXP+ symbols have corresponding $hp_target symbols and use them
// to create export thunks when available.
for (Symbol *s : ctx.symtab.expSymbols) {
for (Symbol *s : ctx.symtabEC->expSymbols) {
if (!s->isUsedInRegularObj)
continue;
assert(s->getName().starts_with("EXP+"));
std::string targetName =
(s->getName().substr(strlen("EXP+")) + "$hp_target").str();
Symbol *sym = ctx.symtab.find(targetName);
Symbol *sym = ctx.symtabEC->find(targetName);
if (!sym)
continue;
Defined *targetSym;
Expand All @@ -1407,7 +1409,7 @@ void LinkerDriver::createECExportThunks() {
if (ctx.symtabEC->entry)
maybeCreateECExportThunk(ctx.symtabEC->entry->getName(),
ctx.symtabEC->entry);
for (Export &e : ctx.config.exports) {
for (Export &e : ctx.symtabEC->exports) {
if (!e.data)
maybeCreateECExportThunk(e.extName.empty() ? e.name : e.extName, e.sym);
}
Expand All @@ -1430,7 +1432,7 @@ void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) {
if (!ctx.config.dll)
return;

if (!ctx.config.exports.empty())
if (!ctx.symtab.exports.empty())
return;
if (args.hasArg(OPT_exclude_all_symbols))
return;
Expand Down Expand Up @@ -1466,7 +1468,7 @@ void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) {
if (!(c->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
e.data = true;
s->isUsedInRegularObj = true;
ctx.config.exports.push_back(e);
ctx.symtab.exports.push_back(e);
});
}

Expand Down Expand Up @@ -2343,7 +2345,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (!e.extName.empty() && !isDecorated(e.extName))
e.extName = saver().save("_" + e.extName);
}
config->exports.push_back(e);
mainSymtab.exports.push_back(e);
}
}

Expand All @@ -2355,7 +2357,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {

// Handle generation of import library from a def file.
if (!args.hasArg(OPT_INPUT, OPT_wholearchive_file)) {
fixupExports();
ctx.forEachSymtab([](SymbolTable &symtab) { symtab.fixupExports(); });
if (!config->noimplib)
createImportLibrary(/*asLib=*/true);
return;
Expand Down Expand Up @@ -2541,16 +2543,16 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// search for its mangled names.
if (symtab.entry)
symtab.mangleMaybe(symtab.entry);
});

// Windows specific -- Make sure we resolve all dllexported symbols.
for (Export &e : config->exports) {
if (!e.forwardTo.empty())
continue;
e.sym = ctx.symtab.addGCRoot(e.name, !e.data);
if (e.source != ExportSource::Directives)
e.symbolName = ctx.symtab.mangleMaybe(e.sym);
}
// Windows specific -- Make sure we resolve all dllexported symbols.
for (Export &e : symtab.exports) {
if (!e.forwardTo.empty())
continue;
e.sym = symtab.addGCRoot(e.name, !e.data);
if (e.source != ExportSource::Directives)
e.symbolName = symtab.mangleMaybe(e.sym);
}
});

// Add weak aliases. Weak aliases is a mechanism to give remaining
// undefined symbols final chance to be resolved successfully.
Expand Down Expand Up @@ -2651,7 +2653,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (errorCount())
return;

config->hadExplicitExports = !config->exports.empty();
ctx.forEachSymtab([](SymbolTable &symtab) {
symtab.hadExplicitExports = !symtab.exports.empty();
});
if (config->mingw) {
// In MinGW, all symbols are automatically exported if no symbols
// are chosen to be exported.
Expand Down Expand Up @@ -2716,17 +2720,18 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// Windows specific -- when we are creating a .dll file, we also
// need to create a .lib file. In MinGW mode, we only do that when the
// -implib option is given explicitly, for compatibility with GNU ld.
if (!config->exports.empty() || config->dll) {
if (!ctx.symtab.exports.empty() || config->dll) {
llvm::TimeTraceScope timeScope("Create .lib exports");
fixupExports();
ctx.forEachSymtab([](SymbolTable &symtab) { symtab.fixupExports(); });
if (!config->noimplib && (!config->mingw || !config->implib.empty()))
createImportLibrary(/*asLib=*/false);
assignExportOrdinals();
ctx.forEachSymtab(
[](SymbolTable &symtab) { symtab.assignExportOrdinals(); });
}

// Handle /output-def (MinGW specific).
if (auto *arg = args.getLastArg(OPT_output_def))
writeDefFile(ctx, arg->getValue(), config->exports);
writeDefFile(ctx, arg->getValue(), ctx.symtab.exports);

// Set extra alignment for .comm symbols
for (auto pair : config->alignComm) {
Expand Down
3 changes: 0 additions & 3 deletions lld/COFF/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ class LinkerDriver {
std::list<std::function<void()>> taskQueue;
std::vector<MemoryBufferRef> resources;

llvm::DenseSet<StringRef> directivesExports;
llvm::DenseSet<StringRef> excludedSymbols;

COFFLinkerContext &ctx;
Expand Down Expand Up @@ -249,8 +248,6 @@ class LinkerDriver {

// Used for dllexported symbols.
Export parseExport(StringRef arg);
void fixupExports();
void assignExportOrdinals();

// Parses a string in the form of "key=value" and check
// if value matches previous values for the key.
Expand Down
Loading
Loading