From 9cf5b49b81615c6ab7b31c6f6c27c46d8dec050c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20P=C3=B6chtrager?= Date: Fri, 23 Oct 2015 19:07:14 +0200 Subject: [PATCH] cctools 877.5 --- .merge.log | 100 ++ README.md | 15 +- cctools/as/driver.c | 5 - cctools/include/Makefile | 2 +- cctools/include/mach-o/loader.h | 4 +- cctools/include/mach/arm/_structs.h | 135 --- cctools/include/stuff/breakout.h | 4 + cctools/include/stuff/bytesex.h | 6 + cctools/include/xar/xar.h | 246 +++++ cctools/libstuff/Makefile.am | 3 +- cctools/libstuff/bytesex.c | 17 + cctools/libstuff/checkout.c | 42 +- cctools/libstuff/emulated.c | 333 +++--- cctools/libstuff/lto.c | 9 +- cctools/libstuff/ofile.c | 22 + cctools/libstuff/swap_headers.c | 11 + cctools/m4/llvm.m4 | 8 +- cctools/man/Makefile | 2 +- cctools/man/as.1 | 7 +- cctools/man/otool.1 | 4 +- cctools/misc/Makefile.am | 10 +- cctools/misc/bitcode_strip.c | 1491 +++++++++++++++++++++++++++ cctools/misc/codesign_allocate.c | 6 + cctools/misc/libtool.c | 96 +- cctools/otool/Makefile.am | 6 +- cctools/otool/main.c | 34 +- cctools/otool/ofile_print.c | 69 +- cctools/otool/ofile_print.h | 15 +- cctools/otool/print_bitcode.c | 228 ++++ cctools/otool/print_objc.c | 3 +- cctools/otool/print_objc2_32bit.c | 23 +- cctools/otool/print_objc2_64bit.c | 21 + tools/create_cctools_merge_patch.sh | 4 +- 33 files changed, 2575 insertions(+), 406 deletions(-) create mode 100644 cctools/include/xar/xar.h create mode 100644 cctools/misc/bitcode_strip.c create mode 100644 cctools/otool/print_bitcode.c diff --git a/.merge.log b/.merge.log index 67f1e1e..dbcd1e5 100644 --- a/.merge.log +++ b/.merge.log @@ -1,3 +1,103 @@ +## cctools 870 -> 877.5 ## + +can't find file to patch at input line 4 +Perhaps you used the wrong -p or --strip option? +The text leading up to this was: +-------------------------- +|diff -Naur ../cctools-870/Makefile ./Makefile +|--- ../cctools-870/Makefile 2015-08-26 07:49:15.000000000 +0200 +|+++ ./Makefile 2015-09-15 03:35:14.000000000 +0200 +-------------------------- +File to patch: +Skip this patch? [y] +Skipping patch. +3 out of 3 hunks ignored +patching file ./as/driver.c +patching file ./include/Makefile +patching file ./include/mach/arm/_structs.h +patching file ./include/mach-o/loader.h +patching file ./include/stuff/breakout.h +patching file ./include/stuff/bytesex.h +Hunk #1 succeeded at 59 (offset 5 lines). +Hunk #2 succeeded at 432 (offset 5 lines). +patching file ./include/xar/xar.h +patching file ./libstuff/bytesex.c +Hunk #1 succeeded at 209 (offset 5 lines). +Hunk #2 succeeded at 2910 (offset 5 lines). +patching file ./libstuff/checkout.c +patching file ./libstuff/lto.c +Hunk #2 succeeded at 139 (offset 11 lines). +Hunk #3 succeeded at 168 (offset 11 lines). +patching file ./libstuff/ofile.c +Hunk #1 succeeded at 4205 (offset 5 lines). +patching file ./libstuff/swap_headers.c +Hunk #1 succeeded at 1172 (offset 5 lines). +Hunk #2 succeeded at 1759 (offset 5 lines). +patching file ./man/Makefile +patching file ./man/as.1 +patching file ./man/bitcode_strip.1 +patching file ./man/otool.1 +can't find file to patch at input line 892 +Perhaps you used the wrong -p or --strip option? +The text leading up to this was: +-------------------------- +|diff -Naur ../cctools-870/misc/Makefile ./misc/Makefile +|--- ../cctools-870/misc/Makefile 2013-12-10 20:28:11.000000000 +0100 +|+++ ./misc/Makefile 2015-03-10 01:33:19.000000000 +0100 +-------------------------- +File to patch: +Skip this patch? [y] +Skipping patch. +7 out of 7 hunks ignored +patching file ./misc/bitcode_strip.c +patching file ./misc/codesign_allocate.c +Hunk #1 succeeded at 372 (offset 20 lines). +patching file ./misc/libtool.c +Hunk #1 succeeded at 211 (offset 3 lines). +Hunk #2 succeeded at 266 (offset 3 lines). +Hunk #3 succeeded at 1524 (offset 10 lines). +Hunk #4 succeeded at 2189 (offset 10 lines). +Hunk #5 succeeded at 2202 (offset 10 lines). +Hunk #6 succeeded at 2214 (offset 10 lines). +Hunk #7 succeeded at 3493 (offset 10 lines). +Hunk #8 succeeded at 3621 (offset 10 lines). +Hunk #9 succeeded at 3700 (offset 10 lines). +Hunk #10 succeeded at 3840 (offset 10 lines). +can't find file to patch at input line 2635 +Perhaps you used the wrong -p or --strip option? +The text leading up to this was: +-------------------------- +|diff -Naur ../cctools-870/otool/Makefile ./otool/Makefile +|--- ../cctools-870/otool/Makefile 2014-01-14 01:21:55.000000000 +0100 +|+++ ./otool/Makefile 2015-03-10 01:33:19.000000000 +0100 +-------------------------- +File to patch: +Skip this patch? [y] +Skipping patch. +1 out of 1 hunk ignored +patching file ./otool/main.c +Hunk #1 succeeded at 1511 (offset 4 lines). +Hunk #2 succeeded at 1553 (offset 4 lines). +patching file ./otool/ofile_print.c +Hunk #1 succeeded at 294 (offset 8 lines). +Hunk #2 succeeded at 2292 (offset 10 lines). +Hunk #3 succeeded at 3502 (offset 10 lines). +Hunk #4 succeeded at 7631 (offset 10 lines). +Hunk #5 succeeded at 7685 (offset 10 lines). +Hunk #6 succeeded at 7701 (offset 10 lines). +Hunk #7 succeeded at 7741 (offset 10 lines). +Hunk #8 succeeded at 7757 (offset 10 lines). +Hunk #9 succeeded at 7772 (offset 10 lines). +Hunk #10 succeeded at 7781 (offset 10 lines). +Hunk #11 succeeded at 7811 (offset 10 lines). +Hunk #12 succeeded at 7826 (offset 10 lines). +Hunk #13 succeeded at 8076 (offset 12 lines). +Hunk #14 succeeded at 8173 (offset 12 lines). +patching file ./otool/ofile_print.h +patching file ./otool/print_bitcode.c +patching file ./otool/print_objc2_32bit.c +patching file ./otool/print_objc2_64bit.c + ## ld64 242.2 -> ld64 253.3 ## patching file ./doc/man/man1/ld.1 diff --git a/README.md b/README.md index 5d21926..3a63205 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Apple cctools port for Linux, *BSD and Windows (Cygwin) # -Current Version: 870 + ld64-242.2. +Current Version: 877.5 + ld64-253.3. Originally ported by [cjacker](http://ios-toolchain-based-on-clang-for-linux.googlecode.com). ## SUPPORTED HOSTS ## @@ -18,19 +18,24 @@ Untested, but compiles: aarch64, ppc, ppc64 -## SUPPORTED TARGETS ## +## SUPPORTED TARGET ARCHITECTURES ## armv4t, armv5, armv6, armv7, armv7f, armv7k, armv7s, armv6m armv7m, armv7em, armv8, arm64, arm64v8, i386, x86_64 and x86_64h. +## SUPPORTED TARGET OPERATING SYSTEMS ## + +Mac OS X, iOS, watchOS (untested), tvOS (untested) + ## DEPENDENCIES ## -`Clang 3.2+ or gcc/g++/gcc-objc 4.6+`, `automake`, `autogen` and `libtool`. +`Clang 3.2+ or gcc/g++/gcc-objc 4.7+`, `automake`, `autogen` and `libtool`. Optional, but recommended: -`llvm-devel` (For Link Time Optimization Support) -`uuid-devel` (For ld64 `-random_uuid` Support) +`llvm-devel` (For Link Time Optimization Support) +`uuid-devel` (For ld64 `-random_uuid` Support) +`llvm-devel` + `xar-devel` (For ld64 `-bitcode_bundle` Support) ## INSTALLATION ## diff --git a/cctools/as/driver.c b/cctools/as/driver.c index 3bf0e7a..4dbe144 100644 --- a/cctools/as/driver.c +++ b/cctools/as/driver.c @@ -270,10 +270,6 @@ char **envp) run_clang = 1; } -#if 0 -/* - * See rdar://9801003 where this will be changed before before NMOs and NMiOS. - */ /* * Use the LLVM integrated assembler as the default with the as(1) * driver for Intel (64-bit & 32-bit) as well as ARM for 32-bit too @@ -283,7 +279,6 @@ char **envp) arch_flag.cputype == CPU_TYPE_I386 || arch_flag.cputype == CPU_TYPE_ARM) run_clang = 1; -#endif /* * Use the clang as the assembler if is the default or asked to with diff --git a/cctools/include/Makefile b/cctools/include/Makefile index 142bdd4..89f45c9 100644 --- a/cctools/include/Makefile +++ b/cctools/include/Makefile @@ -39,7 +39,7 @@ OTHER_SRCS = notes gnu/symseg.h \ coff/base_relocs.h coff/bytesex.h coff/ms_dos_stub.h \ coff/filehdr.h coff/aouthdr.h coff/scnhdr.h coff/syment.h \ coff/debug_directory.h elf/dwarf2.h llvm-c/Disassembler.h \ - $(GAS_OTHER_SRCS) + xar/xar.h $(GAS_OTHER_SRCS) ENCUMBERED_SRCS = gnu/a.out.h gnu/exec.h diff --git a/cctools/include/mach-o/loader.h b/cctools/include/mach-o/loader.h index dd2142f..aba7cb7 100644 --- a/cctools/include/mach-o/loader.h +++ b/cctools/include/mach-o/loader.h @@ -300,6 +300,7 @@ struct load_command { #define LC_ENCRYPTION_INFO_64 0x2C /* 64-bit encrypted segment information */ #define LC_LINKER_OPTION 0x2D /* linker options in MH_OBJECT files */ #define LC_LINKER_OPTIMIZATION_HINT 0x2E /* optimization hints in MH_OBJECT files */ +#define LC_VERSION_MIN_WATCHOS 0x30 /* build for Watch min OS version */ /* * A variable length string in a load command is represented by an lc_str @@ -1201,7 +1202,8 @@ struct encryption_info_command_64 { */ struct version_min_command { uint32_t cmd; /* LC_VERSION_MIN_MACOSX or - LC_VERSION_MIN_IPHONEOS */ + LC_VERSION_MIN_IPHONEOS + LC_VERSION_MIN_WATCHOS */ uint32_t cmdsize; /* sizeof(struct min_version_command) */ uint32_t version; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ diff --git a/cctools/include/mach/arm/_structs.h b/cctools/include/mach/arm/_structs.h index 0c3d756..186a2ef 100644 --- a/cctools/include/mach/arm/_structs.h +++ b/cctools/include/mach/arm/_structs.h @@ -7,7 +7,6 @@ #ifndef _MACH_ARM__STRUCTS_H_ #define _MACH_ARM__STRUCTS_H_ -#if __DARWIN_UNIX03 #define _STRUCT_ARM_EXCEPTION_STATE struct __darwin_arm_exception_state _STRUCT_ARM_EXCEPTION_STATE { @@ -15,17 +14,7 @@ _STRUCT_ARM_EXCEPTION_STATE __uint32_t __fsr; /* Fault status */ __uint32_t __far; /* Virtual Fault Address */ }; -#else /* !__DARWIN_UNIX03 */ -#define _STRUCT_ARM_EXCEPTION_STATE struct arm_exception_state -_STRUCT_ARM_EXCEPTION_STATE -{ - __uint32_t exception; /* number of arm exception taken */ - __uint32_t fsr; /* Fault status */ - __uint32_t far; /* Virtual Fault Address */ -}; -#endif /* __DARWIN_UNIX03 */ -#if __DARWIN_UNIX03 #define _STRUCT_ARM_EXCEPTION_STATE64 struct __darwin_arm_exception_state64 _STRUCT_ARM_EXCEPTION_STATE64 { @@ -33,17 +22,7 @@ _STRUCT_ARM_EXCEPTION_STATE64 __uint32_t __esr; /* Exception syndrome */ __uint32_t __exception; /* number of arm exception taken */ }; -#else /* !__DARWIN_UNIX03 */ -#define _STRUCT_ARM_EXCEPTION_STATE64 struct arm_exception_state64 -_STRUCT_ARM_EXCEPTION_STATE64 -{ - __uint64_t far; /* Virtual Fault Address */ - __uint32_t esr; /* Exception syndrome */ - __uint32_t exception; /* number of arm exception taken */ -}; -#endif /* __DARWIN_UNIX03 */ -#if __DARWIN_UNIX03 #define _STRUCT_ARM_THREAD_STATE struct __darwin_arm_thread_state _STRUCT_ARM_THREAD_STATE { @@ -53,19 +32,7 @@ _STRUCT_ARM_THREAD_STATE __uint32_t __pc; /* Program counter r15 */ __uint32_t __cpsr; /* Current program status register */ }; -#else /* !__DARWIN_UNIX03 */ -#define _STRUCT_ARM_THREAD_STATE struct arm_thread_state -_STRUCT_ARM_THREAD_STATE -{ - __uint32_t r[13]; /* General purpose register r0-r12 */ - __uint32_t sp; /* Stack pointer r13 */ - __uint32_t lr; /* Link register r14 */ - __uint32_t pc; /* Program counter r15 */ - __uint32_t cpsr; /* Current program status register */ -}; -#endif /* __DARWIN_UNIX03 */ -#if __DARWIN_UNIX03 #define _STRUCT_ARM_THREAD_STATE64 struct __darwin_arm_thread_state64 _STRUCT_ARM_THREAD_STATE64 { @@ -76,20 +43,7 @@ _STRUCT_ARM_THREAD_STATE64 __uint64_t __pc; /* Program counter */ __uint32_t __cpsr; /* Current program status register */ }; -#else /* !__DARWIN_UNIX03 */ -#define _STRUCT_ARM_THREAD_STATE64 struct arm_thread_state64 -_STRUCT_ARM_THREAD_STATE64 -{ - __uint64_t x[29]; /* General purpose registers x0-x28 */ - __uint64_t fp; /* Frame pointer x29 */ - __uint64_t lr; /* Link register x30 */ - __uint64_t sp; /* Stack pointer x31 */ - __uint64_t pc; /* Program counter */ - __uint32_t cpsr; /* Current program status register */ -}; -#endif /* __DARWIN_UNIX03 */ -#if __DARWIN_UNIX03 #define _STRUCT_ARM_VFP_STATE struct __darwin_arm_vfp_state _STRUCT_ARM_VFP_STATE { @@ -97,16 +51,7 @@ _STRUCT_ARM_VFP_STATE __uint32_t __fpscr; }; -#else /* !__DARWIN_UNIX03 */ -#define _STRUCT_ARM_VFP_STATE struct arm_vfp_state -_STRUCT_ARM_VFP_STATE -{ - __uint32_t r[64]; - __uint32_t fpscr; -}; -#endif /* __DARWIN_UNIX03 */ -#if __DARWIN_UNIX03 #define _STRUCT_ARM_NEON_STATE64 struct __darwin_arm_neon_state64 #define _STRUCT_ARM_NEON_STATE struct __darwin_arm_neon_state @@ -143,50 +88,11 @@ _STRUCT_ARM_NEON_STATE /* #error Unknown architecture. */ #endif -#else /* !__DARWIN_UNIX03 */ -#define _STRUCT_ARM_NEON_STATE64 struct arm_neon_state64 -#define _STRUCT_ARM_NEON_STATE struct arm_neon_state - -#if defined(__arm64__) -_STRUCT_ARM_NEON_STATE64 -{ - __uint128_t q[32]; - uint32_t fpsr; - uint32_t fpcr; - -}; -_STRUCT_ARM_NEON_STATE -{ - __uint128_t q[16]; - uint32_t fpsr; - uint32_t fpcr; - -}; -#elif defined(__arm__) -/* - * No 128-bit intrinsic for ARM; leave it opaque for now. - */ -_STRUCT_ARM_NEON_STATE64 -{ - char opaque[(32 * 16) + (2 * sizeof(__uint32_t))]; -} __attribute__((aligned(16))); - -_STRUCT_ARM_NEON_STATE -{ - char opaque[(16 * 16) + (2 * sizeof(__uint32_t))]; -} __attribute__((aligned(16))); - -#else -#error Unknown architecture. -#endif - -#endif /* __DARWIN_UNIX03 */ /* * Debug State */ #if defined(__arm__) -#if __DARWIN_UNIX03 #define _STRUCT_ARM_DEBUG_STATE struct __darwin_arm_debug_state _STRUCT_ARM_DEBUG_STATE { @@ -195,19 +101,8 @@ _STRUCT_ARM_DEBUG_STATE __uint32_t __wvr[16]; __uint32_t __wcr[16]; }; -#else /* !__DARWIN_UNIX03 */ -#define _STRUCT_ARM_DEBUG_STATE struct arm_debug_state -_STRUCT_ARM_DEBUG_STATE -{ - __uint32_t bvr[16]; - __uint32_t bcr[16]; - __uint32_t wvr[16]; - __uint32_t wcr[16]; -}; -#endif /* __DARWIN_UNIX03 */ #elif defined(__arm64__) -#if __DARWIN_UNIX03 #define _STRUCT_ARM_LEGACY_DEBUG_STATE struct arm_legacy_debug_state _STRUCT_ARM_LEGACY_DEBUG_STATE { @@ -236,36 +131,6 @@ _STRUCT_ARM_DEBUG_STATE64 __uint64_t __wcr[16]; __uint64_t __mdscr_el1; /* Bit 0 is SS (Hardware Single Step) */ }; -#else /* !__DARWIN_UNIX03 */ -#define _STRUCT_ARM_LEGACY_DEBUG_STATE struct arm_legacy_debug_state -_STRUCT_ARM_LEGACY_DEBUG_STATE -{ - __uint32_t bvr[16]; - __uint32_t bcr[16]; - __uint32_t wvr[16]; - __uint32_t wcr[16]; -}; - -#define _STRUCT_ARM_DEBUG_STATE32 struct arm_debug_state32 -_STRUCT_ARM_DEBUG_STATE32 -{ - __uint32_t bvr[16]; - __uint32_t bcr[16]; - __uint32_t wvr[16]; - __uint32_t wcr[16]; - __uint64_t mdscr_el1; /* Bit 0 is SS (Hardware Single Step) */ -}; - -#define _STRUCT_ARM_DEBUG_STATE64 struct arm_debug_state64 -_STRUCT_ARM_DEBUG_STATE64 -{ - __uint64_t bvr[16]; - __uint64_t bcr[16]; - __uint64_t wvr[16]; - __uint64_t wcr[16]; - __uint64_t mdscr_el1; /* Bit 0 is SS (Hardware Single Step) */ -}; -#endif /* __DARWIN_UNIX03 */ #else /* #error unknown architecture */ diff --git a/cctools/include/stuff/breakout.h b/cctools/include/stuff/breakout.h index faff33c..dec6b38 100644 --- a/cctools/include/stuff/breakout.h +++ b/cctools/include/stuff/breakout.h @@ -148,6 +148,10 @@ struct object { struct twolevel_hints_command /* the two-level namespace hints command */ *hints_cmd; struct prebind_cksum_command *cs;/* the prebind check sum command */ + struct segment_command + *seg_bitcode; /* the 32-bit bitcode segment command */ + struct segment_command_64 + *seg_bitcode64; /* the 64-bit bitcode segment command */ struct segment_command *seg_linkedit; /* the 32-bit link edit segment command */ struct segment_command_64 diff --git a/cctools/include/stuff/bytesex.h b/cctools/include/stuff/bytesex.h index 2e40445..e20228b 100644 --- a/cctools/include/stuff/bytesex.h +++ b/cctools/include/stuff/bytesex.h @@ -59,6 +59,8 @@ #include #include #include +#include "../include/xar/xar.h" /* cctools-port: + force the use of the bundled xar header */ #include "stuff/bool.h" enum byte_sex { @@ -431,6 +433,10 @@ __private_extern__ void swap_data_in_code_entry( uint32_t ndices, enum byte_sex target_byte_sex); +__private_extern__ void swap_xar_header( + struct xar_header *xar, + enum byte_sex target_byte_sex); + /* * swap_object_headers() swaps the object file headers from the host byte sex * into the non-host byte sex. It returns TRUE if it can and did swap the diff --git a/cctools/include/xar/xar.h b/cctools/include/xar/xar.h new file mode 100644 index 0000000..342ae4c --- /dev/null +++ b/cctools/include/xar/xar.h @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2005 Rob Braun + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rob Braun nor the names of his contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * 03-Apr-2005 + * DRI: Rob Braun + */ +/* + * Portions Copyright 2006, Apple Computer, Inc. + * Christopher Ryan + */ + +#ifndef _XAR_H_ +#define _XAR_H_ + +#define XAR_VERSION "1.7dev" + +#include +#include +#include + +#pragma pack(4) + +struct xar_header { + uint32_t magic; + uint16_t size; + uint16_t version; + uint64_t toc_length_compressed; + uint64_t toc_length_uncompressed; + uint32_t cksum_alg; +}; +#pragma pack() +typedef struct xar_header xar_header_t; + +#define XAR_HEADER_MAGIC 0x78617221 +#define XAR_EA_FORK "ea" + +#define XAR_CKSUM_NONE 0 +#define XAR_CKSUM_SHA1 1 +#define XAR_CKSUM_MD5 2 +#define XAR_CKSUM_SHA256 3 +#define XAR_CKSUM_SHA512 4 + +typedef void *xar_errctx_t; +typedef const struct __xar_file_t *xar_file_t; +typedef const struct __xar_iter_t *xar_iter_t; +typedef const struct __xar_t *xar_t; +typedef const struct __xar_subdoc_t *xar_subdoc_t; +typedef const struct __xar_signature_t *xar_signature_t; + +typedef struct { + char *next_out; + unsigned int avail_out; + + unsigned long long total_in; + unsigned long long total_out; + + void *state; +} xar_stream; + +typedef int32_t (*err_handler)(int32_t severit, int32_t instance, xar_errctx_t ctx, void *usrctx); +/* the signed_data must be allocated durring the callback and will be released by the xar lib after the callback */ +typedef int32_t (*xar_signer_callback)(xar_signature_t sig, void *context, uint8_t *data, uint32_t length, uint8_t **signed_data, uint32_t *signed_len); + +#define READ 0 +#define WRITE 1 + +/* xar stream return codes */ +#define XAR_STREAM_OK 0 +#define XAR_STREAM_END 1 +#define XAR_STREAM_ERR -1 + +/* Valid xar options & values */ +#define XAR_OPT_OWNERSHIP "ownership" /* setting owner/group behavior */ +#define XAR_OPT_VAL_SYMBOLIC "symbolic" /* set owner/group based on names */ +#define XAR_OPT_VAL_NUMERIC "numeric" /* set owner/group based on uid/gid */ + +#define XAR_OPT_TOCCKSUM "toc-cksum" /* set the toc checksum algorithm */ +#define XAR_OPT_FILECKSUM "file-chksum" /* set the file checksum algorithm */ +#define XAR_OPT_VAL_NONE "none" +#define XAR_OPT_VAL_SHA1 "sha1" +#define XAR_OPT_VAL_SHA256 "sha256" +#define XAR_OPT_VAL_SHA512 "sha512" +#define XAR_OPT_VAL_MD5 "md5" + +#define XAR_OPT_COMPRESSION "compression" /* set the file compression type */ +#define XAR_OPT_COMPRESSIONARG "compression-arg" /* set the compression opts */ +#define XAR_OPT_VAL_GZIP "gzip" +#define XAR_OPT_VAL_BZIP "bzip2" +#define XAR_OPT_VAL_LZMA "lzma" + +#define XAR_OPT_RSIZE "rsize" /* Read io buffer size */ + +#define XAR_OPT_COALESCE "coalesce" /* Coalesce identical heap blocks */ +#define XAR_OPT_LINKSAME "linksame" /* Hardlink identical files */ + +#define XAR_OPT_PROPINCLUDE "prop-include" /* File property to include */ +#define XAR_OPT_PROPEXCLUDE "prop-exclude" /* File property to exclude */ + +#define XAR_OPT_SAVESUID "savesuid" /* Preserve setuid/setgid bits */ +#define XAR_OPT_VAL_TRUE "true" +#define XAR_OPT_VAL_FALSE "false" + +/* xar signing algorithms */ +#define XAR_SIG_SHA1RSA 1 + + +/* xar error handler macros */ +#define XAR_SEVERITY_DEBUG 1 +#define XAR_SEVERITY_INFO 2 +#define XAR_SEVERITY_NORMAL 3 +#define XAR_SEVERITY_WARNING 4 +#define XAR_SEVERITY_NONFATAL 5 +#define XAR_SEVERITY_FATAL 6 + +#define XAR_ERR_ARCHIVE_CREATION 1 +#define XAR_ERR_ARCHIVE_EXTRACTION 2 + +xar_t xar_open(const char *file, int32_t flags); +int xar_close(xar_t x); +xar_file_t xar_add(xar_t x, const char *path); + +xar_file_t xar_add_frombuffer(xar_t x, xar_file_t parent, const char *name, char *buffer, size_t length); +xar_file_t xar_add_folder(xar_t x, xar_file_t f, const char *name, struct stat *info); +xar_file_t xar_add_frompath(xar_t x, xar_file_t parent, const char *name, const char *realpath); + +xar_file_t xar_add_from_archive(xar_t x, xar_file_t parent, const char *name, xar_t sourcearchive, xar_file_t sourcefile); + +int32_t xar_extract(xar_t x, xar_file_t f); +int32_t xar_extract_tofile(xar_t x, xar_file_t f, const char *path); +int32_t xar_extract_tobuffer(xar_t x, xar_file_t f, char **buffer); +int32_t xar_extract_tobuffersz(xar_t x, xar_file_t f, char **buffer, size_t *size); +int32_t xar_extract_tostream_init(xar_t x, xar_file_t f, xar_stream *stream); +int32_t xar_extract_tostream(xar_stream *stream); +int32_t xar_extract_tostream_end(xar_stream *stream); + +int32_t xar_verify(xar_t x, xar_file_t f); + + +const char *xar_opt_get(xar_t x, const char *option); +int32_t xar_opt_set(xar_t x, const char *option, const char *value); +int32_t xar_opt_unset(xar_t x, const char *option); + +int32_t xar_prop_set(xar_file_t f, const char *key, const char *value); +int32_t xar_prop_create(xar_file_t f, const char *key, const char *value); +int32_t xar_prop_get(xar_file_t f, const char *key, const char **value); + +xar_iter_t xar_iter_new(void); +void xar_iter_free(xar_iter_t i); + +const char *xar_prop_first(xar_file_t f, xar_iter_t i); +const char *xar_prop_next(xar_iter_t i); + +void xar_prop_unset(xar_file_t f, const char *key); +xar_file_t xar_file_first(xar_t x, xar_iter_t i); +xar_file_t xar_file_next(xar_iter_t i); + +const char *xar_attr_get(xar_file_t f, const char *prop, const char *key); +int32_t xar_attr_set(xar_file_t f, const char *prop, const char *key, const char *value); +const char *xar_attr_first(xar_file_t f, const char *prop, xar_iter_t i); +const char *xar_attr_next(xar_iter_t i); + +xar_subdoc_t xar_subdoc_new(xar_t x, const char *name); +int32_t xar_subdoc_prop_set(xar_subdoc_t s, const char *key, const char *value); +int32_t xar_subdoc_prop_get(xar_subdoc_t s, const char *key, const char **value); +int32_t xar_subdoc_attr_set(xar_subdoc_t s, const char *prop, const char *key, const char *value); +const char *xar_subdoc_attr_get(xar_subdoc_t s, const char *prop, const char *key); +xar_subdoc_t xar_subdoc_first(xar_t x); +xar_subdoc_t xar_subdoc_next(xar_subdoc_t s); +const char *xar_subdoc_name(xar_subdoc_t s); +int32_t xar_subdoc_copyout(xar_subdoc_t s, unsigned char **, unsigned int *); +int32_t xar_subdoc_copyin(xar_subdoc_t s, const unsigned char *, unsigned int); +void xar_subdoc_remove(xar_subdoc_t s); + +/* signature api for adding various signature types */ +xar_signature_t xar_signature_new(xar_t x,const char *type, int32_t length, xar_signer_callback callback, void *callback_context); +/* extended signatures are ignored by previous versions of xar */ +xar_signature_t xar_signature_new_extended(xar_t x,const char *type, int32_t length, xar_signer_callback callback, void *callback_context); + +const char *xar_signature_type(xar_signature_t s); + +xar_signature_t xar_signature_first(xar_t x); +xar_signature_t xar_signature_next(xar_signature_t s); + +int32_t xar_signature_add_x509certificate(xar_signature_t sig, const uint8_t *cert_data, uint32_t cert_len ); + +int32_t xar_signature_get_x509certificate_count(xar_signature_t sig); +int32_t xar_signature_get_x509certificate_data(xar_signature_t sig, int32_t index, const uint8_t **cert_data, uint32_t *cert_len); + +uint8_t xar_signature_copy_signed_data(xar_signature_t sig, uint8_t **data, uint32_t *length, uint8_t **signed_data, uint32_t *signed_length, off_t *signed_offset); + +/* Helper functions - caller must free returned memory */ +char *xar_get_size(xar_t x, xar_file_t f); +char *xar_get_type(xar_t x, xar_file_t f); +char *xar_get_mode(xar_t x, xar_file_t f); +char *xar_get_owner(xar_t x, xar_file_t f); +char *xar_get_group(xar_t x, xar_file_t f); +char *xar_get_mtime(xar_t x, xar_file_t f); + +/* For helping calling apps harden against hacked archives that attempt to escape their extraction roots. */ +int xar_path_issane(char* path); + +/* These are for xar modules and should never be needed from a calling app */ +void xar_register_errhandler(xar_t x, err_handler callback, void *usrctx); +xar_t xar_err_get_archive(xar_errctx_t ctx); +xar_file_t xar_err_get_file(xar_errctx_t ctx); +const char *xar_err_get_string(xar_errctx_t ctx); +int xar_err_get_errno(xar_errctx_t ctx); +void xar_err_set_file(xar_t x, xar_file_t f); +void xar_err_set_formatted_string(xar_t x, const char *format, ...); +void xar_err_set_string(xar_t x, const char *str); +void xar_err_set_errno(xar_t x, int e); +void xar_err_new(xar_t x); +int32_t xar_err_callback(xar_t x, int32_t sev, int32_t err); + +void xar_serialize(xar_t x, const char *file); +char *xar_get_path(xar_file_t f); +off_t xar_get_heap_offset(xar_t x); +uint64_t xar_ntoh64(uint64_t num); + +#endif /* _XAR_H_ */ diff --git a/cctools/libstuff/Makefile.am b/cctools/libstuff/Makefile.am index a51d266..31e3e9f 100644 --- a/cctools/libstuff/Makefile.am +++ b/cctools/libstuff/Makefile.am @@ -40,5 +40,6 @@ libstuff_la_SOURCES = \ SymLoc.c \ unix_standard_mode.c \ version_number.c \ - writeout.c + writeout.c \ + coff_bytesex.c diff --git a/cctools/libstuff/bytesex.c b/cctools/libstuff/bytesex.c index 5b3d4e0..65dcdbf 100644 --- a/cctools/libstuff/bytesex.c +++ b/cctools/libstuff/bytesex.c @@ -209,6 +209,8 @@ #include #include #include +#include "../include/xar/xar.h" /* cctools-port: + force the use of the bundled xar header */ #include "stuff/bool.h" #include "stuff/bytesex.h" @@ -2909,3 +2911,18 @@ enum byte_sex target_byte_sex) tocs[i].module_index = SWAP_INT(tocs[i].module_index); } } + +__private_extern__ +void +swap_xar_header( +struct xar_header *xar, +enum byte_sex target_byte_sex) +{ + xar->magic = SWAP_INT(xar->magic); + xar->size = SWAP_SHORT(xar->size); + xar->version = SWAP_SHORT(xar->version); + xar->toc_length_compressed = SWAP_LONG_LONG(xar->toc_length_compressed); + xar->toc_length_uncompressed = + SWAP_LONG_LONG(xar->toc_length_uncompressed); + xar->cksum_alg = SWAP_INT(xar->cksum_alg); +} diff --git a/cctools/libstuff/checkout.c b/cctools/libstuff/checkout.c index 889e0f6..ed4aa5a 100644 --- a/cctools/libstuff/checkout.c +++ b/cctools/libstuff/checkout.c @@ -23,6 +23,8 @@ #ifndef RLD #include #include +#include "../include/xar/xar.h" /* cctools-port: + force the use of the bundled xar header */ #include "stuff/ofile.h" #include "stuff/breakout.h" #include "stuff/rnd.h" @@ -90,6 +92,8 @@ struct object *object) object->st = NULL; object->dyst = NULL; object->hints_cmd = NULL; + object->seg_bitcode = NULL; + object->seg_bitcode64 = NULL; object->seg_linkedit = NULL; object->seg_linkedit64 = NULL; object->code_sig_cmd = NULL; @@ -176,6 +180,12 @@ struct object *object) "one " SEG_LINKEDIT "segment): "); object->seg_linkedit = sg; } + else if(strcmp(sg->segname, "__LLVM") == 0){ + if(object->seg_bitcode != NULL) + fatal_arch(arch, member, "malformed file (more than " + "one __LLVM segment): "); + object->seg_bitcode = sg; + } } else if(lc->cmd == LC_SEGMENT_64){ sg64 = (struct segment_command_64 *)lc; @@ -185,6 +195,12 @@ struct object *object) "one " SEG_LINKEDIT "segment): "); object->seg_linkedit64 = sg64; } + else if(strcmp(sg64->segname, "__LLVM") == 0){ + if(object->seg_bitcode64 != NULL) + fatal_arch(arch, member, "malformed file (more than " + "one __LLVM segment): "); + object->seg_bitcode64 = sg64; + } } else if(lc->cmd == LC_ID_DYLIB){ if(dl_id != NULL) @@ -331,6 +347,16 @@ struct object *object) "be processed) in: "); offset = object->seg_linkedit->fileoff; + + if(object->seg_bitcode != NULL){ + if(object->seg_bitcode->filesize < sizeof(struct xar_header)) + fatal_arch(arch, member, "the __LLVM segment too small " + "(less than sizeof(struct xar_header)) in: "); + if(object->seg_bitcode->fileoff + + object->seg_bitcode->filesize != offset) + fatal_arch(arch, member, "the __LLVM segment not directly " + "before the " SEG_LINKEDIT " segment in: "); + } } else{ if(object->seg_linkedit64 == NULL) @@ -344,6 +370,16 @@ struct object *object) "be processed) in: "); offset = object->seg_linkedit64->fileoff; + + if(object->seg_bitcode64 != NULL){ + if(object->seg_bitcode64->filesize < sizeof(struct xar_header)) + fatal_arch(arch, member, "the __LLVM segment too small " + "(less than sizeof(struct xar_header)) in: "); + if(object->seg_bitcode64->fileoff + + object->seg_bitcode64->filesize != offset) + fatal_arch(arch, member, "the __LLVM segment not directly " + "before the " SEG_LINKEDIT " segment in: "); + } } if(object->dyld_info != NULL){ /* dyld_info starts at beginning of __LINKEDIT */ @@ -407,12 +443,14 @@ struct object *object) offset += object->data_in_code_cmd->datasize; } if(object->code_sign_drs_cmd != NULL){ - if(object->code_sign_drs_cmd->dataoff != offset) + if(object->code_sign_drs_cmd->dataoff != 0 && + object->code_sign_drs_cmd->dataoff != offset) order_error(arch, member, "code signing DRs info out of place"); offset += object->code_sign_drs_cmd->datasize; } if(object->link_opt_hint_cmd != NULL){ - if(object->link_opt_hint_cmd->dataoff != offset) + if(object->link_opt_hint_cmd->dataoff != 0 && + object->link_opt_hint_cmd->dataoff != offset) order_error(arch, member, "linker optimization hint info out " "of place"); offset += object->link_opt_hint_cmd->datasize; diff --git a/cctools/libstuff/emulated.c b/cctools/libstuff/emulated.c index a9e93fb..00b465f 100644 --- a/cctools/libstuff/emulated.c +++ b/cctools/libstuff/emulated.c @@ -6,7 +6,7 @@ #include #include #include -//#include +/* #include */ #include #include #include @@ -27,185 +27,183 @@ int _NSGetExecutablePath(char *epath, unsigned int *size) { #if defined(__FreeBSD__) || defined(__DragonFly__) - int mib[4]; - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PATHNAME; - mib[3] = -1; - size_t cb = *size; - if (sysctl(mib, 4, epath, &cb, NULL, 0) != 0) - return -1; - *size = cb; - return 0; + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + size_t cb = *size; + if (sysctl(mib, 4, epath, &cb, NULL, 0) != 0) + return -1; + *size = cb; + return 0; #elif defined(__OpenBSD__) - int mib[4]; - char **argv; - size_t len; - const char *comm; - int ok = 0; - mib[0] = CTL_KERN; - mib[1] = KERN_PROC_ARGS; - mib[2] = getpid(); - mib[3] = KERN_PROC_ARGV; - if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0) - abort(); - if (!(argv = malloc(len))) - abort(); - if (sysctl(mib, 4, argv, &len, NULL, 0) < 0) - abort(); - comm = argv[0]; - if (*comm == '/' || *comm == '.') { - char *rpath; - if ((rpath = realpath(comm, NULL))) { - strlcpy(epath, rpath, *size); - free(rpath); - ok = 1; + int mib[4]; + char **argv; + size_t len; + const char *comm; + int ok = 0; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = getpid(); + mib[3] = KERN_PROC_ARGV; + if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0) + abort(); + if (!(argv = malloc(len))) + abort(); + if (sysctl(mib, 4, argv, &len, NULL, 0) < 0) + abort(); + comm = argv[0]; + if (*comm == '/' || *comm == '.') + { + char *rpath; + if ((rpath = realpath(comm, NULL))) + { + strlcpy(epath, rpath, *size); + free(rpath); + ok = 1; + } } - } else { - char *sp; - char *xpath = strdup(getenv("PATH")); - char *path = strtok_r(xpath, ":", &sp); - struct stat st; - if (!xpath) - abort(); - while (path) { - snprintf(epath, *size, "%s/%s", path, comm); - if (!stat(epath, &st) && (st.st_mode & S_IXUSR)) { - ok = 1; - break; - } - path = strtok_r(NULL, ":", &sp); + else + { + char *sp; + char *xpath = strdup(getenv("PATH")); + char *path = strtok_r(xpath, ":", &sp); + struct stat st; + if (!xpath) + abort(); + while (path) + { + snprintf(epath, *size, "%s/%s", path, comm); + if (!stat(epath, &st) && (st.st_mode & S_IXUSR)) + { + ok = 1; + break; + } + path = strtok_r(NULL, ":", &sp); + } + free(xpath); + } + free(argv); + if (ok) + { + *size = strlen(epath); + return 0; } - free(xpath); - } - free(argv); - if (ok) { - *size = strlen(epath); - return 0; - } - return -1; -#else - int bufsize = *size; - int ret_size; - ret_size = readlink("/proc/self/exe", epath, bufsize-1); - if (ret_size != -1) - { - *size = ret_size; - epath[ret_size]=0; - return 0; - } - else return -1; +#else + int bufsize = *size; + int ret_size; + ret_size = readlink("/proc/self/exe", epath, bufsize-1); + if (ret_size != -1) + { + *size = ret_size; + epath[ret_size]=0; + return 0; + } + else + return -1; #endif } -kern_return_t mach_timebase_info( mach_timebase_info_t info) { - info->numer = 1; - info->denom = 1; - return 0; -} - char *mach_error_string(mach_error_t error_value) { - return "Unknown mach error"; + return "Unknown mach error"; } mach_port_t mach_host_self(void) { - return 0; + return 0; } -kern_return_t host_info -( - host_t host, - host_flavor_t flavor, - host_info_t host_info_out, - mach_msg_type_number_t *host_info_outCnt - ) +kern_return_t host_info(host_t host, host_flavor_t flavor, + host_info_t host_info_out, + mach_msg_type_number_t *host_info_outCnt) { - if(flavor == HOST_BASIC_INFO) { - host_basic_info_t basic_info; + if (flavor == HOST_BASIC_INFO) + { + host_basic_info_t basic_info; - basic_info = (host_basic_info_t) host_info_out; - memset(basic_info, 0x00, sizeof(*basic_info)); - basic_info->cpu_type = EMULATED_HOST_CPU_TYPE; - basic_info->cpu_subtype = EMULATED_HOST_CPU_SUBTYPE; - } + basic_info = (host_basic_info_t) host_info_out; + memset(basic_info, 0x00, sizeof(*basic_info)); + basic_info->cpu_type = EMULATED_HOST_CPU_TYPE; + basic_info->cpu_subtype = EMULATED_HOST_CPU_SUBTYPE; + } return 0; } mach_port_t mach_task_self_ = 0; -kern_return_t mach_port_deallocate -( - ipc_space_t task, - mach_port_name_t name - ) +kern_return_t mach_port_deallocate(ipc_space_t task, mach_port_name_t name) { - return 0; + return 0; } -kern_return_t vm_allocate -( - vm_map_t target_task, - vm_address_t *address, - vm_size_t size, - int flags - ) +kern_return_t vm_allocate(vm_map_t target_task, vm_address_t *address, + vm_size_t size, int flags) { - vm_address_t addr = 0; + vm_address_t addr = 0; - addr = (vm_address_t)calloc(size, sizeof(char)); - if(addr == 0) - return 1; + addr = (vm_address_t)calloc(size, sizeof(char)); - *address = addr; + if (addr == 0) + return 1; - return 0; + *address = addr; + + return 0; } -kern_return_t vm_deallocate -( - vm_map_t target_task, - vm_address_t address, - vm_size_t size - ) +kern_return_t vm_deallocate(vm_map_t target_task, + vm_address_t address, vm_size_t size) { - // free((void *)address); leak it here - - return 0; -} -kern_return_t host_statistics ( host_t host_priv, host_flavor_t flavor, host_info_t host_info_out, mach_msg_type_number_t *host_info_outCnt) -{ - return ENOTSUP; -} -kern_return_t map_fd( - int fd, - vm_offset_t offset, - vm_offset_t *va, - boolean_t findspace, - vm_size_t size) -{ - void *addr = NULL; - addr = mmap(0, size, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_FILE, fd, offset); - if(addr == (void *)-1) { - return 1; - } - *va = (vm_offset_t)addr; - return 0; + /* free((void *)address); leak it here */ + return 0; } -uint64_t mach_absolute_time(void) { - uint64_t t = 0; - struct timeval tv; - if (gettimeofday(&tv,NULL)) return t; - t = ((uint64_t)tv.tv_sec << 32) | tv.tv_usec; - return t; +kern_return_t host_statistics (host_t host_priv, host_flavor_t flavor, + host_info_t host_info_out, + mach_msg_type_number_t *host_info_outCnt) +{ + return ENOTSUP; } +kern_return_t map_fd(int fd, vm_offset_t offset, vm_offset_t *va, + boolean_t findspace, vm_size_t size) +{ + void *addr = NULL; + addr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FILE, fd, offset); + if (addr == (void *)-1) + return 1; + *va = (vm_offset_t)addr; + return 0; +} + +uint64_t mach_absolute_time(void) +{ + struct timeval tv; + if (gettimeofday(&tv, NULL)) + return 0; + return (tv.tv_sec*1000000ULL)+tv.tv_usec; +} + +kern_return_t mach_timebase_info(mach_timebase_info_t info) +{ + info->numer = 1000; + info->denom = 1; + return 0; +} + +int getattrlist(const char *a,void *b, void *c, size_t d, unsigned int e) +{ + errno = ENOTSUP; + return -1; +} + +vm_size_t vm_page_size = 4096; /* hardcoded to match expectations of darwin */ + #ifndef HAVE_STRMODE #include @@ -213,8 +211,7 @@ uint64_t mach_absolute_time(void) { #include #include -void -strmode(/* mode_t */ int mode, char *p) +void strmode(/* mode_t */ int mode, char *p) { /* print type */ switch (mode & S_IFMT) { @@ -324,16 +321,6 @@ strmode(/* mode_t */ int mode, char *p) } #endif -int getattrlist(const char* a,void* b,void* c,size_t d,unsigned int e) -{ - errno = ENOTSUP; - return -1; -} - -vm_size_t vm_page_size = 4096; // hardcoded to match expectations of darwin - - - /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ /* @@ -355,36 +342,34 @@ vm_size_t vm_page_size = 4096; // hardcoded to match expectations of darwi #include #include - /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ -size_t -strlcpy(char *dst, const char *src, size_t siz) +size_t strlcpy(char *dst, const char *src, size_t siz) { - char *d = dst; - const char *s = src; - size_t n = siz; + char *d = dst; + const char *s = src; + size_t n = siz; - /* Copy as many bytes as will fit */ - if (n != 0) { - while (--n != 0) { - if ((*d++ = *s++) == '\0') - break; - } + /* Copy as many bytes as will fit */ + if (n != 0) { + while (--n != 0) { + if ((*d++ = *s++) == '\0') + break; } + } - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } - return(s - src - 1); /* count does not include NUL */ + return(s - src - 1); /* count does not include NUL */ } #endif /* __APPLE__ */ diff --git a/cctools/libstuff/lto.c b/cctools/libstuff/lto.c index 2eee168..319e142 100644 --- a/cctools/libstuff/lto.c +++ b/cctools/libstuff/lto.c @@ -20,6 +20,8 @@ static int tried_to_load_lto = 0; static void *lto_handle = NULL; static int (*lto_is_object)(const void* mem, size_t length) = NULL; static lto_module_t (*lto_create)(const void* mem, size_t length) = NULL; +static lto_module_t (*lto_create_local)(const void* mem, size_t length, + const char *path) = NULL; static void (*lto_dispose)(void *mod) = NULL; static char * (*lto_get_target)(void *mod) = NULL; static uint32_t (*lto_get_num_symbols)(void *mod) = NULL; @@ -137,6 +139,8 @@ void **pmod) /* maybe NULL */ lto_is_object = dlsym(lto_handle, "lto_module_is_object_file_in_memory"); lto_create = dlsym(lto_handle, "lto_module_create_from_memory"); + lto_create_local = dlsym(lto_handle, + "lto_module_create_in_local_context"); lto_dispose = dlsym(lto_handle, "lto_module_dispose"); lto_get_target = dlsym(lto_handle, "lto_module_get_target_triple"); lto_get_num_symbols = dlsym(lto_handle, @@ -164,7 +168,10 @@ void **pmod) /* maybe NULL */ if(!lto_is_object(addr, size)) return(0); - mod = lto_create(addr, size); + if(lto_create_local) + mod = lto_create_local(addr, size, "is_llvm_bitcode_from_memory"); + else + mod = lto_create(addr, size); if(mod == NULL) return(0); diff --git a/cctools/libstuff/ofile.c b/cctools/libstuff/ofile.c index 6e3859f..d87e68f 100644 --- a/cctools/libstuff/ofile.c +++ b/cctools/libstuff/ofile.c @@ -4205,6 +4205,28 @@ check_linkedit_data_command: break; + case LC_VERSION_MIN_WATCHOS: + if(l.cmdsize < sizeof(struct version_min_command)){ + Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_" + "WATCHOS cmdsize too small) in command %u",i); + goto return_bad; + } + if(vers != NULL){ + Mach_O_error(ofile, "malformed object (more than one " + "LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_MACOSX or " + "LC_VERSION_MIN_WATCHOS command)"); + goto return_bad; + } + vers = (struct version_min_command *)lc; + if(swapped) + swap_version_min_command(vers, host_byte_sex); + if(vers->cmdsize < sizeof(struct version_min_command)){ + Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_" + "WATCHOS command %u has too small cmdsize field)", i); + goto return_bad; + } + break; + case LC_ENCRYPTION_INFO: if(l.cmdsize < sizeof(struct encryption_info_command)){ Mach_O_error(ofile, "malformed object (LC_ENCRYPTION_INFO " diff --git a/cctools/libstuff/swap_headers.c b/cctools/libstuff/swap_headers.c index ab3b13d..3e1a8ac 100644 --- a/cctools/libstuff/swap_headers.c +++ b/cctools/libstuff/swap_headers.c @@ -1172,6 +1172,16 @@ check_dylinker_command: break; + case LC_VERSION_MIN_WATCHOS: + vc = (struct version_min_command *)lc; + if(vc->cmdsize != sizeof(struct version_min_command)){ + error("in swap_object_headers(): malformed load commands " + "(LC_VERSION_MIN_WATCHOS command %lu has incorrect " + "cmdsize", i); + return(FALSE); + } + break; + case LC_RPATH: rpath = (struct rpath_command *)lc; if(rpath->cmdsize < sizeof(struct rpath_command)){ @@ -1749,6 +1759,7 @@ check_dylinker_command: case LC_VERSION_MIN_MACOSX: case LC_VERSION_MIN_IPHONEOS: + case LC_VERSION_MIN_WATCHOS: vc = (struct version_min_command *)lc; swap_version_min_command(vc, target_byte_sex); break; diff --git a/cctools/m4/llvm.m4 b/cctools/m4/llvm.m4 index 29dafca..5cb41a1 100644 --- a/cctools/m4/llvm.m4 +++ b/cctools/m4/llvm.m4 @@ -1,16 +1,16 @@ AC_DEFUN([CHECK_LLVM], [ - AC_ARG_ENABLE([lto], - AS_HELP_STRING([--enable-lto], + AC_ARG_ENABLE([lto-support], + AS_HELP_STRING([--enable-lto-support], [enable link time optimization support]), - [], [enable_lto=yes]) + [], [enable_lto_support=yes]) AC_ARG_WITH([llvm-config], AS_HELP_STRING([--with-llvm-config], [llvm config tool]), [LLVM_CONFIG=$with_llvm_config], [LLVM_CONFIG=no]) - if test "x$enable_lto" = "xyes"; then + if test "x$enable_lto_support" = "xyes"; then if test "x$LLVM_CONFIG" = "xno"; then AC_PATH_PROGS(LLVM_CONFIG, [llvm-config \ diff --git a/cctools/man/Makefile b/cctools/man/Makefile index 5be1575..3936d84 100644 --- a/cctools/man/Makefile +++ b/cctools/man/Makefile @@ -9,7 +9,7 @@ OS_MAN1 = strings.1 lipo.1 COMMON_MAN1 = as.1 nm.1 otool.1 ranlib.1 segedit.1 size.1 \ strip.1 libtool.1 cmpdylib.1 pagestuff.1 \ redo_prebinding.1 nmedit.1 install_name_tool.1 \ - codesign_allocate.1 ctf_insert.1 + codesign_allocate.1 ctf_insert.1 bitcode_strip.1 DEAD = gprof.1 DYLD_MAN3 = dyld.3 NSModule.3 NSObjectFileImage.3 dyld_debug.3 diff --git a/cctools/man/as.1 b/cctools/man/as.1 index f4b8245..d3eb31f 100644 --- a/cctools/man/as.1 +++ b/cctools/man/as.1 @@ -1,4 +1,4 @@ -.TH AS 1 "March 20, 2014" "Apple Inc." +.TH AS 1 "February 12, 2015" "Apple Inc." .SH NAME as \- Mac OS X Mach-O GNU-based assemblers .SH SYNOPSIS @@ -173,9 +173,10 @@ such temporary labels. Use the .IR clang (1) integrated assembler instead of the GNU based system assembler. This is -available for the x86 and arm architectures. +the default for the x86 and arm architectures. +.TP .B \-Q -Used the GNU based system assembler. +Use the GNU based system assembler. .SH "Assembler options for the PowerPC processors" .TP .B \-static_branch_prediction_Y_bit diff --git a/cctools/man/otool.1 b/cctools/man/otool.1 index ab11faf..b659573 100644 --- a/cctools/man/otool.1 +++ b/cctools/man/otool.1 @@ -1,4 +1,4 @@ -.TH OTOOL 1 "October 15, 2014" "Apple Inc." +.TH OTOOL 1 "March 19, 2015" "Apple Inc." .SH NAME otool \- object file displaying tool .SH SYNOPSIS @@ -154,7 +154,7 @@ When doing disassembly using the llvm disassembler use the cpu When doing disassembly print the decimal offset from the last label printed. .TP .B \-j -When doing disassembly print the print the opcode bytes of the instructions. +When doing disassembly print the opcode bytes of the instructions. .TP .B \-Q Use diff --git a/cctools/misc/Makefile.am b/cctools/misc/Makefile.am index 73f4da1..c0b7be8 100644 --- a/cctools/misc/Makefile.am +++ b/cctools/misc/Makefile.am @@ -15,7 +15,8 @@ bin_PROGRAMS = \ segedit \ pagestuff \ ranlib \ - codesign_allocate + codesign_allocate \ + bitcode_strip LDADD = \ $(top_builddir)/libstuff/libstuff.la \ @@ -38,11 +39,10 @@ indr_SOURCES = indr.c strip_SOURCES = strip.c nmedit_SOURCES = strip.c nmedit_CFLAGS = -DNMEDIT $(AM_CFLAGS) - segedit_SOURCES = segedit.c -pagestuff_SOURCES=pagestuff.c - +pagestuff_SOURCES = pagestuff.c ranlib_SOURCES = libtool.c ranlib_CFLAGS = -DRANLIB $(AM_CFLAGS) codesign_allocate_SOURCES = codesign_allocate.c - +bitcode_strip_SOURCES= bitcode_strip.c +bitcode_strip_CFLAGS = -DALLOW_ARCHIVES $(AM_CFLAGS) diff --git a/cctools/misc/bitcode_strip.c b/cctools/misc/bitcode_strip.c new file mode 100644 index 0000000..cbfd67b --- /dev/null +++ b/cctools/misc/bitcode_strip.c @@ -0,0 +1,1491 @@ +/* + * Copyright (c) 2015 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include +#include "stuff/bool.h" +#include "stuff/errors.h" +#include "stuff/breakout.h" +#include "stuff/allocate.h" +#include "stuff/rnd.h" + +/* used by error routines as the name of the program */ +char *progname = NULL; + +static enum bool rflag = FALSE; /* remove bitcode segment */ +static enum bool mflag = FALSE; /* remove bitcode but leave a marker segment */ +static enum bool lflag = FALSE; /* leave only bitcode segment */ + +/* + * We shortcut bitcode_strip(1) to do nothing with the -r option when there is + * no bitcode and the input file is the same as the output file. The this will + * get set to TRUE by strip_bitcode_segment() if it sees any slice containing + * bitcode. + */ +static enum bool some_slice_has_bitcode = FALSE; + +static void usage( + void); + +static void process( + struct arch *archs, + uint32_t narchs); + +static enum bool check_object( + struct arch *arch, + struct object *object); + +static void strip_bitcode_segment( + struct arch *arch, + struct object *object); + +static void leave_just_bitcode_segment( + struct arch *arch, + struct object *object); + +static void strip_bitcode_from_load_commands( + struct arch *arch, + struct object *object); + +static void leave_only_bitcode_load_commands( + struct arch *arch, + struct object *object); + +static void reset_pointers_for_object_load_commands( + struct arch *arch, + struct object *object); + +/* + * The bitcode_strip(1) program takes one of two options: + * -r remove the bitcode segment + * -l leave only the bitcode segment if present (or leave the file the same). + * and operates on a single input file and writes to a specified output file + * with the "-o output" argument. + */ +int +main( +int argc, +char **argv, +char **envp) +{ + uint32_t i; + char *input, *output; + struct arch *archs; + uint32_t narchs; + + progname = argv[0]; + input = NULL; + output = NULL; + archs = NULL; + narchs = 0; + for(i = 1; i < argc; i++){ + if(strcmp(argv[i], "-o") == 0){ + if(i + 1 == argc){ + error("missing argument(s) to: %s option", argv[i]); + usage(); + } + if(output != NULL){ + error("more than one: %s option specified", argv[i]); + usage(); + } + output = argv[i+1]; + i++; + } + else if(strcmp(argv[i], "-l") == 0){ + if(rflag == TRUE || mflag == TRUE){ + error("only one of -r, -m or -l can be specified"); + usage(); + } + lflag = TRUE; + } + else if(strcmp(argv[i], "-r") == 0){ + if(lflag == TRUE || mflag == TRUE){ + error("only one of -r, -m or -l can be specified"); + usage(); + } + rflag = TRUE; + } + else if(strcmp(argv[i], "-m") == 0){ + if(lflag == TRUE || rflag == TRUE){ + error("only one of -r, -m or -l can be specified"); + usage(); + } + mflag = TRUE; + } + else{ + if(input != NULL){ + error("more than one input file specified (%s and %s)", + argv[i], input); + usage(); + } + input = argv[i]; + } + } + if(rflag == FALSE && mflag == FALSE && lflag == FALSE){ + error("one of -r, -m or -l must specified"); + usage(); + } + if(input == NULL || output == NULL) + usage(); + + breakout(input, &archs, &narchs, FALSE); + if(errors) + exit(EXIT_FAILURE); + + checkout(archs, narchs); + + process(archs, narchs); + + /* + * We shortcut bitcode_strip(1) to do nothing with the -r option when + * there is no bitcode and the input file is the same as the output + * file. + */ + if(rflag && some_slice_has_bitcode == FALSE && + strcmp(input, output) == 0) + return(EXIT_SUCCESS); + + writeout(archs, narchs, output, 0777, TRUE, FALSE, FALSE, NULL); + + if(errors) + return(EXIT_FAILURE); + else + return(EXIT_SUCCESS); +} + +/* + * usage() prints the current usage message and exits indicating failure. + */ +static +void +usage( +void) +{ + fprintf(stderr, "Usage: %s input [-r | -m | -l] -o output\n", progname); + exit(EXIT_FAILURE); +} + +/* + * process() drives the work to strip or leave the bitcode segment from each + * architecture slice. The arch must be a fully linked Mach-O file and not + * an archive. + */ +static +void +process( +struct arch *archs, +uint32_t narchs) +{ + uint32_t i; +#ifdef ALLOW_ARCHIVES + uint32_t j, offset, size; +#endif + struct object *object; + + for(i = 0; i < narchs; i++){ + if(archs[i].type == OFILE_ARCHIVE){ +#ifndef ALLOW_ARCHIVES + error_arch(archs + i, NULL, "input file must be a linked " + "Mach-O file not an archive: "); + return; +#else /* defined(ALLOW_ARCHIVES) */ + for(j = 0; j < archs[i].nmembers; j++){ + if(archs[i].members[j].type == OFILE_Mach_O){ + object = archs[i].members[j].object; + if(check_object(archs + i, object) == FALSE) + return; + if(rflag || (object->seg_bitcode == NULL && + object->seg_bitcode64 == NULL)) + strip_bitcode_segment(archs + i, object); + else + leave_just_bitcode_segment(archs + i, object); + } + } + /* + * Reset the library offsets and size. + */ + offset = 0; + for(j = 0; j < archs[i].nmembers; j++){ + archs[i].members[j].offset = offset; + size = 0; + if(archs[i].members[j].member_long_name == TRUE){ + size = rnd(archs[i].members[j].member_name_size, + sizeof(int32_t)); + archs[i].toc_long_name = TRUE; + } + if(archs[i].members[j].object != NULL){ + size += archs[i].members[j].object->object_size + - archs[i].members[j].object->input_sym_info_size + + archs[i].members[j].object->output_sym_info_size; + sprintf(archs[i].members[j].ar_hdr->ar_size, "%-*ld", + (int)sizeof(archs[i].members[j].ar_hdr->ar_size), + (long)(size)); + /* + * This has to be done by hand because sprintf puts a + * null at the end of the buffer. + */ + memcpy(archs[i].members[j].ar_hdr->ar_fmag, ARFMAG, + (int)sizeof(archs[i].members[j].ar_hdr->ar_fmag)); + } + else{ + size += archs[i].members[j].unknown_size; + } + offset += sizeof(struct ar_hdr) + size; + } + archs[i].library_size = offset; +#endif /* defined(ALLOW_ARCHIVES) */ + } + else if(archs[i].type == OFILE_Mach_O){ + object = archs[i].object; + if(check_object(archs +i, object) == FALSE) + return; + if(rflag || mflag || (object->seg_bitcode == NULL && + object->seg_bitcode64 == NULL)) + strip_bitcode_segment(archs + i, object); + else + leave_just_bitcode_segment(archs + i, object); + } + } +} + +/* + * check_object() checks to make sure the object is one that can processed for + * stripping the bitcode segment or just leaving only the bitcode segment. + * This must be a fully linked Mach-O file for use with the dynamic linker. + * And if built for the Watch OS it must have a bitcode segment. + * And the bitcode segment must not have any relocation entries or symbols + * defined it its sections. And its sections must be of type S_REGULAR. + */ +static +enum bool +check_object( +struct arch *arch, +struct object *object) +{ + uint32_t i, mh_ncmds, mh_flags; + struct load_command *lc; + struct segment_command *sg; + struct segment_command_64 *sg64; + uint32_t section_ordinal, first_bitcode_section_ordinal, + last_bitcode_section_ordinal; + struct nlist *symbols; + struct nlist_64 *symbols64; + struct section *s; + struct section_64 *s64; + + sg64 = NULL; /* cctools-port */ + + + if(arch->object->mh != NULL){ + mh_ncmds = arch->object->mh->ncmds; + mh_flags = object->mh->flags; + } + else{ + mh_ncmds = arch->object->mh64->ncmds; + mh_flags = object->mh64->flags; + } + + if((mh_flags & MH_DYLDLINK) != MH_DYLDLINK) + fatal_arch(arch, NULL, "can't be used on a file not built for use " + "with the dynamic linker: "); + + /* + * If it has a bitcode segment it can't have any relocation entries. + * + * The SG_NORELOC segment flag should have been set for the bitcode + * segments created with ld(1)'s -sectcreate option but are currently + * not. + * + * To check this in fully linked images one would have to look in + * the dyld info for any binding from these sections. Older systems + * had these off the LC_DYSYMTAB in nextrel and nlocrel but likely + * binaries from older system would not be used with this program. + */ + + /* + * If it has a bitcode segment it can't have any symbols defined in + * the sections of that segment. + */ + if(object->seg_bitcode != NULL || object->seg_bitcode64 != NULL){ + section_ordinal = 1; + first_bitcode_section_ordinal = 0; + lc = arch->object->load_commands; + for(i = 0; i < mh_ncmds && first_bitcode_section_ordinal == 0; i++){ + if(lc->cmd == LC_SEGMENT){ + sg = (struct segment_command *)lc; + if(sg == object->seg_bitcode && sg->nsects > 0){ + first_bitcode_section_ordinal = section_ordinal; + last_bitcode_section_ordinal = section_ordinal + + sg->nsects; + } + section_ordinal += sg64->nsects; + } + else if(lc->cmd == LC_SEGMENT_64){ + sg64 = (struct segment_command_64 *)lc; + if(sg64 == object->seg_bitcode64 && sg64->nsects > 0){ + first_bitcode_section_ordinal = section_ordinal; + last_bitcode_section_ordinal = section_ordinal + + sg64->nsects; + } + section_ordinal += sg64->nsects; + } + lc = (struct load_command *)((char *)lc + lc->cmdsize); + } + if(first_bitcode_section_ordinal != 0){ + if(object->seg_bitcode != NULL){ + symbols = (struct nlist *) + (object->object_addr + object->st->symoff); + for(i = 0; i < object->st->nsyms; i++){ + if((symbols[i].n_type & N_TYPE) == N_SECT && + symbols[i].n_sect >= first_bitcode_section_ordinal && + symbols[i].n_sect < last_bitcode_section_ordinal){ + fatal_arch(arch, NULL, "bitcode segment can't have " + "symbols defined it its sections in: "); + } + } + } + else{ + symbols64 = (struct nlist_64 *) + (object->object_addr + object->st->symoff); + for(i = 0; i < object->st->nsyms; i++){ + if((symbols64[i].n_type & N_TYPE) == N_SECT && + symbols64[i].n_sect >= + first_bitcode_section_ordinal && + symbols64[i].n_sect < last_bitcode_section_ordinal){ + fatal_arch(arch, NULL, "bitcode segment can't have " + "symbols defined it its sections in: "); + } + } + } + } + } + + /* + * Also all the sections in the bitcode segment should be of type + * S_REGULAR. + */ + if(object->seg_bitcode != NULL){ + s = (struct section *)((char *)object->seg_bitcode + + sizeof(struct segment_command)); + for(i = 0; i < object->seg_bitcode->nsects; i++){ + if((s->flags & SECTION_TYPE) != S_REGULAR) + fatal_arch(arch, NULL, "bitcode segment can't have " + "sections that are not of type S_REGULAR in: "); + s++; + } + } + else if(object->seg_bitcode64 != NULL){ + s64 = (struct section_64 *)((char *)object->seg_bitcode64 + + sizeof(struct segment_command_64)); + for(i = 0; i < object->seg_bitcode64->nsects; i++){ + if((s64->flags & SECTION_TYPE) != S_REGULAR) + fatal_arch(arch, NULL, "bitcode segment can't have " + "sections that are not of type S_REGULAR in: "); + s64++; + } + } + + /* + * If the lflag is used on a file without a bitcode segment then + * then the code in process() will call strip_bitcode_segment() and + * not leave_just_bitcode_segment() and strip_bitcode_segment() will + * just pass the object through essentially unchanged. + */ +#if 0 + if(lflag == TRUE && + object->seg_bitcode == NULL && object->seg_bitcode64 == NULL) + fatal_arch(arch, NULL, "-l to leave only bitcode segment can't be " + "used on a file without a __LLVM segment: "); +#endif + + return(TRUE); +} + +/* + * strip_bitcode_segment() is called when there is a bitcode segment or not. + * If there is a bitcode segment it is removed and the offsets are adjusted. + * In this case the code signature is also removed. It has been previously + * checked that the bitcode segment is directly before the link edit segment. + * + * This is also called when we want to remove the bitcode segment and leave + * just a marker, the -m flag. In this case we leave an __LLVM segment with + * the first section with just one zero byte and the __LLVM segment the size of + * the segment rounding. + * + * If there is no bitcode segment the linkedit information including the + * code signature info is set up to be written out so this arch is essentially + * unchanged. + */ +static +void +strip_bitcode_segment( +struct arch *arch, +struct object *object) +{ + uint32_t start_offset, offset, end_of_string_table, alignment_padding; + uint32_t dyld_info_start; + uint32_t dyld_info_end; + enum bool has_bitcode; + + const struct arch_flag *arch_flag; + uint32_t i, segalign, bitcode_marker_size, sect_offset; + struct section *s; + struct section_64 *s64; + + segalign = 0; /* cctools-port */ + + /* + * If we are removing the bitcode segment and leaving just a marker + * calculate a minimum sized segment contents with all zeros which + * usually will be the segment alignment. + */ + if(mflag){ + arch_flag = get_arch_family_from_cputype(object->mh_cputype); + if(arch_flag != NULL) + segalign = get_segalign_from_flag(arch_flag); + else + segalign = 0x4000; /* 16K */ + } + + /* + * To get the right amount of the start of the file copied out by + * writeout() before the symbolic information for this case when we + * are stripping out the bitcode segment we reduce the object size by + * the size of the bitcode segment which is just before the linkedit + * segment. Then this size minus the size of the input symbolic + * information is copied out from the input file to the output file. + * + * This routine also handles objects without bitcode segments and + * just passes the object through essentially unchanged in this case. + * + * Also adjust the file offsets of the link edit information which is + * where the output symbolic information will start in the output file. + */ + has_bitcode = FALSE; + if(object->mh != NULL){ + if(object->seg_bitcode) { + has_bitcode = TRUE; + object->object_size -= object->seg_bitcode->filesize; + object->seg_linkedit->fileoff -= object->seg_bitcode->filesize; + } + object->input_sym_info_size = object->seg_linkedit->filesize; + start_offset = object->seg_linkedit->fileoff; + + /* + * If we have bitcode and are replacing it with just a marker + * then set up the segment and first section to point to the + * minimum sized zero'ed out segment. The first section is to be 1 + * byte in size and the rest are zero sized. + */ + if(has_bitcode && mflag){ + if(object->seg_bitcode->filesize >= segalign) + bitcode_marker_size = segalign; + else + bitcode_marker_size = object->seg_bitcode->filesize; + object->output_new_content = allocate(bitcode_marker_size); + memset(object->output_new_content, '\0', bitcode_marker_size); + object->output_new_content_size = bitcode_marker_size; + + object->seg_bitcode->filesize = bitcode_marker_size; + object->seg_bitcode->fileoff = start_offset; + /* Note we are leaving the vmsize unchanged */ + + sect_offset = object->seg_bitcode->fileoff; + s = (struct section *)((char *)object->seg_bitcode + + sizeof(struct segment_command)); + if(object->seg_bitcode->nsects > 0){ + s->offset = sect_offset; + s->size = bitcode_marker_size > 0 ? 1 : 0; + s++; + } + for(i = 1; i < object->seg_bitcode->nsects; i++){ + s->offset = 0; + s->size = 0; + s++; + } + + object->seg_linkedit->fileoff += object->seg_bitcode->filesize; + start_offset += object->seg_bitcode->filesize; + } + } + else{ + if(object->seg_bitcode64 != NULL){ + has_bitcode = TRUE; + object->object_size -= object->seg_bitcode64->filesize; + object->seg_linkedit64->fileoff -= + object->seg_bitcode64->filesize; + } + object->input_sym_info_size = object->seg_linkedit64->filesize; + start_offset = object->seg_linkedit64->fileoff; + + /* + * If we have bitcode and are replacing it with just a marker + * then set up the segment and first section to point to the + * minimum sized zero'ed out segment. The first section is to be 1 + * byte in size and the rest are zero sized. + */ + if(has_bitcode && mflag){ + if(object->seg_bitcode64->filesize >= segalign) + bitcode_marker_size = segalign; + else + bitcode_marker_size = object->seg_bitcode64->filesize; + object->output_new_content = allocate(bitcode_marker_size); + memset(object->output_new_content, '\0', bitcode_marker_size); + object->output_new_content_size = bitcode_marker_size; + + object->seg_bitcode64->filesize = bitcode_marker_size; + object->seg_bitcode64->fileoff = start_offset; + /* Note we are leaving the vmsize unchanged */ + + sect_offset = object->seg_bitcode64->fileoff; + s64 = (struct section_64 *)((char *)object->seg_bitcode64 + + sizeof(struct segment_command_64)); + if(object->seg_bitcode64->nsects > 0){ + s64->offset = sect_offset; + s64->size = bitcode_marker_size > 0 ? 1 : 0; + s64++; + } + for(i = 1; i < object->seg_bitcode64->nsects; i++){ + s64->offset = 0; + s64->size = 0; + s64++; + } + + object->seg_linkedit64->fileoff += + object->seg_bitcode64->filesize; + start_offset += object->seg_bitcode64->filesize; + } + } + if(has_bitcode) + some_slice_has_bitcode = TRUE; + + /* + * Now set up all the input symbolic info to be the output symbolic + * info except any code signature data which will be removed. + * + * Assign the offsets to the symbolic data in the proper order and + * increment the local variable offset by the size of each part if the + * the symbolic data. The output_sym_info_size is then determined at + * the end as the difference of the local variable offset from the + * local variable start_offset. + */ + offset = start_offset; + + /* The dyld info is first in symbolic info in the output file. */ + if(object->dyld_info != NULL){ + /* + * There are five parts to the dyld info, but it will be copied as a + * single block of info in the output. + */ + dyld_info_start = 0; + if (object->dyld_info->rebase_off != 0) + dyld_info_start = object->dyld_info->rebase_off; + else if (object->dyld_info->bind_off != 0) + dyld_info_start = object->dyld_info->bind_off; + else if (object->dyld_info->weak_bind_off != 0) + dyld_info_start = object->dyld_info->weak_bind_off; + else if (object->dyld_info->lazy_bind_off != 0) + dyld_info_start = object->dyld_info->lazy_bind_off; + else if (object->dyld_info->export_off != 0) + dyld_info_start = object->dyld_info->export_off; + dyld_info_end = 0; + if (object->dyld_info->export_size != 0) + dyld_info_end = object->dyld_info->export_off + + object->dyld_info->export_size; + else if (object->dyld_info->lazy_bind_size != 0) + dyld_info_end = object->dyld_info->lazy_bind_off + + object->dyld_info->lazy_bind_size; + else if (object->dyld_info->weak_bind_size != 0) + dyld_info_end = object->dyld_info->weak_bind_off + + object->dyld_info->weak_bind_size; + else if (object->dyld_info->bind_size != 0) + dyld_info_end = object->dyld_info->bind_off + + object->dyld_info->bind_size; + else if (object->dyld_info->rebase_size != 0) + dyld_info_end = object->dyld_info->rebase_off + + object->dyld_info->rebase_size; + + object->output_dyld_info = object->object_addr + dyld_info_start; + object->output_dyld_info_size = dyld_info_end - dyld_info_start; + if(object->dyld_info->rebase_off != 0){ + object->dyld_info->rebase_off = offset; + offset += object->dyld_info->rebase_size; + } + if(object->dyld_info->bind_off != 0){ + object->dyld_info->bind_off = offset; + offset += object->dyld_info->bind_size; + } + if(object->dyld_info->weak_bind_off != 0){ + object->dyld_info->weak_bind_off = offset; + offset += object->dyld_info->weak_bind_size; + } + if(object->dyld_info->lazy_bind_off != 0){ + object->dyld_info->lazy_bind_off = offset; + offset += object->dyld_info->lazy_bind_size; + } + if(object->dyld_info->export_off != 0){ + object->dyld_info->export_off = offset; + offset += object->dyld_info->export_size; + } + } + + /* Local relocation entries are next in the output. */ + if(object->dyst != NULL){ + if(object->dyst->nlocrel != 0){ + object->output_loc_relocs = (struct relocation_info *) + (object->object_addr + object->dyst->locreloff); + object->dyst->locreloff = offset; + offset += + object->dyst->nlocrel * sizeof(struct relocation_info); + } + else + object->dyst->locreloff = 0; + } + + if(object->split_info_cmd != NULL){ + object->output_split_info_data = object->object_addr + + object->split_info_cmd->dataoff; + object->output_split_info_data_size = + object->split_info_cmd->datasize; + object->split_info_cmd->dataoff = offset; + offset += object->split_info_cmd->datasize; + } + + if(object->func_starts_info_cmd != NULL){ + object->output_func_start_info_data = object->object_addr + + object->func_starts_info_cmd->dataoff; + object->output_func_start_info_data_size = + object->func_starts_info_cmd->datasize; + object->func_starts_info_cmd->dataoff = offset; + offset += object->func_starts_info_cmd->datasize; + } + + if(object->data_in_code_cmd != NULL){ + object->output_data_in_code_info_data = object->object_addr + + object->data_in_code_cmd->dataoff; + object->output_data_in_code_info_data_size = + object->data_in_code_cmd->datasize; + object->data_in_code_cmd->dataoff = offset; + offset += object->data_in_code_cmd->datasize; + } + + if(object->code_sign_drs_cmd != NULL){ + if(has_bitcode){ + /* + * We remove the code signature on output if we are removing + * a bitcode segment. + */ + if(object->mh != NULL) + object->seg_linkedit->filesize -= + object->code_sign_drs_cmd->datasize; + else + object->seg_linkedit64->filesize -= + object->code_sign_drs_cmd->datasize; + object->output_code_sign_drs_info_data = NULL; + object->output_code_sign_drs_info_data_size = 0; + object->code_sign_drs_cmd->dataoff = 0; + object->code_sign_drs_cmd->datasize = 0; + } + else{ + object->output_code_sign_drs_info_data = object->object_addr + + object->code_sign_drs_cmd->dataoff; + object->output_code_sign_drs_info_data_size = + object->code_sign_drs_cmd->datasize; + object->code_sign_drs_cmd->dataoff = offset; + offset += object->code_sign_drs_cmd->datasize; + } + } + + if(object->link_opt_hint_cmd != NULL){ + object->output_link_opt_hint_info_data = object->object_addr + + object->link_opt_hint_cmd->dataoff; + object->output_link_opt_hint_info_data_size = + object->link_opt_hint_cmd->datasize; + object->link_opt_hint_cmd->dataoff = offset; + offset += object->link_opt_hint_cmd->datasize; + } + + if(object->st != NULL && object->st->nsyms != 0){ + if(object->mh != NULL){ + object->output_symbols = (struct nlist *) + (object->object_addr + object->st->symoff); + if(object->object_byte_sex != get_host_byte_sex()) + swap_nlist(object->output_symbols, + object->st->nsyms, + get_host_byte_sex()); + object->output_symbols64 = NULL; + } + else{ + object->output_symbols64 = (struct nlist_64 *) + (object->object_addr + object->st->symoff); + if(object->object_byte_sex != get_host_byte_sex()) + swap_nlist_64(object->output_symbols64, + object->st->nsyms, + get_host_byte_sex()); + object->output_symbols = NULL; + } + object->output_nsymbols = object->st->nsyms; + object->st->symoff = offset; + if(object->mh != NULL) + offset += object->st->nsyms * sizeof(struct nlist); + else + offset += object->st->nsyms * sizeof(struct nlist_64); + } + else if(object->st != NULL && object->st->nsyms == 0) + object->st->symoff = 0; + + if(object->hints_cmd != NULL){ + if(object->hints_cmd->nhints != 0){ + object->output_hints = (struct twolevel_hint *) + (object->object_addr + object->hints_cmd->offset); + object->hints_cmd->offset = offset; + offset += object->hints_cmd->nhints * + sizeof(struct twolevel_hint); + } + else + object->hints_cmd->offset = 0; + } + + // Note that this should always be true in objects this program + // operates on as it does not need to work on staticly linked images. + if(object->dyst != NULL){ + object->output_ilocalsym = object->dyst->ilocalsym; + object->output_nlocalsym = object->dyst->nlocalsym; + object->output_iextdefsym = object->dyst->iextdefsym; + object->output_nextdefsym = object->dyst->nextdefsym; + object->output_iundefsym = object->dyst->iundefsym; + object->output_nundefsym = object->dyst->nundefsym; + + /* Note local relocation entries are above. */ + + if(object->dyst->nextrel != 0){ + object->output_ext_relocs = (struct relocation_info *) + (object->object_addr + object->dyst->extreloff); + object->dyst->extreloff = offset; + offset += object->dyst->nextrel * + sizeof(struct relocation_info); + } + else + object->dyst->extreloff = 0; + + if(object->dyst->nindirectsyms != 0){ + object->output_indirect_symtab = (uint32_t *) + (object->object_addr + object->dyst->indirectsymoff); + object->dyst->indirectsymoff = offset; + offset += object->dyst->nindirectsyms * sizeof(uint32_t) + + object->input_indirectsym_pad; + } + else + object->dyst->indirectsymoff = 0; + + if(object->dyst->ntoc != 0){ + object->output_tocs = + (struct dylib_table_of_contents *) + (object->object_addr + object->dyst->tocoff); + object->output_ntoc = object->dyst->ntoc; + object->dyst->tocoff = offset; + offset += object->dyst->ntoc * + sizeof(struct dylib_table_of_contents); + } + else + object->dyst->tocoff = 0; + + if(object->dyst->nmodtab != 0){ + if(object->mh != NULL){ + object->output_mods = (struct dylib_module *) + (object->object_addr + object->dyst->modtaboff); + object->output_mods64 = NULL; + } + else{ + object->output_mods64 = (struct dylib_module_64 *) + (object->object_addr + object->dyst->modtaboff); + object->output_mods = NULL; + } + object->output_nmodtab = object->dyst->nmodtab; + object->dyst->modtaboff = offset; + if(object->mh != NULL) + offset += object->dyst->nmodtab * + sizeof(struct dylib_module); + else + offset += object->dyst->nmodtab * + sizeof(struct dylib_module_64); + } + else + object->dyst->modtaboff = 0; + + if(object->dyst->nextrefsyms != 0){ + object->output_refs = (struct dylib_reference *) + (object->object_addr + object->dyst->extrefsymoff); + object->output_nextrefsyms = object->dyst->nextrefsyms; + object->dyst->extrefsymoff = offset; + offset += object->dyst->nextrefsyms * + sizeof(struct dylib_reference); + } + else + object->dyst->extrefsymoff = 0; + } + + if(object->st != NULL && object->st->strsize != 0){ + end_of_string_table = object->st->stroff + object->st->strsize; + object->output_strings = object->object_addr + object->st->stroff; + object->output_strings_size = object->st->strsize; + object->st->stroff = offset; + offset += object->st->strsize; + } + else{ + end_of_string_table = 0; + object->st->stroff = 0; + } + + /* The code signature if any is last, after the strings. */ + if(object->code_sig_cmd != NULL){ + if(has_bitcode){ + /* + * We remove the code signature on output if we are removing + * a bitcode segment. + */ + if(end_of_string_table != 0) + alignment_padding = object->code_sig_cmd->dataoff - + end_of_string_table; + else + alignment_padding = 0; + if(object->mh != NULL) + object->seg_linkedit->filesize -= + object->code_sig_cmd->datasize + alignment_padding; + else + object->seg_linkedit64->filesize -= + object->code_sig_cmd->datasize + alignment_padding; + object->output_code_sig_data = NULL; + object->output_code_sig_data_size = 0; + } + else{ + object->output_code_sig_data = object->object_addr + + object->code_sig_cmd->dataoff; + object->output_code_sig_data_size = + object->code_sig_cmd->datasize; + offset = rnd(offset, 16); + object->code_sig_cmd->dataoff = offset; + offset += object->code_sig_cmd->datasize; + } + } + + object->output_sym_info_size = offset - start_offset; + + if(has_bitcode) + strip_bitcode_from_load_commands(arch, object); +} + +/* + * These are the eight bytes of zeros for the fake string table to be + * written out. + */ +static char fake_string_table[8]; + +/* + * leave_just_bitcode_segment() is only called when there is a bitcode segment, + * and removes everything but that segment contents but leaving the load + * commands intact but zeros out the sizes and counts to make the resulting + * Mach-O file valid. + */ +static +void +leave_just_bitcode_segment( +struct arch *arch, +struct object *object) +{ + uint32_t i, start_offset, offset, sect_offset; + struct load_command *lc; + struct segment_command *sg; + struct segment_command_64 *sg64; + struct section *s; + struct section_64 *s64; + + /* + * To get the right amount of the start of the file copied out by + * writeout() before the symbolic information for this case when we + * are leaving only the bitcode segment we reduce the object size by + * the size of the section contents excluding the padding after the + * load commands. Then this size minus the size of the input symbolic + * information is copied out from the input file to the output file. + * Which is just the size of the old load commands. + * + * To get the bit code segment into the output file we use the + * output_new_content and output_new_content_size. + * + * Lastly to fake up the output symbolic information will have a 8-byte + * string table of zeros and set the size of all the counts to zero + * but leave the load commands so other tools should still be happy. + * + * Also adjust the file offset of the link edit information which is + * where the new fake output symbolic information will start in the + * output file. Which will be right after the load commands. + */ + if(object->mh != NULL){ + start_offset = 0; + lc = arch->object->load_commands; + for(i = 0; i < arch->object->mh->ncmds && start_offset == 0; i++){ + if(lc->cmd == LC_SEGMENT){ + sg = (struct segment_command *)lc; + if(sg->filesize != 0 && sg->fileoff == 0){ + s = (struct section *)((char *)sg + + sizeof(struct segment_command)); + if(sg->nsects > 0) + start_offset = s->offset; + } + } + lc = (struct load_command *)((char *)lc + lc->cmdsize); + } + if(start_offset == 0) + start_offset = sizeof(struct mach_header) + + object->mh->sizeofcmds; + + object->object_size -= (object->seg_linkedit->fileoff - + start_offset); + + object->output_new_content = object->object_addr + + object->seg_bitcode->fileoff; + object->output_new_content_size = object->seg_bitcode->filesize; + + object->seg_bitcode->fileoff = start_offset; + sect_offset = object->seg_bitcode->fileoff; + s = (struct section *)((char *)object->seg_bitcode + + sizeof(struct segment_command)); + for(i = 0; i < object->seg_bitcode->nsects; i++){ + s->offset = sect_offset; + sect_offset += s->offset; + s++; + } + start_offset += object->seg_bitcode->filesize; + + object->input_sym_info_size = object->seg_linkedit->filesize; + object->seg_linkedit->fileoff = start_offset; + } + else{ + start_offset = 0; + lc = arch->object->load_commands; + for(i = 0; i < arch->object->mh64->ncmds && start_offset == 0; i++){ + if(lc->cmd == LC_SEGMENT_64){ + sg64 = (struct segment_command_64 *)lc; + if(sg64->filesize != 0 && sg64->fileoff == 0){ + s64 = (struct section_64 *)((char *)sg64 + + sizeof(struct segment_command_64)); + if(sg64->nsects > 0) + start_offset = s64->offset; + } + } + lc = (struct load_command *)((char *)lc + lc->cmdsize); + } + if(start_offset == 0) + start_offset = sizeof(struct mach_header_64) + + object->mh64->sizeofcmds; + + object->object_size -= (object->seg_linkedit64->fileoff - + start_offset); + + object->output_new_content = object->object_addr + + object->seg_bitcode64->fileoff; + object->output_new_content_size = object->seg_bitcode64->filesize; + + object->seg_bitcode64->fileoff = start_offset; + sect_offset = object->seg_bitcode64->fileoff; + s64 = (struct section_64 *)((char *)object->seg_bitcode64 + + sizeof(struct segment_command_64)); + for(i = 0; i < object->seg_bitcode64->nsects; i++){ + s64->offset = sect_offset; + sect_offset += s64->offset; + s64++; + } + start_offset += object->seg_bitcode64->filesize; + + object->input_sym_info_size = object->seg_linkedit64->filesize; + object->seg_linkedit64->fileoff = start_offset; + } + + /* + * Now "remove" all the input symbolic info so it won't be the output + * symbolic info except for a fake 8 byte string table. + * + * Assign the offsets to the symbolic data in the proper order and + * increment the local variable offset by the size of each part if the + * the symbolic data. The output_sym_info_size is then determined at + * the end as the difference of the local variable offset from the + * local variable start_offset. + */ + offset = start_offset; + + if(object->dyld_info != NULL){ + object->output_dyld_info = NULL; + object->output_dyld_info_size = 0; + object->dyld_info->rebase_off = 0; + object->dyld_info->rebase_size = 0; + object->dyld_info->bind_off = 0; + object->dyld_info->bind_size = 0; + object->dyld_info->weak_bind_off = 0; + object->dyld_info->weak_bind_size = 0; + object->dyld_info->lazy_bind_off = 0; + object->dyld_info->lazy_bind_size = 0; + object->dyld_info->export_off = 0; + object->dyld_info->export_size = 0; + } + + /* Local relocation entries are next in the output. */ + if(object->dyst != NULL){ + object->output_loc_relocs = NULL; + object->dyst->locreloff = 0; + object->dyst->nlocrel = 0; + } + + if(object->split_info_cmd != NULL){ + object->output_split_info_data = NULL; + object->output_split_info_data_size = 0; + object->split_info_cmd->dataoff = 0; + object->split_info_cmd->datasize = 0; + } + + if(object->func_starts_info_cmd != NULL){ + object->output_func_start_info_data = NULL; + object->output_func_start_info_data_size = 0; + object->func_starts_info_cmd->dataoff = 0; + object->func_starts_info_cmd->datasize = 0; + } + + if(object->data_in_code_cmd != NULL){ + object->output_data_in_code_info_data = NULL; + object->output_data_in_code_info_data_size = 0; + object->data_in_code_cmd->dataoff = 0; + object->data_in_code_cmd->datasize = 0; + } + + if(object->code_sign_drs_cmd != NULL){ + object->output_code_sign_drs_info_data = NULL; + object->output_code_sign_drs_info_data_size = 0; + object->code_sign_drs_cmd->dataoff = 0; + object->code_sign_drs_cmd->datasize = 0; + } + + if(object->link_opt_hint_cmd != NULL){ + object->output_link_opt_hint_info_data = NULL; + object->output_link_opt_hint_info_data_size = 0; + object->link_opt_hint_cmd->dataoff = 0; + object->link_opt_hint_cmd->datasize = 0; + } + + if(object->st != NULL){ + object->output_symbols = NULL; + object->output_symbols64 = NULL; + object->output_nsymbols = 0; + object->st->nsyms = 0; + object->st->symoff = 0; + } + + if(object->hints_cmd != NULL){ + object->output_hints = NULL; + object->hints_cmd->offset = 0; + object->hints_cmd->nhints = 0; + } + + // Note that this should always be true in objects this program + // operates on as it does not need to work on staticly linked images. + if(object->dyst != NULL){ + object->output_ilocalsym = 0; + object->output_nlocalsym = 0; + object->output_iextdefsym = 0; + object->output_nextdefsym = 0; + object->output_iundefsym = 0; + object->output_nundefsym = 0; + object->dyst->ilocalsym = 0; + object->dyst->nlocalsym = 0; + object->dyst->iextdefsym = 0; + object->dyst->nextdefsym = 0; + object->dyst->iundefsym = 0; + object->dyst->nundefsym = 0; + + object->output_ext_relocs = NULL; + object->dyst->nextrel = 0; + object->dyst->extreloff = 0; + + object->output_indirect_symtab = NULL; + object->dyst->nindirectsyms = 0; + object->dyst->indirectsymoff = 0; + + object->output_tocs = NULL; + object->output_ntoc = 0; + object->dyst->tocoff = 0; + + object->output_mods = NULL; + object->output_mods64 = NULL; + object->output_nmodtab = 0; + object->dyst->modtaboff = 0; + + object->output_refs = NULL; + object->output_nextrefsyms = 0; + object->dyst->extrefsymoff = 0; + } + + if(object->st != NULL){ + object->output_strings = fake_string_table; + object->output_strings_size = sizeof(fake_string_table); + object->st->stroff = offset; + object->st->strsize = sizeof(fake_string_table); + offset += sizeof(fake_string_table); + } + + /* The code signature if any is last, after the strings. */ + if(object->code_sig_cmd != NULL){ + object->output_code_sig_data = NULL; + object->output_code_sig_data_size = 0; + } + + object->output_sym_info_size = offset - start_offset; + if(object->mh != NULL) + object->seg_linkedit->filesize = object->output_sym_info_size; + else + object->seg_linkedit64->filesize = object->output_sym_info_size; + + leave_only_bitcode_load_commands(arch, object); +} + +/* + * strip_bitcode_segment_command() is called when -r is specified to remove + * the LC_SEGMENT or LC_SEGMENT_64 load command from the object's load commands + * for the bitcode segment and any LC_CODE_SIGNATURE and LC_DYLIB_CODE_SIGN_DRS + * load commands. + * + * If we are using the -m flag to remove the bitcode and leave a marker then + * the LC_SEGMENT or LC_SEGMENT_64 load command are not removed. + */ +static +void +strip_bitcode_from_load_commands( +struct arch *arch, +struct object *object) +{ + uint32_t i, mh_ncmds, new_ncmds, mh_sizeofcmds, new_sizeofcmds; + struct load_command *lc1, *lc2, *new_load_commands; + struct segment_command *sg; + struct segment_command_64 *sg64; + + /* + * A check of the existance of the bitcode segment has already been + * done so it must be present at this point. + */ + + /* + * Allocate space for the new load commands and zero it out so any holes + * will be zero bytes. + */ + if(arch->object->mh != NULL){ + mh_ncmds = arch->object->mh->ncmds; + mh_sizeofcmds = arch->object->mh->sizeofcmds; + } + else{ + mh_ncmds = arch->object->mh64->ncmds; + mh_sizeofcmds = arch->object->mh64->sizeofcmds; + } + new_load_commands = allocate(mh_sizeofcmds); + memset(new_load_commands, '\0', mh_sizeofcmds); + + /* + * Copy all the load commands except the LC_SEGMENT or LC_SEGMENT_64 for + * bitcode segment into the allocated space for the new load commands. + * Unless the -m flag is specified then do copy the bitcode segment + * load command. + */ + lc1 = arch->object->load_commands; + lc2 = new_load_commands; + new_ncmds = 0; + new_sizeofcmds = 0; + for(i = 0; i < mh_ncmds; i++){ + if(lc1->cmd == LC_SEGMENT){ + sg = (struct segment_command *)lc1; + if(strcmp(sg->segname, "__LLVM") != 0 || mflag){ + memcpy(lc2, lc1, lc1->cmdsize); + new_ncmds++; + new_sizeofcmds += lc2->cmdsize; + lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize); + } + } + else if(lc1->cmd == LC_SEGMENT_64){ + sg64 = (struct segment_command_64 *)lc1; + if(strcmp(sg64->segname, "__LLVM") != 0 || mflag){ + memcpy(lc2, lc1, lc1->cmdsize); + new_ncmds++; + new_sizeofcmds += lc2->cmdsize; + lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize); + } + } + else if(lc1->cmd != LC_CODE_SIGNATURE && + lc1->cmd != LC_DYLIB_CODE_SIGN_DRS){ + memcpy(lc2, lc1, lc1->cmdsize); + new_ncmds++; + new_sizeofcmds += lc2->cmdsize; + lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize); + } + lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize); + } + + /* + * Finally copy the updated load commands over the existing load + * commands. + */ + memcpy(arch->object->load_commands, new_load_commands, new_sizeofcmds); + if(mh_sizeofcmds > new_sizeofcmds) + memset((char *)arch->object->load_commands + new_sizeofcmds, + '\0', (mh_sizeofcmds - new_sizeofcmds)); + if(arch->object->mh != NULL) { + arch->object->mh->sizeofcmds = new_sizeofcmds; + arch->object->mh->ncmds = new_ncmds; + } else { + arch->object->mh64->sizeofcmds = new_sizeofcmds; + arch->object->mh64->ncmds = new_ncmds; + } + free(new_load_commands); + + /* reset the pointers into the load commands */ + reset_pointers_for_object_load_commands(arch, object); + + /* + * The LC_CODE_SIGNATURE and LC_DYLIB_CODE_SIGN_DRS load commands + * if any were removed above. + */ + object->code_sig_cmd = NULL; + object->code_sign_drs_cmd = NULL; +} + +/* + * leave_only_bitcode_load_commands() is called when -l is specified to leave + * the LC_SEGMENT or LC_SEGMENT_64 load command from the object's load commands + * for the bitcode segment. It only removes the LC_CODE_SIGNATURE and + * LC_DYLIB_CODE_SIGN_DRS load commands. And zeros out all the fields of + * other load commands to make them valid in the Mach-O file. + */ +static +void +leave_only_bitcode_load_commands( +struct arch *arch, +struct object *object) +{ + uint32_t i, j, mh_ncmds, new_ncmds, mh_sizeofcmds, new_sizeofcmds; + struct load_command *lc1, *lc2, *new_load_commands; + struct segment_command *sg; + struct segment_command_64 *sg64; + struct section *s; + struct section_64 *s64; + struct entry_point_command *ep; + + /* + * Allocate space for the new load commands and zero it out so any holes + * will be zero bytes. + */ + if(arch->object->mh != NULL){ + mh_ncmds = arch->object->mh->ncmds; + mh_sizeofcmds = arch->object->mh->sizeofcmds; + } + else{ + mh_ncmds = arch->object->mh64->ncmds; + mh_sizeofcmds = arch->object->mh64->sizeofcmds; + } + new_load_commands = allocate(mh_sizeofcmds); + memset(new_load_commands, '\0', mh_sizeofcmds); + + /* + * Copy all the load commands except the LC_CODE_SIGNATURE and the + * LC_DYLIB_CODE_SIGN_DRS. For the segment commands other than the + * bitcode segment and linkedit segment zero out the fields. + */ + lc1 = arch->object->load_commands; + lc2 = new_load_commands; + new_ncmds = 0; + new_sizeofcmds = 0; + for(i = 0; i < mh_ncmds; i++){ + if(lc1->cmd == LC_SEGMENT){ + sg = (struct segment_command *)lc1; + if(strcmp(sg->segname, "__LLVM") != 0 && + strcmp(sg->segname, SEG_LINKEDIT) != 0){ + sg->vmaddr = 0; + sg->vmsize = 0; + sg->fileoff = 0; + sg->filesize = 0; + s = (struct section *)((char *)sg + + sizeof(struct segment_command)); + for(j = 0; j < sg->nsects; j++){ + s->addr = 0; + s->size = 0; + s->offset = 0; + s->reloff = 0; + s->nreloc = 0; + s->reserved1 = 0; + s++; + } + } + memcpy(lc2, lc1, lc1->cmdsize); + new_ncmds++; + new_sizeofcmds += lc2->cmdsize; + lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize); + } + else if(lc1->cmd == LC_SEGMENT_64){ + sg64 = (struct segment_command_64 *)lc1; + if(strcmp(sg64->segname, "__LLVM") != 0 && + strcmp(sg64->segname, SEG_LINKEDIT) != 0){ + sg64->vmaddr = 0; + sg64->vmsize = 0; + sg64->fileoff = 0; + sg64->filesize = 0; + s64 = (struct section_64 *)((char *)sg64 + + sizeof(struct segment_command_64)); + for(j = 0; j < sg64->nsects; j++){ + s64->addr = 0; + s64->size = 0; + s64->offset = 0; + s64->reloff = 0; + s64->nreloc = 0; + s64->reserved1 = 0; + s64++; + } + } + memcpy(lc2, lc1, lc1->cmdsize); + new_ncmds++; + new_sizeofcmds += lc2->cmdsize; + lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize); + } + else if(lc1->cmd != LC_CODE_SIGNATURE && + lc1->cmd != LC_DYLIB_CODE_SIGN_DRS){ + if(lc1->cmd == LC_MAIN){ + ep = (struct entry_point_command *)lc1; + ep->entryoff = 0; + } + memcpy(lc2, lc1, lc1->cmdsize); + new_ncmds++; + new_sizeofcmds += lc2->cmdsize; + lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize); + } + lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize); + } + + /* + * Finally copy the updated load commands over the existing load + * commands. + */ + memcpy(arch->object->load_commands, new_load_commands, new_sizeofcmds); + if(mh_sizeofcmds > new_sizeofcmds) + memset((char *)arch->object->load_commands + new_sizeofcmds, + '\0', (mh_sizeofcmds - new_sizeofcmds)); + if(arch->object->mh != NULL) { + arch->object->mh->sizeofcmds = new_sizeofcmds; + arch->object->mh->ncmds = new_ncmds; + } else { + arch->object->mh64->sizeofcmds = new_sizeofcmds; + arch->object->mh64->ncmds = new_ncmds; + } + free(new_load_commands); + + /* reset the pointers into the load commands */ + reset_pointers_for_object_load_commands(arch, object); + + /* + * The LC_CODE_SIGNATURE and LC_DYLIB_CODE_SIGN_DRS load commands + * if any were removed above. + */ + object->code_sig_cmd = NULL; + object->code_sign_drs_cmd = NULL; +} + +/* + * reset_pointers_for_object_load_commands() sets the fields in the object + * struct that are pointers to the load commands. This is needed when we + * rewrite the load commands making those fields that have pointers invalid. + */ +static +void +reset_pointers_for_object_load_commands( +struct arch *arch, +struct object *object) +{ + uint32_t i, mh_ncmds; + struct load_command *lc; + struct segment_command *sg; + struct segment_command_64 *sg64; + + if(arch->object->mh != NULL) + mh_ncmds = arch->object->mh->ncmds; + else + mh_ncmds = arch->object->mh64->ncmds; + + /* reset the pointers into the load commands */ + lc = arch->object->load_commands; + for(i = 0; i < mh_ncmds; i++){ + switch(lc->cmd){ + case LC_SYMTAB: + arch->object->st = (struct symtab_command *)lc; + break; + case LC_DYSYMTAB: + arch->object->dyst = (struct dysymtab_command *)lc; + break; + case LC_TWOLEVEL_HINTS: + arch->object->hints_cmd = (struct twolevel_hints_command *)lc; + break; + case LC_PREBIND_CKSUM: + arch->object->cs = (struct prebind_cksum_command *)lc; + break; + case LC_SEGMENT: + sg = (struct segment_command *)lc; + if(strcmp(sg->segname, SEG_LINKEDIT) == 0) + arch->object->seg_linkedit = sg; + else if(strcmp(sg->segname, "__LLVM") == 0) + arch->object->seg_bitcode = sg; + break; + case LC_SEGMENT_64: + sg64 = (struct segment_command_64 *)lc; + if(strcmp(sg64->segname, SEG_LINKEDIT) == 0) + arch->object->seg_linkedit64 = sg64; + else if(strcmp(sg64->segname, "__LLVM") == 0) + arch->object->seg_bitcode64 = sg64; + break; + case LC_SEGMENT_SPLIT_INFO: + object->split_info_cmd = (struct linkedit_data_command *)lc; + break; + case LC_FUNCTION_STARTS: + object->func_starts_info_cmd = + (struct linkedit_data_command *)lc; + break; + case LC_DATA_IN_CODE: + object->data_in_code_cmd = + (struct linkedit_data_command *)lc; + break; + case LC_LINKER_OPTIMIZATION_HINT: + object->link_opt_hint_cmd = + (struct linkedit_data_command *)lc; + break; + case LC_DYLD_INFO_ONLY: + case LC_DYLD_INFO: + object->dyld_info = (struct dyld_info_command *)lc; + case LC_DYLIB_CODE_SIGN_DRS: + object->code_sign_drs_cmd = (struct linkedit_data_command *)lc; + break; + case LC_CODE_SIGNATURE: + object->code_sig_cmd = (struct linkedit_data_command *)lc; + break; + } + lc = (struct load_command *)((char *)lc + lc->cmdsize); + } +} diff --git a/cctools/misc/codesign_allocate.c b/cctools/misc/codesign_allocate.c index 08f5aaf..bf04faa 100644 --- a/cctools/misc/codesign_allocate.c +++ b/cctools/misc/codesign_allocate.c @@ -372,6 +372,12 @@ struct object *object) object->st->strsize; } } + else if(object->st != NULL && object->st->strsize != 0){ + object->output_strings = + object->object_addr + object->st->stroff; + object->output_strings_size = object->st->strsize; + object->input_sym_info_size = object->st->strsize; + } if(object->dyld_info != NULL){ /* there are five parts to the dyld info, but codesign_allocate does not alter them, so copy as a block */ diff --git a/cctools/misc/libtool.c b/cctools/misc/libtool.c index 472ddcf..f0cab35 100644 --- a/cctools/misc/libtool.c +++ b/cctools/misc/libtool.c @@ -211,7 +211,10 @@ struct member { struct section **sections; /* array of section structs for 32-bit */ struct section_64 **sections64; /* array of section structs for 64-bit */ #ifdef LTO_SUPPORT - void *lto; /* lto module */ + enum bool lto_contents; /* TRUE if this member has lto contents */ + uint32_t lto_toc_nsyms; /* number of symbols for the toc */ + uint32_t lto_toc_strsize; /* the size of the strings for the toc */ + char *lto_toc_strings; /* the strings of the symbols for the toc */ #endif /* LTO_SUPPORT */ /* the name of the member in the output */ @@ -263,6 +266,11 @@ static void create_dynamic_shared_library_cleanup( static void make_table_of_contents( struct arch *arch, char *output); +#ifdef LTO_SUPPORT /* cctools-port */ +static void save_lto_member_toc_info( + struct member *member, + void *mod); +#endif static int toc_name_qsort( const struct toc *toc1, const struct toc *toc2); @@ -1518,7 +1526,7 @@ void) for(k = 0; k < archs[j].nmembers; k++){ if(archs[j].members[k].mh == NULL && #ifdef LTO_SUPPORT - archs[j].members[k].lto == NULL && + archs[j].members[k].lto_contents == TRUE && #endif /* LTO_SUPPORT */ archs[j].members[k].mh64 == NULL){ error("library member: %s(%.*s) is not an " @@ -2183,7 +2191,10 @@ struct ofile *ofile) else if(ofile->file_type == OFILE_LLVM_BITCODE){ member->object_addr = ofile->file_addr; member->object_size = ofile->file_size; - member->lto = ofile->lto; + member->lto_contents = TRUE; + save_lto_member_toc_info(member, ofile->lto); + lto_free(ofile->lto); + ofile->lto = NULL; member->object_byte_sex = get_byte_sex_from_flag(&arch->arch_flag); } else if((ofile->file_type == OFILE_FAT && @@ -2193,7 +2204,10 @@ struct ofile *ofile) ofile->arch_type == OFILE_LLVM_BITCODE)){ member->object_addr = ofile->object_addr; member->object_size = ofile->object_size; - member->lto = ofile->lto; + member->lto_contents = TRUE; + save_lto_member_toc_info(member, ofile->lto); + lto_free(ofile->lto); + ofile->lto = NULL; member->object_byte_sex = get_byte_sex_from_flag(&arch->arch_flag); } #endif /* LTO_SUPPORT */ @@ -2202,7 +2216,10 @@ struct ofile *ofile) member->object_size = ofile->member_size; #ifdef LTO_SUPPORT if(ofile->lto != NULL){ - member->lto = ofile->lto; + member->lto_contents = TRUE; + save_lto_member_toc_info(member, ofile->lto); + lto_free(ofile->lto); + ofile->lto = NULL; member->object_byte_sex = get_byte_sex_from_flag( &arch->arch_flag); } @@ -3478,7 +3495,7 @@ char *output) struct section_64 *section64; uint8_t n_type, n_sect; #ifdef LTO_SUPPORT - uint32_t nsyms; + char *lto_toc_string; #endif /* LTO_SUPPORT */ symbols = NULL; @@ -3606,15 +3623,9 @@ char *output) } } #ifdef LTO_SUPPORT - else if(member->lto != NULL){ - nsyms = lto_get_nsyms(member->lto); - for(j = 0; j < nsyms; j++){ - if(lto_toc_symbol(member->lto, j, cmd_flags.c) == TRUE){ - arch->toc_nranlibs++; - arch->toc_strsize += - strlen(lto_symbol_name(member->lto, j)) + 1; - } - } + else if(member->lto_contents == TRUE){ + arch->toc_nranlibs += member->lto_toc_nsyms; + arch->toc_strsize += member->lto_toc_strsize; } #endif /* LTO_SUPPORT */ else{ @@ -3691,17 +3702,15 @@ char *output) } } #ifdef LTO_SUPPORT - else if(member->lto != NULL){ - nsyms = lto_get_nsyms(member->lto); - for(j = 0; j < nsyms; j++){ - if(lto_toc_symbol(member->lto, j, cmd_flags.c) == TRUE){ - strcpy(arch->toc_strings + s, - lto_symbol_name(member->lto, j)); - arch->tocs[r].name = arch->toc_strings + s; - arch->tocs[r].index1 = i + 1; - r++; - s += strlen(lto_symbol_name(member->lto, j)) + 1; - } + else if(member->lto_contents == TRUE){ + lto_toc_string = member->lto_toc_strings; + for(j = 0; j < member->lto_toc_nsyms; j++){ + strcpy(arch->toc_strings + s, lto_toc_string); + arch->tocs[r].name = arch->toc_strings + s; + arch->tocs[r].index1 = i + 1; + r++; + s += strlen(lto_toc_string) + 1; + lto_toc_string += strlen(lto_toc_string) + 1; } } #endif /* LTO_SUPPORT */ @@ -3832,6 +3841,41 @@ char *output) (int)sizeof(arch->toc_ar_hdr.ar_fmag)); } +/* + * save_lto_member_toc_info() saves away the table of contents info for a + * member that has lto_content. This allows the lto module to be disposed of + * after reading to keep only on in memory at a time. As these turn out to + * use a lot of memory. + */ +#ifdef LTO_SUPPORT /* cctools-port */ +static +void +save_lto_member_toc_info( +struct member *member, +void *mod) +{ + uint32_t i, nsyms; + char *s; + + member->lto_toc_nsyms = 0; + nsyms = lto_get_nsyms(mod); + for(i = 0; i < nsyms; i++){ + if(lto_toc_symbol(mod, i, cmd_flags.c) == TRUE){ + member->lto_toc_nsyms++; + member->lto_toc_strsize += strlen(lto_symbol_name(mod, i)) + 1; + } + } + member->lto_toc_strings = allocate(member->lto_toc_strsize); + s = member->lto_toc_strings; + for(i = 0; i < nsyms; i++){ + if(lto_toc_symbol(mod, i, cmd_flags.c) == TRUE){ + strcpy(s, lto_symbol_name(mod, i)); + s += strlen(lto_symbol_name(mod, i)) + 1; + } + } +} +#endif /* LTO_SUPPORT */ + /* * Function for qsort() for comparing toc structures by name. */ diff --git a/cctools/otool/Makefile.am b/cctools/otool/Makefile.am index a4a6657..bf37108 100644 --- a/cctools/otool/Makefile.am +++ b/cctools/otool/Makefile.am @@ -12,9 +12,9 @@ $(PTHREAD_FLAGS) $(CXXABI_LIB) $(DL_LIB) endif if ISDARWIN -otool_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/include/foreign -I$(top_srcdir)/libstuff $(WARNINGS) $(LTO_DEF) -D_DARWIN_C_SOURCE -D__DARWIN_UNIX03 $(ENDIAN_FLAG) -DOTOOL +otool_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/include/foreign -I$(top_srcdir)/libstuff $(WARNINGS) $(LTO_DEF) -D_DARWIN_C_SOURCE -D__DARWIN_UNIX03 $(ENDIAN_FLAG) -DOTOOL -DEFI_SUPPORT else -otool_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/include/foreign -I$(top_srcdir)/libstuff -I$(top_srcdir)/libobjc2 $(WARNINGS) $(LTO_DEF) -D_DARWIN_C_SOURCE -D__DARWIN_UNIX03 $(ENDIAN_FLAG) -DOTOOL +otool_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/include/foreign -I$(top_srcdir)/libstuff -I$(top_srcdir)/libobjc2 $(WARNINGS) $(LTO_DEF) -D_DARWIN_C_SOURCE -D__DARWIN_UNIX03 $(ENDIAN_FLAG) -DOTOOL -DEFI_SUPPORT endif otool_SOURCES = \ @@ -32,5 +32,7 @@ otool_SOURCES = \ print_objc.c \ print_objc2_32bit.c \ print_objc2_64bit.c \ + print_bitcode.c \ + coff_print.c \ arm64_disasm.c \ dyld_bind_info.c diff --git a/cctools/otool/main.c b/cctools/otool/main.c index 5524549..af2f0b4 100644 --- a/cctools/otool/main.c +++ b/cctools/otool/main.c @@ -1511,6 +1511,15 @@ void *cookie) /* cookie is not used */ mh_sizeofcmds, ofile->object_byte_sex, ofile->object_addr, ofile->object_size, vflag); } + else if(strcmp(segname, "__LLVM") == 0 && + strcmp(sectname, "__bundle") == 0 && + (vflag == TRUE || Vflag == TRUE) && + get_sect_info(segname, sectname, ofile->load_commands, + mh_ncmds, mh_sizeofcmds, mh_filetype, ofile->object_byte_sex, + addr, size, §, §_size, §_addr, §_relocs, + §_nrelocs, §_flags, &seg_addr) == TRUE){ + print_bitcode_section(sect, sect_size, vflag, Vflag); + } #ifdef EFI_SUPPORT else if(strcmp(segname, "__RELOC") == 0 && strcmp(sectname, "__reloc") == 0 && vflag == TRUE){ @@ -1544,20 +1553,23 @@ void *cookie) /* cookie is not used */ Xflag == TRUE ? FALSE : TRUE); break; case S_4BYTE_LITERALS: - print_literal4_section(sect, sect_size, sect_addr, - ofile->object_byte_sex, - Xflag == TRUE ? FALSE : TRUE); - break; - case S_8BYTE_LITERALS: - print_literal8_section(sect, sect_size, sect_addr, - ofile->object_byte_sex, - Xflag == TRUE ? FALSE : TRUE); - break; - case S_16BYTE_LITERALS: - print_literal16_section(sect, sect_size, sect_addr, + print_literal4_section(mh_cputype, sect, sect_size, + sect_addr, ofile->object_byte_sex, Xflag == TRUE ? FALSE : TRUE); break; + case S_8BYTE_LITERALS: + print_literal8_section(mh_cputype, sect, sect_size, + sect_addr, + ofile->object_byte_sex, + Xflag == TRUE ? FALSE : TRUE); + break; + case S_16BYTE_LITERALS: + print_literal16_section(mh_cputype, sect, sect_size, + sect_addr, + ofile->object_byte_sex, + Xflag == TRUE ? FALSE : TRUE); + break; case S_LITERAL_POINTERS: /* create aligned, sorted relocations entries */ nrelocs = sect_nrelocs; diff --git a/cctools/otool/ofile_print.c b/cctools/otool/ofile_print.c index 49fd7ef..eed9e20 100644 --- a/cctools/otool/ofile_print.c +++ b/cctools/otool/ofile_print.c @@ -294,7 +294,8 @@ static void print_literal4( static void print_literal8( uint32_t l0, uint32_t l1, - double d); + double d, + enum byte_sex literal_byte_sex); static void print_literal16( uint32_t l0, uint32_t l1, @@ -2291,6 +2292,7 @@ enum bool very_verbose) case LC_VERSION_MIN_MACOSX: case LC_VERSION_MIN_IPHONEOS: + case LC_VERSION_MIN_WATCHOS: memset((char *)&vd, '\0', sizeof(struct version_min_command)); size = left < sizeof(struct version_min_command) ? left : sizeof(struct version_min_command); @@ -3500,6 +3502,8 @@ struct version_min_command *vd) printf(" cmd LC_VERSION_MIN_MACOSX\n"); else if(vd->cmd == LC_VERSION_MIN_IPHONEOS) printf(" cmd LC_VERSION_MIN_IPHONEOS\n"); + else if(vd->cmd == LC_VERSION_MIN_WATCHOS) + printf(" cmd LC_VERSION_MIN_WATCHOS\n"); else printf(" cmd %u (?)\n", vd->cmd); printf(" cmdsize %u", vd->cmdsize); @@ -7627,7 +7631,7 @@ enum bool print_addresses) for(i = 0; i < sect_size ; i++){ if(print_addresses == TRUE){ if(cputype & CPU_ARCH_ABI64) - printf("0x%016llx ", sect_addr + i); + printf("%016llx ", sect_addr + i); else printf("%08x ", (unsigned int)(sect_addr + i)); } @@ -7681,9 +7685,10 @@ char c) void print_literal4_section( +cpu_type_t cputype, char *sect, uint32_t sect_size, -uint32_t sect_addr, +uint64_t sect_addr, enum byte_sex literal_byte_sex, enum bool print_addresses) { @@ -7696,8 +7701,12 @@ enum bool print_addresses) swapped = host_byte_sex != literal_byte_sex; for(i = 0; i < sect_size ; i += sizeof(float)){ - if(print_addresses == TRUE) - printf("%08x ", (unsigned int)(sect_addr + i)); + if(print_addresses == TRUE){ + if(cputype & CPU_ARCH_ABI64) + printf("%016llx ", sect_addr + i); + else + printf("%08x ", (unsigned int)(sect_addr + i)); + } memcpy((char *)&f, sect + i, sizeof(float)); memcpy((char *)&l, sect + i, sizeof(uint32_t)); if(swapped){ @@ -7732,9 +7741,10 @@ float f) void print_literal8_section( +cpu_type_t cputype, char *sect, uint32_t sect_size, -uint32_t sect_addr, +uint64_t sect_addr, enum byte_sex literal_byte_sex, enum bool print_addresses) { @@ -7747,8 +7757,12 @@ enum bool print_addresses) swapped = host_byte_sex != literal_byte_sex; for(i = 0; i < sect_size ; i += sizeof(double)){ - if(print_addresses == TRUE) - printf("%08x ", (unsigned int)(sect_addr + i)); + if(print_addresses == TRUE){ + if(cputype & CPU_ARCH_ABI64) + printf("%016llx ", sect_addr + i); + else + printf("%08x ", (unsigned int)(sect_addr + i)); + } memcpy((char *)&d, sect + i, sizeof(double)); memcpy((char *)&l0, sect + i, sizeof(uint32_t)); memcpy((char *)&l1, sect + i + sizeof(uint32_t), @@ -7758,7 +7772,7 @@ enum bool print_addresses) l0 = SWAP_INT(l0); l1 = SWAP_INT(l1); } - print_literal8(l0, l1, d); + print_literal8(l0, l1, d, literal_byte_sex); } } @@ -7767,18 +7781,28 @@ void print_literal8( uint32_t l0, uint32_t l1, -double d) +double d, +enum byte_sex literal_byte_sex) { + uint32_t hi, lo; + printf("0x%08x 0x%08x", (unsigned int)l0, (unsigned int)l1); - /* l0 is the high word, so this is equivalent to if(isfinite(d)) */ - if((l0 & 0x7ff00000) != 0x7ff00000) + if(literal_byte_sex == LITTLE_ENDIAN_BYTE_SEX){ + hi = l1; + lo = l0; + } else { + hi = l0; + lo = l1; + } + /* hi is the high word, so this is equivalent to if(isfinite(d)) */ + if((hi & 0x7ff00000) != 0x7ff00000) printf(" (%.16e)\n", d); else{ - if(l0 == 0x7ff00000 && l1 == 0) + if(hi == 0x7ff00000 && lo == 0) printf(" (+Infinity)\n"); - else if(l0 == 0xfff00000 && l1 == 0) + else if(hi == 0xfff00000 && lo == 0) printf(" (-Infinity)\n"); - else if((l0 & 0x00080000) == 0x00080000) + else if((hi & 0x00080000) == 0x00080000) printf(" (non-signaling Not-a-Number)\n"); else printf(" (signaling Not-a-Number)\n"); @@ -7787,9 +7811,10 @@ double d) void print_literal16_section( +cpu_type_t cputype, char *sect, uint32_t sect_size, -uint32_t sect_addr, +uint64_t sect_addr, enum byte_sex literal_byte_sex, enum bool print_addresses) { @@ -7801,8 +7826,12 @@ enum bool print_addresses) swapped = host_byte_sex != literal_byte_sex; for(i = 0; i < sect_size ; i += 4 * sizeof(uint32_t)){ - if(print_addresses == TRUE) - printf("%08x ", (unsigned int)(sect_addr + i)); + if(print_addresses == TRUE){ + if(cputype & CPU_ARCH_ABI64) + printf("%016llx ", sect_addr + i); + else + printf("%08x ", (unsigned int)(sect_addr + i)); + } memcpy((char *)&l0, sect + i, sizeof(uint32_t)); memcpy((char *)&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t)); @@ -8047,7 +8076,7 @@ enum bool print_addresses) for(i = 0; i < sect_size ; i += lp_size){ if(print_addresses == TRUE){ if(cputype & CPU_ARCH_ABI64) - printf("0x%016llx ", sect_addr + i); + printf("%016llx ", sect_addr + i); else printf("%08x ", (unsigned int)(sect_addr + i)); } @@ -8144,7 +8173,7 @@ enum bool print_addresses) l0 = SWAP_INT(l0); l1 = SWAP_INT(l1); } - print_literal8(l0, l1, d); + print_literal8(l0, l1, d, object_byte_sex); break; case S_16BYTE_LITERALS: memcpy((char *)&l0, diff --git a/cctools/otool/ofile_print.h b/cctools/otool/ofile_print.h index 12f02c9..b25e475 100644 --- a/cctools/otool/ofile_print.h +++ b/cctools/otool/ofile_print.h @@ -340,23 +340,26 @@ extern void print_cstring_section( enum bool print_addresses); extern void print_literal4_section( + cpu_type_t cputype, char *sect, uint32_t sect_size, - uint32_t sect_addr, + uint64_t sect_addr, enum byte_sex literal_byte_sex, enum bool print_addresses); extern void print_literal8_section( + cpu_type_t cputype, char *sect, uint32_t sect_size, - uint32_t sect_addr, + uint64_t sect_addr, enum byte_sex literal_byte_sex, enum bool print_addresses); extern void print_literal16_section( + cpu_type_t cputype, char *sect, uint32_t sect_size, - uint32_t sect_addr, + uint64_t sect_addr, enum byte_sex literal_byte_sex, enum bool print_addresses); @@ -548,6 +551,12 @@ extern void print_objc_runtime_setup_section( uint32_t object_size, enum bool verbose); +extern void print_bitcode_section( + char *sect, + uint64_t sect_size, + enum bool verbose, + enum bool print_xar_header); + extern char *get_objc2_64bit_cfstring_name( uint64_t p, struct load_command *load_commands, diff --git a/cctools/otool/print_bitcode.c b/cctools/otool/print_bitcode.c new file mode 100644 index 0000000..5cdb281 --- /dev/null +++ b/cctools/otool/print_bitcode.c @@ -0,0 +1,228 @@ +/* + * Copyright © 2015 Apple Inc. All rights reserved. + + * @APPLE_LICENSE_HEADER_START@ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/xar/xar.h" /* cctools-port: + force the use of the bundled xar header */ +#include "mach-o/loader.h" +#include "objc/runtime.h" /* cctools-port: + objc/objc-runtime.h -> objc/runtime.h */ +#include "stuff/allocate.h" +#include "stuff/bytesex.h" +#include "stuff/symbol.h" +#include "stuff/errors.h" +#include "stuff/allocate.h" +#include "dyld_bind_info.h" +#include "ofile_print.h" +#include + +static enum bool tried_to_load_xar = FALSE; +static void *xar_handle = NULL; +static xar_t (*ptr_xar_open)(const char *file, int32_t flags) = NULL; +static void (*ptr_xar_serialize)(xar_t x, const char *file) = NULL; +static int (*ptr_xar_close)(xar_t x) = NULL; + +void +print_bitcode_section( +char *sect, +uint64_t sect_size, +enum bool verbose, +enum bool print_xar_header) +{ + enum byte_sex host_byte_sex; + uint32_t i, bufsize; + char *p, *prefix, *xar_path, buf[MAXPATHLEN], resolved_name[PATH_MAX]; + struct xar_header xar_hdr; + char xar_filename[] = "/tmp/temp.XXXXXX"; + char toc_filename[] = "/tmp/temp.XXXXXX"; + int xar_fd, toc_fd; + xar_t xar; + struct stat toc_stat_buf; + char *toc; + + host_byte_sex = get_host_byte_sex(); + + memset(&xar_hdr, '\0', sizeof(struct xar_header)); + if(sect_size < sizeof(struct xar_header)) { + printf("size of (__LLVM,__bundle) section too small (smaller " + "than size of struct xar_header)"); + memcpy((char *)&xar_hdr, sect, sect_size); + } + else { + memcpy((char *)&xar_hdr, sect, sizeof(struct xar_header)); + } +#ifdef __LITTLE_ENDIAN__ + swap_xar_header(&xar_hdr, host_byte_sex); +#endif /* __LITTLE_ENDIAN__ */ + if(print_xar_header) { + printf("For (__LLVM,__bundle) section: xar header\n"); + if(xar_hdr.magic == XAR_HEADER_MAGIC) + printf(" magic XAR_HEADER_MAGIC\n"); + else + printf(" magic 0x%08x (not XAR_HEADER_MAGIC)\n" + , xar_hdr.magic); + printf(" size %u\n", xar_hdr.size); + printf(" version %u\n", xar_hdr.version); + printf(" toc_length_compressed %llu\n", + xar_hdr.toc_length_compressed); + printf("toc_length_uncompressed %llu\n", + xar_hdr.toc_length_uncompressed); + printf(" cksum_alg "); + switch(xar_hdr.cksum_alg){ + case XAR_CKSUM_NONE: + printf("XAR_CKSUM_NONE\n"); + break; + case XAR_CKSUM_SHA1: + printf("XAR_CKSUM_SHA1\n"); + break; + case XAR_CKSUM_MD5: + printf("XAR_CKSUM_MD5\n"); + break; + case XAR_CKSUM_SHA256: + printf("XAR_CKSUM_SHA512\n"); + break; + case XAR_CKSUM_SHA512: + printf("XAR_CKSUM_SHA512\n"); + break; + default: + printf("%u\n", xar_hdr.cksum_alg); + break; + } + } + + if(sect_size < sizeof(struct xar_header)) + return; + + if(tried_to_load_xar == FALSE){ + tried_to_load_xar = TRUE; + /* + * Construct the prefix to this executable assuming it is in a bin + * directory relative to a lib directory of the matching xar library + * and first try to load that. If not then fall back to trying + * "/usr/lib/libxar.dylib". + */ +#ifdef __APPLE__ /* cctools-port */ + bufsize = MAXPATHLEN; + p = buf; + i = _NSGetExecutablePath(p, &bufsize); + if(i == -1){ + p = allocate(bufsize); + _NSGetExecutablePath(p, &bufsize); + } + prefix = realpath(p, resolved_name); + p = rindex(prefix, '/'); + if(p != NULL) + p[1] = '\0'; + xar_path = makestr(prefix, "../lib/libxar.dylib", NULL); + + xar_handle = dlopen(xar_path, RTLD_NOW); + if(xar_handle == NULL){ + free(xar_path); + xar_path = NULL; + xar_handle = dlopen("/usr/lib/libxar.dylib", RTLD_NOW); + } +#else + xar_handle = dlopen("libxar.so", RTLD_NOW); + if(xar_handle == NULL) + fprintf(stderr, "Can't open libxar.so\n"); +#endif /* __APPLE__ */ + if(xar_handle == NULL) + return; + + ptr_xar_open = dlsym(xar_handle, "xar_open"); + ptr_xar_serialize = dlsym(xar_handle, "xar_serialize"); + ptr_xar_close = dlsym(xar_handle, "xar_close"); + if(ptr_xar_open == NULL || + ptr_xar_serialize == NULL || + ptr_xar_close == NULL) + return; + } + if(xar_handle == NULL) + return; + + xar_fd = mkstemp(xar_filename); + if(write(xar_fd, sect, sect_size) != sect_size){ + system_error("Can't write (__LLVM,__bundle) section contents " + "to temporary file: %s\n", xar_filename); + close(xar_fd); + return; + } + close(xar_fd); + + if(mktemp(toc_filename) == NULL){ + system_error("Can't create file name for xar toc\n"); + unlink(xar_filename); + return; + } + xar = ptr_xar_open(xar_filename, READ); + if(!xar){ + system_error("Can't create temporary xar archive %s\n", + xar_filename); + unlink(xar_filename); + return; + } + ptr_xar_serialize(xar, toc_filename); + ptr_xar_close(xar); + unlink(xar_filename); + + toc_fd = open(toc_filename, O_RDONLY, 0); + if(toc_fd == 0){ + system_error("Can't open xar table of contents file: %s\n", + toc_filename); + unlink(toc_filename); + return; + } + if(fstat(toc_fd, &toc_stat_buf) != 0){ + system_error("Can't fstat xar table of contents file: %s\n", + toc_filename); + unlink(toc_filename); + return; + } + toc = allocate(toc_stat_buf.st_size + 1); + toc[toc_stat_buf.st_size] = '\0'; + if(read(toc_fd, toc, toc_stat_buf.st_size) != toc_stat_buf.st_size){ + system_error("Can't read xar table of contents file: %s\n", + toc_filename); + unlink(toc_filename); + return; + } + close(toc_fd); + unlink(toc_filename); + printf("For (__LLVM,__bundle) section: xar table of contents:\n"); + printf("%s\n", toc); + free(toc); +} diff --git a/cctools/otool/print_objc.c b/cctools/otool/print_objc.c index bb2ab6f..7d7e4a6 100644 --- a/cctools/otool/print_objc.c +++ b/cctools/otool/print_objc.c @@ -32,7 +32,8 @@ #include "string.h" #include "stdint.h" /* cctools-port: intptr_t */ #include "mach-o/loader.h" -#include "objc/runtime.h" /* cctools-port: objc/objc-runtime.h -> objc/runtime.h */ +#include "objc/runtime.h" /* cctools-port: + objc/objc-runtime.h -> objc/runtime.h */ #include "stuff/allocate.h" #include "stuff/bytesex.h" #include "stuff/symbol.h" diff --git a/cctools/otool/print_objc2_32bit.c b/cctools/otool/print_objc2_32bit.c index 0fff459..e5dba9c 100644 --- a/cctools/otool/print_objc2_32bit.c +++ b/cctools/otool/print_objc2_32bit.c @@ -474,6 +474,9 @@ enum bool verbose) if(s == NULL) s = get_section_32(info.sections, info.nsections, "__DATA", "__objc_classlist"); + if(s == NULL) + s = get_section_32(info.sections, info.nsections, + "__DATA_CONST", "__objc_classlist"); walk_pointer_list("class", s, &info, print_class_t); s = get_section_32(info.sections, info.nsections, @@ -481,6 +484,9 @@ enum bool verbose) if(s == NULL) s = get_section_32(info.sections, info.nsections, "__DATA", "__objc_classrefs"); + if(s == NULL) + s = get_section_32(info.sections, info.nsections, + "__DATA_CONST", "__objc_classrefs"); walk_pointer_list("class refs", s, &info, NULL); s = get_section_32(info.sections, info.nsections, @@ -488,6 +494,9 @@ enum bool verbose) if(s == NULL) s = get_section_32(info.sections, info.nsections, "__DATA", "__objc_superrefs"); + if(s == NULL) + s = get_section_32(info.sections, info.nsections, + "__DATA_CONST", "__objc_superrefs"); walk_pointer_list("super refs", s, &info, NULL); s = get_section_32(info.sections, info.nsections, @@ -495,6 +504,9 @@ enum bool verbose) if(s == NULL) s = get_section_32(info.sections, info.nsections, "__DATA", "__objc_catlist"); + if(s == NULL) + s = get_section_32(info.sections, info.nsections, + "__DATA_CONST", "__objc_catlist"); walk_pointer_list("category", s, &info, print_category_t); s = get_section_32(info.sections, info.nsections, @@ -502,6 +514,9 @@ enum bool verbose) if(s == NULL) s = get_section_32(info.sections, info.nsections, "__DATA", "__objc_protolist"); + if(s == NULL) + s = get_section_32(info.sections, info.nsections, + "__DATA_CONST", "__objc_protolist"); walk_pointer_list("protocol", s, &info, NULL); s = get_section_32(info.sections, info.nsections, @@ -509,6 +524,9 @@ enum bool verbose) if(s == NULL) s = get_section_32(info.sections, info.nsections, "__DATA", "__objc_msgrefs"); + if(s == NULL) + s = get_section_32(info.sections, info.nsections, + "__DATA_CONST", "__objc_msgrefs"); print_message_refs(s, &info); s = get_section_32(info.sections, info.nsections, @@ -516,6 +534,9 @@ enum bool verbose) if(s == NULL) s = get_section_32(info.sections, info.nsections, "__DATA", "__objc_imageinfo"); + if(s == NULL) + s = get_section_32(info.sections, info.nsections, + "__DATA_CONST", "__objc_imageinfo"); print_image_info(s, &info); } @@ -1033,7 +1054,7 @@ struct info *info) printf(" %.*s\n", (int)left, name); else printf("\n"); - printf("\t\t\tattributes x%x", op.attributes); + printf("\t\t\tattributes 0x%x", op.attributes); name = get_pointer_32(op.attributes, NULL, &left, NULL, info->sections, info->nsections); if(name != NULL) diff --git a/cctools/otool/print_objc2_64bit.c b/cctools/otool/print_objc2_64bit.c index 27ea73e..def0785 100644 --- a/cctools/otool/print_objc2_64bit.c +++ b/cctools/otool/print_objc2_64bit.c @@ -536,6 +536,9 @@ enum bool Vflag) if(s == NULL) s = get_section_64(info.sections, info.nsections, "__DATA", "__objc_classlist"); + if(s == NULL) + s = get_section_64(info.sections, info.nsections, + "__DATA_CONST", "__objc_classlist"); walk_pointer_list("class", s, &info, print_class_t); s = get_section_64(info.sections, info.nsections, @@ -543,6 +546,9 @@ enum bool Vflag) if(s == NULL) s = get_section_64(info.sections, info.nsections, "__DATA", "__objc_classrefs"); + if(s == NULL) + s = get_section_64(info.sections, info.nsections, + "__DATA_CONST", "__objc_classrefs"); walk_pointer_list("class refs", s, &info, NULL); s = get_section_64(info.sections, info.nsections, @@ -550,6 +556,9 @@ enum bool Vflag) if(s == NULL) s = get_section_64(info.sections, info.nsections, "__DATA", "__objc_superrefs"); + if(s == NULL) + s = get_section_64(info.sections, info.nsections, + "__DATA_CONST", "__objc_superrefs"); walk_pointer_list("super refs", s, &info, NULL); s = get_section_64(info.sections, info.nsections, @@ -557,6 +566,9 @@ enum bool Vflag) if(s == NULL) s = get_section_64(info.sections, info.nsections, "__DATA", "__objc_catlist"); + if(s == NULL) + s = get_section_64(info.sections, info.nsections, + "__DATA_CONST", "__objc_catlist"); walk_pointer_list("category", s, &info, print_category_t); s = get_section_64(info.sections, info.nsections, @@ -564,6 +576,9 @@ enum bool Vflag) if(s == NULL) s = get_section_64(info.sections, info.nsections, "__DATA", "__objc_protolist"); + if(s == NULL) + s = get_section_64(info.sections, info.nsections, + "__DATA_CONST", "__objc_protolist"); walk_pointer_list("protocol", s, &info, NULL); s = get_section_64(info.sections, info.nsections, @@ -571,6 +586,9 @@ enum bool Vflag) if(s == NULL) s = get_section_64(info.sections, info.nsections, "__DATA", "__objc_msgrefs"); + if(s == NULL) + s = get_section_64(info.sections, info.nsections, + "__DATA_CONST", "__objc_msgrefs"); print_message_refs(s, &info); s = get_section_64(info.sections, info.nsections, @@ -578,6 +596,9 @@ enum bool Vflag) if(s == NULL) s = get_section_64(info.sections, info.nsections, "__DATA", "__objc_imageinfo"); + if(s == NULL) + s = get_section_64(info.sections, info.nsections, + "__DATA_CONST", "__objc_imageinfo"); print_image_info(s, &info); } diff --git a/tools/create_cctools_merge_patch.sh b/tools/create_cctools_merge_patch.sh index 732f0e4..805efcd 100755 --- a/tools/create_cctools_merge_patch.sh +++ b/tools/create_cctools_merge_patch.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash -BASE_VERSION=862 -NEW_VERSION=870 +BASE_VERSION=870 +NEW_VERSION=877.5 set -e