diff options
Diffstat (limited to 'lld/COFF/Writer.cpp')
| -rw-r--r-- | lld/COFF/Writer.cpp | 135 |
1 files changed, 66 insertions, 69 deletions
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 3c6112b7fc89..a5b2b6238db1 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -282,7 +282,8 @@ private: uint32_t getSizeOfInitializedData(); void prepareLoadConfig(); - template <typename T> void prepareLoadConfig(T *loadConfig); + template <typename T> + void prepareLoadConfig(SymbolTable &symtab, T *loadConfig); std::unique_ptr<FileOutputBuffer> &buffer; std::map<PartialSectionKey, PartialSection *> partialSections; @@ -574,7 +575,7 @@ bool Writer::createThunks(OutputSection *os, int margin) { // Create a code map for CHPE metadata. void Writer::createECCodeMap() { - if (!isArm64EC(ctx.config.machine)) + if (!ctx.symtabEC) return; // Clear the map in case we were're recomputing the map after adding @@ -610,7 +611,8 @@ void Writer::createECCodeMap() { closeRange(); - Symbol *tableCountSym = ctx.symtab.findUnderscore("__hybrid_code_map_count"); + Symbol *tableCountSym = + ctx.symtabEC->findUnderscore("__hybrid_code_map_count"); cast<DefinedAbsolute>(tableCountSym)->setVA(codeMap.size()); } @@ -944,7 +946,7 @@ void Writer::appendECImportTables() { const uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; - // IAT is always placed at the begining of .rdata section and its size + // IAT is always placed at the beginning of .rdata section and its size // is aligned to 4KB. Insert it here, after all merges all done. if (PartialSection *importAddresses = findPartialSection(".idata$5", rdata)) { if (!rdataSec->chunks.empty()) @@ -1228,8 +1230,7 @@ void Writer::createMiscChunks() { // Create /guard:cf tables if requested. createGuardCFTables(); - if (isArm64EC(config->machine)) - createECChunks(); + createECChunks(); if (config->autoImport) createRuntimePseudoRelocs(); @@ -1837,22 +1838,10 @@ template <typename PEHeaderTy> void Writer::writeHeader() { dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA(); dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize(); } - if (Symbol *sym = ctx.symtab.findUnderscore("_load_config_used")) { - if (auto *b = dyn_cast<DefinedRegular>(sym)) { - SectionChunk *sc = b->getChunk(); - assert(b->getRVA() >= sc->getRVA()); - uint64_t offsetInChunk = b->getRVA() - sc->getRVA(); - if (!sc->hasData || offsetInChunk + 4 > sc->getSize()) - Fatal(ctx) << "_load_config_used is malformed"; - - ArrayRef<uint8_t> secContents = sc->getContents(); - uint32_t loadConfigSize = - *reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]); - if (offsetInChunk + loadConfigSize > sc->getSize()) - Fatal(ctx) << "_load_config_used is too large"; - dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = b->getRVA(); - dir[LOAD_CONFIG_TABLE].Size = loadConfigSize; - } + if (ctx.symtab.loadConfigSym) { + dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = + ctx.symtab.loadConfigSym->getRVA(); + dir[LOAD_CONFIG_TABLE].Size = ctx.symtab.loadConfigSize; } if (!delayIdata.empty()) { dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress = @@ -2169,7 +2158,11 @@ void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym, // Create CHPE metadata chunks. void Writer::createECChunks() { - for (Symbol *s : ctx.symtab.expSymbols) { + SymbolTable *symtab = ctx.symtabEC; + if (!symtab) + return; + + for (Symbol *s : symtab->expSymbols) { auto sym = dyn_cast<Defined>(s); if (!sym || !sym->getChunk()) continue; @@ -2188,9 +2181,9 @@ void Writer::createECChunks() { // we should use the #foo$hp_target symbol as the redirection target. // First, try to look up the $hp_target symbol. If it can't be found, // assume it's a regular function and look for #foo instead. - Symbol *targetSym = ctx.symtab.find((targetName + "$hp_target").str()); + Symbol *targetSym = symtab->find((targetName + "$hp_target").str()); if (!targetSym) - targetSym = ctx.symtab.find(targetName); + targetSym = symtab->find(targetName); Defined *t = dyn_cast_or_null<Defined>(targetSym); if (t && isArm64EC(t->getChunk()->getMachine())) exportThunks.push_back({chunk, t}); @@ -2199,20 +2192,20 @@ void Writer::createECChunks() { auto codeMapChunk = make<ECCodeMapChunk>(codeMap); rdataSec->addChunk(codeMapChunk); - Symbol *codeMapSym = ctx.symtab.findUnderscore("__hybrid_code_map"); + Symbol *codeMapSym = symtab->findUnderscore("__hybrid_code_map"); replaceSymbol<DefinedSynthetic>(codeMapSym, codeMapSym->getName(), codeMapChunk); CHPECodeRangesChunk *ranges = make<CHPECodeRangesChunk>(exportThunks); rdataSec->addChunk(ranges); Symbol *rangesSym = - ctx.symtab.findUnderscore("__x64_code_ranges_to_entry_points"); + symtab->findUnderscore("__x64_code_ranges_to_entry_points"); replaceSymbol<DefinedSynthetic>(rangesSym, rangesSym->getName(), ranges); CHPERedirectionChunk *entryPoints = make<CHPERedirectionChunk>(exportThunks); a64xrmSec->addChunk(entryPoints); Symbol *entryPointsSym = - ctx.symtab.findUnderscore("__arm64x_redirection_metadata"); + symtab->findUnderscore("__arm64x_redirection_metadata"); replaceSymbol<DefinedSynthetic>(entryPointsSym, entryPointsSym->getName(), entryPoints); } @@ -2305,7 +2298,8 @@ void Writer::setSectionPermissions() { // Set symbols used by ARM64EC metadata. void Writer::setECSymbols() { - if (!isArm64EC(ctx.config.machine)) + SymbolTable *symtab = ctx.symtabEC; + if (!symtab) return; llvm::stable_sort(exportThunks, [](const std::pair<Chunk *, Defined *> &a, @@ -2313,45 +2307,45 @@ void Writer::setECSymbols() { return a.first->getRVA() < b.first->getRVA(); }); - Symbol *rfeTableSym = ctx.symtab.findUnderscore("__arm64x_extra_rfe_table"); + Symbol *rfeTableSym = symtab->findUnderscore("__arm64x_extra_rfe_table"); replaceSymbol<DefinedSynthetic>(rfeTableSym, "__arm64x_extra_rfe_table", pdata.first); if (pdata.first) { Symbol *rfeSizeSym = - ctx.symtab.findUnderscore("__arm64x_extra_rfe_table_size"); + symtab->findUnderscore("__arm64x_extra_rfe_table_size"); cast<DefinedAbsolute>(rfeSizeSym) ->setVA(pdata.last->getRVA() + pdata.last->getSize() - pdata.first->getRVA()); } Symbol *rangesCountSym = - ctx.symtab.findUnderscore("__x64_code_ranges_to_entry_points_count"); + symtab->findUnderscore("__x64_code_ranges_to_entry_points_count"); cast<DefinedAbsolute>(rangesCountSym)->setVA(exportThunks.size()); Symbol *entryPointCountSym = - ctx.symtab.findUnderscore("__arm64x_redirection_metadata_count"); + symtab->findUnderscore("__arm64x_redirection_metadata_count"); cast<DefinedAbsolute>(entryPointCountSym)->setVA(exportThunks.size()); - Symbol *iatSym = ctx.symtab.findUnderscore("__hybrid_auxiliary_iat"); + Symbol *iatSym = symtab->findUnderscore("__hybrid_auxiliary_iat"); replaceSymbol<DefinedSynthetic>(iatSym, "__hybrid_auxiliary_iat", idata.auxIat.empty() ? nullptr : idata.auxIat.front()); - Symbol *iatCopySym = ctx.symtab.findUnderscore("__hybrid_auxiliary_iat_copy"); + Symbol *iatCopySym = symtab->findUnderscore("__hybrid_auxiliary_iat_copy"); replaceSymbol<DefinedSynthetic>( iatCopySym, "__hybrid_auxiliary_iat_copy", idata.auxIatCopy.empty() ? nullptr : idata.auxIatCopy.front()); Symbol *delayIatSym = - ctx.symtab.findUnderscore("__hybrid_auxiliary_delayload_iat"); + symtab->findUnderscore("__hybrid_auxiliary_delayload_iat"); replaceSymbol<DefinedSynthetic>( delayIatSym, "__hybrid_auxiliary_delayload_iat", delayIdata.getAuxIat().empty() ? nullptr : delayIdata.getAuxIat().front()); Symbol *delayIatCopySym = - ctx.symtab.findUnderscore("__hybrid_auxiliary_delayload_iat_copy"); + symtab->findUnderscore("__hybrid_auxiliary_delayload_iat_copy"); replaceSymbol<DefinedSynthetic>( delayIatCopySym, "__hybrid_auxiliary_delayload_iat_copy", delayIdata.getAuxIatCopy().empty() ? nullptr @@ -2649,39 +2643,25 @@ void Writer::fixTlsAlignment() { } void Writer::prepareLoadConfig() { - Symbol *sym = ctx.symtab.findUnderscore("_load_config_used"); - auto *b = cast_if_present<DefinedRegular>(sym); - if (!b) { - if (ctx.config.guardCF != GuardCFLevel::Off) - Warn(ctx) - << "Control Flow Guard is enabled but '_load_config_used' is missing"; - if (ctx.config.dependentLoadFlags) - Warn(ctx) << "_load_config_used not found, /dependentloadflag will have " - "no effect"; - return; - } + ctx.forEachSymtab([&](SymbolTable &symtab) { + if (!symtab.loadConfigSym) + return; - OutputSection *sec = ctx.getOutputSection(b->getChunk()); - uint8_t *buf = buffer->getBufferStart(); - uint8_t *secBuf = buf + sec->getFileOff(); - uint8_t *symBuf = secBuf + (b->getRVA() - sec->getRVA()); - uint32_t expectedAlign = ctx.config.is64() ? 8 : 4; - if (b->getChunk()->getAlignment() < expectedAlign) - Warn(ctx) << "'_load_config_used' is misaligned (expected alignment to be " - << expectedAlign << " bytes, got " - << b->getChunk()->getAlignment() << " instead)"; - else if (!isAligned(Align(expectedAlign), b->getRVA())) - Warn(ctx) << "'_load_config_used' is misaligned (RVA is 0x" - << Twine::utohexstr(b->getRVA()) << " not aligned to " - << expectedAlign << " bytes)"; - - if (ctx.config.is64()) - prepareLoadConfig(reinterpret_cast<coff_load_configuration64 *>(symBuf)); - else - prepareLoadConfig(reinterpret_cast<coff_load_configuration32 *>(symBuf)); + OutputSection *sec = ctx.getOutputSection(symtab.loadConfigSym->getChunk()); + uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff(); + uint8_t *symBuf = secBuf + (symtab.loadConfigSym->getRVA() - sec->getRVA()); + + if (ctx.config.is64()) + prepareLoadConfig(symtab, + reinterpret_cast<coff_load_configuration64 *>(symBuf)); + else + prepareLoadConfig(symtab, + reinterpret_cast<coff_load_configuration32 *>(symBuf)); + }); } -template <typename T> void Writer::prepareLoadConfig(T *loadConfig) { +template <typename T> +void Writer::prepareLoadConfig(SymbolTable &symtab, T *loadConfig) { size_t loadConfigSize = loadConfig->Size; #define RETURN_IF_NOT_CONTAINS(field) \ @@ -2694,12 +2674,12 @@ template <typename T> void Writer::prepareLoadConfig(T *loadConfig) { if (loadConfigSize >= offsetof(T, field) + sizeof(T::field)) #define CHECK_VA(field, sym) \ - if (auto *s = dyn_cast<DefinedSynthetic>(ctx.symtab.findUnderscore(sym))) \ + if (auto *s = dyn_cast<DefinedSynthetic>(symtab.findUnderscore(sym))) \ if (loadConfig->field != ctx.config.imageBase + s->getRVA()) \ Warn(ctx) << #field " not set correctly in '_load_config_used'"; #define CHECK_ABSOLUTE(field, sym) \ - if (auto *s = dyn_cast<DefinedAbsolute>(ctx.symtab.findUnderscore(sym))) \ + if (auto *s = dyn_cast<DefinedAbsolute>(symtab.findUnderscore(sym))) \ if (loadConfig->field != s->getVA()) \ Warn(ctx) << #field " not set correctly in '_load_config_used'"; @@ -2720,6 +2700,23 @@ template <typename T> void Writer::prepareLoadConfig(T *loadConfig) { } } + IF_CONTAINS(CHPEMetadataPointer) { + // On ARM64X, only the EC version of the load config contains + // CHPEMetadataPointer. Copy its value to the native load config. + if (ctx.hybridSymtab && !symtab.isEC() && + ctx.hybridSymtab->loadConfigSize >= + offsetof(T, CHPEMetadataPointer) + sizeof(T::CHPEMetadataPointer)) { + OutputSection *sec = + ctx.getOutputSection(ctx.hybridSymtab->loadConfigSym->getChunk()); + uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff(); + auto hybridLoadConfig = + reinterpret_cast<const coff_load_configuration64 *>( + secBuf + + (ctx.hybridSymtab->loadConfigSym->getRVA() - sec->getRVA())); + loadConfig->CHPEMetadataPointer = hybridLoadConfig->CHPEMetadataPointer; + } + } + if (ctx.config.guardCF == GuardCFLevel::Off) return; RETURN_IF_NOT_CONTAINS(GuardFlags) |
