[lld] 9821079 - [lld-macho] Make __LINKEDIT sections contiguous

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


Author: Jez Ng
Date: 2020-07-30T14:30:07-07:00
New Revision: 98210796e108b59bad56fed9df98e920359afc6b

URL: https://github.com/llvm/llvm-project/commit/98210796e108b59bad56fed9df98e920359afc6b
DIFF: https://github.com/llvm/llvm-project/commit/98210796e108b59bad56fed9df98e920359afc6b.diff

LOG: [lld-macho] Make __LINKEDIT sections contiguous

codesign (or more specifically libstuff) checks that each section in
__LINKEDIT ends where the next one starts -- no gaps are permitted. This
diff achieves it by aligning every section's start and end points to
WordSize.

Remarks: ld64 appears to satisfy the constraint by adding padding bytes
when generating the __LINKEDIT data, e.g. by emitting BIND_OPCODE_DONE
(which is a 0x0 byte) repeatedly. I think the approach this diff takes
is a bit more elegant, but I'm not sure if it's too restrictive. In
particular, it assumes padding always uses the zero byte. But we can
revisit this later.

Reviewed By: #lld-macho, compnerd

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

Added: 
    lld/test/MachO/linkedit-contiguity.s

Modified: 
    lld/MachO/SyntheticSections.cpp
    lld/MachO/SyntheticSections.h
    lld/MachO/Writer.cpp

Removed: 
    


################################################################################
diff  --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index 94df6c50e010..ac772da0129f 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -94,7 +94,7 @@ void GotSection::writeTo(uint8_t *buf) const {
 }
 
 BindingSection::BindingSection()
