/* * Mach-O file handling for TCC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "tcc.h" /* In order to make life easy for us we are generating Mach-O files which don't make use of some modern features, but which aren't entirely classic either in that they do use some modern features. We're also only generating 64bit Mach-O files, and only native endian at that. In particular we're generating executables that don't make use of DYLD_INFO for dynamic linking info, as that requires us building a trie of exported names. We're simply using classic symbol tables which are still supported by modern dyld. But we do use LC_MAIN, which is a "modern" feature in order to not have to setup our own crt code. We're not using lazy linking, so even function calls are resolved at startup. */ #if !defined TCC_TARGET_X86_64 && !defined TCC_TARGET_ARM64#error Platform not supported#endif /* XXX: this file uses tcc_error() to the effect of exit(1) */#undef _tcc_error #define DEBUG_MACHO 0#define dprintf if (DEBUG_MACHO) printf #define MH_EXECUTE (0x2)#define MH_DYLDLINK (0x4)#define MH_DYLIB (0x6)#define MH_PIE (0x200000) #define CPU_SUBTYPE_LIB64 (0x80000000)#define CPU_SUBTYPE_X86_ALL (3)#define CPU_SUBTYPE_ARM64_ALL (0) #define CPU_ARCH_ABI64 (0x01000000) #define CPU_TYPE_X86 (7)#define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64)#define CPU_TYPE_ARM (12)#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) struct fat_header { uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */ uint32_t nfat_arch; /* number of structs that follow */}; struct fat_arch { int cputype; /* cpu specifier (int) */ int cpusubtype; /* machine specifier (int) */ uint32_t offset; /* file offset to this object file */ uint32_t size; /* size of this object file */ uint32_t align; /* alignment as a power of 2 */}; #define FAT_MAGIC 0xcafebabe#define FAT_CIGAM 0xbebafeca#define FAT_MAGIC_64 0xcafebabf#define FAT_CIGAM_64 0xbfbafeca struct mach_header { uint32_t magic; /* mach magic number identifier */ int cputype; /* cpu specifier */ int cpusubtype; /* machine specifier */ uint32_t filetype; /* type of file */ uint32_t ncmds; /* number of load commands */ uint32_t sizeofcmds; /* the size of all the load commands */ uint32_t flags; /* flags */}; struct mach_header_64 { struct mach_header mh; uint32_t reserved; /* reserved, pad to 64bit */}; /* Constant for the magic field of the mach_header (32-bit architectures) */#define MH_MAGIC 0xfeedface /* the mach magic number */#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */ struct load_command { uint32_t cmd; /* type of load command */ uint32_t cmdsize; /* total size of command in bytes */}; #define LC_REQ_DYLD 0x80000000#define LC_SYMTAB 0x2#define LC_DYSYMTAB 0xb#define LC_LOAD_DYLIB 0xc#define LC_ID_DYLIB 0xd#define LC_LOAD_DYLINKER 0xe#define LC_SEGMENT_64 0x19#define LC_RPATH (0x1c | LC_REQ_DYLD)#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD)#define LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD)#define LC_MAIN (0x28|LC_REQ_DYLD)#define LC_SOURCE_VERSION 0x2A#define LC_BUILD_VERSION 0x32#define LC_DYLD_EXPORTS_TRIE (0x33 | LC_REQ_DYLD)#define LC_DYLD_CHAINED_FIXUPS (0x34 | LC_REQ_DYLD) #define SG_READ_ONLY 0x10 /* This segment is made read-only after fixups */ typedef int vm_prot_t; struct segment_command_64 { /* for 64-bit architectures */ uint32_t cmd; /* LC_SEGMENT_64 */ uint32_t cmdsize; /* includes sizeof section_64 structs */ char segname[16]; /* segment name */ uint64_t vmaddr; /* memory address of this segment */ uint64_t vmsize; /* memory size of this segment */ uint64_t fileoff; /* file offset of this segment */ uint64_t filesize; /* amount to map from the file */ vm_prot_t maxprot; /* maximum VM protection */ vm_prot_t initprot; /* initial VM protection */ uint32_t nsects; /* number of sections in segment */ uint32_t flags; /* flags */}; struct section_64 { /* for 64-bit architectures */ char sectname[16]; /* name of this section */ char segname[16]; /* segment this section goes in */ uint64_t addr; /* memory address of this section */ uint64_t size; /* size in bytes of this section */ uint32_t offset; /* file offset of this section */ uint32_t align; /* section alignment (power of 2) */ uint32_t reloff; /* file offset of relocation entries */ uint32_t nreloc; /* number of relocation entries */ uint32_t flags; /* flags (section type and attributes)*/ uint32_t reserved1; /* reserved (for offset or index) */ uint32_t reserved2; /* reserved (for count or sizeof) */ uint32_t reserved3; /* reserved */}; enum { DYLD_CHAINED_IMPORT = 1,}; struct dyld_chained_fixups_header { uint32_t fixups_version; ///< 0 uint32_t starts_offset; ///< Offset of dyld_chained_starts_in_image. uint32_t imports_offset; ///< Offset of imports table in chain_data. uint32_t symbols_offset; ///< Offset of symbol strings in chain_data. uint32_t imports_count; ///< Number of imported symbol names. uint32_t imports_format; ///< DYLD_CHAINED_IMPORT* uint32_t symbols_format; ///< 0 => uncompressed, 1 => zlib compressed}; struct dyld_chained_starts_in_image{ uint32_t seg_count; uint32_t seg_info_offset[1]; // each entry is offset into this struct for that segment // followed by pool of dyld_chain_starts_in_segment data}; enum { DYLD_CHAINED_PTR_64 = 2, // target is vmaddr DYLD_CHAINED_PTR_64_OFFSET = 6, // target is vm offset}; enum { DYLD_CHAINED_PTR_START_NONE = 0xFFFF, // used in page_start[] to denote a page with no fixups}; #define SEG_PAGE_SIZE 16384 struct dyld_chained_starts_in_segment{ uint32_t size; // size of this (amount kernel needs to copy) uint16_t page_size; // 0x1000 or 0x4000 uint16_t pointer_format; // DYLD_CHAINED_PTR_* uint64_t segment_offset; // offset in memory to start of segment uint32_t max_valid_pointer; // for 32-bit OS, any value beyond this is not a pointer uint16_t page_count; // how many pages are in array uint16_t page_start[1]; // each entry is offset in each page of first element in chain // or DYLD_CHAINED_PTR_START_NONE if no fixups on page}; enum BindSpecialDylib { BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2,}; struct dyld_chained_import{ uint32_t lib_ordinal : 8, weak_import : 1, name_offset : 23;}; struct dyld_chained_ptr_64_rebase{ uint64_t target : 36, // vmaddr, 64GB max image size high8 : 8, // top 8 bits set to this after slide added reserved : 7, // all zeros next : 12, // 4-byte stride bind : 1; // == 0}; struct dyld_chained_ptr_64_bind{ uint64_t ordinal : 24, addend : 8, // 0 thru 255 reserved : 19, // all zeros next : 12, // 4-byte stride bind : 1; // == 1}; #define S_REGULAR 0x0#define S_ZEROFILL 0x1#define S_NON_LAZY_SYMBOL_POINTERS 0x6#define S_LAZY_SYMBOL_POINTERS 0x7#define S_SYMBOL_STUBS 0x8#define S_MOD_INIT_FUNC_POINTERS 0x9#define S_MOD_TERM_FUNC_POINTERS 0xa #define S_ATTR_PURE_INSTRUCTIONS 0x80000000#define S_ATTR_SOME_INSTRUCTIONS 0x00000400#define S_ATTR_DEBUG 0x02000000 typedef uint32_t lc_str; struct dylib_command { uint32_t cmd; /* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB, LC_REEXPORT_DYLIB */ uint32_t cmdsize; /* includes pathname string */ lc_str name; /* library's path name */ uint32_t timestamp; /* library's build time stamp */ uint32_t current_version; /* library's current version number */ uint32_t compatibility_version; /* library's compatibility vers number*/}; struct rpath_command { uint32_t cmd; /* LC_RPATH */ uint32_t cmdsize; /* includes string */ lc_str path; /* path to add to run path */}; struct dylinker_command { uint32_t cmd; /* LC_ID_DYLINKER, LC_LOAD_DYLINKER or LC_DYLD_ENVIRONMENT */ uint32_t cmdsize; /* includes pathname string */ lc_str name; /* dynamic linker's path name */}; struct linkedit_data_command { uint32_t cmd; /* LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS, LC_LINKER_OPTIMIZATION_HINT, LC_DYLD_EXPORTS_TRIE, or LC_DYLD_CHAINED_FIXUPS. */ 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 */}; #define PLATFORM_MACOS 1 struct build_version_command { uint32_t cmd; /* LC_BUILD_VERSION */ uint32_t cmdsize; /* sizeof(struct build_version_command) plus */ /* ntools * sizeof(struct build_tool_version) */ uint32_t platform; /* platform */ uint32_t minos; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ uint32_t ntools; /* number of tool entries following this */}; struct source_version_command { uint32_t cmd; /* LC_SOURCE_VERSION */ uint32_t cmdsize; /* 16 */ uint64_t version; /* A.B.C.D.E packed as a24.b10.c10.d10.e10 */}; struct symtab_command { uint32_t cmd; /* LC_SYMTAB */ uint32_t cmdsize; /* sizeof(struct symtab_command) */ uint32_t symoff; /* symbol table offset */ uint32_t nsyms; /* number of symbol table entries */ uint32_t stroff; /* string table offset */ uint32_t strsize; /* string table size in bytes */}; struct dysymtab_command { uint32_t cmd; /* LC_DYSYMTAB */ uint32_t cmdsize; /* sizeof(struct dysymtab_command) */ uint32_t ilocalsym; /* index to local symbols */ uint32_t nlocalsym; /* number of local symbols */ uint32_t iextdefsym;/* index to externally defined symbols */ uint32_t nextdefsym;/* number of externally defined symbols */ uint32_t iundefsym; /* index to undefined symbols */ uint32_t nundefsym; /* number of undefined symbols */ uint32_t tocoff; /* file offset to table of contents */ uint32_t ntoc; /* number of entries in table of contents */ uint32_t modtaboff; /* file offset to module table */ uint32_t nmodtab; /* number of module table entries */ uint32_t extrefsymoff; /* offset to referenced symbol table */ uint32_t nextrefsyms; /* number of referenced symbol table entries */ uint32_t indirectsymoff;/* file offset to the indirect symbol table */ uint32_t nindirectsyms; /* number of indirect symbol table entries */ uint32_t extreloff; /* offset to external relocation entries */ uint32_t nextrel; /* number of external relocation entries */ uint32_t locreloff; /* offset to local relocation entries */ uint32_t nlocrel; /* number of local relocation entries */}; #define BIND_OPCODE_DONE 0x00#define BIND_OPCODE_SET_DYLIB_SPECIAL_IMM 0x30#define BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM 0x40#define BIND_OPCODE_SET_TYPE_IMM 0x50#define BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x70#define BIND_OPCODE_DO_BIND 0x90 #define BIND_SYMBOL_FLAGS_WEAK_IMPORT 0x1 #define BIND_TYPE_POINTER 1#define BIND_SPECIAL_DYLIB_FLAT_LOOKUP -2 #define REBASE_OPCODE_DONE 0x00#define REBASE_OPCODE_SET_TYPE_IMM 0x10#define REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x20#define REBASE_OPCODE_DO_REBASE_IMM_TIMES 0x50 #define REBASE_TYPE_POINTER 1 #define EXPORT_SYMBOL_FLAGS_KIND_REGULAR 0x00#define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02#define EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 0x04 struct dyld_info_command { uint32_t cmd; /* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */ uint32_t cmdsize; /* sizeof(struct dyld_info_command) */ uint32_t rebase_off; /* file offset to rebase info */ uint32_t rebase_size; /* size of rebase info */ uint32_t bind_off; /* file offset to binding info */ uint32_t bind_size; /* size of binding info */ uint32_t weak_bind_off; /* file offset to weak binding info */ uint32_t weak_bind_size; /* size of weak binding info */ uint32_t lazy_bind_off; /* file offset to lazy binding info */ uint32_t lazy_bind_size; /* size of lazy binding infs */ uint32_t export_off; /* file offset to lazy binding info */ uint32_t export_size; /* size of lazy binding infs */}; #define INDIRECT_SYMBOL_LOCAL 0x80000000 struct entry_point_command { uint32_t cmd; /* LC_MAIN only used in MH_EXECUTE filetypes */ uint32_t cmdsize; /* 24 */ uint64_t entryoff; /* file (__TEXT) offset of main() */ uint64_t stacksize;/* if not zero, initial stack size */}; enum skind { sk_unknown = 0, sk_discard, sk_text, sk_stubs, sk_stub_helper, sk_ro_data, sk_uw_info, sk_nl_ptr, // non-lazy pointers, aka GOT sk_debug_info, sk_debug_abbrev, sk_debug_line, sk_debug_aranges, sk_debug_str, sk_debug_line_str, sk_stab, sk_stab_str, sk_la_ptr, // lazy pointers sk_init, sk_fini, sk_rw_data, sk_bss, sk_linkedit, sk_last}; struct nlist_64 { uint32_t n_strx; /* index into the string table */ uint8_t n_type; /* type flag, see below */ uint8_t n_sect; /* section number or NO_SECT */ uint16_t n_desc; /* see <mach-o/stab.h> */ uint64_t n_value; /* value of this symbol (or stab offset) */}; #define N_UNDF 0x0#define N_ABS 0x2#define N_EXT 0x1#define N_SECT 0xe #define N_WEAK_REF 0x0040#define N_WEAK_DEF 0x0080 struct macho { struct mach_header_64 mh; int *seg2lc, nseg; struct load_command **lc; struct entry_point_command *ep; int nlc; struct { Section *s; int machosect; } sk_to_sect[sk_last]; int *elfsectomacho; int *e2msym; Section *symtab, *strtab, *indirsyms, *stubs, *exports; uint32_t ilocal, iextdef, iundef; int stubsym, n_got, nr_plt; int segment[sk_last];#ifdef CONFIG_NEW_MACHO Section *chained_fixups; int n_bind; int n_bind_rebase; struct bind_rebase { int section; int bind; ElfW_Rel rel; } *bind_rebase;#else Section *rebase, *binding, *weak_binding, *lazy_binding; Section *stub_helper, *la_symbol_ptr; struct dyld_info_command *dyldinfo; int helpsym, lasym, dyld_private, dyld_stub_binder; int n_lazy_bind; struct s_lazy_bind { int section; int bind_offset; int la_symbol_offset; ElfW_Rel rel; } *s_lazy_bind; int n_rebase; struct s_rebase { int section; ElfW_Rel rel; } *s_rebase; int n_bind; struct bind { int section; ElfW_Rel rel; } *bind;#endif}; #define SHT_LINKEDIT (SHT_LOOS + 42)#define SHN_FROMDLL (SHN_LOOS + 2) /* Symbol is undefined, comes from a DLL */ static void * add_lc(struct macho *mo, uint32_t cmd, uint32_t cmdsize){ struct load_command *lc = tcc_mallocz(cmdsize); lc->cmd = cmd; lc->cmdsize = cmdsize; mo->lc = tcc_realloc(mo->lc, sizeof(mo->lc[0]) * (mo->nlc + 1)); mo->lc[mo->nlc++] = lc; return lc;} static struct segment_command_64 * add_segment(struct macho *mo, const char *name){ struct segment_command_64 *sc = add_lc(mo, LC_SEGMENT_64, sizeof(*sc)); strncpy(sc->segname, name, 16); mo->seg2lc = tcc_realloc(mo->seg2lc, sizeof(*mo->seg2lc) * (mo->nseg + 1)); mo->seg2lc[mo->nseg++] = mo->nlc - 1; return sc;} static struct segment_command_64 * get_segment(struct macho *mo, int i){ return (struct segment_command_64 *) (mo->lc[mo->seg2lc[i]]);} static int add_section(struct macho *mo, struct segment_command_64 **_seg, const char *name)Lines 1–500 of 2477. Load more
/* * Mach-O file handling for TCC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "tcc.h" /* In order to make life easy for us we are generating Mach-O files which don't make use of some modern features, but which aren't entirely classic either in that they do use some modern features. We're also only generating 64bit Mach-O files, and only native endian at that. In particular we're generating executables that don't make use of DYLD_INFO for dynamic linking info, as that requires us building a trie of exported names. We're simply using classic symbol tables which are still supported by modern dyld. But we do use LC_MAIN, which is a "modern" feature in order to not have to setup our own crt code. We're not using lazy linking, so even function calls are resolved at startup. */ #if !defined TCC_TARGET_X86_64 && !defined TCC_TARGET_ARM64 #error Platform not supported #endif /* XXX: this file uses tcc_error() to the effect of exit(1) */ #undef _tcc_error #define DEBUG_MACHO 0 #define dprintf if (DEBUG_MACHO) printf #define MH_EXECUTE (0x2) #define MH_DYLDLINK (0x4) #define MH_DYLIB (0x6) #define MH_PIE (0x200000) #define CPU_SUBTYPE_LIB64 (0x80000000) #define CPU_SUBTYPE_X86_ALL (3) #define CPU_SUBTYPE_ARM64_ALL (0) #define CPU_ARCH_ABI64 (0x01000000) #define CPU_TYPE_X86 (7) #define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64) #define CPU_TYPE_ARM (12) #define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) struct fat_header { uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */ uint32_t nfat_arch; /* number of structs that follow */ }; struct fat_arch { int cputype; /* cpu specifier (int) */ int cpusubtype; /* machine specifier (int) */ uint32_t offset; /* file offset to this object file */ uint32_t size; /* size of this object file */ uint32_t align; /* alignment as a power of 2 */ }; #define FAT_MAGIC 0xcafebabe #define FAT_CIGAM 0xbebafeca #define FAT_MAGIC_64 0xcafebabf #define FAT_CIGAM_64 0xbfbafeca struct mach_header { uint32_t magic; /* mach magic number identifier */ int cputype; /* cpu specifier */ int cpusubtype; /* machine specifier */ uint32_t filetype; /* type of file */ uint32_t ncmds; /* number of load commands */ uint32_t sizeofcmds; /* the size of all the load commands */ uint32_t flags; /* flags */ }; struct mach_header_64 { struct mach_header mh; uint32_t reserved; /* reserved, pad to 64bit */ }; /* Constant for the magic field of the mach_header (32-bit architectures) */ #define MH_MAGIC 0xfeedface /* the mach magic number */ #define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */ #define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */ #define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */ struct load_command { uint32_t cmd; /* type of load command */ uint32_t cmdsize; /* total size of command in bytes */ }; #define LC_REQ_DYLD 0x80000000 #define LC_SYMTAB 0x2 #define LC_DYSYMTAB 0xb #define LC_LOAD_DYLIB 0xc #define LC_ID_DYLIB 0xd #define LC_LOAD_DYLINKER 0xe #define LC_SEGMENT_64 0x19 #define LC_RPATH (0x1c | LC_REQ_DYLD) #define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) #define LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD) #define LC_MAIN (0x28|LC_REQ_DYLD) #define LC_SOURCE_VERSION 0x2A #define LC_BUILD_VERSION 0x32 #define LC_DYLD_EXPORTS_TRIE (0x33 | LC_REQ_DYLD) #define LC_DYLD_CHAINED_FIXUPS (0x34 | LC_REQ_DYLD) #define SG_READ_ONLY 0x10 /* This segment is made read-only after fixups */ typedef int vm_prot_t; struct segment_command_64 { /* for 64-bit architectures */ uint32_t cmd; /* LC_SEGMENT_64 */ uint32_t cmdsize; /* includes sizeof section_64 structs */ char segname[16]; /* segment name */ uint64_t vmaddr; /* memory address of this segment */ uint64_t vmsize; /* memory size of this segment */ uint64_t fileoff; /* file offset of this segment */ uint64_t filesize; /* amount to map from the file */ vm_prot_t maxprot; /* maximum VM protection */ vm_prot_t initprot; /* initial VM protection */ uint32_t nsects; /* number of sections in segment */ uint32_t flags; /* flags */ }; struct section_64 { /* for 64-bit architectures */ char sectname[16]; /* name of this section */ char segname[16]; /* segment this section goes in */ uint64_t addr; /* memory address of this section */ uint64_t size; /* size in bytes of this section */ uint32_t offset; /* file offset of this section */ uint32_t align; /* section alignment (power of 2) */ uint32_t reloff; /* file offset of relocation entries */ uint32_t nreloc; /* number of relocation entries */ uint32_t flags; /* flags (section type and attributes)*/ uint32_t reserved1; /* reserved (for offset or index) */ uint32_t reserved2; /* reserved (for count or sizeof) */ uint32_t reserved3; /* reserved */ }; enum { DYLD_CHAINED_IMPORT = 1, }; struct dyld_chained_fixups_header { uint32_t fixups_version; ///< 0 uint32_t starts_offset; ///< Offset of dyld_chained_starts_in_image. uint32_t imports_offset; ///< Offset of imports table in chain_data. uint32_t symbols_offset; ///< Offset of symbol strings in chain_data. uint32_t imports_count; ///< Number of imported symbol names. uint32_t imports_format; ///< DYLD_CHAINED_IMPORT* uint32_t symbols_format; ///< 0 => uncompressed, 1 => zlib compressed }; struct dyld_chained_starts_in_image { uint32_t seg_count; uint32_t seg_info_offset[1]; // each entry is offset into this struct for that segment // followed by pool of dyld_chain_starts_in_segment data }; enum { DYLD_CHAINED_PTR_64 = 2, // target is vmaddr DYLD_CHAINED_PTR_64_OFFSET = 6, // target is vm offset }; enum { DYLD_CHAINED_PTR_START_NONE = 0xFFFF, // used in page_start[] to denote a page with no fixups }; #define SEG_PAGE_SIZE 16384 struct dyld_chained_starts_in_segment { uint32_t size; // size of this (amount kernel needs to copy) uint16_t page_size; // 0x1000 or 0x4000 uint16_t pointer_format; // DYLD_CHAINED_PTR_* uint64_t segment_offset; // offset in memory to start of segment uint32_t max_valid_pointer; // for 32-bit OS, any value beyond this is not a pointer uint16_t page_count; // how many pages are in array uint16_t page_start[1]; // each entry is offset in each page of first element in chain // or DYLD_CHAINED_PTR_START_NONE if no fixups on page }; enum BindSpecialDylib { BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2, }; struct dyld_chained_import { uint32_t lib_ordinal : 8, weak_import : 1, name_offset : 23; }; struct dyld_chained_ptr_64_rebase { uint64_t target : 36, // vmaddr, 64GB max image size high8 : 8, // top 8 bits set to this after slide added reserved : 7, // all zeros next : 12, // 4-byte stride bind : 1; // == 0 }; struct dyld_chained_ptr_64_bind { uint64_t ordinal : 24, addend : 8, // 0 thru 255 reserved : 19, // all zeros next : 12, // 4-byte stride bind : 1; // == 1 }; #define S_REGULAR 0x0 #define S_ZEROFILL 0x1 #define S_NON_LAZY_SYMBOL_POINTERS 0x6 #define S_LAZY_SYMBOL_POINTERS 0x7 #define S_SYMBOL_STUBS 0x8 #define S_MOD_INIT_FUNC_POINTERS 0x9 #define S_MOD_TERM_FUNC_POINTERS 0xa #define S_ATTR_PURE_INSTRUCTIONS 0x80000000 #define S_ATTR_SOME_INSTRUCTIONS 0x00000400 #define S_ATTR_DEBUG 0x02000000 typedef uint32_t lc_str; struct dylib_command { uint32_t cmd; /* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB, LC_REEXPORT_DYLIB */ uint32_t cmdsize; /* includes pathname string */ lc_str name; /* library's path name */ uint32_t timestamp; /* library's build time stamp */ uint32_t current_version; /* library's current version number */ uint32_t compatibility_version; /* library's compatibility vers number*/ }; struct rpath_command { uint32_t cmd; /* LC_RPATH */ uint32_t cmdsize; /* includes string */ lc_str path; /* path to add to run path */ }; struct dylinker_command { uint32_t cmd; /* LC_ID_DYLINKER, LC_LOAD_DYLINKER or LC_DYLD_ENVIRONMENT */ uint32_t cmdsize; /* includes pathname string */ lc_str name; /* dynamic linker's path name */ }; struct linkedit_data_command { uint32_t cmd; /* LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS, LC_LINKER_OPTIMIZATION_HINT, LC_DYLD_EXPORTS_TRIE, or LC_DYLD_CHAINED_FIXUPS. */ 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 */ }; #define PLATFORM_MACOS 1 struct build_version_command { uint32_t cmd; /* LC_BUILD_VERSION */ uint32_t cmdsize; /* sizeof(struct build_version_command) plus */ /* ntools * sizeof(struct build_tool_version) */ uint32_t platform; /* platform */ uint32_t minos; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ uint32_t ntools; /* number of tool entries following this */ }; struct source_version_command { uint32_t cmd; /* LC_SOURCE_VERSION */ uint32_t cmdsize; /* 16 */ uint64_t version; /* A.B.C.D.E packed as a24.b10.c10.d10.e10 */ }; struct symtab_command { uint32_t cmd; /* LC_SYMTAB */ uint32_t cmdsize; /* sizeof(struct symtab_command) */ uint32_t symoff; /* symbol table offset */ uint32_t nsyms; /* number of symbol table entries */ uint32_t stroff; /* string table offset */ uint32_t strsize; /* string table size in bytes */ }; struct dysymtab_command { uint32_t cmd; /* LC_DYSYMTAB */ uint32_t cmdsize; /* sizeof(struct dysymtab_command) */ uint32_t ilocalsym; /* index to local symbols */ uint32_t nlocalsym; /* number of local symbols */ uint32_t iextdefsym;/* index to externally defined symbols */ uint32_t nextdefsym;/* number of externally defined symbols */ uint32_t iundefsym; /* index to undefined symbols */ uint32_t nundefsym; /* number of undefined symbols */ uint32_t tocoff; /* file offset to table of contents */ uint32_t ntoc; /* number of entries in table of contents */ uint32_t modtaboff; /* file offset to module table */ uint32_t nmodtab; /* number of module table entries */ uint32_t extrefsymoff; /* offset to referenced symbol table */ uint32_t nextrefsyms; /* number of referenced symbol table entries */ uint32_t indirectsymoff;/* file offset to the indirect symbol table */ uint32_t nindirectsyms; /* number of indirect symbol table entries */ uint32_t extreloff; /* offset to external relocation entries */ uint32_t nextrel; /* number of external relocation entries */ uint32_t locreloff; /* offset to local relocation entries */ uint32_t nlocrel; /* number of local relocation entries */ }; #define BIND_OPCODE_DONE 0x00 #define BIND_OPCODE_SET_DYLIB_SPECIAL_IMM 0x30 #define BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM 0x40 #define BIND_OPCODE_SET_TYPE_IMM 0x50 #define BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x70 #define BIND_OPCODE_DO_BIND 0x90 #define BIND_SYMBOL_FLAGS_WEAK_IMPORT 0x1 #define BIND_TYPE_POINTER 1 #define BIND_SPECIAL_DYLIB_FLAT_LOOKUP -2 #define REBASE_OPCODE_DONE 0x00 #define REBASE_OPCODE_SET_TYPE_IMM 0x10 #define REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x20 #define REBASE_OPCODE_DO_REBASE_IMM_TIMES 0x50 #define REBASE_TYPE_POINTER 1 #define EXPORT_SYMBOL_FLAGS_KIND_REGULAR 0x00 #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02 #define EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 0x04 struct dyld_info_command { uint32_t cmd; /* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */ uint32_t cmdsize; /* sizeof(struct dyld_info_command) */ uint32_t rebase_off; /* file offset to rebase info */ uint32_t rebase_size; /* size of rebase info */ uint32_t bind_off; /* file offset to binding info */ uint32_t bind_size; /* size of binding info */ uint32_t weak_bind_off; /* file offset to weak binding info */ uint32_t weak_bind_size; /* size of weak binding info */ uint32_t lazy_bind_off; /* file offset to lazy binding info */ uint32_t lazy_bind_size; /* size of lazy binding infs */ uint32_t export_off; /* file offset to lazy binding info */ uint32_t export_size; /* size of lazy binding infs */ }; #define INDIRECT_SYMBOL_LOCAL 0x80000000 struct entry_point_command { uint32_t cmd; /* LC_MAIN only used in MH_EXECUTE filetypes */ uint32_t cmdsize; /* 24 */ uint64_t entryoff; /* file (__TEXT) offset of main() */ uint64_t stacksize;/* if not zero, initial stack size */ }; enum skind { sk_unknown = 0, sk_discard, sk_text, sk_stubs, sk_stub_helper, sk_ro_data, sk_uw_info, sk_nl_ptr, // non-lazy pointers, aka GOT sk_debug_info, sk_debug_abbrev, sk_debug_line, sk_debug_aranges, sk_debug_str, sk_debug_line_str, sk_stab, sk_stab_str, sk_la_ptr, // lazy pointers sk_init, sk_fini, sk_rw_data, sk_bss, sk_linkedit, sk_last }; struct nlist_64 { uint32_t n_strx; /* index into the string table */ uint8_t n_type; /* type flag, see below */ uint8_t n_sect; /* section number or NO_SECT */ uint16_t n_desc; /* see <mach-o/stab.h> */ uint64_t n_value; /* value of this symbol (or stab offset) */ }; #define N_UNDF 0x0 #define N_ABS 0x2 #define N_EXT 0x1 #define N_SECT 0xe #define N_WEAK_REF 0x0040 #define N_WEAK_DEF 0x0080 struct macho { struct mach_header_64 mh; int *seg2lc, nseg; struct load_command **lc; struct entry_point_command *ep; int nlc; struct { Section *s; int machosect; } sk_to_sect[sk_last]; int *elfsectomacho; int *e2msym; Section *symtab, *strtab, *indirsyms, *stubs, *exports; uint32_t ilocal, iextdef, iundef; int stubsym, n_got, nr_plt; int segment[sk_last]; #ifdef CONFIG_NEW_MACHO Section *chained_fixups; int n_bind; int n_bind_rebase; struct bind_rebase { int section; int bind; ElfW_Rel rel; } *bind_rebase; #else Section *rebase, *binding, *weak_binding, *lazy_binding; Section *stub_helper, *la_symbol_ptr; struct dyld_info_command *dyldinfo; int helpsym, lasym, dyld_private, dyld_stub_binder; int n_lazy_bind; struct s_lazy_bind { int section; int bind_offset; int la_symbol_offset; ElfW_Rel rel; } *s_lazy_bind; int n_rebase; struct s_rebase { int section; ElfW_Rel rel; } *s_rebase; int n_bind; struct bind { int section; ElfW_Rel rel; } *bind; #endif }; #define SHT_LINKEDIT (SHT_LOOS + 42) #define SHN_FROMDLL (SHN_LOOS + 2) /* Symbol is undefined, comes from a DLL */ static void * add_lc(struct macho *mo, uint32_t cmd, uint32_t cmdsize) { struct load_command *lc = tcc_mallocz(cmdsize); lc->cmd = cmd; lc->cmdsize = cmdsize; mo->lc = tcc_realloc(mo->lc, sizeof(mo->lc[0]) * (mo->nlc + 1)); mo->lc[mo->nlc++] = lc; return lc; } static struct segment_command_64 * add_segment(struct macho *mo, const char *name) { struct segment_command_64 *sc = add_lc(mo, LC_SEGMENT_64, sizeof(*sc)); strncpy(sc->segname, name, 16); mo->seg2lc = tcc_realloc(mo->seg2lc, sizeof(*mo->seg2lc) * (mo->nseg + 1)); mo->seg2lc[mo->nseg++] = mo->nlc - 1; return sc; } static struct segment_command_64 * get_segment(struct macho *mo, int i) { return (struct segment_command_64 *) (mo->lc[mo->seg2lc[i]]); } static int add_section(struct macho *mo, struct segment_command_64 **_seg, const char *name)