[lld] 22e6648 - [lld-macho] Implement -headerpad

Jez Ng via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 30 14:30:34 PDT 2020


Author: Jez Ng
Date: 2020-07-30T14:29:31-07:00
New Revision: 22e6648a1834aa6680064eaf83e1e051a7248e17

URL: https://github.com/llvm/llvm-project/commit/22e6648a1834aa6680064eaf83e1e051a7248e17
DIFF: https://github.com/llvm/llvm-project/commit/22e6648a1834aa6680064eaf83e1e051a7248e17.diff

LOG: [lld-macho] Implement -headerpad

Tools like `install_name_tool` and `codesign` may modify the Mach-O
header and increase its size. The linker has to provide padding to make this
possible. This diff does that, plus sets its default value to 32 bytes (which
is what ld64 does).

Unlike ld64, however, we lay out our sections *exactly* `-headerpad` bytes from
the header, whereas ld64 just treats the padding requirement as a lower bound.
ld64 actually starts laying out the non-header sections in the __TEXT segment
from the end of the (page-aligned) segment rather than the front, so its
binaries typically have more than `-headerpad` bytes of actual padding.
We should consider implementing the same alignment behavior.

Reviewed By: #lld-macho, compnerd

Differential Revision: https://reviews.llvm.org/D84714

Added: 
    lld/test/MachO/headerpad.s

Modified: 
    lld/Common/Args.cpp
    lld/MachO/Config.h
    lld/MachO/Driver.cpp
    lld/MachO/Options.td
    lld/MachO/SyntheticSections.cpp
    lld/include/lld/Common/Args.h
    lld/test/MachO/local-got.s
    lld/test/MachO/relocations.s

Removed: 
    


################################################################################
diff  --git a/lld/Common/Args.cpp b/lld/Common/Args.cpp
index 4ea3a435c7ae..507830f9da34 100644
--- a/lld/Common/Args.cpp
+++ b/lld/Common/Args.cpp
@@ -26,14 +26,14 @@ CodeGenOpt::Level lld::args::getCGOptLevel(int optLevelLTO) {
   return CodeGenOpt::Default;
 }
 
