[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