diff --git a/lld/MachO/OutputSegment.h b/lld/MachO/OutputSegment.h --- a/lld/MachO/OutputSegment.h +++ b/lld/MachO/OutputSegment.h @@ -47,6 +47,7 @@ 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 --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -197,17 +197,11 @@ 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( - c->filesize, osec->fileOff + osec->getFileSize() - seg->fileOff); - } - if (osec->isHidden()) continue; @@ -682,6 +676,7 @@ .Case(segment_names::text, -3) .Case(segment_names::dataConst, -2) .Case(segment_names::data, -1) + .Case(segment_names::llvm, std::numeric_limits::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::max()) @@ -855,15 +850,26 @@ 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 @@ // 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 @@ 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 --- 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: ; CHECK-NEXT: +;; __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 --- 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 @@ 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 --- 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 --- 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 --- 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 {