From 2eac7e159c3f2afaae253290d5c80252d60fc4a7 Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Mon, 20 Nov 2017 17:44:33 +0100 Subject: [PATCH] Programming/ld64 - build-block added --- .../ld64/274/patches.Darwin/PR-29117886.patch | 1 + .../ld64/274/patches.Darwin/PR-29679726.patch | 1 + .../ld64/274/patches.Darwin/PR-29723276.patch | 1 + .../ld64/274/patches.Darwin/PR-29723629.patch | 1 + .../ld64/274/patches.Darwin/PR-49393.patch | 1 + .../ld64-133-no-CrashReporterClient.h.patch | 1 + .../ld64-134-missing-include.patch | 1 + .../ld64-136-i386-badAddress.patch | 1 + .../274/patches.Darwin/ld64-ppc-9610466.patch | 1 + .../274/patches.Darwin/ld64-version.patch | 1 + Programming/ld64/274/variants.Darwin | 1 + Programming/ld64/build | 73 ++ Programming/ld64/files/Disassembler.h | 239 ++++ Programming/ld64/files/Makefile-274 | 106 ++ Programming/ld64/files/PR-29117886.patch | 32 + Programming/ld64/files/PR-29679726.patch | 1120 +++++++++++++++++ Programming/ld64/files/PR-29723276.patch | 12 + Programming/ld64/files/PR-29723629.patch | 37 + Programming/ld64/files/PR-49393.patch | 11 + .../ld64-133-no-CrashReporterClient.h.patch | 21 + .../ld64/files/ld64-134-missing-include.patch | 21 + .../ld64/files/ld64-136-i386-badAddress.patch | 11 + Programming/ld64/files/ld64-ppc-9610466.patch | 17 + Programming/ld64/files/ld64-version.patch | 19 + Programming/ld64/files/lto.h | 797 ++++++++++++ 25 files changed, 2527 insertions(+) create mode 120000 Programming/ld64/274/patches.Darwin/PR-29117886.patch create mode 120000 Programming/ld64/274/patches.Darwin/PR-29679726.patch create mode 120000 Programming/ld64/274/patches.Darwin/PR-29723276.patch create mode 120000 Programming/ld64/274/patches.Darwin/PR-29723629.patch create mode 120000 Programming/ld64/274/patches.Darwin/PR-49393.patch create mode 120000 Programming/ld64/274/patches.Darwin/ld64-133-no-CrashReporterClient.h.patch create mode 120000 Programming/ld64/274/patches.Darwin/ld64-134-missing-include.patch create mode 120000 Programming/ld64/274/patches.Darwin/ld64-136-i386-badAddress.patch create mode 120000 Programming/ld64/274/patches.Darwin/ld64-ppc-9610466.patch create mode 120000 Programming/ld64/274/patches.Darwin/ld64-version.patch create mode 100644 Programming/ld64/274/variants.Darwin create mode 100755 Programming/ld64/build create mode 100644 Programming/ld64/files/Disassembler.h create mode 100644 Programming/ld64/files/Makefile-274 create mode 100644 Programming/ld64/files/PR-29117886.patch create mode 100644 Programming/ld64/files/PR-29679726.patch create mode 100644 Programming/ld64/files/PR-29723276.patch create mode 100644 Programming/ld64/files/PR-29723629.patch create mode 100644 Programming/ld64/files/PR-49393.patch create mode 100644 Programming/ld64/files/ld64-133-no-CrashReporterClient.h.patch create mode 100644 Programming/ld64/files/ld64-134-missing-include.patch create mode 100644 Programming/ld64/files/ld64-136-i386-badAddress.patch create mode 100644 Programming/ld64/files/ld64-ppc-9610466.patch create mode 100644 Programming/ld64/files/ld64-version.patch create mode 100644 Programming/ld64/files/lto.h diff --git a/Programming/ld64/274/patches.Darwin/PR-29117886.patch b/Programming/ld64/274/patches.Darwin/PR-29117886.patch new file mode 120000 index 0000000..ccce0e8 --- /dev/null +++ b/Programming/ld64/274/patches.Darwin/PR-29117886.patch @@ -0,0 +1 @@ +../../files/PR-29117886.patch \ No newline at end of file diff --git a/Programming/ld64/274/patches.Darwin/PR-29679726.patch b/Programming/ld64/274/patches.Darwin/PR-29679726.patch new file mode 120000 index 0000000..f2ffa66 --- /dev/null +++ b/Programming/ld64/274/patches.Darwin/PR-29679726.patch @@ -0,0 +1 @@ +../../files/PR-29679726.patch \ No newline at end of file diff --git a/Programming/ld64/274/patches.Darwin/PR-29723276.patch b/Programming/ld64/274/patches.Darwin/PR-29723276.patch new file mode 120000 index 0000000..6c370da --- /dev/null +++ b/Programming/ld64/274/patches.Darwin/PR-29723276.patch @@ -0,0 +1 @@ +../../files/PR-29723276.patch \ No newline at end of file diff --git a/Programming/ld64/274/patches.Darwin/PR-29723629.patch b/Programming/ld64/274/patches.Darwin/PR-29723629.patch new file mode 120000 index 0000000..e0f3663 --- /dev/null +++ b/Programming/ld64/274/patches.Darwin/PR-29723629.patch @@ -0,0 +1 @@ +../../files/PR-29723629.patch \ No newline at end of file diff --git a/Programming/ld64/274/patches.Darwin/PR-49393.patch b/Programming/ld64/274/patches.Darwin/PR-49393.patch new file mode 120000 index 0000000..3929640 --- /dev/null +++ b/Programming/ld64/274/patches.Darwin/PR-49393.patch @@ -0,0 +1 @@ +../../files/PR-49393.patch \ No newline at end of file diff --git a/Programming/ld64/274/patches.Darwin/ld64-133-no-CrashReporterClient.h.patch b/Programming/ld64/274/patches.Darwin/ld64-133-no-CrashReporterClient.h.patch new file mode 120000 index 0000000..49a1306 --- /dev/null +++ b/Programming/ld64/274/patches.Darwin/ld64-133-no-CrashReporterClient.h.patch @@ -0,0 +1 @@ +../../files/ld64-133-no-CrashReporterClient.h.patch \ No newline at end of file diff --git a/Programming/ld64/274/patches.Darwin/ld64-134-missing-include.patch b/Programming/ld64/274/patches.Darwin/ld64-134-missing-include.patch new file mode 120000 index 0000000..33ed89f --- /dev/null +++ b/Programming/ld64/274/patches.Darwin/ld64-134-missing-include.patch @@ -0,0 +1 @@ +../../files/ld64-134-missing-include.patch \ No newline at end of file diff --git a/Programming/ld64/274/patches.Darwin/ld64-136-i386-badAddress.patch b/Programming/ld64/274/patches.Darwin/ld64-136-i386-badAddress.patch new file mode 120000 index 0000000..8e203e7 --- /dev/null +++ b/Programming/ld64/274/patches.Darwin/ld64-136-i386-badAddress.patch @@ -0,0 +1 @@ +../../files/ld64-136-i386-badAddress.patch \ No newline at end of file diff --git a/Programming/ld64/274/patches.Darwin/ld64-ppc-9610466.patch b/Programming/ld64/274/patches.Darwin/ld64-ppc-9610466.patch new file mode 120000 index 0000000..a9b0155 --- /dev/null +++ b/Programming/ld64/274/patches.Darwin/ld64-ppc-9610466.patch @@ -0,0 +1 @@ +../../files/ld64-ppc-9610466.patch \ No newline at end of file diff --git a/Programming/ld64/274/patches.Darwin/ld64-version.patch b/Programming/ld64/274/patches.Darwin/ld64-version.patch new file mode 120000 index 0000000..53c4978 --- /dev/null +++ b/Programming/ld64/274/patches.Darwin/ld64-version.patch @@ -0,0 +1 @@ +../../files/ld64-version.patch \ No newline at end of file diff --git a/Programming/ld64/274/variants.Darwin b/Programming/ld64/274/variants.Darwin new file mode 100644 index 0000000..e06e45c --- /dev/null +++ b/Programming/ld64/274/variants.Darwin @@ -0,0 +1 @@ +ld64/274.2 unstable diff --git a/Programming/ld64/build b/Programming/ld64/build new file mode 100755 index 0000000..7470141 --- /dev/null +++ b/Programming/ld64/build @@ -0,0 +1,73 @@ +#!/usr/bin/env modbuild + +CCTOOLS_VERSION='895' +DYLD_VERSION='421.2' + +SOURCE_URL="http://opensource.apple.com/tarballs/$P/$P-$V.tar.gz" +CCTOOLS_SOURCE_URL="https://opensource.apple.com/tarballs/cctools/cctools-${CCTOOLS_VERSION}.tar.gz" +DYLD_SOURCE_URL="http://opensource.apple.com/tarballs/dyld/dyld-${DYLD_VERSION}.tar.gz" + + +pbuild::patch_sources () { + find_patchdir() { + local -a patchdirs=() + patchdirs+=( "${BUILD_BLOCK_DIR}/${V}/patches.${OS}" ) + patchdirs+=( "${BUILD_BLOCK_DIR}/${V}/patches" ) + patchdirs+=( "${BUILD_BLOCK_DIR}/${V%.*}/patches.${OS}" ) + patchdirs+=( "${BUILD_BLOCK_DIR}/${V%.*}/patches" ) + patchdirs+=( "${BUILD_BLOCK_DIR}/${V%.*.*}/patches.${OS}" ) + patchdirs+=( "${BUILD_BLOCK_DIR}/${V%.*.*}/patches" ) + + for patchdir in "${patchdirs[@]}"; do + [[ -e "${patchdir}" ]] && return 0; + done + return 1 + } + + find_patchdir || return 0 + local patch_file='' + for patch_file in "${patchdir}"/*; do + patch -p0 < "${patch_file}" + done +} + +pbuild::post_prep() { + local -r DYLD_SRC_DIR="${PMODULES_TMPDIR}/dyld-${DYLD_VERSION}/src" + local -r CCTOOLS_SRC_DIR="${PMODULES_TMPDIR}/cctools-${CCTOOLS_VERSION}/src" + + local source_file='' + pbuild::get_source source_file "${DYLD_SOURCE_URL}" "${PMODULES_DISTFILESDIR}" || + std::die 4 "dyld/${DYLD_VERSION}: sourcecode not found." + pbuild::unpack "${source_file}" "${DYLD_SRC_DIR}" + + pbuild::get_source source_file "${CCTOOLS_SOURCE_URL}" "${PMODULES_DISTFILESDIR}" || + std::die 4 "cctools/${CCTOOLS_VERSION}: sourcecode not found." + pbuild::unpack "${source_file}" "${CCTOOLS_SRC_DIR}" + + cd "${MODULE_SRCDIR}" + mkdir -p "include/mach-o" + rsync --archive "../../cctools-${CCTOOLS_VERSION}/src/include/mach-o/" "include/mach-o/" + rsync --archive "../../dyld-${DYLD_VERSION}/src/include/mach-o/" "include/mach-o/" + mkdir -p "include/llvm-c" + cp -v "${BUILD_BLOCK_DIR}/files/Disassembler.h" "include/llvm-c/" + cp -v "${BUILD_BLOCK_DIR}/files/lto.h" "include/llvm-c/" +} + +pbuild::configure() { + cp -v "${BUILD_BLOCK_DIR}/files/Makefile-${V_MAJOR}" "${MODULE_SRCDIR}/Makefile" +} + +pbuild::build() { + cd "${MODULE_SRCDIR}" + which $CC + make OTHER_CXXFLAGS="-std=c++11 -I$PWD/include" OTHER_LDFLAGS="-L/Applications/Xcode.app/Contents/Frameworks -lLTO" +} + +# use system gcc to compile +declare -rx CC=/usr/bin/gcc +declare -rx CXX=/usr/bin/g++ + +pbuild::add_to_group 'Programming' +pbuild::set_docfiles 'COPYING' 'COPYING.LIB' 'COPYING.RUNTIME' 'COPYING3' 'COPYING3.LIB' 'NEWS' 'README' +pbuild::make_all + diff --git a/Programming/ld64/files/Disassembler.h b/Programming/ld64/files/Disassembler.h new file mode 100644 index 0000000..5fa79fa --- /dev/null +++ b/Programming/ld64/files/Disassembler.h @@ -0,0 +1,239 @@ +/*===-- llvm-c/Disassembler.h - Disassembler Public C Interface ---*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides a public interface to a disassembler library. *| +|* LLVM provides an implementation of this interface. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_DISASSEMBLER_H +#define LLVM_C_DISASSEMBLER_H + +#include + +/** + * @defgroup LLVMCDisassembler Disassembler + * @ingroup LLVMC + * + * @{ + */ + +/** + * An opaque reference to a disassembler context. + */ +typedef void *LLVMDisasmContextRef; + +/** + * The type for the operand information call back function. This is called to + * get the symbolic information for an operand of an instruction. Typically + * this is from the relocation information, symbol table, etc. That block of + * information is saved when the disassembler context is created and passed to + * the call back in the DisInfo parameter. The instruction containing operand + * is at the PC parameter. For some instruction sets, there can be more than + * one operand with symbolic information. To determine the symbolic operand + * information for each operand, the bytes for the specific operand in the + * instruction are specified by the Offset parameter and its byte widith is the + * size parameter. For instructions sets with fixed widths and one symbolic + * operand per instruction, the Offset parameter will be zero and Size parameter + * will be the instruction width. The information is returned in TagBuf and is + * Triple specific with its specific information defined by the value of + * TagType for that Triple. If symbolic information is returned the function + * returns 1, otherwise it returns 0. + */ +typedef int (*LLVMOpInfoCallback)(void *DisInfo, uint64_t Pc, + uint64_t Offset, uint64_t Size, + int TagType, void *TagBuf); + +/** + * The initial support in LLVM MC for the most general form of a relocatable + * expression is "AddSymbol - SubtractSymbol + Offset". For some Darwin targets + * this full form is encoded in the relocation information so that AddSymbol and + * SubtractSymbol can be link edited independent of each other. Many other + * platforms only allow a relocatable expression of the form AddSymbol + Offset + * to be encoded. + * + * The LLVMOpInfoCallback() for the TagType value of 1 uses the struct + * LLVMOpInfo1. The value of the relocatable expression for the operand, + * including any PC adjustment, is passed in to the call back in the Value + * field. The symbolic information about the operand is returned using all + * the fields of the structure with the Offset of the relocatable expression + * returned in the Value field. It is possible that some symbols in the + * relocatable expression were assembly temporary symbols, for example + * "Ldata - LpicBase + constant", and only the Values of the symbols without + * symbol names are present in the relocation information. The VariantKind + * type is one of the Target specific #defines below and is used to print + * operands like "_foo@GOT", ":lower16:_foo", etc. + */ +struct LLVMOpInfoSymbol1 { + uint64_t Present; /* 1 if this symbol is present */ + const char *Name; /* symbol name if not NULL */ + uint64_t Value; /* symbol value if name is NULL */ +}; + +struct LLVMOpInfo1 { + struct LLVMOpInfoSymbol1 AddSymbol; + struct LLVMOpInfoSymbol1 SubtractSymbol; + uint64_t Value; + uint64_t VariantKind; +}; + +/** + * The operand VariantKinds for symbolic disassembly. + */ +#define LLVMDisassembler_VariantKind_None 0 /* all targets */ + +/** + * The ARM target VariantKinds. + */ +#define LLVMDisassembler_VariantKind_ARM_HI16 1 /* :upper16: */ +#define LLVMDisassembler_VariantKind_ARM_LO16 2 /* :lower16: */ + +/** + * The ARM64 target VariantKinds. + */ +#define LLVMDisassembler_VariantKind_ARM64_PAGE 1 /* @page */ +#define LLVMDisassembler_VariantKind_ARM64_PAGEOFF 2 /* @pageoff */ +#define LLVMDisassembler_VariantKind_ARM64_GOTPAGE 3 /* @gotpage */ +#define LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF 4 /* @gotpageoff */ +#define LLVMDisassembler_VariantKind_ARM64_TLVP 5 /* @tvlppage */ +#define LLVMDisassembler_VariantKind_ARM64_TLVOFF 6 /* @tvlppageoff */ + +/** + * The type for the symbol lookup function. This may be called by the + * disassembler for things like adding a comment for a PC plus a constant + * offset load instruction to use a symbol name instead of a load address value. + * It is passed the block information is saved when the disassembler context is + * created and the ReferenceValue to look up as a symbol. If no symbol is found + * for the ReferenceValue NULL is returned. The ReferenceType of the + * instruction is passed indirectly as is the PC of the instruction in + * ReferencePC. If the output reference can be determined its type is returned + * indirectly in ReferenceType along with ReferenceName if any, or that is set + * to NULL. + */ +typedef const char *(*LLVMSymbolLookupCallback)(void *DisInfo, + uint64_t ReferenceValue, + uint64_t *ReferenceType, + uint64_t ReferencePC, + const char **ReferenceName); +/** + * The reference types on input and output. + */ +/* No input reference type or no output reference type. */ +#define LLVMDisassembler_ReferenceType_InOut_None 0 + +/* The input reference is from a branch instruction. */ +#define LLVMDisassembler_ReferenceType_In_Branch 1 +/* The input reference is from a PC relative load instruction. */ +#define LLVMDisassembler_ReferenceType_In_PCrel_Load 2 + +/* The input reference is from an ARM64::ADRP instruction. */ +#define LLVMDisassembler_ReferenceType_In_ARM64_ADRP 0x100000001 +/* The input reference is from an ARM64::ADDXri instruction. */ +#define LLVMDisassembler_ReferenceType_In_ARM64_ADDXri 0x100000002 +/* The input reference is from an ARM64::LDRXui instruction. */ +#define LLVMDisassembler_ReferenceType_In_ARM64_LDRXui 0x100000003 +/* The input reference is from an ARM64::LDRXl instruction. */ +#define LLVMDisassembler_ReferenceType_In_ARM64_LDRXl 0x100000004 +/* The input reference is from an ARM64::ADR instruction. */ +#define LLVMDisassembler_ReferenceType_In_ARM64_ADR 0x100000005 + +/* The output reference is to as symbol stub. */ +#define LLVMDisassembler_ReferenceType_Out_SymbolStub 1 +/* The output reference is to a symbol address in a literal pool. */ +#define LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr 2 +/* The output reference is to a cstring address in a literal pool. */ +#define LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr 3 + +/* The output reference is to a Objective-C CoreFoundation string. */ +#define LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref 4 +/* The output reference is to a Objective-C message. */ +#define LLVMDisassembler_ReferenceType_Out_Objc_Message 5 +/* The output reference is to a Objective-C message ref. */ +#define LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref 6 +/* The output reference is to a Objective-C selector ref. */ +#define LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref 7 +/* The output reference is to a Objective-C class ref. */ +#define LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref 8 + +/* The output reference is to a C++ symbol name. */ +#define LLVMDisassembler_ReferenceType_DeMangled_Name 9 + +#ifdef __cplusplus +extern "C" { +#endif /* !defined(__cplusplus) */ + +/** + * Create a disassembler for the TripleName. Symbolic disassembly is supported + * by passing a block of information in the DisInfo parameter and specifying the + * TagType and callback functions as described above. These can all be passed + * as NULL. If successful, this returns a disassembler context. If not, it + * returns NULL. This function is equivalent to calling LLVMCreateDisasmCPU() + * with an empty CPU name. + */ +LLVMDisasmContextRef LLVMCreateDisasm(const char *TripleName, void *DisInfo, + int TagType, LLVMOpInfoCallback GetOpInfo, + LLVMSymbolLookupCallback SymbolLookUp); + +/** + * Create a disassembler for the TripleName and a specific CPU. Symbolic + * disassembly is supported by passing a block of information in the DisInfo + * parameter and specifying the TagType and callback functions as described + * above. These can all be passed * as NULL. If successful, this returns a + * disassembler context. If not, it returns NULL. + */ +LLVMDisasmContextRef LLVMCreateDisasmCPU(const char *Triple, const char *CPU, + void *DisInfo, int TagType, + LLVMOpInfoCallback GetOpInfo, + LLVMSymbolLookupCallback SymbolLookUp); + +/** + * Set the disassembler's options. Returns 1 if it can set the Options and 0 + * otherwise. + */ +int LLVMSetDisasmOptions(LLVMDisasmContextRef DC, uint64_t Options); + +/* The option to produce marked up assembly. */ +#define LLVMDisassembler_Option_UseMarkup 1 +/* The option to print immediates as hex. */ +#define LLVMDisassembler_Option_PrintImmHex 2 +/* The option use the other assembler printer variant */ +#define LLVMDisassembler_Option_AsmPrinterVariant 4 +/* The option to set comment on instructions */ +#define LLVMDisassembler_Option_SetInstrComments 8 + /* The option to print latency information alongside instructions */ +#define LLVMDisassembler_Option_PrintLatency 16 + +/** + * Dispose of a disassembler context. + */ +void LLVMDisasmDispose(LLVMDisasmContextRef DC); + +/** + * Disassemble a single instruction using the disassembler context specified in + * the parameter DC. The bytes of the instruction are specified in the + * parameter Bytes, and contains at least BytesSize number of bytes. The + * instruction is at the address specified by the PC parameter. If a valid + * instruction can be disassembled, its string is returned indirectly in + * OutString whose size is specified in the parameter OutStringSize. This + * function returns the number of bytes in the instruction or zero if there was + * no valid instruction. + */ +size_t LLVMDisasmInstruction(LLVMDisasmContextRef DC, uint8_t *Bytes, + uint64_t BytesSize, uint64_t Pc, + char *OutString, size_t OutStringSize); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* !defined(__cplusplus) */ + +#endif /* !defined(LLVM_C_DISASSEMBLER_H) */ diff --git a/Programming/ld64/files/Makefile-274 b/Programming/ld64/files/Makefile-274 new file mode 100644 index 0000000..b1a2e02 --- /dev/null +++ b/Programming/ld64/files/Makefile-274 @@ -0,0 +1,106 @@ +ifdef LLVM_CONFIG +LLVM_CPPFLAGS := -I$(shell $(LLVM_CONFIG) --includedir) -DLTO_SUPPORT +LLVM_LDFLAGS := -L$(shell $(LLVM_CONFIG) --libdir) -Wl,-rpath,$(shell $(LLVM_CONFIG) --libdir) -lLTO +endif + +CPPFLAGS = $(LLVM_CPPFLAGS) -Isrc/abstraction -Isrc/ld -Isrc/ld/parsers $(OTHER_CPPFLAGS) +CFLAGS = -Os $(OTHER_CFLAGS) +CXXFLAGS = -Os $(OTHER_CXXFLAGS) +LDFLAGS = $(OTHER_LDFLAGS) + +ifndef RANLIB +RANLIB = ranlib +endif +ifndef AR +AR = ar +endif +ifndef PREFIX +PREFIX = /usr +endif + +# libprunetrie.a +all : src/ld/configure.h ObjectDump dyldinfo ld machocheck rebase unwinddump + +src/ld/Snapshot.o : src/ld/compile_stubs.h +src/ld/compile_stubs.h : compile_stubs + echo "static const char *compile_stubs = " > $@ + cat $^ | sed s/\"/\\\\\"/g | sed s/^/\"/ | sed s/$$/\\\\n\"/ >> $@ + echo ";" >> $@ + +src/ld/configure.h : src/create_configure + DERIVED_SOURCES_DIR=src/ld DERIVED_FILE_DIR=src/ld $^ > $@ + +ObjectDump : src/ld/debugline.o +ObjectDump : src/ld/parsers/macho_relocatable_file.o +ObjectDump : src/ld/parsers/lto_file.o +ObjectDump : src/other/ObjectDump.o + $(CXX) $(LLVM_LDFLAGS) $(LDFLAGS) $^ -o $@ + +dyldinfo : src/other/dyldinfo.o + $(CXX) $(LDFLAGS) -Wl,-exported_symbol,__mh_execute_header $^ -o $@ + +ld : src/ld/debugline.o +ld : src/ld/ld.o +ld : src/ld/InputFiles.o +ld : src/ld/Options.o +ld : src/ld/OutputFile.o +ld : src/ld/Resolver.o +ld : src/ld/Snapshot.o +ld : src/ld/SymbolTable.o +ld : src/ld/parsers/archive_file.o +ld : src/ld/parsers/lto_file.o +ld : src/ld/parsers/macho_dylib_file.o +ld : src/ld/parsers/macho_relocatable_file.o +ld : src/ld/parsers/opaque_section_file.o +ld : src/ld/parsers/textstub_dylib_file.o +ld : src/ld/passes/bitcode_bundle.o +ld : src/ld/passes/branch_island.o +ld : src/ld/passes/branch_shim.o +ld : src/ld/passes/code_dedup.o +ld : src/ld/passes/compact_unwind.o +ld : src/ld/passes/dtrace_dof.o +ld : src/ld/passes/dylibs.o +ld : src/ld/passes/got.o +ld : src/ld/passes/huge.o +ld : src/ld/passes/objc.o +ld : src/ld/passes/order.o +ld : src/ld/passes/tlvp.o +ld : src/ld/passes/stubs/stubs.o + $(CXX) $(LLVM_LDFLAGS) $(LDFLAGS) $(OTHER_LDFLAGS_LD64) -Wl,-exported_symbol,__mh_execute_header $^ -lxar -o $@ + +machocheck : src/other/machochecker.o + $(CXX) $(LDFLAGS) $^ -o $@ + +rebase : src/other/rebase.o + $(CXX) $(LDFLAGS) -Wl,-exported_symbol,__mh_execute_header $^ -o $@ + +unwinddump : src/other/unwinddump.o + $(CXX) $(LDFLAGS) -Wl,-exported_symbol,__mh_execute_header $^ -o $@ + +src/other/PruneTrie.o : src/ld/configure.h +libprunetrie.a : src/other/PruneTrie.o + $(AR) cru $@ $^ + $(RANLIB) $@ + +install : all + install -d -m 755 $(DESTDIR)$(PREFIX)/bin + install -d -m 755 $(DESTDIR)$(PREFIX)/lib + install -d -m 755 $(DESTDIR)$(PREFIX)/include/mach-o + install -d -m 755 $(DESTDIR)$(PREFIX)/share/man/man1 + + install -m 755 ObjectDump $(DESTDIR)$(PREFIX)/bin + install -m 755 dyldinfo $(DESTDIR)$(PREFIX)/bin + install -m 755 ld $(DESTDIR)$(PREFIX)/bin + install -m 755 machocheck $(DESTDIR)$(PREFIX)/bin + install -m 755 rebase $(DESTDIR)$(PREFIX)/bin + install -m 755 unwinddump $(DESTDIR)$(PREFIX)/bin + + #install -m 644 src/other/prune_trie.h $(DESTDIR)$(PREFIX)/include/mach-o + #install -m 644 libprunetrie.a $(DESTDIR)$(PREFIX)/lib + + install -m 644 doc/man/man1/dyldinfo.1 $(DESTDIR)$(PREFIX)/share/man/man1 + install -m 644 doc/man/man1/ld.1 $(DESTDIR)$(PREFIX)/share/man/man1 + install -m 644 doc/man/man1/ld64.1 $(DESTDIR)$(PREFIX)/share/man/man1 + install -m 644 doc/man/man1/rebase.1 $(DESTDIR)$(PREFIX)/share/man/man1 + install -m 644 doc/man/man1/unwinddump.1 $(DESTDIR)$(PREFIX)/share/man/man1 + diff --git a/Programming/ld64/files/PR-29117886.patch b/Programming/ld64/files/PR-29117886.patch new file mode 100644 index 0000000..686aae9 --- /dev/null +++ b/Programming/ld64/files/PR-29117886.patch @@ -0,0 +1,32 @@ +--- src/ld/OutputFile.cpp ++++ src/ld/OutputFile.cpp +@@ -4461,14 +4461,18 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio + assert(minusTarget->definition() != ld::Atom::definitionProxy); + assert(target != NULL); + assert(target->definition() != ld::Atom::definitionProxy); +- // make sure target is not global and weak +- if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) +- && (atom->section().type() != ld::Section::typeCFI) +- && (atom->section().type() != ld::Section::typeDtraceDOF) +- && (atom->section().type() != ld::Section::typeUnwindInfo) +- && (minusTarget != target) ) { +- // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols +- throwf("bad codegen, pointer diff in %s to global weak symbol %s", atom->name(), target->name()); ++ // check if target of pointer-diff is global and weak ++ if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular) ) { ++ if ( (atom->section().type() == ld::Section::typeCFI) ++ || (atom->section().type() == ld::Section::typeDtraceDOF) ++ || (atom->section().type() == ld::Section::typeUnwindInfo) ) { ++ // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols ++ return; ++ } ++ // Have direct reference to weak-global. This should be an indrect reference ++ warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overriden at runtime. " ++ "This was likely caused by different translation units being compiled with different visiblity settings.", ++ atom->name(), target->name()); + } + return; + } +-- +2.10.1 + diff --git a/Programming/ld64/files/PR-29679726.patch b/Programming/ld64/files/PR-29679726.patch new file mode 100644 index 0000000..b53d05d --- /dev/null +++ b/Programming/ld64/files/PR-29679726.patch @@ -0,0 +1,1120 @@ +From 08ebdd8bde8f21872f1ba716eaf887ef1628d738 Mon Sep 17 00:00:00 2001 +From: Jeremy Huddleston Sequoia +Date: Sun, 18 Dec 2016 00:24:11 -0800 +Subject: [PATCH] Revert textstub_dylib_file.cpp back to ld64-264.3.102 version + +Signed-off-by: Jeremy Huddleston Sequoia +--- + ld64.xcodeproj/project.pbxproj | 6 - + src/ld/Options.cpp | 35 +- + src/ld/parsers/generic_dylib_file.hpp | 63 +++ + src/ld/parsers/macho_dylib_file.cpp | 64 --- + src/ld/parsers/textstub_dylib_file.cpp | 717 +++++++++++++++++++++++++++------ + 5 files changed, 658 insertions(+), 227 deletions(-) + +diff --git ld64.xcodeproj/project.pbxproj ld64.xcodeproj/project.pbxproj +index 600aeac9..db20e783 100644 +--- ld64.xcodeproj/project.pbxproj ++++ ld64.xcodeproj/project.pbxproj +@@ -1284,8 +1284,6 @@ + "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib", + "@$(DERIVED_FILE_DIR)/linkExtras", + "-Wl,-exported_symbol,__mh_execute_header", +- "-L$(DT_TOOLCHAIN_DIR)/usr/lib", +- "-ltapi", + ); + PREBINDING = NO; + PRODUCT_NAME = ld; +@@ -1358,8 +1356,6 @@ + "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib", + "@$(DERIVED_FILE_DIR)/linkExtras", + "-Wl,-exported_symbol,__mh_execute_header", +- "-L$(DT_TOOLCHAIN_DIR)/usr/lib", +- "-ltapi", + ); + PREBINDING = NO; + PRODUCT_NAME = ld; +@@ -1577,8 +1573,6 @@ + "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib", + "@$(DERIVED_FILE_DIR)/linkExtras", + "-Wl,-exported_symbol,__mh_execute_header", +- "-L$(DT_TOOLCHAIN_DIR)/usr/lib", +- "-ltapi", + ); + PREBINDING = NO; + PRODUCT_NAME = ld; +diff --git src/ld/Options.cpp src/ld/Options.cpp +index b7e17091..227b0d84 100644 +--- src/ld/Options.cpp ++++ src/ld/Options.cpp +@@ -34,7 +34,6 @@ + #include + #include + #include +-#include + + #include + #include +@@ -832,13 +831,7 @@ bool Options::findFile(const std::string &path, const std::vector & + bool found = tbdInfo.checkFileExists(*this, newPath.c_str()); + if ( fTraceDylibSearching ) + printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), newPath.c_str()); +- if ( found ) +- break; +- } +- +- // If we found a text-based stub file, check if it should be used. +- if ( !tbdInfo.missing() ) { +- if (tapi::LinkerInterfaceFile::shouldPreferTextBasedStubFile(tbdInfo.path)) { ++ if ( found ) { + result = tbdInfo; + return true; + } +@@ -848,31 +841,10 @@ bool Options::findFile(const std::string &path, const std::vector & + bool found = dylibInfo.checkFileExists(*this, path.c_str()); + if ( fTraceDylibSearching ) + printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), path.c_str()); +- } +- +- // There is only a text-based stub file. +- if ( !tbdInfo.missing() && dylibInfo.missing() ) { +- result = tbdInfo; +- return true; +- } +- // There is only a dynamic library file. +- else if ( tbdInfo.missing() && !dylibInfo.missing() ) { +- result = dylibInfo; +- return true; +- } +- // There are both - a text-based stub file and a dynamic library file. +- else if ( !tbdInfo.missing() && !dylibInfo.missing() ) { +- // If the files are still in synv we can use and should use the text-based stub file. +- if (tapi::LinkerInterfaceFile::areEquivalent(tbdInfo.path, dylibInfo.path)) { +- result = tbdInfo; +- } +- // Otherwise issue a warning and fall-back to the dynamic library file. +- else { +- warning("text-based stub file %s and library file %s are out of sync. Falling back to library file for linking.", tbdInfo.path, dylibInfo.path); ++ if ( found ) { + result = dylibInfo; +- ++ return true; + } +- return true; + } + + return false; +@@ -3959,7 +3931,6 @@ void Options::buildSearchPaths(int argc, const char* argv[]) + const char* ltoVers = lto::version(); + if ( ltoVers != NULL ) + fprintf(stderr, "LTO support using: %s\n", ltoVers); +- fprintf(stderr, "TAPI support using: %s\n", tapi::Version::getFullVersionAsString().c_str()); + exit(0); + } + } +diff --git src/ld/parsers/generic_dylib_file.hpp src/ld/parsers/generic_dylib_file.hpp +index 529e4ab6..d581ab37 100644 +--- src/ld/parsers/generic_dylib_file.hpp ++++ src/ld/parsers/generic_dylib_file.hpp +@@ -191,6 +191,7 @@ private: + + protected: + bool isPublicLocation(const char* path) const; ++ void addSymbol(const char* name, bool weak = false, bool tlv = false, pint_t address = 0); + + private: + ld::Section _importProxySection; +@@ -479,6 +480,68 @@ bool File::isPublicLocation(const char* path) const + return false; + } + ++template ++void File::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address) ++{ ++ // symbols that start with $ld$ are meta-data to the static linker ++ // need way for ld and dyld to see different exported symbols in a dylib ++ if ( strncmp(name, "$ld$", 4) == 0 ) { ++ // $ld$ $ $ ++ const char* symAction = &name[4]; ++ const char* symCond = strchr(symAction, '$'); ++ if ( symCond != nullptr ) { ++ char curOSVers[16]; ++ sprintf(curOSVers, "$os%d.%d$", (this->_linkMinOSVersion >> 16), ((this->_linkMinOSVersion >> 8) & 0xFF)); ++ if ( strncmp(symCond, curOSVers, strlen(curOSVers)) == 0 ) { ++ const char* symName = strchr(&symCond[1], '$'); ++ if ( symName != nullptr ) { ++ ++symName; ++ if ( strncmp(symAction, "hide$", 5) == 0 ) { ++ if ( this->_s_logHashtable ) ++ fprintf(stderr, " adding %s to ignore set for %s\n", symName, this->path()); ++ this->_ignoreExports.insert(strdup(symName)); ++ return; ++ } ++ else if ( strncmp(symAction, "add$", 4) == 0 ) { ++ this->addSymbol(symName, weakDef); ++ return; ++ } ++ else if ( strncmp(symAction, "weak$", 5) == 0 ) { ++ if ( !this->_allowWeakImports ) ++ this->_ignoreExports.insert(strdup(symName)); ++ } ++ else if ( strncmp(symAction, "install_name$", 13) == 0 ) { ++ this->_dylibInstallPath = strdup(symName); ++ this->_installPathOverride = true; ++ // CoreGraphics redirects to ApplicationServices, but with wrong compat version ++ if ( strcmp(this->_dylibInstallPath, "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices") == 0 ) ++ this->_dylibCompatibilityVersion = Options::parseVersionNumber32("1.0"); ++ return; ++ } ++ else if ( strncmp(symAction, "compatibility_version$", 22) == 0 ) { ++ this->_dylibCompatibilityVersion = Options::parseVersionNumber32(symName); ++ return; ++ } ++ else { ++ warning("bad symbol action: %s in dylib %s", name, this->path()); ++ } ++ } ++ } ++ } ++ else { ++ warning("bad symbol condition: %s in dylib %s", name, this->path()); ++ } ++ } ++ ++ // add symbol as possible export if we are not supposed to ignore it ++ if ( this->_ignoreExports.count(name) == 0 ) { ++ AtomAndWeak bucket = { nullptr, weakDef, tlv, address }; ++ if ( this->_s_logHashtable ) ++ fprintf(stderr, " adding %s to hash table for %s\n", name, this->path()); ++ this->_atoms[strdup(name)] = bucket; ++ } ++} ++ + // If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB + template + bool File::allSymbolsAreWeakImported() const +diff --git src/ld/parsers/macho_dylib_file.cpp src/ld/parsers/macho_dylib_file.cpp +index 16d3f5d7..a8233055 100644 +--- src/ld/parsers/macho_dylib_file.cpp ++++ src/ld/parsers/macho_dylib_file.cpp +@@ -70,7 +70,6 @@ public: + private: + using P = typename A::P; + using E = typename A::P::E; +- using pint_t = typename A::P::uint_t; + + void addDyldFastStub(); + void buildExportHashTableFromExportInfo(const macho_dyld_info_command

