1455 lines · cpp
1//===- SymbolTable.cpp ----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "SymbolTable.h"10#include "COFFLinkerContext.h"11#include "Config.h"12#include "Driver.h"13#include "LTO.h"14#include "PDB.h"15#include "Symbols.h"16#include "lld/Common/ErrorHandler.h"17#include "lld/Common/Memory.h"18#include "lld/Common/Timer.h"19#include "llvm/DebugInfo/DIContext.h"20#include "llvm/IR/LLVMContext.h"21#include "llvm/IR/Mangler.h"22#include "llvm/LTO/LTO.h"23#include "llvm/Object/COFFModuleDefinition.h"24#include "llvm/Support/Debug.h"25#include "llvm/Support/GlobPattern.h"26#include "llvm/Support/Parallel.h"27#include "llvm/Support/TimeProfiler.h"28#include "llvm/Support/raw_ostream.h"29#include <utility>30 31using namespace llvm;32using namespace llvm::COFF;33using namespace llvm::object;34using namespace llvm::support;35 36namespace lld::coff {37 38StringRef ltrim1(StringRef s, const char *chars) {39 if (!s.empty() && strchr(chars, s[0]))40 return s.substr(1);41 return s;42}43 44static COFFSyncStream errorOrWarn(COFFLinkerContext &ctx) {45 return {ctx, ctx.config.forceUnresolved ? DiagLevel::Warn : DiagLevel::Err};46}47 48// Causes the file associated with a lazy symbol to be linked in.49static void forceLazy(Symbol *s) {50 s->pendingArchiveLoad = true;51 switch (s->kind()) {52 case Symbol::Kind::LazyArchiveKind: {53 auto *l = cast<LazyArchive>(s);54 l->file->addMember(l->sym);55 break;56 }57 case Symbol::Kind::LazyObjectKind: {58 InputFile *file = cast<LazyObject>(s)->file;59 // FIXME: Remove this once we resolve all defineds before all undefineds in60 // ObjFile::initializeSymbols().61 if (!file->lazy)62 return;63 file->lazy = false;64 file->symtab.ctx.driver.addFile(file);65 break;66 }67 case Symbol::Kind::LazyDLLSymbolKind: {68 auto *l = cast<LazyDLLSymbol>(s);69 l->file->makeImport(l->sym);70 break;71 }72 default:73 llvm_unreachable(74 "symbol passed to forceLazy is not a LazyArchive or LazyObject");75 }76}77 78// Returns the symbol in SC whose value is <= Addr that is closest to Addr.79// This is generally the global variable or function whose definition contains80// Addr.81static Symbol *getSymbol(SectionChunk *sc, uint32_t addr) {82 DefinedRegular *candidate = nullptr;83 84 for (Symbol *s : sc->file->getSymbols()) {85 auto *d = dyn_cast_or_null<DefinedRegular>(s);86 if (!d || !d->data || d->file != sc->file || d->getChunk() != sc ||87 d->getValue() > addr ||88 (candidate && d->getValue() < candidate->getValue()))89 continue;90 91 candidate = d;92 }93 94 return candidate;95}96 97static std::vector<std::string> getSymbolLocations(BitcodeFile *file) {98 std::string res("\n>>> referenced by ");99 StringRef source = file->obj->getSourceFileName();100 if (!source.empty())101 res += source.str() + "\n>>> ";102 res += toString(file);103 return {res};104}105 106static std::optional<std::pair<StringRef, uint32_t>>107getFileLineDwarf(const SectionChunk *c, uint32_t addr) {108 std::optional<DILineInfo> optionalLineInfo =109 c->file->getDILineInfo(addr, c->getSectionNumber() - 1);110 if (!optionalLineInfo)111 return std::nullopt;112 const DILineInfo &lineInfo = *optionalLineInfo;113 if (lineInfo.FileName == DILineInfo::BadString)114 return std::nullopt;115 return std::make_pair(saver().save(lineInfo.FileName), lineInfo.Line);116}117 118static std::optional<std::pair<StringRef, uint32_t>>119getFileLine(const SectionChunk *c, uint32_t addr) {120 // MinGW can optionally use codeview, even if the default is dwarf.121 std::optional<std::pair<StringRef, uint32_t>> fileLine =122 getFileLineCodeView(c, addr);123 // If codeview didn't yield any result, check dwarf in MinGW mode.124 if (!fileLine && c->file->symtab.ctx.config.mingw)125 fileLine = getFileLineDwarf(c, addr);126 return fileLine;127}128 129// Given a file and the index of a symbol in that file, returns a description130// of all references to that symbol from that file. If no debug information is131// available, returns just the name of the file, else one string per actual132// reference as described in the debug info.133// Returns up to maxStrings string descriptions, along with the total number of134// locations found.135static std::pair<std::vector<std::string>, size_t>136getSymbolLocations(ObjFile *file, uint32_t symIndex, size_t maxStrings) {137 struct Location {138 Symbol *sym;139 std::pair<StringRef, uint32_t> fileLine;140 };141 std::vector<Location> locations;142 size_t numLocations = 0;143 144 for (Chunk *c : file->getChunks()) {145 auto *sc = dyn_cast<SectionChunk>(c);146 if (!sc)147 continue;148 for (const coff_relocation &r : sc->getRelocs()) {149 if (r.SymbolTableIndex != symIndex)150 continue;151 numLocations++;152 if (locations.size() >= maxStrings)153 continue;154 155 std::optional<std::pair<StringRef, uint32_t>> fileLine =156 getFileLine(sc, r.VirtualAddress);157 Symbol *sym = getSymbol(sc, r.VirtualAddress);158 if (fileLine)159 locations.push_back({sym, *fileLine});160 else if (sym)161 locations.push_back({sym, {"", 0}});162 }163 }164 165 if (maxStrings == 0)166 return std::make_pair(std::vector<std::string>(), numLocations);167 168 if (numLocations == 0)169 return std::make_pair(170 std::vector<std::string>{"\n>>> referenced by " + toString(file)}, 1);171 172 std::vector<std::string> symbolLocations(locations.size());173 size_t i = 0;174 for (Location loc : locations) {175 llvm::raw_string_ostream os(symbolLocations[i++]);176 os << "\n>>> referenced by ";177 if (!loc.fileLine.first.empty())178 os << loc.fileLine.first << ":" << loc.fileLine.second179 << "\n>>> ";180 os << toString(file);181 if (loc.sym)182 os << ":(" << toString(file->symtab.ctx, *loc.sym) << ')';183 }184 return std::make_pair(symbolLocations, numLocations);185}186 187std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) {188 return getSymbolLocations(file, symIndex, SIZE_MAX).first;189}190 191static std::pair<std::vector<std::string>, size_t>192getSymbolLocations(InputFile *file, uint32_t symIndex, size_t maxStrings) {193 if (auto *o = dyn_cast<ObjFile>(file))194 return getSymbolLocations(o, symIndex, maxStrings);195 if (auto *b = dyn_cast<BitcodeFile>(file)) {196 std::vector<std::string> symbolLocations = getSymbolLocations(b);197 size_t numLocations = symbolLocations.size();198 if (symbolLocations.size() > maxStrings)199 symbolLocations.resize(maxStrings);200 return std::make_pair(symbolLocations, numLocations);201 }202 llvm_unreachable("unsupported file type passed to getSymbolLocations");203 return std::make_pair(std::vector<std::string>(), (size_t)0);204}205 206// For an undefined symbol, stores all files referencing it and the index of207// the undefined symbol in each file.208struct UndefinedDiag {209 Symbol *sym;210 struct File {211 InputFile *file;212 uint32_t symIndex;213 };214 std::vector<File> files;215};216 217void SymbolTable::reportUndefinedSymbol(const UndefinedDiag &undefDiag) {218 auto diag = errorOrWarn(ctx);219 diag << "undefined symbol: " << printSymbol(undefDiag.sym);220 221 const size_t maxUndefReferences = 3;222 size_t numDisplayedRefs = 0, numRefs = 0;223 for (const UndefinedDiag::File &ref : undefDiag.files) {224 auto [symbolLocations, totalLocations] = getSymbolLocations(225 ref.file, ref.symIndex, maxUndefReferences - numDisplayedRefs);226 227 numRefs += totalLocations;228 numDisplayedRefs += symbolLocations.size();229 for (const std::string &s : symbolLocations)230 diag << s;231 }232 if (numDisplayedRefs < numRefs)233 diag << "\n>>> referenced " << numRefs - numDisplayedRefs << " more times";234 235 // Hints236 StringRef name = undefDiag.sym->getName();237 if (name.consume_front("__imp_")) {238 Symbol *imp = find(name);239 if (imp && imp->isLazy()) {240 diag << "\nNOTE: a relevant symbol '" << imp->getName()241 << "' is available in " << toString(imp->getFile())242 << " but cannot be used because it is not an import library.";243 }244 }245}246 247void SymbolTable::loadMinGWSymbols() {248 std::vector<Symbol *> undefs;249 for (auto &i : symMap) {250 Symbol *sym = i.second;251 auto *undef = dyn_cast<Undefined>(sym);252 if (!undef)253 continue;254 if (undef->getWeakAlias())255 continue;256 undefs.push_back(sym);257 }258 259 for (auto sym : undefs) {260 auto *undef = dyn_cast<Undefined>(sym);261 if (!undef)262 continue;263 if (undef->getWeakAlias())264 continue;265 StringRef name = undef->getName();266 267 if (machine == I386 && ctx.config.stdcallFixup) {268 // Check if we can resolve an undefined decorated symbol by finding269 // the intended target as an undecorated symbol (only with a leading270 // underscore).271 StringRef origName = name;272 StringRef baseName = name;273 // Trim down stdcall/fastcall/vectorcall symbols to the base name.274 baseName = ltrim1(baseName, "_@");275 baseName = baseName.substr(0, baseName.find('@'));276 // Add a leading underscore, as it would be in cdecl form.277 std::string newName = ("_" + baseName).str();278 Symbol *l;279 if (newName != origName && (l = find(newName)) != nullptr) {280 // If we found a symbol and it is lazy; load it.281 if (l->isLazy() && !l->pendingArchiveLoad) {282 Log(ctx) << "Loading lazy " << l->getName() << " from "283 << l->getFile()->getName() << " for stdcall fixup";284 forceLazy(l);285 }286 // If it's lazy or already defined, hook it up as weak alias.287 if (l->isLazy() || isa<Defined>(l)) {288 if (ctx.config.warnStdcallFixup)289 Warn(ctx) << "Resolving " << origName << " by linking to "290 << newName;291 else292 Log(ctx) << "Resolving " << origName << " by linking to "293 << newName;294 undef->setWeakAlias(l);295 continue;296 }297 }298 }299 300 if (ctx.config.autoImport) {301 if (name.starts_with("__imp_"))302 continue;303 // If we have an undefined symbol, but we have a lazy symbol we could304 // load, load it.305 Symbol *l = find(("__imp_" + name).str());306 if (!l || l->pendingArchiveLoad || !l->isLazy())307 continue;308 309 Log(ctx) << "Loading lazy " << l->getName() << " from "310 << l->getFile()->getName() << " for automatic import";311 forceLazy(l);312 }313 }314}315 316Defined *SymbolTable::impSymbol(StringRef name) {317 if (name.starts_with("__imp_"))318 return nullptr;319 return dyn_cast_or_null<Defined>(find(("__imp_" + name).str()));320}321 322bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) {323 Defined *imp = impSymbol(name);324 if (!imp)325 return false;326 327 // Replace the reference directly to a variable with a reference328 // to the import address table instead. This obviously isn't right,329 // but we mark the symbol as isRuntimePseudoReloc, and a later pass330 // will add runtime pseudo relocations for every relocation against331 // this Symbol. The runtime pseudo relocation framework expects the332 // reference itself to point at the IAT entry.333 size_t impSize = 0;334 if (isa<DefinedImportData>(imp)) {335 Log(ctx) << "Automatically importing " << name << " from "336 << cast<DefinedImportData>(imp)->getDLLName();337 impSize = sizeof(DefinedImportData);338 } else if (isa<DefinedRegular>(imp)) {339 Log(ctx) << "Automatically importing " << name << " from "340 << toString(cast<DefinedRegular>(imp)->file);341 impSize = sizeof(DefinedRegular);342 } else {343 Warn(ctx) << "unable to automatically import " << name << " from "344 << imp->getName() << " from " << cast<DefinedRegular>(imp)->file345 << "; unexpected symbol type";346 return false;347 }348 sym->replaceKeepingName(imp, impSize);349 sym->isRuntimePseudoReloc = true;350 351 // There may exist symbols named .refptr.<name> which only consist352 // of a single pointer to <name>. If it turns out <name> is353 // automatically imported, we don't need to keep the .refptr.<name>354 // pointer at all, but redirect all accesses to it to the IAT entry355 // for __imp_<name> instead, and drop the whole .refptr.<name> chunk.356 DefinedRegular *refptr =357 dyn_cast_or_null<DefinedRegular>(find((".refptr." + name).str()));358 if (refptr && refptr->getChunk()->getSize() == ctx.config.wordsize) {359 SectionChunk *sc = dyn_cast_or_null<SectionChunk>(refptr->getChunk());360 if (sc && sc->getRelocs().size() == 1 && *sc->symbols().begin() == sym) {361 Log(ctx) << "Replacing .refptr." << name << " with " << imp->getName();362 refptr->getChunk()->live = false;363 refptr->replaceKeepingName(imp, impSize);364 }365 }366 return true;367}368 369/// Helper function for reportUnresolvable and resolveRemainingUndefines.370/// This function emits an "undefined symbol" diagnostic for each symbol in371/// undefs. If localImports is not nullptr, it also emits a "locally372/// defined symbol imported" diagnostic for symbols in localImports.373/// objFiles and bitcodeFiles (if not nullptr) are used to report where374/// undefined symbols are referenced.375void SymbolTable::reportProblemSymbols(376 const SmallPtrSetImpl<Symbol *> &undefs,377 const DenseMap<Symbol *, Symbol *> *localImports, bool needBitcodeFiles) {378 // Return early if there is nothing to report (which should be379 // the common case).380 if (undefs.empty() && (!localImports || localImports->empty()))381 return;382 383 for (Symbol *b : ctx.config.gcroot) {384 if (undefs.count(b))385 errorOrWarn(ctx) << "<root>: undefined symbol: " << printSymbol(b);386 if (localImports)387 if (Symbol *imp = localImports->lookup(b))388 Warn(ctx) << "<root>: locally defined symbol imported: "389 << printSymbol(imp) << " (defined in "390 << toString(imp->getFile()) << ") [LNK4217]";391 }392 393 std::vector<UndefinedDiag> undefDiags;394 DenseMap<Symbol *, int> firstDiag;395 396 auto processFile = [&](InputFile *file, ArrayRef<Symbol *> symbols) {397 uint32_t symIndex = (uint32_t)-1;398 for (Symbol *sym : symbols) {399 ++symIndex;400 if (!sym)401 continue;402 if (undefs.count(sym)) {403 auto [it, inserted] = firstDiag.try_emplace(sym, undefDiags.size());404 if (inserted)405 undefDiags.push_back({sym, {{file, symIndex}}});406 else407 undefDiags[it->second].files.push_back({file, symIndex});408 }409 if (localImports)410 if (Symbol *imp = localImports->lookup(sym))411 Warn(ctx) << file412 << ": locally defined symbol imported: " << printSymbol(imp)413 << " (defined in " << imp->getFile() << ") [LNK4217]";414 }415 };416 417 for (ObjFile *file : ctx.objFileInstances)418 processFile(file, file->getSymbols());419 420 if (needBitcodeFiles)421 for (BitcodeFile *file : bitcodeFileInstances)422 processFile(file, file->getSymbols());423 424 for (const UndefinedDiag &undefDiag : undefDiags)425 reportUndefinedSymbol(undefDiag);426}427 428void SymbolTable::reportUnresolvable() {429 SmallPtrSet<Symbol *, 8> undefs;430 for (auto &i : symMap) {431 Symbol *sym = i.second;432 auto *undef = dyn_cast<Undefined>(sym);433 if (!undef || sym->deferUndefined)434 continue;435 if (undef->getWeakAlias())436 continue;437 StringRef name = undef->getName();438 if (name.starts_with("__imp_")) {439 Symbol *imp = find(name.substr(strlen("__imp_")));440 if (Defined *def = dyn_cast_or_null<Defined>(imp)) {441 def->isUsedInRegularObj = true;442 continue;443 }444 }445 if (name.contains("_PchSym_"))446 continue;447 if (ctx.config.autoImport && impSymbol(name))448 continue;449 undefs.insert(sym);450 }451 452 reportProblemSymbols(undefs, /*localImports=*/nullptr, true);453}454 455void SymbolTable::resolveRemainingUndefines(std::vector<Undefined *> &aliases) {456 llvm::TimeTraceScope timeScope("Resolve remaining undefined symbols");457 SmallPtrSet<Symbol *, 8> undefs;458 DenseMap<Symbol *, Symbol *> localImports;459 460 for (auto &i : symMap) {461 Symbol *sym = i.second;462 auto *undef = dyn_cast<Undefined>(sym);463 if (!undef)464 continue;465 if (!sym->isUsedInRegularObj)466 continue;467 468 StringRef name = undef->getName();469 470 // A weak alias may have been resolved, so check for that.471 if (undef->getWeakAlias()) {472 aliases.push_back(undef);473 continue;474 }475 476 // If we can resolve a symbol by removing __imp_ prefix, do that.477 // This odd rule is for compatibility with MSVC linker.478 if (name.starts_with("__imp_")) {479 auto findLocalSym = [&](StringRef n) {480 Symbol *sym = find(n);481 return sym ? sym->getDefined() : nullptr;482 };483 484 StringRef impName = name.substr(strlen("__imp_"));485 Defined *imp = findLocalSym(impName);486 if (!imp && isEC()) {487 // Try to use the mangled symbol on ARM64EC.488 std::optional<std::string> mangledName =489 getArm64ECMangledFunctionName(impName);490 if (mangledName)491 imp = findLocalSym(*mangledName);492 if (!imp && impName.consume_front("aux_")) {493 // If it's a __imp_aux_ symbol, try skipping the aux_ prefix.494 imp = findLocalSym(impName);495 if (!imp && (mangledName = getArm64ECMangledFunctionName(impName)))496 imp = findLocalSym(*mangledName);497 }498 }499 if (imp) {500 replaceSymbol<DefinedLocalImport>(sym, ctx, name, imp);501 localImportChunks.push_back(cast<DefinedLocalImport>(sym)->getChunk());502 localImports[sym] = imp;503 continue;504 }505 }506 507 // We don't want to report missing Microsoft precompiled headers symbols.508 // A proper message will be emitted instead in PDBLinker::aquirePrecompObj509 if (name.contains("_PchSym_"))510 continue;511 512 if (ctx.config.autoImport && handleMinGWAutomaticImport(sym, name))513 continue;514 515 // Remaining undefined symbols are not fatal if /force is specified.516 // They are replaced with dummy defined symbols.517 if (ctx.config.forceUnresolved)518 replaceSymbol<DefinedAbsolute>(sym, ctx, name, 0);519 undefs.insert(sym);520 }521 522 reportProblemSymbols(523 undefs, ctx.config.warnLocallyDefinedImported ? &localImports : nullptr,524 false);525}526 527std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {528 bool inserted = false;529 Symbol *&sym = symMap[CachedHashStringRef(name)];530 if (!sym) {531 sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());532 sym->isUsedInRegularObj = false;533 sym->pendingArchiveLoad = false;534 sym->canInline = true;535 inserted = true;536 537 if (isEC() && name.starts_with("EXP+"))538 expSymbols.push_back(sym);539 }540 return {sym, inserted};541}542 543std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, InputFile *file) {544 std::pair<Symbol *, bool> result = insert(name);545 if (!file || !isa<BitcodeFile>(file))546 result.first->isUsedInRegularObj = true;547 return result;548}549 550void SymbolTable::initializeLoadConfig() {551 auto sym =552 dyn_cast_or_null<DefinedRegular>(findUnderscore("_load_config_used"));553 if (!sym) {554 if (isEC()) {555 Warn(ctx) << "EC version of '_load_config_used' is missing";556 return;557 }558 if (ctx.config.machine == ARM64X) {559 Warn(ctx) << "native version of '_load_config_used' is missing for "560 "ARM64X target";561 return;562 }563 if (ctx.config.guardCF != GuardCFLevel::Off)564 Warn(ctx)565 << "Control Flow Guard is enabled but '_load_config_used' is missing";566 if (ctx.config.dependentLoadFlags)567 Warn(ctx) << "_load_config_used not found, /dependentloadflag will have "568 "no effect";569 return;570 }571 572 SectionChunk *sc = sym->getChunk();573 if (!sc->hasData) {574 Err(ctx) << "_load_config_used points to uninitialized data";575 return;576 }577 uint64_t offsetInChunk = sym->getValue();578 if (offsetInChunk + 4 > sc->getSize()) {579 Err(ctx) << "_load_config_used section chunk is too small";580 return;581 }582 583 ArrayRef<uint8_t> secContents = sc->getContents();584 loadConfigSize =585 *reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]);586 if (offsetInChunk + loadConfigSize > sc->getSize()) {587 Err(ctx) << "_load_config_used specifies a size larger than its containing "588 "section chunk";589 return;590 }591 592 uint32_t expectedAlign = ctx.config.is64() ? 8 : 4;593 if (sc->getAlignment() < expectedAlign)594 Warn(ctx) << "'_load_config_used' is misaligned (expected alignment to be "595 << expectedAlign << " bytes, got " << sc->getAlignment()596 << " instead)";597 else if (!isAligned(Align(expectedAlign), offsetInChunk))598 Warn(ctx) << "'_load_config_used' is misaligned (section offset is 0x"599 << Twine::utohexstr(sym->getValue()) << " not aligned to "600 << expectedAlign << " bytes)";601 602 loadConfigSym = sym;603}604 605void SymbolTable::addEntryThunk(Symbol *from, Symbol *to) {606 entryThunks.push_back({from, to});607}608 609void SymbolTable::addExitThunk(Symbol *from, Symbol *to) {610 exitThunks[from] = to;611}612 613void SymbolTable::initializeECThunks() {614 if (!isArm64EC(ctx.config.machine))615 return;616 617 for (auto it : entryThunks) {618 Defined *to = it.second->getDefined();619 if (!to)620 continue;621 auto *from = dyn_cast_or_null<DefinedRegular>(it.first->getDefined());622 // We need to be able to add padding to the function and fill it with an623 // offset to its entry thunks. To ensure that padding the function is624 // feasible, functions are required to be COMDAT symbols with no offset.625 if (!from || !from->getChunk()->isCOMDAT() ||626 cast<DefinedRegular>(from)->getValue()) {627 Err(ctx) << "non COMDAT symbol '" << from->getName() << "' in hybrid map";628 continue;629 }630 from->getChunk()->setEntryThunk(to);631 }632 633 for (ImportFile *file : ctx.importFileInstances) {634 if (!file->impchkThunk)635 continue;636 637 Symbol *sym = exitThunks.lookup(file->thunkSym);638 if (!sym)639 sym = exitThunks.lookup(file->impECSym);640 if (sym)641 file->impchkThunk->exitThunk = sym->getDefined();642 }643 644 // On ARM64EC, the __imp_ symbol references the auxiliary IAT, while the645 // __imp_aux_ symbol references the regular IAT. However, x86_64 code expects646 // both to reference the regular IAT, so adjust the symbol if necessary.647 parallelForEach(ctx.objFileInstances, [&](ObjFile *file) {648 if (file->getMachineType() != AMD64)649 return;650 for (auto &sym : file->getMutableSymbols()) {651 auto impSym = dyn_cast_or_null<DefinedImportData>(sym);652 if (impSym && impSym->file->impchkThunk && sym == impSym->file->impECSym)653 sym = impSym->file->impSym;654 }655 });656}657 658void SymbolTable::initializeSameAddressThunks() {659 for (auto iter : ctx.config.sameAddresses) {660 auto sym = dyn_cast_or_null<DefinedRegular>(iter.first->getDefined());661 if (!sym || !sym->isLive())662 continue;663 auto nativeSym =664 dyn_cast_or_null<DefinedRegular>(iter.second->getDefined());665 if (!nativeSym || !nativeSym->isLive())666 continue;667 Defined *entryThunk = sym->getChunk()->getEntryThunk();668 if (!entryThunk)669 continue;670 671 // Replace symbols with symbols referencing the thunk. Store the original672 // symbol as equivalent DefinedSynthetic instances for use in the thunk673 // itself.674 auto symClone = make<DefinedSynthetic>(sym->getName(), sym->getChunk(),675 sym->getValue());676 auto nativeSymClone = make<DefinedSynthetic>(677 nativeSym->getName(), nativeSym->getChunk(), nativeSym->getValue());678 SameAddressThunkARM64EC *thunk =679 make<SameAddressThunkARM64EC>(nativeSymClone, symClone, entryThunk);680 sameAddressThunks.push_back(thunk);681 682 replaceSymbol<DefinedSynthetic>(sym, sym->getName(), thunk);683 replaceSymbol<DefinedSynthetic>(nativeSym, nativeSym->getName(), thunk);684 }685}686 687Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f,688 bool overrideLazy) {689 auto [s, wasInserted] = insert(name, f);690 if (wasInserted || (s->isLazy() && overrideLazy)) {691 replaceSymbol<Undefined>(s, name);692 return s;693 }694 if (s->isLazy())695 forceLazy(s);696 return s;697}698 699Symbol *SymbolTable::addGCRoot(StringRef name, bool aliasEC) {700 Symbol *b = addUndefined(name);701 if (!b->isGCRoot) {702 b->isGCRoot = true;703 ctx.config.gcroot.push_back(b);704 }705 706 // On ARM64EC, a symbol may be defined in either its mangled or demangled form707 // (or both). Define an anti-dependency symbol that binds both forms, similar708 // to how compiler-generated code references external functions.709 if (aliasEC && isEC()) {710 if (std::optional<std::string> mangledName =711 getArm64ECMangledFunctionName(name)) {712 auto u = dyn_cast<Undefined>(b);713 if (u && !u->weakAlias) {714 Symbol *t = addUndefined(saver().save(*mangledName));715 u->setWeakAlias(t, true);716 }717 } else if (std::optional<std::string> demangledName =718 getArm64ECDemangledFunctionName(name)) {719 Symbol *us = addUndefined(saver().save(*demangledName));720 auto u = dyn_cast<Undefined>(us);721 if (u && !u->weakAlias)722 u->setWeakAlias(b, true);723 }724 }725 return b;726}727 728// On ARM64EC, a function symbol may appear in both mangled and demangled forms:729// - ARM64EC archives contain only the mangled name, while the demangled symbol730// is defined by the object file as an alias.731// - x86_64 archives contain only the demangled name (the mangled name is732// usually defined by an object referencing the symbol as an alias to a guess733// exit thunk).734// - ARM64EC import files contain both the mangled and demangled names for735// thunks.736// If more than one archive defines the same function, this could lead737// to different libraries being used for the same function depending on how they738// are referenced. Avoid this by checking if the paired symbol is already739// defined before adding a symbol to the table.740template <typename T>741bool checkLazyECPair(SymbolTable *symtab, StringRef name, InputFile *f) {742 if (name.starts_with("__imp_"))743 return true;744 std::string pairName;745 if (std::optional<std::string> mangledName =746 getArm64ECMangledFunctionName(name))747 pairName = std::move(*mangledName);748 else if (std::optional<std::string> demangledName =749 getArm64ECDemangledFunctionName(name))750 pairName = std::move(*demangledName);751 else752 return true;753 754 Symbol *sym = symtab->find(pairName);755 if (!sym)756 return true;757 if (sym->pendingArchiveLoad)758 return false;759 if (auto u = dyn_cast<Undefined>(sym))760 return !u->weakAlias || u->isAntiDep;761 // If the symbol is lazy, allow it only if it originates from the same762 // archive.763 auto lazy = dyn_cast<T>(sym);764 return lazy && lazy->file == f;765}766 767void SymbolTable::addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym) {768 StringRef name = sym.getName();769 if (isEC() && !checkLazyECPair<LazyArchive>(this, name, f))770 return;771 auto [s, wasInserted] = insert(name);772 if (wasInserted) {773 replaceSymbol<LazyArchive>(s, f, sym);774 return;775 }776 auto *u = dyn_cast<Undefined>(s);777 if (!u || (u->weakAlias && !u->isECAlias(machine)) || s->pendingArchiveLoad)778 return;779 s->pendingArchiveLoad = true;780 f->addMember(sym);781}782 783void SymbolTable::addLazyObject(InputFile *f, StringRef n) {784 assert(f->lazy);785 if (isEC() && !checkLazyECPair<LazyObject>(this, n, f))786 return;787 auto [s, wasInserted] = insert(n, f);788 if (wasInserted) {789 replaceSymbol<LazyObject>(s, f, n);790 return;791 }792 auto *u = dyn_cast<Undefined>(s);793 if (!u || (u->weakAlias && !u->isECAlias(machine)) || s->pendingArchiveLoad)794 return;795 s->pendingArchiveLoad = true;796 f->lazy = false;797 ctx.driver.addFile(f);798}799 800void SymbolTable::addLazyDLLSymbol(DLLFile *f, DLLFile::Symbol *sym,801 StringRef n) {802 auto [s, wasInserted] = insert(n);803 if (wasInserted) {804 replaceSymbol<LazyDLLSymbol>(s, f, sym, n);805 return;806 }807 auto *u = dyn_cast<Undefined>(s);808 if (!u || (u->weakAlias && !u->isECAlias(machine)) || s->pendingArchiveLoad)809 return;810 s->pendingArchiveLoad = true;811 f->makeImport(sym);812}813 814static std::string getSourceLocationBitcode(BitcodeFile *file) {815 std::string res("\n>>> defined at ");816 StringRef source = file->obj->getSourceFileName();817 if (!source.empty())818 res += source.str() + "\n>>> ";819 res += toString(file);820 return res;821}822 823static std::string getSourceLocationObj(ObjFile *file, SectionChunk *sc,824 uint32_t offset, StringRef name) {825 std::optional<std::pair<StringRef, uint32_t>> fileLine;826 if (sc)827 fileLine = getFileLine(sc, offset);828 if (!fileLine)829 fileLine = file->getVariableLocation(name);830 831 std::string res;832 llvm::raw_string_ostream os(res);833 os << "\n>>> defined at ";834 if (fileLine)835 os << fileLine->first << ":" << fileLine->second << "\n>>> ";836 os << toString(file);837 return res;838}839 840static std::string getSourceLocation(InputFile *file, SectionChunk *sc,841 uint32_t offset, StringRef name) {842 if (!file)843 return "";844 if (auto *o = dyn_cast<ObjFile>(file))845 return getSourceLocationObj(o, sc, offset, name);846 if (auto *b = dyn_cast<BitcodeFile>(file))847 return getSourceLocationBitcode(b);848 return "\n>>> defined at " + toString(file);849}850 851// Construct and print an error message in the form of:852//853// lld-link: error: duplicate symbol: foo854// >>> defined at bar.c:30855// >>> bar.o856// >>> defined at baz.c:563857// >>> baz.o858void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile,859 SectionChunk *newSc,860 uint32_t newSectionOffset) {861 COFFSyncStream diag(ctx, ctx.config.forceMultiple ? DiagLevel::Warn862 : DiagLevel::Err);863 diag << "duplicate symbol: " << printSymbol(existing);864 865 DefinedRegular *d = dyn_cast<DefinedRegular>(existing);866 if (d && isa<ObjFile>(d->getFile())) {867 diag << getSourceLocation(d->getFile(), d->getChunk(), d->getValue(),868 existing->getName());869 } else {870 diag << getSourceLocation(existing->getFile(), nullptr, 0, "");871 }872 diag << getSourceLocation(newFile, newSc, newSectionOffset,873 existing->getName());874}875 876Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) {877 auto [s, wasInserted] = insert(n, nullptr);878 s->isUsedInRegularObj = true;879 if (wasInserted || isa<Undefined>(s) || s->isLazy())880 replaceSymbol<DefinedAbsolute>(s, ctx, n, sym);881 else if (auto *da = dyn_cast<DefinedAbsolute>(s)) {882 if (da->getVA() != sym.getValue())883 reportDuplicate(s, nullptr);884 } else if (!isa<DefinedCOFF>(s))885 reportDuplicate(s, nullptr);886 return s;887}888 889Symbol *SymbolTable::addAbsolute(StringRef n, uint64_t va) {890 auto [s, wasInserted] = insert(n, nullptr);891 s->isUsedInRegularObj = true;892 if (wasInserted || isa<Undefined>(s) || s->isLazy())893 replaceSymbol<DefinedAbsolute>(s, ctx, n, va);894 else if (auto *da = dyn_cast<DefinedAbsolute>(s)) {895 if (da->getVA() != va)896 reportDuplicate(s, nullptr);897 } else if (!isa<DefinedCOFF>(s))898 reportDuplicate(s, nullptr);899 return s;900}901 902Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) {903 auto [s, wasInserted] = insert(n, nullptr);904 s->isUsedInRegularObj = true;905 if (wasInserted || isa<Undefined>(s) || s->isLazy())906 replaceSymbol<DefinedSynthetic>(s, n, c);907 else if (!isa<DefinedCOFF>(s))908 reportDuplicate(s, nullptr);909 return s;910}911 912Symbol *SymbolTable::addRegular(InputFile *f, StringRef n,913 const coff_symbol_generic *sym, SectionChunk *c,914 uint32_t sectionOffset, bool isWeak) {915 auto [s, wasInserted] = insert(n, f);916 if (wasInserted || !isa<DefinedRegular>(s) || s->isWeak)917 replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ false,918 /*IsExternal*/ true, sym, c, isWeak);919 else if (!isWeak)920 reportDuplicate(s, f, c, sectionOffset);921 return s;922}923 924std::pair<DefinedRegular *, bool>925SymbolTable::addComdat(InputFile *f, StringRef n,926 const coff_symbol_generic *sym) {927 auto [s, wasInserted] = insert(n, f);928 if (wasInserted || !isa<DefinedRegular>(s)) {929 replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ true,930 /*IsExternal*/ true, sym, nullptr);931 return {cast<DefinedRegular>(s), true};932 }933 auto *existingSymbol = cast<DefinedRegular>(s);934 if (!existingSymbol->isCOMDAT)935 reportDuplicate(s, f);936 return {existingSymbol, false};937}938 939Symbol *SymbolTable::addCommon(InputFile *f, StringRef n, uint64_t size,940 const coff_symbol_generic *sym, CommonChunk *c) {941 auto [s, wasInserted] = insert(n, f);942 if (wasInserted || !isa<DefinedCOFF>(s))943 replaceSymbol<DefinedCommon>(s, f, n, size, sym, c);944 else if (auto *dc = dyn_cast<DefinedCommon>(s))945 if (size > dc->getSize())946 replaceSymbol<DefinedCommon>(s, f, n, size, sym, c);947 return s;948}949 950DefinedImportData *SymbolTable::addImportData(StringRef n, ImportFile *f,951 Chunk *&location) {952 auto [s, wasInserted] = insert(n, nullptr);953 s->isUsedInRegularObj = true;954 if (wasInserted || isa<Undefined>(s) || s->isLazy()) {955 replaceSymbol<DefinedImportData>(s, n, f, location);956 return cast<DefinedImportData>(s);957 }958 959 reportDuplicate(s, f);960 return nullptr;961}962 963Defined *SymbolTable::addImportThunk(StringRef name, DefinedImportData *id,964 ImportThunkChunk *chunk) {965 auto [s, wasInserted] = insert(name, nullptr);966 s->isUsedInRegularObj = true;967 if (wasInserted || isa<Undefined>(s) || s->isLazy()) {968 replaceSymbol<DefinedImportThunk>(s, ctx, name, id, chunk);969 return cast<Defined>(s);970 }971 972 reportDuplicate(s, id->file);973 return nullptr;974}975 976void SymbolTable::addLibcall(StringRef name) {977 Symbol *sym = findUnderscore(name);978 if (!sym)979 return;980 981 if (auto *l = dyn_cast<LazyArchive>(sym)) {982 MemoryBufferRef mb = l->getMemberBuffer();983 if (isBitcode(mb))984 addUndefined(sym->getName());985 } else if (LazyObject *o = dyn_cast<LazyObject>(sym)) {986 if (isBitcode(o->file->mb))987 addUndefined(sym->getName());988 }989}990 991Symbol *SymbolTable::find(StringRef name) const {992 return symMap.lookup(CachedHashStringRef(name));993}994 995Symbol *SymbolTable::findUnderscore(StringRef name) const {996 if (machine == I386)997 return find(("_" + name).str());998 return find(name);999}1000 1001// Return all symbols that start with Prefix, possibly ignoring the first1002// character of Prefix or the first character symbol.1003std::vector<Symbol *> SymbolTable::getSymsWithPrefix(StringRef prefix) {1004 std::vector<Symbol *> syms;1005 for (auto pair : symMap) {1006 StringRef name = pair.first.val();1007 if (name.starts_with(prefix) || name.starts_with(prefix.drop_front()) ||1008 name.drop_front().starts_with(prefix) ||1009 name.drop_front().starts_with(prefix.drop_front())) {1010 syms.push_back(pair.second);1011 }1012 }1013 return syms;1014}1015 1016Symbol *SymbolTable::findMangle(StringRef name) {1017 if (Symbol *sym = find(name)) {1018 if (auto *u = dyn_cast<Undefined>(sym)) {1019 // We're specifically looking for weak aliases that ultimately resolve to1020 // defined symbols, hence the call to getWeakAlias() instead of just using1021 // the weakAlias member variable. This matches link.exe's behavior.1022 if (Symbol *weakAlias = u->getWeakAlias())1023 return weakAlias;1024 } else {1025 return sym;1026 }1027 }1028 1029 // Efficient fuzzy string lookup is impossible with a hash table, so iterate1030 // the symbol table once and collect all possibly matching symbols into this1031 // vector. Then compare each possibly matching symbol with each possible1032 // mangling.1033 std::vector<Symbol *> syms = getSymsWithPrefix(name);1034 auto findByPrefix = [&syms](const Twine &t) -> Symbol * {1035 std::string prefix = t.str();1036 for (auto *s : syms)1037 if (s->getName().starts_with(prefix))1038 return s;1039 return nullptr;1040 };1041 1042 // For non-x86, just look for C++ functions.1043 if (machine != I386)1044 return findByPrefix("?" + name + "@@Y");1045 1046 if (!name.starts_with("_"))1047 return nullptr;1048 // Search for x86 stdcall function.1049 if (Symbol *s = findByPrefix(name + "@"))1050 return s;1051 // Search for x86 fastcall function.1052 if (Symbol *s = findByPrefix("@" + name.substr(1) + "@"))1053 return s;1054 // Search for x86 vectorcall function.1055 if (Symbol *s = findByPrefix(name.substr(1) + "@@"))1056 return s;1057 // Search for x86 C++ non-member function.1058 return findByPrefix("?" + name.substr(1) + "@@Y");1059}1060 1061bool SymbolTable::findUnderscoreMangle(StringRef sym) {1062 Symbol *s = findMangle(mangle(sym));1063 return s && !isa<Undefined>(s);1064}1065 1066// Symbol names are mangled by prepending "_" on x86.1067StringRef SymbolTable::mangle(StringRef sym) {1068 assert(machine != IMAGE_FILE_MACHINE_UNKNOWN);1069 if (machine == I386)1070 return saver().save("_" + sym);1071 return sym;1072}1073 1074StringRef SymbolTable::mangleMaybe(Symbol *s) {1075 // If the plain symbol name has already been resolved, do nothing.1076 Undefined *unmangled = dyn_cast<Undefined>(s);1077 if (!unmangled)1078 return "";1079 1080 // Otherwise, see if a similar, mangled symbol exists in the symbol table.1081 Symbol *mangled = findMangle(unmangled->getName());1082 if (!mangled)1083 return "";1084 1085 // If we find a similar mangled symbol, make this an alias to it and return1086 // its name.1087 Log(ctx) << unmangled->getName() << " aliased to " << mangled->getName();1088 unmangled->setWeakAlias(addUndefined(mangled->getName()));1089 return mangled->getName();1090}1091 1092// Windows specific -- find default entry point name.1093//1094// There are four different entry point functions for Windows executables,1095// each of which corresponds to a user-defined "main" function. This function1096// infers an entry point from a user-defined "main" function.1097StringRef SymbolTable::findDefaultEntry() {1098 assert(ctx.config.subsystem != IMAGE_SUBSYSTEM_UNKNOWN &&1099 "must handle /subsystem before calling this");1100 1101 if (ctx.config.mingw)1102 return mangle(ctx.config.subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI1103 ? "WinMainCRTStartup"1104 : "mainCRTStartup");1105 1106 if (ctx.config.subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {1107 if (findUnderscoreMangle("wWinMain")) {1108 if (!findUnderscoreMangle("WinMain"))1109 return mangle("wWinMainCRTStartup");1110 Warn(ctx) << "found both wWinMain and WinMain; using latter";1111 }1112 return mangle("WinMainCRTStartup");1113 }1114 if (findUnderscoreMangle("wmain")) {1115 if (!findUnderscoreMangle("main"))1116 return mangle("wmainCRTStartup");1117 Warn(ctx) << "found both wmain and main; using latter";1118 }1119 return mangle("mainCRTStartup");1120}1121 1122WindowsSubsystem SymbolTable::inferSubsystem() {1123 if (ctx.config.dll)1124 return IMAGE_SUBSYSTEM_WINDOWS_GUI;1125 if (ctx.config.mingw)1126 return IMAGE_SUBSYSTEM_WINDOWS_CUI;1127 // Note that link.exe infers the subsystem from the presence of these1128 // functions even if /entry: or /nodefaultlib are passed which causes them1129 // to not be called.1130 bool haveMain = findUnderscoreMangle("main");1131 bool haveWMain = findUnderscoreMangle("wmain");1132 bool haveWinMain = findUnderscoreMangle("WinMain");1133 bool haveWWinMain = findUnderscoreMangle("wWinMain");1134 if (haveMain || haveWMain) {1135 if (haveWinMain || haveWWinMain) {1136 Warn(ctx) << "found " << (haveMain ? "main" : "wmain") << " and "1137 << (haveWinMain ? "WinMain" : "wWinMain")1138 << "; defaulting to /subsystem:console";1139 }1140 return IMAGE_SUBSYSTEM_WINDOWS_CUI;1141 }1142 if (haveWinMain || haveWWinMain)1143 return IMAGE_SUBSYSTEM_WINDOWS_GUI;1144 return IMAGE_SUBSYSTEM_UNKNOWN;1145}1146 1147void SymbolTable::addUndefinedGlob(StringRef arg) {1148 Expected<GlobPattern> pat = GlobPattern::create(arg);1149 if (!pat) {1150 Err(ctx) << "/includeglob: " << toString(pat.takeError());1151 return;1152 }1153 1154 SmallVector<Symbol *, 0> syms;1155 forEachSymbol([&syms, &pat](Symbol *sym) {1156 if (pat->match(sym->getName())) {1157 syms.push_back(sym);1158 }1159 });1160 1161 for (Symbol *sym : syms)1162 addGCRoot(sym->getName());1163}1164 1165// Convert stdcall/fastcall style symbols into unsuffixed symbols,1166// with or without a leading underscore. (MinGW specific.)1167static StringRef killAt(StringRef sym, bool prefix) {1168 if (sym.empty())1169 return sym;1170 // Strip any trailing stdcall suffix1171 sym = sym.substr(0, sym.find('@', 1));1172 if (!sym.starts_with("@")) {1173 if (prefix && !sym.starts_with("_"))1174 return saver().save("_" + sym);1175 return sym;1176 }1177 // For fastcall, remove the leading @ and replace it with an1178 // underscore, if prefixes are used.1179 sym = sym.substr(1);1180 if (prefix)1181 sym = saver().save("_" + sym);1182 return sym;1183}1184 1185static StringRef exportSourceName(ExportSource s) {1186 switch (s) {1187 case ExportSource::Directives:1188 return "source file (directives)";1189 case ExportSource::Export:1190 return "/export";1191 case ExportSource::ModuleDefinition:1192 return "/def";1193 default:1194 llvm_unreachable("unknown ExportSource");1195 }1196}1197 1198// Performs error checking on all /export arguments.1199// It also sets ordinals.1200void SymbolTable::fixupExports() {1201 llvm::TimeTraceScope timeScope("Fixup exports");1202 // Symbol ordinals must be unique.1203 std::set<uint16_t> ords;1204 for (Export &e : exports) {1205 if (e.ordinal == 0)1206 continue;1207 if (!ords.insert(e.ordinal).second)1208 Fatal(ctx) << "duplicate export ordinal: " << e.name;1209 }1210 1211 for (Export &e : exports) {1212 if (!e.exportAs.empty()) {1213 e.exportName = e.exportAs;1214 continue;1215 }1216 1217 StringRef sym =1218 !e.forwardTo.empty() || e.extName.empty() ? e.name : e.extName;1219 if (machine == I386 && sym.starts_with("_")) {1220 // In MSVC mode, a fully decorated stdcall function is exported1221 // as-is with the leading underscore (with type IMPORT_NAME).1222 // In MinGW mode, a decorated stdcall function gets the underscore1223 // removed, just like normal cdecl functions.1224 if (ctx.config.mingw || !sym.contains('@')) {1225 e.exportName = sym.substr(1);1226 continue;1227 }1228 }1229 if (isEC() && !e.data && !e.constant) {1230 if (std::optional<std::string> demangledName =1231 getArm64ECDemangledFunctionName(sym)) {1232 e.exportName = saver().save(*demangledName);1233 continue;1234 }1235 }1236 e.exportName = sym;1237 }1238 1239 if (ctx.config.killAt && machine == I386) {1240 for (Export &e : exports) {1241 e.name = killAt(e.name, true);1242 e.exportName = killAt(e.exportName, false);1243 e.extName = killAt(e.extName, true);1244 e.symbolName = killAt(e.symbolName, true);1245 }1246 }1247 1248 // Uniquefy by name.1249 DenseMap<StringRef, std::pair<Export *, unsigned>> map(exports.size());1250 std::vector<Export> v;1251 for (Export &e : exports) {1252 auto pair = map.insert(std::make_pair(e.exportName, std::make_pair(&e, 0)));1253 bool inserted = pair.second;1254 if (inserted) {1255 pair.first->second.second = v.size();1256 v.push_back(e);1257 continue;1258 }1259 Export *existing = pair.first->second.first;1260 if (e == *existing || e.name != existing->name)1261 continue;1262 // If the existing export comes from .OBJ directives, we are allowed to1263 // overwrite it with /DEF: or /EXPORT without any warning, as MSVC link.exe1264 // does.1265 if (existing->source == ExportSource::Directives) {1266 *existing = e;1267 v[pair.first->second.second] = e;1268 continue;1269 }1270 if (existing->source == e.source) {1271 Warn(ctx) << "duplicate " << exportSourceName(existing->source)1272 << " option: " << e.name;1273 } else {1274 Warn(ctx) << "duplicate export: " << e.name << " first seen in "1275 << exportSourceName(existing->source) << ", now in "1276 << exportSourceName(e.source);1277 }1278 }1279 exports = std::move(v);1280 1281 // Sort by name.1282 llvm::sort(exports, [](const Export &a, const Export &b) {1283 return a.exportName < b.exportName;1284 });1285}1286 1287void SymbolTable::assignExportOrdinals() {1288 // Assign unique ordinals if default (= 0).1289 uint32_t max = 0;1290 for (Export &e : exports)1291 max = std::max(max, (uint32_t)e.ordinal);1292 for (Export &e : exports)1293 if (e.ordinal == 0)1294 e.ordinal = ++max;1295 if (max > std::numeric_limits<uint16_t>::max())1296 Fatal(ctx) << "too many exported symbols (got " << max << ", max "1297 << Twine(std::numeric_limits<uint16_t>::max()) << ")";1298}1299 1300void SymbolTable::parseModuleDefs(StringRef path) {1301 llvm::TimeTraceScope timeScope("Parse def file");1302 std::unique_ptr<MemoryBuffer> mb =1303 CHECK(MemoryBuffer::getFile(path, /*IsText=*/false,1304 /*RequiresNullTerminator=*/false,1305 /*IsVolatile=*/true),1306 "could not open " + path);1307 COFFModuleDefinition m = check(parseCOFFModuleDefinition(1308 mb->getMemBufferRef(), machine, ctx.config.mingw));1309 1310 // Include in /reproduce: output if applicable.1311 ctx.driver.takeBuffer(std::move(mb));1312 1313 if (ctx.config.outputFile.empty())1314 ctx.config.outputFile = std::string(saver().save(m.OutputFile));1315 ctx.config.importName = std::string(saver().save(m.ImportName));1316 if (m.ImageBase)1317 ctx.config.imageBase = m.ImageBase;1318 if (m.StackReserve)1319 ctx.config.stackReserve = m.StackReserve;1320 if (m.StackCommit)1321 ctx.config.stackCommit = m.StackCommit;1322 if (m.HeapReserve)1323 ctx.config.heapReserve = m.HeapReserve;1324 if (m.HeapCommit)1325 ctx.config.heapCommit = m.HeapCommit;1326 if (m.MajorImageVersion)1327 ctx.config.majorImageVersion = m.MajorImageVersion;1328 if (m.MinorImageVersion)1329 ctx.config.minorImageVersion = m.MinorImageVersion;1330 if (m.MajorOSVersion)1331 ctx.config.majorOSVersion = m.MajorOSVersion;1332 if (m.MinorOSVersion)1333 ctx.config.minorOSVersion = m.MinorOSVersion;1334 1335 for (COFFShortExport e1 : m.Exports) {1336 Export e2;1337 // Renamed exports are parsed and set as "ExtName = Name". If Name has1338 // the form "OtherDll.Func", it shouldn't be a normal exported1339 // function but a forward to another DLL instead. This is supported1340 // by both MS and GNU linkers.1341 if (!e1.ExtName.empty() && e1.ExtName != e1.Name &&1342 StringRef(e1.Name).contains('.')) {1343 e2.name = saver().save(e1.ExtName);1344 e2.forwardTo = saver().save(e1.Name);1345 } else {1346 e2.name = saver().save(e1.Name);1347 e2.extName = saver().save(e1.ExtName);1348 }1349 e2.exportAs = saver().save(e1.ExportAs);1350 e2.importName = saver().save(e1.ImportName);1351 e2.ordinal = e1.Ordinal;1352 e2.noname = e1.Noname;1353 e2.data = e1.Data;1354 e2.isPrivate = e1.Private;1355 e2.constant = e1.Constant;1356 e2.source = ExportSource::ModuleDefinition;1357 exports.push_back(e2);1358 }1359}1360 1361// Parse a string of the form of "<from>=<to>".1362void SymbolTable::parseAlternateName(StringRef s) {1363 auto [from, to] = s.split('=');1364 if (from.empty() || to.empty())1365 Fatal(ctx) << "/alternatename: invalid argument: " << s;1366 auto it = alternateNames.find(from);1367 if (it != alternateNames.end() && it->second != to)1368 Fatal(ctx) << "/alternatename: conflicts: " << s;1369 alternateNames.insert(it, std::make_pair(from, to));1370}1371 1372void SymbolTable::resolveAlternateNames() {1373 // Add weak aliases. Weak aliases is a mechanism to give remaining1374 // undefined symbols final chance to be resolved successfully.1375 for (auto pair : alternateNames) {1376 StringRef from = pair.first;1377 StringRef to = pair.second;1378 Symbol *sym = find(from);1379 if (!sym)1380 continue;1381 if (auto *u = dyn_cast<Undefined>(sym)) {1382 if (u->weakAlias) {1383 // On ARM64EC, anti-dependency aliases are treated as undefined1384 // symbols unless a demangled symbol aliases a defined one, which1385 // is part of the implementation.1386 if (!isEC() || !u->isAntiDep)1387 continue;1388 if (!isa<Undefined>(u->weakAlias) &&1389 !isArm64ECMangledFunctionName(u->getName()))1390 continue;1391 }1392 1393 // Check if the destination symbol is defined. If not, skip it.1394 // It may still be resolved later if more input files are added.1395 // Also skip anti-dependency targets, as they can't be chained anyway.1396 Symbol *toSym = find(to);1397 if (!toSym)1398 continue;1399 auto toUndef = dyn_cast<Undefined>(toSym);1400 if (toUndef && (!toUndef->weakAlias || toUndef->isAntiDep))1401 continue;1402 toSym->isUsedInRegularObj = true;1403 if (toSym->isLazy())1404 forceLazy(toSym);1405 u->setWeakAlias(toSym);1406 }1407 }1408}1409 1410// Parses /aligncomm option argument.1411void SymbolTable::parseAligncomm(StringRef s) {1412 auto [name, align] = s.split(',');1413 if (name.empty() || align.empty()) {1414 Err(ctx) << "/aligncomm: invalid argument: " << s;1415 return;1416 }1417 int v;1418 if (align.getAsInteger(0, v)) {1419 Err(ctx) << "/aligncomm: invalid argument: " << s;1420 return;1421 }1422 alignComm[std::string(name)] = std::max(alignComm[std::string(name)], 1 << v);1423}1424 1425Symbol *SymbolTable::addUndefined(StringRef name) {1426 return addUndefined(name, nullptr, false);1427}1428 1429std::string SymbolTable::printSymbol(Symbol *sym) const {1430 std::string name = maybeDemangleSymbol(ctx, sym->getName());1431 if (ctx.hybridSymtab)1432 return name + (isEC() ? " (EC symbol)" : " (native symbol)");1433 return name;1434}1435 1436void SymbolTable::compileBitcodeFiles() {1437 if (bitcodeFileInstances.empty())1438 return;1439 1440 ScopedTimer t(ctx.ltoTimer);1441 lto.reset(new BitcodeCompiler(ctx));1442 {1443 llvm::TimeTraceScope addScope("Add bitcode file instances");1444 for (BitcodeFile *f : bitcodeFileInstances)1445 lto->add(*f);1446 }1447 for (InputFile *newObj : lto->compile()) {1448 ObjFile *obj = cast<ObjFile>(newObj);1449 obj->parse();1450 ctx.objFileInstances.push_back(obj);1451 }1452}1453 1454} // namespace lld::coff1455