diff options
Diffstat (limited to 'COFF/Writer.cpp')
-rw-r--r-- | COFF/Writer.cpp | 94 |
1 files changed, 69 insertions, 25 deletions
diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp index 36ef87de4263..9729c6938ec8 100644 --- a/COFF/Writer.cpp +++ b/COFF/Writer.cpp @@ -40,8 +40,9 @@ using namespace llvm::COFF; using namespace llvm::object; using namespace llvm::support; using namespace llvm::support::endian; -using namespace lld; -using namespace lld::coff; + +namespace lld { +namespace coff { /* To re-generate DOSProgram: $ cat > /tmp/DOSProgram.asm @@ -240,6 +241,8 @@ private: IdataContents idata; Chunk *importTableStart = nullptr; uint64_t importTableSize = 0; + Chunk *edataStart = nullptr; + Chunk *edataEnd = nullptr; Chunk *iatStart = nullptr; uint64_t iatSize = 0; DelayLoadContents delayIdata; @@ -283,9 +286,6 @@ private: }; } // anonymous namespace -namespace lld { -namespace coff { - static Timer codeLayoutTimer("Code Layout", Timer::root()); static Timer diskCommitTimer("Commit Output File", Timer::root()); @@ -331,9 +331,6 @@ void OutputSection::addContributingPartialSection(PartialSection *sec) { contribSections.push_back(sec); } -} // namespace coff -} // namespace lld - // Check whether the target address S is in range from a relocation // of type relType at address P. static bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin) { @@ -626,6 +623,9 @@ void Writer::run() { writeMapFile(outputSections); + if (errorCount()) + return; + ScopedTimer t2(diskCommitTimer); if (auto e = buffer->commit()) fatal("failed to write the output file: " + toString(std::move(e))); @@ -738,7 +738,8 @@ void Writer::addSyntheticIdata() { add(".idata$2", idata.dirs); add(".idata$4", idata.lookups); add(".idata$5", idata.addresses); - add(".idata$6", idata.hints); + if (!idata.hints.empty()) + add(".idata$6", idata.hints); add(".idata$7", idata.dllNames); } @@ -762,6 +763,28 @@ void Writer::locateImportTables() { } } +// Return whether a SectionChunk's suffix (the dollar and any trailing +// suffix) should be removed and sorted into the main suffixless +// PartialSection. +static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name) { + // On MinGW, comdat groups are formed by putting the comdat group name + // after the '$' in the section name. For .eh_frame$<symbol>, that must + // still be sorted before the .eh_frame trailer from crtend.o, thus just + // strip the section name trailer. For other sections, such as + // .tls$$<symbol> (where non-comdat .tls symbols are otherwise stored in + // ".tls$"), they must be strictly sorted after .tls. And for the + // hypothetical case of comdat .CRT$XCU, we definitely need to keep the + // suffix for sorting. Thus, to play it safe, only strip the suffix for + // the standard sections. + if (!config->mingw) + return false; + if (!sc || !sc->isCOMDAT()) + return false; + return name.startswith(".text$") || name.startswith(".data$") || + name.startswith(".rdata$") || name.startswith(".pdata$") || + name.startswith(".xdata$") || name.startswith(".eh_frame$"); +} + // Create output section objects and add them to OutputSections. void Writer::createSections() { // First, create the builtin sections. @@ -807,10 +830,7 @@ void Writer::createSections() { continue; } StringRef name = c->getSectionName(); - // On MinGW, comdat groups are formed by putting the comdat group name - // after the '$' in the section name. Such a section name suffix shouldn't - // imply separate alphabetical sorting of those section chunks though. - if (config->mingw && sc && sc->isCOMDAT()) + if (shouldStripSectionSuffix(sc, name)) name = name.split('$').first; PartialSection *pSec = createPartialSection(name, c->getOutputCharacteristics()); @@ -818,6 +838,7 @@ void Writer::createSections() { } fixPartialSectionChars(".rsrc", data | r); + fixPartialSectionChars(".edata", data | r); // Even in non MinGW cases, we might need to link against GNU import // libraries. bool hasIdata = fixGnuImportChunks(); @@ -992,10 +1013,19 @@ void Writer::appendImportThunks() { } void Writer::createExportTable() { - if (config->exports.empty()) - return; - for (Chunk *c : edata.chunks) - edataSec->addChunk(c); + if (!edataSec->chunks.empty()) { + // Allow using a custom built export table from input object files, instead + // of having the linker synthesize the tables. + if (config->hadExplicitExports) + warn("literal .edata sections override exports"); + } else if (!config->exports.empty()) { + for (Chunk *c : edata.chunks) + edataSec->addChunk(c); + } + if (!edataSec->chunks.empty()) { + edataStart = edataSec->chunks.front(); + edataEnd = edataSec->chunks.back(); + } } void Writer::removeUnusedSections() { @@ -1076,6 +1106,13 @@ Optional<coff_symbol16> Writer::createSymbol(Defined *def) { } } + // Symbols that are runtime pseudo relocations don't point to the actual + // symbol data itself (as they are imported), but points to the IAT entry + // instead. Avoid emitting them to the symbol table, as they can confuse + // debuggers. + if (def->isRuntimePseudoReloc) + return None; + StringRef name = def->getName(); if (name.size() > COFF::NameSize) { sym.Name.Offset.Zeroes = 0; @@ -1179,9 +1216,11 @@ void Writer::assignAddresses() { sizeOfHeaders += config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); sizeOfHeaders = alignTo(sizeOfHeaders, config->fileAlign); - uint64_t rva = pageSize; // The first page is kept unmapped. fileSize = sizeOfHeaders; + // The first page is kept unmapped. + uint64_t rva = alignTo(sizeOfHeaders, config->align); + for (OutputSection *sec : outputSections) { if (sec == relocSec) addBaserels(); @@ -1211,10 +1250,10 @@ void Writer::assignAddresses() { sec->header.SizeOfRawData = rawSize; if (rawSize != 0) sec->header.PointerToRawData = fileSize; - rva += alignTo(virtualSize, pageSize); + rva += alignTo(virtualSize, config->align); fileSize += alignTo(rawSize, config->fileAlign); } - sizeOfImage = alignTo(rva, pageSize); + sizeOfImage = alignTo(rva, config->align); // Assign addresses to sections in MergeChunks. for (MergeChunk *mc : MergeChunk::instances) @@ -1283,7 +1322,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() { pe->MinorLinkerVersion = 0; pe->ImageBase = config->imageBase; - pe->SectionAlignment = pageSize; + pe->SectionAlignment = config->align; pe->FileAlignment = config->fileAlign; pe->MajorImageVersion = config->majorImageVersion; pe->MinorImageVersion = config->minorImageVersion; @@ -1335,9 +1374,10 @@ template <typename PEHeaderTy> void Writer::writeHeader() { // Write data directory auto *dir = reinterpret_cast<data_directory *>(buf); buf += sizeof(*dir) * numberOfDataDirectory; - if (!config->exports.empty()) { - dir[EXPORT_TABLE].RelativeVirtualAddress = edata.getRVA(); - dir[EXPORT_TABLE].Size = edata.getSize(); + if (edataStart) { + dir[EXPORT_TABLE].RelativeVirtualAddress = edataStart->getRVA(); + dir[EXPORT_TABLE].Size = + edataEnd->getRVA() + edataEnd->getSize() - edataStart->getRVA(); } if (importTableStart) { dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA(); @@ -1475,7 +1515,8 @@ static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms, // Absolute is never code, synthetic generally isn't and usually isn't // determinable. break; - case Symbol::LazyKind: + case Symbol::LazyArchiveKind: + case Symbol::LazyObjectKind: case Symbol::UndefinedKind: // Undefined symbols resolve to zero, so they don't have an RVA. Lazy // symbols shouldn't have relocations. @@ -1899,3 +1940,6 @@ PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) { return it->second; return nullptr; } + +} // namespace coff +} // namespace lld |