-    : SyntheticSection(segment_names::linkEdit, section_names::binding) {}
+    : LinkEditSection(segment_names::linkEdit, section_names::binding) {}
 
 bool BindingSection::isNeeded() const {
   return bindings.size() != 0 || in.got->isNeeded();
@@ -301,7 +301,7 @@ void LazyPointerSection::writeTo(uint8_t *buf) const {
 }
 
 LazyBindingSection::LazyBindingSection()
-    : SyntheticSection(segment_names::linkEdit, section_names::lazyBinding) {}
+    : LinkEditSection(segment_names::linkEdit, section_names::lazyBinding) {}
 
 bool LazyBindingSection::isNeeded() const { return in.stubs->isNeeded(); }
 
@@ -344,7 +344,7 @@ uint32_t LazyBindingSection::encode(const DylibSymbol &sym) {
 }
 
 ExportSection::ExportSection()
-    : SyntheticSection(segment_names::linkEdit, section_names::export_) {}
+    : LinkEditSection(segment_names::linkEdit, section_names::export_) {}
 
 void ExportSection::finalizeContents() {
   // TODO: We should check symbol visibility.
@@ -358,11 +358,7 @@ void ExportSection::writeTo(uint8_t *buf) const { trieBuilder.writeTo(buf); }
 
 SymtabSection::SymtabSection(StringTableSection &stringTableSection)
     : SyntheticSection(segment_names::linkEdit, section_names::symbolTable),
-      stringTableSection(stringTableSection) {
-  // TODO: When we introduce the SyntheticSections superclass, we should make
-  // all synthetic sections aligned to WordSize by default.
-  align = WordSize;
-}
+      stringTableSection(stringTableSection) {}
 
 uint64_t SymtabSection::getSize() const {
   return symbols.size() * sizeof(structs::nlist_64);
@@ -392,7 +388,7 @@ void SymtabSection::writeTo(uint8_t *buf) const {
 }
 
 StringTableSection::StringTableSection()
-    : SyntheticSection(segment_names::linkEdit, section_names::stringTable) {}
+    : LinkEditSection(segment_names::linkEdit, section_names::stringTable) {}
 
 uint32_t StringTableSection::addString(StringRef str) {
   uint32_t strx = size;

diff  --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h
index f3052000be5f..db2ffbe57d44 100644
--- a/lld/MachO/SyntheticSections.h
+++ b/lld/MachO/SyntheticSections.h
@@ -49,6 +49,27 @@ class SyntheticSection : public OutputSection {
   const StringRef segname;
 };
 
+// All sections in __LINKEDIT should inherit from this.
+class LinkEditSection : public SyntheticSection {
+public:
+  LinkEditSection(const char *segname, const char *name)
+      : SyntheticSection(segname, name) {
+    align = WordSize;
+  }
+
+  virtual uint64_t getRawSize() const = 0;
+
+  // codesign (or more specifically libstuff) checks that each section in
+  // __LINKEDIT ends where the next one starts -- no gaps are permitted. We
+  // therefore align every section's start and end points to WordSize.
+  //
+  // NOTE: This assumes that the extra bytes required for alignment can be
+  // zero-valued bytes.
+  uint64_t getSize() const override final {
+    return llvm::alignTo(getRawSize(), WordSize);
+  }
+};
+
 // The header of the Mach-O file, which must have a file offset of zero.
 class MachHeaderSection : public SyntheticSection {
 public:
@@ -105,11 +126,11 @@ struct BindingEntry {
 };
 
 // Stores bind opcodes for telling dyld which symbols to load non-lazily.
-class BindingSection : public SyntheticSection {
+class BindingSection : public LinkEditSection {
 public:
   BindingSection();
   void finalizeContents();
-  uint64_t getSize() const override { return contents.size(); }
+  uint64_t getRawSize() const override { return contents.size(); }
   // Like other sections in __LINKEDIT, the binding section is special: its
   // offsets are recorded in the LC_DYLD_INFO_ONLY load command, instead of in
   // section headers.
@@ -194,11 +215,11 @@ class LazyPointerSection : public SyntheticSection {
   void writeTo(uint8_t *buf) const override;
 };
 
-class LazyBindingSection : public SyntheticSection {
+class LazyBindingSection : public LinkEditSection {
 public:
   LazyBindingSection();
   void finalizeContents();
-  uint64_t getSize() const override { return contents.size(); }
+  uint64_t getRawSize() const override { return contents.size(); }
   uint32_t encode(const DylibSymbol &);
   // Like other sections in __LINKEDIT, the lazy binding section is special: its
   // offsets are recorded in the LC_DYLD_INFO_ONLY load command, instead of in
@@ -213,11 +234,11 @@ class LazyBindingSection : public SyntheticSection {
 };
 
 // Stores a trie that describes the set of exported symbols.
-class ExportSection : public SyntheticSection {
+class ExportSection : public LinkEditSection {
 public:
   ExportSection();
   void finalizeContents();
-  uint64_t getSize() const override { return size; }
+  uint64_t getRawSize() const override { return size; }
   // Like other sections in __LINKEDIT, the export section is special: its
   // offsets are recorded in the LC_DYLD_INFO_ONLY load command, instead of in
   // section headers.
@@ -230,12 +251,12 @@ class ExportSection : public SyntheticSection {
 };
 
 // Stores the strings referenced by the symbol table.
-class StringTableSection : public SyntheticSection {
+class StringTableSection : public LinkEditSection {
 public:
   StringTableSection();
   // Returns the start offset of the added string.
   uint32_t addString(StringRef);
-  uint64_t getSize() const override { return size; }
+  uint64_t getRawSize() const override { return size; }
   // Like other sections in __LINKEDIT, the string table section is special: its
   // offsets are recorded in the LC_SYMTAB load command, instead of in section
   // headers.

diff  --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
index 593e24f6b859..886ca482136b 100644
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -353,7 +353,8 @@ static int sectionOrder(OutputSection *osec) {
       return -1;
   } else if (segname == segment_names::linkEdit) {
     return StringSwitch<int>(osec->name)
-        .Case(section_names::binding, -4)
+        .Case(section_names::binding, -5)
+        .Case(section_names::lazyBinding, -4)
         .Case(section_names::export_, -3)
         .Case(section_names::symbolTable, -2)
         .Case(section_names::stringTable, -1)

diff  --git a/lld/test/MachO/linkedit-contiguity.s b/lld/test/MachO/linkedit-contiguity.s
new file mode 100644
index 000000000000..f815e5555a85
--- /dev/null
+++ b/lld/test/MachO/linkedit-contiguity.s
@@ -0,0 +1,41 @@
+# REQUIRES: x86
+# RUN: mkdir -p %t
+
+## codesign requires that each setion in __LINKEDIT ends where the next one
+## starts. This test enforces that invariant.
+## TODO: Test other __LINKEDIT sections here as support for them gets added.
+## Examples of such sections include the data for LC_CODE_SIGNATURE and
+## LC_DATA_IN_CODE.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %p/Inputs/libhello.s \
+# RUN:   -o %t/libhello.o
+# RUN: lld -flavor darwinnew -dylib -L%S/Inputs/MacOSX.sdk/usr/lib \
+# RUN:   -install_name @executable_path/libhello.dylib %t/libhello.o \
+# RUN:   -o %t/libhello.dylib
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/test.o
+# RUN: lld -flavor darwinnew -o %t/test \
+# RUN:   -L%S/Inputs/MacOSX.sdk/usr/lib -L%t -lhello %t/test.o -lSystem
+
+# RUN: llvm-objdump --macho --all-headers %t/test | FileCheck %s
+
+# CHECK:      cmd LC_DYLD_INFO_ONLY
+# CHECK-NEXT: cmdsize 48
+# CHECK-NEXT: rebase_off 0
+# CHECK-NEXT: rebase_size 0
+# CHECK-NEXT: bind_off [[#BIND_OFF:]]
+# CHECK-NEXT: bind_size [[#BIND_SIZE:]]
+# CHECK-NEXT: weak_bind_off 0
+# CHECK-NEXT: weak_bind_size 0
+# CHECK-NEXT: lazy_bind_off [[#LAZY_OFF: BIND_OFF + BIND_SIZE]]
+# CHECK-NEXT: lazy_bind_size [[#LAZY_SIZE:]]
+# CHECK-NEXT: export_off [[#EXPORT_OFF: LAZY_OFF + LAZY_SIZE]]
+# CHECK-NEXT: export_size [[#]]
+
+.text
+.globl _main
+_main:
+  sub $8, %rsp # 16-byte-align the stack; dyld checks for this
+  callq _print_hello
+  add $8, %rsp
+  ret


        


More information about the llvm-commits mailing list