diff --git a/Makefile b/Makefile index 58b35e7..e90e502 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,29 @@ +# +# Makefile for striptease project +# Copyright (C) 2011,2012 Kyle J. McKay. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the author(s) shall not +# be used in advertising or otherwise to promote the sale, use or other +# dealings in this Software without prior written authorization from the +# author(s). + # Makefile for striptease project # Copyright (C) 2011,2012 Kyle J. McKay. All rights reserved. # @@ -23,7 +49,92 @@ # dealings in this Software without prior written authorization from the # author(s). -include version.mak +# The cctools version suffix these sources are based on +# The tarball can be found at: +# http://opensource.apple.com/tarballs/cctools/cctools-$(CCTOOLSVER).tar.gz + +CCTOOLSVER = 855 + +ifneq (0,$$([(uname -r | cut -f1 -d.) -gt 9]; echo $$?)) # For old makefile. + +DEBUG ?= Release +DD=build/$(DEBUG)/ + +CC ?= cc +CFLAGS += -O3 -fPIC -g0 -Wno-private-extern +COPTS += $(CFLAGS) -Iinclude -include preinc.h -DCCTOOLSVER=$(CCTOOLSVER) +LDOPTS += -Wl,-dead_strip,-dead_strip_dylibs,-no_eh_labels +LDOPTS += -Wl,-no_uuid,-no_version_load_command,-search_paths_first + +ifeq ($(DEBUG),Debug) + COPTS+=-O0 -g + LDOPTS=+-g +else + LDOPTS+= -Wl,-S,-x,-w +endif + +$(shell mkdir -p $(DD)/libstuff) + +all : $(DD)tease tools + +.PHONY : tools tease strip install_name_tool nm + +tools : strip install_name_tool nm tease + +tease : $(DD)tease +strip : $(DD)strip +install_name_tool : $(DD)install_name_tool +nm : $(DD)nm + +LIBSTUFF_SRC := $(wildcard libstuff/*.c) + +TEASE_SRC = tease.c $(LIBSTUFF_SRC) +STRIP_SRC = strip.c $(LIBSTUFF_SRC) +INSTALL_NAME_TOOL_SRC = install_name_tool.c $(LIBSTUFF_SRC) +NM_SRC = nm.c $(LIBSTUFF_SRC) + +TEASE_OBJS = $(addprefix $(DD),$(TEASE_SRC:.c=.o)) $(DD)version_tease.o +STRIP_OBJS = $(addprefix $(DD),$(STRIP_SRC:.c=.o)) $(DD)version_strip.o + +INSTALL_NAME_TOOL_OBJS = $(addprefix $(DD),$(INSTALL_NAME_TOOL_SRC:.c=.o)) \ + $(DD)version_install_name_tool.o + +NM_OBJS = $(addprefix $(DD),$(NM_SRC:.c=.o)) $(DD)nm.o + +$(DD)%.o : %.c + $(CC) -c $(COPTS) -o $@ $< + +$(DD)version_tease.o : version.c + $(CC) -c $(COPTS) -DPROGRAMNAME=tease -o $@ $< + +$(DD)version_strip.o : version.c + $(CC) -c $(COPTS) -DPROGRAMNAME=strip -o $@ $< + +$(DD)version_install_name_tool.o : version.c + $(CC) -c $(COPTS) -DPROGRAMNAME=install_name_tool -o $@ $< + +$(DD)version_nm.o : version.c + $(CC) -c $(COPTS) -DPROGRAMNAME=nm -o $@ $< + +$(DD)tease : $(TEASE_OBJS) + $(CC) -o $@ $(LDOPTS) $^ + +$(DD)strip : $(STRIP_OBJS) + $(CC) -o $@ $(LDOPTS) $^ + +$(DD)install_name_tool : $(INSTALL_NAME_TOOL_OBJS) + $(CC) -o $@ $(LDOPTS) $^ + +$(DD)nm : $(NM_OBJS) + $(CC) -o $@ $(LDOPTS) $^ + +clean : + rm -rf build + + +####################################### +else ## ** Begin "Old" Makefile ** ## +####################################### .PHONY : all clean @@ -194,3 +305,5 @@ endif clean : rm -rf build + +endif # "Old" makefile. diff --git a/include/mach-o/dyld.h b/include/mach-o/dyld.h index c7ab7b7..9699d83 100644 --- a/include/mach-o/dyld.h +++ b/include/mach-o/dyld.h @@ -23,7 +23,7 @@ #ifndef _MACH_O_DYLD_H_ #define _MACH_O_DYLD_H_ -#if __cplusplus +#ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -239,7 +239,7 @@ extern long NSVersionOfLinkTimeLibrary( const char *libraryName); extern int _NSGetExecutablePath( /* SPI first appeared in Mac OS X 10.2 */ char *buf, - unsigned long *bufsize); + uint32_t *bufsize); /* * The low level _dyld_... API. @@ -320,7 +320,7 @@ __private_extern__ int _dyld_func_lookup( const char *dyld_func_name, unsigned long *address); -#if __cplusplus +#ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/include/mach-o/loader.h b/include/mach-o/loader.h index f41664e..cc17c6f 100644 --- a/include/mach-o/loader.h +++ b/include/mach-o/loader.h @@ -294,6 +294,9 @@ struct load_command { #define LC_DATA_IN_CODE 0x29 /* table of non-instructions in __text */ #define LC_SOURCE_VERSION 0x2A /* source version used to build binary */ #define LC_DYLIB_CODE_SIGN_DRS 0x2B /* Code signing DRs copied from linked dylibs */ +#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 */ /* @@ -1155,7 +1158,8 @@ struct rpath_command { struct linkedit_data_command { uint32_t cmd; /* LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, - or LC_DYLIB_CODE_SIGN_DRS */ + LC_DYLIB_CODE_SIGN_DRS or + LC_LINKER_OPTIMIZATION_HINT. */ uint32_t cmdsize; /* sizeof(struct linkedit_data_command) */ uint32_t dataoff; /* file offset of data in __LINKEDIT segment */ uint32_t datasize; /* file size of data in __LINKEDIT segment */ @@ -1174,6 +1178,21 @@ struct encryption_info_command { 0 means not-encrypted yet */ }; +/* + * The encryption_info_command_64 contains the file offset and size of an + * of an encrypted segment (for use in x86_64 targets). + */ +struct encryption_info_command_64 { + uint32_t cmd; /* LC_ENCRYPTION_INFO_64 */ + uint32_t cmdsize; /* sizeof(struct encryption_info_command_64) */ + uint32_t cryptoff; /* file offset of encrypted range */ + uint32_t cryptsize; /* file size of encrypted range */ + uint32_t cryptid; /* which enryption system, + 0 means not-encrypted yet */ + uint32_t pad; /* padding to make this struct's size a multiple + of 8 bytes */ +}; + /* * The version_min_command contains the min OS version on which this * binary was built to run. @@ -1359,6 +1378,17 @@ struct dyld_info_command { #define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08 #define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10 +/* + * The linker_option_command contains linker options embedded in object files. + */ +struct linker_option_command { + uint32_t cmd; /* LC_LINKER_OPTION only used in MH_OBJECT filetypes */ + uint32_t cmdsize; + uint32_t count; /* number of strings */ + /* concatenation of zero terminated UTF8 strings. + Zero filled at end to align */ +}; + /* * The symseg_command contains the offset and size of the GNU style * symbol table information as described in the header file . @@ -1428,19 +1458,18 @@ struct source_version_command { /* * The LC_DATA_IN_CODE load commands uses a linkedit_data_command * to point to an array of data_in_code_entry entries. Each entry - * describes a range of data in a code section. This load command - * is only used in final linked images. + * describes a range of data in a code section. */ struct data_in_code_entry { uint32_t offset; /* from mach_header to start of data range*/ uint16_t length; /* number of bytes in data range */ uint16_t kind; /* a DICE_KIND_* value */ }; -#define DICE_KIND_DATA 0x0001 /* L$start$data$... label */ -#define DICE_KIND_JUMP_TABLE8 0x0002 /* L$start$jt8$... label */ -#define DICE_KIND_JUMP_TABLE16 0x0003 /* L$start$jt16$... label */ -#define DICE_KIND_JUMP_TABLE32 0x0004 /* L$start$jt32$... label */ -#define DICE_KIND_ABS_JUMP_TABLE32 0x0005 /* L$start$jta32$... label */ +#define DICE_KIND_DATA 0x0001 +#define DICE_KIND_JUMP_TABLE8 0x0002 +#define DICE_KIND_JUMP_TABLE16 0x0003 +#define DICE_KIND_JUMP_TABLE32 0x0004 +#define DICE_KIND_ABS_JUMP_TABLE32 0x0005 diff --git a/include/mach-o/nlist.h b/include/mach-o/nlist.h index dd19888..a5b45a0 100644 --- a/include/mach-o/nlist.h +++ b/include/mach-o/nlist.h @@ -297,14 +297,14 @@ struct nlist_64 { #define N_SYMBOL_RESOLVER 0x0100 #ifndef __STRICT_BSD__ -#if __cplusplus +#ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * The function nlist(3) from the C library. */ extern int nlist (const char *filename, struct nlist *list); -#if __cplusplus +#ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __STRICT_BSD__ */ diff --git a/include/mach/arm/_structs.h b/include/mach/arm/_structs.h index 9c7b338..0c3d756 100644 --- a/include/mach/arm/_structs.h +++ b/include/mach/arm/_structs.h @@ -25,6 +25,24 @@ _STRUCT_ARM_EXCEPTION_STATE }; #endif /* __DARWIN_UNIX03 */ +#if __DARWIN_UNIX03 +#define _STRUCT_ARM_EXCEPTION_STATE64 struct __darwin_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 */ +}; +#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 @@ -47,6 +65,30 @@ _STRUCT_ARM_THREAD_STATE }; #endif /* __DARWIN_UNIX03 */ +#if __DARWIN_UNIX03 +#define _STRUCT_ARM_THREAD_STATE64 struct __darwin_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 */ +}; +#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 @@ -64,8 +106,110 @@ _STRUCT_ARM_VFP_STATE }; #endif /* __DARWIN_UNIX03 */ -#define _STRUCT_ARM_DEBUG_STATE struct __darwin_arm_debug_state +#if __DARWIN_UNIX03 +#define _STRUCT_ARM_NEON_STATE64 struct __darwin_arm_neon_state64 +#define _STRUCT_ARM_NEON_STATE struct __darwin_arm_neon_state + +#if defined(__arm64__) +_STRUCT_ARM_NEON_STATE64 +{ + __uint128_t __v[32]; + __uint32_t __fpsr; + __uint32_t __fpcr; +}; + +_STRUCT_ARM_NEON_STATE +{ + __uint128_t __v[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 + +#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 +{ + __uint32_t __bvr[16]; + __uint32_t __bcr[16]; + __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 { __uint32_t __bvr[16]; __uint32_t __bcr[16]; @@ -73,4 +217,58 @@ _STRUCT_ARM_DEBUG_STATE __uint32_t __wcr[16]; }; +#define _STRUCT_ARM_DEBUG_STATE32 struct __darwin_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 __darwin_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) */ +}; +#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 */ +#endif + #endif /* _MACH_ARM__STRUCTS_H_ */ diff --git a/include/mach/arm/thread_state.h b/include/mach/arm/thread_state.h index 2dbcb07..e430319 100644 --- a/include/mach/arm/thread_state.h +++ b/include/mach/arm/thread_state.h @@ -14,4 +14,8 @@ #define THREAD_STATE_MAX ARM_THREAD_STATE_MAX #endif +#if defined(__arm64__) && !defined(THREAD_STATE_MAX) +#define THREAD_STATE_MAX ARM_THREAD_STATE_MAX +#endif + #endif /* _MACH_ARM_THREAD_STATE_H_ */ diff --git a/include/mach/arm/thread_status.h b/include/mach/arm/thread_status.h index aae2cb2..9eedf96 100644 --- a/include/mach/arm/thread_status.h +++ b/include/mach/arm/thread_status.h @@ -19,43 +19,516 @@ /* - * Flavors + * Flavors */ #define ARM_THREAD_STATE 1 #define ARM_VFP_STATE 2 #define ARM_EXCEPTION_STATE 3 -#define ARM_DEBUG_STATE 4 +#define ARM_DEBUG_STATE 4 /* pre-armv8 */ #define THREAD_STATE_NONE 5 +#define ARM_THREAD_STATE64 6 +#define ARM_EXCEPTION_STATE64 7 + +/* ARM64_TODO: ref. ARM_SAVED_STATE64. Separate these namespaces! */ + +#ifdef XNU_KERNEL_PRIVATE +#define THREAD_STATE_LAST 8 +#endif + +/* For kernel use */ +#define ARM_SAVED_STATE32 (THREAD_STATE_LAST+1) +#define ARM_SAVED_STATE64 (THREAD_STATE_LAST+2) +#define ARM_NEON_SAVED_STATE32 (THREAD_STATE_LAST+3) +#define ARM_NEON_SAVED_STATE64 (THREAD_STATE_LAST+4) +/* ARM_VFP_STATE64 (THREAD_STATE_LAST+5) */ +/* API */ +#define ARM_DEBUG_STATE32 (THREAD_STATE_LAST+6) +#define ARM_DEBUG_STATE64 (THREAD_STATE_LAST+7) +#define ARM_NEON_STATE64 (THREAD_STATE_LAST+9) #define VALID_THREAD_STATE_FLAVOR(x)\ ((x == ARM_THREAD_STATE) || \ (x == ARM_VFP_STATE) || \ (x == ARM_EXCEPTION_STATE) || \ (x == ARM_DEBUG_STATE) || \ - (x == THREAD_STATE_NONE)) + (x == THREAD_STATE_NONE) || \ + (x == ARM_NEON_STATE) || \ + (x == ARM_DEBUG_STATE32) || \ + (x == ARM_THREAD_STATE64) || \ + (x == ARM_EXCEPTION_STATE64) || \ + (x == ARM_NEON_STATE64) || \ + (x == ARM_DEBUG_STATE64)) typedef _STRUCT_ARM_THREAD_STATE arm_thread_state_t; +typedef _STRUCT_ARM_THREAD_STATE64 arm_thread_state64_t; typedef _STRUCT_ARM_VFP_STATE arm_vfp_state_t; +typedef _STRUCT_ARM_NEON_STATE arm_neon_state_t; +typedef _STRUCT_ARM_NEON_STATE64 arm_neon_state64_t; typedef _STRUCT_ARM_EXCEPTION_STATE arm_exception_state_t; +typedef _STRUCT_ARM_EXCEPTION_STATE64 arm_exception_state64_t; + +#if defined(XNU_KERNEL_PRIVATE) && defined(__arm64__) +/* See below for ARM64 kernel structure definition for arm_debug_state. */ +#else +/* + * Otherwise not ARM64 kernel and we must preserve legacy ARM definitions of + * arm_debug_state for binary compatability of userland consumers of this file. + */ +#if defined(__arm__) typedef _STRUCT_ARM_DEBUG_STATE arm_debug_state_t; +#elif defined(__arm64__) +typedef _STRUCT_ARM_LEGACY_DEBUG_STATE arm_debug_state_t; +#else +/* #error Undefined architecture */ +#endif +#endif #define ARM_THREAD_STATE_COUNT ((mach_msg_type_number_t) \ (sizeof (arm_thread_state_t)/sizeof(uint32_t))) +#define ARM_THREAD_STATE64_COUNT ((mach_msg_type_number_t) \ + (sizeof (arm_thread_state64_t)/sizeof(uint32_t))) + #define ARM_VFP_STATE_COUNT ((mach_msg_type_number_t) \ (sizeof (arm_vfp_state_t)/sizeof(uint32_t))) #define ARM_EXCEPTION_STATE_COUNT ((mach_msg_type_number_t) \ (sizeof (arm_exception_state_t)/sizeof(uint32_t))) +#define ARM_EXCEPTION_STATE64_COUNT ((mach_msg_type_number_t) \ + (sizeof (arm_exception_state64_t)/sizeof(uint32_t))) + #define ARM_DEBUG_STATE_COUNT ((mach_msg_type_number_t) \ (sizeof (arm_debug_state_t)/sizeof(uint32_t))) +#define MACHINE_THREAD_STATE ARM_THREAD_STATE64 +#define MACHINE_THREAD_STATE_COUNT ARM_THREAD_STATE_COUNT64 + /* * Largest state on this machine: */ #define THREAD_MACHINE_STATE_MAX THREAD_STATE_MAX +#ifdef XNU_KERNEL_PRIVATE + +#if defined(__arm__) + +#define ARM_SAVED_STATE THREAD_STATE_NONE + 1 + +struct arm_saved_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 */ + uint32_t fsr; /* Fault status */ + uint32_t far; /* Virtual Fault Address */ + uint32_t exception; /* exception number */ +}; +typedef struct arm_saved_state arm_saved_state_t; + +#ifdef XNU_KERNEL_PRIVATE +typedef struct arm_saved_state arm_saved_state32_t; + +/* + * Just for coexistence with AArch64 code. + */ +static inline arm_saved_state32_t* +saved_state32(arm_saved_state_t *iss) +{ + return iss; +} + +static inline boolean_t +is_saved_state32(arm_saved_state_t *iss __unused) +{ + return TRUE; +} + +#endif + +struct arm_saved_state_tagged { + uint32_t tag; + struct arm_saved_state state; +}; +typedef struct arm_saved_state_tagged arm_saved_state_tagged_t; + +#define ARM_SAVED_STATE32_COUNT ((mach_msg_type_number_t) \ + (sizeof (arm_saved_state_t)/sizeof(unsigned int))) + +#elif defined(__arm64__) + +#include +#include +#define CAST_ASSERT_SAFE(type, val) (assert((val) == ((type)(val))), (type)(val)) + +/* + * GPR context + */ + + +struct arm_saved_state32 { + 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 */ + uint32_t far; /* Virtual fault address */ + uint32_t esr; /* Exception syndrome register */ + uint32_t exception; /* Exception number */ +}; +typedef struct arm_saved_state32 arm_saved_state32_t; + +struct arm_saved_state32_tagged { + uint32_t tag; + struct arm_saved_state32 state; +}; +typedef struct arm_saved_state32_tagged arm_saved_state32_tagged_t; + +#define ARM_SAVED_STATE32_COUNT ((mach_msg_type_number_t) \ + (sizeof (arm_saved_state32_t)/sizeof(unsigned int))) + +struct arm_saved_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 */ + uint32_t reserved; /* Reserved padding */ + uint64_t far; /* Virtual fault address */ + uint32_t esr; /* Exception syndrome register */ + uint32_t exception; /* Exception number */ +}; +typedef struct arm_saved_state64 arm_saved_state64_t; + +#define ARM_SAVED_STATE64_COUNT ((mach_msg_type_number_t) \ + (sizeof (arm_saved_state64_t)/sizeof(unsigned int))) + +struct arm_saved_state64_tagged { + uint32_t tag; + struct arm_saved_state64 state; +}; +typedef struct arm_saved_state64_tagged arm_saved_state64_tagged_t; + +struct arm_saved_state { + uint32_t flavor; + union { + struct arm_saved_state32 ss_32; + struct arm_saved_state64 ss_64; + } uss; +} __attribute__((aligned(16))); +#define ss_32 uss.ss_32 +#define ss_64 uss.ss_64 + +typedef struct arm_saved_state arm_saved_state_t; + + +static inline boolean_t +is_saved_state32(arm_saved_state_t *iss) +{ + return (iss->flavor == ARM_SAVED_STATE32); +} + +static inline boolean_t +is_saved_state64(arm_saved_state_t *iss) +{ + return (iss->flavor == ARM_SAVED_STATE64); +} + +static inline arm_saved_state32_t* +saved_state32(arm_saved_state_t *iss) +{ + return &iss->ss_32; +} + +static inline arm_saved_state64_t* +saved_state64(arm_saved_state_t *iss) +{ + return &iss->ss_64; +} + +static inline register_t +get_saved_state_pc(arm_saved_state_t *iss) +{ + return (is_saved_state32(iss) ? saved_state32(iss)->pc : saved_state64(iss)->pc); +} + +static inline void +set_saved_state_pc(arm_saved_state_t *iss, register_t pc) +{ + if (is_saved_state32(iss)) { + saved_state32(iss)->pc = CAST_ASSERT_SAFE(uint32_t, pc); + } else { + saved_state64(iss)->pc = pc; + } +} + +static inline register_t +get_saved_state_sp(arm_saved_state_t *iss) +{ + return (is_saved_state32(iss) ? saved_state32(iss)->sp : saved_state64(iss)->sp); +} + +static inline void +set_saved_state_sp(arm_saved_state_t *iss, register_t sp) +{ + if (is_saved_state32(iss)) { + saved_state32(iss)->sp = CAST_ASSERT_SAFE(uint32_t, sp); + } else { + saved_state64(iss)->sp = sp; + } +} + +static inline register_t +get_saved_state_lr(arm_saved_state_t *iss) +{ + return (is_saved_state32(iss) ? saved_state32(iss)->lr : saved_state64(iss)->lr); +} + +static inline void +set_saved_state_lr(arm_saved_state_t *iss, register_t lr) +{ + if (is_saved_state32(iss)) { + saved_state32(iss)->lr = CAST_ASSERT_SAFE(uint32_t, lr); + } else { + saved_state64(iss)->lr = lr; + } +} + +static inline register_t +get_saved_state_fp(arm_saved_state_t *iss) +{ + return (is_saved_state32(iss) ? saved_state32(iss)->r[7] : saved_state64(iss)->fp); +} + +static inline void +set_saved_state_fp(arm_saved_state_t *iss, register_t fp) +{ + if (is_saved_state32(iss)) { + saved_state32(iss)->r[7] = CAST_ASSERT_SAFE(uint32_t, fp); + } else { + saved_state64(iss)->fp = fp; + } +} + +static inline int +check_saved_state_reglimit(arm_saved_state_t *iss, unsigned reg) +{ + return (is_saved_state32(iss) ? (reg < ARM_SAVED_STATE32_COUNT) : (reg < ARM_SAVED_STATE64_COUNT)); +} + +static inline register_t +get_saved_state_reg(arm_saved_state_t *iss, unsigned reg) +{ + if (!check_saved_state_reglimit(iss, reg)) return 0; + + return (is_saved_state32(iss) ? (saved_state32(iss)->r[reg]) : (saved_state64(iss)->x[reg])); +} + +static inline void +set_saved_state_reg(arm_saved_state_t *iss, unsigned reg, register_t value) +{ + if (!check_saved_state_reglimit(iss, reg)) return; + + if (is_saved_state32(iss)) { + saved_state32(iss)->r[reg] = CAST_ASSERT_SAFE(uint32_t, value); + } else { + saved_state64(iss)->x[reg] = value; + } +} + +static inline uint32_t +get_saved_state_cpsr(arm_saved_state_t *iss) +{ + return (is_saved_state32(iss) ? saved_state32(iss)->cpsr : saved_state64(iss)->cpsr); +} + +static inline void +set_saved_state_cpsr(arm_saved_state_t *iss, uint32_t cpsr) +{ + if (is_saved_state32(iss)) { + saved_state32(iss)->cpsr = cpsr; + } else { + saved_state64(iss)->cpsr = cpsr; + } +} + +static inline register_t +get_saved_state_far(arm_saved_state_t *iss) +{ + return (is_saved_state32(iss) ? saved_state32(iss)->far : saved_state64(iss)->far); +} + +static inline void +set_saved_state_far(arm_saved_state_t *iss, register_t far) +{ + if (is_saved_state32(iss)) { + saved_state32(iss)->far = CAST_ASSERT_SAFE(uint32_t, far); + } else { + saved_state64(iss)->far = far; + } +} + +static inline uint32_t +get_saved_state_esr(arm_saved_state_t *iss) +{ + return (is_saved_state32(iss) ? saved_state32(iss)->esr : saved_state64(iss)->esr); +} + +static inline void +set_saved_state_esr(arm_saved_state_t *iss, uint32_t esr) +{ + if (is_saved_state32(iss)) { + saved_state32(iss)->esr = esr; + } else { + saved_state64(iss)->esr = esr; + } +} + +static inline uint32_t +get_saved_state_exc(arm_saved_state_t *iss) +{ + return (is_saved_state32(iss) ? saved_state32(iss)->exception : saved_state64(iss)->exception); +} + +static inline void +set_saved_state_exc(arm_saved_state_t *iss, uint32_t exc) +{ + if (is_saved_state32(iss)) { + saved_state32(iss)->exception = exc; + } else { + saved_state64(iss)->exception = exc; + } +} + +/* + * ARM64_TODO: what register holds syscall number? + */ +extern void panic_unimplemented(void); + +static inline int +get_saved_state_svc_number(arm_saved_state_t *iss) +{ + return (is_saved_state32(iss) ? (int)saved_state32(iss)->r[12] : (int)saved_state64(iss)->x[ARM64_SYSCALL_CODE_REG_NUM]); /* Only first word counts here */ +} + + +typedef _STRUCT_ARM_LEGACY_DEBUG_STATE arm_legacy_debug_state_t; +typedef _STRUCT_ARM_DEBUG_STATE32 arm_debug_state32_t; +typedef _STRUCT_ARM_DEBUG_STATE64 arm_debug_state64_t; + +struct arm_state_hdr { + int flavor; + int count; +}; +typedef struct arm_state_hdr arm_state_hdr_t; + +struct arm_debug_aggregate_state { + arm_state_hdr_t dsh; + union { + arm_debug_state32_t ds32; + arm_debug_state64_t ds64; + } uds; +} __attribute__((aligned(16))); + +typedef struct arm_debug_aggregate_state arm_debug_state_t; + +#define ARM_LEGACY_DEBUG_STATE_COUNT ((mach_msg_type_number_t) \ + (sizeof (arm_legacy_debug_state_t)/sizeof(uint32_t))) + +#define ARM_DEBUG_STATE32_COUNT ((mach_msg_type_number_t) \ + (sizeof (arm_debug_state32_t)/sizeof(uint32_t))) + +#define ARM_DEBUG_STATE64_COUNT ((mach_msg_type_number_t) \ + (sizeof (arm_debug_state64_t)/sizeof(uint32_t))) + +/* + * NEON context + */ +typedef __uint128_t uint128_t; +typedef uint64_t uint64x2_t __attribute__((ext_vector_type(2))); +typedef uint32_t uint32x4_t __attribute__((ext_vector_type(4))); + +struct arm_neon_saved_state32 { + union { + uint128_t q[16]; + uint64_t d[32]; + uint32_t s[32]; + } v; + uint32_t fpsr; + uint32_t fpcr; +}; +typedef struct arm_neon_saved_state32 arm_neon_saved_state32_t; + +struct arm_neon_saved_state64 { + union { + uint128_t q[32]; + uint64x2_t d[32]; + uint32x4_t s[32]; + } v; + uint32_t fpsr; + uint32_t fpcr; +}; +typedef struct arm_neon_saved_state64 arm_neon_saved_state64_t; + + +#define ARM_NEON_STATE_COUNT ((mach_msg_type_number_t) \ + (sizeof (arm_neon_state_t)/sizeof(uint32_t))) +#define ARM_NEON_STATE64_COUNT ((mach_msg_type_number_t) \ + (sizeof (arm_neon_state64_t)/sizeof(uint32_t))) + +struct arm_neon_saved_state { + uint32_t flavor; + union { + struct arm_neon_saved_state32 ns_32; + struct arm_neon_saved_state64 ns_64; + } uns; +}; +typedef struct arm_neon_saved_state arm_neon_saved_state_t; +#define ns_32 uns.ns_32 +#define ns_64 uns.ns_64 + +static inline boolean_t +is_neon_saved_state32(arm_neon_saved_state_t *state) +{ + return (state->flavor == ARM_NEON_SAVED_STATE32); +} + +static inline boolean_t +is_neon_saved_state64(arm_neon_saved_state_t *state) +{ + return (state->flavor == ARM_NEON_SAVED_STATE64); +} + +static inline arm_neon_saved_state32_t * +neon_state32(arm_neon_saved_state_t *state) +{ + return &state->ns_32; +} + +static inline arm_neon_saved_state64_t * +neon_state64(arm_neon_saved_state_t *state) +{ + return &state->ns_64; +} + + +/* + * Aggregated context + */ + +struct arm_context { + struct arm_saved_state ss; + struct arm_neon_saved_state ns; +}; +typedef struct arm_context arm_context_t; + +#else +#error Unknown arch +#endif + +#endif /* XNU_KERNEL_PRIVATE */ #endif /* _ARM_THREAD_STATUS_H_ */ diff --git a/include/mach/machine.h b/include/mach/machine.h index 0bca89b..28a5a1c 100644 --- a/include/mach/machine.h +++ b/include/mach/machine.h @@ -159,6 +159,8 @@ extern vm_offset_t interrupt_stack[]; #define CPU_ARCH_ABI64 0x1000000 #define CPU_TYPE_POWERPC64 ((cpu_type_t)(CPU_TYPE_POWERPC | CPU_ARCH_ABI64)) #define CPU_TYPE_VEO ((cpu_type_t) 255) +#define CPU_TYPE_ARM64 ((cpu_type_t)(CPU_TYPE_ARM | CPU_ARCH_ABI64)) + /* * Machine subtypes (these are defined here, instead of in a machine @@ -249,6 +251,7 @@ extern vm_offset_t interrupt_stack[]; #define CPU_SUBTYPE_INTEL_MODEL(x) ((x) >> 4) #define CPU_SUBTYPE_INTEL_MODEL_ALL 0 +#define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) /* Haswell and compatible */ /* * Mips subtypes. @@ -307,7 +310,15 @@ extern vm_offset_t interrupt_stack[]; #define CPU_SUBTYPE_ARM_XSCALE ((cpu_subtype_t) 8) #define CPU_SUBTYPE_ARM_V7 ((cpu_subtype_t) 9) #define CPU_SUBTYPE_ARM_V7F ((cpu_subtype_t) 10) /* Cortex A9 */ -#define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t) 12) +#define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t) 11) /* Swift */ +#define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t) 12) /* Kirkwood40 */ +#define CPU_SUBTYPE_ARM_V6M ((cpu_subtype_t) 14) /* Not meant to be run under xnu */ +#define CPU_SUBTYPE_ARM_V7M ((cpu_subtype_t) 15) /* Not meant to be run under xnu */ +#define CPU_SUBTYPE_ARM_V7EM ((cpu_subtype_t) 16) /* Not meant to be run under xnu */ +#define CPU_SUBTYPE_ARM_V8 ((cpu_subtype_t) 13) + +#define CPU_SUBTYPE_ARM64_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_ARM64_V8 ((cpu_subtype_t) 1) /* * MC88000 subtypes @@ -385,4 +396,5 @@ extern vm_offset_t interrupt_stack[]; #define CPU_SUBTYPE_VEO_4 ((cpu_subtype_t) 4) #define CPU_SUBTYPE_VEO_ALL CPU_SUBTYPE_VEO_2 + #endif /* _MACH_MACHINE_H_ */ diff --git a/include/stuff/breakout.h b/include/stuff/breakout.h index 7f97153..faff33c 100644 --- a/include/stuff/breakout.h +++ b/include/stuff/breakout.h @@ -48,8 +48,8 @@ struct toc_entry { struct arch { char *file_name; /* name of file this arch came from */ enum ofile_type type; /* The type of file for this architecture */ - /* can be OFILE_ARCHIVE, OFILE_Mach_O or */ - /* OFILE_UNKNOWN. */ + /* can be OFILE_ARCHIVE, OFILE_Mach_O, */ + /* OFILE_LLVM_BITCODE or OFILE_UNKNOWN. */ struct fat_arch *fat_arch; /* If this came from fat file this is valid */ /* and not NULL (needed for the align value */ /* and to output a fat file if only one arch)*/ @@ -84,6 +84,11 @@ struct arch { /* if this is an object file: the object file */ struct object *object; /* the object file */ +#ifdef LTO_SUPPORT + /* if this member is an llvm bit code file: the lto module */ + void *lto; /* lto module */ +#endif /* LTO_SUPPORT */ + /* if this is an unknown file: the addr and size of the file */ char *unknown_addr; uint32_t unknown_size; @@ -94,7 +99,7 @@ struct arch { struct member { enum ofile_type type; /* the type of this member can be OFILE_Mach_O*/ - /* or OFILE_UNKNOWN */ + /* OFILE_LLVM_BITCODE or OFILE_UNKNOWN */ struct ar_hdr *ar_hdr; /* the archive header for this member */ uint32_t offset; /* current working offset and final offset */ /* use in creating the table of contents */ @@ -108,6 +113,11 @@ struct member { /* if this member is an object file: the object file */ struct object *object; /* the object file */ +#ifdef LTO_SUPPORT + /* if this member is an llvm bit code file: the lto module */ + void *lto; /* lto module */ +#endif /* LTO_SUPPORT */ + /* if this member is an unknown file: the addr and size of the member */ char *unknown_addr; uint32_t unknown_size; @@ -152,6 +162,9 @@ struct object { *data_in_code_cmd; /* the data in code load command, if any */ struct linkedit_data_command *code_sign_drs_cmd; /* the code signing DRs command, if any */ + struct linkedit_data_command + *link_opt_hint_cmd; /* the linker optimization hint command, + if any */ struct section **sections; /* array of 32-bit section structs */ struct section_64 **sections64; /* array of 64-bit section structs */ struct dyld_info_command @@ -200,6 +213,8 @@ struct object { uint32_t output_data_in_code_info_data_size; char *output_code_sign_drs_info_data; uint32_t output_code_sign_drs_info_data_size; + char *output_link_opt_hint_info_data; + uint32_t output_link_opt_hint_info_data_size; uint32_t output_ilocalsym; uint32_t output_nlocalsym; diff --git a/include/stuff/bytesex.h b/include/stuff/bytesex.h index bc74335..2e5f4c4 100644 --- a/include/stuff/bytesex.h +++ b/include/stuff/bytesex.h @@ -50,10 +50,6 @@ #include #include #include -#undef MACHINE_THREAD_STATE /* need to undef these to avoid warnings */ -#undef MACHINE_THREAD_STATE_COUNT -#undef THREAD_STATE_NONE -#undef VALID_THREAD_STATE_FLAVOR #include #include #include @@ -311,6 +307,10 @@ __private_extern__ void swap_arm_thread_state_t( arm_thread_state_t *cpu, enum byte_sex target_byte_sex); +__private_extern__ void swap_arm_thread_state64_t( + arm_thread_state64_t *cpu, + enum byte_sex target_byte_sex); + __private_extern__ void swap_ident_command( struct ident_command *id_cmd, enum byte_sex target_byte_sex); @@ -351,6 +351,14 @@ __private_extern__ void swap_encryption_command( struct encryption_info_command *ec, enum byte_sex target_byte_sex); +__private_extern__ void swap_encryption_command_64( + struct encryption_info_command_64 *ec, + enum byte_sex target_byte_sex); + +__private_extern__ void swap_linker_option_command( + struct linker_option_command *lo, + enum byte_sex target_byte_sex); + __private_extern__ void swap_dyld_info_command( struct dyld_info_command *dc, enum byte_sex target_byte_sex); @@ -413,6 +421,11 @@ __private_extern__ void swap_twolevel_hint( uint32_t nhints, enum byte_sex target_byte_sex); +__private_extern__ void swap_data_in_code_entry( + struct data_in_code_entry *dices, + uint32_t ndices, + 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/include/stuff/errors.h b/include/stuff/errors.h index 294a217..a2da7ce 100644 --- a/include/stuff/errors.h +++ b/include/stuff/errors.h @@ -25,67 +25,63 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__MWERKS__) && !defined(__private_extern__) -#define __private_extern__ __declspec(private_extern) -#endif - #import "mach/mach.h" /* user defined (imported) */ -__private_extern__ char *progname; +extern char *progname __attribute__((visibility("hidden"))); /* defined in errors.c */ /* number of detected calls to error() */ -__private_extern__ uint32_t errors; +extern uint32_t errors __attribute__((visibility("hidden"))); -__private_extern__ void warning( +extern void warning( const char *format, ...) #ifdef __GNUC__ __attribute__ ((format (printf, 1, 2))) #endif - ; -__private_extern__ void error( + __attribute__((visibility("hidden"))); +extern void error( const char *format, ...) #ifdef __GNUC__ __attribute__ ((format (printf, 1, 2))) #endif - ; -__private_extern__ void error_with_arch( + __attribute__((visibility("hidden"))); +extern void error_with_arch( const char *arch_name, const char *format, ...) #ifdef __GNUC__ __attribute__ ((format (printf, 2, 3))) #endif - ; -__private_extern__ void system_error( + __attribute__((visibility("hidden"))); +extern void system_error( const char *format, ...) #ifdef __GNUC__ __attribute__ ((format (printf, 1, 2))) #endif - ; -__private_extern__ void fatal( + __attribute__((visibility("hidden"))); +extern void fatal( const char *format, ...) #ifdef __GNUC__ __attribute__ ((format (printf, 1, 2))) #endif - ; -__private_extern__ void system_fatal( + __attribute__((visibility("hidden"))); +extern void system_fatal( const char *format, ...) #ifdef __GNUC__ __attribute__ ((format (printf, 1, 2))) #endif - ; -__private_extern__ void my_mach_error( + __attribute__((visibility("hidden"))); +extern void my_mach_error( kern_return_t r, char *format, ...) #ifdef __GNUC__ __attribute__ ((format (printf, 2, 3))) #endif - ; -__private_extern__ void mach_fatal( + __attribute__((visibility("hidden"))); +extern void mach_fatal( kern_return_t r, char *format, ...) #ifdef __GNUC__ __attribute__ ((format (printf, 2, 3))) #endif - ; + __attribute__((visibility("hidden"))); diff --git a/include/stuff/ofile.h b/include/stuff/ofile.h index 0b97e7e..1bcf577 100644 --- a/include/stuff/ofile.h +++ b/include/stuff/ofile.h @@ -57,7 +57,7 @@ enum ofile_type { struct ofile { char *file_name; /* pointer to name malloc'ed by ofile_map */ char *file_addr; /* pointer to vm_allocate'ed memory */ - uint32_t file_size; /* size of vm_allocate'ed memory */ + uint64_t file_size; /* size of vm_allocate'ed memory */ uint64_t file_mtime; /* stat(2)'s mtime */ enum ofile_type file_type; /* type of the file */ @@ -159,7 +159,7 @@ __private_extern__ NSObjectFileImageReturnCode ofile_map_from_memory( __private_extern__ enum bool ofile_map_from_memory( #endif char *addr, - uint32_t size, + uint64_t size, const char *file_name, uint64_t mtime, const struct arch_flag *arch_flag, /* can be NULL */ diff --git a/install_name_tool.c b/install_name_tool.c index d576e62..e3647c2 100644 --- a/install_name_tool.c +++ b/install_name_tool.c @@ -595,6 +595,16 @@ struct object *object) object->output_sym_info_size += 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->input_sym_info_size += + object->link_opt_hint_cmd->datasize; + object->output_sym_info_size += + object->link_opt_hint_cmd->datasize; + } if(object->hints_cmd != NULL){ object->output_hints = (struct twolevel_hint *) (object->object_addr + @@ -978,6 +988,7 @@ uint32_t *header_size) rpath2->path.offset = sizeof(struct rpath_command); path2 = (char *)rpath2 + rpath2->path.offset; strcpy(path2, add_rpaths[i].new); + lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize); } ncmds += nadd_rpaths; ncmds -= ndelete_rpaths; @@ -1061,6 +1072,10 @@ uint32_t *header_size) arch->object->code_sign_drs_cmd = (struct linkedit_data_command *)lc1; break; + case LC_LINKER_OPTIMIZATION_HINT: + arch->object->link_opt_hint_cmd = + (struct linkedit_data_command *)lc1; + break; } lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize); } diff --git a/libstuff/arch.c b/libstuff/arch.c index 10488c1..5fb88c3 100644 --- a/libstuff/arch.c +++ b/libstuff/arch.c @@ -48,6 +48,8 @@ static const struct arch_flag arch_flags[] = { /* architecture families */ { "ppc64", CPU_TYPE_POWERPC64, CPU_SUBTYPE_POWERPC_ALL }, { "x86_64", CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL }, + { "x86_64h", CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H }, + { "arm64", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL }, /* specific architecture implementations */ { "ppc970-64", CPU_TYPE_POWERPC64, CPU_SUBTYPE_POWERPC_970 }, @@ -94,9 +96,14 @@ static const struct arch_flag arch_flags[] = { { "armv5", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V5TEJ}, { "xscale", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_XSCALE}, { "armv6", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6 }, + { "armv6m", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6M }, { "armv7", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7 }, { "armv7f", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7F }, + { "armv7s", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S }, { "armv7k", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7K }, + { "armv7m", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7M }, + { "armv7em", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7EM }, + { "arm64v8",CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_V8 }, { NULL, 0, 0 } }; @@ -214,6 +221,7 @@ const struct arch_flag *flag) return BIG_ENDIAN_BYTE_SEX; else if(flag->cputype == CPU_TYPE_I386 || flag->cputype == CPU_TYPE_X86_64 || + flag->cputype == CPU_TYPE_ARM64 || flag->cputype == CPU_TYPE_ARM) return LITTLE_ENDIAN_BYTE_SEX; else diff --git a/libstuff/breakout.c b/libstuff/breakout.c index 50fec73..5f10307 100644 --- a/libstuff/breakout.c +++ b/libstuff/breakout.c @@ -30,6 +30,9 @@ #include "stuff/errors.h" #include "stuff/rnd.h" #include "stuff/crc32.h" +#ifdef LTO_SUPPORT +#include "stuff/lto.h" +#endif /* LTO_SUPPORT */ static void breakout_internal( char *filename, @@ -170,6 +173,14 @@ struct ofile *ofile) arch->object->load_commands = ofile->load_commands; cksum_object(arch, calculate_input_prebind_cksum); } +#ifdef LTO_SUPPORT + else if(ofile->arch_type == OFILE_LLVM_BITCODE){ + arch->lto = ofile->lto; + arch->unknown_addr = ofile->file_addr + + arch->fat_arch->offset; + arch->unknown_size = arch->fat_arch->size; + } +#endif /* LTO_SUPPORT */ else{ /* ofile->arch_type == OFILE_UNKNOWN */ arch->unknown_addr = ofile->file_addr + arch->fat_arch->offset; @@ -201,6 +212,16 @@ struct ofile *ofile) arch->object->load_commands = ofile->load_commands; cksum_object(arch, calculate_input_prebind_cksum); } +#ifdef LTO_SUPPORT + else if(ofile->file_type == OFILE_LLVM_BITCODE && errors == 0){ + arch = new_arch(archs, narchs); + arch->file_name = savestr(filename); + arch->type = ofile->file_type; + arch->lto = ofile->lto; + arch->unknown_addr = ofile->file_addr; + arch->unknown_size = ofile->file_size; + } +#endif /* LTO_SUPPORT */ else if(errors == 0){ /* ofile->file_type == OFILE_UNKNOWN */ arch = new_arch(archs, narchs); arch->file_name = savestr(filename); @@ -327,6 +348,13 @@ struct ofile *ofile) member->object->mh_cpusubtype = ofile->mh_cpusubtype; member->object->load_commands = ofile->load_commands; } +#ifdef LTO_SUPPORT + else if(ofile->member_type == OFILE_LLVM_BITCODE){ + member->lto = ofile->lto; + member->unknown_addr = ofile->member_addr; + member->unknown_size = ofile->member_size; + } +#endif /* LTO_SUPPORT */ else{ /* ofile->member_type == OFILE_UNKNOWN */ member->unknown_addr = ofile->member_addr; member->unknown_size = ofile->member_size; @@ -436,6 +464,12 @@ uint32_t narchs) ofile_unmap(archs[i].members[j].object->ld_r_ofile); free(archs[i].members[j].object); } +#ifdef LTO_SUPPORT + else if(archs[i].members[j].type == OFILE_LLVM_BITCODE){ + if(archs[i].members[j].lto != NULL) + lto_free(archs[i].members[j].lto); + } +#endif /* LTO_SUPPORT */ } if(archs[i].nmembers > 0 && archs[i].members != NULL) free(archs[i].members); @@ -445,6 +479,12 @@ uint32_t narchs) ofile_unmap(archs[i].object->ld_r_ofile); free(archs[i].object); } +#ifdef LTO_SUPPORT + else if(archs[i].type == OFILE_LLVM_BITCODE){ + if(archs[i].lto != NULL) + lto_free(archs[i].lto); + } +#endif /* LTO_SUPPORT */ } if(narchs > 0 && archs != NULL) free(archs); diff --git a/libstuff/bytesex.c b/libstuff/bytesex.c index 61990dd..27e7169 100644 --- a/libstuff/bytesex.c +++ b/libstuff/bytesex.c @@ -200,10 +200,6 @@ #include #include #include -#undef MACHINE_THREAD_STATE /* need to undef these to avoid warnings */ -#undef MACHINE_THREAD_STATE_COUNT -#undef THREAD_STATE_NONE -#undef VALID_THREAD_STATE_FLAVOR #include #include #include @@ -2349,6 +2345,22 @@ enum byte_sex target_byte_sex) cpu->__cpsr = SWAP_INT(cpu->__cpsr); } +void +swap_arm_thread_state64_t( +arm_thread_state64_t *cpu, +enum byte_sex target_byte_sex) +{ + int i; + + for(i = 0; i < 29; i++) + cpu->__x[i] = SWAP_LONG_LONG(cpu->__x[i]); + cpu->__fp = SWAP_LONG_LONG(cpu->__fp); + cpu->__lr = SWAP_LONG_LONG(cpu->__lr); + cpu->__sp = SWAP_LONG_LONG(cpu->__sp); + cpu->__pc = SWAP_LONG_LONG(cpu->__pc); + cpu->__cpsr = SWAP_INT(cpu->__cpsr); +} + __private_extern__ void swap_ident_command( @@ -2462,6 +2474,22 @@ enum byte_sex target_byte_sex) } } +__private_extern__ +void +swap_data_in_code_entry( +struct data_in_code_entry *dices, +uint32_t ndices, +enum byte_sex target_byte_sex) +{ + uint32_t i; + + for(i = 0; i < ndices; i++){ + dices[i].offset = SWAP_INT(dices[i].offset); + dices[i].length = SWAP_INT(dices[i].length); + dices[i].kind = SWAP_INT(dices[i].kind); + } +} + __private_extern__ void swap_prebind_cksum_command( @@ -2533,6 +2561,31 @@ enum byte_sex target_byte_sex) ec->cryptid = SWAP_INT(ec->cryptid); } +__private_extern__ + void +swap_encryption_command_64( +struct encryption_info_command_64 *ec, +enum byte_sex target_byte_sex) +{ + ec->cmd = SWAP_INT(ec->cmd); + ec->cmdsize = SWAP_INT(ec->cmdsize); + ec->cryptoff = SWAP_INT(ec->cryptoff); + ec->cryptsize = SWAP_INT(ec->cryptsize); + ec->cryptid = SWAP_INT(ec->cryptid); + ec->cryptid = SWAP_INT(ec->pad); +} + +__private_extern__ + void +swap_linker_option_command( +struct linker_option_command *lo, +enum byte_sex target_byte_sex) +{ + lo->cmd = SWAP_INT(lo->cmd); + lo->cmdsize = SWAP_INT(lo->cmdsize); + lo->count = SWAP_INT(lo->count); +} + __private_extern__ void swap_dyld_info_command( diff --git a/libstuff/checkout.c b/libstuff/checkout.c index 5b893c1..7404671 100644 --- a/libstuff/checkout.c +++ b/libstuff/checkout.c @@ -155,6 +155,13 @@ struct object *object) object->code_sign_drs_cmd = (struct linkedit_data_command *)lc; } + else if(lc->cmd == LC_LINKER_OPTIMIZATION_HINT){ + if(object->link_opt_hint_cmd != NULL) + fatal_arch(arch, member, "malformed file (more than one " + "LC_LINKER_OPTIMIZATION_HINT load command): "); + object->link_opt_hint_cmd = + (struct linkedit_data_command *)lc; + } else if((lc->cmd == LC_DYLD_INFO) ||(lc->cmd == LC_DYLD_INFO_ONLY)){ if(object->dyld_info != NULL) fatal_arch(arch, member, "malformed file (more than one " @@ -394,6 +401,12 @@ struct object *object) 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) + order_error(arch, member, "linker optimization hint info out " + "of place"); + offset += object->link_opt_hint_cmd->datasize; + } if(object->st->nsyms != 0){ if(object->st->symoff != offset) order_error(arch, member, "symbol table out of place"); diff --git a/libstuff/errors.c b/libstuff/errors.c index 0a7ca53..5a7dad6 100644 --- a/libstuff/errors.c +++ b/libstuff/errors.c @@ -45,7 +45,7 @@ const char *format, va_list ap; va_start(ap, format); - fprintf(stderr, "%s: ", progname); + fprintf(stderr, "warning: %s: ", progname); vfprintf(stderr, format, ap); fprintf(stderr, "\n"); va_end(ap); @@ -64,7 +64,7 @@ const char *format, va_list ap; va_start(ap, format); - fprintf(stderr, "%s: ", progname); + fprintf(stderr, "error: %s: ", progname); vfprintf(stderr, format, ap); fprintf(stderr, "\n"); va_end(ap); @@ -85,7 +85,7 @@ const char *format, va_list ap; va_start(ap, format); - fprintf(stderr, "%s: ", progname); + fprintf(stderr, "error: %s: ", progname); if(arch_name != NULL) fprintf(stderr, "for architecture: %s ", arch_name); vfprintf(stderr, format, ap); @@ -107,7 +107,7 @@ const char *format, va_list ap; va_start(ap, format); - fprintf(stderr, "%s: ", progname); + fprintf(stderr, "error: %s: ", progname); vfprintf(stderr, format, ap); fprintf(stderr, " (%s)\n", strerror(errno)); va_end(ap); @@ -127,7 +127,7 @@ char *format, va_list ap; va_start(ap, format); - fprintf(stderr, "%s: ", progname); + fprintf(stderr, "error: %s: ", progname); vfprintf(stderr, format, ap); fprintf(stderr, " (%s)\n", mach_error_string(r)); va_end(ap); diff --git a/libstuff/execute.c b/libstuff/execute.c index cbc58bb..46a705c 100644 --- a/libstuff/execute.c +++ b/libstuff/execute.c @@ -149,7 +149,7 @@ char *str) int i; char *p; char *prefix, buf[MAXPATHLEN], resolved_name[PATH_MAX]; - unsigned long bufsize; + uint32_t bufsize; /* * Construct the prefix to the program running. diff --git a/libstuff/fatals.c b/libstuff/fatals.c index 20b45d3..a7947bd 100644 --- a/libstuff/fatals.c +++ b/libstuff/fatals.c @@ -43,7 +43,7 @@ const char *format, va_list ap; va_start(ap, format); - fprintf(stderr, "%s: ", progname); + fprintf(stderr, "fatal error: %s: ", progname); vfprintf(stderr, format, ap); fprintf(stderr, "\n"); va_end(ap); @@ -62,7 +62,7 @@ const char *format, va_list ap; va_start(ap, format); - fprintf(stderr, "%s: ", progname); + fprintf(stderr, "fatal error: %s: ", progname); vfprintf(stderr, format, ap); fprintf(stderr, " (%s)\n", strerror(errno)); va_end(ap); @@ -82,7 +82,7 @@ char *format, va_list ap; va_start(ap, format); - fprintf(stderr, "%s: ", progname); + fprintf(stderr, "fatal error: %s: ", progname); vfprintf(stderr, format, ap); fprintf(stderr, " (%s)\n", mach_error_string(r)); va_end(ap); diff --git a/libstuff/get_arch_from_host.c b/libstuff/get_arch_from_host.c index 38a5329..7454c2c 100644 --- a/libstuff/get_arch_from_host.c +++ b/libstuff/get_arch_from_host.c @@ -439,6 +439,14 @@ struct arch_flag *specific_arch_flag) if(specific_arch_flag != NULL) specific_arch_flag->name = "armv6"; return(1); + case CPU_SUBTYPE_ARM_V6M: + if(family_arch_flag != NULL){ + family_arch_flag->name = "arm"; + family_arch_flag->cpusubtype = CPU_SUBTYPE_ARM_ALL; + } + if(specific_arch_flag != NULL) + specific_arch_flag->name = "armv6m"; + return(1); case CPU_SUBTYPE_ARM_V7: if(family_arch_flag != NULL){ family_arch_flag->name = "arm"; @@ -455,6 +463,14 @@ struct arch_flag *specific_arch_flag) if(specific_arch_flag != NULL) specific_arch_flag->name = "armv7f"; return(1); + case CPU_SUBTYPE_ARM_V7S: + if(family_arch_flag != NULL){ + family_arch_flag->name = "arm"; + family_arch_flag->cpusubtype = CPU_SUBTYPE_ARM_ALL; + } + if(specific_arch_flag != NULL) + specific_arch_flag->name = "armv7s"; + return(1); case CPU_SUBTYPE_ARM_V7K: if(family_arch_flag != NULL){ family_arch_flag->name = "arm"; @@ -463,6 +479,42 @@ struct arch_flag *specific_arch_flag) if(specific_arch_flag != NULL) specific_arch_flag->name = "armv7k"; return(1); + case CPU_SUBTYPE_ARM_V7M: + if(family_arch_flag != NULL){ + family_arch_flag->name = "arm"; + family_arch_flag->cpusubtype = CPU_SUBTYPE_ARM_ALL; + } + if(specific_arch_flag != NULL) + specific_arch_flag->name = "armv7m"; + return(1); + case CPU_SUBTYPE_ARM_V7EM: + if(family_arch_flag != NULL){ + family_arch_flag->name = "arm"; + family_arch_flag->cpusubtype = CPU_SUBTYPE_ARM_ALL; + } + if(specific_arch_flag != NULL) + specific_arch_flag->name = "armv7em"; + return(1); + } + break; + case CPU_TYPE_ARM64: + switch(host_basic_info.cpu_subtype){ + case CPU_SUBTYPE_ARM64_ALL: + if(family_arch_flag != NULL){ + family_arch_flag->name = "arm64"; + family_arch_flag->cpusubtype = CPU_SUBTYPE_ARM64_ALL; + } + if(specific_arch_flag != NULL) + specific_arch_flag->name = "arm64"; + return(1); + case CPU_SUBTYPE_ARM64_V8: + if(family_arch_flag != NULL){ + family_arch_flag->name = "arm64"; + family_arch_flag->cpusubtype = CPU_SUBTYPE_ARM64_ALL; + } + if(specific_arch_flag != NULL) + specific_arch_flag->name = "arm64v8"; + return(1); } break; } diff --git a/libstuff/lto.c b/libstuff/lto.c index b96a804..d5d9a4e 100644 --- a/libstuff/lto.c +++ b/libstuff/lto.c @@ -77,7 +77,7 @@ struct arch_flag *arch_flag, void **pmod) /* maybe NULL */ { - size_t bufsize; + uint32_t bufsize; char *p, *prefix, *lto_path, buf[MAXPATHLEN], resolved_name[PATH_MAX]; int i; void *mod; @@ -92,18 +92,11 @@ void **pmod) /* maybe NULL */ if(tried_to_load_lto == 0){ tried_to_load_lto = 1; /* - * The design is rather lame and inelegant: "llvm support is only - * for stuff in /Developer and not the tools installed in /". - * Which would mean tools like libtool(1) run from /usr/bin would - * not work with lto, and work differently if the same binary was - * installed in /Developer/usr/bin . And if the tools were - * installed in some other location besides /Developer, like - * /Developer/Platforms/... that would also not work. - * - * So instead construct the prefix to this executable assuming it - * is in a bin directory relative to a lib directory of the matching - * lto library and first try to load that. If not then fall back to - * trying "/Developer/usr/lib/libLTO.dylib". + * Construct the prefix to this executable assuming it is in a bin + * directory relative to a lib directory of the matching lto library + * and first try to load that. If not then fall back to trying + * "/Applications/Xcode.app/Contents/Developer/Toolchains/ + * XcodeDefault.xctoolchain/usr/lib/libLTO.dylib". */ bufsize = MAXPATHLEN; p = buf; @@ -122,7 +115,9 @@ void **pmod) /* maybe NULL */ if(lto_handle == NULL){ free(lto_path); lto_path = NULL; - lto_handle = dlopen("/Developer/usr/lib/libLTO.dylib", + lto_handle = dlopen("/Applications/Xcode.app/Contents/" + "Developer/Toolchains/XcodeDefault." + "xctoolchain/usr/lib/libLTO.dylib", RTLD_NOW); } if(lto_handle == NULL) @@ -212,6 +207,10 @@ char *target_triple) arch_flag->cputype = CPU_TYPE_X86_64; arch_flag->cpusubtype = CPU_SUBTYPE_X86_64_ALL; } + else if(strncmp(target_triple, "x86_64h", n) == 0){ + arch_flag->cputype = CPU_TYPE_X86_64; + arch_flag->cpusubtype = CPU_SUBTYPE_X86_64_H; + } else if(strncmp(target_triple, "powerpc", n) == 0){ arch_flag->cputype = CPU_TYPE_POWERPC; arch_flag->cpusubtype = CPU_SUBTYPE_POWERPC_ALL; @@ -236,6 +235,11 @@ char *target_triple) arch_flag->cputype = CPU_TYPE_ARM; arch_flag->cpusubtype = CPU_SUBTYPE_ARM_V6; } + else if(strncmp(target_triple, "armv6m", n) == 0 || + strncmp(target_triple, "thumbv6m", n) == 0){ + arch_flag->cputype = CPU_TYPE_ARM; + arch_flag->cpusubtype = CPU_SUBTYPE_ARM_V6M; + } else if(strncmp(target_triple, "armv7", n) == 0 || strncmp(target_triple, "thumbv7", n) == 0){ arch_flag->cputype = CPU_TYPE_ARM; @@ -246,11 +250,30 @@ char *target_triple) arch_flag->cputype = CPU_TYPE_ARM; arch_flag->cpusubtype = CPU_SUBTYPE_ARM_V7F; } + else if(strncmp(target_triple, "armv7s", n) == 0 || + strncmp(target_triple, "thumbv7s", n) == 0){ + arch_flag->cputype = CPU_TYPE_ARM; + arch_flag->cpusubtype = CPU_SUBTYPE_ARM_V7S; + } else if(strncmp(target_triple, "armv7k", n) == 0 || strncmp(target_triple, "thumbv7k", n) == 0){ arch_flag->cputype = CPU_TYPE_ARM; arch_flag->cpusubtype = CPU_SUBTYPE_ARM_V7K; } + else if(strncmp(target_triple, "armv7m", n) == 0 || + strncmp(target_triple, "thumbv7m", n) == 0){ + arch_flag->cputype = CPU_TYPE_ARM; + arch_flag->cpusubtype = CPU_SUBTYPE_ARM_V7M; + } + else if(strncmp(target_triple, "armv7em", n) == 0 || + strncmp(target_triple, "thumbv7em", n) == 0){ + arch_flag->cputype = CPU_TYPE_ARM; + arch_flag->cpusubtype = CPU_SUBTYPE_ARM_V7EM; + } + else if(strncmp(target_triple, "arm64", n) == 0){ + arch_flag->cputype = CPU_TYPE_ARM64; + arch_flag->cpusubtype = CPU_SUBTYPE_ARM64_ALL; + } else{ return(0); } diff --git a/libstuff/ofile.c b/libstuff/ofile.c index 6b34051..6e5b7a8 100644 --- a/libstuff/ofile.c +++ b/libstuff/ofile.c @@ -60,10 +60,6 @@ #import #import #import -#undef MACHINE_THREAD_STATE /* need to undef these to avoid warnings */ -#undef MACHINE_THREAD_STATE_COUNT -#undef THREAD_STATE_NONE -#undef VALID_THREAD_STATE_FLAVOR #import #include #include @@ -84,6 +80,7 @@ #ifdef OTOOL #undef ALIGNMENT_CHECKS #include "otool.h" +#include "dyld_bind_info.h" #include "ofile_print.h" static enum bool otool_first_ofile_map = TRUE; #else /* !define(OTOOL) */ @@ -209,7 +206,7 @@ void *cookie) uint32_t len, i; struct ofile ofile; enum bool flag, hostflag, arch_found, family; - struct arch_flag host_arch_flag; + struct arch_flag host_arch_flag, specific_arch_flag; const struct arch_flag *family_arch_flag; /* @@ -400,7 +397,7 @@ void *cookie) * specified. */ if(all_archs == FALSE){ - (void)get_arch_from_host(&host_arch_flag, NULL); + (void)get_arch_from_host(&host_arch_flag, &specific_arch_flag); #if __LP64__ /* * If runing as a 64-bit binary and on an Intel x86 host @@ -415,10 +412,12 @@ void *cookie) family = FALSE; family_arch_flag = get_arch_family_from_cputype(host_arch_flag.cputype); +#ifndef __arm__ if(family_arch_flag != NULL) family = (enum bool) ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) == (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK)); +#endif /* __arm__ */ ofile_unmap(&ofile); if(ofile_map(name, NULL, NULL, &ofile, FALSE) == FALSE) @@ -431,7 +430,11 @@ void *cookie) if(ofile.arch_flag.cputype == host_arch_flag.cputype && ((ofile.arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) == +#ifdef __arm__ + (specific_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) || +#else (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) || +#endif /* __arm__ */ family == TRUE)){ hostflag = TRUE; if(ofile.arch_type == OFILE_ARCHIVE){ @@ -836,7 +839,8 @@ enum bool archives_with_fat_objects) { int fd; struct stat stat_buf; - uint32_t size, magic; + uint64_t size; + uint32_t magic; char *addr; magic = 0; /* to shut up the compiler warning message */ @@ -894,7 +898,7 @@ enum bool #endif ofile_map_from_memory( char *addr, -uint32_t size, +uint64_t size, const char *file_name, uint64_t mtime, const struct arch_flag *arch_flag, /* can be NULL */ @@ -1619,7 +1623,15 @@ uint32_t narch) * program. */ else{ - ofile->arch_type = OFILE_UNKNOWN; +#ifdef LTO_SUPPORT + if(is_llvm_bitcode(ofile, addr, size) == TRUE){ + ofile->arch_type = OFILE_LLVM_BITCODE; + ofile->object_addr = addr; + ofile->object_size = size; + } + else +#endif /* LTO_SUPPORT */ + ofile->arch_type = OFILE_UNKNOWN; } return(TRUE); cleanup: @@ -1659,7 +1671,7 @@ ofile_first_member( struct ofile *ofile) { char *addr; - uint32_t size, offset; + uint64_t size, offset; uint32_t magic; enum byte_sex host_byte_sex; struct ar_hdr *ar_hdr; @@ -1923,7 +1935,7 @@ ofile_next_member( struct ofile *ofile) { char *addr; - uint32_t size, offset; + uint64_t size, offset; uint32_t magic; enum byte_sex host_byte_sex; struct ar_hdr *ar_hdr; @@ -2151,7 +2163,7 @@ struct ofile *ofile) { int32_t i; char *addr; - uint32_t size, offset; + uint64_t size, offset; uint32_t magic; enum byte_sex host_byte_sex; char *ar_name; @@ -2909,11 +2921,23 @@ struct ofile *ofile) #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */ } else{ - archive_member_error(ofile, "fat file for cputype (%d) " - "cpusubtype (%d) is not an object file (bad magic " - "number)", ofile->fat_archs[i].cputype, - ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK); - return(CHECK_BAD); +#ifdef LTO_SUPPORT + if(is_llvm_bitcode(ofile, ofile->file_addr + + ofile->member_offset + ofile->fat_archs[i].offset, + ofile->fat_archs[i].size) == TRUE){ + ofile->member_type = OFILE_LLVM_BITCODE; + ofile->object_addr = ofile->member_addr; + ofile->object_size = ofile->member_size; + } + else +#endif /* LTO_SUPPORT */ + { + archive_member_error(ofile, "fat file for cputype (%d) " + "cpusubtype (%d) is not an object file (bad magic " + "number)", ofile->fat_archs[i].cputype, + ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK); + return(CHECK_BAD); + } } } for(i = 0; i < ofile->fat_header->nfat_arch; i++){ @@ -2946,7 +2970,7 @@ enum bool archives_with_fat_objects) return(CHECK_GOOD); #else /* !defined OTOOL */ char *addr; - uint32_t size, offset; + uint64_t size, offset; uint64_t big_size; uint32_t magic; enum byte_sex host_byte_sex; @@ -3348,9 +3372,12 @@ struct ofile *ofile) struct twolevel_hints_command *hints; struct linkedit_data_command *code_sig, *split_info, *func_starts, *data_in_code, *code_sign_drs, *linkedit_data; + struct linkedit_data_command *link_opt_hint; struct version_min_command *vers; struct prebind_cksum_command *cs; struct encryption_info_command *encrypt_info; + struct encryption_info_command_64 *encrypt_info64; + struct linker_option_command *lo; struct dyld_info_command *dyld_info; struct uuid_command *uuid; struct rpath_command *rpath; @@ -3447,6 +3474,7 @@ struct ofile *ofile) func_starts = NULL; data_in_code = NULL; code_sign_drs = NULL; + link_opt_hint = NULL; split_info = NULL; cs = NULL; uuid = NULL; @@ -3547,7 +3575,8 @@ struct ofile *ofile) if(mh->filetype != MH_DYLIB_STUB && s->flags != S_ZEROFILL && s->flags != S_THREAD_LOCAL_ZEROFILL && - sg->fileoff == 0 && s->offset < sizeofhdrs){ + sg->fileoff == 0 && s->offset < sizeofhdrs && + s->size != 0){ Mach_O_error(ofile, "malformed object (offset field of " "section %u in LC_SEGMENT command %u not " "past the headers of the file)", j, i); @@ -3592,6 +3621,7 @@ struct ofile *ofile) goto return_bad; } if(mh->filetype != MH_DYLIB_STUB && + mh->filetype != MH_DSYM && s->flags != S_ZEROFILL && s->flags != S_THREAD_LOCAL_ZEROFILL && check_overlaping_element(ofile, &elements, s->offset, @@ -3684,6 +3714,7 @@ struct ofile *ofile) goto return_bad; } if(mh64->filetype != MH_DYLIB_STUB && + mh64->filetype != MH_DSYM && s64->flags != S_ZEROFILL && s64->flags != S_THREAD_LOCAL_ZEROFILL && check_overlaping_element(ofile, &elements, s64->offset, @@ -4051,6 +4082,17 @@ struct ofile *ofile) code_sign_drs = (struct linkedit_data_command *)lc; goto check_linkedit_data_command; + case LC_LINKER_OPTIMIZATION_HINT: + cmd_name = "LC_LINKER_OPTIMIZATION_HINT"; + element_name = "linker optimization hint"; + if(link_opt_hint != NULL){ + Mach_O_error(ofile, "malformed object (more than one " + "%s command)", cmd_name); + goto return_bad; + } + link_opt_hint = (struct linkedit_data_command *)lc; + goto check_linkedit_data_command; + check_linkedit_data_command: if(l.cmdsize < sizeof(struct linkedit_data_command)){ Mach_O_error(ofile, "malformed object (%s cmdsize too " @@ -4163,6 +4205,55 @@ struct ofile *ofile) } break; + case LC_ENCRYPTION_INFO_64: + if(l.cmdsize < sizeof(struct encryption_info_command_64)){ + Mach_O_error(ofile, "malformed object (LC_ENCRYPTION_INFO" + "_64 cmdsize too small) in command %u", i); + goto return_bad; + } + encrypt_info64 = (struct encryption_info_command_64 *)lc; + if(swapped) + swap_encryption_command_64(encrypt_info64, host_byte_sex); + if(encrypt_info64->cmdsize != + sizeof(struct encryption_info_command_64)){ + Mach_O_error(ofile, "malformed object (LC_ENCRYPTION_INFO" + "_64 command %u has incorrect cmdsize)", i); + goto return_bad; + } + if(encrypt_info64->cryptoff > size){ + Mach_O_error(ofile, "truncated or malformed object (cryptoff " + "field of LC_ENCRYPTION_INFO_64 command %u extends" + " past the end of the file)", i); + goto return_bad; + } + big_size = encrypt_info64->cryptoff; + big_size += encrypt_info64->cryptsize; + if(big_size > size){ + Mach_O_error(ofile, "truncated or malformed object " + "(cryptoff field plus cryptsize field of " + "LC_ENCRYPTION_INFO_64 command %u extends past" + " the end of the file)", i); + goto return_bad; + } + break; + + case LC_LINKER_OPTION: + if(l.cmdsize < sizeof(struct linker_option_command)){ + Mach_O_error(ofile, "malformed object (LC_LINKER_OPTION " + "cmdsize too small) in command %u", i); + goto return_bad; + } + lo = (struct linker_option_command *)lc; + if(swapped) + swap_linker_option_command(lo, host_byte_sex); + if(lo->cmdsize < + sizeof(struct linker_option_command)){ + Mach_O_error(ofile, "malformed object (LC_LINKER_OPTION " + " command %u cmdsize too small)", i); + goto return_bad; + } + break; + case LC_DYLD_INFO: case LC_DYLD_INFO_ONLY: if(l.cmdsize < sizeof(struct dyld_info_command)){ @@ -5711,6 +5802,81 @@ struct ofile *ofile) } break; } + if(cputype == CPU_TYPE_ARM64){ + arm_thread_state64_t *cpu; + + nflavor = 0; + p = (char *)ut + ut->cmdsize; + while(state < p){ + if(state + sizeof(uint32_t) > + (char *)ut + ut->cmdsize){ + Mach_O_error(ofile, "malformed object (flavor in " + "%s command %u extends past end of command)", + ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : + "LC_THREAD", i); + goto return_bad; + } + flavor = *((uint32_t *)state); + if(swapped){ + flavor = SWAP_INT(flavor); + *((uint32_t *)state) = flavor; + } + state += sizeof(uint32_t); + if(state + sizeof(uint32_t) > + (char *)ut + ut->cmdsize){ + Mach_O_error(ofile, "malformed object (count in " + "%s command %u extends past end of command)", + ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : + "LC_THREAD", i); + goto return_bad; + } + count = *((uint32_t *)state); + if(swapped){ + count = SWAP_INT(count); + *((uint32_t *)state) = count; + } + state += sizeof(uint32_t); + switch(flavor){ + case ARM_THREAD_STATE64: + if(count != ARM_THREAD_STATE64_COUNT){ + Mach_O_error(ofile, "malformed object (count " + "not ARM_THREAD_STATE64_COUNT for " + "flavor number %u which is a ARM_THREAD_" + "STATE64 flavor in %s command %u)", + nflavor, ut->cmd == LC_UNIXTHREAD ? + "LC_UNIXTHREAD" : "LC_THREAD", i); + goto return_bad; + } + cpu = (arm_thread_state64_t *)state; + if(state + sizeof(arm_thread_state64_t) > + (char *)ut + ut->cmdsize){ + Mach_O_error(ofile, "malformed object (" + "ARM_THREAD_STATE64 in %s command %u " + "extends past end of command)", ut->cmd == + LC_UNIXTHREAD ? "LC_UNIXTHREAD" : + "LC_THREAD", i); + goto return_bad; + } + if(swapped) + swap_arm_thread_state64_t(cpu, host_byte_sex); + state += sizeof(arm_thread_state64_t); + break; + default: + if(swapped){ + Mach_O_error(ofile, "malformed object (unknown " + "flavor for flavor number %u in %s command" + " %u can't byte swap it)", nflavor, + ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : + "LC_THREAD", i); + goto return_bad; + } + state += count * sizeof(uint32_t); + break; + } + nflavor++; + } + break; + } if(swapped){ Mach_O_error(ofile, "malformed object (unknown cputype and " "cpusubtype of object and can't byte swap and check %s " diff --git a/libstuff/reloc.c b/libstuff/reloc.c index 3475760..9d9c76c 100644 --- a/libstuff/reloc.c +++ b/libstuff/reloc.c @@ -73,6 +73,12 @@ cpu_type_t cputype) case CPU_TYPE_ARM: return(ARM_RELOC_PAIR); break; + case CPU_TYPE_ARM64: + /* + * We should never hit this case for arm64, so drop down to the + * fatal error below. + */ + break; } fatal("internal error: reloc_pair_r_type() called with unknown " "cputype (%u)", cputype); @@ -153,6 +159,8 @@ uint32_t r_type) r_type == ARM_RELOC_HALF_SECTDIFF) return(TRUE); break; + case CPU_TYPE_ARM64: + return(FALSE); default: fatal("internal error: reloc_has_pair() called with unknown " "cputype (%u)", cputype); @@ -217,6 +225,10 @@ uint32_t r_type) r_type == ARM_RELOC_HALF_SECTDIFF) return(TRUE); break; + case CPU_TYPE_ARM64: + /* No sectdiff relocs for arm64. */ + return(FALSE); + break; default: fatal("internal error: reloc_is_sectdiff() called with unknown " "cputype (%u)", cputype); diff --git a/libstuff/swap_headers.c b/libstuff/swap_headers.c index bed9c3a..76959d5 100644 --- a/libstuff/swap_headers.c +++ b/libstuff/swap_headers.c @@ -40,10 +40,6 @@ #include #include #include -#undef MACHINE_THREAD_STATE /* need to undef these to avoid warnings */ -#undef MACHINE_THREAD_STATE_COUNT -#undef THREAD_STATE_NONE -#undef VALID_THREAD_STATE_FLAVOR #include #include "stuff/bool.h" #include "stuff/bytesex.h" @@ -96,6 +92,8 @@ struct load_command *load_commands) struct linkedit_data_command *ld; struct rpath_command *rpath; struct encryption_info_command *ec; + struct encryption_info_command_64 *ec64; + struct linker_option_command *lo; struct dyld_info_command *dc; struct version_min_command *vc; uint32_t flavor, count; @@ -961,6 +959,43 @@ struct load_command *load_commands) } break; } + if(cputype == CPU_TYPE_ARM64){ + arm_thread_state64_t *cpu; + + nflavor = 0; + p = (char *)ut + ut->cmdsize; + while(state < p){ + flavor = *((uint32_t *)state); + state += sizeof(uint32_t); + count = *((uint32_t *)state); + state += sizeof(uint32_t); + switch(flavor){ + case ARM_THREAD_STATE: + if(count != ARM_THREAD_STATE_COUNT){ + error("in swap_object_headers(): malformed " + "load commands (count " + "not ARM_THREAD_STATE_COUNT for " + "flavor number %lu which is a ARM_THREAD_" + "STATE flavor in %s command %lu)", + nflavor, ut->cmd == LC_UNIXTHREAD ? + "LC_UNIXTHREAD" : "LC_THREAD", i); + return(FALSE); + } + cpu = (arm_thread_state64_t *)state; + state += sizeof(arm_thread_state64_t); + break; + default: + error("in swap_object_headers(): malformed load " + "commands (unknown flavor for flavor number " + "%lu in %s command %lu can't byte swap it)", + nflavor, ut->cmd == LC_UNIXTHREAD ? + "LC_UNIXTHREAD" : "LC_THREAD", i); + return(FALSE); + } + nflavor++; + } + break; + } error("in swap_object_headers(): malformed load commands " "(unknown cputype (%d) and cpusubtype (%d) of object and " "can't byte swap %s command %lu)", cputype, @@ -1101,6 +1136,16 @@ struct load_command *load_commands) } break; + case LC_LINKER_OPTIMIZATION_HINT: + ld = (struct linkedit_data_command *)lc; + if(ld->cmdsize != sizeof(struct linkedit_data_command)){ + error("in swap_object_headers(): malformed load commands " + "(LC_LINKER_OPTIMIZATION_HINT command %lu has " + "incorrect cmdsize", i); + return(FALSE); + } + break; + case LC_VERSION_MIN_MACOSX: vc = (struct version_min_command *)lc; if(vc->cmdsize != sizeof(struct version_min_command)){ @@ -1148,6 +1193,25 @@ struct load_command *load_commands) } break; + case LC_ENCRYPTION_INFO_64: + ec64 = (struct encryption_info_command_64 *)lc; + if(ec64->cmdsize != sizeof(struct encryption_info_command_64)){ + error("in swap_object_headers(): malformed load commands " + "(LC_ENCRYPTION_INFO_64 command %lu has incorrect " + "cmdsize", i); + return(FALSE); + } + break; + + case LC_LINKER_OPTION: + lo = (struct linker_option_command *)lc; + if(lo->cmdsize < sizeof(struct linker_option_command)){ + error("in swap_object_headers(): malformed load commands " + "(LC_LINKER_OPTION command %lu is too small", i); + return(FALSE); + } + break; + case LC_DYLD_INFO: case LC_DYLD_INFO_ONLY: dc = (struct dyld_info_command *)lc; @@ -1579,6 +1643,26 @@ struct load_command *load_commands) } break; } + if(cputype == CPU_TYPE_ARM64){ + arm_thread_state64_t *cpu; + + while(state < p){ + flavor = *((uint32_t *)state); + *((uint32_t *)state) = SWAP_INT(flavor); + state += sizeof(uint32_t); + count = *((uint32_t *)state); + *((uint32_t *)state) = SWAP_INT(count); + state += sizeof(uint32_t); + switch(flavor){ + case ARM_THREAD_STATE64: + cpu = (arm_thread_state64_t *)state; + swap_arm_thread_state64_t(cpu, target_byte_sex); + state += sizeof(arm_thread_state64_t); + break; + } + } + break; + } break; case LC_MAIN: @@ -1626,6 +1710,7 @@ struct load_command *load_commands) case LC_FUNCTION_STARTS: case LC_DATA_IN_CODE: case LC_DYLIB_CODE_SIGN_DRS: + case LC_LINKER_OPTIMIZATION_HINT: ld = (struct linkedit_data_command *)lc; swap_linkedit_data_command(ld, target_byte_sex); break; @@ -1640,6 +1725,16 @@ struct load_command *load_commands) swap_encryption_command(ec, target_byte_sex); break; + case LC_ENCRYPTION_INFO_64: + ec64 = (struct encryption_info_command_64 *)lc; + swap_encryption_command_64(ec64, target_byte_sex); + break; + + case LC_LINKER_OPTION: + lo = (struct linker_option_command *)lc; + swap_linker_option_command(lo, target_byte_sex); + break; + case LC_DYLD_INFO: case LC_DYLD_INFO_ONLY: dc = (struct dyld_info_command *)lc; diff --git a/libstuff/writeout.c b/libstuff/writeout.c index 82cf317..4e543c8 100644 --- a/libstuff/writeout.c +++ b/libstuff/writeout.c @@ -33,6 +33,9 @@ #include "stuff/allocate.h" #include "stuff/rnd.h" #include "stuff/errors.h" +#ifdef LTO_SUPPORT +#include "stuff/lto.h" +#endif /* LTO_SUPPORT */ static void copy_new_symbol_info( char *p, @@ -773,6 +776,12 @@ struct object *object) object->output_code_sign_drs_info_data_size); *size += object->output_code_sign_drs_info_data_size; } + if(object->output_link_opt_hint_info_data_size != 0){ + if(object->output_link_opt_hint_info_data != NULL) + memcpy(p + *size, object->output_link_opt_hint_info_data, + object->output_link_opt_hint_info_data_size); + *size += object->output_link_opt_hint_info_data_size; + } if(object->mh != NULL){ memcpy(p + *size, object->output_symbols, object->output_nsymbols * sizeof(struct nlist)); @@ -843,6 +852,12 @@ struct object *object) object->output_data_in_code_info_data_size); *size += object->output_data_in_code_info_data_size; } + if(object->output_link_opt_hint_info_data_size != 0){ + if(object->output_link_opt_hint_info_data != NULL) + memcpy(p + *size, object->output_link_opt_hint_info_data, + object->output_link_opt_hint_info_data_size); + *size += object->output_link_opt_hint_info_data_size; + } if(object->mh != NULL){ memcpy(p + *size, object->output_symbols, object->output_nsymbols * sizeof(struct nlist)); @@ -1020,6 +1035,18 @@ enum bool library_warnings) } } } +#ifdef LTO_SUPPORT + else if(member->type == OFILE_LLVM_BITCODE){ + nsymbols = lto_get_nsyms(member->lto); + for(j = 0; j < nsymbols; j++){ + if(lto_toc_symbol(member->lto, j, commons_in_toc) == TRUE){ + arch->ntocs++; + arch->toc_strsize += + strlen(lto_symbol_name(member->lto, j)) + 1; + } + } + } +#endif /* LTO_SUPPORT */ } /* @@ -1117,6 +1144,22 @@ enum bool library_warnings) } } } +#ifdef LTO_SUPPORT + else if(member->type == OFILE_LLVM_BITCODE){ + nsymbols = lto_get_nsyms(member->lto); + for(j = 0; j < nsymbols; j++){ + if(lto_toc_symbol(member->lto, j, commons_in_toc) == TRUE){ + strcpy(arch->toc_strings + s, + lto_symbol_name(member->lto, j)); + arch->toc_entries[r].symbol_name = + arch->toc_strings + s; + arch->toc_entries[r].member_index = i + 1; + r++; + s += strlen(lto_symbol_name(member->lto, j)) + 1; + } + } + } +#endif /* LTO_SUPPORT */ } /* diff --git a/preinc.h b/preinc.h index 565a113..2b7d9ee 100644 --- a/preinc.h +++ b/preinc.h @@ -34,7 +34,6 @@ struct __darwin_i386_float_state; #define __uint32_t uint32_t #define __lr lr #define __pc pc -#include "mach/arm/_structs.h" #undef __pc #undef __lr #undef __uint32_t diff --git a/strip.c b/strip.c index c32f5c8..e6c236b 100644 --- a/strip.c +++ b/strip.c @@ -1365,6 +1365,17 @@ struct object *object) 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->input_sym_info_size += + object->link_opt_hint_cmd->datasize; + object->output_sym_info_size += + object->link_opt_hint_cmd->datasize; + } + if(object->mh != NULL){ object->input_sym_info_size += nsyms * sizeof(struct nlist); object->output_symbols = new_symbols; @@ -1612,6 +1623,11 @@ struct object *object) offset += object->code_sign_drs_cmd->datasize; } + if(object->link_opt_hint_cmd != NULL){ + object->link_opt_hint_cmd->dataoff = offset; + offset += object->link_opt_hint_cmd->datasize; + } + if(object->st->nsyms != 0){ object->st->symoff = offset; if(object->mh != NULL) @@ -1865,6 +1881,8 @@ struct object *object) object->input_indirectsym_pad; } } + if(no_uuid == TRUE) + strip_LC_UUID_commands(arch, member, object); } #endif /* !defined(NMEDIT) */ @@ -2141,6 +2159,18 @@ struct object *object) object->dyst->nlocrel != 0 && object->dyst->locreloff < offset) offset = object->dyst->locreloff; + if(object->func_starts_info_cmd != NULL && + object->func_starts_info_cmd->datasize != 0 && + object->func_starts_info_cmd->dataoff < offset) + offset = object->func_starts_info_cmd->dataoff; + if(object->data_in_code_cmd != NULL && + object->data_in_code_cmd->datasize != 0 && + object->data_in_code_cmd->dataoff < offset) + offset = object->data_in_code_cmd->dataoff; + if(object->link_opt_hint_cmd != NULL && + object->link_opt_hint_cmd->datasize != 0 && + object->link_opt_hint_cmd->dataoff < offset) + offset = object->link_opt_hint_cmd->dataoff; if(object->st->nsyms != 0 && object->st->symoff < offset) offset = object->st->symoff; @@ -2564,10 +2594,7 @@ uint32_t nextrefsyms) } new_nsyms = 0; - if(object->mh != NULL) - new_strsize = sizeof(int32_t); - else - new_strsize = sizeof(int64_t); + new_strsize = sizeof(int32_t); new_nlocalsym = 0; new_nextdefsym = 0; new_nundefsym = 0; @@ -2575,7 +2602,10 @@ uint32_t nextrefsyms) /* * If this an object file that has DWARF debugging sections to strip - * then we have to run ld -r on it. + * then we have to run ld -r on it. We also have to do this for + * ARM objects because thumb symbols can't be stripped as they are + * needed for proper linking in .o files. And we need to for i386 + * objects to not mess up compact unwind info. */ if(object->mh_filetype == MH_OBJECT && (Sflag || xflag)){ has_dwarf = FALSE; @@ -2611,7 +2641,14 @@ uint32_t nextrefsyms) } lc = (struct load_command *)((char *)lc + lc->cmdsize); } - if(has_dwarf == TRUE) + /* + * If the file has dwarf symbols or is an ARM or i386 object then + * have ld(1) do the "stripping" and make an ld -r version of the + * object. + */ + if(has_dwarf == TRUE || + object->mh_cputype == CPU_TYPE_ARM || + object->mh_cputype == CPU_TYPE_I386) make_ld_r_object(arch, member, object); } /* @@ -2741,12 +2778,14 @@ uint32_t nextrefsyms) } if((n_type & N_EXT) == 0){ /* local symbol */ /* - * For x86_64 .o files we have run ld -r on them and are stuck - * keeping all resulting symbols. + * For x86_64, i386 .o or ARM files we have run ld -r on them + * we keeping all resulting symbols. */ - if(object->mh == NULL && ( - object->mh64->cputype == CPU_TYPE_X86_64) && - object->mh64->filetype == MH_OBJECT){ + if((object->mh_cputype == CPU_TYPE_X86_64 || + object->mh_cputype == CPU_TYPE_I386 || + object->mh_cputype == CPU_TYPE_ARM64 || + object->mh_cputype == CPU_TYPE_ARM) && + object->mh_filetype == MH_OBJECT){ if(n_strx != 0) new_strsize += strlen(strings + n_strx) + 1; new_nlocalsym++; @@ -3087,13 +3126,16 @@ uint32_t nextrefsyms) saves[i] = new_nsyms; } /* - * For x86_64 .o files we have run ld -r on them and are stuck - * keeping all resulting symbols. + * For x86_64 and i386 .o files we have run ld -r on them and + * are stuck keeping all resulting symbols. */ if(saves[i] == 0 && - object->mh == NULL && - object->mh64->cputype == CPU_TYPE_X86_64 && - object->mh64->filetype == MH_OBJECT){ + ((object->mh == NULL && + object->mh64->cputype == CPU_TYPE_X86_64 && + object->mh64->filetype == MH_OBJECT) || + (object->mh64 == NULL && + object->mh->cputype == CPU_TYPE_I386 && + object->mh->filetype == MH_OBJECT))){ len = strlen(strings + n_strx) + 1; new_strsize += len; new_ext_strsize += len; @@ -4120,6 +4162,10 @@ struct object *object) object->code_sign_drs_cmd = (struct linkedit_data_command *)lc1; break; + case LC_LINKER_OPTIMIZATION_HINT: + object->link_opt_hint_cmd = + (struct linkedit_data_command *)lc1; + break; case LC_CODE_SIGNATURE: object->code_sig_cmd = (struct linkedit_data_command *)lc1; break; @@ -4241,6 +4287,10 @@ struct object *object) object->code_sign_drs_cmd = (struct linkedit_data_command *)lc1; break; + case LC_LINKER_OPTIMIZATION_HINT: + object->link_opt_hint_cmd = + (struct linkedit_data_command *)lc1; + break; } lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize); } diff --git a/tease.c b/tease.c index 181fec4..39104dc 100644 --- a/tease.c +++ b/tease.c @@ -1272,8 +1272,8 @@ struct object *object) #endif /* !defined(NMEDIT) */ #ifndef NMEDIT - if(sfile != NULL || Rfile != NULL || dfile != NULL || Aflag || aflag || - uflag || Sflag || xflag || Xflag || tflag || nflag || rflag || + if(sfile != NULL || Rfile != NULL || dfile != NULL || Aflag || uflag || + Sflag || xflag || Xflag || nflag || rflag || aflag || tflag || default_dyld_executable || object->mh_filetype == MH_DYLIB || object->mh_filetype == MH_DYLINKER) #endif /* !defined(NMEDIT) */ @@ -1289,10 +1289,10 @@ struct object *object) return; if(no_uuid == TRUE) strip_LC_UUID_commands(arch, member, object); - if(no_dylib || no_dylib_unused) - strip_LC_DYLIB_commands(arch, member, object); #endif /* !defined(NMEDIT) */ /* + if(no_dylib || no_dylib_unused) + strip_LC_DYLIB_commands(arch, member, object); * The parts that make up output_sym_info_size must be added up in * the output order so that when the sizes of things are rounded up * before parts that must be aligned the final output_sym_info_size @@ -1415,6 +1415,17 @@ struct object *object) 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->input_sym_info_size += + object->link_opt_hint_cmd->datasize; + object->output_sym_info_size += + object->link_opt_hint_cmd->datasize; + } + if(object->mh != NULL){ object->input_sym_info_size += nsyms * sizeof(struct nlist); object->output_symbols = new_symbols; @@ -1662,6 +1673,11 @@ struct object *object) offset += object->code_sign_drs_cmd->datasize; } + if(object->link_opt_hint_cmd != NULL){ + object->link_opt_hint_cmd->dataoff = offset; + offset += object->link_opt_hint_cmd->datasize; + } + if(object->st->nsyms != 0){ object->st->symoff = offset; if(object->mh != NULL) @@ -1915,6 +1931,8 @@ struct object *object) object->input_indirectsym_pad; } } + if(no_uuid == TRUE) + strip_LC_UUID_commands(arch, member, object); } #endif /* !defined(NMEDIT) */ @@ -2191,6 +2209,18 @@ struct object *object) object->dyst->nlocrel != 0 && object->dyst->locreloff < offset) offset = object->dyst->locreloff; + if(object->func_starts_info_cmd != NULL && + object->func_starts_info_cmd->datasize != 0 && + object->func_starts_info_cmd->dataoff < offset) + offset = object->func_starts_info_cmd->dataoff; + if(object->data_in_code_cmd != NULL && + object->data_in_code_cmd->datasize != 0 && + object->data_in_code_cmd->dataoff < offset) + offset = object->data_in_code_cmd->dataoff; + if(object->link_opt_hint_cmd != NULL && + object->link_opt_hint_cmd->datasize != 0 && + object->link_opt_hint_cmd->dataoff < offset) + offset = object->link_opt_hint_cmd->dataoff; if(object->st->nsyms != 0 && object->st->symoff < offset) offset = object->st->symoff; @@ -2615,10 +2645,7 @@ uint32_t nextrefsyms) } new_nsyms = 0; - if(object->mh != NULL) - new_strsize = sizeof(int32_t); - else - new_strsize = sizeof(int64_t); + new_strsize = sizeof(int32_t); new_nlocalsym = 0; new_nextdefsym = 0; new_nundefsym = 0; @@ -2626,7 +2653,10 @@ uint32_t nextrefsyms) /* * If this an object file that has DWARF debugging sections to strip - * then we have to run ld -r on it. + * then we have to run ld -r on it. We also have to do this for + * ARM objects because thumb symbols can't be stripped as they are + * needed for proper linking in .o files. And we need to for i386 + * objects to not mess up compact unwind info. */ if(object->mh_filetype == MH_OBJECT && (Sflag || xflag)){ has_dwarf = FALSE; @@ -2662,7 +2692,14 @@ uint32_t nextrefsyms) } lc = (struct load_command *)((char *)lc + lc->cmdsize); } - if(has_dwarf == TRUE) + /* + * If the file has dwarf symbols or is an ARM or i386 object then + * have ld(1) do the "stripping" and make an ld -r version of the + * object. + */ + if(has_dwarf == TRUE || + object->mh_cputype == CPU_TYPE_ARM || + object->mh_cputype == CPU_TYPE_I386) make_ld_r_object(arch, member, object); } /* @@ -2733,7 +2770,7 @@ uint32_t nextrefsyms) strcmp((s + j)->segname, SEG_TEXT) == 0) text_nsect = nsects + 1; sections[nsects++] = s++; - } + } } else if(lc->cmd == LC_SEGMENT_64){ sg64 = (struct segment_command_64 *)lc; @@ -2744,7 +2781,7 @@ uint32_t nextrefsyms) strcmp((s64 + j)->segname, SEG_TEXT) == 0) text_nsect = nsects + 1; sections64[nsects++] = s64++; - } + } } lc = (struct load_command *)((char *)lc + lc->cmdsize); } @@ -2800,6 +2837,10 @@ uint32_t nextrefsyms) } } if((n_type & N_EXT) == 0){ /* local symbol */ + /* + * For x86_64, i386 .o or ARM files we have run ld -r on them + * we keeping all resulting symbols. + */ if(aflag){ if(n_strx != 0) new_strsize += strlen(strings + n_strx) + 1; @@ -2807,13 +2848,11 @@ uint32_t nextrefsyms) new_nsyms++; saves[i] = new_nsyms; } - /* - * For x86_64 .o files we have run ld -r on them and are stuck - * keeping all resulting symbols. - */ - else if(object->mh == NULL && ( - object->mh64->cputype == CPU_TYPE_X86_64) && - object->mh64->filetype == MH_OBJECT){ + else if((object->mh_cputype == CPU_TYPE_X86_64 || + object->mh_cputype == CPU_TYPE_I386 || + object->mh_cputype == CPU_TYPE_ARM64 || + object->mh_cputype == CPU_TYPE_ARM) && + object->mh_filetype == MH_OBJECT){ if(n_strx != 0) new_strsize += strlen(strings + n_strx) + 1; new_nlocalsym++; @@ -3163,13 +3202,16 @@ uint32_t nextrefsyms) saves[i] = new_nsyms; } /* - * For x86_64 .o files we have run ld -r on them and are stuck - * keeping all resulting symbols. + * For x86_64 and i386 .o files we have run ld -r on them and + * are stuck keeping all resulting symbols. */ if(saves[i] == 0 && - object->mh == NULL && - object->mh64->cputype == CPU_TYPE_X86_64 && - object->mh64->filetype == MH_OBJECT){ + ((object->mh == NULL && + object->mh64->cputype == CPU_TYPE_X86_64 && + object->mh64->filetype == MH_OBJECT) || + (object->mh64 == NULL && + object->mh->cputype == CPU_TYPE_I386 && + object->mh->filetype == MH_OBJECT))){ len = strlen(strings + n_strx) + 1; new_strsize += len; new_ext_strsize += len; @@ -4196,6 +4238,10 @@ struct object *object) object->code_sign_drs_cmd = (struct linkedit_data_command *)lc1; break; + case LC_LINKER_OPTIMIZATION_HINT: + object->link_opt_hint_cmd = + (struct linkedit_data_command *)lc1; + break; case LC_CODE_SIGNATURE: object->code_sig_cmd = (struct linkedit_data_command *)lc1; break; @@ -4528,6 +4574,10 @@ struct object *object) object->code_sign_drs_cmd = (struct linkedit_data_command *)lc1; break; + case LC_LINKER_OPTIMIZATION_HINT: + object->link_opt_hint_cmd = + (struct linkedit_data_command *)lc1; + break; case LC_DYLD_INFO_ONLY: case LC_DYLD_INFO: object->dyld_info = (struct dyld_info_command *)lc1; @@ -4536,35 +4586,34 @@ struct object *object) } if(cflag){ - /* - * To get the right amount of the file copied out by writeout() for - * the case when we are stripping out the section contents we - * already reduce the object size by the size of the section - * contents including the padding after the load commands. So here - * we need to further reduce it by the load command for the - * LC_CODE_SIGNATURE (a struct linkedit_data_command) we are - * removing. - */ - object->object_size -= sizeof(struct linkedit_data_command); - /* - * Then this size minus the size of the input symbolic information - * is what is copied out from the file by writeout(). Which in this - * case is just the new headers. - */ + /* + * To get the right amount of the file copied out by writeout() for the + * case when we are stripping out the section contents we already reduce + * the object size by the size of the section contents including the + * padding after the load commands. So here we need to further reduce + * it by the load command for the LC_CODE_SIGNATURE (a struct + * linkedit_data_command) we are removing. + */ + object->object_size -= sizeof(struct linkedit_data_command); + /* + * Then this size minus the size of the input symbolic information is + * what is copied out from the file by writeout(). Which in this case + * is just the new headers. + */ - /* - * Finally for -c the file offset to the link edit information is to - * be right after the load commands. So reset this for the updated - * size of the load commands without the LC_CODE_SIGNATURE. - */ - if(object->mh != NULL) - object->seg_linkedit->fileoff = sizeof(struct mach_header) + - sizeofcmds; - else - object->seg_linkedit64->fileoff = - sizeof(struct mach_header_64) + sizeofcmds; - } + /* + * Finally for -c the file offset to the link edit information is to be + * right after the load commands. So reset this for the updated size + * of the load commands without the LC_CODE_SIGNATURE. + */ + if(object->mh != NULL) + object->seg_linkedit->fileoff = sizeof(struct mach_header) + + sizeofcmds; + else + object->seg_linkedit64->fileoff = sizeof(struct mach_header_64) + + sizeofcmds; } + } #endif /* !(NMEDIT) */ /* diff --git a/update-cctools.sh b/update-cctools.sh new file mode 100755 index 0000000..b0ae7ff --- /dev/null +++ b/update-cctools.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env VERSION=855 sh -x # <-- Update VERSION to correspond with drop. +URI=http://opensource.apple.com/tarballs/cctools/cctools-$VERSION.tar.gz + +git checkout -b cctools-$VERSION 2>/dev/null || : + +cp strip.c tease.c; git diff -R --histogram -- tease.c > /tmp/tease.patch +git checkout -- tease.c + +curl -L\# $URI | tar x --strip-components 1; git checkout -- Makefile + +for file in strip.c install_name_tool.c nm.c; do cp misc/$file .; done + +git clean -dfq; git add -A . && git commit -am "Import cctools-$VERSION." +cp strip.c tease.c; git apply /tmp/tease.patch && success=yes || success=no +[ $success = yes ] && git add -A . && git commit -am "Apply cctools-$VERSION." + +[ $success = yes ] && exit 0 || git checkout -- tease.c; mv /tmp/tease.patch . +echo "Could not auto-apply patch. See strip.c, tease.c, tease.patch." && exit 1 diff --git a/version.mak b/version.mak deleted file mode 100644 index 2427b2b..0000000 --- a/version.mak +++ /dev/null @@ -1,5 +0,0 @@ -# The cctools version suffix these sources are based on -# The tarball can be found at: -# http://opensource.apple.com/tarballs/cctools/cctools-$(CCTOOLSVER).tar.gz - -CCTOOLSVER = 822