Index: lld/Common/Args.cpp =================================================================== --- lld/Common/Args.cpp +++ lld/Common/Args.cpp @@ -54,6 +54,24 @@ return ::getInteger(args, key, Default, 16); } +uint64_t lld::args::getHexUnsigned(opt::InputArgList &args, unsigned key, + uint64_t Default) { + auto *a = args.getLastArg(key); + if (!a) + return Default; + + uint64_t v; + StringRef s = a->getValue(); + if (s.startswith("0x") || s.startswith("0X")) + s = s.drop_front(2); + if (to_integer(s, v, 16)) + return v; + + StringRef spelling = args.getArgString(a->getIndex()); + error(spelling + ": number expected, but got '" + a->getValue() + "'"); + return 0; +} + std::vector lld::args::getStrings(opt::InputArgList &args, int id) { std::vector v; for (auto *arg : args.filtered(id)) Index: lld/MachO/Arch/ARM.cpp =================================================================== --- lld/MachO/Arch/ARM.cpp +++ lld/MachO/Arch/ARM.cpp @@ -164,6 +164,8 @@ stubSize = 0 /* FIXME */; stubHelperHeaderSize = 0 /* FIXME */; stubHelperEntrySize = 0 /* FIXME */; + + threadCommandFlavor = ARM_THREAD_STATE; } TargetInfo *macho::createARMTargetInfo(uint32_t cpuSubtype) { Index: lld/MachO/Arch/ARM64.cpp =================================================================== --- lld/MachO/Arch/ARM64.cpp +++ lld/MachO/Arch/ARM64.cpp @@ -143,6 +143,8 @@ stubHelperHeaderSize = sizeof(stubHelperHeaderCode); stubHelperEntrySize = sizeof(stubHelperEntryCode); + + threadCommandFlavor = ARM_THREAD_STATE64; } TargetInfo *macho::createARM64TargetInfo() { Index: lld/MachO/Arch/X86_64.cpp =================================================================== --- lld/MachO/Arch/X86_64.cpp +++ lld/MachO/Arch/X86_64.cpp @@ -188,6 +188,8 @@ stubSize = sizeof(stub); stubHelperHeaderSize = sizeof(stubHelperHeader); stubHelperEntrySize = sizeof(stubHelperEntry); + + threadCommandFlavor = x86_THREAD_STATE64; } TargetInfo *macho::createX86_64TargetInfo() { Index: lld/MachO/Config.h =================================================================== --- lld/MachO/Config.h +++ lld/MachO/Config.h @@ -187,6 +187,10 @@ llvm::StringRef osoPrefix; + llvm::Optional pagezeroSize; + bool addLoadVersion = true; + uint64_t imageBase; + llvm::MachO::Architecture arch() const { return platformInfo.target.Arch; } llvm::MachO::PlatformType platform() const { Index: lld/MachO/Driver.cpp =================================================================== --- lld/MachO/Driver.cpp +++ lld/MachO/Driver.cpp @@ -635,6 +635,9 @@ return nullptr; } + if (args.hasArg(OPT_pagezero_size)) + config->pagezeroSize = args::getHex(args, OPT_pagezero_size, 0); + PlatformType platform = parsePlatformVersion(args); config->platformInfo.target = MachO::Target(getArchitectureFromName(archName), platform); @@ -1226,8 +1229,6 @@ config->deadStripDylibs = args.hasArg(OPT_dead_strip_dylibs); config->demangle = args.hasArg(OPT_demangle); config->implicitDylibs = !args.hasArg(OPT_no_implicit_dylibs); - config->emitFunctionStarts = - args.hasFlag(OPT_function_starts, OPT_no_function_starts, true); config->emitBitcodeBundle = args.hasArg(OPT_bitcode_bundle); config->emitDataInCodeInfo = args.hasFlag(OPT_data_in_code_info, OPT_no_data_in_code_info, true); @@ -1276,6 +1277,12 @@ if (const Arg *arg = args.getLastArg(OPT_static, OPT_dynamic)) config->staticLink = (arg->getOption().getID() == OPT_static); + config->addLoadVersion = + args.hasFlag(OPT_version_load_command, OPT_INVALID, !config->staticLink); + config->emitFunctionStarts = args.hasFlag( + OPT_function_starts, OPT_no_function_starts, !config->staticLink); + config->imageBase = args::getHexUnsigned(args, OPT_image_base, /*Default=*/0); + if (const Arg *arg = args.getLastArg(OPT_flat_namespace, OPT_twolevel_namespace)) config->namespaceKind = arg->getOption().getID() == OPT_twolevel_namespace Index: lld/MachO/Options.td =================================================================== --- lld/MachO/Options.td +++ lld/MachO/Options.td @@ -127,7 +127,6 @@ Group; def static : Flag<["-"], "static">, HelpText<"Link statically">, - Flags<[HelpHidden]>, Group; def preload : Flag<["-"], "preload">, HelpText<"Produce an unsegmented binary for embedded systems">, @@ -286,7 +285,6 @@ def image_base : Separate<["-"], "image_base">, MetaVarName<"
">, HelpText<"Preferred hex load address for a dylib or bundle.">, - Flags<[HelpHidden]>, Group; def seg1addr : Separate<["-"], "seg1addr">, MetaVarName<"
">, @@ -444,7 +442,6 @@ def pagezero_size : Separate<["-"], "pagezero_size">, MetaVarName<"">, HelpText<"Size of unreadable segment at address zero is hex (default is 4KB on 32-bit and 4GB on 64-bit)">, - Flags<[HelpHidden]>, Group; def stack_size : Separate<["-"], "stack_size">, MetaVarName<"">, @@ -1329,7 +1326,6 @@ Group; def version_load_command : Flag<["-"], "version_load_command">, HelpText<"This option is undocumented in ld64">, - Flags<[HelpHidden]>, Group; def grp_ignored : OptionGroup<"ignored">, HelpText<"IGNORED">; Index: lld/MachO/SyntheticSections.h =================================================================== --- lld/MachO/SyntheticSections.h +++ lld/MachO/SyntheticSections.h @@ -103,6 +103,7 @@ public: PageZeroSection(); bool isHidden() const override { return true; } + bool isNeeded() const override { return target->pageZeroSize != 0; } uint64_t getSize() const override { return target->pageZeroSize; } uint64_t getFileSize() const override { return 0; } void writeTo(uint8_t *buf) const override {} Index: lld/MachO/Target.h =================================================================== --- lld/MachO/Target.h +++ lld/MachO/Target.h @@ -9,6 +9,7 @@ #ifndef LLD_MACHO_TARGET_H #define LLD_MACHO_TARGET_H +#include "Config.h" #include "MachOStructs.h" #include "Relocations.h" @@ -34,7 +35,7 @@ // Having these values available in TargetInfo allows us to access them // without having to resort to templates. magic = LP::magic; - pageZeroSize = LP::pageZeroSize; + pageZeroSize = config->pagezeroSize.getValueOr(LP::pageZeroSize); headerSize = sizeof(typename LP::mach_header); wordSize = LP::wordSize; } @@ -91,6 +92,8 @@ uint64_t forwardBranchRange = 0; uint64_t backwardBranchRange = 0; + uint32_t threadCommandFlavor = 0; + // We contrive this value as sufficiently far from any valid address that it // will always be out-of-range for any architecture. UINT64_MAX is not a // good choice because it is (a) only 1 away from wrapping to 0, and (b) the Index: lld/MachO/Writer.cpp =================================================================== --- lld/MachO/Writer.cpp +++ lld/MachO/Writer.cpp @@ -46,7 +46,7 @@ class Writer { public: - Writer() : buffer(errorHandler().outputBuffer) {} + Writer() : buffer(errorHandler().outputBuffer), addr(config->imageBase) {} void treatSpecialUndefineds(); void scanRelocations(); @@ -291,6 +291,89 @@ } }; +class LCUnixThread final : public LoadCommand { + uint32_t getFlavorSize() const { + switch (target->cpuType & ~CPU_ARCH_MASK) { + case CPU_TYPE_I386: + switch (target->threadCommandFlavor) { + case x86_THREAD_STATE32: + return sizeof(x86_thread_state32_t); + case x86_THREAD_STATE64: + return sizeof(x86_thread_state64_t); + } + break; + case CPU_TYPE_ARM: + switch (target->threadCommandFlavor) { + case ARM_THREAD_STATE: + return sizeof(arm_thread_state32_t); + case ARM_THREAD_STATE64: + return sizeof(arm_thread_state64_t); + } + break; + } + + fatal("Unknown flavor " + + llvm::Twine::utohexstr(target->threadCommandFlavor)); + return 0; + } + + uint32_t getSize() const override { + return sizeof(thread_command) + sizeof(x86_state_hdr_t) + getFlavorSize(); + } + + template + return_type *get_thread_state(uint8_t *buf) const { + constexpr auto offset = sizeof(thread_command) + sizeof(x86_state_hdr_t); + auto *state = reinterpret_cast(buf + offset); + return state; + }; + + void writeTo(uint8_t *buf) const override { + auto *c = reinterpret_cast(buf); + c->cmd = LC_UNIXTHREAD; + c->cmdsize = getSize(); + + auto *hdr = + reinterpret_cast(buf + sizeof(thread_command)); + hdr->flavor = target->threadCommandFlavor; + + // Yes, this is what the macOS SDK does. + hdr->count = getFlavorSize() / sizeof(uint32_t); + memset(get_thread_state(buf), 0, getFlavorSize()); + + switch (target->cpuType & ~CPU_ARCH_MASK) { + case CPU_TYPE_I386: + switch (target->threadCommandFlavor) { + case x86_THREAD_STATE32: { + auto *state = get_thread_state(buf); + state->eip = config->entry->getVA(); + break; + } + case x86_THREAD_STATE64: { + auto *state = get_thread_state(buf); + state->rip = config->entry->getVA(); + break; + } + } + break; + case CPU_TYPE_ARM: + switch (target->threadCommandFlavor) { + case ARM_THREAD_STATE: { + auto *state = get_thread_state(buf); + state->pc = config->entry->getVA(); + break; + } + case ARM_THREAD_STATE64: { + auto *state = get_thread_state(buf); + state->pc = config->entry->getVA(); + break; + } + } + break; + } + } +}; + class LCSymtab final : public LoadCommand { public: LCSymtab(SymtabSection *symtabSection, StringTableSection *stringTableSection) @@ -744,7 +827,8 @@ switch (config->outputType) { case MH_EXECUTE: - in.header->addLoadCommand(make()); + if (!config->staticLink) + in.header->addLoadCommand(make()); break; case MH_DYLIB: in.header->addLoadCommand(make(LC_ID_DYLIB, config->installName, @@ -760,14 +844,20 @@ uuidCommand = make(); in.header->addLoadCommand(uuidCommand); - if (useLCBuildVersion(config->platformInfo)) - in.header->addLoadCommand(make(config->platformInfo)); - else - in.header->addLoadCommand(make(config->platformInfo)); + if (config->addLoadVersion) { + if (useLCBuildVersion(config->platformInfo)) + in.header->addLoadCommand(make(config->platformInfo)); + else + in.header->addLoadCommand(make(config->platformInfo)); + } // This is down here to match ld64's load command order. - if (config->outputType == MH_EXECUTE) - in.header->addLoadCommand(make()); + if (config->outputType == MH_EXECUTE) { + if (!config->staticLink) + in.header->addLoadCommand(make()); + else + in.header->addLoadCommand(make()); + } int64_t dylibOrdinal = 1; DenseMap ordinalForInstallName; @@ -837,7 +927,7 @@ if (functionStartsSection) in.header->addLoadCommand(make(functionStartsSection)); - if (dataInCodeSection) + if (dataInCodeSection && !config->staticLink) in.header->addLoadCommand(make(dataInCodeSection)); if (codeSignatureSection) in.header->addLoadCommand(make(codeSignatureSection)); Index: lld/include/lld/Common/Args.h =================================================================== --- lld/include/lld/Common/Args.h +++ lld/include/lld/Common/Args.h @@ -30,6 +30,9 @@ int64_t getHex(llvm::opt::InputArgList &args, unsigned key, int64_t Default); +uint64_t getHexUnsigned(llvm::opt::InputArgList &args, unsigned key, + uint64_t Default); + std::vector getStrings(llvm::opt::InputArgList &args, int id); uint64_t getZOptionValue(llvm::opt::InputArgList &args, int id, StringRef key,