Index: include/lld/ReaderWriter/MachOLinkingContext.h =================================================================== --- include/lld/ReaderWriter/MachOLinkingContext.h +++ include/lld/ReaderWriter/MachOLinkingContext.h @@ -143,6 +143,9 @@ uint64_t baseAddress() const { return _baseAddress; } void setBaseAddress(uint64_t baseAddress) { _baseAddress = baseAddress; } + uint64_t headerPad() const { return _headerPad; } + void setHeaderPad(uint64_t headerPad) { _headerPad = headerPad; } + bool padHeaderPaths() const { return _padHeaderPaths; } void setPadHeaderPaths(bool padHeaderPaths) { _padHeaderPaths = padHeaderPaths; @@ -399,6 +402,9 @@ uint64_t _pageSize; uint64_t _baseAddress; uint64_t _stackSize; + // Note, _headerPad is 32 as that leaves enough space for code signing to be + // done after linking. + uint64_t _headerPad; uint32_t _compatibilityVersion; uint32_t _currentVersion; StringRef _installName; Index: lib/Driver/DarwinLdDriver.cpp =================================================================== --- lib/Driver/DarwinLdDriver.cpp +++ lib/Driver/DarwinLdDriver.cpp @@ -735,6 +735,17 @@ ctx.setStackSize(stackSizeVal); } + // Handle headerpad + if (llvm::opt::Arg *headerPad = parsedArgs.getLastArg(OPT_headerpad)) { + uint64_t headerPadVal; + if (parseNumberBase16(headerPad->getValue(), headerPadVal)) { + diagnostics << "error: headerpad expects a hex number\n"; + return false; + } + + ctx.setHeaderPad(headerPadVal); + } + // Handle -headerpad_max_install_names if (parsedArgs.getLastArg(OPT_headerpad_max_install_names)) ctx.setPadHeaderPaths(true); Index: lib/Driver/DarwinLdOptions.td =================================================================== --- lib/Driver/DarwinLdOptions.td +++ lib/Driver/DarwinLdOptions.td @@ -195,6 +195,8 @@ HelpText<"Add path to the runpath search path list for image being created">; def headerpad_max_install_names : Flag<["-"], "headerpad_max_install_names">, HelpText<"Pads paths up to MAXPATHLEN for use with install_name_tool">; +def headerpad : Separate<["-"], "headerpad">, + HelpText<"Pads the header by the given (hex) number of bytes (default=32b)">; def t : Flag<["-"], "t">, HelpText<"Print the names of the input files as ld processes them">; Index: lib/ReaderWriter/MachO/MachOLinkingContext.cpp =================================================================== --- lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -143,8 +143,8 @@ : _outputMachOType(MH_EXECUTE), _outputMachOTypeStatic(false), _doNothing(false), _pie(false), _arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0), _pageZeroSize(0), _pageSize(4096), _baseAddress(0), - _stackSize(0), _compatibilityVersion(0), _currentVersion(0), - _flatNamespace(false), _padHeaderPaths(false), + _stackSize(0), _headerPad(32), _compatibilityVersion(0), + _currentVersion(0), _flatNamespace(false), _padHeaderPaths(false), _undefinedMode(UndefinedMode::error), _deadStrippableDylib(false), _printAtoms(false), _testingFileUsage(false), _keepPrivateExterns(false), _demangle(false), _archHandler(nullptr), Index: lib/ReaderWriter/MachO/MachONormalizedFile.h =================================================================== --- lib/ReaderWriter/MachO/MachONormalizedFile.h +++ lib/ReaderWriter/MachO/MachONormalizedFile.h @@ -246,6 +246,7 @@ PackedVersion currentVersion = 0; // dylibs only bool hasUUID = false; bool padHeaderPaths = false; + Hex32 headerPad = 0; std::vector rpaths; Hex64 entryAddress = 0; Hex64 stackSize = 0; Index: lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp =================================================================== --- lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp +++ lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp @@ -272,7 +272,8 @@ _swap(!MachOLinkingContext::isHostEndian(file.arch)), _bigEndianArch(MachOLinkingContext::isBigEndian(file.arch)), _padHeaderPaths(file.padHeaderPaths), - _seg1addr(INT64_MAX) { + _seg1addr(INT64_MAX), + _headerPad(file.headerPad) { _startOfLoadCommands = _is64 ? sizeof(mach_header_64) : sizeof(mach_header); const size_t segCommandBaseSize = (_is64 ? sizeof(segment_command_64) : sizeof(segment_command)); @@ -453,7 +454,6 @@ } void MachOFileLayout::padHeader() { - _headerPad = 0; if (!_padHeaderPaths) return; @@ -461,7 +461,7 @@ // pad the header with enough space for each path to grow to MAXPATHLEN. // FIXME!: We need to get the max path in a reliable way. const unsigned maxpathlen = 1024; - size_t padding = 0; + uint32_t padding = 0; for (const DependentDylib &dep : _file.dependentDylibs) { size_t size = pointerAlign(dep.path.size()+1); if (size < maxpathlen) @@ -475,7 +475,7 @@ padding += maxpathlen - size; } - _headerPad = padding; + _headerPad = std::max(padding, _headerPad); } static bool overlaps(const Segment &s1, const Segment &s2) { Index: lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp =================================================================== --- lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp +++ lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp @@ -1202,6 +1202,7 @@ normFile.pageSize = context.pageSize(); normFile.rpaths = context.rpaths(); normFile.padHeaderPaths = context.padHeaderPaths(); + normFile.headerPad = context.headerPad(); util.addDependentDylibs(atomFile, normFile); util.copySegmentInfo(normFile); util.copySectionInfo(normFile); Index: test/mach-o/headerpad.yaml =================================================================== --- /dev/null +++ test/mach-o/headerpad.yaml @@ -0,0 +1,89 @@ +# RUN: lld -flavor darwin -arch x86_64 -dylib %s \ +# RUN: -install_name /usr/lib/libfoo.dylib %p/Inputs/libSystem.yaml -o %t1.dylib +# RUN: lld -flavor darwin -arch x86_64 -dylib %s \ +# RUN: -install_name /usr/lib/libfoo.dylib %p/Inputs/libSystem.yaml -headerpad 0x1000 -o %t2.dylib +# RUN: llvm-objdump -headers %t1.dylib | FileCheck %s --check-prefix=UNPADDED +# RUN: llvm-objdump -headers %t2.dylib | FileCheck %s --check-prefix=PADDED +# RUN: not lld -flavor darwin -arch x86_64 -headerpad hithere %s >/dev/null 2> %t +# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-NOTHEX + +# UNPADDED: Sections: +# UNPADDED-NEXT: Idx Name Size Address Type +# UNPADDED-NEXT: 0 __text 000001a0 0000000000000e60 TEXT + +# PADDED: Sections: +# PADDED-NEXT: Idx Name Size Address Type +# PADDED-NEXT: 0 __text 000001a0 0000000000001e60 TEXT + +# CHECK-ERROR-NOTHEX: error: headerpad expects a hex number + +--- !mach-o +arch: x86_64 +file-type: MH_OBJECT +flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ] +sections: + - segment: __TEXT + section: __text + type: S_REGULAR + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + address: 0x0000000000000000 + content: [ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 ] +global-symbols: + - name: _foo + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000000 + +... Index: test/mach-o/headerpad_max_install_names.yaml =================================================================== --- test/mach-o/headerpad_max_install_names.yaml +++ test/mach-o/headerpad_max_install_names.yaml @@ -2,8 +2,14 @@ # RUN: -install_name /usr/lib/libfoo.dylib %p/Inputs/libSystem.yaml -o %t1.dylib # RUN: lld -flavor darwin -arch x86_64 -dylib %s \ # RUN: -install_name /usr/lib/libfoo.dylib %p/Inputs/libSystem.yaml -headerpad_max_install_names -o %t2.dylib +# RUN: lld -flavor darwin -arch x86_64 -dylib %s \ +# RUN: -install_name /usr/lib/libfoo.dylib %p/Inputs/libSystem.yaml -headerpad_max_install_names -headerpad 0x100 -o %t3.dylib +# RUN: lld -flavor darwin -arch x86_64 -dylib %s \ +# RUN: -install_name /usr/lib/libfoo.dylib %p/Inputs/libSystem.yaml -headerpad_max_install_names -headerpad 0x2000 -o %t4.dylib # RUN: llvm-objdump -headers %t1.dylib | FileCheck %s --check-prefix=UNPADDED # RUN: llvm-objdump -headers %t2.dylib | FileCheck %s --check-prefix=PADDED +# RUN: llvm-objdump -headers %t3.dylib | FileCheck %s --check-prefix=PADDED +# RUN: llvm-objdump -headers %t4.dylib | FileCheck %s --check-prefix=HEADERPAD # # Note, this test contains a very large text section. The load commands and header are typically around 0x200 # bytes. This large text section then grows from a page alignment down towards the end of the loads commands. @@ -14,10 +20,18 @@ # UNPADDED-NEXT: Idx Name Size Address Type # UNPADDED-NEXT: 0 __text 00000c28 00000000000003d8 TEXT +# This case is for only passing -headerpad_max_install_names or additionally passing a -headerpad +# which is small enough that the calculated -headerpad_max_install_names is still used. # PADDED: Sections: # PADDED-NEXT: Idx Name Size Address Type # PADDED-NEXT: 0 __text 00000c28 00000000000013d8 TEXT +# This case is for passing -headerpad_max_install_names, but also a much large -headerpad and so we +# use the value in -headerpad +# HEADERPAD: Sections: +# HEADERPAD-NEXT: Idx Name Size Address Type +# HEADERPAD-NEXT: 0 __text 00000c28 00000000000023d8 TEXT + --- !mach-o arch: x86_64 file-type: MH_OBJECT