Index: COFF/Chunks.h =================================================================== --- COFF/Chunks.h +++ COFF/Chunks.h @@ -116,7 +116,7 @@ uint64_t OutputSectionOff = 0; }; -// A chunk corresponding a section of an input file. +// A chunk corresponding to a section of an input file. class SectionChunk final : public Chunk { // Identical COMDAT Folding feature accesses section internal data. friend class ICF; @@ -140,13 +140,21 @@ SectionChunk(ObjFile *File, const coff_section *Header); static bool classof(const Chunk *C) { return C->kind() == SectionKind; } - size_t getSize() const override { return Header->SizeOfRawData; } + + // Sections can have N bytes of padding in front in order to support + // /FUNCTIONPADMIN. + size_t getSize() const override { return Padding + getRawSize(); } + ArrayRef getContents() const; void writeTo(uint8_t *Buf) const override; bool hasData() const override; uint32_t getOutputCharacteristics() const override; StringRef getSectionName() const override { return SectionName; } void getBaserels(std::vector *Res) override; + + // The raw size without any (optional) padding. + size_t getRawSize() const { return Header->SizeOfRawData; } + bool isCOMDAT() const; void applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const; @@ -200,7 +208,7 @@ // A pointer pointing to a replacement for this chunk. // Initially it points to "this" object. If this chunk is merged // with other chunk by ICF, it points to another chunk, - // and this chunk is considrered as dead. + // and this chunk is considered as dead. SectionChunk *Repl; // The CRC of the contents as described in the COFF spec 4.5.5. @@ -227,6 +235,9 @@ // Used for ICF (Identical COMDAT Folding) void replace(SectionChunk *Other); uint32_t Class[2] = {0, 0}; + + // Padding used for supporting /FUNCTIONPADMIN. + uint32_t Padding; }; // This class is used to implement an lld-specific feature (not implemented in Index: COFF/Chunks.cpp =================================================================== --- COFF/Chunks.cpp +++ COFF/Chunks.cpp @@ -42,6 +42,14 @@ // files will be built with -ffunction-sections or /Gy, so most things worth // stripping will be in a comdat. Live = !Config->DoGC || !isCOMDAT(); + + // If /FUNCTIONPADMIN is used, functions are padded in order to create a + // hotpatchable image. + const bool IsCodeSection = (Header->Characteristics & IMAGE_SCN_CNT_CODE) && + (Header->Characteristics & IMAGE_SCN_MEM_READ) && + (Header->Characteristics & IMAGE_SCN_MEM_EXECUTE); + + Padding = IsCodeSection ? Config->Padding : 0; } static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); } @@ -86,17 +94,39 @@ void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const { switch (Type) { - case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break; - case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break; - case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break; - case IMAGE_REL_AMD64_REL32: add32(Off, S - P - 4); break; - case IMAGE_REL_AMD64_REL32_1: add32(Off, S - P - 5); break; - case IMAGE_REL_AMD64_REL32_2: add32(Off, S - P - 6); break; - case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break; - case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break; - case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break; - case IMAGE_REL_AMD64_SECTION: applySecIdx(Off, OS); break; - case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, OS, S); break; + case IMAGE_REL_AMD64_ADDR32: + add32(Off, S + Config->ImageBase); + break; + case IMAGE_REL_AMD64_ADDR64: + add64(Off, S + Config->ImageBase); + break; + case IMAGE_REL_AMD64_ADDR32NB: + add32(Off, S); + break; + case IMAGE_REL_AMD64_REL32: + add32(Off, S - P - 4); + break; + case IMAGE_REL_AMD64_REL32_1: + add32(Off, S - P - 5); + break; + case IMAGE_REL_AMD64_REL32_2: + add32(Off, S - P - 6); + break; + case IMAGE_REL_AMD64_REL32_3: + add32(Off, S - P - 7); + break; + case IMAGE_REL_AMD64_REL32_4: + add32(Off, S - P - 8); + break; + case IMAGE_REL_AMD64_REL32_5: + add32(Off, S - P - 9); + break; + case IMAGE_REL_AMD64_SECTION: + applySecIdx(Off, OS); + break; + case IMAGE_REL_AMD64_SECREL: + applySecRel(this, Off, OS, S); + break; default: fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + toString(File)); @@ -106,12 +136,23 @@ void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const { switch (Type) { - case IMAGE_REL_I386_ABSOLUTE: break; - case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break; - case IMAGE_REL_I386_DIR32NB: add32(Off, S); break; - case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break; - case IMAGE_REL_I386_SECTION: applySecIdx(Off, OS); break; - case IMAGE_REL_I386_SECREL: applySecRel(this, Off, OS, S); break; + case IMAGE_REL_I386_ABSOLUTE: + break; + case IMAGE_REL_I386_DIR32: + add32(Off, S + Config->ImageBase); + break; + case IMAGE_REL_I386_DIR32NB: + add32(Off, S); + break; + case IMAGE_REL_I386_REL32: + add32(Off, S - P - 4); + break; + case IMAGE_REL_I386_SECTION: + applySecIdx(Off, OS); + break; + case IMAGE_REL_I386_SECREL: + applySecRel(this, Off, OS, S); + break; default: fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + toString(File)); @@ -119,8 +160,10 @@ } static void applyMOV(uint8_t *Off, uint16_t V) { - write16le(Off, (read16le(Off) & 0xfbf0) | ((V & 0x800) >> 1) | ((V >> 12) & 0xf)); - write16le(Off + 2, (read16le(Off + 2) & 0x8f00) | ((V & 0x700) << 4) | (V & 0xff)); + write16le(Off, + (read16le(Off) & 0xfbf0) | ((V & 0x800) >> 1) | ((V >> 12) & 0xf)); + write16le(Off + 2, + (read16le(Off + 2) & 0x8f00) | ((V & 0x700) << 4) | (V & 0xff)); } static uint16_t readMOV(uint8_t *Off) { @@ -134,7 +177,7 @@ uint16_t ImmW = readMOV(Off); // read MOVW operand uint16_t ImmT = readMOV(Off + 4); // read MOVT operand uint32_t Imm = ImmW | (ImmT << 16); - V += Imm; // add the immediate offset + V += Imm; // add the immediate offset applyMOV(Off, V); // set MOVW operand applyMOV(Off + 4, V >> 16); // set MOVT operand } @@ -157,7 +200,8 @@ uint32_t J2 = ((~V >> 22) & 1) ^ S; or16(Off, (S << 10) | ((V >> 12) & 0x3ff)); // Clear out the J1 and J2 bits which may be set. - write16le(Off + 2, (read16le(Off + 2) & 0xd000) | (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); + write16le(Off + 2, (read16le(Off + 2) & 0xd000) | (J1 << 13) | (J2 << 11) | + ((V >> 1) & 0x7ff)); } void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, @@ -167,14 +211,30 @@ if (OS && (OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)) SX |= 1; switch (Type) { - case IMAGE_REL_ARM_ADDR32: add32(Off, SX + Config->ImageBase); break; - case IMAGE_REL_ARM_ADDR32NB: add32(Off, SX); break; - case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, SX + Config->ImageBase); break; - case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, SX - P - 4); break; - case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, SX - P - 4); break; - case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, SX - P - 4); break; - case IMAGE_REL_ARM_SECTION: applySecIdx(Off, OS); break; - case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, OS, S); break; + case IMAGE_REL_ARM_ADDR32: + add32(Off, SX + Config->ImageBase); + break; + case IMAGE_REL_ARM_ADDR32NB: + add32(Off, SX); + break; + case IMAGE_REL_ARM_MOV32T: + applyMOV32T(Off, SX + Config->ImageBase); + break; + case IMAGE_REL_ARM_BRANCH20T: + applyBranch20T(Off, SX - P - 4); + break; + case IMAGE_REL_ARM_BRANCH24T: + applyBranch24T(Off, SX - P - 4); + break; + case IMAGE_REL_ARM_BLX23T: + applyBranch24T(Off, SX - P - 4); + break; + case IMAGE_REL_ARM_SECTION: + applySecIdx(Off, OS); + break; + case IMAGE_REL_ARM_SECREL: + applySecRel(this, Off, OS, S); + break; default: fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + toString(File)); @@ -271,21 +331,51 @@ void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const { switch (Type) { - case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P, 12); break; - case IMAGE_REL_ARM64_REL21: applyArm64Addr(Off, S, P, 0); break; - case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff, 0); break; - case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break; - case IMAGE_REL_ARM64_BRANCH26: applyArm64Branch26(Off, S - P); break; - case IMAGE_REL_ARM64_BRANCH19: applyArm64Branch19(Off, S - P); break; - case IMAGE_REL_ARM64_BRANCH14: applyArm64Branch14(Off, S - P); break; - case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break; - case IMAGE_REL_ARM64_ADDR32NB: add32(Off, S); break; - case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break; - case IMAGE_REL_ARM64_SECREL: applySecRel(this, Off, OS, S); break; - case IMAGE_REL_ARM64_SECREL_LOW12A: applySecRelLow12A(this, Off, OS, S); break; - case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, Off, OS, S); break; - case IMAGE_REL_ARM64_SECREL_LOW12L: applySecRelLdr(this, Off, OS, S); break; - case IMAGE_REL_ARM64_SECTION: applySecIdx(Off, OS); break; + case IMAGE_REL_ARM64_PAGEBASE_REL21: + applyArm64Addr(Off, S, P, 12); + break; + case IMAGE_REL_ARM64_REL21: + applyArm64Addr(Off, S, P, 0); + break; + case IMAGE_REL_ARM64_PAGEOFFSET_12A: + applyArm64Imm(Off, S & 0xfff, 0); + break; + case IMAGE_REL_ARM64_PAGEOFFSET_12L: + applyArm64Ldr(Off, S & 0xfff); + break; + case IMAGE_REL_ARM64_BRANCH26: + applyArm64Branch26(Off, S - P); + break; + case IMAGE_REL_ARM64_BRANCH19: + applyArm64Branch19(Off, S - P); + break; + case IMAGE_REL_ARM64_BRANCH14: + applyArm64Branch14(Off, S - P); + break; + case IMAGE_REL_ARM64_ADDR32: + add32(Off, S + Config->ImageBase); + break; + case IMAGE_REL_ARM64_ADDR32NB: + add32(Off, S); + break; + case IMAGE_REL_ARM64_ADDR64: + add64(Off, S + Config->ImageBase); + break; + case IMAGE_REL_ARM64_SECREL: + applySecRel(this, Off, OS, S); + break; + case IMAGE_REL_ARM64_SECREL_LOW12A: + applySecRelLow12A(this, Off, OS, S); + break; + case IMAGE_REL_ARM64_SECREL_HIGH12A: + applySecRelHigh12A(this, Off, OS, S); + break; + case IMAGE_REL_ARM64_SECREL_LOW12L: + applySecRelLdr(this, Off, OS, S); + break; + case IMAGE_REL_ARM64_SECTION: + applySecIdx(Off, OS); + break; default: fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + toString(File)); @@ -320,7 +410,8 @@ if (!Sym) { if (isCodeView() || isDWARF()) continue; - // Symbols in early discarded sections are represented using null pointers, + // Symbols in early discarded sections are represented using null + // pointers, // so we need to retrieve the name from the object file. COFFSymbolRef Sym = check(File->getCOFFObj()->getSymbol(Rel.SymbolTableIndex)); @@ -506,9 +597,7 @@ Res->emplace_back(getRVA()); } -size_t LocalImportChunk::getSize() const { - return Config->is64() ? 8 : 4; -} +size_t LocalImportChunk::getSize() const { return Config->is64() ? 8 : 4; } void LocalImportChunk::writeTo(uint8_t *Buf) const { if (Config->is64()) { @@ -632,9 +721,7 @@ return IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA; } -size_t MergeChunk::getSize() const { - return Builder.getSize(); -} +size_t MergeChunk::getSize() const { return Builder.getSize(); } void MergeChunk::writeTo(uint8_t *Buf) const { Builder.write(Buf + OutputSectionOff); Index: COFF/Config.h =================================================================== --- COFF/Config.h +++ COFF/Config.h @@ -38,8 +38,8 @@ // Represents an /export option. struct Export { - StringRef Name; // N in /export:N or /export:E=N - StringRef ExtName; // E in /export:E=N + StringRef Name; // N in /export:N or /export:E=N + StringRef ExtName; // E in /export:E=N Symbol *Sym = nullptr; uint16_t Ordinal = 0; bool Noname = false; @@ -59,17 +59,16 @@ StringRef ExportName; // Name in DLL bool operator==(const Export &E) { - return (Name == E.Name && ExtName == E.ExtName && - Ordinal == E.Ordinal && Noname == E.Noname && - Data == E.Data && Private == E.Private); + return (Name == E.Name && ExtName == E.ExtName && Ordinal == E.Ordinal && + Noname == E.Noname && Data == E.Data && Private == E.Private); } }; enum class DebugType { - None = 0x0, - CV = 0x1, /// CodeView - PData = 0x2, /// Procedure Data - Fixup = 0x4, /// Relocation Table + None = 0x0, + CV = 0x1, /// CodeView + PData = 0x2, /// Procedure Data + Fixup = 0x4, /// Relocation Table }; enum class GuardCFLevel { @@ -173,6 +172,9 @@ // Used for /lldmap. std::string MapFile; + // Used for /functionpadmin. + uint32_t Padding = 0; + uint64_t ImageBase = -1; uint64_t StackReserve = 1024 * 1024; uint64_t StackCommit = 4096; Index: COFF/Driver.h =================================================================== --- COFF/Driver.h +++ COFF/Driver.h @@ -159,6 +159,9 @@ void parseSection(StringRef); void parseAligncomm(StringRef); +// Parses a string in the form of "[:]" +void parseFunctionpadmin(StringRef Arg, llvm::COFF::MachineTypes Machine); + // Parses a string in the form of "EMBED[,=]|NO". void parseManifest(StringRef Arg); Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -83,7 +83,7 @@ static std::string getOutputPath(StringRef Path) { auto P = Path.find_last_of("\\/"); StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1); - const char* E = Config->DLL ? ".dll" : ".exe"; + const char *E = Config->DLL ? ".dll" : ".exe"; return (S.substr(0, S.rfind('.')) + E).str(); } @@ -834,8 +834,7 @@ if (Set.count(S) == 0) { if (Config->WarnMissingOrderSymbol) warn("/order:" + Arg + ": missing symbol: " + S + " [LNK4037]"); - } - else + } else Config->Order[S] = INT_MIN + Config->Order.size(); } } @@ -1278,6 +1277,10 @@ if (Config->Manifest == Configuration::Embed) addBuffer(createManifestRes(), false); + // Handle /functionpadmin + for (auto *Arg : Args.filtered(OPT_functionpadmin)) + parseFunctionpadmin(Arg->getValue(), Config->Machine); + // Read all input files given via the command line. run(); @@ -1500,7 +1503,8 @@ E.Name = Def->getName(); E.Sym = Def; if (Def->getChunk() && - !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) + !(Def->getChunk()->getOutputCharacteristics() & + IMAGE_SCN_MEM_EXECUTE)) E.Data = true; Config->Exports.push_back(E); }); Index: COFF/DriverUtils.cpp =================================================================== --- COFF/DriverUtils.cpp +++ COFF/DriverUtils.cpp @@ -144,16 +144,17 @@ StringRef SysStr, Ver; std::tie(SysStr, Ver) = Arg.split(','); *Sys = StringSwitch(SysStr.lower()) - .Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION) - .Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI) - .Case("efi_application", IMAGE_SUBSYSTEM_EFI_APPLICATION) - .Case("efi_boot_service_driver", IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) - .Case("efi_rom", IMAGE_SUBSYSTEM_EFI_ROM) - .Case("efi_runtime_driver", IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) - .Case("native", IMAGE_SUBSYSTEM_NATIVE) - .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI) - .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI) - .Default(IMAGE_SUBSYSTEM_UNKNOWN); + .Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION) + .Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI) + .Case("efi_application", IMAGE_SUBSYSTEM_EFI_APPLICATION) + .Case("efi_boot_service_driver", + IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) + .Case("efi_rom", IMAGE_SUBSYSTEM_EFI_ROM) + .Case("efi_runtime_driver", IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) + .Case("native", IMAGE_SUBSYSTEM_NATIVE) + .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI) + .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI) + .Default(IMAGE_SUBSYSTEM_UNKNOWN); if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN) fatal("unknown subsystem: " + SysStr); if (!Ver.empty()) @@ -250,6 +251,29 @@ Config->AlignComm[Name] = std::max(Config->AlignComm[Name], 1 << V); } +// Parses /functionpadmin option argument. +void parseFunctionpadmin(StringRef Arg, llvm::COFF::MachineTypes Machine) { + StringRef Name, Padding; + std::tie(Name, Padding) = Arg.split(':'); + if (!Padding.empty()) { + // Optional padding in bytes is given. + if (Padding.getAsInteger(0, Config->Padding)) { + error("/functionpadmin: invalid argument: " + Arg); + return; + } + } else { + // No optional argument given. + // Set default padding based on machine, similar to link.exe. + if (Machine == I386) { + Config->Padding = 5; + } else if (Machine == AMD64) { + Config->Padding = 6; + } else { + error("/functionpadmin: invalid argument for this machine: " + Arg); + } + } +} + // Parses a string in the form of "EMBED[,=]|NO". // Results are directly written to Config. void parseManifest(StringRef Arg) { @@ -314,9 +338,7 @@ } } - TemporaryFile(TemporaryFile &&Obj) { - std::swap(Path, Obj.Path); - } + TemporaryFile(TemporaryFile &&Obj) { std::swap(Path, Obj.Path); } ~TemporaryFile() { if (Path.empty()) @@ -743,8 +765,11 @@ // Create table mapping all options defined in Options.td static const llvm::opt::OptTable::Info InfoTable[] = { #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ - {X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \ - X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, + { \ + X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, X9, X8, \ + OPT_##GROUP, OPT_##ALIAS, X7, X12 \ + } \ + , #include "Options.inc" #undef OPTION }; Index: COFF/Options.td =================================================================== --- COFF/Options.td +++ COFF/Options.td @@ -61,6 +61,7 @@ def timestamp : P<"timestamp", "Specify the PE header timestamp">; def version : P<"version", "Specify a version number in the PE header">; def wholearchive_file : P<"wholearchive", "Include all object files from this archive">; +def functionpadmin : Joined<["/", "-", "-?"], "functionpadmin">, HelpText<"Create hotpatchable image">; def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias; @@ -166,7 +167,6 @@ def _no : F; } -def functionpadmin : F<"functionpadmin">; def ignoreidl : F<"ignoreidl">; def nologo : F<"nologo">; def throwingnew : F<"throwingnew">; Index: COFF/PDB.cpp =================================================================== --- COFF/PDB.cpp +++ COFF/PDB.cpp @@ -115,11 +115,11 @@ /// If the object does not use a type server PDB (compiled with /Z7), we merge /// all the type and item records from the .debug$S stream and fill in the /// caller-provided ObjectIndexMap. - Expected mergeDebugT(ObjFile *File, - CVIndexMap &ObjectIndexMap); + Expected mergeDebugT(ObjFile *File, + CVIndexMap &ObjectIndexMap); - Expected maybeMergeTypeServerPDB(ObjFile *File, - TypeServer2Record &TS); + Expected maybeMergeTypeServerPDB(ObjFile *File, + TypeServer2Record &TS); /// Add the section map and section contributions to the PDB. void addSections(ArrayRef OutputSections, @@ -256,8 +256,8 @@ return std::move(TS); } -Expected PDBLinker::mergeDebugT(ObjFile *File, - CVIndexMap &ObjectIndexMap) { +Expected +PDBLinker::mergeDebugT(ObjFile *File, CVIndexMap &ObjectIndexMap) { ScopedTimer T(TypeMergingTimer); ArrayRef Data = getDebugSection(File, ".debug$T"); @@ -332,15 +332,15 @@ return std::move(NS); } -Expected PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, - TypeServer2Record &TS) { - const GUID& TSId = TS.getGuid(); +Expected +PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, TypeServer2Record &TS) { + const GUID &TSId = TS.getGuid(); StringRef TSPath = TS.getName(); // First, check if the PDB has previously failed to load. if (MissingTypeServerPDBs.count(TSId)) return make_error( - pdb::generic_error_code::type_server_not_found, TSPath); + pdb::generic_error_code::type_server_not_found, TSPath); // Second, check if we already loaded a PDB with this GUID. Return the type // index mapping if we have it. @@ -361,8 +361,8 @@ StringRef LocalPath = !File->ParentName.empty() ? File->ParentName : File->getName(); SmallString<128> Path = sys::path::parent_path(LocalPath); - sys::path::append( - Path, sys::path::filename(TSPath, sys::path::Style::windows)); + sys::path::append(Path, + sys::path::filename(TSPath, sys::path::Style::windows)); ExpectedSession = tryToLoadPDB(TSId, Path); } if (auto E = ExpectedSession.takeError()) { @@ -783,8 +783,12 @@ memset(&SC, 0, sizeof(SC)); SC.ISect = OS->SectionIndex; SC.Off = C->getRVA() - OS->getRVA(); - SC.Size = C->getSize(); if (auto *SecChunk = dyn_cast(C)) { + // Section chunks might be padded due to /FUNCTIONPADMIN, which alters their + // size. However, contributions stored in the PDB need to store the raw size + // without any padding to mimic the behaviour of link.exe. + SC.Size = SecChunk->getRawSize(); + SC.Characteristics = SecChunk->Header->Characteristics; SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex(); ArrayRef Contents = SecChunk->getContents(); @@ -794,7 +798,9 @@ CRC.update(CharContents); SC.DataCrc = CRC.getCRC(); } else { + SC.Size = C->getSize(); SC.Characteristics = OS->Header.Characteristics; + // FIXME: When we start creating DBI for import libraries, use those here. SC.Imod = Modi; }