[lld] bb62ef9 - [lld-macho] Ensure segments are laid out contiguously
Jez Ng via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 20 13:59:09 PDT 2021
Author: Jez Ng
Date: 2021-04-20T16:58:57-04:00
New Revision: bb62ef9943008281a2223c942c71e67b3902a07e
URL: https://github.com/llvm/llvm-project/commit/bb62ef9943008281a2223c942c71e67b3902a07e
DIFF: https://github.com/llvm/llvm-project/commit/bb62ef9943008281a2223c942c71e67b3902a07e.diff
LOG: [lld-macho] Ensure segments are laid out contiguously
codesign/libstuff checks that the `__LLVM` segment is directly
before `__LINKEDIT` by checking that `fileOff + fileSize == next segment
fileOff`. Previously, there would be gaps between the segments due to
the fact that their fileOffs are page-aligned but their fileSizes
aren't. In order to satisfy codesign, we page-align fileOff *before*
calculating fileSize. (I don't think codesign checks for the relative
ordering of other segments, so in theory we could do this just for
`__LLVM`, but ld64 seems to do it for all segments.)
Note that we *don't* round up the fileSize of the `__LINKEDIT` segment.
Since it's the last segment, it doesn't need to worry about contiguity;
in addition, codesign checks that the last (hidden) section in
`__LINKEDIT` covers the last byte of the segment, so if we rounded up
`__LINKEDIT`'s size we would have to do the same for its last section,
which is a bother.
While at it, I also addressed a FIXME in the linkedit-contiguity.s test
to cover more `__LINKEDIT` sections.
Reviewed By: #lld-macho, thakis, alexshap
Differential Revision: https://reviews.llvm.org/D100848
Added:
Modified:
lld/MachO/OutputSegment.h
lld/MachO/Writer.cpp
lld/test/MachO/bitcode-bundle.ll
lld/test/MachO/bss.s
lld/test/MachO/linkedit-contiguity.s
lld/test/MachO/section-headers.s
lld/test/MachO/segments.s
Removed:
################################################################################
diff --git a/lld/MachO/OutputSegment.h b/lld/MachO/OutputSegment.h
index 559aae2af75b9..1db3f0ac79a3b 100644
--- a/lld/MachO/OutputSegment.h
+++ b/lld/MachO/OutputSegment.h
@@ -47,6 +47,7 @@ class OutputSegment {
uint64_t fileOff = 0;
uint64_t fileSize = 0;
+ uint64_t vmSize = 0;
StringRef name;
uint32_t maxProt = 0;
uint32_t initProt = 0;
diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
index 6ba7ed0eaba9d..b2ce72e84fc3f 100644
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -197,17 +197,11 @@ template <class LP> class LCSegment : public LoadCommand {
return;
c->vmaddr = seg->firstSection()->addr;
- c->vmsize =
- seg->lastSection()->addr + seg->lastSection()->getSize() - c->vmaddr;
+ c->vmsize = seg->vmSize;
+ c->filesize = seg->fileSize;
c->nsects = seg->numNonHiddenSections();
for (const OutputSection *osec : seg->getSections()) {
- if (!isZeroFill(osec->flags)) {
- assert(osec->fileOff >= seg->fileOff);
- c->filesize = std::max<uint64_t>(
- c->filesize, osec->fileOff + osec->getFileSize() - seg->fileOff);
- }
-
if (osec->isHidden())
continue;
@@ -682,6 +676,7 @@ static int segmentOrder(OutputSegment *seg) {
.Case(segment_names::text, -3)
.Case(segment_names::dataConst, -2)
.Case(segment_names::data, -1)
+ .Case(segment_names::llvm, std::numeric_limits<int>::max() - 1)
// Make sure __LINKEDIT is the last segment (i.e. all its hidden
// sections must be ordered after other sections).
.Case(segment_names::linkEdit, std::numeric_limits<int>::max())
@@ -855,15 +850,26 @@ template <class LP> void Writer::createOutputSections() {
void Writer::finalizeAddresses() {
TimeTraceScope timeScope("Finalize addresses");
+ uint64_t pageSize = target->getPageSize();
// Ensure that segments (and the sections they contain) are allocated
// addresses in ascending order, which dyld requires.
//
// Note that at this point, __LINKEDIT sections are empty, but we need to
// determine addresses of other segments/sections before generating its
// contents.
- for (OutputSegment *seg : outputSegments)
- if (seg != linkEditSegment)
- assignAddresses(seg);
+ for (OutputSegment *seg : outputSegments) {
+ if (seg == linkEditSegment)
+ continue;
+ assignAddresses(seg);
+ // codesign / libstuff checks for segment ordering by verifying that
+ // `fileOff + fileSize == next segment fileOff`. So we call alignTo() before
+ // (instead of after) computing fileSize to ensure that the segments are
+ // contiguous. We handle addr / vmSize similarly for the same reason.
+ fileOff = alignTo(fileOff, pageSize);
+ addr = alignTo(addr, pageSize);
+ seg->vmSize = addr - seg->firstSection()->addr;
+ seg->fileSize = fileOff - seg->fileOff;
+ }
// FIXME(gkm): create branch-extension thunks here, then adjust addresses
}
@@ -883,12 +889,12 @@ void Writer::finalizeLinkEditSegment() {
// Now that __LINKEDIT is filled out, do a proper calculation of its
// addresses and offsets.
assignAddresses(linkEditSegment);
+ // No need to page-align fileOff / addr here since this is the last segment.
+ linkEditSegment->vmSize = addr - linkEditSegment->firstSection()->addr;
+ linkEditSegment->fileSize = fileOff - linkEditSegment->fileOff;
}
void Writer::assignAddresses(OutputSegment *seg) {
- uint64_t pageSize = target->getPageSize();
- addr = alignTo(addr, pageSize);
- fileOff = alignTo(fileOff, pageSize);
seg->fileOff = fileOff;
for (OutputSection *osec : seg->getSections()) {
@@ -903,7 +909,6 @@ void Writer::assignAddresses(OutputSegment *seg) {
addr += osec->getSize();
fileOff += osec->getFileSize();
}
- seg->fileSize = fileOff - seg->fileOff;
}
void Writer::openFile() {
diff --git a/lld/test/MachO/bitcode-bundle.ll b/lld/test/MachO/bitcode-bundle.ll
index 7daf96fc24c09..5deedbfb7b952 100644
--- a/lld/test/MachO/bitcode-bundle.ll
+++ b/lld/test/MachO/bitcode-bundle.ll
@@ -4,6 +4,7 @@
; RUN: opt -module-summary %t/foo.ll -o %t/foo.o
; RUN: %lld -lSystem -bitcode_bundle %t/test.o %t/foo.o -o %t/test
; RUN: llvm-objdump --macho --section=__LLVM,__bundle %t/test | FileCheck %s
+; RUN: llvm-readobj --macho-segment %t/test | FileCheck %s --check-prefix=SEGMENT
; CHECK: Contents of (__LLVM,__bundle) section
; CHECK-NEXT: For (__LLVM,__bundle) section: xar header
@@ -25,6 +26,32 @@
; CHECK-NEXT: </toc>
; CHECK-NEXT: </xar>
+;; __LLVM must directly precede __LINKEDIT.
+; SEGMENT: Name: __LLVM
+; SEGMENT-NEXT: Size: 152
+; SEGMENT-NEXT: vmaddr: 0x[[#%X,LLVM_ADDR:]]
+; SEGMENT-NEXT: vmsize: 0x[[#%X,LLVM_VMSIZE:]]
+; SEGMENT-NEXT: fileoff: [[#LLVM_OFF:]]
+; SEGMENT-NEXT: filesize: [[#LLVM_FILESIZE:]]
+; SEGMENT-NEXT: maxprot: rw-
+; SEGMENT-NEXT: initprot: rw-
+; SEGMENT-NEXT: nsects: 1
+; SEGMENT-NEXT: flags: 0x0
+; SEGMENT-NEXT: }
+; SEGMENT-NEXT: Segment {
+; SEGMENT-NEXT: Cmd: LC_SEGMENT_64
+; SEGMENT-NEXT: Name: __LINKEDIT
+; SEGMENT-NEXT: Size: 72
+; SEGMENT-NEXT: vmaddr: 0x[[#LLVM_ADDR + LLVM_VMSIZE]]
+; SEGMENT-NEXT: vmsize:
+; SEGMENT-NEXT: fileoff: [[#LLVM_OFF + LLVM_FILESIZE]]
+; SEGMENT-NEXT: filesize:
+; SEGMENT-NEXT: maxprot: r--
+; SEGMENT-NEXT: initprot: r--
+; SEGMENT-NEXT: nsects: 0
+; SEGMENT-NEXT: flags: 0x0
+; SEGMENT-NEXT: }
+
;--- foo.ll
target triple = "x86_64-apple-darwin"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/lld/test/MachO/bss.s b/lld/test/MachO/bss.s
index 480065be550d9..d773e6762b14c 100644
--- a/lld/test/MachO/bss.s
+++ b/lld/test/MachO/bss.s
@@ -45,7 +45,7 @@
# CHECK-NEXT: Name: __bss
# CHECK-NEXT: Segment: __DATA
# CHECK-NEXT: Address:
-# CHECK-NEXT: Size: 0x8
+# CHECK-NEXT: Size: 0x10000
# CHECK-NEXT: Offset: 0
# CHECK-NEXT: Alignment: 0
# CHECK-NEXT: RelocationOffset: 0x0
@@ -92,16 +92,16 @@
# CHECK: Name: __DATA
# CHECK-NEXT: Size:
# CHECK-NEXT: vmaddr:
-# CHECK-NEXT: vmsize: 0x14
+# CHECK-NEXT: vmsize: 0x11000
# CHECK-NEXT: fileoff:
-# CHECK-NEXT: filesize: 8
+# CHECK-NEXT: filesize: 4096
# CHECK: Name: FOO
# CHECK-NEXT: Size:
# CHECK-NEXT: vmaddr:
-# CHECK-NEXT: vmsize: 0x10
+# CHECK-NEXT: vmsize: 0x9000
# CHECK-NEXT: fileoff:
-# CHECK-NEXT: filesize: 8
+# CHECK-NEXT: filesize: 4096
.globl _main
@@ -111,15 +111,15 @@ _main:
retq
.bss
-.zero 4
+.zero 0x8000
.tbss _foo, 4
-.zero 4
+.zero 0x8000
.data
.quad 0x1234
-.zerofill FOO,bss,_zero_foo,0x8
+.zerofill FOO,bss,_zero_foo,0x8000
.section FOO,foo
.quad 123
diff --git a/lld/test/MachO/linkedit-contiguity.s b/lld/test/MachO/linkedit-contiguity.s
index 3fb9053d4828a..63a11dbc7551a 100644
--- a/lld/test/MachO/linkedit-contiguity.s
+++ b/lld/test/MachO/linkedit-contiguity.s
@@ -1,33 +1,36 @@
# REQUIRES: x86
-# RUN: mkdir -p %t
+# RUN: rm -rf %t; split-file %s %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.
+## It also checks that the last section in __LINKEDIT covers the last byte of
+## the segment.
-# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %p/Inputs/libhello.s \
-# RUN: -o %t/libhello.o
-# RUN: %lld -dylib \
-# RUN: -install_name @executable_path/libhello.dylib %t/libhello.o \
-# RUN: -o %t/libhello.dylib
+## FIXME: Include LC_DATA_IN_CODE in this test when we add support for it.
-# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/test.o
-# RUN: %lld -o %t/test \
-# RUN: -L%t -lhello %t/test.o -lSystem
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo.s -o %t/foo.o
+# RUN: %lld %t/foo.o -dylib -o %t/libfoo.dylib
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
+# RUN: %lld -lSystem -pie -adhoc_codesign -o %t/test %t/libfoo.dylib %t/test.o
# RUN: llvm-objdump --macho --all-headers %t/test | FileCheck %s
+# CHECK: segname __LINKEDIT
+# CHECK-NEXT: vmaddr
+# CHECK-NEXT: vmsize
+# CHECK-NEXT: fileoff [[#LINKEDIT_OFF:]]
+# CHECK-NEXT: filesize [[#LINKEDIT_SIZE:]]
+
# 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: rebase_off [[#REBASE_OFF:]]
+# CHECK-NEXT: rebase_size [[#REBASE_SIZE:]]
+# CHECK-NEXT: bind_off [[#BIND_OFF: REBASE_OFF + REBASE_SIZE]]
# 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: weak_bind_off [[#WEAK_OFF: BIND_OFF + BIND_SIZE]]
+# CHECK-NEXT: weak_bind_size [[#WEAK_SIZE:]]
+# CHECK-NEXT: lazy_bind_off [[#LAZY_OFF: WEAK_OFF + WEAK_SIZE]]
# CHECK-NEXT: lazy_bind_size [[#LAZY_SIZE:]]
# CHECK-NEXT: export_off [[#EXPORT_OFF: LAZY_OFF + LAZY_SIZE]]
# CHECK-NEXT: export_size [[#EXPORT_SIZE:]]
@@ -36,10 +39,20 @@
# CHECK-NEXT: cmdsize
# CHECK-NEXT: dataoff [[#FUNCSTARTS_OFF: EXPORT_OFF + EXPORT_SIZE]]
-.text
+# CHECK: cmd LC_CODE_SIGNATURE
+# CHECK-NEXT: cmdsize 16
+# CHECK-NEXT: dataoff [[#SIG_OFF:]]
+# CHECK-NEXT: datasize [[#SIG_SIZE: LINKEDIT_OFF + LINKEDIT_SIZE - SIG_OFF]]
+
+#--- foo.s
+.globl _foo, _weak_foo
+.weak_definition _weak_foo
+_foo:
+_weak_foo:
+
+#--- test.s
.globl _main
_main:
- sub $8, %rsp # 16-byte-align the stack; dyld checks for this
- callq _print_hello
- add $8, %rsp
+ callq _foo
+ callq _weak_foo
ret
diff --git a/lld/test/MachO/section-headers.s b/lld/test/MachO/section-headers.s
index f44f0398c0346..c8a9689d35028 100644
--- a/lld/test/MachO/section-headers.s
+++ b/lld/test/MachO/section-headers.s
@@ -26,8 +26,8 @@
# CHECK: Name: maxlen_16ch_name
# CHECK-NEXT: Segment: __TEXT
# CHECK-NEXT: Address:
-# CHECK-NEXT: Size: [[#%x, LAST_SEC_SIZE:]]
-# CHECK-NEXT: Offset: [[#%u, LAST_SEC_OFF:]]
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Offset:
# CHECK-NEXT: Alignment: 3
# CHECK-NOT: }
# CHECK: Type: Regular (0x0)
@@ -38,7 +38,7 @@
# CHECK-NEXT: vmaddr:
# CHECK-NEXT: vmsize:
# CHECK-NEXT: fileoff: 0
-# CHECK-NEXT: filesize: [[#%u, LAST_SEC_SIZE + LAST_SEC_OFF]]
+# CHECK-NEXT: filesize: 4096
.text
.align 1
diff --git a/lld/test/MachO/segments.s b/lld/test/MachO/segments.s
index e63848baf3a44..b167813d40188 100644
--- a/lld/test/MachO/segments.s
+++ b/lld/test/MachO/segments.s
@@ -13,7 +13,7 @@
# RUN: llvm-readobj --macho-segment %t/arm64_32 > %t/arm64-32.out
# RUN: echo "Total file size" >> %t/arm64-32.out
# RUN: wc -c %t/arm64_32 >> %t/arm64-32.out
-# RUN: FileCheck %s -DSUFFIX= -DPAGEZERO_SIZE=0x1000 -DTEXT_ADDR=0x4000 < %t/arm64-32.out
+# RUN: FileCheck %s -DSUFFIX= -DPAGEZERO_SIZE=0x4000 -DTEXT_ADDR=0x4000 < %t/arm64-32.out
## These two segments must always be present at the start of an executable.
# CHECK-NOT: Segment {
More information about the llvm-commits
mailing list