[lld] [LLD][COFF] Implement support for hybrid IAT on ARM64X (PR #124189)
Martin Storsjö via llvm-commits
llvm-commits at lists.llvm.org
Sat Jan 25 14:54:40 PST 2025
================
@@ -717,52 +716,176 @@ class ExportOrdinalChunk : public NonSectionChunk {
void IdataContents::create(COFFLinkerContext &ctx) {
std::vector<std::vector<DefinedImportData *>> v = binImports(ctx, imports);
+ // In hybrid images, EC and native code are usually very similar,
+ // resulting in a highly similar set of imported symbols. Consequently,
+ // their import tables can be shared, with ARM64X relocations handling any
+ // differences. Identify matching import files used by EC and native code, and
+ // merge them into a single hybrid import entry.
+ if (ctx.hybridSymtab) {
+ for (std::vector<DefinedImportData *> &syms : v) {
+ std::vector<DefinedImportData *> hybridSyms;
+ ImportFile *prev = nullptr;
+ for (DefinedImportData *sym : syms) {
+ ImportFile *file = sym->file;
+ // At this stage, symbols are sorted by base name, ensuring that
+ // compatible import files, if present, are adjacent. Check if the
+ // current symbol's file imports the same symbol as the previously added
+ // one (if any and if it was not already merged). Additionally, verify
+ // that one of them is native while the other is EC. In rare cases,
+ // separate matching import entries may exist within the same namespace,
+ // which cannot be merged.
+ if (!prev || file->isEC() == prev->isEC() ||
+ !file->isSameImport(prev)) {
+ // We can't merge the import file, just add it to hybridSyms
+ // and set prev to its file so that we can try to match the next
+ // symbol.
+ hybridSyms.push_back(sym);
+ prev = file;
+ continue;
+ }
+
+ // A matching symbol may appear in syms in any order. The native variant
+ // exposes a subset of EC symbols and chunks, so always use the EC
+ // variant as the hybrid import file. If the native file was already
+ // added, replace it with the EC symbol in hybridSyms. Otherwise, the EC
+ // variant is already pushed, so we can simply merge it.
+ if (file->isEC()) {
+ hybridSyms.pop_back();
+ hybridSyms.push_back(sym);
+ }
+
+ // Merge import files by storing their hybrid form in the corresponding
+ // file class.
+ prev->hybridFile = file;
+ file->hybridFile = prev;
+ prev = nullptr; // A hybrid import file cannot be merged again.
+ }
+
+ // Sort symbols by type: native-only files first, followed by merged
+ // hybrid files, and then EC-only files.
+ llvm::stable_sort(hybridSyms,
+ [](DefinedImportData *a, DefinedImportData *b) {
+ if (a->file->hybridFile)
+ return !b->file->hybridFile && b->file->isEC();
+ return !a->file->isEC() && b->file->isEC();
+ });
+ syms = std::move(hybridSyms);
+ }
+ }
+
// Create .idata contents for each DLL.
for (std::vector<DefinedImportData *> &syms : v) {
// Create lookup and address tables. If they have external names,
// we need to create hintName chunks to store the names.
// If they don't (if they are import-by-ordinals), we store only
// ordinal values to the table.
size_t base = lookups.size();
+ Chunk *lookupsTerminator = nullptr, *addressesTerminator = nullptr;
for (DefinedImportData *s : syms) {
uint16_t ord = s->getOrdinal();
+ HintNameChunk *hintChunk = nullptr;
+ Chunk *lookupsChunk, *addressesChunk;
+
if (s->getExternalName().empty()) {
- lookups.push_back(make<OrdinalOnlyChunk>(ctx, ord));
- addresses.push_back(make<OrdinalOnlyChunk>(ctx, ord));
+ lookupsChunk = make<OrdinalOnlyChunk>(ctx, ord);
+ addressesChunk = make<OrdinalOnlyChunk>(ctx, ord);
} else {
- auto *c = make<HintNameChunk>(s->getExternalName(), ord);
- lookups.push_back(make<LookupChunk>(ctx, c));
- addresses.push_back(make<LookupChunk>(ctx, c));
- hints.push_back(c);
+ hintChunk = make<HintNameChunk>(s->getExternalName(), ord);
+ lookupsChunk = make<LookupChunk>(ctx, hintChunk);
+ addressesChunk = make<LookupChunk>(ctx, hintChunk);
+ hints.push_back(hintChunk);
}
- if (s->file->impECSym) {
+ // Detect the first EC-only import in the hybrid IAT. Emit null chunks
----------------
mstorsjo wrote:
Nit: As it is only one chunk that is inserted, would it be clearer to just mention "a null chunk" here? (The next row talks about "as a terminator" - if we keep the plural form here we probably should say "as terminators" below as well?)
https://github.com/llvm/llvm-project/pull/124189
More information about the llvm-commits
mailing list