* dyldInfo, +@@ -78,7 +77,6 @@ private: + void buildExportHashTableFromSymbolTable(const macho_dysymtab_command

* dynamicInfo, + const macho_nlist

* symbolTable, const char* strings, + const uint8_t* fileContent); +- void addSymbol(const char* name, bool weakDef = false, bool tlv = false, pint_t address = 0); + static const char* objCInfoSegmentName(); + static const char* objCInfoSectionName(); + +@@ -526,68 +524,6 @@ void File::buildExportHashTableFromExportInfo(const macho_dyld_info_command

+-void File::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address) +-{ +- // symbols that start with $ld$ are meta-data to the static linker +- // need way for ld and dyld to see different exported symbols in a dylib +- if ( strncmp(name, "$ld$", 4) == 0 ) { +- // $ld$ $ $ +- const char* symAction = &name[4]; +- const char* symCond = strchr(symAction, '$'); +- if ( symCond != nullptr ) { +- char curOSVers[16]; +- sprintf(curOSVers, "$os%d.%d$", (this->_linkMinOSVersion >> 16), ((this->_linkMinOSVersion >> 8) & 0xFF)); +- if ( strncmp(symCond, curOSVers, strlen(curOSVers)) == 0 ) { +- const char* symName = strchr(&symCond[1], '$'); +- if ( symName != nullptr ) { +- ++symName; +- if ( strncmp(symAction, "hide$", 5) == 0 ) { +- if ( this->_s_logHashtable ) +- fprintf(stderr, " adding %s to ignore set for %s\n", symName, this->path()); +- this->_ignoreExports.insert(strdup(symName)); +- return; +- } +- else if ( strncmp(symAction, "add$", 4) == 0 ) { +- this->addSymbol(symName, weakDef); +- return; +- } +- else if ( strncmp(symAction, "weak$", 5) == 0 ) { +- if ( !this->_allowWeakImports ) +- this->_ignoreExports.insert(strdup(symName)); +- } +- else if ( strncmp(symAction, "install_name$", 13) == 0 ) { +- this->_dylibInstallPath = symName; +- this->_installPathOverride = true; +- // CoreGraphics redirects to ApplicationServices, but with wrong compat version +- if ( strcmp(this->_dylibInstallPath, "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices") == 0 ) +- this->_dylibCompatibilityVersion = Options::parseVersionNumber32("1.0"); +- return; +- } +- else if ( strncmp(symAction, "compatibility_version$", 22) == 0 ) { +- this->_dylibCompatibilityVersion = Options::parseVersionNumber32(symName); +- return; +- } +- else { +- warning("bad symbol action: %s in dylib %s", name, this->path()); +- } +- } +- } +- } +- else { +- warning("bad symbol condition: %s in dylib %s", name, this->path()); +- } +- } +- +- // add symbol as possible export if we are not supposed to ignore it +- if ( this->_ignoreExports.count(name) == 0 ) { +- typename Base::AtomAndWeak bucket = { nullptr, weakDef, tlv, address }; +- if ( this->_s_logHashtable ) +- fprintf(stderr, " adding %s to hash table for %s\n", name, this->path()); +- this->_atoms[strdup(name)] = bucket; +- } +-} +- + template <> + void File::addDyldFastStub() + { +diff --git src/ld/parsers/textstub_dylib_file.cpp src/ld/parsers/textstub_dylib_file.cpp +index 58544625..74dbcd7c 100644 +--- src/ld/parsers/textstub_dylib_file.cpp ++++ src/ld/parsers/textstub_dylib_file.cpp +@@ -25,7 +25,7 @@ + + #include + #include +-#include ++ + #include + + #include "Architectures.hpp" +@@ -35,6 +35,469 @@ + #include "generic_dylib_file.hpp" + #include "textstub_dylib_file.hpp" + ++namespace { ++ ++/// ++/// A token is a light-weight reference to the content of an nmap'ed file. It ++/// doesn't own the data and it doesn't make a copy of it. The referenced data ++/// is only valid as long as the file is mapped in. ++/// ++class Token { ++ const char* _p; ++ size_t _size; ++ ++ int compareMemory(const char* lhs, const char* rhs, size_t size) const { ++ if (size == 0) ++ return 0; ++ return ::memcmp(lhs, rhs, size); ++ } ++ ++public: ++ Token() : _p(nullptr), _size(0) {} ++ ++ Token(const char* p) : _p(p), _size(0) { ++ if (p) ++ _size = ::strlen(p); ++ } ++ ++ Token(const char* p, size_t s) : _p(p), _size(s) {} ++ ++ const char* data() const { return _p; } ++ ++ size_t size() const { return _size; } ++ ++ std::string str() const { return std::string(_p, _size); } ++ ++ bool empty() const { return _size == 0; } ++ ++ bool operator==(Token other) const { ++ if (_size != other._size) ++ return false; ++ return compareMemory(_p, other._p, _size) == 0; ++ } ++ ++ bool operator!=(Token other) const { ++ return !(*this == other); ++ } ++}; ++ ++/// ++/// Simple text-based dynamic library file tokenizer. ++/// ++class Tokenizer { ++ const char* _start; ++ const char* _current; ++ const char* _end; ++ Token _currentToken; ++ ++ void fetchNextToken(); ++ void scanToNextToken(); ++ void skip(unsigned distance) { ++ _current += distance; ++ assert(_current <= _end && "Skipped past the end"); ++ } ++ ++ const char* skipLineBreak(const char* pos) const; ++ bool isDelimiter(const char* pos) const; ++ ++public: ++ Tokenizer(const char* data, uint64_t size) : _start(data), _current(data), _end(data + size) {} ++ ++ void reset() { ++ _current = _start; ++ fetchNextToken(); ++ } ++ ++ Token peek() { return _currentToken; } ++ Token next() { ++ Token token = peek(); ++ fetchNextToken(); ++ return token; ++ } ++}; ++ ++const char* Tokenizer::skipLineBreak(const char* pos) const ++{ ++ if ( pos == _end ) ++ return pos; ++ ++ // Carriage return. ++ if ( *pos == 0x0D ) { ++ // line feed. ++ if ( pos + 1 != _end && *(pos + 1) == 0x0A) ++ return pos + 2; ++ return pos + 1; ++ } ++ ++ // line feed. ++ if ( *pos == 0x0A ) ++ return pos + 1; ++ ++ return pos; ++} ++ ++void Tokenizer::scanToNextToken() { ++ while (true) { ++ while ( isDelimiter(_current) ) ++ skip(1); ++ ++ const char* i = skipLineBreak(_current); ++ if ( i == _current ) ++ break; ++ ++ _current = i; ++ } ++} ++ ++ ++bool Tokenizer::isDelimiter(const char* pos) const { ++ if ( pos == _end ) ++ return false; ++ if ( *pos == ' ' || *pos == '\t' || *pos == '\r' || *pos == '\n' || *pos == ',' || *pos == ':' || *pos == '\'' || *pos == '\"' ) ++ return true; ++ return false; ++} ++ ++void Tokenizer::fetchNextToken() { ++ scanToNextToken(); ++ ++ if (_current == _end) { ++ _currentToken = Token(); ++ return; ++ } ++ ++ auto start = _current; ++ while ( !isDelimiter(_current) ) { ++ ++_current; ++ } ++ ++ _currentToken = Token(start, _current - start); ++} ++ ++/// ++/// Representation of a parsed text-based dynamic library file. ++/// ++struct DynamicLibrary { ++ Token _installName; ++ uint32_t _currentVersion; ++ uint32_t _compatibilityVersion; ++ uint8_t _swiftVersion; ++ ld::File::ObjcConstraint _objcConstraint; ++ Options::Platform _platform; ++ std::vector _allowedClients; ++ std::vector _reexportedLibraries; ++ std::vector _symbols; ++ std::vector _classes; ++ std::vector _ivars; ++ std::vector _weakDefSymbols; ++ std::vector _tlvSymbols; ++ ++ DynamicLibrary() : _currentVersion(0x10000), _compatibilityVersion(0x10000), _swiftVersion(0), ++ _objcConstraint(ld::File::objcConstraintNone) {} ++}; ++ ++/// ++/// A simple text-based dynamic library file parser. ++/// ++class TBDFile { ++ Tokenizer _tokenizer; ++ ++ Token peek() { return _tokenizer.peek(); } ++ Token next() { return _tokenizer.next(); } ++ ++ void expectToken(Token str) { ++ Token token = next(); ++ if (token != str) ++ throwf("unexpected token: %s", token.str().c_str()); ++ } ++ ++ bool hasOptionalToken(Token str) { ++ auto token = peek(); ++ if ( token == str ) { ++ next(); ++ return true; ++ } ++ return false; ++ } ++ ++ ++ void parseFlowSequence(std::function func) { ++ expectToken("["); ++ ++ while ( true ) { ++ auto token = peek(); ++ if ( token == "]" ) ++ break; ++ ++ token = next(); ++ func(token); ++ } ++ ++ expectToken("]"); ++ } ++ ++ void parseAllowedClients(DynamicLibrary& lib) { ++ if ( !hasOptionalToken("allowed-clients") ) ++ return; ++ parseFlowSequence([&](Token name) { ++ lib._allowedClients.emplace_back(name); ++ }); ++ } ++ ++ void parseReexportedDylibs(DynamicLibrary& lib) { ++ if ( !hasOptionalToken("re-exports") ) ++ return; ++ parseFlowSequence([&](Token name) { ++ lib._reexportedLibraries.emplace_back(name); ++ }); ++ } ++ ++ void parseSymbols(DynamicLibrary& lib) { ++ if ( hasOptionalToken("symbols") ) { ++ parseFlowSequence([&](Token name) { ++ lib._symbols.emplace_back(name); ++ }); ++ } ++ ++ if ( hasOptionalToken("objc-classes") ) { ++ parseFlowSequence([&](Token name) { ++ lib._classes.emplace_back(name); ++ }); ++ } ++ ++ if ( hasOptionalToken("objc-ivars") ) { ++ parseFlowSequence([&](Token name) { ++ lib._ivars.emplace_back(name); ++ }); ++ } ++ ++ if ( hasOptionalToken("weak-def-symbols") ) { ++ parseFlowSequence([&](Token name) { ++ lib._weakDefSymbols.emplace_back(name); ++ }); ++ } ++ ++ if ( hasOptionalToken("thread-local-symbols") ) { ++ parseFlowSequence([&](Token name) { ++ lib._tlvSymbols.emplace_back(name); ++ }); ++ } ++ } ++ ++ std::vector parseArchFlowSequence() { ++ std::vector availabledArchitectures; ++ expectToken("archs"); ++ parseFlowSequence([&](Token name) { ++ availabledArchitectures.emplace_back(name.str()); ++ }); ++ return availabledArchitectures; ++ } ++ ++ bool parseArchFlowSequence(std::string &selectedArchName) { ++ auto availabledArchitectures = parseArchFlowSequence(); ++ ++ for (const auto &archName : availabledArchitectures) { ++ if (archName == selectedArchName) ++ return true; ++ } ++ ++ return false; ++ } ++ ++ void parsePlatform(DynamicLibrary& lib) { ++ expectToken("platform"); ++ ++ auto token = next(); ++ if (token == "macosx") ++ lib._platform = Options::kPlatformOSX; ++ else if (token == "ios") ++ lib._platform = Options::kPlatformiOS; ++ else if (token == "watchos") ++ lib._platform = Options::kPlatformWatchOS; ++#if SUPPORT_APPLE_TV ++ else if (token == "tvos") ++ lib._platform = Options::kPlatform_tvOS; ++#endif ++ else ++ lib._platform = Options::kPlatformUnknown; ++ } ++ ++ void parseInstallName(DynamicLibrary& lib) { ++ expectToken("install-name"); ++ ++ lib._installName = next(); ++ if ( lib._installName.empty() ) ++ throwf("no install name specified"); ++ } ++ ++ uint32_t parseVersionNumber32(Token token) { ++ if ( token.size() >= 128 ) ++ throwf("malformed version number"); ++ ++ // Make a null-terminated string. ++ char buffer[128]; ++ ::memcpy(buffer, token.data(), token.size()); ++ buffer[token.size()] = '\0'; ++ ++ return Options::parseVersionNumber32(buffer); ++ } ++ ++ void parseCurrentVersion(DynamicLibrary& lib) { ++ if ( !hasOptionalToken("current-version") ) ++ return; ++ lib._currentVersion = parseVersionNumber32(next()); ++ } ++ ++ void parseCompatibilityVersion(DynamicLibrary& lib) { ++ if ( !hasOptionalToken("compatibility-version") ) ++ return; ++ lib._compatibilityVersion = parseVersionNumber32(next()); ++ } ++ ++ void parseSwiftVersion(DynamicLibrary& lib) { ++ if ( !hasOptionalToken("swift-version") ) ++ return; ++ auto token = next(); ++ if ( token == "1.0" ) ++ lib._swiftVersion = 1; ++ else if ( token == "1.1" ) ++ lib._swiftVersion = 2; ++ else if ( token == "2.0" ) ++ lib._swiftVersion = 3; ++ else ++ throwf("unsupported Swift ABI version: %s", token.str().c_str()); ++ } ++ ++ void parseObjCConstraint(DynamicLibrary& lib) { ++ if ( !hasOptionalToken("objc-constraint") ) ++ return; ++ auto token = next(); ++ if ( token == "none" ) ++ lib._objcConstraint = ld::File::objcConstraintNone; ++ else if ( token == "retain_release" ) ++ lib._objcConstraint = ld::File::objcConstraintRetainRelease; ++ else if ( token == "retain_release_for_simulator" ) ++ lib._objcConstraint = ld::File::objcConstraintRetainReleaseForSimulator; ++ else if ( token == "retain_release_or_gc" ) ++ lib._objcConstraint = ld::File::objcConstraintRetainReleaseOrGC; ++ else if ( token == "gc" ) ++ lib._objcConstraint = ld::File::objcConstraintGC; ++ else ++ throwf("unexpected token: %s", token.str().c_str()); ++ } ++ void parseExportsBlock(DynamicLibrary& lib, std::string &selectedArchName) { ++ if ( !hasOptionalToken("exports") ) ++ return; ++ ++ if ( !hasOptionalToken("-") ) ++ return; ++ ++ while ( true ) { ++ if ( !parseArchFlowSequence(selectedArchName) ) { ++ Token token; ++ while ( true ) { ++ token = peek(); ++ if ( token == "archs" || token == "..." || token.empty() ) ++ break; ++ next(); ++ } ++ if (token == "..." || token.empty() ) ++ break; ++ ++ continue; ++ } ++ ++ parseAllowedClients(lib); ++ parseReexportedDylibs(lib); ++ parseSymbols(lib); ++ if ( !hasOptionalToken("-") ) ++ break; ++ } ++ } ++ ++ std::vector getCompatibleArchList(std::string &requestedArchName) { ++ if (requestedArchName == "i386") ++ return {"i386"}; ++ else if (requestedArchName == "x86_64" || requestedArchName == "x86_64h") ++ return {"x86_64", "x86_64h"}; ++ else if (requestedArchName == "armv7" || requestedArchName == "armv7s") ++ return {"armv7", "armv7s"}; ++ else if (requestedArchName == "armv7k") ++ return {"armv7k"}; ++ else if (requestedArchName == "arm64") ++ return {"arm64"}; ++ else ++ return {}; ++ } ++ ++ std::string parseAndSelectArchitecture(std::string &requestedArchName) { ++ auto availabledArchitectures = parseArchFlowSequence(); ++ ++ // First try to find an exact match (cpu type and sub-cpu type). ++ if (std::find(availabledArchitectures.begin(), availabledArchitectures.end(), requestedArchName) ++ != availabledArchitectures.end()) ++ return requestedArchName; ++ ++ // If there is no exact match, then try to find an ABI compatible slice. ++ auto compatibleArchitectures = getCompatibleArchList(requestedArchName); ++ std::vector result; ++ std::sort(availabledArchitectures.begin(), availabledArchitectures.end()); ++ std::sort(compatibleArchitectures.begin(), compatibleArchitectures.end()); ++ std::set_intersection(availabledArchitectures.begin(), availabledArchitectures.end(), ++ compatibleArchitectures.begin(), compatibleArchitectures.end(), ++ std::back_inserter(result)); ++ ++ if (result.empty()) ++ return std::string(); ++ else ++ return result.front(); ++ } ++ ++ void parseDocument(DynamicLibrary& lib, std::string &requestedArchName) { ++ auto selectedArchName = parseAndSelectArchitecture(requestedArchName); ++ if (selectedArchName.empty()) ++ throwf("invalid arch"); ++ ++ parsePlatform(lib); ++ parseInstallName(lib); ++ parseCurrentVersion(lib); ++ parseCompatibilityVersion(lib); ++ parseSwiftVersion(lib); ++ parseObjCConstraint(lib); ++ parseExportsBlock(lib, selectedArchName); ++ } ++ ++public: ++ TBDFile(const char* data, uint64_t size) : _tokenizer(data, size) {} ++ ++ DynamicLibrary parseFileForArch(std::string requestedArchName) { ++ _tokenizer.reset(); ++ DynamicLibrary lib; ++ expectToken("---"); ++ parseDocument(lib, requestedArchName); ++ expectToken("..."); ++ return lib; ++ } ++ ++ bool validForArch(std::string requestedArchName) { ++ _tokenizer.reset(); ++ auto token = next(); ++ if ( token != "---" ) ++ return false; ++ return !parseAndSelectArchitecture(requestedArchName).empty(); ++ } ++ ++ void dumpTokens() { ++ _tokenizer.reset(); ++ Token token; ++ do { ++ token = next(); ++ printf("token: %s\n", token.str().c_str()); ++ } while ( !token.empty() ); ++ } ++}; ++ ++} // end anonymous namespace + + namespace textstub { + namespace dylib { +@@ -50,94 +513,51 @@ class File final : public generic::dylib::File + using Base = generic::dylib::File; + + public: +- File(const char* path, const uint8_t* fileContent, uint64_t fileLength, ++ static bool validFile(const uint8_t* fileContent, bool executableOrDylib); ++ File(const uint8_t* fileContent, uint64_t fileLength, const char* path, + time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace, +- bool linkingMainExecutable, bool hoistImplicitPublicDylibs, +- Options::Platform platform, uint32_t linkMinOSVersion, bool allowWeakImports, +- cpu_type_t cpuType, cpu_subtype_t cpuSubType, bool enforceDylibSubtypesMatch, +- bool allowSimToMacOSX, bool addVers, bool buildingForSimulator, ++ bool hoistImplicitPublicDylibs, Options::Platform platform, ++ cpu_type_t cpuType, const char* archName, uint32_t linkMinOSVersion, ++ bool allowWeakImports, bool allowSimToMacOSX, bool addVers, bool buildingForSimulator, + bool logAllFiles, const char* installPath, bool indirectDylib); + virtual ~File() noexcept {} + + private: +- void buildExportHashTable(const tapi::LinkerInterfaceFile* file); +-}; +- +-static ld::File::ObjcConstraint mapObjCConstraint(tapi::ObjCConstraint constraint) { +- switch (constraint) { +- case tapi::ObjCConstraint::None: +- return ld::File::objcConstraintNone; +- case tapi::ObjCConstraint::Retain_Release: +- return ld::File::objcConstraintRetainRelease; +- case tapi::ObjCConstraint::Retain_Release_For_Simulator: +- return ld::File::objcConstraintRetainReleaseForSimulator; +- case tapi::ObjCConstraint::Retain_Release_Or_GC: +- return ld::File::objcConstraintRetainReleaseOrGC; +- case tapi::ObjCConstraint::GC: +- return ld::File::objcConstraintGC; +- } +- +- return ld::File::objcConstraintNone; +-} ++ void buildExportHashTable(const DynamicLibrary &lib); + +-static Options::Platform mapPlatform(tapi::Platform platform) { +- switch (platform) { +- case tapi::Platform::Unknown: +- return Options::kPlatformUnknown; +- case tapi::Platform::OSX: +- return Options::kPlatformOSX; +- case tapi::Platform::iOS: +- return Options::kPlatformiOS; +- case tapi::Platform::watchOS: +- return Options::kPlatformWatchOS; +- case tapi::Platform::tvOS: +- return Options::kPlatform_tvOS; +- } +- +- return Options::kPlatformUnknown; +-} ++ cpu_type_t _cpuType; ++}; + + template +- File::File(const char* path, const uint8_t* fileContent, uint64_t fileLength, +- time_t mTime, ld::File::Ordinal ord, bool linkingFlatNamespace, +- bool linkingMainExecutable, bool hoistImplicitPublicDylibs, Options::Platform platform, +- uint32_t linkMinOSVersion, bool allowWeakImports, cpu_type_t cpuType, cpu_subtype_t cpuSubType, +- bool enforceDylibSubtypesMatch, bool allowSimToMacOSX, bool addVers, ++File::File(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t mTime, ++ ld::File::Ordinal ord, bool linkingFlatNamespace, bool hoistImplicitPublicDylibs, ++ Options::Platform platform, cpu_type_t cpuType, const char* archName, ++ uint32_t linkMinOSVersion, bool allowWeakImports, bool allowSimToMacOSX, bool addVers, + bool buildingForSimulator, bool logAllFiles, const char* targetInstallPath, + bool indirectDylib) + : Base(strdup(path), mTime, ord, platform, linkMinOSVersion, allowWeakImports, linkingFlatNamespace, +- hoistImplicitPublicDylibs, allowSimToMacOSX, addVers) ++ hoistImplicitPublicDylibs, allowSimToMacOSX, addVers), ++ _cpuType(cpuType) + { +- auto matchingType = enforceDylibSubtypesMatch ? +- tapi::CpuSubTypeMatching::Exact : tapi::CpuSubTypeMatching::ABI_Compatible; +- +- std::string errorMessage; +- auto file = std::unique_ptr( +- tapi::LinkerInterfaceFile::create(path, fileContent, fileLength, cpuType, +- cpuSubType, matchingType, +- tapi::PackedVersion32(linkMinOSVersion), errorMessage)); +- +- if (file == nullptr) +- throw strdup(errorMessage.c_str()); +- +- // unmap file - it is no longer needed. +- munmap((caddr_t)fileContent, fileLength); ++ this->_bitcode = std::unique_ptr(new ld::Bitcode(nullptr, 0)); ++ // Text stubs are implicit app extension safe. ++ this->_appExtensionSafe = true; + + // write out path for -t option + if ( logAllFiles ) + printf("%s\n", path); + +- this->_bitcode = std::unique_ptr(new ld::Bitcode(nullptr, 0)); +- this->_noRexports = !file->hasReexportedLibraries(); +- this->_hasWeakExports = file->hasWeakDefinedExports(); +- this->_dylibInstallPath = strdup(file->getInstallName().c_str()); +- this->_installPathOverride = file->isInstallNameVersionSpecific(); +- this->_dylibCurrentVersion = file->getCurrentVersion(); +- this->_dylibCompatibilityVersion = file->getCompatibilityVersion(); +- this->_swiftVersion = file->getSwiftVersion(); +- this->_objcConstraint = mapObjCConstraint(file->getObjCConstraint()); +- this->_parentUmbrella = file->getParentFrameworkName().empty() ? nullptr : strdup(file->getParentFrameworkName().c_str()); +- this->_appExtensionSafe = file->isApplicationExtensionSafe(); ++ TBDFile stub((const char*)fileContent, fileLength); ++ auto lib = stub.parseFileForArch(archName); ++ ++ this->_noRexports = lib._reexportedLibraries.empty(); ++ this->_hasWeakExports = !lib._weakDefSymbols.empty(); ++ this->_dylibInstallPath = strdup(lib._installName.str().c_str()); ++ this->_dylibCurrentVersion = lib._currentVersion; ++ this->_dylibCompatibilityVersion = lib._compatibilityVersion; ++ this->_swiftVersion = lib._swiftVersion; ++ this->_objcConstraint = lib._objcConstraint; ++ this->_hasPublicInstallName = this->isPublicLocation(this->_dylibInstallPath); + + // if framework, capture framework name + const char* lastSlash = strrchr(this->_dylibInstallPath, '/'); +@@ -151,69 +571,100 @@ template + this->_frameworkName = leafName; + } + +- for (auto &client : file->allowableClients()) +- this->_allowableClients.push_back(strdup(client.c_str())); ++ // TEMPORARY HACK BEGIN: Support ancient re-export command LC_SUB_FRAMEWORK. ++ // [TAPI] Support LC_SUB_FRAMEWORK as re-export indicator. ++ auto installName = std::string(this->_dylibInstallPath); ++ ++ // All sub-frameworks of ApplicationServices use LC_SUB_FRAMEWORK. ++ if (installName.find("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/") == 0 && ++ installName.find(".dylib") == std::string::npos) { ++ this->_parentUmbrella = "ApplicationServices"; ++ } else if (installName.find("/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/") == 0) { ++ this->_parentUmbrella = "Carbon"; ++ } else if (installName.find("/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/") == 0 && ++ installName.find(".dylib") == std::string::npos) { ++ this->_parentUmbrella = "CoreServices"; ++ } else if (installName.find("/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLinearAlgebra.dylib") == 0 || ++ installName.find("/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libQuadrature.dylib") == 0 || ++ installName.find("System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparseBLAS.dylib") == 0) { ++ this->_parentUmbrella = "vecLib"; ++ } else if (installName.find("/System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks/WebCore.framework/Versions/A/WebCore") == 0) { ++ this->_parentUmbrella = "WebKit"; ++ } else if (installName.find("/usr/lib/system/") == 0 && ++ installName != "/usr/lib/system/libkxld.dylib") { ++ this->_parentUmbrella = "System"; ++ } ++ // TEMPORARY HACK END ++ ++ for (auto &client : lib._allowedClients) { ++ if ((this->_parentUmbrella != nullptr) && (client.str() != this->_parentUmbrella)) ++ this->_allowableClients.push_back(strdup(client.str().c_str())); ++ } + + // [TAPI] Don't hoist "public" (in /usr/lib/) dylibs that should not be directly linked +- this->_hasPublicInstallName = file->hasAllowableClients() ? false : this->isPublicLocation(file->getInstallName().c_str()); +- +- for (const auto &client : file->allowableClients()) +- this->_allowableClients.emplace_back(strdup(client.c_str())); ++ if ( !this->_allowableClients.empty() ) ++ this->_hasPublicInstallName = false; + +- auto dylibPlatform = mapPlatform(file->getPlatform()); +- if ( (dylibPlatform != platform) && (platform != Options::kPlatformUnknown) ) { ++ if ( (lib._platform != platform) && (platform != Options::kPlatformUnknown) ) { + this->_wrongOS = true; + if ( this->_addVersionLoadCommand && !indirectDylib ) { + if ( buildingForSimulator ) { + if ( !this->_allowSimToMacOSXLinking ) + throwf("building for %s simulator, but linking against dylib built for %s (%s).", +- Options::platformName(platform), Options::platformName(dylibPlatform), path); ++ Options::platformName(platform), Options::platformName(lib._platform), path); + } else { + throwf("building for %s, but linking against dylib built for %s (%s).", +- Options::platformName(platform), Options::platformName(dylibPlatform), path); ++ Options::platformName(platform), Options::platformName(lib._platform), path); + } + } + } + +- for (const auto& reexport : file->reexportedLibraries()) { +- const char *path = strdup(reexport.c_str()); ++ this->_dependentDylibs.reserve(lib._reexportedLibraries.size()); ++ for ( const auto& reexport : lib._reexportedLibraries ) { ++ const char *path = strdup(reexport.str().c_str()); + if ( (targetInstallPath == nullptr) || (strcmp(targetInstallPath, path) != 0) ) + this->_dependentDylibs.emplace_back(path, true); + } + +- for (const auto& symbol : file->ignoreExports()) +- this->_ignoreExports.insert(strdup(symbol.c_str())); +- +- // if linking flat and this is a flat dylib, create one atom that references all imported symbols. +- if ( linkingFlatNamespace && linkingMainExecutable && (file->hasTwoLevelNamespace() == false) ) { +- std::vector importNames; +- importNames.reserve(file->undefineds().size()); +- // We do not need to strdup the name, because that will be done by the +- // ImportAtom constructor. +- for (const auto &sym : file->undefineds()) +- importNames.emplace_back(sym.getName().c_str()); +- this->_importAtom = new generic::dylib::ImportAtom(*this, importNames); +- } +- + // build hash table +- buildExportHashTable(file.get()); ++ buildExportHashTable(lib); ++ ++ munmap((caddr_t)fileContent, fileLength); + } + + template +-void File::buildExportHashTable(const tapi::LinkerInterfaceFile* file) { ++void File::buildExportHashTable(const DynamicLibrary& lib) { + if (this->_s_logHashtable ) + fprintf(stderr, "ld: building hashtable from text-stub info in %s\n", this->path()); + +- for (const auto &sym : file->exports()) { +- const char* name = sym.getName().c_str(); +- bool weakDef = sym.isWeakDefined(); +- bool tlv = sym.isThreadLocalValue(); ++ for (auto &sym : lib._symbols) ++ this->addSymbol(sym.str().c_str()); + +- typename Base::AtomAndWeak bucket = { nullptr, weakDef, tlv, 0 }; +- if ( this->_s_logHashtable ) +- fprintf(stderr, " adding %s to hash table for %s\n", name, this->path()); +- this->_atoms[strdup(name)] = bucket; ++#if SUPPORT_ARCH_i386 ++ if (this->_platform == Options::kPlatformOSX && _cpuType == CPU_TYPE_I386) { ++ for (auto &sym : lib._classes) ++ this->addSymbol((".objc_class_name" + sym.str()).c_str()); ++ } else { ++ for (auto &sym : lib._classes) { ++ this->addSymbol(("_OBJC_CLASS_$" + sym.str()).c_str()); ++ this->addSymbol(("_OBJC_METACLASS_$" + sym.str()).c_str()); ++ } + } ++#else ++ for (auto &sym : lib._classes) { ++ this->addSymbol(("_OBJC_CLASS_$" + sym.str()).c_str()); ++ this->addSymbol(("_OBJC_METACLASS_$" + sym.str()).c_str()); ++ } ++#endif ++ ++ for (auto &sym : lib._ivars) ++ this->addSymbol(("_OBJC_IVAR_$" + sym.str()).c_str()); ++ ++ for (auto &sym : lib._weakDefSymbols) ++ this->addSymbol(sym.str().c_str(), /*weak=*/true); ++ ++ for (auto &sym : lib._tlvSymbols) ++ this->addSymbol(sym.str().c_str(), /*weak=*/false, /*tlv=*/true); + } + + template +@@ -222,21 +673,20 @@ class Parser + public: + using P = typename A::P; + +- static ld::dylib::File* parse(const char* path, const uint8_t* fileContent, +- uint64_t fileLength, time_t mTime, +- ld::File::Ordinal ordinal, const Options& opts, ++ static bool validFile(const uint8_t* fileContent, uint64_t fileLength, ++ const std::string &path, const char* archName); ++ static ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, ++ time_t mTime, ld::File::Ordinal ordinal, const Options& opts, + bool indirectDylib) + { +- return new File(path, fileContent, fileLength,mTime, ordinal, ++ return new File(fileContent, fileLength, path, mTime, ordinal, + opts.flatNamespace(), +- opts.linkingMainExecutable(), + opts.implicitlyLinkIndirectPublicDylibs(), + opts.platform(), ++ opts.architecture(), ++ opts.architectureName(), + opts.minOSversion(), + opts.allowWeakImports(), +- opts.architecture(), +- opts.subArchitecture(), +- opts.enforceDylibSubtypesMatch(), + opts.allowSimulatorToLinkWithMacOSX(), + opts.addVersionLoadCommand(), + opts.targetIOSSimulator(), +@@ -246,6 +696,20 @@ public: + } + }; + ++template ++bool Parser::validFile(const uint8_t* fileContent, uint64_t fileLength, const std::string &path, ++ const char* archName) ++{ ++ if ( path.find(".tbd", path.size()-4) == std::string::npos ) ++ return false; ++ ++ TBDFile stub((const char*)fileContent, fileLength); ++ if ( !stub.validForArch(archName) ) ++ throwf("missing required architecture %s in file %s", archName, path.c_str()); ++ ++ return true; ++} ++ + // + // main function used by linker to instantiate ld::Files + // +@@ -253,27 +717,30 @@ ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const ch + time_t modTime, const Options& opts, ld::File::Ordinal ordinal, + bool bundleLoader, bool indirectDylib) + { +- + switch ( opts.architecture() ) { + #if SUPPORT_ARCH_x86_64 + case CPU_TYPE_X86_64: +- if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength)) +- return Parser::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib); ++ if ( Parser::validFile(fileContent, fileLength, path, opts.architectureName()) ) ++ return Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); ++ break; + #endif + #if SUPPORT_ARCH_i386 + case CPU_TYPE_I386: +- if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength)) +- return Parser::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib); ++ if ( Parser::validFile(fileContent, fileLength, path, opts.architectureName()) ) ++ return Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); ++ break; + #endif + #if SUPPORT_ARCH_arm_any + case CPU_TYPE_ARM: +- if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength)) +- return Parser::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib); ++ if ( Parser::validFile(fileContent, fileLength, path, opts.architectureName()) ) ++ return Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); ++ break; + #endif + #if SUPPORT_ARCH_arm64 + case CPU_TYPE_ARM64: +- if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength)) +- return Parser::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib); ++ if ( Parser::validFile(fileContent, fileLength, path, opts.architectureName()) ) ++ return Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); ++ break; + #endif + } + return nullptr; +-- +2.11.0 + diff --git a/Programming/ld64/files/PR-29723276.patch b/Programming/ld64/files/PR-29723276.patch new file mode 100644 index 0000000..fb5a32a --- /dev/null +++ b/Programming/ld64/files/PR-29723276.patch @@ -0,0 +1,12 @@ +--- src/other/ObjectDump.cpp.orig 2016-03-09 13:27:56.000000000 -0800 ++++ src/other/ObjectDump.cpp 2016-12-18 00:12:47.000000000 -0800 +@@ -843,9 +843,6 @@ void dumper::dumpFixup(const ld::Fixup* + case ld::Fixup::kindStoreARM64PCRelToGOT: + printf(", then store as 32-bit delta to GOT entry"); + break; +- case ld::Fixup::kindStoreARM64PointerToGOT32: +- printf(", then store as 32-bit pointer to GOT entry"); +- break; + case ld::Fixup::kindDtraceExtra: + printf("dtrace static probe extra info"); + break; diff --git a/Programming/ld64/files/PR-29723629.patch b/Programming/ld64/files/PR-29723629.patch new file mode 100644 index 0000000..66a8c8d --- /dev/null +++ b/Programming/ld64/files/PR-29723629.patch @@ -0,0 +1,37 @@ +guard usage of thinlto_code_gen_t behind an appropriate API version check + +--- src/ld/parsers/lto_file.cpp ++++ src/ld/parsers/lto_file.cpp +@@ -292,12 +292,14 @@ private: + std::vector& newAtoms, + std::vector& additionalUndefines); + ++#if LTO_API_VERSION >= 18 + static thinlto_code_gen_t init_thinlto_codegen(const std::vector& files, + const std::vector& allAtoms, + ld::Internal& state, + const OptimizeOptions& options, + CStringToAtom& deadllvmAtoms, + CStringToAtom& llvmAtoms); ++#endif + + static std::vector _s_files; + static bool _s_llvmOptionsProcessed; +@@ -1035,6 +1037,7 @@ bool Parser::optimizeLTO(const std::vector files, + return true; + } + ++#if LTO_API_VERSION >= 18 + // Create the ThinLTO codegenerator + thinlto_code_gen_t Parser::init_thinlto_codegen(const std::vector& files, + const std::vector& allAtoms, +@@ -1185,6 +1188,7 @@ thinlto_code_gen_t Parser::init_thinlto_codegen(const std::vector& + + return thingenerator; + } ++#endif + + // Full LTO processing + bool Parser::optimizeThinLTO(const std::vector& files, +-- +2.11.0 diff --git a/Programming/ld64/files/PR-49393.patch b/Programming/ld64/files/PR-49393.patch new file mode 100644 index 0000000..47921a4 --- /dev/null +++ b/Programming/ld64/files/PR-49393.patch @@ -0,0 +1,11 @@ +--- src/ld/parsers/textstub_dylib_file.cpp.orig 2015-06-15 15:42:21.000000000 -0700 ++++ src/ld/parsers/textstub_dylib_file.cpp 2015-10-23 17:45:56.000000000 -0700 +@@ -29,7 +29,7 @@ + #include + + #include "Architectures.hpp" +-#include "bitcode.hpp" ++#include "Bitcode.hpp" + #include "MachOFileAbstraction.hpp" + #include "MachOTrie.hpp" + #include "textstub_dylib_file.hpp" diff --git a/Programming/ld64/files/ld64-133-no-CrashReporterClient.h.patch b/Programming/ld64/files/ld64-133-no-CrashReporterClient.h.patch new file mode 100644 index 0000000..20e7cdc --- /dev/null +++ b/Programming/ld64/files/ld64-133-no-CrashReporterClient.h.patch @@ -0,0 +1,21 @@ +--- src/ld/Options.cpp.orig 2012-09-04 14:00:10.000000000 -0700 ++++ src/ld/Options.cpp 2012-09-04 14:00:37.000000000 -0700 +@@ -50,7 +50,7 @@ namespace lto { + // magic to place command line in crash reports + const int crashreporterBufferSize = 2000; + static char crashreporterBuffer[crashreporterBufferSize]; +-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 ++#if 0 && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + #include + // hack until ld does not need to build on 10.6 anymore + struct crashreporter_annotations_t gCRAnnotations +@@ -4246,7 +4247,7 @@ void Options::checkForClassic(int argc, + bool newLinker = false; + + // build command line buffer in case ld crashes +-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 ++#if 0 && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + CRSetCrashLogMessage(crashreporterBuffer); + #endif + const char* srcRoot = getenv("SRCROOT"); + diff --git a/Programming/ld64/files/ld64-134-missing-include.patch b/Programming/ld64/files/ld64-134-missing-include.patch new file mode 100644 index 0000000..f682e56 --- /dev/null +++ b/Programming/ld64/files/ld64-134-missing-include.patch @@ -0,0 +1,21 @@ +--- src/ld/parsers/lto_file.cpp.orig 2012-12-30 20:08:12.000000000 -0800 ++++ src/ld/parsers/lto_file.cpp 2012-12-30 20:08:32.000000000 -0800 +@@ -35,6 +35,8 @@ + #include + #include + ++#include ++ + #include "MachOFileAbstraction.hpp" + #include "Architectures.hpp" + #include "ld.hpp" +--- src/other/rebase.cpp.orig 2013-02-08 09:28:44.000000000 -0800 ++++ src/other/rebase.cpp 2013-02-08 09:29:01.000000000 -0800 +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + #include diff --git a/Programming/ld64/files/ld64-136-i386-badAddress.patch b/Programming/ld64/files/ld64-136-i386-badAddress.patch new file mode 100644 index 0000000..9a44484 --- /dev/null +++ b/Programming/ld64/files/ld64-136-i386-badAddress.patch @@ -0,0 +1,11 @@ +--- src/ld/LinkEdit.hpp.orig 2013-05-27 10:47:54.000000000 -0700 ++++ src/ld/LinkEdit.hpp 2013-05-27 10:56:06.000000000 -0700 +@@ -1278,7 +1278,7 @@ template + void FunctionStartsAtom::encode() const + { + this->_encodedData.reserve(8192); +- const uint64_t badAddress = 0xFFFFFFFFFFFFFFFF; ++ const uint64_t badAddress = 0xFFFFFFFFFFFFFFFFULL; + uint64_t addr = badAddress; + // delta compress all function addresses + for (std::vector::iterator it = this->_state.sections.begin(); it != this->_state.sections.end(); ++it) { diff --git a/Programming/ld64/files/ld64-ppc-9610466.patch b/Programming/ld64/files/ld64-ppc-9610466.patch new file mode 100644 index 0000000..1a3c91e --- /dev/null +++ b/Programming/ld64/files/ld64-ppc-9610466.patch @@ -0,0 +1,17 @@ +Adjust out-of range error to be a warning on ppc + +AKA for ppc + +https://trac.macports.org/ticket/46801 + +--- src/ld/OutputFile.cpp ++++ src/ld/OutputFile.cpp +@@ -625,7 +625,7 @@ void OutputFile::rangeCheckAbsolute32(int64_t displacement, ld::Internal& state, + // is encoded in mach-o the same as: + // .long _foo + 0x40000000 + // so if _foo lays out to 0xC0000100, the first is ok, but the second is not. +- if ( (_options.architecture() == CPU_TYPE_ARM) || (_options.architecture() == CPU_TYPE_I386) ) { ++ if ( (_options.architecture() == CPU_TYPE_ARM) || (_options.architecture() == CPU_TYPE_I386) || (_options.architecture() == CPU_TYPE_POWERPC) ) { + // Unlikely userland code does funky stuff like this, so warn for them, but not warn for -preload or -static + if ( (_options.outputKind() != Options::kPreload) && (_options.outputKind() != Options::kStaticExecutable) ) { + warning("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to 0x%08llX", diff --git a/Programming/ld64/files/ld64-version.patch b/Programming/ld64/files/ld64-version.patch new file mode 100644 index 0000000..85df69a --- /dev/null +++ b/Programming/ld64/files/ld64-version.patch @@ -0,0 +1,19 @@ +--- src/ld/Options.cpp 2008-03-20 18:48:04.000000000 -0700 ++++ src/ld/Options.cpp 2012-04-11 15:54:34.000000000 -0700 +@@ -32,6 +32,8 @@ + + #include "Options.h" + ++const char ldVersionString[] = "@(#)PROGRAM:ld PROJECT:ld64-@@VERSION@@\n"; ++ + void throwf(const char* format, ...) + { + va_list list; +@@ -2153,7 +2155,6 @@ void Options::buildSearchPaths(int argc, + addStandardLibraryDirectories = false; + else if ( strcmp(argv[i], "-v") == 0 ) { + fVerbose = true; +- extern const char ldVersionString[]; + fprintf(stderr, "%s", ldVersionString); + // if only -v specified, exit cleanly + if ( argc == 2 ) diff --git a/Programming/ld64/files/lto.h b/Programming/ld64/files/lto.h new file mode 100644 index 0000000..b1f5a45 --- /dev/null +++ b/Programming/ld64/files/lto.h @@ -0,0 +1,797 @@ +/*===-- llvm-c/lto.h - LTO Public C Interface ---------------------*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides public interface to an abstract link time optimization*| +|* library. LLVM provides an implementation of this interface for use with *| +|* llvm bitcode files. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_LTO_H +#define LLVM_C_LTO_H + +#ifdef __cplusplus +#include +#else +#include +#endif +#include + +#ifndef __cplusplus +#if !defined(_MSC_VER) +#include +typedef bool lto_bool_t; +#else +/* MSVC in particular does not have anything like _Bool or bool in C, but we can + at least make sure the type is the same size. The implementation side will + use C++ bool. */ +typedef unsigned char lto_bool_t; +#endif +#else +typedef bool lto_bool_t; +#endif + +/** + * @defgroup LLVMCLTO LTO + * @ingroup LLVMC + * + * @{ + */ + +#define LTO_API_VERSION 20 + +/** + * \since prior to LTO_API_VERSION=3 + */ +typedef enum { + LTO_SYMBOL_ALIGNMENT_MASK = 0x0000001F, /* log2 of alignment */ + LTO_SYMBOL_PERMISSIONS_MASK = 0x000000E0, + LTO_SYMBOL_PERMISSIONS_CODE = 0x000000A0, + LTO_SYMBOL_PERMISSIONS_DATA = 0x000000C0, + LTO_SYMBOL_PERMISSIONS_RODATA = 0x00000080, + LTO_SYMBOL_DEFINITION_MASK = 0x00000700, + LTO_SYMBOL_DEFINITION_REGULAR = 0x00000100, + LTO_SYMBOL_DEFINITION_TENTATIVE = 0x00000200, + LTO_SYMBOL_DEFINITION_WEAK = 0x00000300, + LTO_SYMBOL_DEFINITION_UNDEFINED = 0x00000400, + LTO_SYMBOL_DEFINITION_WEAKUNDEF = 0x00000500, + LTO_SYMBOL_SCOPE_MASK = 0x00003800, + LTO_SYMBOL_SCOPE_INTERNAL = 0x00000800, + LTO_SYMBOL_SCOPE_HIDDEN = 0x00001000, + LTO_SYMBOL_SCOPE_PROTECTED = 0x00002000, + LTO_SYMBOL_SCOPE_DEFAULT = 0x00001800, + LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN = 0x00002800, + LTO_SYMBOL_COMDAT = 0x00004000, + LTO_SYMBOL_ALIAS = 0x00008000 +} lto_symbol_attributes; + +/** + * \since prior to LTO_API_VERSION=3 + */ +typedef enum { + LTO_DEBUG_MODEL_NONE = 0, + LTO_DEBUG_MODEL_DWARF = 1 +} lto_debug_model; + +/** + * \since prior to LTO_API_VERSION=3 + */ +typedef enum { + LTO_CODEGEN_PIC_MODEL_STATIC = 0, + LTO_CODEGEN_PIC_MODEL_DYNAMIC = 1, + LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC = 2, + LTO_CODEGEN_PIC_MODEL_DEFAULT = 3 +} lto_codegen_model; + +/** opaque reference to a loaded object module */ +typedef struct LLVMOpaqueLTOModule *lto_module_t; + +/** opaque reference to a code generator */ +typedef struct LLVMOpaqueLTOCodeGenerator *lto_code_gen_t; + +/** opaque reference to a thin code generator */ +typedef struct LLVMOpaqueThinLTOCodeGenerator *thinlto_code_gen_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Returns a printable string. + * + * \since prior to LTO_API_VERSION=3 + */ +extern const char* +lto_get_version(void); + +/** + * Returns the last error string or NULL if last operation was successful. + * + * \since prior to LTO_API_VERSION=3 + */ +extern const char* +lto_get_error_message(void); + +/** + * Checks if a file is a loadable object file. + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_bool_t +lto_module_is_object_file(const char* path); + +/** + * Checks if a file is a loadable object compiled for requested target. + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_bool_t +lto_module_is_object_file_for_target(const char* path, + const char* target_triple_prefix); + +/** + * Return true if \p Buffer contains a bitcode file with ObjC code (category + * or class) in it. + * + * \since LTO_API_VERSION=20 + */ +extern lto_bool_t +lto_module_has_objc_category(const void *mem, size_t length); + +/** +* Checks if a buffer is a loadable object file. +* +* \since prior to LTO_API_VERSION=3 +*/ +extern lto_bool_t lto_module_is_object_file_in_memory(const void *mem, + size_t length); + +/** + * Checks if a buffer is a loadable object compiled for requested target. + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_bool_t +lto_module_is_object_file_in_memory_for_target(const void* mem, size_t length, + const char* target_triple_prefix); + +/** + * Loads an object file from disk. + * Returns NULL on error (check lto_get_error_message() for details). + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_module_t +lto_module_create(const char* path); + +/** + * Loads an object file from memory. + * Returns NULL on error (check lto_get_error_message() for details). + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_module_t +lto_module_create_from_memory(const void* mem, size_t length); + +/** + * Loads an object file from memory with an extra path argument. + * Returns NULL on error (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=9 + */ +extern lto_module_t +lto_module_create_from_memory_with_path(const void* mem, size_t length, + const char *path); + +/** + * \brief Loads an object file in its own context. + * + * Loads an object file in its own LLVMContext. This function call is + * thread-safe. However, modules created this way should not be merged into an + * lto_code_gen_t using \a lto_codegen_add_module(). + * + * Returns NULL on error (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=11 + */ +extern lto_module_t +lto_module_create_in_local_context(const void *mem, size_t length, + const char *path); + +/** + * \brief Loads an object file in the codegen context. + * + * Loads an object file into the same context as \c cg. The module is safe to + * add using \a lto_codegen_add_module(). + * + * Returns NULL on error (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=11 + */ +extern lto_module_t +lto_module_create_in_codegen_context(const void *mem, size_t length, + const char *path, lto_code_gen_t cg); + +/** + * Loads an object file from disk. The seek point of fd is not preserved. + * Returns NULL on error (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=5 + */ +extern lto_module_t +lto_module_create_from_fd(int fd, const char *path, size_t file_size); + +/** + * Loads an object file from disk. The seek point of fd is not preserved. + * Returns NULL on error (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=5 + */ +extern lto_module_t +lto_module_create_from_fd_at_offset(int fd, const char *path, size_t file_size, + size_t map_size, off_t offset); + +/** + * Frees all memory internally allocated by the module. + * Upon return the lto_module_t is no longer valid. + * + * \since prior to LTO_API_VERSION=3 + */ +extern void +lto_module_dispose(lto_module_t mod); + +/** + * Returns triple string which the object module was compiled under. + * + * \since prior to LTO_API_VERSION=3 + */ +extern const char* +lto_module_get_target_triple(lto_module_t mod); + +/** + * Sets triple string with which the object will be codegened. + * + * \since LTO_API_VERSION=4 + */ +extern void +lto_module_set_target_triple(lto_module_t mod, const char *triple); + +/** + * Returns the number of symbols in the object module. + * + * \since prior to LTO_API_VERSION=3 + */ +extern unsigned int +lto_module_get_num_symbols(lto_module_t mod); + +/** + * Returns the name of the ith symbol in the object module. + * + * \since prior to LTO_API_VERSION=3 + */ +extern const char* +lto_module_get_symbol_name(lto_module_t mod, unsigned int index); + +/** + * Returns the attributes of the ith symbol in the object module. + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_symbol_attributes +lto_module_get_symbol_attribute(lto_module_t mod, unsigned int index); + +/** + * Returns the module's linker options. + * + * The linker options may consist of multiple flags. It is the linker's + * responsibility to split the flags using a platform-specific mechanism. + * + * \since LTO_API_VERSION=16 + */ +extern const char* +lto_module_get_linkeropts(lto_module_t mod); + +/** + * Diagnostic severity. + * + * \since LTO_API_VERSION=7 + */ +typedef enum { + LTO_DS_ERROR = 0, + LTO_DS_WARNING = 1, + LTO_DS_REMARK = 3, // Added in LTO_API_VERSION=10. + LTO_DS_NOTE = 2 +} lto_codegen_diagnostic_severity_t; + +/** + * Diagnostic handler type. + * \p severity defines the severity. + * \p diag is the actual diagnostic. + * The diagnostic is not prefixed by any of severity keyword, e.g., 'error: '. + * \p ctxt is used to pass the context set with the diagnostic handler. + * + * \since LTO_API_VERSION=7 + */ +typedef void (*lto_diagnostic_handler_t)( + lto_codegen_diagnostic_severity_t severity, const char *diag, void *ctxt); + +/** + * Set a diagnostic handler and the related context (void *). + * This is more general than lto_get_error_message, as the diagnostic handler + * can be called at anytime within lto. + * + * \since LTO_API_VERSION=7 + */ +extern void lto_codegen_set_diagnostic_handler(lto_code_gen_t, + lto_diagnostic_handler_t, + void *); + +/** + * Instantiates a code generator. + * Returns NULL on error (check lto_get_error_message() for details). + * + * All modules added using \a lto_codegen_add_module() must have been created + * in the same context as the codegen. + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_code_gen_t +lto_codegen_create(void); + +/** + * \brief Instantiate a code generator in its own context. + * + * Instantiates a code generator in its own context. Modules added via \a + * lto_codegen_add_module() must have all been created in the same context, + * using \a lto_module_create_in_codegen_context(). + * + * \since LTO_API_VERSION=11 + */ +extern lto_code_gen_t +lto_codegen_create_in_local_context(void); + +/** + * Frees all code generator and all memory it internally allocated. + * Upon return the lto_code_gen_t is no longer valid. + * + * \since prior to LTO_API_VERSION=3 + */ +extern void +lto_codegen_dispose(lto_code_gen_t); + +/** + * Add an object module to the set of modules for which code will be generated. + * Returns true on error (check lto_get_error_message() for details). + * + * \c cg and \c mod must both be in the same context. See \a + * lto_codegen_create_in_local_context() and \a + * lto_module_create_in_codegen_context(). + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_bool_t +lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod); + +/** + * Sets the object module for code generation. This will transfer the ownership + * of the module to the code generator. + * + * \c cg and \c mod must both be in the same context. + * + * \since LTO_API_VERSION=13 + */ +extern void +lto_codegen_set_module(lto_code_gen_t cg, lto_module_t mod); + +/** + * Sets if debug info should be generated. + * Returns true on error (check lto_get_error_message() for details). + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_bool_t +lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model); + +/** + * Sets which PIC code model to generated. + * Returns true on error (check lto_get_error_message() for details). + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_bool_t +lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model); + +/** + * Sets the cpu to generate code for. + * + * \since LTO_API_VERSION=4 + */ +extern void +lto_codegen_set_cpu(lto_code_gen_t cg, const char *cpu); + +/** + * Sets the location of the assembler tool to run. If not set, libLTO + * will use gcc to invoke the assembler. + * + * \since LTO_API_VERSION=3 + */ +extern void +lto_codegen_set_assembler_path(lto_code_gen_t cg, const char* path); + +/** + * Sets extra arguments that libLTO should pass to the assembler. + * + * \since LTO_API_VERSION=4 + */ +extern void +lto_codegen_set_assembler_args(lto_code_gen_t cg, const char **args, + int nargs); + +/** + * Adds to a list of all global symbols that must exist in the final generated + * code. If a function is not listed there, it might be inlined into every usage + * and optimized away. + * + * \since prior to LTO_API_VERSION=3 + */ +extern void +lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg, const char* symbol); + +/** + * Writes a new object file at the specified path that contains the + * merged contents of all modules added so far. + * Returns true on error (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=5 + */ +extern lto_bool_t +lto_codegen_write_merged_modules(lto_code_gen_t cg, const char* path); + +/** + * Generates code for all added modules into one native object file. + * This calls lto_codegen_optimize then lto_codegen_compile_optimized. + * + * On success returns a pointer to a generated mach-o/ELF buffer and + * length set to the buffer size. The buffer is owned by the + * lto_code_gen_t and will be freed when lto_codegen_dispose() + * is called, or lto_codegen_compile() is called again. + * On failure, returns NULL (check lto_get_error_message() for details). + * + * \since prior to LTO_API_VERSION=3 + */ +extern const void* +lto_codegen_compile(lto_code_gen_t cg, size_t* length); + +/** + * Generates code for all added modules into one native object file. + * This calls lto_codegen_optimize then lto_codegen_compile_optimized (instead + * of returning a generated mach-o/ELF buffer, it writes to a file). + * + * The name of the file is written to name. Returns true on error. + * + * \since LTO_API_VERSION=5 + */ +extern lto_bool_t +lto_codegen_compile_to_file(lto_code_gen_t cg, const char** name); + +/** + * Runs optimization for the merged module. Returns true on error. + * + * \since LTO_API_VERSION=12 + */ +extern lto_bool_t +lto_codegen_optimize(lto_code_gen_t cg); + +/** + * Generates code for the optimized merged module into one native object file. + * It will not run any IR optimizations on the merged module. + * + * On success returns a pointer to a generated mach-o/ELF buffer and length set + * to the buffer size. The buffer is owned by the lto_code_gen_t and will be + * freed when lto_codegen_dispose() is called, or + * lto_codegen_compile_optimized() is called again. On failure, returns NULL + * (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=12 + */ +extern const void* +lto_codegen_compile_optimized(lto_code_gen_t cg, size_t* length); + +/** + * Returns the runtime API version. + * + * \since LTO_API_VERSION=12 + */ +extern unsigned int +lto_api_version(void); + +/** + * Sets options to help debug codegen bugs. + * + * \since prior to LTO_API_VERSION=3 + */ +extern void +lto_codegen_debug_options(lto_code_gen_t cg, const char *); + +/** + * Initializes LLVM disassemblers. + * FIXME: This doesn't really belong here. + * + * \since LTO_API_VERSION=5 + */ +extern void +lto_initialize_disassembler(void); + +/** + * Sets if we should run internalize pass during optimization and code + * generation. + * + * \since LTO_API_VERSION=14 + */ +extern void +lto_codegen_set_should_internalize(lto_code_gen_t cg, + lto_bool_t ShouldInternalize); + +/** + * \brief Set whether to embed uselists in bitcode. + * + * Sets whether \a lto_codegen_write_merged_modules() should embed uselists in + * output bitcode. This should be turned on for all -save-temps output. + * + * \since LTO_API_VERSION=15 + */ +extern void +lto_codegen_set_should_embed_uselists(lto_code_gen_t cg, + lto_bool_t ShouldEmbedUselists); + +/** + * @} + * @defgroup LLVMCTLTO ThinLTO + * @ingroup LLVMC + * + * @{ + */ + +/** + * Type to wrap a single object returned by ThinLTO. + * + * \since LTO_API_VERSION=18 + */ +typedef struct { + const char *Buffer; + size_t Size; +} LTOObjectBuffer; + +/** + * Instantiates a ThinLTO code generator. + * Returns NULL on error (check lto_get_error_message() for details). + * + * + * The ThinLTOCodeGenerator is not intended to be reuse for multiple + * compilation: the model is that the client adds modules to the generator and + * ask to perform the ThinLTO optimizations / codegen, and finally destroys the + * codegenerator. + * + * \since LTO_API_VERSION=18 + */ +extern thinlto_code_gen_t thinlto_create_codegen(void); + +/** + * Frees the generator and all memory it internally allocated. + * Upon return the thinlto_code_gen_t is no longer valid. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_dispose(thinlto_code_gen_t cg); + +/** + * Add a module to a ThinLTO code generator. Identifier has to be unique among + * all the modules in a code generator. The data buffer stays owned by the + * client, and is expected to be available for the entire lifetime of the + * thinlto_code_gen_t it is added to. + * + * On failure, returns NULL (check lto_get_error_message() for details). + * + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_add_module(thinlto_code_gen_t cg, + const char *identifier, const char *data, + int length); + +/** + * Optimize and codegen all the modules added to the codegenerator using + * ThinLTO. Resulting objects are accessible using thinlto_module_get_object(). + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_process(thinlto_code_gen_t cg); + +/** + * Returns the number of object files produced by the ThinLTO CodeGenerator. + * + * It usually matches the number of input files, but this is not a guarantee of + * the API and may change in future implementation, so the client should not + * assume it. + * + * \since LTO_API_VERSION=18 + */ +extern unsigned int thinlto_module_get_num_objects(thinlto_code_gen_t cg); + +/** + * Returns a reference to the ith object file produced by the ThinLTO + * CodeGenerator. + * + * Client should use \p thinlto_module_get_num_objects() to get the number of + * available objects. + * + * \since LTO_API_VERSION=18 + */ +extern LTOObjectBuffer thinlto_module_get_object(thinlto_code_gen_t cg, + unsigned int index); + +/** + * Sets which PIC code model to generate. + * Returns true on error (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=18 + */ +extern lto_bool_t thinlto_codegen_set_pic_model(thinlto_code_gen_t cg, + lto_codegen_model); + +/** + * @} + * @defgroup LLVMCTLTO_CACHING ThinLTO Cache Control + * @ingroup LLVMCTLTO + * + * These entry points control the ThinLTO cache. The cache is intended to + * support incremental build, and thus needs to be persistent accross build. + * The client enabled the cache by supplying a path to an existing directory. + * The code generator will use this to store objects files that may be reused + * during a subsequent build. + * To avoid filling the disk space, a few knobs are provided: + * - The pruning interval limit the frequency at which the garbage collector + * will try to scan the cache directory to prune it from expired entries. + * Setting to -1 disable the pruning (default). + * - The pruning expiration time indicates to the garbage collector how old an + * entry needs to be to be removed. + * - Finally, the garbage collector can be instructed to prune the cache till + * the occupied space goes below a threshold. + * @{ + */ + +/** + * Sets the path to a directory to use as a cache storage for incremental build. + * Setting this activates caching. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_set_cache_dir(thinlto_code_gen_t cg, + const char *cache_dir); + +/** + * Sets the cache pruning interval (in seconds). A negative value disable the + * pruning. An unspecified default value will be applied, and a value of 0 will + * be ignored. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_set_cache_pruning_interval(thinlto_code_gen_t cg, + int interval); + +/** + * Sets the maximum cache size that can be persistent across build, in terms of + * percentage of the available space on the the disk. Set to 100 to indicate + * no limit, 50 to indicate that the cache size will not be left over half the + * available space. A value over 100 will be reduced to 100, a value of 0 will + * be ignored. An unspecified default value will be applied. + * + * The formula looks like: + * AvailableSpace = FreeSpace + ExistingCacheSize + * NewCacheSize = AvailableSpace * P/100 + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_set_final_cache_size_relative_to_available_space( + thinlto_code_gen_t cg, unsigned percentage); + +/** + * Sets the expiration (in seconds) for an entry in the cache. An unspecified + * default value will be applied. A value of 0 will be ignored. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_set_cache_entry_expiration(thinlto_code_gen_t cg, + unsigned expiration); + +/** + * @} + */ + +/** + * Sets the path to a directory to use as a storage for temporary bitcode files. + * The intention is to make the bitcode files available for debugging at various + * stage of the pipeline. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_set_savetemps_dir(thinlto_code_gen_t cg, + const char *save_temps_dir); + +/** + * Sets the cpu to generate code for. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_set_cpu(thinlto_code_gen_t cg, const char *cpu); + +/** + * Disable CodeGen, only run the stages till codegen and stop. The output will + * be bitcode. + * + * \since LTO_API_VERSION=19 + */ +extern void thinlto_codegen_disable_codegen(thinlto_code_gen_t cg, + lto_bool_t disable); + +/** + * Perform CodeGen only: disable all other stages. + * + * \since LTO_API_VERSION=19 + */ +extern void thinlto_codegen_set_codegen_only(thinlto_code_gen_t cg, + lto_bool_t codegen_only); + +/** + * Parse -mllvm style debug options. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_debug_options(const char *const *options, int number); + +/** + * Test if a module has support for ThinLTO linking. + * + * \since LTO_API_VERSION=18 + */ +extern lto_bool_t lto_module_is_thinlto(lto_module_t mod); + +/** + * Adds a symbol to the list of global symbols that must exist in the final + * generated code. If a function is not listed there, it might be inlined into + * every usage and optimized away. For every single module, the functions + * referenced from code outside of the ThinLTO modules need to be added here. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_add_must_preserve_symbol(thinlto_code_gen_t cg, + const char *name, + int length); + +/** + * Adds a symbol to the list of global symbols that are cross-referenced between + * ThinLTO files. If the ThinLTO CodeGenerator can ensure that every + * references from a ThinLTO module to this symbol is optimized away, then + * the symbol can be discarded. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_add_cross_referenced_symbol(thinlto_code_gen_t cg, + const char *name, + int length); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* LLVM_C_LTO_H */