[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