[lld] r354716 - [LLD][COFF] Add support for /FUNCTIONPADMIN command-line option
Alexandre Ganea via llvm-commits
llvm-commits at lists.llvm.org
Fri Feb 22 17:46:18 PST 2019
Author: aganea
Date: Fri Feb 22 17:46:18 2019
New Revision: 354716
URL: http://llvm.org/viewvc/llvm-project?rev=354716&view=rev
Log:
[LLD][COFF] Add support for /FUNCTIONPADMIN command-line option
Initial patch by Stefan Reinalter.
Fixes PR36775
Differential Revision: https://reviews.llvm.org/D49366
Added:
lld/trunk/test/COFF/functionpadmin.test
Modified:
lld/trunk/COFF/Chunks.cpp
lld/trunk/COFF/Chunks.h
lld/trunk/COFF/Config.h
lld/trunk/COFF/Driver.cpp
lld/trunk/COFF/Driver.h
lld/trunk/COFF/DriverUtils.cpp
lld/trunk/COFF/InputFiles.cpp
lld/trunk/COFF/InputFiles.h
lld/trunk/COFF/Options.td
lld/trunk/COFF/PDB.cpp
lld/trunk/COFF/Writer.cpp
Modified: lld/trunk/COFF/Chunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.cpp?rev=354716&r1=354715&r2=354716&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.cpp (original)
+++ lld/trunk/COFF/Chunks.cpp Fri Feb 22 17:46:18 2019
@@ -594,6 +594,40 @@ ArrayRef<uint8_t> SectionChunk::getConte
return A;
}
+ArrayRef<uint8_t> SectionChunk::consumeDebugMagic() {
+ assert(isCodeView());
+ return consumeDebugMagic(getContents(), SectionName);
+}
+
+ArrayRef<uint8_t> SectionChunk::consumeDebugMagic(ArrayRef<uint8_t> Data,
+ StringRef SectionName) {
+ if (Data.empty())
+ return {};
+
+ // First 4 bytes are section magic.
+ if (Data.size() < 4)
+ fatal("the section is too short: " + SectionName);
+
+ if (!SectionName.startswith(".debug$"))
+ fatal("invalid section: " + SectionName);
+
+ unsigned Magic = support::endian::read32le(Data.data());
+ unsigned ExpectedMagic = SectionName == ".debug$H"
+ ? DEBUG_HASHES_SECTION_MAGIC
+ : DEBUG_SECTION_MAGIC;
+ if (Magic != ExpectedMagic)
+ fatal("section: " + SectionName + " has an invalid magic: " + Twine(Magic));
+ return Data.slice(4);
+}
+
+SectionChunk *SectionChunk::findByName(ArrayRef<SectionChunk *> Sections,
+ StringRef Name) {
+ for (SectionChunk *C : Sections)
+ if (C->getSectionName() == Name)
+ return C;
+ return nullptr;
+}
+
void SectionChunk::replace(SectionChunk *Other) {
Alignment = std::max(Alignment, Other->Alignment);
Other->Repl = Repl;
Modified: lld/trunk/COFF/Chunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.h?rev=354716&r1=354715&r2=354716&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.h (original)
+++ lld/trunk/COFF/Chunks.h Fri Feb 22 17:46:18 2019
@@ -108,6 +108,8 @@ public:
// The alignment of this chunk. The writer uses the value.
uint32_t Alignment = 1;
+ virtual bool isHotPatchable() const { return false; }
+
protected:
Chunk(Kind K = OtherKind) : ChunkKind(K) {}
const Kind ChunkKind;
@@ -205,6 +207,16 @@ public:
// The section ID this chunk belongs to in its Obj.
uint32_t getSectionNumber() const;
+ ArrayRef<uint8_t> consumeDebugMagic();
+
+ static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> Data,
+ StringRef SectionName);
+
+ static SectionChunk *findByName(ArrayRef<SectionChunk *> Sections,
+ StringRef Name);
+
+ bool isHotPatchable() const override { return File->HotPatchable; }
+
// 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,
@@ -321,6 +333,8 @@ public:
size_t getSize() const override { return sizeof(ImportThunkX86); }
void writeTo(uint8_t *Buf) const override;
+ bool isHotPatchable() const override { return true; }
+
private:
Defined *ImpSymbol;
};
@@ -332,6 +346,8 @@ public:
void getBaserels(std::vector<Baserel> *Res) override;
void writeTo(uint8_t *Buf) const override;
+ bool isHotPatchable() const override { return true; }
+
private:
Defined *ImpSymbol;
};
@@ -343,6 +359,8 @@ public:
void getBaserels(std::vector<Baserel> *Res) override;
void writeTo(uint8_t *Buf) const override;
+ bool isHotPatchable() const override { return true; }
+
private:
Defined *ImpSymbol;
};
@@ -353,6 +371,8 @@ public:
size_t getSize() const override { return sizeof(ImportThunkARM64); }
void writeTo(uint8_t *Buf) const override;
+ bool isHotPatchable() const override { return true; }
+
private:
Defined *ImpSymbol;
};
Modified: lld/trunk/COFF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Config.h?rev=354716&r1=354715&r2=354716&view=diff
==============================================================================
--- lld/trunk/COFF/Config.h (original)
+++ lld/trunk/COFF/Config.h Fri Feb 22 17:46:18 2019
@@ -185,6 +185,7 @@ struct Configuration {
uint32_t MajorOSVersion = 6;
uint32_t MinorOSVersion = 0;
uint32_t Timestamp = 0;
+ uint32_t FunctionPadMin = 0;
bool DynamicBase = true;
bool AllowBind = true;
bool NxCompat = true;
Modified: lld/trunk/COFF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=354716&r1=354715&r2=354716&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.cpp (original)
+++ lld/trunk/COFF/Driver.cpp Fri Feb 22 17:46:18 2019
@@ -1418,6 +1418,10 @@ void LinkerDriver::link(ArrayRef<const c
}
Config->Wordsize = Config->is64() ? 8 : 4;
+ // Handle /functionpadmin
+ for (auto *Arg : Args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt))
+ parseFunctionPadMin(Arg, Config->Machine);
+
// Input files can be Windows resource files (.res files). We use
// WindowsResource to convert resource files to a regular COFF file,
// then link the resulting file normally.
Modified: lld/trunk/COFF/Driver.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.h?rev=354716&r1=354715&r2=354716&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.h (original)
+++ lld/trunk/COFF/Driver.h Fri Feb 22 17:46:18 2019
@@ -158,6 +158,9 @@ void parseMerge(StringRef);
void parseSection(StringRef);
void parseAligncomm(StringRef);
+// Parses a string in the form of "[:<integer>]"
+void parseFunctionPadMin(llvm::opt::Arg *A, llvm::COFF::MachineTypes Machine);
+
// Parses a string in the form of "EMBED[,=<integer>]|NO".
void parseManifest(StringRef Arg);
Modified: lld/trunk/COFF/DriverUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DriverUtils.cpp?rev=354716&r1=354715&r2=354716&view=diff
==============================================================================
--- lld/trunk/COFF/DriverUtils.cpp (original)
+++ lld/trunk/COFF/DriverUtils.cpp Fri Feb 22 17:46:18 2019
@@ -249,6 +249,27 @@ void parseAligncomm(StringRef S) {
Config->AlignComm[Name] = std::max(Config->AlignComm[Name], 1 << V);
}
+// Parses /functionpadmin option argument.
+void parseFunctionPadMin(llvm::opt::Arg *A, llvm::COFF::MachineTypes Machine) {
+ StringRef Arg = A->getNumValues() ? A->getValue() : "";
+ if (!Arg.empty()) {
+ // Optional padding in bytes is given.
+ if (Arg.getAsInteger(0, Config->FunctionPadMin))
+ error("/functionpadmin: invalid argument: " + Arg);
+ return;
+ }
+ // No optional argument given.
+ // Set default padding based on machine, similar to link.exe.
+ // There is no default padding for ARM platforms.
+ if (Machine == I386) {
+ Config->FunctionPadMin = 5;
+ } else if (Machine == AMD64) {
+ Config->FunctionPadMin = 6;
+ } else {
+ error("/functionpadmin: invalid argument for this machine: " + Arg);
+ }
+}
+
// Parses a string in the form of "EMBED[,=<integer>]|NO".
// Results are directly written to Config.
void parseManifest(StringRef Arg) {
Modified: lld/trunk/COFF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.cpp?rev=354716&r1=354715&r2=354716&view=diff
==============================================================================
--- lld/trunk/COFF/InputFiles.cpp (original)
+++ lld/trunk/COFF/InputFiles.cpp Fri Feb 22 17:46:18 2019
@@ -19,6 +19,9 @@
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Casting.h"
@@ -34,6 +37,7 @@
using namespace llvm;
using namespace llvm::COFF;
+using namespace llvm::codeview;
using namespace llvm::object;
using namespace llvm::support::endian;
@@ -124,6 +128,7 @@ void ObjFile::parse() {
// Read section and symbol tables.
initializeChunks();
initializeSymbols();
+ initializeFlags();
}
const coff_section* ObjFile::getSection(uint32_t I) {
@@ -598,6 +603,59 @@ MachineTypes ObjFile::getMachineType() {
return IMAGE_FILE_MACHINE_UNKNOWN;
}
+ArrayRef<uint8_t> ObjFile::getDebugSection(StringRef SecName) {
+ if (SectionChunk *Sec = SectionChunk::findByName(DebugChunks, SecName))
+ return Sec->consumeDebugMagic();
+ return {};
+}
+
+// OBJ files systematically store critical informations in a .debug$S stream,
+// even if the TU was compiled with no debug info. At least two records are
+// always there. S_OBJNAME stores a 32-bit signature, which is loaded into the
+// PCHSignature member. S_COMPILE3 stores compile-time cmd-line flags. This is
+// currently used to initialize the HotPatchable member.
+void ObjFile::initializeFlags() {
+ ArrayRef<uint8_t> Data = getDebugSection(".debug$S");
+ if (Data.empty())
+ return;
+
+ DebugSubsectionArray Subsections;
+
+ BinaryStreamReader Reader(Data, support::little);
+ ExitOnError ExitOnErr;
+ ExitOnErr(Reader.readArray(Subsections, Data.size()));
+
+ for (const DebugSubsectionRecord &SS : Subsections) {
+ if (SS.kind() != DebugSubsectionKind::Symbols)
+ continue;
+
+ unsigned Offset = 0;
+
+ // Only parse the first two records. We are only looking for S_OBJNAME
+ // and S_COMPILE3, and they usually appear at the beginning of the
+ // stream.
+ for (unsigned I = 0; I < 2; ++I) {
+ Expected<CVSymbol> Sym = readSymbolFromStream(SS.getRecordData(), Offset);
+ if (!Sym) {
+ consumeError(Sym.takeError());
+ return;
+ }
+ if (Sym->kind() == SymbolKind::S_COMPILE3) {
+ auto CS =
+ cantFail(SymbolDeserializer::deserializeAs<Compile3Sym>(Sym.get()));
+ HotPatchable =
+ (CS.Flags & CompileSym3Flags::HotPatch) != CompileSym3Flags::None;
+ }
+ if (Sym->kind() == SymbolKind::S_OBJNAME) {
+ auto ObjName = cantFail(SymbolDeserializer::deserializeAs<ObjNameSym>(
+ Sym.get()));
+ PCHSignature = ObjName.Signature;
+ }
+ Offset += Sym->length();
+ }
+ }
+}
+
StringRef ltrim1(StringRef S, const char *Chars) {
if (!S.empty() && strchr(Chars, S[0]))
return S.substr(1);
Modified: lld/trunk/COFF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.h?rev=354716&r1=354715&r2=354716&view=diff
==============================================================================
--- lld/trunk/COFF/InputFiles.h (original)
+++ lld/trunk/COFF/InputFiles.h Fri Feb 22 17:46:18 2019
@@ -117,6 +117,8 @@ public:
ArrayRef<SectionChunk *> getGuardLJmpChunks() { return GuardLJmpChunks; }
ArrayRef<Symbol *> getSymbols() { return Symbols; }
+ ArrayRef<uint8_t> getDebugSection(StringRef SecName);
+
// Returns a Symbol object for the SymbolIndex'th symbol in the
// underlying object file.
Symbol *getSymbol(uint32_t SymbolIndex) {
@@ -156,6 +158,9 @@ public:
// precompiled object. Any difference indicates out-of-date objects.
llvm::Optional<uint32_t> PCHSignature;
+ // Tells whether this file was compiled with /hotpatch
+ bool HotPatchable = false;
+
private:
const coff_section* getSection(uint32_t I);
const coff_section *getSection(COFFSymbolRef Sym) {
@@ -164,6 +169,7 @@ private:
void initializeChunks();
void initializeSymbols();
+ void initializeFlags();
SectionChunk *
readSection(uint32_t SectionNumber,
Modified: lld/trunk/COFF/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Options.td?rev=354716&r1=354715&r2=354716&view=diff
==============================================================================
--- lld/trunk/COFF/Options.td (original)
+++ lld/trunk/COFF/Options.td Fri Feb 22 17:46:18 2019
@@ -32,6 +32,8 @@ def errorlimit : P<"errorlimit",
def export : P<"export", "Export a function">;
// No help text because /failifmismatch is not intended to be used by the user.
def failifmismatch : P<"failifmismatch", "">;
+def functionpadmin : F<"functionpadmin">;
+def functionpadmin_opt : P<"functionpadmin", "Prepares an image for hotpatching">;
def guard : P<"guard", "Control flow guard">;
def heap : P<"heap", "Size of the heap">;
def ignore : P<"ignore", "Specify warning codes to ignore">;
@@ -178,7 +180,6 @@ multiclass QB<string name> {
def _no : F<name#":no">;
}
-def functionpadmin : F<"functionpadmin">;
def ignoreidl : F<"ignoreidl">;
def nologo : F<"nologo">;
def throwingnew : F<"throwingnew">;
Modified: lld/trunk/COFF/PDB.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/PDB.cpp?rev=354716&r1=354715&r2=354716&view=diff
==============================================================================
--- lld/trunk/COFF/PDB.cpp (original)
+++ lld/trunk/COFF/PDB.cpp Fri Feb 22 17:46:18 2019
@@ -308,30 +308,6 @@ static void pdbMakeAbsolute(SmallVectorI
FileName = std::move(AbsoluteFileName);
}
-static SectionChunk *findByName(ArrayRef<SectionChunk *> Sections,
- StringRef Name) {
- for (SectionChunk *C : Sections)
- if (C->getSectionName() == Name)
- return C;
- return nullptr;
-}
-
-static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> Data,
- StringRef SecName) {
- // First 4 bytes are section magic.
- if (Data.size() < 4)
- fatal(SecName + " too short");
- if (support::endian::read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC)
- fatal(SecName + " has an invalid magic");
- return Data.slice(4);
-}
-
-static ArrayRef<uint8_t> getDebugSection(ObjFile *File, StringRef SecName) {
- if (SectionChunk *Sec = findByName(File->getDebugChunks(), SecName))
- return consumeDebugMagic(Sec->getContents(), SecName);
- return {};
-}
-
// A COFF .debug$H section is currently a clang extension. This function checks
// if a .debug$H section is in a format that we expect / understand, so that we
// can ignore any sections which are coincidentally also named .debug$H but do
@@ -349,7 +325,8 @@ static bool canUseDebugH(ArrayRef<uint8_
}
static Optional<ArrayRef<uint8_t>> getDebugH(ObjFile *File) {
- SectionChunk *Sec = findByName(File->getDebugChunks(), ".debug$H");
+ SectionChunk *Sec =
+ SectionChunk::findByName(File->getDebugChunks(), ".debug$H");
if (!Sec)
return llvm::None;
ArrayRef<uint8_t> Contents = Sec->getContents();
@@ -381,51 +358,17 @@ static void addTypeInfo(pdb::TpiStreamBu
});
}
-// OBJs usually start their symbol stream with a S_OBJNAME record. This record
-// also contains the signature/key of the current PCH session. The signature
-// must be same for all objects which depend on the precompiled object.
-// Recompiling the precompiled headers will generate a new PCH key and thus
-// invalidate all the dependent objects.
-static uint32_t extractPCHSignature(ObjFile *File) {
- auto DbgIt = find_if(File->getDebugChunks(), [](SectionChunk *C) {
- return C->getSectionName() == ".debug$S";
- });
- if (!DbgIt)
- return 0;
-
- ArrayRef<uint8_t> Contents =
- consumeDebugMagic((*DbgIt)->getContents(), ".debug$S");
- DebugSubsectionArray Subsections;
- BinaryStreamReader Reader(Contents, support::little);
- ExitOnErr(Reader.readArray(Subsections, Contents.size()));
-
- for (const DebugSubsectionRecord &SS : Subsections) {
- if (SS.kind() != DebugSubsectionKind::Symbols)
- continue;
-
- // If it's there, the S_OBJNAME record shall come first in the stream.
- Expected<CVSymbol> Sym = readSymbolFromStream(SS.getRecordData(), 0);
- if (!Sym) {
- consumeError(Sym.takeError());
- continue;
- }
- if (auto ObjName = SymbolDeserializer::deserializeAs<ObjNameSym>(Sym.get()))
- return ObjName->Signature;
- }
- return 0;
-}
-
Expected<const CVIndexMap &>
PDBLinker::mergeDebugT(ObjFile *File, CVIndexMap *ObjectIndexMap) {
ScopedTimer T(TypeMergingTimer);
bool IsPrecompiledHeader = false;
- ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
+ ArrayRef<uint8_t> Data = File->getDebugSection(".debug$T");
if (Data.empty()) {
// Try again, Microsoft precompiled headers use .debug$P instead of
// .debug$T
- Data = getDebugSection(File, ".debug$P");
+ Data = File->getDebugSection(".debug$P");
IsPrecompiledHeader = true;
}
if (Data.empty())
@@ -434,7 +377,7 @@ PDBLinker::mergeDebugT(ObjFile *File, CV
// Precompiled headers objects need to save the index map for further
// reference by other objects which use the precompiled headers.
if (IsPrecompiledHeader) {
- uint32_t PCHSignature = extractPCHSignature(File);
+ uint32_t PCHSignature = File->PCHSignature.getValueOr(0);
if (PCHSignature == 0)
fatal("No signature found for the precompiled headers OBJ (" +
File->getName() + ")");
@@ -1176,7 +1119,7 @@ translateStringTableIndex(uint32_t ObjIn
void DebugSHandler::handleDebugS(lld::coff::SectionChunk &DebugS) {
DebugSubsectionArray Subsections;
- ArrayRef<uint8_t> RelocatedDebugContents = consumeDebugMagic(
+ ArrayRef<uint8_t> RelocatedDebugContents = SectionChunk::consumeDebugMagic(
relocateDebugChunk(Linker.Alloc, DebugS), DebugS.getSectionName());
BinaryStreamReader Reader(RelocatedDebugContents, support::little);
@@ -1676,7 +1619,7 @@ static bool findLineTable(const SectionC
}
ArrayRef<uint8_t> Contents =
- consumeDebugMagic(DbgC->getContents(), ".debug$S");
+ SectionChunk::consumeDebugMagic(DbgC->getContents(), ".debug$S");
DebugSubsectionArray Subsections;
BinaryStreamReader Reader(Contents, support::little);
ExitOnErr(Reader.readArray(Subsections, Contents.size()));
Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=354716&r1=354715&r2=354716&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Fri Feb 22 17:46:18 2019
@@ -1117,7 +1117,18 @@ void Writer::assignAddresses() {
addBaserels();
uint64_t RawSize = 0, VirtualSize = 0;
Sec->Header.VirtualAddress = RVA;
+
+ // If /FUNCTIONPADMIN is used, functions are padded in order to create a
+ // hotpatchable image.
+ const bool IsCodeSection =
+ (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE) &&
+ (Sec->Header.Characteristics & IMAGE_SCN_MEM_READ) &&
+ (Sec->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE);
+ uint32_t Padding = IsCodeSection ? Config->FunctionPadMin : 0;
+
for (Chunk *C : Sec->Chunks) {
+ if (Padding && C->isHotPatchable())
+ VirtualSize += Padding;
VirtualSize = alignTo(VirtualSize, C->Alignment);
C->setRVA(RVA + VirtualSize);
C->OutputSectionOff = VirtualSize;
Added: lld/trunk/test/COFF/functionpadmin.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/functionpadmin.test?rev=354716&view=auto
==============================================================================
--- lld/trunk/test/COFF/functionpadmin.test (added)
+++ lld/trunk/test/COFF/functionpadmin.test Fri Feb 22 17:46:18 2019
@@ -0,0 +1,147 @@
+// ---- precomp-a.obj - x86_64, hotpatch
+RUN: lld-link %S/Inputs/precomp-a.obj /out:%t.exe /nodefaultlib /force
+RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix BASE
+
+RUN: lld-link %S/Inputs/precomp-a.obj /out:%t.exe /nodefaultlib /force /functionpadmin
+RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix PADDED
+
+RUN: lld-link %S/Inputs/precomp-a.obj /out:%t.exe /nodefaultlib /force /functionpadmin:17
+RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix PADDED-MORE
+
+// ---- Many arguments
+RUN: lld-link %S/Inputs/precomp-a.obj /out:%t.exe /nodefaultlib /force /functionpadmin:17 /functionpadmin
+RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix PADDED
+
+RUN: lld-link %S/Inputs/precomp-a.obj /out:%t.exe /nodefaultlib /force /functionpadmin /functionpadmin:17
+RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix PADDED-MORE
+
+RUN: not lld-link %S/Inputs/precomp-a.obj /out:%t.exe /nodefaultlib /force /functionpadmin:zz 2>&1 | FileCheck %s --check-prefix FAIL
+
+// ---- precomp-a.obj, precomp-b.obj - x86_64, hotpatch - Ensure several functions are properly padded
+RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /out:%t.exe /nodefaultlib /force
+RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix MULTI-BASE
+
+RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /out:%t.exe /nodefaultlib /force /functionpadmin
+RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix MULTI-BASE-PADDED
+
+RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /out:%t.exe /nodefaultlib /force /functionpadmin:17
+RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix MULTI-BASE-PADDED-MORE
+
+// ---- pdb-diff.obj - x86, no hotpatch - No padding is applied
+RUN: lld-link %S/Inputs/pdb-diff.obj /out:%t.exe /nodefaultlib /force /functionpadmin
+RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix NO-HOTPATCH
+
+// ---- hello64.obj - MASM, x86_64, no hotpatch - No padding is applied
+RUN: lld-link %S/Inputs/hello64.obj /out:%t.exe /nodefaultlib /force /functionpadmin
+RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix HELLO
+
+// ---- std64.lib - Import library, x86_64 - Ensure thunks are padded
+RUN: lld-link %S/Inputs/std64.lib /entry:ExitProcess /out:%t.exe /nodefaultlib /force /subsystem:console
+RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix THUNKS-NO-PAD
+RUN: llvm-readobj --file-headers %t.exe | FileCheck %s --check-prefix THUNKS-NO-PAD-ENTRY
+
+RUN: lld-link %S/Inputs/std64.lib /entry:ExitProcess /out:%t.exe /nodefaultlib /force /functionpadmin /subsystem:console
+RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix THUNKS-PAD
+RUN: llvm-readobj --file-headers %t.exe | FileCheck %s --check-prefix THUNKS-PAD-ENTRY
+
+BASE: Contents of section .text:
+BASE-NEXT: 140001000 4883ec28 b161e8f5 efffbf33 c04883c4 H..(.a.....3.H..
+BASE-NEXT: 140001010 28c3 (.
+BASE-NEXT: Contents of section .rdata:
+BASE-NEXT: 140002000 01040100 04420000 .....B..
+BASE-NEXT: Contents of section .pdata:
+BASE-NEXT: 140003000 00100000 12100000 00200000 ......... ..
+
+PADDED: Contents of section .text:
+PADDED-NEXT: 140001000 cccccccc cccccccc cccccccc cccccccc ................
+PADDED-NEXT: 140001010 4883ec28 b161e8e5 efffbf33 c04883c4 H..(.a.....3.H..
+PADDED-NEXT: 140001020 28c3 (.
+PADDED-NEXT: Contents of section .rdata:
+PADDED-NEXT: 140002000 01040100 04420000 .....B..
+PADDED-NEXT: Contents of section .pdata:
+PADDED-NEXT: 140003000 10100000 22100000 00200000 ....".... ..
+
+PADDED-MORE: Contents of section .text:
+PADDED-MORE-NEXT: 140001000 cccccccc cccccccc cccccccc cccccccc ................
+PADDED-MORE-NEXT: 140001010 cccccccc cccccccc cccccccc cccccccc ................
+PADDED-MORE-NEXT: 140001020 4883ec28 b161e8d5 efffbf33 c04883c4 H..(.a.....3.H..
+PADDED-MORE-NEXT: 140001030 28c3 (.
+PADDED-MORE-NEXT: Contents of section .rdata:
+PADDED-MORE-NEXT: 140002000 01040100 04420000 .....B..
+PADDED-MORE-NEXT: Contents of section .pdata:
+PADDED-MORE-NEXT: 140003000 20100000 32100000 00200000 ...2.... ..
+
+FAIL: lld-link: error: /functionpadmin: invalid argument: zz
+
+MULTI-BASE: Contents of section .text:
+MULTI-BASE-NEXT: 140001000 4883ec28 b161e815 00000033 c04883c4 H..(.a.....3.H..
+MULTI-BASE-NEXT: 140001010 28c3cccc cccccccc cccccccc cccccccc (...............
+MULTI-BASE-NEXT: 140001020 884c2408 0fbe4424 08c3 .L$...D$..
+MULTI-BASE-NEXT: Contents of section .rdata:
+MULTI-BASE-NEXT: 140002000 01040100 04420000 .....B..
+MULTI-BASE-NEXT: Contents of section .pdata:
+MULTI-BASE-NEXT: 140004000 00100000 12100000 00200000 ......... ..
+
+MULTI-BASE-PADDED: Contents of section .text:
+MULTI-BASE-PADDED-NEXT: 140001000 cccccccc cccccccc cccccccc cccccccc ................
+MULTI-BASE-PADDED-NEXT: 140001010 4883ec28 b161e815 00000033 c04883c4 H..(.a.....3.H..
+MULTI-BASE-PADDED-NEXT: 140001020 28c3cccc cccccccc cccccccc cccccccc (...............
+MULTI-BASE-PADDED-NEXT: 140001030 884c2408 0fbe4424 08c3 .L$...D$..
+MULTI-BASE-PADDED-NEXT: Contents of section .rdata:
+MULTI-BASE-PADDED-NEXT: 140002000 01040100 04420000 .....B..
+MULTI-BASE-PADDED-NEXT: Contents of section .pdata:
+MULTI-BASE-PADDED-NEXT: 140004000 10100000 22100000 00200000 ....".... ..
+
+MULTI-BASE-PADDED-MORE: Contents of section .text:
+MULTI-BASE-PADDED-MORE-NEXT: 140001000 cccccccc cccccccc cccccccc cccccccc ................
+MULTI-BASE-PADDED-MORE-NEXT: 140001010 cccccccc cccccccc cccccccc cccccccc ................
+MULTI-BASE-PADDED-MORE-NEXT: 140001020 4883ec28 b161e825 00000033 c04883c4 H..(.a.%...3.H..
+MULTI-BASE-PADDED-MORE-NEXT: 140001030 28c3cccc cccccccc cccccccc cccccccc (...............
+MULTI-BASE-PADDED-MORE-NEXT: 140001040 cccccccc cccccccc cccccccc cccccccc ................
+MULTI-BASE-PADDED-MORE-NEXT: 140001050 884c2408 0fbe4424 08c3 .L$...D$..
+MULTI-BASE-PADDED-MORE-NEXT: Contents of section .rdata:
+MULTI-BASE-PADDED-MORE-NEXT: 140002000 01040100 04420000 .....B..
+MULTI-BASE-PADDED-MORE-NEXT: Contents of section .pdata:
+MULTI-BASE-PADDED-MORE-NEXT: 140004000 20100000 32100000 00200000 ...2.... ..
+
+
+NO-HOTPATCH: Contents of section .text:
+NO-HOTPATCH-NEXT: 401000 558becb8 2a000000 5dc3 U...*...].
+
+HELLO: Contents of section .text:
+HELLO-NEXT: 140001000 4883ec28 48c7c100 00000048 8d15f40f H..(H......H....
+HELLO-NEXT: 140001010 00004c8d 05e70f00 0041b900 000000e8 ..L......A......
+HELLO-NEXT: 140001020 dcefffbf b9000000 00e8d2ef ffbfe8cd ................
+HELLO-NEXT: 140001030 efffbf ...
+HELLO-NEXT: Contents of section .data:
+HELLO-NEXT: 140002000 48656c6c 6f004865 6c6c6f20 576f726c Hello.Hello Worl
+HELLO-NEXT: 140002010 642100 d!.
+
+THUNKS-NO-PAD: Contents of section .text:
+THUNKS-NO-PAD-NEXT: 140001000 ff253210 0000 .%2...
+THUNKS-NO-PAD-NEXT: Contents of section .rdata:
+THUNKS-NO-PAD-NEXT: 140002000 28200000 00000000 00000000 56200000 ( ..........V ..
+THUNKS-NO-PAD-NEXT: 140002010 38200000 00000000 00000000 00000000 8 ..............
+THUNKS-NO-PAD-NEXT: 140002020 00000000 00000000 48200000 00000000 ........H ......
+THUNKS-NO-PAD-NEXT: 140002030 00000000 00000000 48200000 00000000 ........H ......
+THUNKS-NO-PAD-NEXT: 140002040 00000000 00000000 00004578 69745072 ..........ExitPr
+THUNKS-NO-PAD-NEXT: 140002050 6f636573 73007374 6436342e 646c6c00 ocess.std64.dll.
+
+THUNKS-NO-PAD-ENTRY-LABEL: ImageOptionalHeader {
+THUNKS-NO-PAD-ENTRY: AddressOfEntryPoint: 0x1000
+THUNKS-NO-PAD-ENTRY-NEXT: BaseOfCode: 0x1000
+
+THUNKS-PAD: Contents of section .text:
+THUNKS-PAD-NEXT: 140001000 cccccccc cccccccc cccccccc cccccccc ................
+THUNKS-PAD-NEXT: 140001010 ff252210 0000 .%"...
+THUNKS-PAD-NEXT: Contents of section .rdata:
+THUNKS-PAD-NEXT: 140002000 28200000 00000000 00000000 56200000 ( ..........V ..
+THUNKS-PAD-NEXT: 140002010 38200000 00000000 00000000 00000000 8 ..............
+THUNKS-PAD-NEXT: 140002020 00000000 00000000 48200000 00000000 ........H ......
+THUNKS-PAD-NEXT: 140002030 00000000 00000000 48200000 00000000 ........H ......
+THUNKS-PAD-NEXT: 140002040 00000000 00000000 00004578 69745072 ..........ExitPr
+THUNKS-PAD-NEXT: 140002050 6f636573 73007374 6436342e 646c6c00 ocess.std64.dll.
+
+THUNKS-PAD-ENTRY-LABEL: ImageOptionalHeader {
+THUNKS-PAD-ENTRY: AddressOfEntryPoint: 0x1010
+THUNKS-PAD-ENTRY-NEXT: BaseOfCode: 0x1000
More information about the llvm-commits
mailing list