aboutsummaryrefslogtreecommitdiff
path: root/tinycc/tccmacho.c
diff options
context:
space:
mode:
authorUneven Prankster <unevenprankster@protonmail.com>2023-10-15 21:28:29 -0300
committerUneven Prankster <unevenprankster@protonmail.com>2023-10-15 21:28:29 -0300
commit1c0cc775732201f4c4d3ee0d6772be786b3b4aa1 (patch)
treef5d692d046868261275c7430a624c3ea9ed75d3d /tinycc/tccmacho.c
parenta89f892640cf12f75c7ce18e6e88c70a8d3965ed (diff)
A lot has certainly happened!
Diffstat (limited to 'tinycc/tccmacho.c')
-rw-r--r--tinycc/tccmacho.c2480
1 files changed, 0 insertions, 2480 deletions
diff --git a/tinycc/tccmacho.c b/tinycc/tccmacho.c
deleted file mode 100644
index 4d282dd..0000000
--- a/tinycc/tccmacho.c
+++ /dev/null
@@ -1,2480 +0,0 @@
-/*
- * 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)
-{
- struct segment_command_64 *seg = *_seg;
- int ret = seg->nsects;
- struct section_64 *sec;
- seg->nsects++;
- seg->cmdsize += sizeof(*sec);
- seg = tcc_realloc(seg, sizeof(*seg) + seg->nsects * sizeof(*sec));
- sec = (struct section_64*)((char*)seg + sizeof(*seg)) + ret;
- memset(sec, 0, sizeof(*sec));
- strncpy(sec->sectname, name, 16);
- strncpy(sec->segname, seg->segname, 16);
- *_seg = seg;
- return ret;
-}
-
-static struct section_64 *get_section(struct segment_command_64 *seg, int i)
-{
- return (struct section_64*)((char*)seg + sizeof(*seg)) + i;
-}
-
-static void * add_dylib(struct macho *mo, char *name)
-{
- struct dylib_command *lc;
- int sz = (sizeof(*lc) + strlen(name) + 1 + 7) & -8;
- lc = add_lc(mo, LC_LOAD_DYLIB, sz);
- lc->name = sizeof(*lc);
- strcpy((char*)lc + lc->name, name);
- lc->timestamp = 2;
- lc->current_version = 1 << 16;
- lc->compatibility_version = 1 << 16;
- return lc;
-}
-
-static int uleb128_size (unsigned long long value)
-{
- int size = 0;
-
- do {
- value >>= 7;
- size++;
- } while (value != 0);
- return size;
-}
-
-static void write_uleb128(Section *section, uint64_t value)
-{
- do {
- unsigned char byte = value & 0x7f;
- uint8_t *ptr = section_ptr_add(section, 1);
-
- value >>= 7;
- *ptr = byte | (value ? 0x80 : 0);
- } while (value != 0);
-}
-
-static void tcc_macho_add_destructor(TCCState *s1)
-{
- int init_sym, mh_execute_header, at_exit_sym;
- Section *s;
- ElfW_Rel *rel;
- uint8_t *ptr;
-
- mh_execute_header = put_elf_sym(s1->symtab, -4096, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), 0,
- text_section->sh_num, "__mh_execute_header");
- s = find_section(s1, ".fini_array");
- if (s->data_offset == 0)
- return;
- init_sym = put_elf_sym(s1->symtab, text_section->data_offset, 0,
- ELFW(ST_INFO)(STB_LOCAL, STT_FUNC), 0,
- text_section->sh_num, "___GLOBAL_init_65535");
- at_exit_sym = put_elf_sym(s1->symtab, 0, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_FUNC), 0,
- SHN_UNDEF, "___cxa_atexit");
-#ifdef TCC_TARGET_X86_64
- ptr = section_ptr_add(text_section, 4);
- ptr[0] = 0x55; // pushq %rbp
- ptr[1] = 0x48; // movq %rsp, %rbp
- ptr[2] = 0x89;
- ptr[3] = 0xe5;
- for_each_elem(s->reloc, 0, rel, ElfW_Rel) {
- int sym_index = ELFW(R_SYM)(rel->r_info);
-
- ptr = section_ptr_add(text_section, 26);
- ptr[0] = 0x48; // lea destructor(%rip),%rax
- ptr[1] = 0x8d;
- ptr[2] = 0x05;
- put_elf_reloca(s1->symtab, text_section,
- text_section->data_offset - 23,
- R_X86_64_PC32, sym_index, -4);
- ptr[7] = 0x48; // mov %rax,%rdi
- ptr[8] = 0x89;
- ptr[9] = 0xc7;
- ptr[10] = 0x31; // xorl %ecx, %ecx
- ptr[11] = 0xc9;
- ptr[12] = 0x89; // movl %ecx, %esi
- ptr[13] = 0xce;
- ptr[14] = 0x48; // lea mh_execute_header(%rip),%rdx
- ptr[15] = 0x8d;
- ptr[16] = 0x15;
- put_elf_reloca(s1->symtab, text_section,
- text_section->data_offset - 9,
- R_X86_64_PC32, mh_execute_header, -4);
- ptr[21] = 0xe8; // call __cxa_atexit
- put_elf_reloca(s1->symtab, text_section,
- text_section->data_offset - 4,
- R_X86_64_PLT32, at_exit_sym, -4);
- }
- ptr = section_ptr_add(text_section, 2);
- ptr[0] = 0x5d; // pop %rbp
- ptr[1] = 0xc3; // ret
-#elif defined TCC_TARGET_ARM64
- ptr = section_ptr_add(text_section, 8);
- write32le(ptr, 0xa9bf7bfd); // stp x29, x30, [sp, #-16]!
- write32le(ptr + 4, 0x910003fd); // mov x29, sp
- for_each_elem(s->reloc, 0, rel, ElfW_Rel) {
- int sym_index = ELFW(R_SYM)(rel->r_info);
-
- ptr = section_ptr_add(text_section, 24);
- put_elf_reloc(s1->symtab, text_section,
- text_section->data_offset - 24,
- R_AARCH64_ADR_PREL_PG_HI21, sym_index);
- write32le(ptr, 0x90000000); // adrp x0, destructor@page
- put_elf_reloc(s1->symtab, text_section,
- text_section->data_offset - 20,
- R_AARCH64_LDST8_ABS_LO12_NC, sym_index);
- write32le(ptr + 4, 0x91000000); // add x0,x0,destructor@pageoff
- write32le(ptr + 8, 0xd2800001); // mov x1, #0
- put_elf_reloc(s1->symtab, text_section,
- text_section->data_offset - 12,
- R_AARCH64_ADR_PREL_PG_HI21, mh_execute_header);
- write32le(ptr + 12, 0x90000002); // adrp x2, mh_execute_header@page
- put_elf_reloc(s1->symtab, text_section,
- text_section->data_offset - 8,
- R_AARCH64_LDST8_ABS_LO12_NC, mh_execute_header);
- write32le(ptr + 16, 0x91000042); // add x2,x2,mh_execute_header@pageoff
- put_elf_reloc(s1->symtab, text_section,
- text_section->data_offset - 4,
- R_AARCH64_CALL26, at_exit_sym);
- write32le(ptr + 20, 0x94000000); // bl __cxa_atexit
- }
- ptr = section_ptr_add(text_section, 8);
- write32le(ptr, 0xa8c17bfd); // ldp x29, x30, [sp], #16
- write32le(ptr + 4, 0xd65f03c0); // ret
-#endif
- s->reloc->data_offset = s->data_offset = 0;
- s->sh_flags &= ~SHF_ALLOC;
- add_array (s1, ".init_array", init_sym);
-}
-
-#ifdef CONFIG_NEW_MACHO
-static void bind_rebase_add(struct macho *mo, int bind, int sh_info,
- ElfW_Rel *rel, struct sym_attr *attr)
-{
- mo->bind_rebase = tcc_realloc(mo->bind_rebase, (mo->n_bind_rebase + 1) *
- sizeof(struct bind_rebase));
- mo->bind_rebase[mo->n_bind_rebase].section = sh_info;
- mo->bind_rebase[mo->n_bind_rebase].bind = bind;
- mo->bind_rebase[mo->n_bind_rebase].rel = *rel;
- if (attr)
- mo->bind_rebase[mo->n_bind_rebase].rel.r_offset = attr->got_offset;
- mo->n_bind_rebase++;
- mo->n_bind += bind;
-}
-
-static void check_relocs(TCCState *s1, struct macho *mo)
-{
- Section *s;
- ElfW_Rel *rel, save_rel;
- ElfW(Sym) *sym;
- int i, j, type, gotplt_entry, sym_index, for_code;
- uint32_t *pi, *goti;
- struct sym_attr *attr;
-
- goti = NULL;
- mo->nr_plt = mo->n_got = 0;
- for (i = 1; i < s1->nb_sections; i++) {
- s = s1->sections[i];
- if (s->sh_type != SHT_RELX ||
- !strncmp(s1->sections[s->sh_info]->name, ".debug_", 7))
- continue;
- for_each_elem(s, 0, rel, ElfW_Rel) {
- save_rel = *rel;
- type = ELFW(R_TYPE)(rel->r_info);
- gotplt_entry = gotplt_entry_type(type);
- for_code = code_reloc(type);
- /* We generate a non-lazy pointer for used undefined symbols
- and for defined symbols that must have a place for their
- address due to codegen (i.e. a reloc requiring a got slot). */
- sym_index = ELFW(R_SYM)(rel->r_info);
- sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
- if (sym->st_shndx == SHN_UNDEF
- || gotplt_entry == ALWAYS_GOTPLT_ENTRY) {
- attr = get_sym_attr(s1, sym_index, 1);
- if (!attr->dyn_index) {
- attr->got_offset = s1->got->data_offset;
- attr->plt_offset = -1;
- attr->dyn_index = 1; /* used as flag */
- section_ptr_add(s1->got, PTR_SIZE);
- put_elf_reloc(s1->symtab, s1->got, attr->got_offset,
- R_JMP_SLOT, sym_index);
- goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti));
- if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
- if (sym->st_shndx == SHN_UNDEF)
- tcc_error("undefined local symbo: '%s'",
- (char *) symtab_section->link->data + sym->st_name);
- goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
- } else {
- goti[mo->n_got++] = mo->e2msym[sym_index];
- if (sym->st_shndx == SHN_UNDEF
-#ifdef TCC_TARGET_X86_64
- && type == R_X86_64_GOTPCREL
-#elif defined TCC_TARGET_ARM64
- && type == R_AARCH64_ADR_GOT_PAGE
-#endif
- ) {
- attr->plt_offset = -mo->n_bind_rebase - 2;
- bind_rebase_add(mo, 1, s1->got->reloc->sh_info, &save_rel, attr);
- s1->got->reloc->data_offset -= sizeof (ElfW_Rel);
- }
- if (for_code && sym->st_shndx == SHN_UNDEF)
- s1->got->reloc->data_offset -= sizeof (ElfW_Rel);
- }
- }
- if (for_code && sym->st_shndx == SHN_UNDEF) {
- if ((int)attr->plt_offset < -1) {
- /* remove above bind and replace with plt */
- mo->bind_rebase[-attr->plt_offset - 2].bind = 2;
- attr->plt_offset = -1;
- }
- if (attr->plt_offset == -1) {
- uint8_t *jmp;
-
- attr->plt_offset = mo->stubs->data_offset;
-#ifdef TCC_TARGET_X86_64
- if (type != R_X86_64_PLT32)
- continue;
- jmp = section_ptr_add(mo->stubs, 6);
- jmp[0] = 0xff; /* jmpq *ofs(%rip) */
- jmp[1] = 0x25;
- put_elf_reloc(s1->symtab, mo->stubs,
- attr->plt_offset + 2,
- R_X86_64_GOTPCREL, sym_index);
-#elif defined TCC_TARGET_ARM64
- if (type != R_AARCH64_CALL26)
- continue;
- jmp = section_ptr_add(mo->stubs, 12);
- put_elf_reloc(s1->symtab, mo->stubs,
- attr->plt_offset,
- R_AARCH64_ADR_GOT_PAGE, sym_index);
- write32le(jmp, // adrp x16, #sym
- 0x90000010);
- put_elf_reloc(s1->symtab, mo->stubs,
- attr->plt_offset + 4,
- R_AARCH64_LD64_GOT_LO12_NC, sym_index);
- write32le(jmp + 4, // ld x16,[x16, #sym]
- 0xf9400210);
- write32le(jmp + 8, // br x16
- 0xd61f0200);
-#endif
- bind_rebase_add(mo, 1, s1->got->reloc->sh_info, &save_rel, attr);
- pi = section_ptr_add(mo->indirsyms, sizeof(*pi));
- *pi = mo->e2msym[sym_index];
- mo->nr_plt++;
- }
- rel->r_info = ELFW(R_INFO)(mo->stubsym, type);
- rel->r_addend += attr->plt_offset;
- }
- }
- if (type == R_DATA_PTR || type == R_JMP_SLOT)
- bind_rebase_add(mo, sym->st_shndx == SHN_UNDEF ? 1 : 0,
- s->sh_info, &save_rel, NULL);
- }
- }
- /* remove deleted binds */
- for (i = 0, j = 0; i < mo->n_bind_rebase; i++)
- if (mo->bind_rebase[i].bind == 2)
- mo->n_bind--;
- else
- mo->bind_rebase[j++] = mo->bind_rebase[i];
- mo->n_bind_rebase = j;
- pi = section_ptr_add(mo->indirsyms, mo->n_got * sizeof(*pi));
- memcpy(pi, goti, mo->n_got * sizeof(*pi));
- tcc_free(goti);
-}
-
-#else
-
-static void check_relocs(TCCState *s1, struct macho *mo)
-{
- uint8_t *jmp;
- Section *s;
- ElfW_Rel *rel, save_rel;
- ElfW(Sym) *sym;
- int i, type, gotplt_entry, sym_index, for_code;
- int bind_offset, la_symbol_offset;
- uint32_t *pi, *goti;
- struct sym_attr *attr;
-
-#ifdef TCC_TARGET_X86_64
- jmp = section_ptr_add(mo->stub_helper, 16);
- jmp[0] = 0x4c; /* leaq _dyld_private(%rip), %r11 */
- jmp[1] = 0x8d;
- jmp[2] = 0x1d;
- put_elf_reloca(s1->symtab, mo->stub_helper, 3,
- R_X86_64_PC32, mo->dyld_private, -4);
- jmp[7] = 0x41; /* pushq %r11 */
- jmp[8] = 0x53;
- jmp[9] = 0xff; /* jmpq *dyld_stub_binder@GOT(%rip) */
- jmp[10] = 0x25;
- put_elf_reloca(s1->symtab, mo->stub_helper, 11,
- R_X86_64_GOTPCREL, mo->dyld_stub_binder, -4);
- jmp[15] = 0x90; /* nop */
-#elif defined TCC_TARGET_ARM64
- jmp = section_ptr_add(mo->stub_helper, 24);
- put_elf_reloc(s1->symtab, mo->stub_helper, 0,
- R_AARCH64_ADR_PREL_PG_HI21, mo->dyld_private);
- write32le(jmp, 0x90000011); // adrp x17, _dyld_private@page
- put_elf_reloc(s1->symtab, mo->stub_helper, 4,
- R_AARCH64_LDST64_ABS_LO12_NC, mo->dyld_private);
- write32le(jmp + 4, 0x91000231); // add x17,x17,_dyld_private@pageoff
- write32le(jmp + 8, 0xa9bf47f0); // stp x16/x17, [sp, #-16]!
- put_elf_reloc(s1->symtab, mo->stub_helper, 12,
- R_AARCH64_ADR_GOT_PAGE, mo->dyld_stub_binder);
- write32le(jmp + 12, 0x90000010); // adrp x16, dyld_stub_binder@page
- put_elf_reloc(s1->symtab, mo->stub_helper, 16,
- R_AARCH64_LD64_GOT_LO12_NC, mo->dyld_stub_binder);
- write32le(jmp + 16, 0xf9400210); // ldr x16,[x16,dyld_stub_binder@pageoff]
- write32le(jmp + 20, 0xd61f0200); // br x16
-#endif
-
- goti = NULL;
- mo->nr_plt = mo->n_got = 0;
- for (i = 1; i < s1->nb_sections; i++) {
- s = s1->sections[i];
- if (s->sh_type != SHT_RELX ||
- !strncmp(s1->sections[s->sh_info]->name, ".debug_", 7))
- continue;
- for_each_elem(s, 0, rel, ElfW_Rel) {
- save_rel = *rel;
- type = ELFW(R_TYPE)(rel->r_info);
- gotplt_entry = gotplt_entry_type(type);
- for_code = code_reloc(type);
- /* We generate a non-lazy pointer for used undefined symbols
- and for defined symbols that must have a place for their
- address due to codegen (i.e. a reloc requiring a got slot). */
- sym_index = ELFW(R_SYM)(rel->r_info);
- sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
- if (sym->st_shndx == SHN_UNDEF
- || gotplt_entry == ALWAYS_GOTPLT_ENTRY) {
- attr = get_sym_attr(s1, sym_index, 1);
- if (!attr->dyn_index) {
- attr->got_offset = s1->got->data_offset;
- attr->plt_offset = -1;
- attr->dyn_index = 1; /* used as flag */
- section_ptr_add(s1->got, PTR_SIZE);
- put_elf_reloc(s1->symtab, s1->got, attr->got_offset,
- R_JMP_SLOT, sym_index);
- goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti));
- if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
- if (sym->st_shndx == SHN_UNDEF)
- tcc_error("undefined local symbo: '%s'",
- (char *) symtab_section->link->data + sym->st_name);
- goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
- } else {
- goti[mo->n_got++] = mo->e2msym[sym_index];
- if (sym->st_shndx == SHN_UNDEF
-#ifdef TCC_TARGET_X86_64
- && type == R_X86_64_GOTPCREL
-#elif defined TCC_TARGET_ARM64
- && type == R_AARCH64_ADR_GOT_PAGE
-#endif
- ) {
- mo->bind =
- tcc_realloc(mo->bind,
- (mo->n_bind + 1) *
- sizeof(struct bind));
- mo->bind[mo->n_bind].section = s1->got->reloc->sh_info;
- mo->bind[mo->n_bind].rel = save_rel;
- mo->bind[mo->n_bind].rel.r_offset = attr->got_offset;
- mo->n_bind++;
- s1->got->reloc->data_offset -= sizeof (ElfW_Rel);
- }
- }
- }
- if (for_code && sym->st_shndx == SHN_UNDEF) {
- if (attr->plt_offset == -1) {
- attr->plt_offset = mo->stubs->data_offset;
-#ifdef TCC_TARGET_X86_64
- if (type != R_X86_64_PLT32)
- continue;
- /* __stubs */
- jmp = section_ptr_add(mo->stubs, 6);
- jmp[0] = 0xff; /* jmpq *__la_symbol_ptr(%rip) */
- jmp[1] = 0x25;
- put_elf_reloca(s1->symtab, mo->stubs,
- mo->stubs->data_offset - 4,
- R_X86_64_PC32, mo->lasym,
- mo->la_symbol_ptr->data_offset - 4);
-
- /* __stub_helper */
- bind_offset = mo->stub_helper->data_offset + 1;
- jmp = section_ptr_add(mo->stub_helper, 10);
- jmp[0] = 0x68; /* pushq $bind_offset */
- jmp[5] = 0xe9; /* jmpq __stub_helper */
- write32le(jmp + 6, -mo->stub_helper->data_offset);
-
- /* __la_symbol_ptr */
- la_symbol_offset = mo->la_symbol_ptr->data_offset;
- put_elf_reloca(s1->symtab, mo->la_symbol_ptr,
- mo->la_symbol_ptr->data_offset,
- R_DATA_PTR, mo->helpsym,
- mo->stub_helper->data_offset - 10);
- section_ptr_add(mo->la_symbol_ptr, PTR_SIZE);
-#elif defined TCC_TARGET_ARM64
- if (type != R_AARCH64_CALL26)
- continue;
- /* __stubs */
- jmp = section_ptr_add(mo->stubs, 12);
- put_elf_reloca(s1->symtab, mo->stubs,
- mo->stubs->data_offset - 12,
- R_AARCH64_ADR_PREL_PG_HI21, mo->lasym,
- mo->la_symbol_ptr->data_offset);
- write32le(jmp, // adrp x16, __la_symbol_ptr@page
- 0x90000010);
- put_elf_reloca(s1->symtab, mo->stubs,
- mo->stubs->data_offset - 8,
- R_AARCH64_LDST64_ABS_LO12_NC, mo->lasym,
- mo->la_symbol_ptr->data_offset);
- write32le(jmp + 4, // ldr x16,[x16, __la_symbol_ptr@pageoff]
- 0xf9400210);
- write32le(jmp + 8, // br x16
- 0xd61f0200);
-
- /* __stub_helper */
- bind_offset = mo->stub_helper->data_offset + 8;
- jmp = section_ptr_add(mo->stub_helper, 12);
- write32le(jmp + 0, // ldr w16, l0
- 0x18000050);
- write32le(jmp + 4, // b stubHelperHeader
- 0x14000000 +
- ((-(mo->stub_helper->data_offset - 8) / 4) &
- 0x3ffffff));
- write32le(jmp + 8, 0); // l0: .long bind_offset
-
- /* __la_symbol_ptr */
- la_symbol_offset = mo->la_symbol_ptr->data_offset;
- put_elf_reloca(s1->symtab, mo->la_symbol_ptr,
- mo->la_symbol_ptr->data_offset,
- R_DATA_PTR, mo->helpsym,
- mo->stub_helper->data_offset - 12);
- section_ptr_add(mo->la_symbol_ptr, PTR_SIZE);
-#endif
- mo->s_lazy_bind =
- tcc_realloc(mo->s_lazy_bind, (mo->n_lazy_bind + 1) *
- sizeof(struct s_lazy_bind));
- mo->s_lazy_bind[mo->n_lazy_bind].section =
- mo->stub_helper->reloc->sh_info;
- mo->s_lazy_bind[mo->n_lazy_bind].bind_offset =
- bind_offset;
- mo->s_lazy_bind[mo->n_lazy_bind].la_symbol_offset =
- la_symbol_offset;
- mo->s_lazy_bind[mo->n_lazy_bind].rel = save_rel;
- mo->s_lazy_bind[mo->n_lazy_bind].rel.r_offset =
- attr->plt_offset;
- mo->n_lazy_bind++;
- pi = section_ptr_add(mo->indirsyms, sizeof(*pi));
- *pi = mo->e2msym[sym_index];
- mo->nr_plt++;
- }
- rel->r_info = ELFW(R_INFO)(mo->stubsym, type);
- rel->r_addend += attr->plt_offset;
- }
- }
- if (type == R_DATA_PTR || type == R_JMP_SLOT) {
- if (sym->st_shndx == SHN_UNDEF) {
- mo->bind = tcc_realloc(mo->bind,
- (mo->n_bind + 1) *
- sizeof(struct bind));
- mo->bind[mo->n_bind].section = s->sh_info;
- mo->bind[mo->n_bind].rel = save_rel;
- mo->n_bind++;
- }
- else {
- mo->s_rebase =
- tcc_realloc(mo->s_rebase, (mo->n_rebase + 1) *
- sizeof(struct s_rebase));
- mo->s_rebase[mo->n_rebase].section = s->sh_info;
- mo->s_rebase[mo->n_rebase].rel = save_rel;
- mo->n_rebase++;
- }
- }
- }
- }
- pi = section_ptr_add(mo->indirsyms, mo->n_got * sizeof(*pi));
- memcpy(pi, goti, mo->n_got * sizeof(*pi));
- pi = section_ptr_add(mo->indirsyms, mo->nr_plt * sizeof(*pi));
- memcpy(pi, mo->indirsyms->data, mo->nr_plt * sizeof(*pi));
- tcc_free(goti);
-}
-#endif
-
-static int check_symbols(TCCState *s1, struct macho *mo)
-{
- int sym_index, sym_end;
- int ret = 0;
-
- mo->ilocal = mo->iextdef = mo->iundef = -1;
- sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
- for (sym_index = 1; sym_index < sym_end; ++sym_index) {
- int elf_index = ((struct nlist_64 *)mo->symtab->data + sym_index - 1)->n_value;
- ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + elf_index;
- const char *name = (char*)symtab_section->link->data + sym->st_name;
- unsigned type = ELFW(ST_TYPE)(sym->st_info);
- unsigned bind = ELFW(ST_BIND)(sym->st_info);
- unsigned vis = ELFW(ST_VISIBILITY)(sym->st_other);
-
- dprintf("%4d (%4d): %09lx %4d %4d %4d %3d %s\n",
- sym_index, elf_index, (long)sym->st_value,
- type, bind, vis, sym->st_shndx, name);
- if (bind == STB_LOCAL) {
- if (mo->ilocal == -1)
- mo->ilocal = sym_index - 1;
- if (mo->iextdef != -1 || mo->iundef != -1)
- tcc_error("local syms after global ones");
- } else if (sym->st_shndx != SHN_UNDEF) {
- if (mo->iextdef == -1)
- mo->iextdef = sym_index - 1;
- if (mo->iundef != -1)
- tcc_error("external defined symbol after undefined");
- } else if (sym->st_shndx == SHN_UNDEF) {
- if (mo->iundef == -1)
- mo->iundef = sym_index - 1;
- if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK
- || s1->output_type != TCC_OUTPUT_EXE
- || find_elf_sym(s1->dynsymtab_section, name)) {
- /* Mark the symbol as coming from a dylib so that
- relocate_syms doesn't complain. Normally bind_exe_dynsyms
- would do this check, and place the symbol into dynsym
- which is checked by relocate_syms. But Mach-O doesn't use
- bind_exe_dynsyms. */
- sym->st_shndx = SHN_FROMDLL;
- continue;
- }
- tcc_error_noabort("undefined symbol '%s'", name);
- ret = -1;
- }
- }
- return ret;
-}
-
-static void convert_symbol(TCCState *s1, struct macho *mo, struct nlist_64 *pn)
-{
- struct nlist_64 n = *pn;
- ElfSym *sym = (ElfW(Sym) *)symtab_section->data + pn->n_value;
- const char *name = (char*)symtab_section->link->data + sym->st_name;
- switch(ELFW(ST_TYPE)(sym->st_info)) {
- case STT_NOTYPE:
- case STT_OBJECT:
- case STT_FUNC:
- case STT_SECTION:
- n.n_type = N_SECT;
- break;
- case STT_FILE:
- n.n_type = N_ABS;
- break;
- default:
- tcc_error("unhandled ELF symbol type %d %s",
- ELFW(ST_TYPE)(sym->st_info), name);
- }
- if (sym->st_shndx == SHN_UNDEF)
- tcc_error("should have been rewritten to SHN_FROMDLL: %s", name);
- else if (sym->st_shndx == SHN_FROMDLL)
- n.n_type = N_UNDF, n.n_sect = 0;
- else if (sym->st_shndx == SHN_ABS)
- n.n_type = N_ABS, n.n_sect = 0;
- else if (sym->st_shndx >= SHN_LORESERVE)
- tcc_error("unhandled ELF symbol section %d %s", sym->st_shndx, name);
- else if (!mo->elfsectomacho[sym->st_shndx]) {
- if (strncmp(s1->sections[sym->st_shndx]->name, ".debug_", 7))
- tcc_error("ELF section %d(%s) not mapped into Mach-O for symbol %s",
- sym->st_shndx, s1->sections[sym->st_shndx]->name, name);
- }
- else
- n.n_sect = mo->elfsectomacho[sym->st_shndx];
- if (ELFW(ST_BIND)(sym->st_info) == STB_GLOBAL)
- n.n_type |= N_EXT;
- else if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
- n.n_desc |= N_WEAK_REF | (n.n_type != N_UNDF ? N_WEAK_DEF : 0);
- n.n_strx = pn->n_strx;
- n.n_value = sym->st_value;
- *pn = n;
-}
-
-static void convert_symbols(TCCState *s1, struct macho *mo)
-{
- struct nlist_64 *pn;
- for_each_elem(mo->symtab, 0, pn, struct nlist_64)
- convert_symbol(s1, mo, pn);
-}
-
-static int machosymcmp(const void *_a, const void *_b, void *arg)
-{
- TCCState *s1 = arg;
- int ea = ((struct nlist_64 *)_a)->n_value;
- int eb = ((struct nlist_64 *)_b)->n_value;
- ElfSym *sa = (ElfSym *)symtab_section->data + ea;
- ElfSym *sb = (ElfSym *)symtab_section->data + eb;
- int r;
- /* locals, then defined externals, then undefined externals, the
- last two sections also by name, otherwise stable sort */
- r = (ELFW(ST_BIND)(sb->st_info) == STB_LOCAL)
- - (ELFW(ST_BIND)(sa->st_info) == STB_LOCAL);
- if (r)
- return r;
- r = (sa->st_shndx == SHN_UNDEF) - (sb->st_shndx == SHN_UNDEF);
- if (r)
- return r;
- if (ELFW(ST_BIND)(sa->st_info) != STB_LOCAL) {
- const char * na = (char*)symtab_section->link->data + sa->st_name;
- const char * nb = (char*)symtab_section->link->data + sb->st_name;
- r = strcmp(na, nb);
- if (r)
- return r;
- }
- return ea - eb;
-}
-
-/* cannot use qsort because code has to be reentrant */
-static void tcc_qsort (void *base, size_t nel, size_t width,
- int (*comp)(const void *, const void *, void *), void *arg)
-{
- size_t wnel, gap, wgap, i, j, k;
- char *a, *b, tmp;
-
- wnel = width * nel;
- for (gap = 0; ++gap < nel;)
- gap *= 3;
- while ( gap /= 3 ) {
- wgap = width * gap;
- for (i = wgap; i < wnel; i += width) {
- for (j = i - wgap; ;j -= wgap) {
- a = j + (char *)base;
- b = a + wgap;
- if ( (*comp)(a, b, arg) <= 0 )
- break;
- k = width;
- do {
- tmp = *a;
- *a++ = *b;
- *b++ = tmp;
- } while ( --k );
- if (j < wgap)
- break;
- }
- }
- }
-}
-
-static void create_symtab(TCCState *s1, struct macho *mo)
-{
- int sym_index, sym_end;
- struct nlist_64 *pn;
-
- /* Stub creation belongs to check_relocs, but we need to create
- the symbol now, so its included in the sorting. */
- mo->stubs = new_section(s1, "__stubs", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
- s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
- mo->stubsym = put_elf_sym(s1->symtab, 0, 0,
- ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
- mo->stubs->sh_num, ".__stubs");
-#ifdef CONFIG_NEW_MACHO
- mo->chained_fixups = new_section(s1, "CHAINED_FIXUPS",
- SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
-#else
- mo->stub_helper = new_section(s1, "__stub_helper", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
- mo->la_symbol_ptr = new_section(s1, "__la_symbol_ptr", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
- mo->helpsym = put_elf_sym(s1->symtab, 0, 0,
- ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
- mo->stub_helper->sh_num, ".__stub_helper");
- mo->lasym = put_elf_sym(s1->symtab, 0, 0,
- ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
- mo->la_symbol_ptr->sh_num, ".__la_symbol_ptr");
- section_ptr_add(data_section, -data_section->data_offset & (PTR_SIZE - 1));
- mo->dyld_private = put_elf_sym(s1->symtab, data_section->data_offset, PTR_SIZE,
- ELFW(ST_INFO)(STB_LOCAL, STT_OBJECT), 0,
- data_section->sh_num, ".__dyld_private");
- section_ptr_add(data_section, PTR_SIZE);
- mo->dyld_stub_binder = put_elf_sym(s1->symtab, 0, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), 0,
- SHN_UNDEF, "dyld_stub_binder");
- mo->rebase = new_section(s1, "REBASE", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
- mo->binding = new_section(s1, "BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
- mo->weak_binding = new_section(s1, "WEAK_BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
- mo->lazy_binding = new_section(s1, "LAZY_BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
-#endif
- mo->exports = new_section(s1, "EXPORT", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
- mo->indirsyms = new_section(s1, "LEINDIR", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
-
- mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
- mo->strtab = new_section(s1, "LESTRTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
- put_elf_str(mo->strtab, " "); /* Mach-O starts strtab with a space */
- sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
- pn = section_ptr_add(mo->symtab, sizeof(*pn) * (sym_end - 1));
- for (sym_index = 1; sym_index < sym_end; ++sym_index) {
- ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
- const char *name = (char*)symtab_section->link->data + sym->st_name;
- pn[sym_index - 1].n_strx = put_elf_str(mo->strtab, name);
- pn[sym_index - 1].n_value = sym_index;
- }
- section_ptr_add(mo->strtab, -mo->strtab->data_offset & (PTR_SIZE - 1));
- tcc_qsort(pn, sym_end - 1, sizeof(*pn), machosymcmp, s1);
- mo->e2msym = tcc_malloc(sym_end * sizeof(*mo->e2msym));
- mo->e2msym[0] = -1;
- for (sym_index = 1; sym_index < sym_end; ++sym_index) {
- mo->e2msym[pn[sym_index - 1].n_value] = sym_index - 1;
- }
-}
-
-const struct {
- int seg_initial;
- uint32_t flags;
- const char *name;
-} skinfo[sk_last] = {
- /*[sk_unknown] =*/ { 0 },
- /*[sk_discard] =*/ { 0 },
- /*[sk_text] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS
- | S_ATTR_SOME_INSTRUCTIONS, "__text" },
- /*[sk_stubs] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_SYMBOL_STUBS
- | S_ATTR_SOME_INSTRUCTIONS , "__stubs" },
- /*[sk_stub_helper] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS
- | S_ATTR_SOME_INSTRUCTIONS , "__stub_helper" },
- /*[sk_ro_data] =*/ { 2, S_REGULAR, "__rodata" },
- /*[sk_uw_info] =*/ { 0 },
- /*[sk_nl_ptr] =*/ { 2, S_NON_LAZY_SYMBOL_POINTERS, "__got" },
- /*[sk_debug_info] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_info" },
- /*[sk_debug_abbrev] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_abbrev" },
- /*[sk_debug_line] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_line" },
- /*[sk_debug_aranges] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_aranges" },
- /*[sk_debug_str] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_str" },
- /*[sk_debug_line_str] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_line_str" },
- /*[sk_stab] =*/ { 4, S_REGULAR, "__stab" },
- /*[sk_stab_str] =*/ { 4, S_REGULAR, "__stab_str" },
- /*[sk_la_ptr] =*/ { 4, S_LAZY_SYMBOL_POINTERS, "__la_symbol_ptr" },
- /*[sk_init] =*/ { 4, S_MOD_INIT_FUNC_POINTERS, "__mod_init_func" },
- /*[sk_fini] =*/ { 4, S_MOD_TERM_FUNC_POINTERS, "__mod_term_func" },
- /*[sk_rw_data] =*/ { 4, S_REGULAR, "__data" },
- /*[sk_bss] =*/ { 4, S_ZEROFILL, "__bss" },
- /*[sk_linkedit] =*/ { 5, S_REGULAR, NULL },
-};
-
-#define START ((uint64_t)1 << 32)
-
-const struct {
- int used;
- const char *name;
- uint64_t vmaddr;
- uint64_t vmsize;
- vm_prot_t maxprot;
- vm_prot_t initprot;
- uint32_t flags;
-} all_segment[] = {
- { 1, "__PAGEZERO", 0, START, 0, 0, 0 },
- { 0, "__TEXT", START, 0, 5, 5, 0 },
- { 0, "__DATA_CONST", -1, 0, 3, 3, SG_READ_ONLY },
- { 0, "__DWARF", -1, 0, 7, 3, 0 },
- { 0, "__DATA", -1, 0, 3, 3, 0 },
- { 1, "__LINKEDIT", -1, 0, 1, 1, 0 },
-};
-
-#define N_SEGMENT (sizeof(all_segment)/sizeof(all_segment[0]))
-
-#ifdef CONFIG_NEW_MACHO
-static void calc_fixup_size(TCCState *s1, struct macho *mo)
-{
- int i, size;
-
- size = (sizeof(struct dyld_chained_fixups_header) + 7) & -8;
- size += (sizeof(struct dyld_chained_starts_in_image) + (mo->nseg - 1) * sizeof(uint32_t) + 7) & -8;
- for (i = (s1->output_type == TCC_OUTPUT_EXE); i < mo->nseg - 1; i++) {
- int page_count = (get_segment(mo, i)->vmsize + SEG_PAGE_SIZE - 1) / SEG_PAGE_SIZE;
- size += (sizeof(struct dyld_chained_starts_in_segment) + (page_count - 1) * sizeof(uint16_t) + 7) & -8;
- }
- size += mo->n_bind * sizeof (struct dyld_chained_import) + 1;
- for (i = 0; i < mo->n_bind_rebase; i++) {
- if (mo->bind_rebase[i].bind) {
- int sym_index = ELFW(R_SYM)(mo->bind_rebase[i].rel.r_info);
- ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
- const char *name = (char *) symtab_section->link->data + sym->st_name;
- size += strlen(name) + 1;
- }
- }
- size = (size + 7) & -8;
- section_ptr_add(mo->chained_fixups, size);
-}
-
-#else
-
-static void set_segment_and_offset(TCCState *s1, struct macho *mo, addr_t addr,
- uint8_t *ptr, int opcode,
- Section *sec, addr_t offset)
-{
- int i;
- struct segment_command_64 *seg = NULL;
-
- for (i = (s1->output_type == TCC_OUTPUT_EXE); i < mo->nseg - 1; i++) {
- seg = get_segment(mo, i);
- if (addr >= seg->vmaddr && addr < (seg->vmaddr + seg->vmsize))
- break;
- }
- *ptr = opcode | i;
- write_uleb128(sec, offset - seg->vmaddr);
-}
-
-static void bind_rebase(TCCState *s1, struct macho *mo)
-{
- int i;
- uint8_t *ptr;
- ElfW(Sym) *sym;
- const char *name;
-
- for (i = 0; i < mo->n_lazy_bind; i++) {
- int sym_index = ELFW(R_SYM)(mo->s_lazy_bind[i].rel.r_info);
-
- sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
- name = (char *) symtab_section->link->data + sym->st_name;
- write32le(mo->stub_helper->data +
- mo->s_lazy_bind[i].bind_offset,
- mo->lazy_binding->data_offset);
- ptr = section_ptr_add(mo->lazy_binding, 1);
- set_segment_and_offset(s1, mo, mo->la_symbol_ptr->sh_addr, ptr,
- BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB,
- mo->lazy_binding,
- mo->s_lazy_bind[i].la_symbol_offset +
- mo->la_symbol_ptr->sh_addr);
- ptr = section_ptr_add(mo->lazy_binding, 5 + strlen(name));
- *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM |
- (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf);
- *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | 0;
- strcpy((char *)ptr, name);
- ptr += strlen(name) + 1;
- *ptr++ = BIND_OPCODE_DO_BIND;
- *ptr = BIND_OPCODE_DONE;
- }
- for (i = 0; i < mo->n_rebase; i++) {
- Section *s = s1->sections[mo->s_rebase[i].section];
-
- ptr = section_ptr_add(mo->rebase, 2);
- *ptr++ = REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER;
- set_segment_and_offset(s1, mo, s->sh_addr, ptr,
- REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB,
- mo->rebase,
- mo->s_rebase[i].rel.r_offset +
- s->sh_addr);
- ptr = section_ptr_add(mo->rebase, 1);
- *ptr = REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1;
- }
- for (i = 0; i < mo->n_bind; i++) {
- int sym_index = ELFW(R_SYM)(mo->bind[i].rel.r_info);
- Section *s = s1->sections[mo->bind[i].section];
- Section *binding;
-
- sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
- name = (char *) symtab_section->link->data + sym->st_name;
- binding = ELFW(ST_BIND)(sym->st_info) == STB_WEAK
- ? mo->weak_binding : mo->binding;
- ptr = section_ptr_add(binding, 4 + (binding == mo->binding) +
- strlen(name));
- if (binding == mo->binding)
- *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM |
- (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf);
- *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM |
- (binding == mo->weak_binding
- ? BIND_SYMBOL_FLAGS_WEAK_IMPORT : 0);
- strcpy((char *)ptr, name);
- ptr += strlen(name) + 1;
- *ptr++ = BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER;
- set_segment_and_offset(s1, mo, s->sh_addr, ptr,
- BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB,
- binding,
- mo->bind[i].rel.r_offset + s->sh_addr);
- ptr = section_ptr_add(binding, 1);
- *ptr++ = BIND_OPCODE_DO_BIND;
- }
- if (mo->rebase->data_offset) {
- ptr = section_ptr_add(mo->rebase, 1);
- *ptr = REBASE_OPCODE_DONE;
- }
- if (mo->binding->data_offset) {
- ptr = section_ptr_add(mo->binding, 1);
- *ptr = BIND_OPCODE_DONE;
- }
- if (mo->weak_binding->data_offset) {
- ptr = section_ptr_add(mo->weak_binding, 1);
- *ptr = BIND_OPCODE_DONE;
- }
- tcc_free(mo->s_lazy_bind);
- tcc_free(mo->s_rebase);
- tcc_free(mo->bind);
-}
-#endif
-
-struct trie_info {
- const char *name;
- int flag;
- addr_t addr;
- int str_size;
- int term_size;
-};
-
-struct trie_node {
- int start;
- int end;
- int index_start;
- int index_end;
- int n_child;
- struct trie_node *child;
-};
-
-struct trie_seq {
- int n_child;
- struct trie_node *node;
- int offset;
- int nest_offset;
-};
-
-static void create_trie(struct trie_node *node,
- int from, int to, int index_start,
- int n_trie, struct trie_info *trie)
-{
- int i;
- int start, end, index_end;
- char cur;
- struct trie_node *child;
-
- for (i = from; i < to; i = end) {
- cur = trie[i].name[index_start];
- start = i++;
- for (; i < to; i++)
- if (cur != trie[i].name[index_start])
- break;
- end = i;
- if (start == end - 1 ||
- (trie[start].name[index_start] &&
- trie[start].name[index_start + 1] == 0))
- index_end = trie[start].str_size - 1;
- else {
- index_end = index_start + 1;
- for (;;) {
- cur = trie[start].name[index_end];
- for (i = start + 1; i < end; i++)
- if (cur != trie[i].name[index_end])
- break;
- if (trie[start].name[index_end] &&
- trie[start].name[index_end + 1] == 0) {
- end = start + 1;
- index_end = trie[start].str_size - 1;
- break;
- }
- if (i != end)
- break;
- index_end++;
- }
- }
- node->child = tcc_realloc(node->child,
- (node->n_child + 1) *
- sizeof(struct trie_node));
- child = &node->child[node->n_child];
- child->start = start;
- child->end = end;
- child->index_start = index_start;
- child->index_end = index_end;
- child->n_child = 0;
- child->child = NULL;
- node->n_child++;
- if (start != end - 1)
- create_trie(child, start, end, index_end, n_trie, trie);
- }
-}
-
-static int create_seq(int *offset, int *n_seq, struct trie_seq **seq,
- struct trie_node *node,
- int n_trie, struct trie_info *trie)
-{
- int i, nest_offset, last_seq = *n_seq, retval = *offset;
- struct trie_seq *p_seq;
- struct trie_node *p_nest;
-
- for (i = 0; i < node->n_child; i++) {
- p_nest = &node->child[i];
- *seq = tcc_realloc(*seq, (*n_seq + 1) * sizeof(struct trie_seq));
- p_seq = &(*seq)[(*n_seq)++];
- p_seq->n_child = i == 0 ? node->n_child : -1;
- p_seq->node = p_nest;
- p_seq->offset = *offset;
- p_seq->nest_offset = 0;
- *offset += (i == 0 ? 1 + 1 : 0) +
- p_nest->index_end - p_nest->index_start + 1 + 3;
- }
- for (i = 0; i < node->n_child; i++) {
- nest_offset =
- create_seq(offset, n_seq, seq, &node->child[i], n_trie, trie);
- p_seq = &(*seq)[last_seq + i];
- p_seq->nest_offset = nest_offset;
- }
- return retval;
-}
-
-static void node_free(struct trie_node *node)
-{
- int i;
-
- for (i = 0; i < node->n_child; i++)
- node_free(&node->child[i]);
- tcc_free(node->child);
-}
-
-static int triecmp(const void *_a, const void *_b, void *arg)
-{
- struct trie_info *a = (struct trie_info *) _a;
- struct trie_info *b = (struct trie_info *) _b;
- int len_a = strlen(a->name);
- int len_b = strlen(b->name);
-
- /* strange sorting needed. Name 'xx' should be after 'xx1' */
- if (!strncmp(a->name, b->name, len_a < len_b ? len_a : len_b))
- return len_a < len_b ? 1 : (len_a > len_b ? -1 : 0);
- return strcmp(a->name, b->name);
-}
-
-static void export_trie(TCCState *s1, struct macho *mo)
-{
- int i, size, offset = 0, save_offset;
- uint8_t *ptr;
- int sym_index;
- int sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
- int n_trie = 0, n_seq = 0;
- struct trie_info *trie = NULL, *p_trie;
- struct trie_node node, *p_node;
- struct trie_seq *seq = NULL;
- addr_t vm_addr = get_segment(mo, s1->output_type == TCC_OUTPUT_EXE)->vmaddr;
-
- for (sym_index = 1; sym_index < sym_end; ++sym_index) {
- ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
- const char *name = (char*)symtab_section->link->data + sym->st_name;
-
- if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE &&
- (ELFW(ST_BIND)(sym->st_info) == STB_GLOBAL ||
- ELFW(ST_BIND)(sym->st_info) == STB_WEAK)) {
- int flag = EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
- addr_t addr =
- sym->st_value + s1->sections[sym->st_shndx]->sh_addr - vm_addr;
-
- if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
- flag |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
- dprintf ("%s %d %llx\n", name, flag, (long long)addr + vm_addr);
- trie = tcc_realloc(trie, (n_trie + 1) * sizeof(struct trie_info));
- trie[n_trie].name = name;
- trie[n_trie].flag = flag;
- trie[n_trie].addr = addr;
- trie[n_trie].str_size = strlen(name) + 1;
- trie[n_trie].term_size = uleb128_size(flag) + uleb128_size(addr);
- n_trie++;
- }
- }
- if (n_trie) {
- tcc_qsort(trie, n_trie, sizeof(struct trie_info), triecmp, NULL);
- memset(&node, 0, sizeof(node));
- create_trie(&node, 0, n_trie, 0, n_trie, trie);
- create_seq(&offset, &n_seq, &seq, &node, n_trie, trie);
- save_offset = offset;
- for (i = 0; i < n_seq; i++) {
- p_node = seq[i].node;
- if (p_node->n_child == 0) {
- p_trie = &trie[p_node->start];
- seq[i].nest_offset = offset;
- offset += 1 + p_trie->term_size + 1;
- }
- }
- for (i = 0; i < n_seq; i++) {
- p_node = seq[i].node;
- p_trie = &trie[p_node->start];
- if (seq[i].n_child >= 0) {
- section_ptr_add(mo->exports,
- seq[i].offset - mo->exports->data_offset);
- ptr = section_ptr_add(mo->exports, 2);
- *ptr++ = 0;
- *ptr = seq[i].n_child;
- }
- size = p_node->index_end - p_node->index_start;
- ptr = section_ptr_add(mo->exports, size + 1);
- memcpy(ptr, &p_trie->name[p_node->index_start], size);
- ptr[size] = 0;
- write_uleb128(mo->exports, seq[i].nest_offset);
- }
- section_ptr_add(mo->exports, save_offset - mo->exports->data_offset);
- for (i = 0; i < n_seq; i++) {
- p_node = seq[i].node;
- if (p_node->n_child == 0) {
- p_trie = &trie[p_node->start];
- write_uleb128(mo->exports, p_trie->term_size);
- write_uleb128(mo->exports, p_trie->flag);
- write_uleb128(mo->exports, p_trie->addr);
- ptr = section_ptr_add(mo->exports, 1);
- *ptr = 0;
- }
- }
- section_ptr_add(mo->exports, -mo->exports->data_offset & 7);
- node_free(&node);
- tcc_free(seq);
- }
- tcc_free(trie);
-}
-
-static void collect_sections(TCCState *s1, struct macho *mo, const char *filename)
-{
- int i, sk, numsec;
- int used_segment[N_SEGMENT];
- uint64_t curaddr, fileofs;
- Section *s;
- struct segment_command_64 *seg;
- struct dylib_command *dylib;
-#ifdef CONFIG_NEW_MACHO
- struct linkedit_data_command *chained_fixups_lc;
- struct linkedit_data_command *export_trie_lc;
-#endif
- struct build_version_command *dyldbv;
- struct source_version_command *dyldsv;
- struct rpath_command *rpath;
- struct dylinker_command *dyldlc;
- struct symtab_command *symlc;
- struct dysymtab_command *dysymlc;
- char *str;
-
- for (i = 0; i < N_SEGMENT; i++)
- used_segment[i] = all_segment[i].used;
-
- memset (mo->sk_to_sect, 0, sizeof(mo->sk_to_sect));
- for (i = s1->nb_sections; i-- > 1;) {
- int type, flags;
- s = s1->sections[i];
- type = s->sh_type;
- flags = s->sh_flags;
- sk = sk_unknown;
- /* debug sections have sometimes no SHF_ALLOC */
- if ((flags & SHF_ALLOC) || !strncmp(s->name, ".debug_", 7)) {
- switch (type) {
- default: sk = sk_unknown; break;
- case SHT_INIT_ARRAY: sk = sk_init; break;
- case SHT_FINI_ARRAY: sk = sk_fini; break;
- case SHT_NOBITS: sk = sk_bss; break;
- case SHT_SYMTAB: sk = sk_discard; break;
- case SHT_STRTAB:
- if (s == stabstr_section)
- sk = sk_stab_str;
- else
- sk = sk_discard;
- break;
- case SHT_RELX: sk = sk_discard; break;
- case SHT_LINKEDIT: sk = sk_linkedit; break;
- case SHT_PROGBITS:
- if (s == mo->stubs)
- sk = sk_stubs;
-#ifndef CONFIG_NEW_MACHO
- else if (s == mo->stub_helper)
- sk = sk_stub_helper;
- else if (s == mo->la_symbol_ptr)
- sk = sk_la_ptr;
-#endif
- else if (s == rodata_section)
- sk = sk_ro_data;
- else if (s == s1->got)
- sk = sk_nl_ptr;
- else if (s == stab_section)
- sk = sk_stab;
- else if (s == dwarf_info_section)
- sk = sk_debug_info;
- else if (s == dwarf_abbrev_section)
- sk = sk_debug_abbrev;
- else if (s == dwarf_line_section)
- sk = sk_debug_line;
- else if (s == dwarf_aranges_section)
- sk = sk_debug_aranges;
- else if (s == dwarf_str_section)
- sk = sk_debug_str;
- else if (s == dwarf_line_str_section)
- sk = sk_debug_line_str;
- else if (flags & SHF_EXECINSTR)
- sk = sk_text;
- else if (flags & SHF_WRITE)
- sk = sk_rw_data;
- else
- sk = sk_ro_data;
- break;
- }
- } else
- sk = sk_discard;
- s->prev = mo->sk_to_sect[sk].s;
- mo->sk_to_sect[sk].s = s;
- used_segment[skinfo[sk].seg_initial] = 1;
- }
-
- if (s1->output_type != TCC_OUTPUT_EXE)
- used_segment[0] = 0;
-
- for (i = 0; i < N_SEGMENT; i++)
- if (used_segment[i]) {
- seg = add_segment(mo, all_segment[i].name);
- if (i == 1 && s1->output_type != TCC_OUTPUT_EXE)
- seg->vmaddr = 0;
- else
- seg->vmaddr = all_segment[i].vmaddr;
- seg->vmsize = all_segment[i].vmsize;
- seg->maxprot = all_segment[i].maxprot;
- seg->initprot = all_segment[i].initprot;
- seg->flags = all_segment[i].flags;
- for (sk = sk_unknown; sk < sk_last; sk++)
- if (skinfo[sk].seg_initial == i)
- mo->segment[sk] = mo->nseg - 1;
- }
-
- if (s1->output_type != TCC_OUTPUT_EXE) {
- const char *name = s1->install_name ? s1->install_name : filename;
- i = (sizeof(*dylib) + strlen(name) + 1 + 7) &-8;
- dylib = add_lc(mo, LC_ID_DYLIB, i);
- dylib->name = sizeof(*dylib);
- dylib->timestamp = 1;
- dylib->current_version =
- s1->current_version ? s1->current_version : 1 << 16;
- dylib->compatibility_version =
- s1->compatibility_version ? s1->compatibility_version : 1 << 16;
- str = (char*)dylib + dylib->name;
- strcpy(str, name);
- }
-
-#ifdef CONFIG_NEW_MACHO
- chained_fixups_lc = add_lc(mo, LC_DYLD_CHAINED_FIXUPS,
- sizeof(struct linkedit_data_command));
- export_trie_lc = add_lc(mo, LC_DYLD_EXPORTS_TRIE,
- sizeof(struct linkedit_data_command));
-#else
- mo->dyldinfo = add_lc(mo, LC_DYLD_INFO_ONLY, sizeof(*mo->dyldinfo));
-#endif
-
- symlc = add_lc(mo, LC_SYMTAB, sizeof(*symlc));
- dysymlc = add_lc(mo, LC_DYSYMTAB, sizeof(*dysymlc));
-
- if (s1->output_type == TCC_OUTPUT_EXE) {
- i = (sizeof(*dyldlc) + strlen("/usr/lib/dyld") + 1 + 7) &-8;
- dyldlc = add_lc(mo, LC_LOAD_DYLINKER, i);
- dyldlc->name = sizeof(*dyldlc);
- str = (char*)dyldlc + dyldlc->name;
- strcpy(str, "/usr/lib/dyld");
- }
-
- dyldbv = add_lc(mo, LC_BUILD_VERSION, sizeof(*dyldbv));
- dyldbv->platform = PLATFORM_MACOS;
- dyldbv->minos = (10 << 16) + (6 << 8);
- dyldbv->sdk = (10 << 16) + (6 << 8);
- dyldbv->ntools = 0;
-
- dyldsv = add_lc(mo, LC_SOURCE_VERSION, sizeof(*dyldsv));
- dyldsv->version = 0;
-
- if (s1->output_type == TCC_OUTPUT_EXE) {
- mo->ep = add_lc(mo, LC_MAIN, sizeof(*mo->ep));
- mo->ep->entryoff = 4096;
- }
-
- for(i = 0; i < s1->nb_loaded_dlls; i++) {
- DLLReference *dllref = s1->loaded_dlls[i];
- if (dllref->level == 0)
- add_dylib(mo, dllref->name);
- }
-
- if (s1->rpath) {
- char *path = s1->rpath, *end;
- do {
- end = strchr(path, ':');
- if (!end)
- end = strchr(path, 0);
- i = (sizeof(*rpath) + (end - path) + 1 + 7) &-8;
- rpath = add_lc(mo, LC_RPATH, i);
- rpath->path = sizeof(*rpath);
- str = (char*)rpath + rpath->path;
- memcpy(str, path, end - path);
- str[end - path] = 0;
- path = end + 1;
- } while (*end);
- }
-
- fileofs = 4096; /* leave space for mach-o headers */
- curaddr = get_segment(mo, s1->output_type == TCC_OUTPUT_EXE)->vmaddr;
- curaddr += 4096;
- seg = NULL;
- numsec = 0;
- mo->elfsectomacho = tcc_mallocz(sizeof(*mo->elfsectomacho) * s1->nb_sections);
- for (sk = sk_unknown; sk < sk_last; sk++) {
- struct section_64 *sec = NULL;
- if (seg) {
- seg->vmsize = curaddr - seg->vmaddr;
- seg->filesize = fileofs - seg->fileoff;
- }
-#ifdef CONFIG_NEW_MACHO
- if (sk == sk_linkedit) {
- calc_fixup_size(s1, mo);
- export_trie(s1, mo);
- }
-#else
- if (sk == sk_linkedit) {
- bind_rebase(s1, mo);
- export_trie(s1, mo);
- }
-#endif
- if (skinfo[sk].seg_initial &&
- (s1->output_type != TCC_OUTPUT_EXE || mo->segment[sk]) &&
- mo->sk_to_sect[sk].s) {
- uint64_t al = 0;
- int si;
- seg = get_segment(mo, mo->segment[sk]);
- if (skinfo[sk].name) {
- si = add_section(mo, &seg, skinfo[sk].name);
- numsec++;
- mo->lc[mo->seg2lc[mo->segment[sk]]] = (struct load_command*)seg;
- mo->sk_to_sect[sk].machosect = si;
- sec = get_section(seg, si);
- sec->flags = skinfo[sk].flags;
- if (sk == sk_stubs)
-#ifdef TCC_TARGET_X86_64
- sec->reserved2 = 6;
-#elif defined TCC_TARGET_ARM64
- sec->reserved2 = 12;
-#endif
- if (sk == sk_nl_ptr)
- sec->reserved1 = mo->nr_plt;
-#ifndef CONFIG_NEW_MACHO
- if (sk == sk_la_ptr)
- sec->reserved1 = mo->nr_plt + mo->n_got;
-#endif
- }
- if (seg->vmaddr == -1) {
- curaddr = (curaddr + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE;
- seg->vmaddr = curaddr;
- fileofs = (fileofs + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE;
- seg->fileoff = fileofs;
- }
-
- for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
- int a = exact_log2p1(s->sh_addralign);
- if (a && al < (a - 1))
- al = a - 1;
- s->sh_size = s->data_offset;
- }
- if (sec)
- sec->align = al;
- al = 1ULL << al;
- if (al > 4096)
- tcc_warning("alignment > 4096"), sec->align = 12, al = 4096;
- curaddr = (curaddr + al - 1) & -al;
- fileofs = (fileofs + al - 1) & -al;
- if (sec) {
- sec->addr = curaddr;
- sec->offset = fileofs;
- }
- for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
- al = s->sh_addralign;
- curaddr = (curaddr + al - 1) & -al;
- dprintf("%s: curaddr now 0x%lx\n", s->name, (long)curaddr);
- s->sh_addr = curaddr;
- curaddr += s->sh_size;
- if (s->sh_type != SHT_NOBITS) {
- fileofs = (fileofs + al - 1) & -al;
- s->sh_offset = fileofs;
- fileofs += s->sh_size;
- dprintf("%s: fileofs now %ld\n", s->name, (long)fileofs);
- }
- if (sec)
- mo->elfsectomacho[s->sh_num] = numsec;
- }
- if (sec)
- sec->size = curaddr - sec->addr;
- }
- if (DEBUG_MACHO)
- for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
- int type = s->sh_type;
- int flags = s->sh_flags;
- printf("%d section %-16s %-10s %09lx %04x %02d %s,%s,%s\n",
- sk,
- s->name,
- type == SHT_PROGBITS ? "progbits" :
- type == SHT_NOBITS ? "nobits" :
- type == SHT_SYMTAB ? "symtab" :
- type == SHT_STRTAB ? "strtab" :
- type == SHT_INIT_ARRAY ? "init" :
- type == SHT_FINI_ARRAY ? "fini" :
- type == SHT_RELX ? "rel" : "???",
- (long)s->sh_addr,
- (unsigned)s->data_offset,
- s->sh_addralign,
- flags & SHF_ALLOC ? "alloc" : "",
- flags & SHF_WRITE ? "write" : "",
- flags & SHF_EXECINSTR ? "exec" : ""
- );
- }
- }
- if (seg) {
- seg->vmsize = curaddr - seg->vmaddr;
- seg->filesize = fileofs - seg->fileoff;
- }
-
- /* Fill symtab info */
- symlc->symoff = mo->symtab->sh_offset;
- symlc->nsyms = mo->symtab->data_offset / sizeof(struct nlist_64);
- symlc->stroff = mo->strtab->sh_offset;
- symlc->strsize = mo->strtab->data_offset;
-
- dysymlc->iundefsym = mo->iundef == -1 ? symlc->nsyms : mo->iundef;
- dysymlc->iextdefsym = mo->iextdef == -1 ? dysymlc->iundefsym : mo->iextdef;
- dysymlc->ilocalsym = mo->ilocal == -1 ? dysymlc->iextdefsym : mo->ilocal;
- dysymlc->nlocalsym = dysymlc->iextdefsym - dysymlc->ilocalsym;
- dysymlc->nextdefsym = dysymlc->iundefsym - dysymlc->iextdefsym;
- dysymlc->nundefsym = symlc->nsyms - dysymlc->iundefsym;
- dysymlc->indirectsymoff = mo->indirsyms->sh_offset;
- dysymlc->nindirectsyms = mo->indirsyms->data_offset / sizeof(uint32_t);
-
-#ifdef CONFIG_NEW_MACHO
- if (mo->chained_fixups->data_offset) {
- chained_fixups_lc->dataoff = mo->chained_fixups->sh_offset;
- chained_fixups_lc->datasize = mo->chained_fixups->data_offset;
- }
- if (mo->exports->data_offset) {
- export_trie_lc->dataoff = mo->exports->sh_offset;
- export_trie_lc->datasize = mo->exports->data_offset;
- }
-#else
- if (mo->rebase->data_offset) {
- mo->dyldinfo->rebase_off = mo->rebase->sh_offset;
- mo->dyldinfo->rebase_size = mo->rebase->data_offset;
- }
- if (mo->binding->data_offset) {
- mo->dyldinfo->bind_off = mo->binding->sh_offset;
- mo->dyldinfo->bind_size = mo->binding->data_offset;
- }
- if (mo->weak_binding->data_offset) {
- mo->dyldinfo->weak_bind_off = mo->weak_binding->sh_offset;
- mo->dyldinfo->weak_bind_size = mo->weak_binding->data_offset;
- }
- if (mo->lazy_binding->data_offset) {
- mo->dyldinfo->lazy_bind_off = mo->lazy_binding->sh_offset;
- mo->dyldinfo->lazy_bind_size = mo->lazy_binding->data_offset;
- }
- if (mo->exports->data_offset) {
- mo->dyldinfo->export_off = mo->exports->sh_offset;
- mo->dyldinfo->export_size = mo->exports->data_offset;
- }
-#endif
-}
-
-static void macho_write(TCCState *s1, struct macho *mo, FILE *fp)
-{
- int i, sk;
- uint64_t fileofs = 0;
- Section *s;
- mo->mh.mh.magic = MH_MAGIC_64;
-#ifdef TCC_TARGET_X86_64
- mo->mh.mh.cputype = CPU_TYPE_X86_64;
- mo->mh.mh.cpusubtype = CPU_SUBTYPE_LIB64 | CPU_SUBTYPE_X86_ALL;
-#elif defined TCC_TARGET_ARM64
- mo->mh.mh.cputype = CPU_TYPE_ARM64;
- mo->mh.mh.cpusubtype = CPU_SUBTYPE_ARM64_ALL;
-#endif
- if (s1->output_type == TCC_OUTPUT_EXE) {
- mo->mh.mh.filetype = MH_EXECUTE;
- mo->mh.mh.flags = MH_DYLDLINK | MH_PIE;
- }
- else {
- mo->mh.mh.filetype = MH_DYLIB;
- mo->mh.mh.flags = MH_DYLDLINK;
- }
- mo->mh.mh.ncmds = mo->nlc;
- mo->mh.mh.sizeofcmds = 0;
- for (i = 0; i < mo->nlc; i++)
- mo->mh.mh.sizeofcmds += mo->lc[i]->cmdsize;
-
- fwrite(&mo->mh, 1, sizeof(mo->mh), fp);
- fileofs += sizeof(mo->mh);
- for (i = 0; i < mo->nlc; i++) {
- fwrite(mo->lc[i], 1, mo->lc[i]->cmdsize, fp);
- fileofs += mo->lc[i]->cmdsize;
- }
-
- for (sk = sk_unknown; sk < sk_last; sk++) {
- //struct segment_command_64 *seg;
- if (skinfo[sk].seg_initial == 0 ||
- (s1->output_type == TCC_OUTPUT_EXE && !mo->segment[sk]) ||
- !mo->sk_to_sect[sk].s)
- continue;
- /*seg =*/ get_segment(mo, mo->segment[sk]);
- for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
- if (s->sh_type != SHT_NOBITS) {
- while (fileofs < s->sh_offset)
- fputc(0, fp), fileofs++;
- if (s->sh_size) {
- fwrite(s->data, 1, s->sh_size, fp);
- fileofs += s->sh_size;
- }
- }
- }
- }
-}
-
-#ifdef CONFIG_NEW_MACHO
-static int bind_rebase_cmp(const void *_a, const void *_b, void *arg)
-{
- TCCState *s1 = arg;
- struct bind_rebase *a = (struct bind_rebase *) _a;
- struct bind_rebase *b = (struct bind_rebase *) _b;
- addr_t aa = s1->sections[a->section]->sh_addr + a->rel.r_offset;
- addr_t ab = s1->sections[b->section]->sh_addr + b->rel.r_offset;
-
- return aa > ab ? 1 : aa < ab ? -1 : 0;
-}
-
-ST_FUNC void bind_rebase_import(TCCState *s1, struct macho *mo)
-{
- int i, j, k, bind_index, size, page_count, sym_index;
- const char *name;
- ElfW(Sym) *sym;
- unsigned char *data = mo->chained_fixups->data;
- struct segment_command_64 *seg;
- struct dyld_chained_fixups_header *header;
- struct dyld_chained_starts_in_image *image;
- struct dyld_chained_starts_in_segment *segment;
- struct dyld_chained_import *import;
-
- tcc_qsort(mo->bind_rebase, mo->n_bind_rebase, sizeof(struct bind_rebase),
- bind_rebase_cmp, s1);
- for (i = 0; i < mo->n_bind_rebase - 1; i++)
- if (mo->bind_rebase[i].section == mo->bind_rebase[i + 1].section &&
- mo->bind_rebase[i].rel.r_offset == mo->bind_rebase[i + 1].rel.r_offset) {
- sym_index = ELFW(R_SYM)(mo->bind_rebase[i].rel.r_info);
- sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
- name = (char *) symtab_section->link->data + sym->st_name;
- tcc_error("Overlap %s/%s %s:%s",
- mo->bind_rebase[i].bind ? "bind" : "rebase",
- mo->bind_rebase[i + 1].bind ? "bind" : "rebase",
- s1->sections[mo->bind_rebase[i].section]->name, name);
- }
- header = (struct dyld_chained_fixups_header *) data;
- data += (sizeof(struct dyld_chained_fixups_header) + 7) & -8;
- header->starts_offset = data - mo->chained_fixups->data;
- header->imports_count = mo->n_bind;
- header->imports_format = DYLD_CHAINED_IMPORT;
- header->symbols_format = 0;
- size = sizeof(struct dyld_chained_starts_in_image) +
- (mo->nseg - 1) * sizeof(uint32_t);
- image = (struct dyld_chained_starts_in_image *) data;
- data += (size + 7) & -8;
- image->seg_count = mo->nseg;
- for (i = (s1->output_type == TCC_OUTPUT_EXE); i < mo->nseg - 1; i++) {
- image->seg_info_offset[i] = (data - mo->chained_fixups->data) -
- header->starts_offset;
- seg = get_segment(mo, i);
- page_count = (seg->vmsize + SEG_PAGE_SIZE - 1) / SEG_PAGE_SIZE;
- size = sizeof(struct dyld_chained_starts_in_segment) +
- (page_count - 1) * sizeof(uint16_t);
- segment = (struct dyld_chained_starts_in_segment *) data;
- data += (size + 7) & -8;
- segment->size = size;
- segment->page_size = SEG_PAGE_SIZE;
-#if 1
-#define PTR_64_OFFSET 0
-#define PTR_64_MASK 0x7FFFFFFFFFFULL
- segment->pointer_format = DYLD_CHAINED_PTR_64;
-#else
-#define PTR_64_OFFSET 0x100000000ULL
-#define PTR_64_MASK 0xFFFFFFFFFFFFFFULL
- segment->pointer_format = DYLD_CHAINED_PTR_64_OFFSET;
-#endif
- segment->segment_offset = seg->fileoff;
- segment->max_valid_pointer = 0;
- segment->page_count = page_count;
- // add bind/rebase
- bind_index = 0;
- k = 0;
- for (j = 0; j < page_count; j++) {
- addr_t start = seg->vmaddr + j * SEG_PAGE_SIZE;
- addr_t end = start + SEG_PAGE_SIZE;
- void *last = NULL;
- addr_t last_o = 0;
- addr_t cur_o, cur;
- struct dyld_chained_ptr_64_rebase *rebase;
- struct dyld_chained_ptr_64_bind *bind;
-
- segment->page_start[j] = DYLD_CHAINED_PTR_START_NONE;
- for (; k < mo->n_bind_rebase; k++) {
- Section *s = s1->sections[mo->bind_rebase[k].section];
- addr_t r_offset = mo->bind_rebase[k].rel.r_offset;
- addr_t addr = s->sh_addr + r_offset;
-
- if ((addr & 3) ||
- (addr & (SEG_PAGE_SIZE - 1)) > SEG_PAGE_SIZE - PTR_SIZE)
- tcc_error("Illegal rel_offset %s %lld",
- s->name, (long long)r_offset);
- if (addr >= end)
- break;
- if (addr >= start) {
- cur_o = addr - start;
- if (mo->bind_rebase[k].bind) {
- if (segment->page_start[j] == DYLD_CHAINED_PTR_START_NONE)
- segment->page_start[j] = cur_o;
- else {
- bind = (struct dyld_chained_ptr_64_bind *) last;
- bind->next = (cur_o - last_o) / 4;
- }
- bind = (struct dyld_chained_ptr_64_bind *)
- (s->data + r_offset);
- last = bind;
- last_o = cur_o;
- bind->ordinal = bind_index;
- bind->addend = 0;
- bind->reserved = 0;
- bind->next = 0;
- bind->bind = 1;
- }
- else {
- if (segment->page_start[j] == DYLD_CHAINED_PTR_START_NONE)
- segment->page_start[j] = cur_o;
- else {
- rebase = (struct dyld_chained_ptr_64_rebase *) last;
- rebase->next = (cur_o - last_o) / 4;
- }
- rebase = (struct dyld_chained_ptr_64_rebase *)
- (s->data + r_offset);
- last = rebase;
- last_o = cur_o;
- cur = (*(uint64_t *) (s->data + r_offset)) -
- PTR_64_OFFSET;
- rebase->target = cur & PTR_64_MASK;
- rebase->high8 = cur >> (64 - 8);
- if (cur != ((uint64_t)rebase->high8 << (64 - 8)) + rebase->target)
- tcc_error("rebase error");
- rebase->reserved = 0;
- rebase->next = 0;
- rebase->bind = 0;
- }
- }
- bind_index += mo->bind_rebase[k].bind;
- }
- }
- }
- // add imports
- header->imports_offset = data - mo->chained_fixups->data;
- import = (struct dyld_chained_import *) data;
- data += mo->n_bind * sizeof (struct dyld_chained_import);
- header->symbols_offset = data - mo->chained_fixups->data;
- data++;
- for (i = 0, bind_index = 0; i < mo->n_bind_rebase; i++) {
- if (mo->bind_rebase[i].bind) {
- import[bind_index].lib_ordinal =
- BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xffu;
- import[bind_index].name_offset =
- (data - mo->chained_fixups->data) - header->symbols_offset;
- sym_index = ELFW(R_SYM)(mo->bind_rebase[i].rel.r_info);
- sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
- import[bind_index].weak_import =
- ELFW(ST_BIND)(sym->st_info) == STB_WEAK;
- name = (char *) symtab_section->link->data + sym->st_name;
- strcpy((char *) data, name);
- data += strlen(name) + 1;
- bind_index++;
- }
- }
- tcc_free(mo->bind_rebase);
-}
-#endif
-
-ST_FUNC int macho_output_file(TCCState *s1, const char *filename)
-{
- int fd, mode, file_type;
- FILE *fp;
- int i, ret = -1;
- struct macho mo;
-
- (void)memset(&mo, 0, sizeof(mo));
-
- file_type = s1->output_type;
- if (file_type == TCC_OUTPUT_OBJ)
- mode = 0666;
- else
- mode = 0777;
- unlink(filename);
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
- if (fd < 0 || (fp = fdopen(fd, "wb")) == NULL) {
- tcc_error_noabort("could not write '%s: %s'", filename, strerror(errno));
- return -1;
- }
- if (s1->verbose)
- printf("<- %s\n", filename);
-
- tcc_add_runtime(s1);
- tcc_macho_add_destructor(s1);
- resolve_common_syms(s1);
- create_symtab(s1, &mo);
- check_relocs(s1, &mo);
- ret = check_symbols(s1, &mo);
- if (!ret) {
- int save_output = s1->output_type;
-
- collect_sections(s1, &mo, filename);
- relocate_syms(s1, s1->symtab, 0);
- if (s1->output_type == TCC_OUTPUT_EXE)
- mo.ep->entryoff = get_sym_addr(s1, "main", 1, 1)
- - get_segment(&mo, 1)->vmaddr;
- if (s1->nb_errors)
- goto do_ret;
- // Macho uses bind/rebase instead of dynsym
- s1->output_type = TCC_OUTPUT_EXE;
- relocate_sections(s1);
- s1->output_type = save_output;
-#ifdef CONFIG_NEW_MACHO
- bind_rebase_import(s1, &mo);
-#endif
- convert_symbols(s1, &mo);
- macho_write(s1, &mo, fp);
- }
-
- do_ret:
- for (i = 0; i < mo.nlc; i++)
- tcc_free(mo.lc[i]);
- tcc_free(mo.seg2lc);
- tcc_free(mo.lc);
- tcc_free(mo.elfsectomacho);
- tcc_free(mo.e2msym);
-
- fclose(fp);
-#ifdef CONFIG_CODESIGN
- {
- char command[1024];
- int retval;
-
- snprintf(command, sizeof(command), "codesign -f -s - %s", filename);
- retval = system (command);
- if (retval == -1 || !(WIFEXITED(retval) && WEXITSTATUS(retval) == 0))
- tcc_error ("command failed '%s'", command);
- }
-#endif
- return ret;
-}
-
-static uint32_t macho_swap32(uint32_t x)
-{
- return (x >> 24) | (x << 24) | ((x >> 8) & 0xff00) | ((x & 0xff00) << 8);
-}
-#define SWAP(x) (swap ? macho_swap32(x) : (x))
-#define tbd_parse_movepast(s) \
- (pos = (pos = strstr(pos, s)) ? pos + strlen(s) : NULL)
-#define tbd_parse_movetoany(cs) (pos = strpbrk(pos, cs))
-#define tbd_parse_skipws while (*pos && (*pos==' '||*pos=='\n')) ++pos
-#define tbd_parse_tramplequote if(*pos=='\''||*pos=='"') tbd_parse_trample
-#define tbd_parse_tramplespace if(*pos==' ') tbd_parse_trample
-#define tbd_parse_trample *pos++=0
-
-#ifdef TCC_IS_NATIVE
-/* Looks for the active developer SDK set by xcode-select (or the default
- one set during installation.) */
-ST_FUNC void tcc_add_macos_sdkpath(TCCState* s)
-{
- char *sdkroot = NULL, *pos = NULL;
- void* xcs = dlopen("libxcselect.dylib", RTLD_GLOBAL | RTLD_LAZY);
- CString path;
- int (*f)(unsigned int, char**) = dlsym(xcs, "xcselect_host_sdk_path");
- cstr_new(&path);
- if (f) f(1, &sdkroot);
- if (sdkroot)
- pos = strstr(sdkroot,"SDKs/MacOSX");
- if (pos)
- cstr_printf(&path, "%.*s.sdk/usr/lib", (int)(pos - sdkroot + 11), sdkroot);
- /* must use free from libc directly */
-#pragma push_macro("free")
-#undef free
- free(sdkroot);
-#pragma pop_macro("free")
- if (path.size)
- tcc_add_library_path(s, (char*)path.data);
- else
- tcc_add_library_path(s,
- "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
- ":" "/Applications/Xcode.app/Developer/SDKs/MacOSX.sdk/usr/lib"
- );
- cstr_free(&path);
-}
-
-ST_FUNC const char* macho_tbd_soname(const char* filename) {
- char *soname, *data, *pos;
- const char *ret = filename;
-
- int fd = open(filename,O_RDONLY);
- if (fd<0) return ret;
- pos = data = tcc_load_text(fd);
- if (!tbd_parse_movepast("install-name: ")) goto the_end;
- tbd_parse_skipws;
- tbd_parse_tramplequote;
- soname = pos;
- if (!tbd_parse_movetoany("\n \"'")) goto the_end;
- tbd_parse_trample;
- ret = tcc_strdup(soname);
-the_end:
- tcc_free(data);
- return ret;
-}
-#endif /* TCC_IS_NATIVE */
-
-ST_FUNC int macho_load_tbd(TCCState* s1, int fd, const char* filename, int lev)
-{
- char *soname, *data, *pos;
- int ret = -1;
-
- pos = data = tcc_load_text(fd);
- if (!tbd_parse_movepast("install-name: ")) goto the_end;
- tbd_parse_skipws;
- tbd_parse_tramplequote;
- soname = pos;
- if (!tbd_parse_movetoany("\n \"'")) goto the_end;
- tbd_parse_trample;
- ret = 0;
- if (tcc_add_dllref(s1, soname, lev)->found)
- goto the_end;
- while(pos) {
- char* sym = NULL;
- int cont = 1;
- if (!tbd_parse_movepast("symbols: ")) break;
- if (!tbd_parse_movepast("[")) break;
- while (cont) {
- tbd_parse_skipws;
- tbd_parse_tramplequote;
- sym = pos;
- if (!tbd_parse_movetoany(",] \"'")) break;
- tbd_parse_tramplequote;
- tbd_parse_tramplespace;
- tbd_parse_skipws;
- if (*pos==0||*pos==']') cont=0;
- tbd_parse_trample;
- set_elf_sym(s1->dynsymtab_section, 0, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, SHN_UNDEF, sym);
- }
- }
-
-the_end:
- tcc_free(data);
- return ret;
-}
-
-ST_FUNC int macho_load_dll(TCCState * s1, int fd, const char* filename, int lev)
-{
- unsigned char buf[sizeof(struct mach_header_64)];
- void *buf2;
- uint32_t machofs = 0;
- struct fat_header fh;
- struct mach_header mh;
- struct load_command *lc;
- int i, swap = 0;
- const char *soname = filename;
- struct nlist_64 *symtab = 0;
- uint32_t nsyms = 0;
- char *strtab = 0;
- uint32_t strsize = 0;
- uint32_t iextdef = 0;
- uint32_t nextdef = 0;
-
- again:
- if (full_read(fd, buf, sizeof(buf)) != sizeof(buf))
- return -1;
- memcpy(&fh, buf, sizeof(fh));
- if (fh.magic == FAT_MAGIC || fh.magic == FAT_CIGAM) {
- struct fat_arch *fa = load_data(fd, sizeof(fh),
- fh.nfat_arch * sizeof(*fa));
- swap = fh.magic == FAT_CIGAM;
- for (i = 0; i < SWAP(fh.nfat_arch); i++)
-#ifdef TCC_TARGET_X86_64
- if (SWAP(fa[i].cputype) == CPU_TYPE_X86_64
- && SWAP(fa[i].cpusubtype) == CPU_SUBTYPE_X86_ALL)
-#elif defined TCC_TARGET_ARM64
- if (SWAP(fa[i].cputype) == CPU_TYPE_ARM64
- && SWAP(fa[i].cpusubtype) == CPU_SUBTYPE_ARM64_ALL)
-#endif
- break;
- if (i == SWAP(fh.nfat_arch)) {
- tcc_free(fa);
- return -1;
- }
- machofs = SWAP(fa[i].offset);
- tcc_free(fa);
- lseek(fd, machofs, SEEK_SET);
- goto again;
- } else if (fh.magic == FAT_MAGIC_64 || fh.magic == FAT_CIGAM_64) {
- tcc_warning("%s: Mach-O fat 64bit files of type 0x%x not handled",
- filename, fh.magic);
- return -1;
- }
-
- memcpy(&mh, buf, sizeof(mh));
- if (mh.magic != MH_MAGIC_64)
- return -1;
- dprintf("found Mach-O at %d\n", machofs);
- buf2 = load_data(fd, machofs + sizeof(struct mach_header_64), mh.sizeofcmds);
- for (i = 0, lc = buf2; i < mh.ncmds; i++) {
- dprintf("lc %2d: 0x%08x\n", i, lc->cmd);
- switch (lc->cmd) {
- case LC_SYMTAB:
- {
- struct symtab_command *sc = (struct symtab_command*)lc;
- nsyms = sc->nsyms;
- symtab = load_data(fd, machofs + sc->symoff, nsyms * sizeof(*symtab));
- strsize = sc->strsize;
- strtab = load_data(fd, machofs + sc->stroff, strsize);
- break;
- }
- case LC_ID_DYLIB:
- {
- struct dylib_command *dc = (struct dylib_command*)lc;
- soname = (char*)lc + dc->name;
- dprintf(" ID_DYLIB %d 0x%x 0x%x %s\n",
- dc->timestamp, dc->current_version,
- dc->compatibility_version, soname);
- break;
- }
- case LC_REEXPORT_DYLIB:
- {
- struct dylib_command *dc = (struct dylib_command*)lc;
- char *name = (char*)lc + dc->name;
- int subfd = open(name, O_RDONLY | O_BINARY);
- dprintf(" REEXPORT %s\n", name);
- if (subfd < 0)
- tcc_warning("can't open %s (reexported from %s)", name, filename);
- else {
- /* Hopefully the REEXPORTs never form a cycle, we don't check
- for that! */
- macho_load_dll(s1, subfd, name, lev + 1);
- close(subfd);
- }
- break;
- }
- case LC_DYSYMTAB:
- {
- struct dysymtab_command *dc = (struct dysymtab_command*)lc;
- iextdef = dc->iextdefsym;
- nextdef = dc->nextdefsym;
- break;
- }
- }
- lc = (struct load_command*) ((char*)lc + lc->cmdsize);
- }
-
- if (tcc_add_dllref(s1, soname, lev)->found)
- goto the_end;
-
- if (!nsyms || !nextdef)
- tcc_warning("%s doesn't export any symbols?", filename);
-
- //dprintf("symbols (all):\n");
- dprintf("symbols (exported):\n");
- dprintf(" n: typ sec desc value name\n");
- //for (i = 0; i < nsyms; i++) {
- for (i = iextdef; i < iextdef + nextdef; i++) {
- struct nlist_64 *sym = symtab + i;
- dprintf("%5d: %3d %3d 0x%04x 0x%016lx %s\n",
- i, sym->n_type, sym->n_sect, sym->n_desc, (long)sym->n_value,
- strtab + sym->n_strx);
- set_elf_sym(s1->dynsymtab_section, 0, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE),
- 0, SHN_UNDEF, strtab + sym->n_strx);
- }
-
- the_end:
- tcc_free(strtab);
- tcc_free(symtab);
- tcc_free(buf2);
- return 0;
-}