-int64_t lld::args::getInteger(opt::InputArgList &args, unsigned key,
-                              int64_t Default) {
+static int64_t getInteger(opt::InputArgList &args, unsigned key,
+                          int64_t Default, unsigned base) {
   auto *a = args.getLastArg(key);
   if (!a)
     return Default;
 
   int64_t v;
-  if (to_integer(a->getValue(), v, 10))
+  if (to_integer(a->getValue(), v, base))
     return v;
 
   StringRef spelling = args.getArgString(a->getIndex());
@@ -41,6 +41,16 @@ int64_t lld::args::getInteger(opt::InputArgList &args, unsigned key,
   return 0;
 }
 
+int64_t lld::args::getInteger(opt::InputArgList &args, unsigned key,
+                              int64_t Default) {
+  return ::getInteger(args, key, Default, 10);
+}
+
+int64_t lld::args::getHex(opt::InputArgList &args, unsigned key,
+                          int64_t Default) {
+  return ::getInteger(args, key, Default, 16);
+}
+
 std::vector<StringRef> lld::args::getStrings(opt::InputArgList &args, int id) {
   std::vector<StringRef> v;
   for (auto *arg : args.filtered(id))

diff  --git a/lld/MachO/Config.h b/lld/MachO/Config.h
index c66991b581fc..f65ff7c5c104 100644
--- a/lld/MachO/Config.h
+++ b/lld/MachO/Config.h
@@ -25,6 +25,7 @@ struct SymbolPriorityEntry;
 struct Configuration {
   Symbol *entry;
   bool hasReexports = false;
+  uint32_t headerPad;
   llvm::StringRef installName;
   llvm::StringRef outputFile;
   llvm::MachO::Architecture arch;

diff  --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index a6d3eb69b8a0..afb914b55a16 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -396,6 +396,7 @@ bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
   config->outputFile = args.getLastArgValue(OPT_o, "a.out");
   config->installName =
       args.getLastArgValue(OPT_install_name, config->outputFile);
+  config->headerPad = args::getHex(args, OPT_headerpad, 32);
   getLibrarySearchPaths(config->librarySearchPaths, args);
   getFrameworkSearchPaths(config->frameworkSearchPaths, args);
   config->outputType = args.hasArg(OPT_dylib) ? MH_DYLIB : MH_EXECUTE;
@@ -450,6 +451,7 @@ bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
     case OPT_e:
     case OPT_F:
     case OPT_L:
+    case OPT_headerpad:
     case OPT_install_name:
     case OPT_Z:
     case OPT_arch:

diff  --git a/lld/MachO/Options.td b/lld/MachO/Options.td
index 7d81ca7c1427..c27ca0d0195f 100644
--- a/lld/MachO/Options.td
+++ b/lld/MachO/Options.td
@@ -693,7 +693,6 @@ def umbrella : Separate<["-"], "umbrella">,
 def headerpad : Separate<["-"], "headerpad">,
      MetaVarName<"<size>">,
      HelpText<"Allocate hex <size> extra space for future expansion of the load commands via install_name_tool">,
-     Flags<[HelpHidden]>,
      Group<grp_rare>;
 def headerpad_max_install_names : Flag<["-"], "headerpad_max_install_names">,
      HelpText<"Allocate extra space so all load-command paths can expand to MAXPATHLEN via install_name_tool">,

diff  --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index a2d8bf42e9ed..94df6c50e010 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -47,7 +47,7 @@ void MachHeaderSection::addLoadCommand(LoadCommand *lc) {
 }
 
 uint64_t MachHeaderSection::getSize() const {
-  return sizeof(MachO::mach_header_64) + sizeOfCmds;
+  return sizeof(MachO::mach_header_64) + sizeOfCmds + config->headerPad;
 }
 
 void MachHeaderSection::writeTo(uint8_t *buf) const {

diff  --git a/lld/include/lld/Common/Args.h b/lld/include/lld/Common/Args.h
index b3c8686e57e2..48f7b4079cd9 100644
--- a/lld/include/lld/Common/Args.h
+++ b/lld/include/lld/Common/Args.h
@@ -28,6 +28,8 @@ llvm::CodeGenOpt::Level getCGOptLevel(int optLevelLTO);
 int64_t getInteger(llvm::opt::InputArgList &args, unsigned key,
                    int64_t Default);
 
+int64_t getHex(llvm::opt::InputArgList &args, unsigned key, int64_t Default);
+
 std::vector<StringRef> getStrings(llvm::opt::InputArgList &args, int id);
 
 uint64_t getZOptionValue(llvm::opt::InputArgList &args, int id, StringRef key,

diff  --git a/lld/test/MachO/headerpad.s b/lld/test/MachO/headerpad.s
new file mode 100644
index 000000000000..963ccf9ce4e7
--- /dev/null
+++ b/lld/test/MachO/headerpad.s
@@ -0,0 +1,34 @@
+# REQUIRES: x86
+
+## NOTE: Here we check that the first non-header section -- __text -- appears
+## *exactly* `-headerpad` bytes from the end of the header. ld64 actually
+## starts laying out the non-header sections in the __TEXT segment from the end
+## of the (page-aligned) segment rather than the front, so its binaries
+## typically have more than `-headerpad` bytes of actual padding. `-headerpad`
+## just enforces a lower bound. We should consider implementing the same
+## alignment behavior.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
+# RUN: lld -flavor darwinnew -o %t %t.o -headerpad 0
+# RUN: llvm-objdump --macho --all-headers %t | FileCheck %s --check-prefix=PAD0
+# PAD0:      magic        cputype  cpusubtype  caps    filetype ncmds sizeofcmds
+# PAD0-NEXT: MH_MAGIC_64  X86_64   ALL         LIB64   EXECUTE  8     [[#%u, CMDSIZE:]] {{.*}}
+# PAD0:      sectname __text
+# PAD0-NEXT: segname __TEXT
+# PAD0-NEXT: addr
+# PAD0-NEXT: size
+# PAD0-NEXT: offset [[#%u, CMDSIZE + 32]]
+
+# RUN: lld -flavor darwinnew -o %t %t.o -headerpad 11
+# RUN: llvm-objdump --macho --all-headers %t | FileCheck %s --check-prefix=PAD11
+# PAD11:      magic        cputype  cpusubtype  caps    filetype ncmds sizeofcmds
+# PAD11-NEXT: MH_MAGIC_64  X86_64   ALL         LIB64   EXECUTE  8     [[#%u, CMDSIZE:]] {{.*}}
+# PAD11:      sectname __text
+# PAD11-NEXT: segname __TEXT
+# PAD11-NEXT: addr
+# PAD11-NEXT: size
+# PAD11-NEXT: offset [[#%u, CMDSIZE + 32 + 0x11]]
+
+.globl _main
+_main:
+  ret

diff  --git a/lld/test/MachO/local-got.s b/lld/test/MachO/local-got.s
index 6099a6bf18c7..baf4b3336b7a 100644
--- a/lld/test/MachO/local-got.s
+++ b/lld/test/MachO/local-got.s
@@ -12,12 +12,12 @@
 ## address offset and the contents at that address very similarly, so am using
 ## --match-full-lines to make sure we match on the right thing.
 # CHECK:      Contents of section __cstring:
-# CHECK-NEXT: 1000003cc {{.*}}
+# CHECK-NEXT: 1000003ec {{.*}}
 
 ## 1st 8 bytes refer to the start of __cstring + 0xe, 2nd 8 bytes refer to the
 ## start of __cstring
 # CHECK:      Contents of section __got:
-# CHECK-NEXT: [[#%X,ADDR:]]  da030000 01000000 cc030000 01000000 {{.*}}
+# CHECK-NEXT: [[#%X,ADDR:]]  fa030000 01000000 ec030000 01000000 {{.*}}
 # CHECK-NEXT: [[#ADDR + 16]] 00000000 00000000 {{.*}}
 
 ## Check that a non-locally-defined symbol is still bound at the correct offset:

diff  --git a/lld/test/MachO/relocations.s b/lld/test/MachO/relocations.s
index edaa30893560..93be4998db68 100644
--- a/lld/test/MachO/relocations.s
+++ b/lld/test/MachO/relocations.s
@@ -21,7 +21,7 @@
 
 # RUN: llvm-objdump --section=__const --full-contents -d %t | FileCheck %s --check-prefix=NONPCREL
 # NONPCREL:      Contents of section __const:
-# NONPCREL-NEXT: 100001000 b0030000 01000000 b0030000 01000000
+# NONPCREL-NEXT: 100001000 d0030000 01000000 d0030000 01000000
 
 .section __TEXT,__text
 .globl _main, _f


        


More information about the llvm-commits mailing list