├── mach ├── dylib │ ├── lib.h │ ├── weak.h │ ├── main.c │ ├── lib.c │ ├── weak_lib.cc │ ├── weak_main.cc │ └── dlfcn.c ├── printf.c ├── fflush_null.c ├── hello_cpp.cc ├── stderr.c ├── getenv.c ├── class.cc ├── atexit.c ├── setlocale.c ├── hello.c ├── stack.c ├── gettimeofday.c ├── strcmp.c ├── nsgetexecpath.c ├── stat_type.c ├── argv.c ├── putc.c ├── stat.c ├── ctor_dtor.c ├── mycat.c ├── dirent.c ├── uname.c ├── strlcpy.c ├── getrusage.c └── pthread.c ├── .travis.yml ├── .gitignore ├── libmac ├── errno.c ├── popcountdi2.c ├── stack_protector-obsd.c ├── none.c ├── strmode.c └── runetable.c ├── log.cc ├── fat.h ├── .gdbinit ├── no_trampoline.tab ├── log.h ├── ld-mac.sh ├── include ├── _types.h ├── mach-o │ └── fat.h ├── mach │ ├── vm_prot.h │ └── machine.h ├── mac-ctype.h └── runetype.h ├── gdb_maloader.py ├── binfmt_misc.sh ├── env_flags.h ├── Makefile ├── fat.cc ├── extract.cc ├── runtests.sh ├── mach-o.h ├── unpack_xcode.sh ├── rename.tab ├── README.md ├── macho2elf.cc ├── mach-o.cc └── ld-mac.cc /mach/dylib/lib.h: -------------------------------------------------------------------------------- 1 | extern int check_value; 2 | 3 | int hello(const char* arg); 4 | -------------------------------------------------------------------------------- /mach/printf.c: -------------------------------------------------------------------------------- 1 | int main(int argc) { 2 | printf("%d\n", argc); 3 | return 0; 4 | } 5 | -------------------------------------------------------------------------------- /mach/fflush_null.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | return fflush(NULL); 5 | } 6 | -------------------------------------------------------------------------------- /mach/hello_cpp.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << "Hello, world!" << std::endl; 5 | } 6 | -------------------------------------------------------------------------------- /mach/stderr.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | fprintf(stderr, "Hello, world!\n"); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /mach/getenv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | int main() { 4 | printf("%s\n", getenv("HOME")); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /mach/dylib/weak.h: -------------------------------------------------------------------------------- 1 | template 2 | class C { 3 | public: 4 | static int weak; 5 | }; 6 | 7 | template 8 | int C::weak = 0; 9 | -------------------------------------------------------------------------------- /mach/class.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class C { 4 | public: 5 | C() {} 6 | }; 7 | 8 | int main() { 9 | C c; 10 | puts("OK"); 11 | } 12 | -------------------------------------------------------------------------------- /mach/dylib/main.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | #include 4 | 5 | int main() { 6 | if (hello("world") != 42) 7 | abort(); 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /mach/atexit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void f() { 5 | puts("atexit"); 6 | } 7 | 8 | int main() { 9 | atexit(f); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /mach/setlocale.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | char* p = setlocale(2, ""); 6 | printf("%p\n", p); 7 | printf("%s\n", p); 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /mach/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main() { 3 | #ifdef __x86_64__ 4 | printf("Hello, 64bit world!\n"); 5 | #else 6 | printf("Hello, 32bit world!\n"); 7 | #endif 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /mach/stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int fib(int n) { 4 | if (n < 2) return 1; 5 | return fib(n-1) + fib(n-2); 6 | } 7 | 8 | int main() { 9 | printf("%d\n", fib(20)); 10 | return 0; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /mach/gettimeofday.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | struct timeval tv; 6 | int r = gettimeofday(&tv, NULL); 7 | printf("%d %d\n", tv.tv_sec, tv.tv_usec); 8 | return 0; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /mach/strcmp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char* argv[]) { 4 | puts("run"); 5 | if (strcmp(argv[argc-1], "a.out")) { 6 | puts("yes"); 7 | } else { 8 | puts("no"); 9 | } 10 | puts("done"); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | 4 | language: cpp 5 | 6 | compiler: 7 | - clang 8 | - gcc 9 | 10 | before_install: 11 | - sudo apt-get -qq update 12 | - sudo apt-get install -y uuid-dev 13 | 14 | script: make release 15 | 16 | -------------------------------------------------------------------------------- /mach/dylib/lib.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int check_value; 4 | 5 | __attribute__((constructor)) static void init() { 6 | check_value = 999; 7 | } 8 | 9 | int hello(const char* arg) { 10 | printf("Hello, %s!\n", arg); 11 | return 42; 12 | } 13 | -------------------------------------------------------------------------------- /mach/nsgetexecpath.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | char buf[4096]; 6 | unsigned int size = 4095; 7 | int r = _NSGetExecutablePath(buf, &size); 8 | printf("r=%d %s\n", r, buf); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /mach/stat_type.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char* argv[]) { 6 | struct stat buf; 7 | int ret = stat("/tmp", &buf); 8 | if (!S_ISDIR(buf.st_mode)) 9 | abort(); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /mach/argv.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char* argv[]) { 4 | printf("argc=%d\n", argc); 5 | printf("argv[0]=%p\n", argv[0]); 6 | printf("argv[0]=%s\n", argv[0]); 7 | printf("argv[1]=%p\n", argv[1]); 8 | printf("argv[1]=%s\n", argv[1]); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /mach/dylib/weak_lib.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "weak.h" 4 | 5 | __attribute__((constructor)) void init_weak() { 6 | printf("init_weak before: %d %p\n", C::weak, &C::weak); 7 | C::weak = 42; 8 | printf("init_weak after: %d %p\n", C::weak, &C::weak); 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.exe 7 | *.o 8 | *.so 9 | *.pyc 10 | 11 | # Logs and databases # 12 | ###################### 13 | *.log 14 | 15 | # OS generated files # 16 | ###################### 17 | .DS_Store* 18 | ehthumbs.db 19 | Icon? 20 | Thumbs.db 21 | -------------------------------------------------------------------------------- /mach/putc.c: -------------------------------------------------------------------------------- 1 | // It's very unfortunate that apple's putc_unlocked is a macro and depends on 2 | // the layout of FILE. 3 | #include 4 | 5 | int main() { 6 | putc_unlocked('h', stdout); 7 | putc_unlocked('o', stdout); 8 | putc_unlocked('g', stdout); 9 | putc_unlocked('e', stdout); 10 | putc_unlocked('\n', stdout); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /mach/stat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char* argv[]) { 6 | struct stat buf; 7 | int fd = open(argv[0], O_RDONLY); 8 | int ret = fstat(fd, &buf); 9 | printf("ret=%d size=%d size_offset=%ld\n", 10 | ret, buf.st_size, (char*)&buf.st_size - (char*)&buf); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /mach/ctor_dtor.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | __attribute__((constructor)) void ctor() { 4 | puts("ctor"); 5 | } 6 | 7 | __attribute__((constructor)) void ctor2() { 8 | puts("ctor2"); 9 | } 10 | 11 | __attribute__((destructor)) void dtor() { 12 | puts("dtor"); 13 | } 14 | 15 | __attribute__((destructor)) void dtor2() { 16 | puts("dtor2"); 17 | } 18 | 19 | int main() { 20 | puts("main"); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /mach/mycat.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char* argv[]) { 4 | if (argc < 2) { 5 | fprintf(stderr, "need file name\n"); 6 | return 0; 7 | } 8 | 9 | FILE* fp = fopen(argv[1], "rb"); 10 | char buf[4096]; 11 | size_t len; 12 | while (1) { 13 | len = fread(buf, 1, 4096, fp); 14 | fwrite(buf, 1, len, stdout); 15 | if (len != 4096) break; 16 | } 17 | fclose(fp); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /mach/dirent.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | DIR* dir = opendir("/tmp"); 9 | if (!dir) 10 | abort(); 11 | int found = 0; 12 | struct dirent* ent; 13 | while ((ent = readdir(dir)) != NULL) { 14 | printf("%s\n", ent->d_name); 15 | if (!strcmp(ent->d_name, ".")) 16 | found = 1; 17 | } 18 | closedir(dir); 19 | if (!found) 20 | abort(); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /mach/dylib/weak_main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "weak.h" 6 | 7 | int main() { 8 | #ifdef DL 9 | int dlflags = RTLD_NOW; 10 | # ifdef __APPLE__ 11 | void* h = dlopen("mach/dylib/weak_lib.dylib", dlflags); 12 | # else 13 | void* h = dlopen("mach/dylib/weak_lib.so", dlflags); 14 | # endif 15 | if (!h) { 16 | printf("%s\n", dlerror()); 17 | abort(); 18 | } 19 | #endif 20 | printf("%d %p\n", C::weak, &C::weak); 21 | if (C::weak != 42) { 22 | abort(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /mach/uname.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char* argv[]) { 7 | struct utsname buf; 8 | if (uname(&buf) != 0) 9 | abort(); 10 | printf("sysname=%s\nnodename=%s\nrelease=%s\nversion=%s\nmachine=%s\n", 11 | buf.sysname, buf.nodename, buf.release, buf.version, buf.machine); 12 | printf("sysname=%lu\nnodename=%lu\nrelease=%lu\nversion=%lu\nmachine=%lu\n", 13 | offsetof(struct utsname, sysname), offsetof(struct utsname, nodename), 14 | offsetof(struct utsname, release), offsetof(struct utsname, version), 15 | offsetof(struct utsname, machine)); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /mach/strlcpy.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char* argv[]) { 4 | char dst[100]; 5 | char src[100]; 6 | 7 | strcpy(src, "foobar"); 8 | 9 | memset(dst, 0, sizeof(dst)); 10 | strlcpy(dst, src, 4); 11 | if (strcmp(dst, "foo")) { 12 | puts("fail - 4"); 13 | return 1; 14 | } 15 | 16 | memset(dst, 0, sizeof(dst)); 17 | strlcpy(dst, src, 6); 18 | if (strcmp(dst, "fooba")) { 19 | puts("fail - 6"); 20 | return 1; 21 | } 22 | 23 | memset(dst, 0, sizeof(dst)); 24 | strlcpy(dst, src, 7); 25 | if (strcmp(dst, "foobar")) { 26 | puts("fail - 7"); 27 | return 1; 28 | } 29 | 30 | memset(dst, 0, sizeof(dst)); 31 | strlcpy(dst, src, 8); 32 | if (strcmp(dst, "foobar")) { 33 | puts("fail - 8"); 34 | return 1; 35 | } 36 | 37 | puts("ok"); 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /mach/getrusage.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | struct rusage ru; 7 | int r = getrusage(RUSAGE_SELF, &ru); 8 | printf("ret=%d\n", r); 9 | printf("utime=%d.%d stime=%d.%d\n" 10 | "maxrss=%ld ixrss=%ld idrss=%ld isrss=%ld\n" 11 | "minflt=%ld majflt=%ld nswap=%ld\n" 12 | "inblock=%ld oublock=%ld msgsnd=%ld msgrcv=%ld\n" 13 | "nsignals=%ld nvcsw=%ld nivcsw=%ld\n" 14 | , 15 | (int)ru.ru_utime.tv_sec, (int)ru.ru_utime.tv_usec, 16 | (int)ru.ru_stime.tv_sec, (int)ru.ru_stime.tv_usec, 17 | ru.ru_maxrss, ru.ru_ixrss, ru.ru_idrss, ru.ru_isrss, 18 | ru.ru_minflt, ru.ru_majflt, ru.ru_nswap, 19 | ru.ru_inblock, ru.ru_oublock, ru.ru_msgsnd, ru.ru_msgrcv, 20 | ru.ru_nsignals, ru.ru_nvcsw, ru.ru_nivcsw); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /mach/pthread.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | 6 | pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; 7 | 8 | int main() { 9 | { 10 | pthread_mutexattr_t attr; 11 | if (pthread_mutexattr_init(&attr) != 0) { 12 | abort(); 13 | } 14 | if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL) != 0) { 15 | abort(); 16 | } 17 | if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE) != 0) { 18 | abort(); 19 | } 20 | } 21 | 22 | { 23 | pthread_rwlockattr_t attr; 24 | if (pthread_rwlockattr_init(&attr) != 0) { 25 | abort(); 26 | } 27 | if (pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE) != 0) { 28 | abort(); 29 | } 30 | } 31 | 32 | // TODO(hamaji): PTHREAD_MUTEX_INITIALIZER has a different implementation... 33 | #if 0 34 | if (pthread_mutex_lock(&g_mutex) != 0) { 35 | abort(); 36 | } 37 | #endif 38 | } 39 | -------------------------------------------------------------------------------- /libmac/errno.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | /* 24 | * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved 25 | */ 26 | /* 27 | * The world-renowned global variable 28 | */ 29 | #include 30 | 31 | int *__error(void) { 32 | return &errno; 33 | } 34 | 35 | int cthread_errno(void) { 36 | return *__error(); 37 | } 38 | 39 | -------------------------------------------------------------------------------- /libmac/popcountdi2.c: -------------------------------------------------------------------------------- 1 | /* ===-- popcountdi2.c - Implement __popcountdi2 ----------------------------=== 2 | * 3 | * The LLVM Compiler Infrastructure 4 | * 5 | * This file is distributed under the University of Illinois Open Source 6 | * License. See LICENSE.TXT for details. 7 | * 8 | * ===----------------------------------------------------------------------=== 9 | * 10 | * This file implements __popcountdi2 for the compiler_rt library. 11 | * 12 | * ===----------------------------------------------------------------------=== 13 | */ 14 | 15 | int 16 | __popcountdi2(int64_t a) 17 | { 18 | uint64_t x2 = (uint64_t)a; 19 | x2 = x2 - ((x2 >> 1) & 0x5555555555555555uLL); 20 | /* Every 2 bits holds the sum of every pair of bits (32) */ 21 | x2 = ((x2 >> 2) & 0x3333333333333333uLL) + (x2 & 0x3333333333333333uLL); 22 | /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (16) */ 23 | x2 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0FuLL; 24 | /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (8) */ 25 | unsigned int x = (unsigned int)(x2 + (x2 >> 32)); 26 | /* The lower 32 bits hold four 16 bit sums (5 significant bits). */ 27 | /* Upper 32 bits are garbage */ 28 | x = x + (x >> 16); 29 | /* The lower 16 bits hold two 32 bit sums (6 significant bits). */ 30 | /* Upper 16 bits are garbage */ 31 | return (x + (x >> 8)) & 0x0000007F; /* (7 significant bits) */ 32 | } 33 | -------------------------------------------------------------------------------- /log.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Shinichiro Hamaji. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions 5 | // are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following 12 | // disclaimer in the documentation and/or other materials 13 | // provided with the distribution. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 16 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 19 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 22 | // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | // SUCH DAMAGE. 27 | 28 | #include "env_flags.h" 29 | 30 | DEFINE_bool(LOG, false, "Output bunch of logs"); 31 | -------------------------------------------------------------------------------- /mach/dylib/dlfcn.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | const char* err; 7 | 8 | #ifdef __APPLE__ 9 | void* h = dlopen("mach/dylib/lib.dylib", RTLD_NOW); 10 | #else 11 | void* h = dlopen("mach/dylib/lib.so", RTLD_NOW); 12 | #endif 13 | if (!h) { 14 | fprintf(stderr, "dlopen failed: %s\n", dlerror()); 15 | abort(); 16 | } 17 | 18 | if ((err = dlerror())) { 19 | fprintf(stderr, "dlopen failed (dlerror): %s\n", err); 20 | abort(); 21 | } 22 | 23 | int (*hello)(const char*) = (int(*)(const char*))dlsym(h, "hello"); 24 | if (!hello) { 25 | fprintf(stderr, "dlsym failed: %s\n", dlerror()); 26 | abort(); 27 | } 28 | 29 | if ((err = dlerror())) { 30 | fprintf(stderr, "dlsym failed (dlerror): %s\n", err); 31 | abort(); 32 | } 33 | 34 | if (hello("world") != 42) { 35 | fprintf(stderr, "hello failed\n"); 36 | abort(); 37 | } 38 | 39 | int (*hell)(const char*) = (int(*)(const char*))dlsym(h, "hell"); 40 | if (hell) { 41 | fprintf(stderr, "dlsym unexcepctedly succeeded: %s\n", dlerror()); 42 | abort(); 43 | } 44 | 45 | if (!(err = dlerror())) { 46 | fprintf(stderr, "dlsym unexcepctedly succeeded (dlerror)\n"); 47 | abort(); 48 | } 49 | 50 | printf("The error message for failing dlsym: %s\n", err); 51 | 52 | if (dlerror()) { 53 | fprintf(stderr, "dlerror has still been set\n"); 54 | abort(); 55 | } 56 | 57 | int* check_value = (int*)dlsym(h, "check_value"); 58 | if (!check_value) { 59 | fprintf(stderr, "dlsym failed: %s\n", dlerror()); 60 | abort(); 61 | } 62 | 63 | if (*check_value != 999) { 64 | fprintf(stderr, "initializer function didn't run?\n"); 65 | abort(); 66 | } 67 | 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /fat.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Shinichiro Hamaji. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions 5 | // are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following 12 | // disclaimer in the documentation and/or other materials 13 | // provided with the distribution. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 16 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 19 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 22 | // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | // SUCH DAMAGE. 27 | 28 | #ifndef FAT_H_ 29 | #define FAT_H_ 30 | 31 | #include 32 | #include 33 | 34 | #include "mach-o/fat.h" 35 | 36 | using namespace std; 37 | 38 | // Reads fd and fill fat info. Returns true if fd is a fat binary. 39 | bool readFatInfo(int fd, map* fat); 40 | 41 | #endif // FAT_H_ 42 | -------------------------------------------------------------------------------- /.gdbinit: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Shinichiro Hamaji. All rights reserved. 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 7 | # 1. Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # 10 | # 2. Redistributions in binary form must reproduce the above 11 | # copyright notice, this list of conditions and the following 12 | # disclaimer in the documentation and/or other materials 13 | # provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 16 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 19 | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 22 | # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | # SUCH DAMAGE. 27 | 28 | set follow-fork-mode child 29 | 30 | python sys.path.insert(0, '.') 31 | python import gdb_maloader 32 | 33 | define mreload 34 | python reload(gdb_maloader) 35 | end 36 | 37 | define mbt 38 | mreload 39 | python gdb_maloader.bt() 40 | end 41 | 42 | define mbtr 43 | mreload 44 | python gdb_maloader.bt(demangle=False) 45 | end 46 | -------------------------------------------------------------------------------- /no_trampoline.tab: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Shinichiro Hamaji. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions 5 | // are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following 12 | // disclaimer in the documentation and/or other materials 13 | // provided with the distribution. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 16 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 19 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 22 | // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | // SUCH DAMAGE. 27 | 28 | // A list of symbols which should not be wrapped by trampolines. 29 | // Symbols for data should be listed here. 30 | // TODO(hamaji): Investigate a way to get rid of this exemption list. 31 | 32 | NO_TRAMPOLINE(__darwin_stdin) 33 | NO_TRAMPOLINE(__darwin_stdout) 34 | NO_TRAMPOLINE(__darwin_stderr) 35 | 36 | NO_TRAMPOLINE(optind) 37 | NO_TRAMPOLINE(opterr) 38 | NO_TRAMPOLINE(optopt) 39 | 40 | NO_TRAMPOLINE(_DefaultRuneLocale) 41 | NO_TRAMPOLINE(__stack_chk_guard) 42 | -------------------------------------------------------------------------------- /log.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Shinichiro Hamaji. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions 5 | // are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following 12 | // disclaimer in the documentation and/or other materials 13 | // provided with the distribution. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 16 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 19 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 22 | // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | // SUCH DAMAGE. 27 | 28 | #ifndef LOG_H_ 29 | #define LOG_H_ 30 | 31 | #include 32 | 33 | #include "env_flags.h" 34 | 35 | DECLARE_bool(LOG); 36 | 37 | #ifdef NOLOG 38 | # define LOG if (0) cout 39 | # define LOGF(...) if (0) fprintf(stderr, __VA_ARGS__) 40 | #else 41 | # define LOG if (FLAGS_LOG) cerr 42 | # define LOGF(...) if (FLAGS_LOG) fprintf(stderr, __VA_ARGS__) 43 | #endif 44 | 45 | #define ERR cerr 46 | 47 | #ifdef NDEBUG 48 | // Do an extra check to avoid warning around unused local variables. 49 | # define CHECK(r) do { if (!(r)) assert(r); } while (0) 50 | #else 51 | # define CHECK(r) assert(r); 52 | #endif 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /ld-mac.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright 2011 Shinichiro Hamaji. All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions 7 | # are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # 12 | # 2. Redistributions in binary form must reproduce the above 13 | # copyright notice, this list of conditions and the following 14 | # disclaimer in the documentation and/or other materials 15 | # provided with the distribution. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 18 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 21 | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 24 | # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 | # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | # SUCH DAMAGE. 29 | # 30 | # Run ld-mac or ld-mac32 based on $LD_MAC_BITS or the target binary 31 | # 32 | # Usage: 33 | # 34 | # % ./ld-mac.sh hello32 35 | # % ./ld-mac.sh hello64 36 | # 37 | # See README for more detail 38 | 39 | set -e 40 | 41 | ld_mac_dir=$(cd $(dirname $0) && pwd) 42 | 43 | if [ "x" != "x$LD_MAC_LOG" ]; then 44 | set -x 45 | fi 46 | 47 | if [ "x" = "x$LD_MAC_BITS" ]; then 48 | ld_mac_binary="$ld_mac_dir/ld-mac" 49 | if file $1 | grep i386 2>&1 > /dev/null; then 50 | ld_mac_binary="$ld_mac_dir/ld-mac32" 51 | fi 52 | else 53 | ld_mac_binary="$ld_mac_dir/ld-mac$LD_MAC_BITS" 54 | if [ ! -x $ld_mac_binary ]; then 55 | echo "Cannot run $ld_mac_binary" 56 | exit 1 57 | fi 58 | fi 59 | 60 | exec $ld_mac_binary "$@" 61 | -------------------------------------------------------------------------------- /include/_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004, 2008, 2009 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | 24 | #ifndef __TYPES_H_ 25 | #define __TYPES_H_ 26 | 27 | #include 28 | //#include 29 | 30 | #if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7 31 | #define __strfmonlike(fmtarg, firstvararg) \ 32 | __attribute__((__format__ (__strfmon__, fmtarg, firstvararg))) 33 | #define __strftimelike(fmtarg) \ 34 | __attribute__((__format__ (__strftime__, fmtarg, 0))) 35 | #else 36 | #define __strfmonlike(fmtarg, firstvararg) 37 | #define __strftimelike(fmtarg) 38 | #endif 39 | 40 | typedef int __darwin_nl_item; 41 | typedef int __darwin_wctrans_t; 42 | #ifdef __LP64__ 43 | typedef uint32_t __darwin_wctype_t; 44 | #else /* !__LP64__ */ 45 | typedef unsigned long __darwin_wctype_t; 46 | #endif /* __LP64__ */ 47 | 48 | #ifdef __WCHAR_MAX__ 49 | #define __DARWIN_WCHAR_MAX __WCHAR_MAX__ 50 | #else /* ! __WCHAR_MAX__ */ 51 | #define __DARWIN_WCHAR_MAX 0x7fffffff 52 | #endif /* __WCHAR_MAX__ */ 53 | 54 | #if __DARWIN_WCHAR_MAX > 0xffffU 55 | #define __DARWIN_WCHAR_MIN (-0x7fffffff - 1) 56 | #else 57 | #define __DARWIN_WCHAR_MIN 0 58 | #endif 59 | #define __DARWIN_WEOF ((__darwin_wint_t)-1) 60 | 61 | #ifndef _FORTIFY_SOURCE 62 | # if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && ((__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0) < 1050) 63 | # define _FORTIFY_SOURCE 0 64 | # else 65 | # define _FORTIFY_SOURCE 2 /* on by default */ 66 | # endif 67 | #endif 68 | 69 | #endif /* __TYPES_H_ */ 70 | -------------------------------------------------------------------------------- /gdb_maloader.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Shinichiro Hamaji. All rights reserved. 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 7 | # 1. Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # 10 | # 2. Redistributions in binary form must reproduce the above 11 | # copyright notice, this list of conditions and the following 12 | # disclaimer in the documentation and/or other materials 13 | # provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 16 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 19 | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 22 | # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | # SUCH DAMAGE. 27 | 28 | import gdb 29 | import os 30 | import re 31 | import sys 32 | 33 | def bt(demangle=True): 34 | # Find the newest frame. 35 | frame = gdb.selected_frame() 36 | while True: 37 | next = frame.newer() 38 | if not next: 39 | break 40 | frame = next 41 | 42 | if demangle: 43 | pipe = os.popen('c++filt', 'w') 44 | else: 45 | pipe = sys.stdout 46 | 47 | i = 0 48 | while frame: 49 | s = gdb.execute('p dumpSymbol((void*)0x%x)' % frame.pc(), 50 | to_string=True) 51 | m = re.match(r'.*"(.*)"$', s) 52 | if m: 53 | pipe.write("#%-2d %s\n" % (i, m.group(1))) 54 | else: 55 | sal = frame.find_sal() 56 | lineno = '' 57 | if sal.symtab: 58 | lineno = ' at %s:%d' % (sal.symtab, sal.line) 59 | pipe.write("#%-2d 0x%x %s%s\n" % 60 | (i, frame.pc(), frame.name(), lineno)) 61 | frame = frame.older() 62 | i += 1 63 | 64 | pipe.close() 65 | -------------------------------------------------------------------------------- /binfmt_misc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright 2011 Shinichiro Hamaji. All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions 7 | # are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # 12 | # 2. Redistributions in binary form must reproduce the above 13 | # copyright notice, this list of conditions and the following 14 | # disclaimer in the documentation and/or other materials 15 | # provided with the distribution. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 18 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 21 | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 24 | # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 | # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | # SUCH DAMAGE. 29 | # 30 | # Setup binfmt_misc for Mach-O binaries. 31 | # 32 | # Usage: 33 | # 34 | # % ./binfmt_misc.sh 35 | # % ./binfmt_misc.sh stop 36 | 37 | cmd=$1 38 | if [ "x$cmd" = "x" ]; then 39 | cmd=start 40 | fi 41 | 42 | if [ "x$2" = "x" ]; then 43 | ld_mac_dir=$(cd $(dirname $0); pwd) 44 | ld_mac=$ld_mac_dir/ld-mac 45 | else 46 | ld_mac="$2" 47 | fi 48 | 49 | case $cmd in 50 | start) 51 | sudo sh -c " 52 | echo :Mach-O '64bit:M::\\xcf\\xfa\\xed\\xfe::$ld_mac:' > /proc/sys/fs/binfmt_misc/register 53 | echo :Mach-O '32bit:M::\\xce\\xfa\\xed\\xfe::$ld_mac:' > /proc/sys/fs/binfmt_misc/register 54 | echo :Mach-O 'fat:M::\\xca\\xfe\\xba\\xbe::$ld_mac:' > /proc/sys/fs/binfmt_misc/register 55 | " 56 | echo "binfmt_misc for mach-o was registered" 57 | ;; 58 | stop) 59 | sudo sh -c ' 60 | echo -1 > /proc/sys/fs/binfmt_misc/Mach-O\ 64bit 61 | echo -1 > /proc/sys/fs/binfmt_misc/Mach-O\ 32bit 62 | echo -1 > /proc/sys/fs/binfmt_misc/Mach-O\ fat 63 | ' 64 | echo "binfmt_misc for mach-o was unregistered" 65 | ;; 66 | *) 67 | echo "unknown command: $1" 68 | exit 1 69 | ;; 70 | esac 71 | -------------------------------------------------------------------------------- /include/mach-o/fat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | #ifndef _MACH_O_FAT_H_ 24 | #define _MACH_O_FAT_H_ 25 | /* 26 | * This header file describes the structures of the file format for "fat" 27 | * architecture specific file (wrapper design). At the begining of the file 28 | * there is one fat_header structure followed by a number of fat_arch 29 | * structures. For each architecture in the file, specified by a pair of 30 | * cputype and cpusubtype, the fat_header describes the file offset, file 31 | * size and alignment in the file of the architecture specific member. 32 | * The padded bytes in the file to place each member on it's specific alignment 33 | * are defined to be read as zeros and can be left as "holes" if the file system 34 | * can support them as long as they read as zeros. 35 | * 36 | * All structures defined here are always written and read to/from disk 37 | * in big-endian order. 38 | */ 39 | 40 | /* 41 | * is needed here for the cpu_type_t and cpu_subtype_t types 42 | * and contains the constants for the possible values of these types. 43 | */ 44 | #include 45 | #include 46 | //#include 47 | 48 | #define FAT_MAGIC 0xcafebabe 49 | #define FAT_CIGAM 0xbebafeca /* NXSwapLong(FAT_MAGIC) */ 50 | 51 | struct fat_header { 52 | uint32_t magic; /* FAT_MAGIC */ 53 | uint32_t nfat_arch; /* number of structs that follow */ 54 | }; 55 | 56 | struct fat_arch { 57 | cpu_type_t cputype; /* cpu specifier (int) */ 58 | cpu_subtype_t cpusubtype; /* machine specifier (int) */ 59 | uint32_t offset; /* file offset to this object file */ 60 | uint32_t size; /* size of this object file */ 61 | uint32_t align; /* alignment as a power of 2 */ 62 | }; 63 | 64 | #endif /* _MACH_O_FAT_H_ */ 65 | -------------------------------------------------------------------------------- /libmac/stack_protector-obsd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2002 Hiroaki Etoh, Federico G. Schwindt, and Miodrag Vallat. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, 18 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 23 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #if defined(LIBC_SCCS) && !defined(list) 29 | static char rcsid[] = "$OpenBSD: stack_protector.c,v 1.3 2002/12/10 08:53:42 etoh Exp $"; 30 | #endif 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | long __stack_chk_guard[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 41 | void __guard_setup(void) __attribute__ ((visibility ("hidden"))); 42 | void __stack_chk_fail(void); 43 | 44 | void 45 | __guard_setup(void) 46 | { 47 | int fd; 48 | if (__stack_chk_guard[0]!=0) return; 49 | fd = open ("/dev/urandom", 0); 50 | if (fd != -1) { 51 | ssize_t size = read (fd, (char*)&__stack_chk_guard, 52 | sizeof(__stack_chk_guard)); 53 | close (fd) ; 54 | if (size == sizeof(__stack_chk_guard) 55 | && *__stack_chk_guard != 0) return; 56 | } 57 | /* If a random generator can't be used, the protector switches the guard 58 | to the "terminator canary" */ 59 | ((char*)__stack_chk_guard)[0] = 0; ((char*)__stack_chk_guard)[1] = 0; 60 | ((char*)__stack_chk_guard)[2] = '\n'; ((char*)__stack_chk_guard)[3] = 255; 61 | } 62 | 63 | void 64 | __stack_chk_fail() 65 | { 66 | const char message[] = "[%d] stack overflow"; 67 | 68 | /* this may fail on a chroot jail, though luck */ 69 | syslog(LOG_CRIT, message, getpid()); 70 | 71 | abort(); 72 | } 73 | -------------------------------------------------------------------------------- /env_flags.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Shinichiro Hamaji. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions 5 | // are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following 12 | // disclaimer in the documentation and/or other materials 13 | // provided with the distribution. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 16 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 19 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 22 | // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | // SUCH DAMAGE. 27 | 28 | #ifndef ENV_FLAGS_H_ 29 | #define ENV_FLAGS_H_ 30 | 31 | #include 32 | #include 33 | 34 | #define LD_MAC_EnvToBool(envname, dflt) \ 35 | (!getenv(envname) ? (dflt) : memchr("tTyY1\0", getenv(envname)[0], 6) != NULL) 36 | 37 | #define LD_MAC_DECLARE_VARIABLE(type, name, tn) \ 38 | namespace FLAG__namespace_do_not_use_directly_use_LD_MAC_DECLARE_##tn##_instead { \ 39 | extern type FLAGS_##name; \ 40 | } \ 41 | using FLAG__namespace_do_not_use_directly_use_LD_MAC_DECLARE_##tn##_instead::FLAGS_##name 42 | 43 | #define LD_MAC_DEFINE_VARIABLE(type, name, value, meaning, tn) \ 44 | namespace FLAG__namespace_do_not_use_directly_use_LD_MAC_DECLARE_##tn##_instead { \ 45 | type FLAGS_##name(value); \ 46 | } \ 47 | using FLAG__namespace_do_not_use_directly_use_LD_MAC_DECLARE_##tn##_instead::FLAGS_##name; 48 | 49 | #define DECLARE_bool(name) \ 50 | LD_MAC_DECLARE_VARIABLE(bool, name, bool) 51 | 52 | #define DEFINE_bool(name, value, meaning) \ 53 | LD_MAC_DEFINE_VARIABLE(bool, name, LD_MAC_EnvToBool("LD_MAC_" #name, value), \ 54 | meaning, bool) 55 | 56 | #endif // ENV_FLAGS_H_ 57 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VERSION=0.4 2 | BITS=64 3 | 4 | GCC_EXTRA_FLAGS=-m$(BITS) 5 | GCCFLAGS+=-g -Iinclude -Wall -MMD -fno-omit-frame-pointer -O $(GCC_EXTRA_FLAGS) 6 | ifeq ($(USE_LIBCXX), 1) 7 | GCCFLAGS+=-stdlib=libc++ -DUSE_LIBCXX 8 | CXX_LDFLAGS+=-lc++ -lsupc++ 9 | CC=clang 10 | CXX=clang++ 11 | endif 12 | CXXFLAGS=$(GCCFLAGS) -W -Werror --std=c++11 13 | CFLAGS=$(GCCFLAGS) -fPIC 14 | 15 | EXES=libmac.so extract macho2elf ld-mac 16 | 17 | MAC_C_SRCS=$(wildcard mach/*.c) 18 | MAC_CXX_SRCS=$(wildcard mach/*.cc) 19 | MAC_C_BINS=$(MAC_C_SRCS:.c=.c.bin) 20 | MAC_CXX_BINS=$(MAC_CXX_SRCS:.cc=.cc.bin) 21 | MACBINS=$(MAC_C_BINS) $(MAC_CXX_BINS) 22 | MACTXTS=$(MACBINS:.bin=.txt) 23 | 24 | OS=$(shell uname) 25 | 26 | ifeq ($(OS), Linux) 27 | MAC_TOOL_DIR=/usr/i686-apple-darwin10 28 | MAC_BIN_DIR=$(MAC_TOOL_DIR)/usr/bin 29 | MAC_CC=PATH=$(MAC_BIN_DIR) ./ld-mac $(MAC_BIN_DIR)/gcc --sysroot=$(MAC_TOOL_DIR) 30 | MAC_CXX=PATH=$(MAC_BIN_DIR) ./ld-mac $(MAC_BIN_DIR)/g++ --sysroot=$(MAC_TOOL_DIR) 31 | MAC_OTOOL=./ld-mac $(MAC_BIN_DIR)/otool 32 | MAC_TARGETS=ld-mac $(MACBINS) $(MACTXTS) 33 | else 34 | MAC_CC=$(CC) 35 | MAC_CXX=$(CXX) 36 | MAC_OTOOL=otool 37 | MAC_TARGETS=$(MACBINS) $(MACTXTS) 38 | endif 39 | 40 | all: $(EXES) 41 | 42 | profile: 43 | $(MAKE) clean 44 | $(MAKE) all GCC_EXTRA_FLAGS=-pg 45 | 46 | release: 47 | $(MAKE) clean 48 | $(MAKE) all "GCC_EXTRA_FLAGS=-DNOLOG -DNDEBUG" 49 | 50 | both: 51 | $(MAKE) clean 52 | $(MAKE) BITS=32 all 53 | mv ld-mac ld-mac32 54 | mv libmac.so libmac32.so 55 | $(MAKE) clean 56 | $(MAKE) BITS=64 all 57 | 58 | mach: $(MAC_TARGETS) 59 | 60 | check: all mach 61 | ./runtests.sh 62 | 63 | check-all: check 64 | rm -f $(MACBINS) 65 | MACOSX_DEPLOYMENT_TARGET=10.5 make mach 66 | MACOSX_DEPLOYMENT_TARGET=10.5 ./runtests.sh 67 | 68 | $(MAC_C_BINS): %.c.bin: %.c 69 | $(MAC_CC) -g -arch i386 -arch x86_64 $^ -o $@ 70 | 71 | $(MAC_CXX_BINS): %.cc.bin: %.cc 72 | $(MAC_CXX) -g -arch i386 -arch x86_64 $^ -o $@ 73 | 74 | $(MACTXTS): %.txt: %.bin 75 | $(MAC_OTOOL) -hLltvV $^ > $@ 76 | 77 | #ok: macho2elf 78 | # ./genelf.sh 79 | # touch $@ 80 | 81 | extract: extract.o fat.o 82 | $(CXX) $^ -o $@ -g -I. -W -Wall $(GCC_EXTRA_FLAGS) $(CXX_LDFLAGS) 83 | 84 | macho2elf: macho2elf.o mach-o.o fat.o log.o 85 | $(CXX) $^ -o $@ -g $(GCC_EXTRA_FLAGS) $(CXX_LDFLAGS) 86 | 87 | ld-mac: ld-mac.o mach-o.o fat.o log.o 88 | $(CXX) -v $^ -o $@ -g -ldl -lpthread $(GCC_EXTRA_FLAGS) $(CXX_LDFLAGS) 89 | 90 | # TODO(hamaji): autotoolize? 91 | libmac.so: libmac/mac.o libmac/strmode.c 92 | $(CC) -shared $^ $(CFLAGS) -o $@ $(GCC_EXTRA_FLAGS) $(LDFLAGS) -luuid -lz 93 | 94 | dist: 95 | cd /tmp && rm -fr maloader-$(VERSION) && git clone git@github.com:shinh/maloader.git && rm -fr maloader/.git && mv maloader maloader-$(VERSION) && tar -cvzf maloader-$(VERSION).tar.gz maloader-$(VERSION) 96 | 97 | clean: 98 | rm -f *.o *.d */*.o */*.d $(EXES) 99 | 100 | -include *.d */*.d 101 | -------------------------------------------------------------------------------- /fat.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Shinichiro Hamaji. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions 5 | // are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following 12 | // disclaimer in the documentation and/or other materials 13 | // provided with the distribution. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 16 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 19 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 22 | // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | // SUCH DAMAGE. 27 | 28 | #include "fat.h" 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | static void fixEndian(uint32_t* p, bool be) { 35 | if (!be) { 36 | return; 37 | } 38 | 39 | uint32_t v = *p; 40 | *p = (v << 24) | ((v << 8) & 0x00ff0000) | ((v >> 8) & 0xff00) | (v >> 24); 41 | } 42 | 43 | static string getArchName(uint32_t a) { 44 | switch (a) { 45 | case CPU_TYPE_X86: 46 | return "i386"; 47 | case CPU_TYPE_X86_64: 48 | return "x86-64"; 49 | case CPU_TYPE_POWERPC: 50 | return "ppc"; 51 | case CPU_TYPE_POWERPC64: 52 | return "ppc64"; 53 | default: 54 | char buf[99]; 55 | sprintf(buf, "??? (%u)", a); 56 | return buf; 57 | } 58 | } 59 | 60 | bool readFatInfo(int fd, map* fat) { 61 | lseek(fd, 0, SEEK_SET); 62 | 63 | fat_header header; 64 | ssize_t len = read(fd, &header, sizeof(header)); 65 | if (len < 0) { 66 | perror("read"); 67 | exit(1); 68 | } 69 | if (len != sizeof(header)) { 70 | return false; 71 | } 72 | 73 | bool be = false; 74 | if (header.magic == FAT_CIGAM) { 75 | be = true; 76 | } else if (header.magic != FAT_MAGIC) { 77 | return false; 78 | } 79 | 80 | fixEndian(&header.nfat_arch, be); 81 | for (uint32_t i = 0; i < header.nfat_arch; i++) { 82 | fat_arch arch; 83 | len = read(fd, &arch, sizeof(arch)); 84 | 85 | fixEndian(&arch.cputype, be); 86 | fixEndian(&arch.cpusubtype, be); 87 | fixEndian(&arch.offset, be); 88 | fixEndian(&arch.size, be); 89 | fixEndian(&arch.align, be); 90 | 91 | const string& name = getArchName(arch.cputype); 92 | fat->insert(make_pair(name, arch)); 93 | } 94 | 95 | return true; 96 | } 97 | -------------------------------------------------------------------------------- /extract.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Shinichiro Hamaji. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions 5 | // are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following 12 | // disclaimer in the documentation and/or other materials 13 | // provided with the distribution. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 16 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 19 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 22 | // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | // SUCH DAMAGE. 27 | 28 | // A command line tool to extract a Mach-O binary from a fat binary. 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | 41 | #include "mach-o/fat.h" 42 | 43 | #include "fat.h" 44 | 45 | using namespace std; 46 | 47 | int main(int argc, char* argv[]) { 48 | if (argc < 2) { 49 | fprintf(stderr, "Usage: %s fat [arch out]\n", argv[0]); 50 | exit(1); 51 | } 52 | 53 | int fd = open(argv[1], O_RDONLY); 54 | if (fd < 0) { 55 | perror("open"); 56 | exit(1); 57 | } 58 | 59 | off_t len = lseek(fd, 0, SEEK_END); 60 | char* bin = reinterpret_cast( 61 | mmap(NULL, len, 62 | PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0)); 63 | if (bin == MAP_FAILED) { 64 | perror("mmap"); 65 | exit(1); 66 | } 67 | 68 | map archs; 69 | if (!readFatInfo(fd, &archs)) { 70 | fprintf(stderr, "Not fat\n"); 71 | exit(1); 72 | } 73 | 74 | printf("%lu archs:\n", (unsigned long)archs.size()); 75 | for (map::const_iterator iter = archs.begin(); 76 | iter != archs.end(); 77 | ++iter) { 78 | const fat_arch& arch = iter->second; 79 | printf("cputype=%d (%s) cpusubtype=%d offset=%d size=%d align=%d\n", 80 | arch.cputype, iter->first.c_str(), arch.cpusubtype, 81 | arch.offset, arch.size, arch.align); 82 | } 83 | 84 | for (int i = 2; i + 1 < argc; i += 2) { 85 | const char* arch_name = argv[i]; 86 | map::const_iterator found = archs.find(arch_name); 87 | if (found == archs.end()) { 88 | printf("unknown arch: %s\n", arch_name); 89 | continue; 90 | } 91 | 92 | const fat_arch& arch = found->second; 93 | FILE* fp = fopen(argv[i+1], "wb"); 94 | if (fwrite(bin + arch.offset, 1, arch.size, fp) != arch.size) { 95 | printf("failed to fwrite\n"); 96 | exit(1); 97 | } 98 | fclose(fp); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /libmac/none.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * The contents of this file constitute Original Code as defined in and 7 | * are subject to the Apple Public Source License Version 1.1 (the 8 | * "License"). You may not use this file except in compliance with the 9 | * License. Please obtain a copy of the License at 10 | * http://www.apple.com/publicsource and read it before using this file. 11 | * 12 | * This Original Code and all software distributed under the License are 13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 | * License for the specific language governing rights and limitations 18 | * under the License. 19 | * 20 | * @APPLE_LICENSE_HEADER_END@ 21 | */ 22 | /* 23 | * Copyright (c) 1993 24 | * The Regents of the University of California. All rights reserved. 25 | * 26 | * This code is derived from software contributed to Berkeley by 27 | * Paul Borman at Krystal Technologies. 28 | * 29 | * Redistribution and use in source and binary forms, with or without 30 | * modification, are permitted provided that the following conditions 31 | * are met: 32 | * 1. Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above copyright 35 | * notice, this list of conditions and the following disclaimer in the 36 | * documentation and/or other materials provided with the distribution. 37 | * 3. All advertising materials mentioning features or use of this software 38 | * must display the following acknowledgement: 39 | * This product includes software developed by the University of 40 | * California, Berkeley and its contributors. 41 | * 4. Neither the name of the University nor the names of its contributors 42 | * may be used to endorse or promote products derived from this software 43 | * without specific prior written permission. 44 | * 45 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 46 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 49 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 | * SUCH DAMAGE. 56 | */ 57 | 58 | rune_t 59 | _none_sgetrune(string, n, result) 60 | const char *string; 61 | size_t n; 62 | char const **result; 63 | { 64 | if (n < 1) { 65 | if (result) 66 | *result = string; 67 | return(_INVALID_RUNE); 68 | } 69 | if (result) 70 | *result = string + 1; 71 | return(*string & 0xff); 72 | } 73 | 74 | int 75 | _none_sputrune(c, string, n, result) 76 | rune_t c; 77 | char *string, **result; 78 | size_t n; 79 | { 80 | if (n >= 1) { 81 | if (string) 82 | *string = c; 83 | if (result) 84 | *result = string + 1; 85 | } else if (result) 86 | *result = (char *)0; 87 | return(1); 88 | } 89 | -------------------------------------------------------------------------------- /runtests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright 2011 Shinichiro Hamaji. All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions 7 | # are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # 12 | # 2. Redistributions in binary form must reproduce the above 13 | # copyright notice, this list of conditions and the following 14 | # disclaimer in the documentation and/or other materials 15 | # provided with the distribution. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 18 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 21 | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 24 | # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 | # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | # SUCH DAMAGE. 29 | 30 | set -e 31 | 32 | # Run small unit tests 33 | 34 | for i in mach/*.bin; do 35 | echo "Running $i" 36 | ./ld-mac ./$i 37 | done 38 | 39 | # Run regressions tests with real compilers 40 | 41 | MAC_TOOL_DIR=/usr/i686-apple-darwin10 42 | MAC_BIN_DIR=$MAC_TOOL_DIR/usr/bin 43 | 44 | apple() { 45 | gcc="$1" 46 | shift 47 | PATH=$MAC_BIN_DIR ./ld-mac $MAC_BIN_DIR/$gcc --sysroot=$MAC_TOOL_DIR "$@" 48 | } 49 | 50 | # Run GCC with ld-mac 51 | 52 | echo "Running gcc -c mach/hello.c" 53 | ./ld-mac $MAC_BIN_DIR/gcc -c mach/hello.c 54 | echo "Running gcc mach/hello.c" 55 | ./ld-mac $MAC_BIN_DIR/gcc mach/hello.c 56 | echo "Running gcc -g mach/hello.c" 57 | PATH=$MAC_BIN_DIR ./ld-mac $MAC_BIN_DIR/gcc -g mach/hello.c 58 | 59 | # Run clang with ld-mac 60 | 61 | echo "Running clang -c mach/hello.c" 62 | ./ld-mac $MAC_BIN_DIR/clang -c mach/hello.c 63 | 64 | # Check dylib 65 | 66 | echo "Running dylib tests" 67 | 68 | apple gcc -g -dynamiclib mach/dylib/lib.c -o mach/dylib/lib.dylib 69 | apple gcc -g mach/dylib/main.c mach/dylib/lib.dylib -o mach/dylib/main 70 | 71 | echo "Running mach/dylib/main" 72 | ./ld-mac mach/dylib/main 73 | 74 | echo "Running dylib tests" 75 | 76 | apple gcc -g -dynamiclib mach/dylib/lib.c -o mach/dylib/lib.dylib 77 | apple gcc -g mach/dylib/main.c mach/dylib/lib.dylib -o mach/dylib/main 78 | 79 | echo "Running mach/dylib/main" 80 | ./ld-mac mach/dylib/main 81 | 82 | apple gcc -g mach/dylib/dlfcn.c -o mach/dylib/dlfcn 83 | 84 | echo "Running mach/dylib/dlfcn" 85 | ./ld-mac mach/dylib/dlfcn 86 | 87 | # Check dylib with weak symbols 88 | 89 | echo "Running dylib tests with a weak symbol" 90 | 91 | apple g++ -g -fPIC -dynamiclib mach/dylib/weak_lib.cc -o mach/dylib/weak_lib.dylib 92 | apple g++ -g -fPIC mach/dylib/weak_main.cc -o mach/dylib/weak_main mach/dylib/weak_lib.dylib 93 | apple g++ -g -fPIC mach/dylib/weak_main.cc -o mach/dylib/weak_main-dl -DDL 94 | 95 | echo "Running mach/dylib/weak_main" 96 | ./ld-mac mach/dylib/weak_main 97 | 98 | echo "Running mach/dylib/weak_main-dl" 99 | ./ld-mac mach/dylib/weak_main-dl 100 | 101 | # Compile and run unit tests with clang 102 | 103 | # Need this file from Xcode 4 104 | CLANG=$MAC_BIN_DIR/clang-137 105 | if [ -x $CLANG ]; then 106 | for i in mach/*.c; do 107 | echo "Compiling $i with clang" 108 | ./ld-mac $CLANG -Wl,-syslibroot,$MAC_TOOL_DIR -isysroot $MAC_TOOL_DIR $i -o $i.clang.bin 109 | echo "Running $i.clang.bin" 110 | ./ld-mac $i.clang.bin 111 | done 112 | else 113 | echo "$CLANG not found, skipping some tests with it" 114 | fi 115 | 116 | echo 117 | echo '*** ALL TESTS PASS ***' 118 | -------------------------------------------------------------------------------- /mach-o.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Shinichiro Hamaji. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions 5 | // are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following 12 | // disclaimer in the documentation and/or other materials 13 | // provided with the distribution. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 16 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 19 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 22 | // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | // SUCH DAMAGE. 27 | 28 | #ifndef MACH_O_H_ 29 | #define MACH_O_H_ 30 | 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | #include "mach-o/loader.h" 37 | 38 | using namespace std; 39 | 40 | class MachO { 41 | public: 42 | struct Rebase { 43 | uint64_t vmaddr; 44 | uint8_t type; 45 | }; 46 | 47 | struct Bind { 48 | uint64_t vmaddr; 49 | const char* name; 50 | union { 51 | int64_t addend; 52 | uint64_t value; 53 | }; 54 | uint8_t type; 55 | uint8_t ordinal; 56 | bool is_weak; 57 | bool is_classic; 58 | }; 59 | 60 | struct Export { 61 | string name; 62 | uint64_t addr; 63 | uint32_t flag; 64 | }; 65 | 66 | struct Symbol { 67 | string name; 68 | uint64_t addr; 69 | }; 70 | 71 | static MachO* read(const char* path, const char* arch, 72 | bool need_exports = true); 73 | 74 | virtual ~MachO() {} 75 | virtual void close() = 0; 76 | 77 | const string& filename() const { return filename_; } 78 | 79 | const vector& segments64() const { 80 | return segments64_; 81 | } 82 | 83 | const vector& segments() const { 84 | return segments_; 85 | } 86 | 87 | const vector& dylibs() const { return dylibs_; } 88 | 89 | const vector& rebases() const { return rebases_; } 90 | 91 | const vector& binds() const { return binds_; } 92 | 93 | const vector& exports() const { return exports_; } 94 | 95 | const vector& symbols() const { return symbols_; } 96 | 97 | const char* base() const { return base_; } 98 | 99 | uint64_t entry() const { return entry_; } 100 | 101 | uint64_t text_base() const { return text_base_; } 102 | 103 | bool is_lc_main_entry() const { return is_lc_main_entry_; } 104 | 105 | const vector& init_funcs() const { return init_funcs_; } 106 | 107 | uint64_t dyld_data() const { return dyld_data_; } 108 | 109 | bool is64() const { return is64_; } 110 | 111 | int fd() const { return fd_; } 112 | size_t offset() const { return offset_; } 113 | 114 | protected: 115 | string filename_; 116 | vector segments64_; 117 | vector segments_; 118 | vector dylibs_; 119 | vector rebases_; 120 | vector binds_; 121 | vector exports_; 122 | vector symbols_; 123 | const char* base_; 124 | uint64_t entry_; 125 | vector init_funcs_; 126 | uint64_t dyld_data_; 127 | bool is64_; 128 | int ptrsize_; 129 | int fd_; 130 | size_t offset_; 131 | uint64_t text_base_; 132 | bool is_lc_main_entry_; 133 | }; 134 | 135 | #endif // MACH_O_H_ 136 | -------------------------------------------------------------------------------- /unpack_xcode.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright 2011 Shinichiro Hamaji. All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions 7 | # are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # 12 | # 2. Redistributions in binary form must reproduce the above 13 | # copyright notice, this list of conditions and the following 14 | # disclaimer in the documentation and/or other materials 15 | # provided with the distribution. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 18 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 21 | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 24 | # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 | # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | # SUCH DAMAGE. 29 | # 30 | # Usage: 31 | # 32 | # %./unpack_xcode.sh xcode_3.2.6_and_ios_sdk_4.3__final.dmg 33 | # 34 | # The above commandline will put CLI tools in the dmg package into 35 | # ./xcode_3.2.6_and_ios_sdk_4.3__final/root . 36 | # 37 | # This script was inspired by this document: 38 | # http://devs.openttd.org/~truebrain/compile-farm/apple-darwin9.txt 39 | 40 | set -e 41 | 42 | dmg=$1 43 | dir=`basename $dmg .dmg` 44 | 45 | HFS=5.hfs 46 | if echo $dmg | grep xcode_5.0; then 47 | # Tested with xcode_5.0.1_command_line_tools 48 | PKGS="MacOSX10_9_SDK CLTools_Executables" 49 | XCODE=xcode_5.0 50 | PKG_DIR="Command Line Developer Tools/Packages" 51 | HFS=3.hfs 52 | elif echo $dmg | grep xcode_4.4; then 53 | # Tested with xcode_4.4.1_command_line_tools 54 | PKGS="DevSDK DeveloperToolsCLI clang llvm-gcc4.2" 55 | XCODE=xcode_4.4 56 | PKG_DIR="Command Line Tools*/Packages" 57 | HFS=3.hfs 58 | elif echo $dmg | grep xcode_4.3; then 59 | # Tested with xcode_4.3.3_command_line_tools 60 | PKGS="DevSDK DeveloperToolsCLI clang llvm-gcc4.2" 61 | XCODE=xcode_4.3 62 | PKG_DIR="Command Line Tools*/Packages" 63 | elif echo $dmg | grep xcode_4.1; then 64 | PKGS="MacOSX10.6 gcc4.2 llvm-gcc4.2 DeveloperToolsCLI clang" 65 | XCODE=xcode_4.1 66 | PKG_DIR="Applications/Install Xcode.app/Contents/Resources/Packages" 67 | elif echo $dmg | grep xcode_3; then 68 | PKGS="MacOSX10.6 gcc4.2 gcc4.0 llvm-gcc4.2 DeveloperToolsCLI clang" 69 | XCODE=xcode_3 70 | PKG_DIR="*/Packages" 71 | elif echo $dmg | grep xcode_4.; then 72 | # Tested with xcode_4.6.2_command_line_tools 73 | # Tested with xcode_4.5.2_command_line_tools 74 | PKGS="DevSDK DeveloperToolsCLI" 75 | XCODE=xcode_4.6 76 | PKG_DIR="Command Line Tools*/Packages" 77 | HFS=3.hfs 78 | else 79 | PKGS="MacOSX10.6 gcc4.2 llvm-gcc4.2 DeveloperToolsCLI clang" 80 | XCODE=xcode_4.0 81 | PKG_DIR="*/Packages" 82 | fi 83 | 84 | rm -fr $dir 85 | mkdir $dir 86 | cd $dir 87 | 88 | 7z x $dmg 89 | 7z x $HFS 90 | 91 | if [ $XCODE = "xcode_4.1" ]; then 92 | 7z x -y "Install Xcode/InstallXcode.pkg" 93 | 7z x -y InstallXcode.pkg/Payload 94 | fi 95 | 96 | for pkg in $PKGS; do 97 | 7z x -y "$PKG_DIR/$pkg.pkg" 98 | 7z x -y Payload 99 | mkdir -p $pkg 100 | cd $pkg 101 | cpio -i < ../Payload~ 102 | cd .. 103 | rm -f Payload* 104 | done 105 | 106 | rm -fr root 107 | mkdir root 108 | for pkg in $PKGS; do 109 | if [ $pkg = "MacOSX10.6" ]; then 110 | cp -R $pkg/SDKs/*/* root 111 | else 112 | cd $pkg || continue 113 | if [ $pkg = "CLTools_Executables" ]; then 114 | mv Library Library- 115 | mv Library-/Developer/CommandLineTools/* . 116 | rm -fr Library- 117 | fi 118 | tar -c * | tar -xC ../root 119 | cd .. 120 | fi 121 | done 122 | 123 | ln -sf "../../System/Library/Frameworks root/Library/Frameworks" 124 | cd root/usr/lib 125 | ln -s system/* . 126 | 127 | echo "The package was unpacked into $dir/root" 128 | -------------------------------------------------------------------------------- /rename.tab: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Shinichiro Hamaji. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions 5 | // are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following 12 | // disclaimer in the documentation and/or other materials 13 | // provided with the distribution. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 16 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 19 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 22 | // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | // SUCH DAMAGE. 27 | 28 | // A translation table from Mac symbols to Linux's. 29 | 30 | RENAME(__stderrp, __darwin_stderr) 31 | RENAME(__stdoutp, __darwin_stdout) 32 | RENAME(__stdinp, __darwin_stdin) 33 | WRAP(stderr) 34 | WRAP(stdout) 35 | WRAP(stdin) 36 | 37 | WRAP(fopen) 38 | WRAP(fdopen) 39 | WRAP(freopen) 40 | WRAP(fclose) 41 | WRAP(fread) 42 | WRAP(fwrite) 43 | WRAP(fseek) 44 | WRAP(fseeko) 45 | WRAP(fseeko64) 46 | WRAP(ftell) 47 | WRAP(rewind) 48 | WRAP(getc) 49 | WRAP(fgetc) 50 | WRAP(ungetc) 51 | WRAP(fgets) 52 | WRAP(putc) 53 | WRAP(fputc) 54 | WRAP(fputs) 55 | WRAP(fscanf) 56 | WRAP(vfscanf) 57 | WRAP(fprintf) 58 | WRAP(vfprintf) 59 | WRAP(fflush) 60 | WRAP(setbuf) 61 | WRAP(setbuffer) 62 | WRAP(ferror) 63 | RENAME(_ferror, __darwin_ferror) 64 | WRAP(feof) 65 | WRAP(fileno) 66 | WRAP(tmpfile) 67 | WRAP(fgetln) 68 | 69 | RENAME(__srget, __darwin_fgetc) 70 | RENAME(__swbuf, __darwin_fputc) 71 | 72 | RENAME(__toupper, toupper) 73 | RENAME(__tolower, tolower) 74 | 75 | RENAME(opendir$INODE64, opendir) 76 | RENAME(readdir$INODE64, __darwin_readdir64) 77 | WRAP(readdir) 78 | 79 | WRAP(stat) 80 | WRAP(fstat) 81 | WRAP(lstat) 82 | RENAME(stat$INODE64, __darwin_stat64) 83 | RENAME(fstat$INODE64, __darwin_fstat64) 84 | RENAME(lstat$INODE64, __darwin_lstat64) 85 | 86 | RENAME(statfs$INODE64, __darwin_statfs64) 87 | RENAME(fstatfs$INODE64, __darwin_fstatfs64) 88 | 89 | WRAP(open) 90 | 91 | WRAP(mmap) 92 | WRAP(sysctl) 93 | WRAP(fcntl) 94 | 95 | RENAME(realpath$DARWIN_EXTSN, realpath) 96 | 97 | WRAP(execv) 98 | WRAP(execvp) 99 | WRAP(execl) 100 | WRAP(execlp) 101 | WRAP(execve) 102 | WRAP(execle) 103 | WRAP(posix_spawn) 104 | WRAP(posix_spawnp) 105 | 106 | WRAP(posix_spawn_file_actions_init) 107 | WRAP(posix_spawn_file_actions_destroy) 108 | WRAP(posix_spawn_file_actions_addopen) 109 | WRAP(posix_spawn_file_actions_addclose) 110 | WRAP(posix_spawn_file_actions_adddup2) 111 | 112 | RENAME(CC_MD5_Init, MD5_Init) 113 | RENAME(CC_MD5_Update, MD5_Update) 114 | RENAME(CC_MD5_Final, MD5_Final) 115 | RENAME(CC_MD5, MD5) 116 | 117 | WRAP(__cxa_throw) 118 | 119 | RENAME(atexit, __cxa_atexit) 120 | 121 | WRAP(signal) 122 | WRAP(sigaction) 123 | WRAP(sigaltstack) 124 | WRAP(sigprocmask) 125 | WRAP(sigfillset); 126 | WRAP(pthread_sigmask) 127 | 128 | #ifdef __x86_64__ 129 | RENAME(__ashldi3, __ashlti3) 130 | RENAME(__ashrdi3, __ashrti3) 131 | RENAME(__cmpdi2, __cmpti2) 132 | RENAME(__divdi3, __divti3) 133 | RENAME(__fixdfdi, __fixdfti) 134 | RENAME(__fixsfdi, __fixsfti) 135 | RENAME(__floatdidf, __floattidf) 136 | RENAME(__floatdisf, __floattisf) 137 | RENAME(__lshrdi3, __lshrti3) 138 | RENAME(__moddi3, __modti3) 139 | RENAME(__udivdi3, __udivti3) 140 | RENAME(__umoddi3, __umodti3) 141 | #endif 142 | 143 | // TODO(hamaji): *attr_gettype and *attr_getpshared 144 | WRAP(pthread_mutexattr_settype) 145 | WRAP(pthread_mutexattr_setpshared) 146 | WRAP(pthread_rwlockattr_setpshared) 147 | 148 | // Do we need workaround for other initializer macro? 149 | WRAP(pthread_mutex_lock) 150 | 151 | WRAP(dlopen) 152 | WRAP(dlclose) 153 | WRAP(dlerror) 154 | WRAP(dlsym) 155 | // TODO(hamaji): dladdr? 156 | 157 | RENAME(_ZNSt12__basic_fileIcE8sys_openEP7__sFILESt13_Ios_Openmode, 158 | _ZNSt12__basic_fileIcE8sys_openEP8_IO_FILESt13_Ios_Openmode) 159 | 160 | WRAP(uname) 161 | 162 | // TODO(hamaji): Not sure if this is right... 163 | RENAME(select$1050, select) 164 | 165 | WRAP(qsort_r) 166 | 167 | WRAP(newlocale) 168 | 169 | WRAP(compat_mode) 170 | 171 | WRAP(gethostuuid) 172 | 173 | WRAP(_ZNSt3__15mutex4lockEv) 174 | -------------------------------------------------------------------------------- /include/mach/vm_prot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. The rights granted to you under the License 10 | * may not be used to create, or enable the creation or redistribution of, 11 | * unlawful or unlicensed copies of an Apple operating system, or to 12 | * circumvent, violate, or enable the circumvention or violation of, any 13 | * terms of an Apple operating system software license agreement. 14 | * 15 | * Please obtain a copy of the License at 16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 | * 18 | * The Original Code and all software distributed under the License are 19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 | * Please see the License for the specific language governing rights and 24 | * limitations under the License. 25 | * 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 | */ 28 | /* 29 | * @OSF_COPYRIGHT@ 30 | */ 31 | /* 32 | * Mach Operating System 33 | * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University 34 | * All Rights Reserved. 35 | * 36 | * Permission to use, copy, modify and distribute this software and its 37 | * documentation is hereby granted, provided that both the copyright 38 | * notice and this permission notice appear in all copies of the 39 | * software, derivative works or modified versions, and any portions 40 | * thereof, and that both notices appear in supporting documentation. 41 | * 42 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 43 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 44 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 45 | * 46 | * Carnegie Mellon requests users of this software to return to 47 | * 48 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 49 | * School of Computer Science 50 | * Carnegie Mellon University 51 | * Pittsburgh PA 15213-3890 52 | * 53 | * any improvements or extensions that they make and grant Carnegie Mellon 54 | * the rights to redistribute these changes. 55 | */ 56 | /* 57 | */ 58 | /* 59 | * File: mach/vm_prot.h 60 | * Author: Avadis Tevanian, Jr., Michael Wayne Young 61 | * 62 | * Virtual memory protection definitions. 63 | * 64 | */ 65 | 66 | #ifndef _MACH_VM_PROT_H_ 67 | #define _MACH_VM_PROT_H_ 68 | 69 | /* 70 | * Types defined: 71 | * 72 | * vm_prot_t VM protection values. 73 | */ 74 | 75 | typedef int vm_prot_t; 76 | 77 | /* 78 | * Protection values, defined as bits within the vm_prot_t type 79 | */ 80 | 81 | #define VM_PROT_NONE ((vm_prot_t) 0x00) 82 | 83 | #define VM_PROT_READ ((vm_prot_t) 0x01) /* read permission */ 84 | #define VM_PROT_WRITE ((vm_prot_t) 0x02) /* write permission */ 85 | #define VM_PROT_EXECUTE ((vm_prot_t) 0x04) /* execute permission */ 86 | 87 | /* 88 | * The default protection for newly-created virtual memory 89 | */ 90 | 91 | #define VM_PROT_DEFAULT (VM_PROT_READ|VM_PROT_WRITE) 92 | 93 | /* 94 | * The maximum privileges possible, for parameter checking. 95 | */ 96 | 97 | #define VM_PROT_ALL (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE) 98 | 99 | /* 100 | * An invalid protection value. 101 | * Used only by memory_object_lock_request to indicate no change 102 | * to page locks. Using -1 here is a bad idea because it 103 | * looks like VM_PROT_ALL and then some. 104 | */ 105 | 106 | #define VM_PROT_NO_CHANGE ((vm_prot_t) 0x08) 107 | 108 | /* 109 | * When a caller finds that he cannot obtain write permission on a 110 | * mapped entry, the following flag can be used. The entry will 111 | * be made "needs copy" effectively copying the object (using COW), 112 | * and write permission will be added to the maximum protections 113 | * for the associated entry. 114 | */ 115 | 116 | #define VM_PROT_COPY ((vm_prot_t) 0x10) 117 | 118 | 119 | /* 120 | * Another invalid protection value. 121 | * Used only by memory_object_data_request upon an object 122 | * which has specified a copy_call copy strategy. It is used 123 | * when the kernel wants a page belonging to a copy of the 124 | * object, and is only asking the object as a result of 125 | * following a shadow chain. This solves the race between pages 126 | * being pushed up by the memory manager and the kernel 127 | * walking down the shadow chain. 128 | */ 129 | 130 | #define VM_PROT_WANTS_COPY ((vm_prot_t) 0x10) 131 | 132 | 133 | #endif /* _MACH_VM_PROT_H_ */ 134 | -------------------------------------------------------------------------------- /include/mac-ctype.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000, 2005, 2008 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | /* 24 | * Copyright (c) 1989, 1993 25 | * The Regents of the University of California. All rights reserved. 26 | * (c) UNIX System Laboratories, Inc. 27 | * All or some portions of this file are derived from material licensed 28 | * to the University of California by American Telephone and Telegraph 29 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with 30 | * the permission of UNIX System Laboratories, Inc. 31 | * 32 | * This code is derived from software contributed to Berkeley by 33 | * Paul Borman at Krystal Technologies. 34 | * 35 | * Redistribution and use in source and binary forms, with or without 36 | * modification, are permitted provided that the following conditions 37 | * are met: 38 | * 1. Redistributions of source code must retain the above copyright 39 | * notice, this list of conditions and the following disclaimer. 40 | * 2. Redistributions in binary form must reproduce the above copyright 41 | * notice, this list of conditions and the following disclaimer in the 42 | * documentation and/or other materials provided with the distribution. 43 | * 3. All advertising materials mentioning features or use of this software 44 | * must display the following acknowledgement: 45 | * This product includes software developed by the University of 46 | * California, Berkeley and its contributors. 47 | * 4. Neither the name of the University nor the names of its contributors 48 | * may be used to endorse or promote products derived from this software 49 | * without specific prior written permission. 50 | * 51 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 | * SUCH DAMAGE. 62 | * 63 | * @(#)ctype.h 8.4 (Berkeley) 1/21/94 64 | */ 65 | 66 | #ifndef MAC_CTYPE_H_ 67 | #define MAC_CTYPE_H_ 68 | 69 | #define _CTYPE_A 0x00000100L /* Alpha */ 70 | #define _CTYPE_C 0x00000200L /* Control */ 71 | #define _CTYPE_D 0x00000400L /* Digit */ 72 | #define _CTYPE_G 0x00000800L /* Graph */ 73 | #define _CTYPE_L 0x00001000L /* Lower */ 74 | #define _CTYPE_P 0x00002000L /* Punct */ 75 | #define _CTYPE_S 0x00004000L /* Space */ 76 | #define _CTYPE_U 0x00008000L /* Upper */ 77 | #define _CTYPE_X 0x00010000L /* X digit */ 78 | #define _CTYPE_B 0x00020000L /* Blank */ 79 | #define _CTYPE_R 0x00040000L /* Print */ 80 | #define _CTYPE_I 0x00080000L /* Ideogram */ 81 | #define _CTYPE_T 0x00100000L /* Special */ 82 | #define _CTYPE_Q 0x00200000L /* Phonogram */ 83 | 84 | /* 85 | * Backward compatibility 86 | */ 87 | #define _A _CTYPE_A /* Alpha */ 88 | #define _C _CTYPE_C /* Control */ 89 | #define _D _CTYPE_D /* Digit */ 90 | #define _G _CTYPE_G /* Graph */ 91 | #define _L _CTYPE_L /* Lower */ 92 | #define _P _CTYPE_P /* Punct */ 93 | #define _S _CTYPE_S /* Space */ 94 | #define _U _CTYPE_U /* Upper */ 95 | #define _X _CTYPE_X /* X digit */ 96 | #define _B _CTYPE_B /* Blank */ 97 | #define _R _CTYPE_R /* Print */ 98 | #define _I _CTYPE_I /* Ideogram */ 99 | #define _T _CTYPE_T /* Special */ 100 | #define _Q _CTYPE_Q /* Phonogram */ 101 | 102 | #endif /* !MAC_CTYPE_H_ */ 103 | -------------------------------------------------------------------------------- /include/runetype.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 1993 3 | * The Regents of the University of California. All rights reserved. 4 | * 5 | * This code is derived from software contributed to Berkeley by 6 | * Paul Borman at Krystal Technologies. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. All advertising materials mentioning features or use of this software 17 | * must display the following acknowledgement: 18 | * This product includes software developed by the University of 19 | * California, Berkeley and its contributors. 20 | * 4. Neither the name of the University nor the names of its contributors 21 | * may be used to endorse or promote products derived from this software 22 | * without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 | * SUCH DAMAGE. 35 | * 36 | * @(#)runetype.h 8.1 (Berkeley) 6/2/93 37 | */ 38 | 39 | #ifndef _RUNETYPE_H_ 40 | #define _RUNETYPE_H_ 41 | 42 | #include <_types.h> 43 | #include 44 | 45 | typedef wchar_t __darwin_rune_t; 46 | typedef size_t __darwin_size_t; 47 | 48 | #if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE) 49 | 50 | #ifndef _SIZE_T 51 | #define _SIZE_T 52 | typedef __darwin_size_t size_t; 53 | #endif 54 | 55 | #ifndef _CT_RUNE_T 56 | #define _CT_RUNE_T 57 | typedef __darwin_ct_rune_t ct_rune_t; 58 | #endif 59 | 60 | #ifndef _RUNE_T 61 | #define _RUNE_T 62 | typedef __darwin_rune_t rune_t; 63 | #endif 64 | 65 | #ifndef __cplusplus 66 | #ifndef _WCHAR_T 67 | #define _WCHAR_T 68 | typedef __darwin_wchar_t wchar_t; 69 | #endif /* _WCHAR_T */ 70 | #endif /* __cplusplus */ 71 | 72 | #ifndef _WINT_T 73 | #define _WINT_T 74 | typedef __darwin_wint_t wint_t; 75 | #endif 76 | 77 | #endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */ 78 | 79 | #define _CACHED_RUNES (1 <<8 ) /* Must be a power of 2 */ 80 | #define _CRMASK (~(_CACHED_RUNES - 1)) 81 | 82 | /* 83 | * The lower 8 bits of runetype[] contain the digit value of the rune. 84 | */ 85 | typedef struct { 86 | __darwin_rune_t __min; /* First rune of the range */ 87 | __darwin_rune_t __max; /* Last rune (inclusive) of the range */ 88 | __darwin_rune_t __map; /* What first maps to in maps */ 89 | uint32_t *__types; /* Array of types in range */ 90 | } _RuneEntry; 91 | 92 | typedef struct { 93 | int __nranges; /* Number of ranges stored */ 94 | _RuneEntry *__ranges; /* Pointer to the ranges */ 95 | } _RuneRange; 96 | 97 | typedef struct { 98 | char __name[14]; /* CHARCLASS_NAME_MAX = 14 */ 99 | uint32_t __mask; /* charclass mask */ 100 | } _RuneCharClass; 101 | 102 | typedef struct { 103 | char __magic[8]; /* Magic saying what version we are */ 104 | char __encoding[32]; /* ASCII name of this encoding */ 105 | 106 | __darwin_rune_t (*__sgetrune)(const char *, __darwin_size_t, char const **); 107 | int (*__sputrune)(__darwin_rune_t, char *, __darwin_size_t, char **); 108 | __darwin_rune_t __invalid_rune; 109 | 110 | uint32_t __runetype[_CACHED_RUNES]; 111 | __darwin_rune_t __maplower[_CACHED_RUNES]; 112 | __darwin_rune_t __mapupper[_CACHED_RUNES]; 113 | 114 | /* 115 | * The following are to deal with Runes larger than _CACHED_RUNES - 1. 116 | * Their data is actually contiguous with this structure so as to make 117 | * it easier to read/write from/to disk. 118 | */ 119 | _RuneRange __runetype_ext; 120 | _RuneRange __maplower_ext; 121 | _RuneRange __mapupper_ext; 122 | 123 | void *__variable; /* Data which depends on the encoding */ 124 | int __variable_len; /* how long that data is */ 125 | 126 | /* 127 | * extra fields to deal with arbitrary character classes 128 | */ 129 | int __ncharclasses; 130 | _RuneCharClass *__charclasses; 131 | } _RuneLocale; 132 | 133 | #define _RUNE_MAGIC_A "RuneMagA" /* Indicates version A of RuneLocale */ 134 | 135 | __BEGIN_DECLS 136 | extern _RuneLocale _DefaultRuneLocale; 137 | extern _RuneLocale *_CurrentRuneLocale; 138 | __END_DECLS 139 | 140 | #endif /* !_RUNETYPE_H_ */ 141 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Maloader [![Build Status](https://travis-ci.org/shinh/maloader.svg)](https://travis-ci.org/shinh/maloader) 2 | This is a userland Mach-O loader for linux. 3 | 4 | ## Installation 5 | 6 | ```bash 7 | $ make release 8 | ``` 9 | ## Usage 10 | 11 | ```bash 12 | $ ./ld-mac mac_binary [options...] 13 | ``` 14 | You need OpenCFLite (http://sourceforge.net/projects/opencflite/) 15 | installed if you want to run some programs such as dsymutil. 16 | opencflite-476.17.2 is recommended. 17 | 18 | ## How to use compiler toolchains of Xcode 19 | 20 | Recent Xcode toolchains are built by clang/libc++. This means some C++ 21 | programs do not work with ld-mac linked against libstdc++. To build 22 | ld-mac with clang/libc++, run 23 | 24 | ```bash 25 | $ make clean 26 | $ make USE_LIBCXX=1 27 | ``` 28 | You need compiler toolchain binaries on your Linux. unpack_xcode.sh in 29 | this repository helps you to set up them if you have a dmg package of 30 | Xcode. This script was checked with Xcode 4.3.3, 4.4.1, 4.5.2, 4.6.2, 31 | and 5.0.1. It would work even on other Xcode releases, but you may 32 | need to modify the script by yourself. How things are stored in dmg 33 | packages heavily depend on the version of Xcode. You can use this like 34 | 35 | ```bash 36 | $ ./unpack_xcode.sh ~/Downloads/xcode_5.0.1_command_line_tools*.dmg 37 | ``` 38 | 39 | This will create xcode_5.0.1_command_line_tools*/root. We will call 40 | this directory as $ROOT. 41 | 42 | ```bash 43 | $ ./ld-mac $ROOT/usr/bin/clang --sysroot=$ROOT -c mach/hello.c 44 | $ file hello.o 45 | hello.o: Mach-O 64-bit x86_64 object 46 | ``` 47 | To link binaries on Linux, you also need necessary dylibs in 48 | root/usr/lib. For example, simple hello world program requires 49 | /usr/lib/libSystem.dylib and /usr/lib/system. Do something like 50 | 51 | ```bash 52 | (mac)$ tar -cvzf sys.tgz /usr/lib/libSystem* /usr/lib/system 53 | (mac)$ scp sys.tgz $USER@linux:/tmp 54 | (linux)$ cd $ROOT && tar -xvzf /tmp/sys.tgz 55 | ``` 56 | Also note that it seems ld does not like the version number of 57 | Xcode. So you need to move xcode_5.0.1_command_line_tools*/root to 58 | somewhere else. For example: 59 | 60 | ```bash 61 | $ ln -sf xcode_5.0.1_command_line_tools_10.9_20131022/root 62 | $ ./ld-mac $ROOT/usr/bin/clang --sysroot=$ROOT -g mach/hello.c 63 | $ ./ld-mac ./a.out 64 | Hello, 64bit world! 65 | ``` 66 | ## How to use compiler toolchains of Xcode 3.2.6 67 | 68 | Get xcode_3.2.6_and_ios_sdk_4.3__final.dmg (or another xcode package). 69 | 70 | ```bash 71 | $ git clone git@github.com:shinh/maloader.git 72 | $ ./maloader/unpack_xcode.sh xcode_3.2.6_and_ios_sdk_4.3__final.dmg 73 | $ sudo cp -a xcode_3.2.6_and_ios_sdk_4.3__final/root /usr/i686-apple-darwin10 74 | $ cd maloader 75 | $ make release 76 | $ ./ld-mac /usr/i686-apple-darwin10/usr/bin/gcc mach/hello.c 77 | $ ./ld-mac a.out 78 | ``` 79 | 80 | ## How to run Mach-O binaries using binfmt_misc 81 | ```bash 82 | $ ./binfmt_misc.sh 83 | $ /usr/i686-apple-darwin10/usr/bin/gcc mach/hello.c 84 | $ ./a.out 85 | ``` 86 | To remove the entries, run the following command: 87 | 88 | ```bash 89 | $ ./binfmt_misc.sh stop 90 | ``` 91 | 92 | ## How to try 32bit support 93 | 94 | ```bash 95 | $ make clean 96 | $ make all BITS=32 97 | ``` 98 | If you see permission errors like: 99 | 100 | ```bash 101 | ld-mac: ./mach/hello.c.bin mmap(file) failed: Operation not permitted 102 | ``` 103 | you should run the following command to allow users to mmap files to 104 | addresses less than 0x10000. 105 | 106 | ```bash 107 | $ sudo sh -c 'echo 4096 > /proc/sys/vm/mmap_min_addr' 108 | ``` 109 | Or, running ld-mac as a super user would also work. 110 | 111 | ## How to run both 64bit Mach-O and 32bit Mach-O binaries 112 | ```bash 113 | $ make both 114 | $ ./binfmt_misc.sh start `pwd`/ld-mac.sh 115 | $ /usr/i686-apple-darwin10/usr/bin/gcc -arch i386 mach/hello.c -o hello32 116 | $ /usr/i686-apple-darwin10/usr/bin/gcc -arch x86_64 mach/hello.c -o hello64 117 | $ /usr/i686-apple-darwin10/usr/bin/gcc -arch i386 -arch x86_64 mach/hello.c -o hello 118 | $ ./hello32 119 | Hello, 32bit world! 120 | $ ./hello64 121 | Hello, 64bit world! 122 | $ ./hello 123 | Hello, 64bit world! 124 | $ LD_MAC_BITS=32 ./hello 125 | Hello, 32bit world! 126 | ``` 127 | 128 | ## Which programs should work 129 | 130 | OK 131 | 132 | - gcc-4.2 (link with -g requires OpenCFLite) 133 | - otool 134 | - nm 135 | - dyldinfo 136 | - dwarfdump 137 | - strip 138 | - size 139 | - dsymutil (need OpenCFLite) 140 | - cpp-4.2 141 | - clang 142 | 143 | not OK 144 | 145 | - llvm-gcc 146 | - gnumake and bsdmake 147 | - lex and flex 148 | - ar 149 | - m4 150 | - gdb 151 | - libtool 152 | - nasm and ndisasm (i386) 153 | - mpicc, mpicxx, and mpic++ 154 | 155 | ## Notice 156 | 157 | - Running all Mac binaries isn't my goal. Only command line tools such 158 | as compiler tool chain can be executed by this loader. 159 | - A slide about this: http://shinh.skr.jp/slide/ldmac/000.html 160 | 161 | ## TODO 162 | 163 | - read dwarf for better backtracing 164 | - make llvm-gcc work 165 | - improve 32bit support 166 | - handle dwarf and C++ exception 167 | 168 | ## License 169 | 170 | Simplified BSD License or GPLv3. 171 | 172 | Note that all files in "include" directory and some files in "libmac" 173 | were copied from Apple's Libc-594.9.1. 174 | http://www.opensource.apple.com/release/mac-os-x-1064/ 175 | 176 | See http://www.gnu.org/licenses/gpl-3.0.txt for GPLv3. 177 | -------------------------------------------------------------------------------- /libmac/strmode.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: strmode.c,v 1.5 2004/08/23 03:32:12 jlam Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 1990, 1993 5 | * The Regents of the University of California. All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 3. Neither the name of the University nor the names of its contributors 16 | * may be used to endorse or promote products derived from this software 17 | * without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | * SUCH DAMAGE. 30 | */ 31 | 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | 38 | void 39 | strmode(mode, p) 40 | mode_t mode; 41 | char *p; 42 | { 43 | 44 | assert(p != NULL); 45 | 46 | /* print type */ 47 | switch (mode & S_IFMT) { 48 | case S_IFDIR: /* directory */ 49 | *p++ = 'd'; 50 | break; 51 | case S_IFCHR: /* character special */ 52 | *p++ = 'c'; 53 | break; 54 | case S_IFBLK: /* block special */ 55 | *p++ = 'b'; 56 | break; 57 | case S_IFREG: /* regular */ 58 | #ifdef S_ARCH2 59 | if ((mode & S_ARCH2) != 0) { 60 | *p++ = 'A'; 61 | } else if ((mode & S_ARCH1) != 0) { 62 | *p++ = 'a'; 63 | } else { 64 | #endif 65 | *p++ = '-'; 66 | #ifdef S_ARCH2 67 | } 68 | #endif 69 | break; 70 | case S_IFLNK: /* symbolic link */ 71 | *p++ = 'l'; 72 | break; 73 | #ifdef S_IFSOCK 74 | case S_IFSOCK: /* socket */ 75 | *p++ = 's'; 76 | break; 77 | #endif 78 | #ifdef S_IFIFO 79 | case S_IFIFO: /* fifo */ 80 | *p++ = 'p'; 81 | break; 82 | #endif 83 | #ifdef S_IFWHT 84 | case S_IFWHT: /* whiteout */ 85 | *p++ = 'w'; 86 | break; 87 | #endif 88 | #ifdef S_IFDOOR 89 | case S_IFDOOR: /* door */ 90 | *p++ = 'D'; 91 | break; 92 | #endif 93 | default: /* unknown */ 94 | *p++ = '?'; 95 | break; 96 | } 97 | /* usr */ 98 | if (mode & S_IRUSR) 99 | *p++ = 'r'; 100 | else 101 | *p++ = '-'; 102 | if (mode & S_IWUSR) 103 | *p++ = 'w'; 104 | else 105 | *p++ = '-'; 106 | switch (mode & (S_IXUSR | S_ISUID)) { 107 | case 0: 108 | *p++ = '-'; 109 | break; 110 | case S_IXUSR: 111 | *p++ = 'x'; 112 | break; 113 | case S_ISUID: 114 | *p++ = 'S'; 115 | break; 116 | case S_IXUSR | S_ISUID: 117 | *p++ = 's'; 118 | break; 119 | } 120 | /* group */ 121 | if (mode & S_IRGRP) 122 | *p++ = 'r'; 123 | else 124 | *p++ = '-'; 125 | if (mode & S_IWGRP) 126 | *p++ = 'w'; 127 | else 128 | *p++ = '-'; 129 | switch (mode & (S_IXGRP | S_ISGID)) { 130 | case 0: 131 | *p++ = '-'; 132 | break; 133 | case S_IXGRP: 134 | *p++ = 'x'; 135 | break; 136 | case S_ISGID: 137 | *p++ = 'S'; 138 | break; 139 | case S_IXGRP | S_ISGID: 140 | *p++ = 's'; 141 | break; 142 | } 143 | /* other */ 144 | if (mode & S_IROTH) 145 | *p++ = 'r'; 146 | else 147 | *p++ = '-'; 148 | if (mode & S_IWOTH) 149 | *p++ = 'w'; 150 | else 151 | *p++ = '-'; 152 | switch (mode & (S_IXOTH | S_ISVTX)) { 153 | case 0: 154 | *p++ = '-'; 155 | break; 156 | case S_IXOTH: 157 | *p++ = 'x'; 158 | break; 159 | case S_ISVTX: 160 | *p++ = 'T'; 161 | break; 162 | case S_IXOTH | S_ISVTX: 163 | *p++ = 't'; 164 | break; 165 | } 166 | *p++ = ' '; /* will be a '+' if ACL's implemented */ 167 | *p = '\0'; 168 | } 169 | -------------------------------------------------------------------------------- /libmac/runetable.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * The contents of this file constitute Original Code as defined in and 7 | * are subject to the Apple Public Source License Version 1.1 (the 8 | * "License"). You may not use this file except in compliance with the 9 | * License. Please obtain a copy of the License at 10 | * http://www.apple.com/publicsource and read it before using this file. 11 | * 12 | * This Original Code and all software distributed under the License are 13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 | * License for the specific language governing rights and limitations 18 | * under the License. 19 | * 20 | * @APPLE_LICENSE_HEADER_END@ 21 | */ 22 | /* 23 | * Copyright (c) 1993 24 | * The Regents of the University of California. All rights reserved. 25 | * 26 | * This code is derived from software contributed to Berkeley by 27 | * Paul Borman at Krystal Technologies. 28 | * 29 | * Redistribution and use in source and binary forms, with or without 30 | * modification, are permitted provided that the following conditions 31 | * are met: 32 | * 1. Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above copyright 35 | * notice, this list of conditions and the following disclaimer in the 36 | * documentation and/or other materials provided with the distribution. 37 | * 3. All advertising materials mentioning features or use of this software 38 | * must display the following acknowledgement: 39 | * This product includes software developed by the University of 40 | * California, Berkeley and its contributors. 41 | * 4. Neither the name of the University nor the names of its contributors 42 | * may be used to endorse or promote products derived from this software 43 | * without specific prior written permission. 44 | * 45 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 46 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 49 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 | * SUCH DAMAGE. 56 | */ 57 | 58 | _RuneLocale _DefaultRuneLocale = { 59 | _RUNE_MAGIC_A, 60 | "none", 61 | _none_sgetrune, 62 | _none_sputrune, 63 | 0xFFFD, 64 | 65 | { /*00*/ _C, _C, _C, _C, 66 | _C, _C, _C, _C, 67 | /*08*/ _C, _C|_S|_B, _C|_S, _C|_S, 68 | _C|_S, _C|_S, _C, _C, 69 | /*10*/ _C, _C, _C, _C, 70 | _C, _C, _C, _C, 71 | /*18*/ _C, _C, _C, _C, 72 | _C, _C, _C, _C, 73 | /*20*/ _S|_B|_R, _P|_R|_G, _P|_R|_G, _P|_R|_G, 74 | _P|_R|_G, _P|_R|_G, _P|_R|_G, _P|_R|_G, 75 | /*28*/ _P|_R|_G, _P|_R|_G, _P|_R|_G, _P|_R|_G, 76 | _P|_R|_G, _P|_R|_G, _P|_R|_G, _P|_R|_G, 77 | /*30*/ _D|_R|_G|_X|0, _D|_R|_G|_X|1, _D|_R|_G|_X|2, _D|_R|_G|_X|3, 78 | _D|_R|_G|_X|4, _D|_R|_G|_X|5, _D|_R|_G|_X|6, _D|_R|_G|_X|7, 79 | /*38*/ _D|_R|_G|_X|8, _D|_R|_G|_X|9, _P|_R|_G, _P|_R|_G, 80 | _P|_R|_G, _P|_R|_G, _P|_R|_G, _P|_R|_G, 81 | /*40*/ _P|_R|_G, _U|_X|_R|_G|_A|10, _U|_X|_R|_G|_A|11, _U|_X|_R|_G|_A|12, 82 | _U|_X|_R|_G|_A|13, _U|_X|_R|_G|_A|14, _U|_X|_R|_G|_A|15, _U|_R|_G|_A, 83 | /*48*/ _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, 84 | _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, 85 | /*50*/ _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, 86 | _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, 87 | /*58*/ _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, _P|_R|_G, 88 | _P|_R|_G, _P|_R|_G, _P|_R|_G, _P|_R|_G, 89 | /*60*/ _P|_R|_G, _L|_X|_R|_G|_A|10, _L|_X|_R|_G|_A|11, _L|_X|_R|_G|_A|12, 90 | _L|_X|_R|_G|_A|13, _L|_X|_R|_G|_A|14, _L|_X|_R|_G|_A|15, _L|_R|_G|_A, 91 | /*68*/ _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, 92 | _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, 93 | /*70*/ _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, 94 | _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, 95 | /*78*/ _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, _P|_R|_G, 96 | _P|_R|_G, _P|_R|_G, _P|_R|_G, _C, 97 | }, 98 | { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 99 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 100 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 101 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 102 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 103 | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 104 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 105 | 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 106 | 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 107 | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 108 | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 109 | 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 110 | 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 111 | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 112 | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 113 | 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 114 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 115 | 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 116 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 117 | 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 118 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 119 | 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 120 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 121 | 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 122 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 123 | 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 124 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 125 | 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 126 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 127 | 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 128 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 129 | 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 130 | }, 131 | { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 132 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 133 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 134 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 135 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 136 | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 137 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 138 | 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 139 | 0x40, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 140 | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 141 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 142 | 'X', 'Y', 'Z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 143 | 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 144 | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 145 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 146 | 'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 147 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 148 | 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 149 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 150 | 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 151 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 152 | 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 153 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 154 | 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 155 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 156 | 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 157 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 158 | 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 159 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 160 | 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 161 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 162 | 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 163 | }, 164 | }; 165 | -------------------------------------------------------------------------------- /include/mach/machine.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000-2007 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. The rights granted to you under the License 10 | * may not be used to create, or enable the creation or redistribution of, 11 | * unlawful or unlicensed copies of an Apple operating system, or to 12 | * circumvent, violate, or enable the circumvention or violation of, any 13 | * terms of an Apple operating system software license agreement. 14 | * 15 | * Please obtain a copy of the License at 16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 | * 18 | * The Original Code and all software distributed under the License are 19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 | * Please see the License for the specific language governing rights and 24 | * limitations under the License. 25 | * 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 | */ 28 | /* 29 | * Mach Operating System 30 | * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University 31 | * All Rights Reserved. 32 | * 33 | * Permission to use, copy, modify and distribute this software and its 34 | * documentation is hereby granted, provided that both the copyright 35 | * notice and this permission notice appear in all copies of the 36 | * software, derivative works or modified versions, and any portions 37 | * thereof, and that both notices appear in supporting documentation. 38 | * 39 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 40 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 41 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 42 | * 43 | * Carnegie Mellon requests users of this software to return to 44 | * 45 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 46 | * School of Computer Science 47 | * Carnegie Mellon University 48 | * Pittsburgh PA 15213-3890 49 | * 50 | * any improvements or extensions that they make and grant Carnegie Mellon 51 | * the rights to redistribute these changes. 52 | */ 53 | /* File: machine.h 54 | * Author: Avadis Tevanian, Jr. 55 | * Date: 1986 56 | * 57 | * Machine independent machine abstraction. 58 | */ 59 | 60 | #ifndef _MACH_MACHINE_H_ 61 | #define _MACH_MACHINE_H_ 62 | 63 | #include 64 | //#include 65 | //#include 66 | 67 | typedef uint32_t integer_t; 68 | 69 | typedef integer_t cpu_type_t; 70 | typedef integer_t cpu_subtype_t; 71 | typedef integer_t cpu_threadtype_t; 72 | 73 | #define CPU_STATE_MAX 4 74 | 75 | #define CPU_STATE_USER 0 76 | #define CPU_STATE_SYSTEM 1 77 | #define CPU_STATE_IDLE 2 78 | #define CPU_STATE_NICE 3 79 | 80 | 81 | 82 | /* 83 | * Capability bits used in the definition of cpu_type. 84 | */ 85 | #define CPU_ARCH_MASK 0xff000000 /* mask for architecture bits */ 86 | #define CPU_ARCH_ABI64 0x01000000 /* 64 bit ABI */ 87 | 88 | /* 89 | * Machine types known by all. 90 | */ 91 | 92 | #define CPU_TYPE_ANY ((cpu_type_t) -1) 93 | 94 | #define CPU_TYPE_VAX ((cpu_type_t) 1) 95 | /* skip ((cpu_type_t) 2) */ 96 | /* skip ((cpu_type_t) 3) */ 97 | /* skip ((cpu_type_t) 4) */ 98 | /* skip ((cpu_type_t) 5) */ 99 | #define CPU_TYPE_MC680x0 ((cpu_type_t) 6) 100 | #define CPU_TYPE_X86 ((cpu_type_t) 7) 101 | #define CPU_TYPE_I386 CPU_TYPE_X86 /* compatibility */ 102 | #define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64) 103 | 104 | /* skip CPU_TYPE_MIPS ((cpu_type_t) 8) */ 105 | /* skip ((cpu_type_t) 9) */ 106 | #define CPU_TYPE_MC98000 ((cpu_type_t) 10) 107 | #define CPU_TYPE_HPPA ((cpu_type_t) 11) 108 | #define CPU_TYPE_ARM ((cpu_type_t) 12) 109 | #define CPU_TYPE_MC88000 ((cpu_type_t) 13) 110 | #define CPU_TYPE_SPARC ((cpu_type_t) 14) 111 | #define CPU_TYPE_I860 ((cpu_type_t) 15) 112 | /* skip CPU_TYPE_ALPHA ((cpu_type_t) 16) */ 113 | /* skip ((cpu_type_t) 17) */ 114 | #define CPU_TYPE_POWERPC ((cpu_type_t) 18) 115 | #define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64) 116 | 117 | /* 118 | * Machine subtypes (these are defined here, instead of in a machine 119 | * dependent directory, so that any program can get all definitions 120 | * regardless of where is it compiled). 121 | */ 122 | 123 | /* 124 | * Capability bits used in the definition of cpu_subtype. 125 | */ 126 | #define CPU_SUBTYPE_MASK 0xff000000 /* mask for feature flags */ 127 | #define CPU_SUBTYPE_LIB64 0x80000000 /* 64 bit libraries */ 128 | 129 | 130 | /* 131 | * Object files that are hand-crafted to run on any 132 | * implementation of an architecture are tagged with 133 | * CPU_SUBTYPE_MULTIPLE. This functions essentially the same as 134 | * the "ALL" subtype of an architecture except that it allows us 135 | * to easily find object files that may need to be modified 136 | * whenever a new implementation of an architecture comes out. 137 | * 138 | * It is the responsibility of the implementor to make sure the 139 | * software handles unsupported implementations elegantly. 140 | */ 141 | #define CPU_SUBTYPE_MULTIPLE ((cpu_subtype_t) -1) 142 | #define CPU_SUBTYPE_LITTLE_ENDIAN ((cpu_subtype_t) 0) 143 | #define CPU_SUBTYPE_BIG_ENDIAN ((cpu_subtype_t) 1) 144 | 145 | /* 146 | * Machine threadtypes. 147 | * This is none - not defined - for most machine types/subtypes. 148 | */ 149 | #define CPU_THREADTYPE_NONE ((cpu_threadtype_t) 0) 150 | 151 | /* 152 | * VAX subtypes (these do *not* necessary conform to the actual cpu 153 | * ID assigned by DEC available via the SID register). 154 | */ 155 | 156 | #define CPU_SUBTYPE_VAX_ALL ((cpu_subtype_t) 0) 157 | #define CPU_SUBTYPE_VAX780 ((cpu_subtype_t) 1) 158 | #define CPU_SUBTYPE_VAX785 ((cpu_subtype_t) 2) 159 | #define CPU_SUBTYPE_VAX750 ((cpu_subtype_t) 3) 160 | #define CPU_SUBTYPE_VAX730 ((cpu_subtype_t) 4) 161 | #define CPU_SUBTYPE_UVAXI ((cpu_subtype_t) 5) 162 | #define CPU_SUBTYPE_UVAXII ((cpu_subtype_t) 6) 163 | #define CPU_SUBTYPE_VAX8200 ((cpu_subtype_t) 7) 164 | #define CPU_SUBTYPE_VAX8500 ((cpu_subtype_t) 8) 165 | #define CPU_SUBTYPE_VAX8600 ((cpu_subtype_t) 9) 166 | #define CPU_SUBTYPE_VAX8650 ((cpu_subtype_t) 10) 167 | #define CPU_SUBTYPE_VAX8800 ((cpu_subtype_t) 11) 168 | #define CPU_SUBTYPE_UVAXIII ((cpu_subtype_t) 12) 169 | 170 | /* 171 | * 680x0 subtypes 172 | * 173 | * The subtype definitions here are unusual for historical reasons. 174 | * NeXT used to consider 68030 code as generic 68000 code. For 175 | * backwards compatability: 176 | * 177 | * CPU_SUBTYPE_MC68030 symbol has been preserved for source code 178 | * compatability. 179 | * 180 | * CPU_SUBTYPE_MC680x0_ALL has been defined to be the same 181 | * subtype as CPU_SUBTYPE_MC68030 for binary comatability. 182 | * 183 | * CPU_SUBTYPE_MC68030_ONLY has been added to allow new object 184 | * files to be tagged as containing 68030-specific instructions. 185 | */ 186 | 187 | #define CPU_SUBTYPE_MC680x0_ALL ((cpu_subtype_t) 1) 188 | #define CPU_SUBTYPE_MC68030 ((cpu_subtype_t) 1) /* compat */ 189 | #define CPU_SUBTYPE_MC68040 ((cpu_subtype_t) 2) 190 | #define CPU_SUBTYPE_MC68030_ONLY ((cpu_subtype_t) 3) 191 | 192 | /* 193 | * I386 subtypes 194 | */ 195 | 196 | #define CPU_SUBTYPE_INTEL(f, m) ((cpu_subtype_t) (f) + ((m) << 4)) 197 | 198 | #define CPU_SUBTYPE_I386_ALL CPU_SUBTYPE_INTEL(3, 0) 199 | #define CPU_SUBTYPE_386 CPU_SUBTYPE_INTEL(3, 0) 200 | #define CPU_SUBTYPE_486 CPU_SUBTYPE_INTEL(4, 0) 201 | #define CPU_SUBTYPE_486SX CPU_SUBTYPE_INTEL(4, 8) // 8 << 4 = 128 202 | #define CPU_SUBTYPE_586 CPU_SUBTYPE_INTEL(5, 0) 203 | #define CPU_SUBTYPE_PENT CPU_SUBTYPE_INTEL(5, 0) 204 | #define CPU_SUBTYPE_PENTPRO CPU_SUBTYPE_INTEL(6, 1) 205 | #define CPU_SUBTYPE_PENTII_M3 CPU_SUBTYPE_INTEL(6, 3) 206 | #define CPU_SUBTYPE_PENTII_M5 CPU_SUBTYPE_INTEL(6, 5) 207 | #define CPU_SUBTYPE_CELERON CPU_SUBTYPE_INTEL(7, 6) 208 | #define CPU_SUBTYPE_CELERON_MOBILE CPU_SUBTYPE_INTEL(7, 7) 209 | #define CPU_SUBTYPE_PENTIUM_3 CPU_SUBTYPE_INTEL(8, 0) 210 | #define CPU_SUBTYPE_PENTIUM_3_M CPU_SUBTYPE_INTEL(8, 1) 211 | #define CPU_SUBTYPE_PENTIUM_3_XEON CPU_SUBTYPE_INTEL(8, 2) 212 | #define CPU_SUBTYPE_PENTIUM_M CPU_SUBTYPE_INTEL(9, 0) 213 | #define CPU_SUBTYPE_PENTIUM_4 CPU_SUBTYPE_INTEL(10, 0) 214 | #define CPU_SUBTYPE_PENTIUM_4_M CPU_SUBTYPE_INTEL(10, 1) 215 | #define CPU_SUBTYPE_ITANIUM CPU_SUBTYPE_INTEL(11, 0) 216 | #define CPU_SUBTYPE_ITANIUM_2 CPU_SUBTYPE_INTEL(11, 1) 217 | #define CPU_SUBTYPE_XEON CPU_SUBTYPE_INTEL(12, 0) 218 | #define CPU_SUBTYPE_XEON_MP CPU_SUBTYPE_INTEL(12, 1) 219 | 220 | #define CPU_SUBTYPE_INTEL_FAMILY(x) ((x) & 15) 221 | #define CPU_SUBTYPE_INTEL_FAMILY_MAX 15 222 | 223 | #define CPU_SUBTYPE_INTEL_MODEL(x) ((x) >> 4) 224 | #define CPU_SUBTYPE_INTEL_MODEL_ALL 0 225 | 226 | /* 227 | * X86 subtypes. 228 | */ 229 | 230 | #define CPU_SUBTYPE_X86_ALL ((cpu_subtype_t)3) 231 | #define CPU_SUBTYPE_X86_64_ALL ((cpu_subtype_t)3) 232 | #define CPU_SUBTYPE_X86_ARCH1 ((cpu_subtype_t)4) 233 | 234 | 235 | #define CPU_THREADTYPE_INTEL_HTT ((cpu_threadtype_t) 1) 236 | 237 | /* 238 | * Mips subtypes. 239 | */ 240 | 241 | #define CPU_SUBTYPE_MIPS_ALL ((cpu_subtype_t) 0) 242 | #define CPU_SUBTYPE_MIPS_R2300 ((cpu_subtype_t) 1) 243 | #define CPU_SUBTYPE_MIPS_R2600 ((cpu_subtype_t) 2) 244 | #define CPU_SUBTYPE_MIPS_R2800 ((cpu_subtype_t) 3) 245 | #define CPU_SUBTYPE_MIPS_R2000a ((cpu_subtype_t) 4) /* pmax */ 246 | #define CPU_SUBTYPE_MIPS_R2000 ((cpu_subtype_t) 5) 247 | #define CPU_SUBTYPE_MIPS_R3000a ((cpu_subtype_t) 6) /* 3max */ 248 | #define CPU_SUBTYPE_MIPS_R3000 ((cpu_subtype_t) 7) 249 | 250 | /* 251 | * MC98000 (PowerPC) subtypes 252 | */ 253 | #define CPU_SUBTYPE_MC98000_ALL ((cpu_subtype_t) 0) 254 | #define CPU_SUBTYPE_MC98601 ((cpu_subtype_t) 1) 255 | 256 | /* 257 | * HPPA subtypes for Hewlett-Packard HP-PA family of 258 | * risc processors. Port by NeXT to 700 series. 259 | */ 260 | 261 | #define CPU_SUBTYPE_HPPA_ALL ((cpu_subtype_t) 0) 262 | #define CPU_SUBTYPE_HPPA_7100 ((cpu_subtype_t) 0) /* compat */ 263 | #define CPU_SUBTYPE_HPPA_7100LC ((cpu_subtype_t) 1) 264 | 265 | /* 266 | * MC88000 subtypes. 267 | */ 268 | #define CPU_SUBTYPE_MC88000_ALL ((cpu_subtype_t) 0) 269 | #define CPU_SUBTYPE_MC88100 ((cpu_subtype_t) 1) 270 | #define CPU_SUBTYPE_MC88110 ((cpu_subtype_t) 2) 271 | 272 | /* 273 | * SPARC subtypes 274 | */ 275 | #define CPU_SUBTYPE_SPARC_ALL ((cpu_subtype_t) 0) 276 | 277 | /* 278 | * I860 subtypes 279 | */ 280 | #define CPU_SUBTYPE_I860_ALL ((cpu_subtype_t) 0) 281 | #define CPU_SUBTYPE_I860_860 ((cpu_subtype_t) 1) 282 | 283 | /* 284 | * PowerPC subtypes 285 | */ 286 | #define CPU_SUBTYPE_POWERPC_ALL ((cpu_subtype_t) 0) 287 | #define CPU_SUBTYPE_POWERPC_601 ((cpu_subtype_t) 1) 288 | #define CPU_SUBTYPE_POWERPC_602 ((cpu_subtype_t) 2) 289 | #define CPU_SUBTYPE_POWERPC_603 ((cpu_subtype_t) 3) 290 | #define CPU_SUBTYPE_POWERPC_603e ((cpu_subtype_t) 4) 291 | #define CPU_SUBTYPE_POWERPC_603ev ((cpu_subtype_t) 5) 292 | #define CPU_SUBTYPE_POWERPC_604 ((cpu_subtype_t) 6) 293 | #define CPU_SUBTYPE_POWERPC_604e ((cpu_subtype_t) 7) 294 | #define CPU_SUBTYPE_POWERPC_620 ((cpu_subtype_t) 8) 295 | #define CPU_SUBTYPE_POWERPC_750 ((cpu_subtype_t) 9) 296 | #define CPU_SUBTYPE_POWERPC_7400 ((cpu_subtype_t) 10) 297 | #define CPU_SUBTYPE_POWERPC_7450 ((cpu_subtype_t) 11) 298 | #define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100) 299 | 300 | /* 301 | * ARM subtypes 302 | */ 303 | #define CPU_SUBTYPE_ARM_ALL ((cpu_subtype_t) 0) 304 | #define CPU_SUBTYPE_ARM_V4T ((cpu_subtype_t) 5) 305 | #define CPU_SUBTYPE_ARM_V6 ((cpu_subtype_t) 6) 306 | #define CPU_SUBTYPE_ARM_V5TEJ ((cpu_subtype_t) 7) 307 | #define CPU_SUBTYPE_ARM_XSCALE ((cpu_subtype_t) 8) 308 | #define CPU_SUBTYPE_ARM_V7 ((cpu_subtype_t) 9) 309 | 310 | /* 311 | * CPU families (sysctl hw.cpufamily) 312 | * 313 | * These are meant to identify the CPU's marketing name - an 314 | * application can map these to (possibly) localized strings. 315 | * NB: the encodings of the CPU families are intentionally arbitrary. 316 | * There is no ordering, and you should never try to deduce whether 317 | * or not some feature is available based on the family. 318 | * Use feature flags (eg, hw.optional.altivec) to test for optional 319 | * functionality. 320 | */ 321 | #define CPUFAMILY_UNKNOWN 0 322 | #define CPUFAMILY_POWERPC_G3 0xcee41549 323 | #define CPUFAMILY_POWERPC_G4 0x77c184ae 324 | #define CPUFAMILY_POWERPC_G5 0xed76d8aa 325 | #define CPUFAMILY_INTEL_6_13 0xaa33392b 326 | #define CPUFAMILY_INTEL_6_14 0x73d67300 /* "Intel Core Solo" and "Intel Core Duo" (32-bit Pentium-M with SSE3) */ 327 | #define CPUFAMILY_INTEL_6_15 0x426f69ef /* "Intel Core 2 Duo" */ 328 | #define CPUFAMILY_INTEL_6_23 0x78ea4fbc /* Penryn */ 329 | #define CPUFAMILY_INTEL_6_26 0x6b5a4cd2 /* Nehalem */ 330 | #define CPUFAMILY_ARM_9 0xe73283ae 331 | #define CPUFAMILY_ARM_11 0x8ff620d8 332 | #define CPUFAMILY_ARM_XSCALE 0x53b005f5 333 | #define CPUFAMILY_ARM_13 0x0cc90e64 334 | 335 | #define CPUFAMILY_INTEL_YONAH CPUFAMILY_INTEL_6_14 336 | #define CPUFAMILY_INTEL_MEROM CPUFAMILY_INTEL_6_15 337 | #define CPUFAMILY_INTEL_PENRYN CPUFAMILY_INTEL_6_23 338 | #define CPUFAMILY_INTEL_NEHALEM CPUFAMILY_INTEL_6_26 339 | 340 | #define CPUFAMILY_INTEL_CORE CPUFAMILY_INTEL_6_14 341 | #define CPUFAMILY_INTEL_CORE2 CPUFAMILY_INTEL_6_15 342 | 343 | #endif /* _MACH_MACHINE_H_ */ 344 | -------------------------------------------------------------------------------- /macho2elf.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Shinichiro Hamaji. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions 5 | // are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following 12 | // disclaimer in the documentation and/or other materials 13 | // provided with the distribution. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 16 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 19 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 22 | // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | // SUCH DAMAGE. 27 | 28 | // An attempt to translate from Mach-O to ELF. 29 | // 30 | // Note that programs generated by this program won't run because this 31 | // doesn't initialize glibc properly. 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include "mach-o.h" 45 | 46 | using namespace std; 47 | 48 | static map g_rename; 49 | static vector g_sos; 50 | 51 | static void initRename() { 52 | #define RENAME(src, dst) g_rename.insert(make_pair(#src, #dst)); 53 | #define WRAP(src) RENAME(src, __darwin_ ## src) 54 | #include "rename.tab" 55 | #undef RENAME 56 | #undef WRAP 57 | } 58 | 59 | static uint64_t alignMem(uint64_t p, uint64_t a) { 60 | a--; 61 | return (p + a) & ~a; 62 | } 63 | 64 | static void fwrite_checked(const void* ptr, 65 | size_t size, 66 | size_t nmemb, 67 | FILE* stream) { 68 | size_t r = fwrite(ptr, size, nmemb, stream); 69 | if (r != nmemb) { 70 | fprintf(stderr, "fwrite failed\n"); 71 | abort(); 72 | } 73 | } 74 | 75 | 76 | template 77 | struct BitsHelpers { 78 | typedef Elf64_Ehdr Elf_Ehdr; 79 | typedef Elf64_Phdr Elf_Phdr; 80 | typedef Elf64_Shdr Elf_Shdr; 81 | typedef Elf64_Dyn Elf_Dyn; 82 | typedef Elf64_Sym Elf_Sym; 83 | typedef Elf64_Rela Elf_Rel; 84 | typedef uint64_t intptr; 85 | typedef segment_command_64 mach_segment; 86 | 87 | static const vector& segments(const MachO& mach) { 88 | return mach.segments64(); 89 | } 90 | 91 | static int elf_st_bind(int val) { 92 | return ELF64_ST_BIND(val); 93 | } 94 | }; 95 | 96 | template <> 97 | struct BitsHelpers { 98 | typedef Elf32_Ehdr Elf_Ehdr; 99 | typedef Elf32_Phdr Elf_Phdr; 100 | typedef Elf32_Shdr Elf_Shdr; 101 | typedef Elf32_Dyn Elf_Dyn; 102 | typedef Elf32_Sym Elf_Sym; 103 | typedef Elf32_Rela Elf_Rel; 104 | typedef uint32_t intptr; 105 | typedef segment_command mach_segment; 106 | 107 | static const vector& segments(const MachO& mach) { 108 | return mach.segments(); 109 | } 110 | 111 | static int elf_st_bind(int val) { 112 | return ELF32_ST_BIND(val); 113 | } 114 | }; 115 | 116 | template 117 | class ELFBuilder { 118 | typedef BitsHelpers Helpers; 119 | typedef typename Helpers::Elf_Ehdr Ehdr; 120 | typedef typename Helpers::Elf_Phdr Phdr; 121 | typedef typename Helpers::Elf_Shdr Shdr; 122 | typedef typename Helpers::Elf_Dyn Dyn; 123 | typedef typename Helpers::Elf_Sym Sym; 124 | typedef typename Helpers::Elf_Rel Rel; 125 | typedef typename Helpers::intptr intptr; 126 | typedef typename Helpers::mach_segment Segment; 127 | 128 | public: 129 | ~ELFBuilder() { 130 | for (size_t i = 0; i < sections_.size(); i++) { 131 | delete sections_[i]; 132 | } 133 | 134 | fclose(fp_); 135 | } 136 | 137 | void emit(const MachO& mach, const char* filename) { 138 | Section* null_section = newSection("", SHT_NULL); 139 | null_section->flags = 0; 140 | 141 | fp_ = fopen(filename, "wb"); 142 | if (!fp_) { 143 | fprintf(stderr, "Cannot write %s\n", filename); 144 | exit(1); 145 | } 146 | 147 | int num_phdr = 3; // PT_INTERP + PT_DYNAMIC + PT_LOAD for dynamic 148 | intptr base_vaddr = 0; 149 | intptr max_vaddr = 0; 150 | 151 | const vector& segments = Helpers::segments(mach); 152 | for (size_t i = 0; i < segments.size(); i++) { 153 | Segment* seg = segments[i]; 154 | const char* name = seg->segname; 155 | if (!strcmp(name, SEG_PAGEZERO)) { 156 | continue; 157 | } 158 | if (!strcmp(name, SEG_TEXT)) { 159 | base_vaddr = seg->vmaddr; 160 | } 161 | max_vaddr = max(max_vaddr, seg->vmaddr + seg->vmsize); 162 | num_phdr++; 163 | } 164 | 165 | Ehdr ehdr; 166 | memset(&ehdr, 0, sizeof(ehdr)); 167 | ehdr.e_ident[EI_MAG0] = ELFMAG0; 168 | ehdr.e_ident[EI_MAG1] = ELFMAG1; 169 | ehdr.e_ident[EI_MAG2] = ELFMAG2; 170 | ehdr.e_ident[EI_MAG3] = ELFMAG3; 171 | ehdr.e_ident[EI_CLASS] = is64 ? ELFCLASS64 : ELFCLASS32; 172 | ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 173 | ehdr.e_ident[EI_VERSION] = EV_CURRENT; 174 | ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV; 175 | ehdr.e_type = ET_EXEC; 176 | ehdr.e_machine = is64 ? EM_X86_64 : EM_386; 177 | ehdr.e_version = EV_CURRENT; 178 | ehdr.e_entry = mach.entry(); 179 | ehdr.e_phoff = sizeof(ehdr); 180 | ehdr.e_shoff = 0; 181 | ehdr.e_flags = 0; 182 | ehdr.e_ehsize = sizeof(ehdr); 183 | ehdr.e_phentsize = sizeof(Phdr); 184 | ehdr.e_phnum = num_phdr; 185 | ehdr.e_shentsize = sizeof(Shdr); 186 | ehdr.e_shnum = 0; 187 | ehdr.e_shstrndx = 0; 188 | fwrite_checked(&ehdr, sizeof(ehdr), 1, fp_); 189 | 190 | intptr offset = sizeof(Ehdr) + sizeof(Phdr) * num_phdr; 191 | Phdr phdr; 192 | 193 | const char* loader = 194 | is64 ? "/lib64/ld-linux-x86-64.so.2" : "/lib/ld-linux.so.2"; 195 | phdr.p_type = PT_INTERP; 196 | phdr.p_offset = offset; 197 | phdr.p_vaddr = base_vaddr + phdr.p_offset; 198 | phdr.p_paddr = phdr.p_vaddr; 199 | phdr.p_filesz = strlen(loader) + 1; 200 | phdr.p_memsz = phdr.p_filesz; 201 | phdr.p_flags = PF_R; 202 | phdr.p_align = 1; 203 | fwrite_checked(&phdr, sizeof(phdr), 1, fp_); 204 | 205 | offset += phdr.p_filesz; 206 | 207 | for (size_t i = 0; i < segments.size(); i++) { 208 | Segment* seg = segments[i]; 209 | const char* name = seg->segname; 210 | if (!strcmp(name, SEG_PAGEZERO)) { 211 | continue; 212 | } 213 | 214 | phdr.p_type = PT_LOAD; 215 | phdr.p_offset = seg->fileoff; 216 | phdr.p_vaddr = seg->vmaddr; 217 | phdr.p_paddr = phdr.p_vaddr; 218 | // TODO! 219 | //phdr.p_filesz = max(0x1000, seg->filesize); 220 | phdr.p_filesz = alignMem(seg->filesize, 0x1000); 221 | phdr.p_memsz = seg->vmsize; 222 | phdr.p_flags = 0; 223 | if (seg->initprot & VM_PROT_READ) { 224 | phdr.p_flags |= PF_R; 225 | } 226 | if (seg->initprot & VM_PROT_WRITE) { 227 | phdr.p_flags |= PF_W; 228 | } 229 | if (seg->initprot & VM_PROT_EXECUTE) { 230 | phdr.p_flags |= PF_X; 231 | } 232 | phdr.p_align = 0x1000; 233 | fwrite_checked(&phdr, sizeof(phdr), 1, fp_); 234 | 235 | const char* sec_name = seg->segname; 236 | int flags = SHF_ALLOC; 237 | int align = 8; 238 | //size = phdr.p_filesz; 239 | uint64_t size = seg->filesize; 240 | if (!strcmp(sec_name, SEG_TEXT)) { 241 | sec_name = ".text"; 242 | flags |= SHF_EXECINSTR; 243 | align = 16; 244 | // TODO: maybe OK? 245 | size = alignMem(size, 0x1000) - offset; 246 | seg->fileoff = offset; 247 | seg->filesize = size; 248 | } else if (!strcmp(sec_name, SEG_DATA)) { 249 | sec_name = ".data"; 250 | flags |= SHF_WRITE; 251 | } 252 | Section* sec = newSection(sec_name, SHT_PROGBITS); 253 | sec->override_data_size = phdr.p_filesz; 254 | sec->vmaddr = seg->vmaddr; 255 | sec->offset = phdr.p_offset; 256 | sec->flags |= flags; 257 | sec->align = align; 258 | 259 | offset += size; 260 | } 261 | 262 | size_t num_dyns = 9 + g_sos.size(); 263 | 264 | intptr dynamic_offset = max_vaddr + (offset & 0xfff); 265 | 266 | phdr.p_type = PT_LOAD; 267 | phdr.p_offset = offset; 268 | phdr.p_vaddr = dynamic_offset; 269 | phdr.p_paddr = phdr.p_vaddr; 270 | // TODO: need to rewrite the size 271 | phdr.p_filesz = 0x4000; 272 | phdr.p_memsz = phdr.p_filesz; 273 | phdr.p_flags = PF_R | PF_W; 274 | phdr.p_align = 8; 275 | fwrite_checked(&phdr, sizeof(phdr), 1, fp_); 276 | 277 | phdr.p_type = PT_DYNAMIC; 278 | phdr.p_filesz = sizeof(Dyn) * num_dyns; 279 | fwrite_checked(&phdr, sizeof(phdr), 1, fp_); 280 | 281 | Section* dynamic = newSection(".dynamic", SHT_DYNAMIC); 282 | dynamic->entsize = sizeof(Dyn); 283 | dynamic->offset = phdr.p_offset; 284 | dynamic->override_data_size = phdr.p_filesz; 285 | dynamic->flags |= SHF_WRITE; 286 | 287 | offset += phdr.p_filesz; 288 | dynamic_offset += phdr.p_filesz; 289 | 290 | fwrite_checked(loader, strlen(loader) + 1, 1, fp_); 291 | 292 | for (size_t i = 0; i < segments.size(); i++) { 293 | Segment* seg = segments[i]; 294 | const char* name = seg->segname; 295 | if (!strcmp(name, SEG_PAGEZERO)) { 296 | continue; 297 | } 298 | 299 | fwrite_checked(mach.base() + seg->fileoff, 1, seg->filesize, fp_); 300 | } 301 | 302 | Symtab* symtab = newSymtab(".dynsym", SHT_DYNSYM, ".dynstr", ".hash"); 303 | dynamic->link = symtab->str; 304 | 305 | vector rels; 306 | for (size_t i = 0; i < mach.binds().size(); i++) { 307 | MachO::Bind* bind = mach.binds()[i]; 308 | 309 | if (bind->name[0] != '_') { 310 | continue; 311 | } 312 | 313 | if (bind->type == BIND_TYPE_POINTER) { 314 | const char* name = bind->name + 1; 315 | 316 | printf("Putting ELF symbol: %s\n", name); 317 | 318 | map::const_iterator found = 319 | g_rename.find(name); 320 | if (found != g_rename.end()) { 321 | printf("Applying renaming: %s => %s\n", 322 | name, found->second.c_str()); 323 | name = found->second.c_str(); 324 | } 325 | 326 | int sym_index = putELFSym(symtab, bind->vmaddr, 0, 327 | ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), 328 | 0, 0, name); 329 | 330 | Rel rel; 331 | rel.r_offset = bind->vmaddr; 332 | rel.r_info = ELF64_R_INFO(sym_index, R_X86_64_JUMP_SLOT); 333 | rel.r_addend = bind->addend; 334 | rels.push_back(rel); 335 | } else { 336 | printf("Unknown bind type: %d\n", bind->type); 337 | abort(); 338 | } 339 | } 340 | 341 | vector dyns; 342 | for (size_t i = 0; i < g_sos.size(); i++) { 343 | addDynVal(DT_NEEDED, putELFStr(symtab->str, g_sos[i].c_str()), 344 | &dyns); 345 | } 346 | 347 | addDynVal(DT_HASH, dynamic_offset, &dyns); 348 | symtab->hash->offset = offset; 349 | offset += symtab->hash->data.size(); 350 | dynamic_offset += symtab->hash->data.size(); 351 | 352 | addDynVal(DT_SYMTAB, dynamic_offset, &dyns); 353 | symtab->sym->offset = offset; 354 | offset += symtab->sym->data.size(); 355 | dynamic_offset += symtab->sym->data.size(); 356 | 357 | addDynVal(DT_STRTAB, dynamic_offset, &dyns); 358 | symtab->str->offset = offset; 359 | offset += symtab->str->data.size(); 360 | dynamic_offset += symtab->str->data.size(); 361 | 362 | addDynVal(DT_STRSZ, symtab->str->data.size(), &dyns); 363 | addDynVal(DT_SYMENT, sizeof(Sym), &dyns); 364 | addDynVal(DT_RELA, dynamic_offset, &dyns); 365 | 366 | addDynVal(DT_RELASZ, sizeof(Rel) * rels.size(), &dyns); 367 | Section* rel_sec = newSection(".rela.got", SHT_RELA); 368 | rel_sec->offset = offset; 369 | rel_sec->override_data_size = sizeof(Rel) * rels.size(); 370 | rel_sec->entsize = sizeof(Rel); 371 | rel_sec->link = symtab->sym; 372 | offset += sizeof(Rel) * rels.size(); 373 | 374 | addDynVal(DT_RELAENT, sizeof(Rel), &dyns); 375 | addDynVal(DT_NULL, 0, &dyns); 376 | 377 | assert(num_dyns == dyns.size()); 378 | 379 | for (size_t i = 0; i < dyns.size(); i++) { 380 | fwrite_checked(&dyns[i], 1, sizeof(Dyn), fp_); 381 | } 382 | fwrite_checked(symtab->hash->data.data(), 383 | symtab->hash->data.size(), 1, fp_); 384 | fwrite_checked(symtab->sym->data.data(), 385 | symtab->sym->data.size(), 1, fp_); 386 | fwrite_checked(symtab->str->data.data(), 387 | symtab->str->data.size(), 1, fp_); 388 | for (size_t i = 0; i < rels.size(); i++) { 389 | fwrite_checked(&rels[i], 1, sizeof(Rel), fp_); 390 | } 391 | 392 | delete symtab; 393 | 394 | Section* shstrtab = newSection(".shstrtab", SHT_STRTAB); 395 | shstrtab->offset = offset; 396 | 397 | for (size_t i = 0; i < sections_.size(); i++) { 398 | Section* sec = sections_[i]; 399 | sec->name_offset = putELFStr(shstrtab, sec->name.c_str()); 400 | } 401 | 402 | fwrite_checked(shstrtab->data.data(), shstrtab->data.size(), 1, fp_); 403 | offset += shstrtab->data.size(); 404 | 405 | ehdr.e_shoff = offset; 406 | ehdr.e_shstrndx = sections_.size() - 1; 407 | 408 | for (size_t i = 0; i < sections_.size(); i++) { 409 | Section* sec = sections_[i]; 410 | Shdr shdr; 411 | shdr.sh_name = sec->name_offset; 412 | shdr.sh_type = sec->type; 413 | shdr.sh_flags = sec->flags; 414 | shdr.sh_addr = sec->offset + base_vaddr; 415 | if (sec->vmaddr) { 416 | shdr.sh_addr = sec->vmaddr; 417 | } 418 | shdr.sh_offset = sec->offset; 419 | shdr.sh_size = sec->data.size(); 420 | if (sec->override_data_size) { 421 | shdr.sh_size = sec->override_data_size; 422 | } 423 | shdr.sh_link = 0; 424 | if (sec->link) { 425 | shdr.sh_link = sec->link->index; 426 | } 427 | shdr.sh_info = 0; 428 | //shdr.sh_addralign = sec->align; 429 | shdr.sh_addralign = 0; 430 | shdr.sh_entsize = sec->entsize; 431 | fwrite_checked(&shdr, 1, sizeof(shdr), fp_); 432 | } 433 | ehdr.e_shnum = sections_.size(); 434 | 435 | char padding[4096]; 436 | fwrite_checked(padding, 1, sizeof(padding), fp_); 437 | 438 | fseek(fp_, 0, SEEK_SET); 439 | fwrite_checked(&ehdr, sizeof(ehdr), 1, fp_); 440 | } 441 | 442 | private: 443 | struct Section { 444 | string name; 445 | int name_offset; 446 | string data; 447 | uint64_t offset; 448 | uint64_t vmaddr; 449 | uint64_t override_data_size; 450 | uint32_t type; 451 | int nb_hashed_syms; 452 | int entsize; 453 | int index; 454 | int flags; 455 | int align; 456 | Section* link; 457 | }; 458 | 459 | struct Symtab { 460 | Section* sym; 461 | Section* str; 462 | Section* hash; 463 | 464 | ~Symtab() { 465 | } 466 | }; 467 | 468 | static char* addSectionPtr(Section* sec, uint64_t size) { 469 | size_t offset = sec->data.size(); 470 | sec->data.resize(offset + size); 471 | return &sec->data[offset]; 472 | } 473 | 474 | Section* newSection(const char *name, uint32_t type) { 475 | Section* sec; 476 | sec = new Section(); 477 | sec->name = name; 478 | sec->type = type; 479 | sec->flags = SHF_ALLOC; 480 | sec->index = static_cast(sections_.size()); 481 | 482 | sec->name_offset = 0; 483 | sec->offset = 0; 484 | sec->vmaddr = 0; 485 | sec->override_data_size = 0; 486 | sec->nb_hashed_syms = 0; 487 | sec->entsize = 0; 488 | sec->align = 0; 489 | sec->link = NULL; 490 | 491 | sections_.push_back(sec); 492 | return sec; 493 | } 494 | 495 | Symtab* newSymtab(const char* symtab_name, uint32_t symtab_type, 496 | const char* strtab_name, 497 | const char* hash_name) { 498 | Symtab* symtab = new Symtab(); 499 | symtab->sym = newSection(symtab_name, symtab_type); 500 | symtab->sym->entsize = sizeof(Sym); 501 | symtab->str = newSection(strtab_name, SHT_STRTAB); 502 | putELFStr(symtab->str, ""); 503 | symtab->sym->link = symtab->str; 504 | putELFSym(symtab, 0, 0, 0, 0, 0, NULL); 505 | 506 | int nb_buckets = 1; 507 | symtab->hash = newSection(hash_name, SHT_HASH); 508 | symtab->hash->entsize = sizeof(int); 509 | symtab->hash->link = symtab->sym; 510 | 511 | int* ptr = (int*)addSectionPtr(symtab->hash, 512 | (2 + nb_buckets + 1) * sizeof(int)); 513 | ptr[0] = nb_buckets; 514 | ptr[1] = 1; 515 | memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int)); 516 | 517 | return symtab; 518 | } 519 | 520 | /* return the symbol number */ 521 | static int putELFSym(Symtab* symtab, 522 | unsigned long value, unsigned long size, 523 | int info, int other, int shndx, const char *name) { 524 | int name_offset, sym_index; 525 | int nbuckets, h; 526 | Sym* sym; 527 | Section* hs; 528 | Section* s = symtab->sym; 529 | 530 | sym = reinterpret_cast(addSectionPtr(s, sizeof(Sym))); 531 | if (name) { 532 | name_offset = putELFStr(symtab->str, name); 533 | } else { 534 | name_offset = 0; 535 | } 536 | /* XXX: endianness */ 537 | sym->st_name = name_offset; 538 | sym->st_value = value; 539 | sym->st_size = size; 540 | sym->st_info = info; 541 | sym->st_other = other; 542 | sym->st_shndx = shndx; 543 | sym_index = sym - (Sym*)s->data.data(); 544 | printf("sym: %x %p index=%d\n", 545 | sym->st_name, (void*)(intptr_t)sym->st_value, sym_index); 546 | hs = symtab->hash; 547 | if (hs) { 548 | int *ptr, *base; 549 | ptr = reinterpret_cast(addSectionPtr(hs, sizeof(int))); 550 | base = (int*)hs->data.data(); 551 | /* only add global or weak symbols */ 552 | if (Helpers::elf_st_bind(info) != STB_LOCAL) { 553 | /* add another hashing entry */ 554 | nbuckets = base[0]; 555 | h = calcHash(name) % nbuckets; 556 | *ptr = base[2 + h]; 557 | base[2 + h] = sym_index; 558 | base[1]++; 559 | /* we resize the hash table */ 560 | hs->nb_hashed_syms++; 561 | if (hs->nb_hashed_syms > 2 * nbuckets) { 562 | rebuildHash(symtab, 2 * nbuckets); 563 | } 564 | } else { 565 | *ptr = 0; 566 | base[1]++; 567 | } 568 | } 569 | return sym_index; 570 | } 571 | 572 | /* rebuild hash table of section s */ 573 | /* NOTE: we do factorize the hash table code to go faster */ 574 | static void rebuildHash(Symtab* symtab, unsigned int nb_buckets) { 575 | Sym* sym; 576 | int* ptr; 577 | int* hash; 578 | int nb_syms, sym_index, h; 579 | char* strtab; 580 | Section* s = symtab->sym; 581 | 582 | strtab = (char*)symtab->str->data.data(); 583 | nb_syms = s->data.size() / sizeof(Sym); 584 | 585 | symtab->hash->data.clear(); 586 | ptr = (int*)addSectionPtr(symtab->hash, 587 | (2 + nb_buckets + nb_syms) * sizeof(int)); 588 | ptr[0] = nb_buckets; 589 | ptr[1] = nb_syms; 590 | ptr += 2; 591 | hash = ptr; 592 | memset(hash, 0, (nb_buckets + 1) * sizeof(int)); 593 | ptr += nb_buckets + 1; 594 | 595 | sym = (Sym*)s->data.data() + 1; 596 | for(sym_index = 1; sym_index < nb_syms; sym_index++) { 597 | if (Helpers::elf_st_bind(sym->st_info) != STB_LOCAL) { 598 | h = calcHash(strtab + sym->st_name) % nb_buckets; 599 | *ptr = hash[h]; 600 | hash[h] = sym_index; 601 | } else { 602 | *ptr = 0; 603 | } 604 | ptr++; 605 | sym++; 606 | } 607 | } 608 | 609 | static uint64_t putELFStr(Section* sec, const char* sym) { 610 | uint64_t offset = sec->data.size(); 611 | sec->data += sym; 612 | sec->data += '\0'; 613 | return offset; 614 | } 615 | 616 | static void addDynVal(int64_t tag, uint64_t val, vector* dyns) { 617 | Dyn dyn; 618 | dyn.d_tag = tag; 619 | dyn.d_un.d_val = val; 620 | dyns->push_back(dyn); 621 | } 622 | 623 | static void addDynPtr(int64_t tag, uint64_t ptr, vector* dyns) { 624 | Dyn dyn; 625 | dyn.d_tag = tag; 626 | dyn.d_un.d_ptr = ptr; 627 | dyns->push_back(dyn); 628 | } 629 | 630 | static uint64_t addStr(const string& s, string* o) { 631 | uint64_t r = s.size(); 632 | *o += s; 633 | *o += '\0'; 634 | return r; 635 | } 636 | 637 | static uint32_t calcHash(const char* name) { 638 | const uint8_t* ptr = reinterpret_cast(name); 639 | uint32_t h = 0; 640 | while (*ptr) { 641 | h <<= 4; 642 | h += *ptr++; 643 | uint32_t g = h & 0xf0000000; 644 | h ^= g >> 24; 645 | h &= ~g; 646 | } 647 | return h; 648 | } 649 | 650 | FILE* fp_; 651 | vector sections_; 652 | }; 653 | 654 | template 655 | void emitELF(const MachO& mach, const char* filename) { 656 | ELFBuilder builder; 657 | builder.emit(mach, filename); 658 | } 659 | 660 | int main(int argc, char* argv[]) { 661 | initRename(); 662 | 663 | vector args; 664 | g_sos.push_back("/lib/libc.so.6"); 665 | for (int i = 1; i < argc; i++) { 666 | const char* arg = argv[i]; 667 | if (arg[0] != '-') { 668 | args.push_back(arg); 669 | continue; 670 | } 671 | 672 | if (arg[1] == 'l') { 673 | g_sos.push_back(arg + 2); 674 | } else { 675 | fprintf(stderr, "Unknown switch '%s'\n", arg); 676 | exit(1); 677 | } 678 | } 679 | 680 | if (args.size() < 2) { 681 | exit(1); 682 | } 683 | 684 | unique_ptr mach(MachO::read(args[0].c_str(), "x86-64", 685 | false /* need_exports */)); 686 | if (mach->is64()) { 687 | emitELF(*mach, args[1].c_str()); 688 | } else { 689 | emitELF(*mach, args[1].c_str()); 690 | } 691 | } 692 | -------------------------------------------------------------------------------- /mach-o.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Shinichiro Hamaji. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions 5 | // are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following 12 | // disclaimer in the documentation and/or other materials 13 | // provided with the distribution. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 16 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 19 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 22 | // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | // SUCH DAMAGE. 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "fat.h" 40 | #include "log.h" 41 | #include "mach-o.h" 42 | #include "mach-o/loader.h" 43 | 44 | DEFINE_bool(READ_SYMTAB, 45 | #ifdef NDEBUG 46 | false, 47 | #else 48 | true, 49 | #endif 50 | "Read symtab for better backtrace"); 51 | DEFINE_bool(READ_DYSYMTAB, false, "Read dysymtab"); 52 | 53 | typedef long long ll; 54 | typedef unsigned long long ull; 55 | 56 | struct sym { 57 | uint32_t name; 58 | uint32_t addr; 59 | uint32_t flag; 60 | }; 61 | 62 | struct sym64 { 63 | uint32_t name; 64 | uint64_t addr; 65 | uint32_t flag; 66 | }; 67 | 68 | // See mach-o/nlist.h for this layout 69 | struct nlist { 70 | uint32_t n_strx; 71 | uint8_t n_type; 72 | uint8_t n_sect; 73 | uint16_t n_desc; 74 | uint64_t n_value; 75 | }; 76 | 77 | #define N_WEAK_DEF 0x0080 78 | 79 | static uint64_t uleb128(const uint8_t*& p) { 80 | uint64_t r = 0; 81 | int s = 0; 82 | do { 83 | r |= (uint64_t)(*p & 0x7f) << s; 84 | s += 7; 85 | } while (*p++ >= 0x80); 86 | return r; 87 | } 88 | 89 | static int64_t sleb128(const uint8_t*& p) { 90 | int64_t r = 0; 91 | int s = 0; 92 | for (;;) { 93 | uint8_t b = *p++; 94 | if (b < 0x80) { 95 | if (b & 0x40) { 96 | r -= (0x80 - b) << s; 97 | } 98 | else { 99 | r |= (b & 0x3f) << s; 100 | } 101 | break; 102 | } 103 | r |= (b & 0x7f) << s; 104 | s += 7; 105 | } 106 | return r; 107 | } 108 | 109 | class MachOImpl : public MachO { 110 | public: 111 | // Take ownership of fd. 112 | // If len is 0, the size of file will be used as len. 113 | MachOImpl(const char* filename, int fd, size_t offset, size_t len, 114 | bool need_exports); 115 | virtual ~MachOImpl(); 116 | virtual void close(); 117 | 118 | private: 119 | struct RebaseState; 120 | friend struct MachOImpl::RebaseState; 121 | struct BindState; 122 | friend struct MachOImpl::BindState; 123 | 124 | template 125 | void readSegment(char* cmds_ptr, 126 | vector* segments, 127 | vector* bind_sections); 128 | void readRebase(const uint8_t* p, const uint8_t* end); 129 | void readBind(const uint8_t* p, const uint8_t* end, bool is_weak); 130 | void readExport(const uint8_t* start, const uint8_t* p, const uint8_t* end, 131 | string* name_buf); 132 | 133 | template 134 | void readClassicBind(const section& sec, 135 | uint32_t* dysyms, 136 | uint32_t* symtab, 137 | const char* symstrtab) { 138 | uint32_t indirect_offset = sec.reserved1; 139 | int count = sec.size / ptrsize_; 140 | for (int i = 0; i < count; i++) { 141 | uint32_t dysym = dysyms[indirect_offset + i]; 142 | uint32_t index = dysym & 0x3fffffff; 143 | nlist* sym = (nlist*)(symtab + index * (is64_ ? 4 : 3)); 144 | 145 | MachO::Bind* bind = new MachO::Bind(); 146 | bind->name = symstrtab + sym->n_strx; 147 | bind->vmaddr = sec.addr + i * ptrsize_; 148 | bind->value = sym->n_value; 149 | bind->type = BIND_TYPE_POINTER; 150 | bind->ordinal = 1; 151 | bind->is_weak = ((sym->n_desc & N_WEAK_DEF) != 0); 152 | bind->is_classic = true; 153 | LOGF("add classic bind! %s type=%d sect=%d desc=%d value=%lld " 154 | "vmaddr=%p is_weak=%d\n", 155 | bind->name, sym->n_type, sym->n_sect, sym->n_desc, (ll)sym->n_value, 156 | (void*)(bind->vmaddr), bind->is_weak); 157 | binds_.push_back(bind); 158 | } 159 | } 160 | 161 | char* mapped_; 162 | size_t mapped_size_; 163 | bool need_exports_; 164 | }; 165 | 166 | template 167 | void MachOImpl::readSegment(char* cmds_ptr, 168 | vector* segments, 169 | vector* bind_sections) { 170 | segment_command* segment = 171 | reinterpret_cast(cmds_ptr); 172 | segments->push_back(segment); 173 | 174 | LOGF("segment %s: vmaddr=%p vmsize=%llu " 175 | "fileoff=%llu filesize=%llu " 176 | "maxprot=%d initprot=%d nsects=%u flags=%u\n", 177 | segment->segname, 178 | (void*)(intptr_t)segment->vmaddr, (ull)segment->vmsize, 179 | (ull)segment->fileoff, (ull)segment->filesize, 180 | segment->maxprot, segment->initprot, 181 | segment->nsects, segment->flags); 182 | 183 | if (!strcmp(segment->segname, "__TEXT")) { 184 | CHECK(text_base_ == 0); 185 | text_base_ = segment->vmaddr; 186 | } 187 | 188 | section* sections = reinterpret_cast( 189 | cmds_ptr + sizeof(segment_command)); 190 | for (uint32_t j = 0; j < segment->nsects; j++) { 191 | const section& sec = sections[j]; 192 | LOGF("section %s in %s: " 193 | "addr=%p size=%llu offset=%u align=%u " 194 | "reloff=%u nreloc=%u flags=%u " 195 | "reserved1=%u reserved2=%u\n", 196 | sec.sectname, sec.segname, 197 | (void*)(intptr_t)sec.addr, (ull)sec.size, 198 | sec.offset, sec.align, 199 | sec.reloff, sec.nreloc, sec.flags, 200 | sec.reserved1, sec.reserved2); 201 | 202 | if (!strcmp(sec.sectname, "__dyld") && 203 | !strcmp(sec.segname, "__DATA")) { 204 | dyld_data_ = sec.addr; 205 | } 206 | 207 | int section_type = sec.flags & SECTION_TYPE; 208 | switch (section_type) { 209 | case S_REGULAR: 210 | /* Regular section: nothing to do */ 211 | break; 212 | 213 | case S_MOD_INIT_FUNC_POINTERS: { 214 | for (uint64_t p = sec.addr; p < sec.addr + sec.size; p += ptrsize_) { 215 | init_funcs_.push_back(p); 216 | } 217 | break; 218 | } 219 | case S_NON_LAZY_SYMBOL_POINTERS: 220 | case S_LAZY_SYMBOL_POINTERS: { 221 | bind_sections->push_back(sections + j); 222 | break; 223 | } 224 | case S_ZEROFILL: 225 | case S_CSTRING_LITERALS: 226 | case S_4BYTE_LITERALS: 227 | case S_8BYTE_LITERALS: 228 | case S_LITERAL_POINTERS: 229 | case S_SYMBOL_STUBS: 230 | case S_MOD_TERM_FUNC_POINTERS: 231 | // TODO(hamaji): Support term_funcs. 232 | case S_COALESCED: 233 | case S_GB_ZEROFILL: 234 | case S_INTERPOSING: 235 | case S_16BYTE_LITERALS: 236 | case S_DTRACE_DOF: 237 | case S_LAZY_DYLIB_SYMBOL_POINTERS: 238 | LOGF("FIXME: section type %d will not be handled for %s in %s\n", 239 | section_type, sec.sectname, sec.segname); 240 | break; 241 | 242 | default: 243 | fprintf(stderr, "Unknown section type: %d\n", section_type); 244 | abort(); 245 | break; 246 | } 247 | } 248 | } 249 | 250 | struct MachOImpl::RebaseState { 251 | explicit RebaseState(MachOImpl* mach0) 252 | : mach(mach0), type(0), seg_index(0), seg_offset(0) {} 253 | 254 | bool readRebaseOp(const uint8_t*& p) { 255 | uint8_t op = *p & REBASE_OPCODE_MASK; 256 | uint8_t imm = *p & REBASE_IMMEDIATE_MASK; 257 | p++; 258 | switch (op) { 259 | case REBASE_OPCODE_DONE: 260 | return false; 261 | 262 | case REBASE_OPCODE_SET_TYPE_IMM: 263 | type = imm; 264 | break; 265 | 266 | case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: 267 | seg_index = imm; 268 | seg_offset = uleb128(p); 269 | break; 270 | 271 | case REBASE_OPCODE_ADD_ADDR_ULEB: 272 | seg_offset += uleb128(p); 273 | break; 274 | 275 | case REBASE_OPCODE_ADD_ADDR_IMM_SCALED: 276 | seg_offset += imm * mach->ptrsize_; 277 | break; 278 | 279 | case REBASE_OPCODE_DO_REBASE_IMM_TIMES: 280 | for (int i = 0; i < imm; i++) { 281 | addRebase(); 282 | } 283 | break; 284 | 285 | case REBASE_OPCODE_DO_REBASE_ULEB_TIMES: { 286 | int count = uleb128(p); 287 | for (int i = 0; i < count; i++) { 288 | addRebase(); 289 | } 290 | break; 291 | } 292 | 293 | case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: 294 | addRebase(); 295 | seg_offset += uleb128(p); 296 | break; 297 | 298 | case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: { 299 | int count = uleb128(p); 300 | uint64_t skip = uleb128(p); 301 | for (int i = 0; i < count; i++) { 302 | addRebase(); 303 | seg_offset += skip; 304 | } 305 | break; 306 | } 307 | 308 | default: 309 | fprintf(stderr, "unknown op: %x\n", op); 310 | } 311 | 312 | return true; 313 | } 314 | 315 | void addRebase() { 316 | MachO::Rebase* rebase = new MachO::Rebase(); 317 | uint64_t vmaddr; 318 | if (mach->is64_) { 319 | vmaddr = mach->segments64_[seg_index]->vmaddr; 320 | } else { 321 | vmaddr = mach->segments_[seg_index]->vmaddr; 322 | } 323 | LOGF("add rebase! seg_index=%d seg_offset=%llu type=%d vmaddr=%p\n", 324 | seg_index, (ull)seg_offset, type, (void*)vmaddr); 325 | rebase->vmaddr = vmaddr + seg_offset; 326 | rebase->type = type; 327 | mach->rebases_.push_back(rebase); 328 | 329 | seg_offset += mach->ptrsize_; 330 | } 331 | 332 | MachOImpl* mach; 333 | uint8_t type; 334 | int seg_index; 335 | uint64_t seg_offset; 336 | }; 337 | 338 | void MachOImpl::readRebase(const uint8_t* p, const uint8_t* end) { 339 | RebaseState state(this); 340 | while (p < end) { 341 | if (!state.readRebaseOp(p)) 342 | break; 343 | } 344 | } 345 | 346 | struct MachOImpl::BindState { 347 | BindState(MachOImpl* mach0, bool is_weak0) 348 | : mach(mach0), ordinal(0), sym_name(NULL), type(BIND_TYPE_POINTER), 349 | addend(0), seg_index(0), seg_offset(0), is_weak(is_weak0) {} 350 | 351 | void readBindOp(const uint8_t*& p) { 352 | uint8_t op = *p & BIND_OPCODE_MASK; 353 | uint8_t imm = *p & BIND_IMMEDIATE_MASK; 354 | p++; 355 | LOGF("bind: op=%x imm=%d\n", op, imm); 356 | switch (op) { 357 | case BIND_OPCODE_DONE: 358 | break; 359 | 360 | case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: 361 | ordinal = imm; 362 | break; 363 | 364 | case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: 365 | ordinal = uleb128(p); 366 | break; 367 | 368 | case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: 369 | if (imm == 0) { 370 | ordinal = 0; 371 | } else { 372 | ordinal = BIND_OPCODE_MASK | imm; 373 | } 374 | break; 375 | 376 | case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: 377 | sym_name = reinterpret_cast(p); 378 | p += strlen(sym_name) + 1; 379 | LOGF("sym_name=%s\n", sym_name); 380 | break; 381 | 382 | case BIND_OPCODE_SET_TYPE_IMM: 383 | type = imm; 384 | break; 385 | 386 | case BIND_OPCODE_SET_ADDEND_SLEB: 387 | addend = sleb128(p); 388 | break; 389 | 390 | case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: 391 | seg_index = imm; 392 | seg_offset = uleb128(p); 393 | break; 394 | 395 | case BIND_OPCODE_ADD_ADDR_ULEB: 396 | seg_offset += uleb128(p); 397 | break; 398 | 399 | case BIND_OPCODE_DO_BIND: 400 | addBind(); 401 | break; 402 | 403 | case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: 404 | LOGF("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB\n"); 405 | addBind(); 406 | seg_offset += uleb128(p); 407 | break; 408 | 409 | case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: 410 | LOGF("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED %d\n", (int)imm); 411 | addBind(); 412 | seg_offset += imm * mach->ptrsize_; 413 | break; 414 | 415 | case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: { 416 | uint64_t count = uleb128(p); 417 | uint64_t skip = uleb128(p); 418 | LOGF("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB %u %u\n", 419 | (unsigned)count, (unsigned)skip); 420 | for (uint64_t i = 0; i < count; i++) { 421 | addBind(); 422 | seg_offset += skip; 423 | } 424 | break; 425 | } 426 | 427 | default: 428 | fprintf(stderr, "unknown op: %x\n", op); 429 | } 430 | } 431 | 432 | void addBind() { 433 | MachO::Bind* bind = new MachO::Bind(); 434 | uint64_t vmaddr; 435 | if (mach->is64_) { 436 | vmaddr = mach->segments64_[seg_index]->vmaddr; 437 | } else { 438 | vmaddr = mach->segments_[seg_index]->vmaddr; 439 | } 440 | LOGF("add bind! %s seg_index=%d seg_offset=%llu " 441 | "type=%d ordinal=%d addend=%lld vmaddr=%p is_weak=%d\n", 442 | sym_name, seg_index, (ull)seg_offset, 443 | type, ordinal, (ll)addend, (void*)(vmaddr + seg_offset), is_weak); 444 | bind->name = sym_name; 445 | bind->vmaddr = vmaddr + seg_offset; 446 | bind->addend = addend; 447 | bind->type = type; 448 | bind->ordinal = ordinal; 449 | bind->is_weak = is_weak; 450 | mach->binds_.push_back(bind); 451 | 452 | seg_offset += mach->ptrsize_; 453 | } 454 | 455 | MachOImpl* mach; 456 | uint8_t ordinal; 457 | const char* sym_name; 458 | uint8_t type; 459 | int64_t addend; 460 | int seg_index; 461 | uint64_t seg_offset; 462 | bool is_weak; 463 | }; 464 | 465 | void MachOImpl::readBind(const uint8_t* p, const uint8_t* end, bool is_weak) { 466 | BindState state(this, is_weak); 467 | while (p < end) { 468 | state.readBindOp(p); 469 | } 470 | } 471 | 472 | void MachOImpl::readExport(const uint8_t* start, 473 | const uint8_t* p, 474 | const uint8_t* end, 475 | string* name_buf) { 476 | LOGF("readExport: %p-%p\n", p, end); 477 | #if 0 478 | char buf[17]; 479 | buf[16] = '\0'; 480 | for (int i = 0; i < 16*8; i++) { 481 | LOGF("%02x ", p[i]); 482 | buf[i % 16] = p[i] < 32 ? '?' : p[i]; 483 | if (i % 16 == 15) LOGF("%s\n", buf); 484 | } 485 | #endif 486 | 487 | if (p >= end) { 488 | fprintf(stderr, "broken export trie\n"); 489 | exit(1); 490 | } 491 | 492 | if (uint8_t term_size = *p++) { 493 | const uint8_t* expected_term_end = p + term_size; 494 | Export* exp = new Export; 495 | exp->name = *name_buf; 496 | exp->flag = uleb128(p); 497 | exp->addr = uleb128(p); 498 | LOGF("export: %s %lu %p\n", 499 | name_buf->c_str(), (long)exp->flag, (void*)exp->addr); 500 | 501 | exports_.push_back(exp); 502 | 503 | CHECK(expected_term_end == p); 504 | } 505 | 506 | const uint8_t num_children = *p++; 507 | for (uint8_t i = 0; i < num_children; i++) { 508 | size_t orig_name_size = name_buf->size(); 509 | while (*p) { 510 | name_buf->push_back(*p++); 511 | } 512 | p++; 513 | 514 | uint64_t off = uleb128(p); 515 | CHECK(off != 0); 516 | readExport(start, start + off, end, name_buf); 517 | 518 | name_buf->resize(orig_name_size); 519 | } 520 | } 521 | 522 | MachOImpl::MachOImpl(const char* filename, int fd, size_t offset, size_t len, 523 | bool need_exports) 524 | : mapped_(NULL), mapped_size_(len) { 525 | filename_ = filename; 526 | need_exports_ = need_exports; 527 | dyld_data_ = 0; 528 | CHECK(fd); 529 | fd_ = fd; 530 | offset_ = offset; 531 | text_base_ = 0; 532 | is_lc_main_entry_ = false; 533 | 534 | if (!mapped_size_) { 535 | mapped_size_ = lseek(fd_, 0, SEEK_END); 536 | } 537 | lseek(fd, 0, SEEK_SET); 538 | 539 | char* bin = mapped_ = reinterpret_cast( 540 | mmap(NULL, mapped_size_, 541 | PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd_, offset)); 542 | base_ = bin; 543 | 544 | mach_header* header = reinterpret_cast(bin); 545 | LOGF("magic=%x cpu=%d cpusub=%d file=%d ncmds=%d sizecmd=%d flags=%x\n", 546 | header->magic, header->cputype, header->cpusubtype, 547 | header->filetype, header->ncmds, header->sizeofcmds, 548 | header->flags); 549 | 550 | is64_ = false; 551 | if (header->magic == MH_MAGIC_64) { 552 | is64_ = true; 553 | } else if (header->magic != MH_MAGIC) { 554 | fprintf(stderr, "Not mach-o: %s\n", filename); 555 | exit(1); 556 | } 557 | ptrsize_ = is64_ ? 8 : 4; 558 | 559 | if ((header->cputype & 0x00ffffff) != CPU_TYPE_X86) { 560 | fprintf(stderr, "Unsupported CPU\n"); 561 | exit(1); 562 | } 563 | 564 | struct load_command* cmds_ptr = reinterpret_cast( 565 | bin + (is64_ ? sizeof(mach_header_64) 566 | : sizeof(mach_header))); 567 | 568 | uint32_t* symtab = NULL; 569 | uint32_t* dysyms = NULL; 570 | const char* symstrtab = NULL; 571 | dyld_info_command* dyinfo = NULL; 572 | vector bind_sections_64; 573 | vector bind_sections_32; 574 | 575 | for (uint32_t ii = 0; ii < header->ncmds; ii++) { 576 | LOGF("cmd type:%x\n", cmds_ptr->cmd); 577 | 578 | switch (cmds_ptr->cmd) { 579 | case LC_SEGMENT_64: { 580 | readSegment( 581 | (char*)cmds_ptr, &segments64_, &bind_sections_64); 582 | break; 583 | } 584 | 585 | case LC_SEGMENT: { 586 | readSegment( 587 | (char*)cmds_ptr, &segments_, &bind_sections_32); 588 | break; 589 | } 590 | 591 | case LC_DYLD_INFO: 592 | case LC_DYLD_INFO_ONLY: { 593 | dyinfo = reinterpret_cast(cmds_ptr); 594 | LOGF("dyld info: rebase_off=%u rebase_size=%u " 595 | "bind_off=%u bind_size=%u " 596 | "weak_bind_off=%u weak_bind_size=%u " 597 | "lazy_bind_off=%u lazy_bind_size=%u " 598 | "export_off=%u export_size=%u\n", 599 | dyinfo->rebase_off, dyinfo->rebase_size, 600 | dyinfo->bind_off, dyinfo->bind_size, 601 | dyinfo->weak_bind_off, dyinfo->weak_bind_size, 602 | dyinfo->lazy_bind_off, dyinfo->lazy_bind_size, 603 | dyinfo->export_off, dyinfo->export_size); 604 | 605 | { 606 | const uint8_t* p = reinterpret_cast( 607 | bin + dyinfo->rebase_off); 608 | const uint8_t* end = p + dyinfo->rebase_size; 609 | if (dyinfo->rebase_off && dyinfo->rebase_size) { 610 | readRebase(p, end); 611 | } 612 | } 613 | 614 | { 615 | const uint8_t* p = reinterpret_cast( 616 | bin + dyinfo->bind_off); 617 | const uint8_t* end = p + dyinfo->bind_size; 618 | readBind(p, end, false); 619 | } 620 | 621 | { 622 | const uint8_t* p = reinterpret_cast( 623 | bin + dyinfo->lazy_bind_off); 624 | const uint8_t* end = p + dyinfo->lazy_bind_size; 625 | readBind(p, end, false); 626 | } 627 | 628 | { 629 | const uint8_t* p = reinterpret_cast( 630 | bin + dyinfo->weak_bind_off); 631 | const uint8_t* end = p + dyinfo->weak_bind_size; 632 | readBind(p, end, true); 633 | } 634 | 635 | if (need_exports_) { 636 | const uint8_t* p = reinterpret_cast( 637 | bin + dyinfo->export_off); 638 | const uint8_t* end = p + dyinfo->export_size; 639 | if (dyinfo->export_off && dyinfo->export_size) { 640 | string buf; 641 | readExport(p, p, end, &buf); 642 | } 643 | } 644 | 645 | break; 646 | } 647 | 648 | case LC_SYMTAB: { 649 | symtab_command* symtab_cmd = 650 | reinterpret_cast(cmds_ptr); 651 | 652 | LOGF("symoff=%u nsysm=%u stroff=%u strsize=%u\n", 653 | symtab_cmd->symoff, symtab_cmd->nsyms, 654 | symtab_cmd->stroff, symtab_cmd->strsize); 655 | 656 | uint32_t* symtab_top = symtab = 657 | reinterpret_cast(bin + symtab_cmd->symoff); 658 | symstrtab = bin + symtab_cmd->stroff; 659 | 660 | if (FLAGS_READ_SYMTAB) { 661 | for (uint32_t i = 0; i < symtab_cmd->nsyms; i++) { 662 | Symbol sym; 663 | nlist* nl = (nlist*)symtab; 664 | sym.name = symstrtab + nl->n_strx; 665 | if (is64_) { 666 | sym.addr = nl->n_value; 667 | symtab += 4; 668 | } else { 669 | sym.addr = (uint32_t)nl->n_value; 670 | symtab += 3; 671 | } 672 | 673 | LOGF("%d %s(%d) %p\n", 674 | i, sym.name.c_str(), nl->n_strx, (void*)sym.addr); 675 | symbols_.push_back(sym); 676 | } 677 | } 678 | 679 | // Will be used by other load commands. 680 | symtab = symtab_top; 681 | 682 | break; 683 | } 684 | 685 | case LC_DYSYMTAB: { 686 | dysymtab_command* dysymtab_cmd = 687 | reinterpret_cast(cmds_ptr); 688 | 689 | LOGF("dysym:\n" 690 | " ilocalsym=%u nlocalsym=%u\n" 691 | " iextdefsym=%u nextdefsym=%u\n" 692 | " iundefsym=%u nundefsym=%u\n" 693 | " tocoff=%u ntoc=%u\n" 694 | " modtaboff=%u nmodtab=%u\n" 695 | " extrefsymoff=%u nextrefsyms=%u\n" 696 | " indirectsymoff=%u nindirectsyms=%u\n" 697 | " extreloff=%u nextrel=%u\n" 698 | " locreloff=%u nlocrel=%u\n" 699 | , 700 | dysymtab_cmd->ilocalsym, dysymtab_cmd->nlocalsym, 701 | dysymtab_cmd->iextdefsym, dysymtab_cmd->nextdefsym, 702 | dysymtab_cmd->iundefsym, dysymtab_cmd->nundefsym, 703 | dysymtab_cmd->tocoff, dysymtab_cmd->ntoc, 704 | dysymtab_cmd->modtaboff, dysymtab_cmd->nmodtab, 705 | dysymtab_cmd->extrefsymoff, dysymtab_cmd->nextrefsyms, 706 | dysymtab_cmd->indirectsymoff, dysymtab_cmd->nindirectsyms, 707 | dysymtab_cmd->extreloff, dysymtab_cmd->nextrel, 708 | dysymtab_cmd->locreloff, dysymtab_cmd->nlocrel); 709 | 710 | if (dysymtab_cmd->nindirectsyms) { 711 | dysyms = reinterpret_cast( 712 | bin + dysymtab_cmd->indirectsymoff); 713 | } 714 | if (FLAGS_READ_DYSYMTAB) { 715 | for (uint32_t j = 0; j < dysymtab_cmd->nindirectsyms; j++) { 716 | uint32_t dysym = dysyms[j]; 717 | uint32_t index = dysym & 0x3fffffff; 718 | const char* local = 719 | (dysym & INDIRECT_SYMBOL_LOCAL) ? " local" : ""; 720 | const char* abs = 721 | (dysym & INDIRECT_SYMBOL_ABS) ? " abs" : ""; 722 | 723 | uint32_t* sym = symtab; 724 | sym += index * (is64_ ? 4 : 3); 725 | 726 | LOGF("dysym %d %s(%u)%s%s\n", 727 | j, symstrtab + sym[0], index, local, abs); 728 | } 729 | 730 | uint32_t* dymods = reinterpret_cast( 731 | bin + dysymtab_cmd->modtaboff); 732 | for (uint32_t j = 0; j < dysymtab_cmd->nmodtab; j++) { 733 | LOGF("dymods: %u\n", dymods[j]); 734 | } 735 | } 736 | 737 | break; 738 | } 739 | 740 | case LC_LOAD_DYLINKER: { 741 | lc_str name = reinterpret_cast(cmds_ptr)->name; 742 | LOGF("dylinker: %s\n", (char*)cmds_ptr + name.offset); 743 | break; 744 | } 745 | 746 | case LC_UUID: 747 | break; 748 | 749 | case LC_UNIXTHREAD: { 750 | uint32_t* p = reinterpret_cast(cmds_ptr); 751 | LOGF("UNIXTHREAD"); 752 | for (uint32_t i = 2; i < p[1]; i++) { 753 | LOGF(" %d:%x", i, p[i]); 754 | } 755 | LOGF("\n"); 756 | if (is64_) { 757 | entry_ = reinterpret_cast(cmds_ptr)[18]; 758 | } else { 759 | entry_ = reinterpret_cast(cmds_ptr)[14]; 760 | } 761 | LOGF("entry=%llx\n", (ull)entry_); 762 | break; 763 | } 764 | 765 | case LC_MAIN: { 766 | entry_ = 767 | reinterpret_cast(cmds_ptr)->entryoff; 768 | is_lc_main_entry_ = true; 769 | LOGF("MAIN entry=%llx\n", (ull)entry_); 770 | break; 771 | } 772 | 773 | case LC_LOAD_DYLIB: { 774 | dylib* lib = &reinterpret_cast(cmds_ptr)->dylib; 775 | LOGF("dylib: '%s'\n", (char*)cmds_ptr + lib->name.offset); 776 | dylibs_.push_back((char*)cmds_ptr + lib->name.offset); 777 | break; 778 | } 779 | 780 | } 781 | 782 | cmds_ptr = reinterpret_cast( 783 | reinterpret_cast(cmds_ptr) + cmds_ptr->cmdsize); 784 | } 785 | 786 | LOGF("%p vs %p\n", cmds_ptr, bin + mapped_size_); 787 | 788 | // No LC_DYLD_INFO_ONLY, we will read classic binding info. 789 | if (!dyinfo && dysyms && symtab && symstrtab) { 790 | for (size_t i = 0; i < bind_sections_64.size(); i++) { 791 | readClassicBind( 792 | *bind_sections_64[i], dysyms, symtab, symstrtab); 793 | } 794 | for (size_t i = 0; i < bind_sections_32.size(); i++) { 795 | readClassicBind
( 796 | *bind_sections_32[i], dysyms, symtab, symstrtab); 797 | } 798 | } 799 | } 800 | 801 | MachOImpl::~MachOImpl() { 802 | close(); 803 | } 804 | 805 | void MachOImpl::close() { 806 | for (size_t i = 0; i < binds_.size(); i++) { 807 | delete binds_[i]; 808 | } 809 | binds_.clear(); 810 | for (size_t i = 0; i < rebases_.size(); i++) { 811 | delete rebases_[i]; 812 | } 813 | rebases_.clear(); 814 | for (size_t i = 0; i < exports_.size(); i++) { 815 | delete exports_[i]; 816 | } 817 | exports_.clear(); 818 | 819 | if (mapped_) { 820 | munmap(mapped_, mapped_size_); 821 | ::close(fd_); 822 | mapped_ = NULL; 823 | fd_ = -1; 824 | } 825 | } 826 | 827 | MachO* MachO::read(const char* path, const char* arch, bool need_exports) { 828 | int fd = open(path, O_RDONLY); 829 | if (fd < 0) { 830 | fprintf(stderr, "%s: %s\n", path, strerror(errno)); 831 | exit(1); 832 | } 833 | 834 | size_t offset = 0, len = 0; 835 | map archs; 836 | if (readFatInfo(fd, &archs)) { 837 | map::const_iterator found = archs.find(arch); 838 | if (found == archs.end()) { 839 | fprintf(stderr, 840 | "%s is a fat binary, but doesn't contain %s binary\n", 841 | path, arch); 842 | exit(1); 843 | } 844 | offset = found->second.offset; 845 | len = found->second.size; 846 | LOGF("fat offset=%lu, len=%lu\n", 847 | (unsigned long)offset, (unsigned long)len); 848 | } 849 | 850 | return new MachOImpl(path, fd, offset, len, need_exports); 851 | } 852 | -------------------------------------------------------------------------------- /ld-mac.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Shinichiro Hamaji. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions 5 | // are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following 12 | // disclaimer in the documentation and/or other materials 13 | // provided with the distribution. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY 16 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR 19 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 22 | // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | // SUCH DAMAGE. 27 | 28 | // A Mach-O loader for linux. 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | 54 | #ifdef USE_LIBCXX 55 | #include 56 | #else 57 | #include 58 | #endif 59 | 60 | #include "env_flags.h" 61 | #include "fat.h" 62 | #include "log.h" 63 | #include "mach-o.h" 64 | 65 | using namespace std; 66 | #ifndef USE_LIBCXX 67 | using namespace std::tr1; 68 | #endif 69 | 70 | DEFINE_bool(TRACE_FUNCTIONS, false, "Show calling functions"); 71 | DEFINE_bool(PRINT_TIME, false, "Print time spent in this loader"); 72 | 73 | class MachO; 74 | 75 | static map g_rename; 76 | static vector g_bound_names; 77 | static set g_no_trampoline; 78 | 79 | struct Timer { 80 | Timer() : start_time(0) {} 81 | 82 | void start() { 83 | if (FLAGS_PRINT_TIME) { 84 | start_time = clock(); 85 | } 86 | } 87 | 88 | void print(const char* name) { 89 | if (FLAGS_PRINT_TIME) { 90 | double elapsed = ((double)clock() - start_time) / CLOCKS_PER_SEC; 91 | printf("Elapsed time (%s): %f sec\n", name, elapsed); 92 | } 93 | } 94 | 95 | clock_t start_time; 96 | }; 97 | 98 | class FileMap { 99 | public: 100 | void add(const MachO& mach, uintptr_t slide, uintptr_t base) { 101 | SymbolMap* symbol_map = new SymbolMap(); 102 | symbol_map->filename = mach.filename(); 103 | symbol_map->base = base; 104 | if (!maps_.insert(make_pair(base, symbol_map)).second) { 105 | err(1, "dupicated base addr: %p in %s", 106 | (void*)base, mach.filename().c_str()); 107 | } 108 | 109 | for (size_t i = 0; i < mach.symbols().size(); i++) { 110 | MachO::Symbol sym = mach.symbols()[i]; 111 | if (sym.name.empty() || sym.name[0] != '_') 112 | continue; 113 | sym.addr += slide; 114 | if (sym.addr < base) 115 | continue; 116 | symbol_map->symbols.insert(make_pair(sym.addr, sym.name.substr(1))); 117 | } 118 | } 119 | 120 | void addWatchDog(uintptr_t addr) { 121 | bool r = maps_.insert(make_pair(addr, (SymbolMap*)NULL)).second; 122 | CHECK(r); 123 | } 124 | 125 | const char* dumpSymbol(void* p) { 126 | uintptr_t addr = reinterpret_cast(p); 127 | map::const_iterator found = maps_.upper_bound(addr); 128 | if (found == maps_.begin() || found == maps_.end()) { 129 | return NULL; 130 | } 131 | 132 | --found; 133 | return dumpSymbolFromMap(*found->second, addr); 134 | } 135 | 136 | private: 137 | struct SymbolMap { 138 | string filename; 139 | map symbols; 140 | uintptr_t base; 141 | }; 142 | 143 | const char* dumpSymbolFromMap(const SymbolMap& symbol_map, uintptr_t addr) { 144 | uintptr_t file_offset = addr - symbol_map.base; 145 | 146 | // Use lower_bound as PC may be in just after call. 147 | map::const_iterator found = 148 | symbol_map.symbols.lower_bound(addr); 149 | if (found == symbol_map.symbols.begin()) { 150 | snprintf(dumped_stack_frame_buf_, 4095, "%s [%p(%lx)]", 151 | symbol_map.filename.c_str(), (void*)addr, (long)file_offset); 152 | return dumped_stack_frame_buf_; 153 | } 154 | 155 | --found; 156 | const char* name = found->second.c_str(); 157 | uintptr_t func_offset = addr - found->first; 158 | snprintf(dumped_stack_frame_buf_, 4095, "%s(%s+%lx) [%p(%lx)]", 159 | symbol_map.filename.c_str(), name, (long)func_offset, 160 | (void*)addr, (long)file_offset); 161 | return dumped_stack_frame_buf_; 162 | } 163 | 164 | map maps_; 165 | char dumped_stack_frame_buf_[4096]; 166 | }; 167 | 168 | static FileMap g_file_map; 169 | 170 | #ifdef __x86_64__ 171 | static const char* ARCH_NAME = "x86-64"; 172 | static const int BITS = 64; 173 | #else 174 | static const char* ARCH_NAME = "i386"; 175 | static const int BITS = 32; 176 | #endif 177 | 178 | static char* g_darwin_executable_path; 179 | 180 | static Timer g_timer; 181 | 182 | class MachOLoader; 183 | static MachOLoader* g_loader; 184 | 185 | static void initRename() { 186 | #define RENAME(src, dst) g_rename.insert(make_pair(#src, #dst)); 187 | #define WRAP(src) RENAME(src, __darwin_ ## src) 188 | #include "rename.tab" 189 | #undef RENAME 190 | #undef WRAP 191 | } 192 | 193 | static void initNoTrampoline() { 194 | #define NO_TRAMPOLINE(name) g_no_trampoline.insert(#name); 195 | #include "no_trampoline.tab" 196 | #undef NO_TRAMPOLINE 197 | } 198 | 199 | static void undefinedFunction() { 200 | fprintf(stderr, "Undefined function called\n"); 201 | abort(); 202 | } 203 | 204 | static void doNothing() { 205 | } 206 | 207 | static bool lookupDyldFunction(const char* name, uint64_t* addr) { 208 | LOG << "lookupDyldFunction: " << name << endl; 209 | *addr = (int64_t)&doNothing; 210 | return true; 211 | } 212 | 213 | static uint64_t alignMem(uint64_t p, uint64_t a) { 214 | a--; 215 | return (p + a) & ~a; 216 | } 217 | 218 | static void dumpInt(int bound_name_id) { 219 | if (bound_name_id < 0) { 220 | fprintf(stderr, "%d: negative bound function id\n", bound_name_id); 221 | return; 222 | } 223 | if (bound_name_id >= (int)g_bound_names.size()) { 224 | fprintf(stderr, "%d: bound function id overflow\n", bound_name_id); 225 | return; 226 | } 227 | if (g_bound_names[bound_name_id].empty()) { 228 | fprintf(stderr, "%d: unbound function id\n", bound_name_id); 229 | return; 230 | } 231 | printf("calling %s(%d)\n", 232 | g_bound_names[bound_name_id].c_str(), bound_name_id); 233 | fflush(stdout); 234 | } 235 | 236 | static MachO* loadDylib(string dylib) { 237 | static const char executable_str[] = "@executable_path"; 238 | static const size_t executable_str_len = strlen(executable_str); 239 | if (!strncmp(dylib.c_str(), executable_str, executable_str_len)) { 240 | string dir = g_darwin_executable_path; 241 | size_t found = dir.rfind('/'); 242 | if (found == string::npos) { 243 | dir = "."; 244 | } else { 245 | dir = dir.substr(0, found); 246 | } 247 | dylib.replace(0, executable_str_len, dir); 248 | } 249 | 250 | return MachO::read(dylib.c_str(), ARCH_NAME); 251 | } 252 | 253 | typedef unordered_map Exports; 254 | 255 | class MachOLoader { 256 | #ifdef __x86_64__ 257 | typedef uint64_t intptr; 258 | typedef segment_command_64 Segment; 259 | 260 | static const vector& getSegments(const MachO& mach) { 261 | return mach.segments64(); 262 | } 263 | #else 264 | typedef uint32_t intptr; 265 | typedef segment_command Segment; 266 | 267 | static const vector& getSegments(const MachO& mach) { 268 | return mach.segments(); 269 | } 270 | #endif 271 | 272 | public: 273 | MachOLoader() 274 | : last_addr_(0) { 275 | dylib_to_so_["/System/Library/Frameworks/CoreFoundation.framework" 276 | "/Versions/A/CoreFoundation"].push_back( 277 | "libCoreFoundation.so"); 278 | 279 | // From Xcode 5.1, clang requires libncurses. However, since libncurses.so 280 | // looks a linker script (at least ubuntu 12.04), we cannot dlopen it. 281 | // We need to load libtinfo.so and libncurses.so.5 both. 282 | dylib_to_so_["/usr/lib/libncurses.5.4.dylib"].push_back("libtinfo.so"); 283 | dylib_to_so_["/usr/lib/libncurses.5.4.dylib"].push_back("libncurses.so.5"); 284 | 285 | symbol_to_so_.insert(make_pair("uuid_clear", "libuuid.so")); 286 | symbol_to_so_.insert(make_pair("uuid_compare", "libuuid.so")); 287 | symbol_to_so_.insert(make_pair("uuid_copy", "libuuid.so")); 288 | symbol_to_so_.insert(make_pair("uuid_generate", "libuuid.so")); 289 | symbol_to_so_.insert(make_pair("uuid_generate_random", "libuuid.so")); 290 | symbol_to_so_.insert(make_pair("uuid_generate_time", "libuuid.so")); 291 | symbol_to_so_.insert(make_pair("uuid_is_null", "libuuid.so")); 292 | symbol_to_so_.insert(make_pair("uuid_pack", "libuuid.so")); 293 | symbol_to_so_.insert(make_pair("uuid_parse", "libuuid.so")); 294 | symbol_to_so_.insert(make_pair("uuid_unpack", "libuuid.so")); 295 | symbol_to_so_.insert(make_pair("uuid_unparse", "libuuid.so")); 296 | symbol_to_so_.insert(make_pair("uuid_unparse_lower", "libuuid.so")); 297 | symbol_to_so_.insert(make_pair("uuid_unparse_upper", "libuuid.so")); 298 | 299 | symbol_to_so_.insert(make_pair("MD5", "libcrypto.so")); 300 | symbol_to_so_.insert(make_pair("MD5_Final", "libcrypto.so")); 301 | symbol_to_so_.insert(make_pair("MD5_Init", "libcrypto.so")); 302 | symbol_to_so_.insert(make_pair("MD5_Update", "libcrypto.so")); 303 | 304 | symbol_to_so_.insert(make_pair("compress", "libz.so")); 305 | symbol_to_so_.insert(make_pair("compressBound", "libz.so")); 306 | symbol_to_so_.insert(make_pair("deflate", "libz.so")); 307 | symbol_to_so_.insert(make_pair("deflateEnd", "libz.so")); 308 | symbol_to_so_.insert(make_pair("deflateInit_", "libz.so")); 309 | symbol_to_so_.insert(make_pair("inflate", "libz.so")); 310 | symbol_to_so_.insert(make_pair("inflateEnd", "libz.so")); 311 | symbol_to_so_.insert(make_pair("inflateInit_", "libz.so")); 312 | symbol_to_so_.insert(make_pair("inflateReset", "libz.so")); 313 | symbol_to_so_.insert(make_pair("zError", "libz.so")); 314 | 315 | if (FLAGS_TRACE_FUNCTIONS) { 316 | // Push all arguments into stack. 317 | 318 | // push %rax 319 | pushTrampolineCode(0x50); 320 | // push %rdi 321 | pushTrampolineCode(0x57); 322 | // push %rsi 323 | pushTrampolineCode(0x56); 324 | // push %rdx 325 | pushTrampolineCode(0x52); 326 | // push %rcx 327 | pushTrampolineCode(0x51); 328 | // push %r8 329 | pushTrampolineCode(0x5041); 330 | // push %r9 331 | pushTrampolineCode(0x5141); 332 | 333 | // push %xmm0..%xmm7 334 | for (int i = 0; i < 8; i++) { 335 | // sub $8, %rsp 336 | pushTrampolineCode(0x08ec8348); 337 | 338 | // movq %xmmN, (%rsp) 339 | pushTrampolineCode(0xd60f66); 340 | pushTrampolineCode(4 + i * 8); 341 | pushTrampolineCode(0x24); 342 | } 343 | 344 | // mov %r10, %rdi 345 | pushTrampolineCode(0xd7894c); 346 | 347 | // mov $func, %rdx 348 | pushTrampolineCode(0xba48); 349 | pushTrampolineCode64((unsigned long long)(void*)&dumpInt); 350 | 351 | // call *%rdx 352 | pushTrampolineCode(0xd2ff); 353 | 354 | // pop %xmm7..%xmm0 355 | for (int i = 7; i >= 0; i--) { 356 | // movq (%rsp), %xmmN 357 | pushTrampolineCode(0x7e0ff3); 358 | pushTrampolineCode(4 + i * 8); 359 | pushTrampolineCode(0x24); 360 | 361 | // add $8, %rsp 362 | pushTrampolineCode(0x08c48348); 363 | } 364 | 365 | // pop %r9 366 | pushTrampolineCode(0x5941); 367 | // pop %r8 368 | pushTrampolineCode(0x5841); 369 | // pop %rcx 370 | pushTrampolineCode(0x59); 371 | // pop %rdx 372 | pushTrampolineCode(0x5a); 373 | // pop %rsi 374 | pushTrampolineCode(0x5e); 375 | // pop %rdi 376 | pushTrampolineCode(0x5f); 377 | // pop %rax 378 | pushTrampolineCode(0x58); 379 | 380 | // ret 381 | pushTrampolineCode(0xc3); 382 | } 383 | } 384 | 385 | void loadSegments(const MachO& mach, intptr* slide, intptr* base) { 386 | *base = 0; 387 | --*base; 388 | 389 | const vector& segments = getSegments(mach); 390 | for (size_t i = 0; i < segments.size(); i++) { 391 | Segment* seg = segments[i]; 392 | const char* name = seg->segname; 393 | if (!strcmp(name, SEG_PAGEZERO)) { 394 | continue; 395 | } 396 | 397 | LOG << seg->segname << ": " 398 | << "fileoff=" << seg->fileoff 399 | << ", vmaddr=" << seg->vmaddr << endl; 400 | 401 | int prot = 0; 402 | if (seg->initprot & VM_PROT_READ) { 403 | prot |= PROT_READ; 404 | } 405 | if (seg->initprot & VM_PROT_WRITE) { 406 | prot |= PROT_WRITE; 407 | } 408 | if (seg->initprot & VM_PROT_EXECUTE) { 409 | prot |= PROT_EXEC; 410 | } 411 | 412 | intptr filesize = alignMem(seg->filesize, 0x1000); 413 | intptr vmaddr = seg->vmaddr + *slide; 414 | if (vmaddr < last_addr_) { 415 | LOG << "will rebase: filename=" << mach.filename() 416 | << ", vmaddr=" << (void*)vmaddr 417 | << ", last_addr=" << (void*)last_addr_ << endl; 418 | CHECK(i == 0); 419 | vmaddr = last_addr_; 420 | *slide = vmaddr - seg->vmaddr; 421 | } 422 | *base = min(*base, vmaddr); 423 | 424 | intptr vmsize = alignMem(seg->vmsize, 0x1000); 425 | LOG << "mmap(file) " << mach.filename() << ' ' << name 426 | << ": " << (void*)vmaddr << "-" << (void*)(vmaddr + filesize) 427 | << " offset=" << mach.offset() + seg->fileoff << endl; 428 | if (filesize == 0) { 429 | continue; 430 | } 431 | void* mapped = mmap((void*)vmaddr, filesize, prot, 432 | MAP_PRIVATE | MAP_FIXED, 433 | mach.fd(), mach.offset() + seg->fileoff); 434 | if (mapped == MAP_FAILED) { 435 | err(1, "%s mmap(file) failed", mach.filename().c_str()); 436 | } 437 | 438 | if (vmsize != filesize) { 439 | LOG << "mmap(anon) " << mach.filename() << ' ' << name 440 | << ": " << (void*)(vmaddr + filesize) << "-" 441 | << (void*)(vmaddr + vmsize) 442 | << endl; 443 | CHECK(vmsize > filesize); 444 | void* mapped = mmap((void*)(vmaddr + filesize), 445 | vmsize - filesize, prot, 446 | MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 447 | 0, 0); 448 | if (mapped == MAP_FAILED) { 449 | err(1, "%s mmap(anon) failed", mach.filename().c_str()); 450 | } 451 | } 452 | 453 | last_addr_ = max(last_addr_, (intptr)vmaddr + vmsize); 454 | } 455 | } 456 | 457 | void doRebase(const MachO& mach, intptr slide) { 458 | for (size_t i = 0; i < mach.rebases().size(); i++) { 459 | const MachO::Rebase& rebase = *mach.rebases()[i]; 460 | switch (rebase.type) { 461 | case REBASE_TYPE_POINTER: { 462 | char** ptr = (char**)(rebase.vmaddr + slide); 463 | LOG << "rebase: " << i << ": " << (void*)rebase.vmaddr << ' ' 464 | << (void*)*ptr << " => " 465 | << (void*)(*ptr + slide) << " @" << ptr << endl; 466 | *ptr += slide; 467 | break; 468 | } 469 | 470 | default: 471 | fprintf(stderr, "Unknown rebase type: %d\n", rebase.type); 472 | exit(1); 473 | } 474 | } 475 | } 476 | 477 | void loadInitFuncs(const MachO& mach, intptr slide) { 478 | for (size_t i = 0; i < mach.init_funcs().size(); i++) { 479 | intptr addr = mach.init_funcs()[i] + slide; 480 | LOG << "Registering init func " << (void*)addr 481 | << " from " << mach.filename() << endl; 482 | init_funcs_.push_back(addr); 483 | } 484 | } 485 | 486 | void loadDylibs(const MachO& mach) { 487 | for (size_t i = 0; i < mach.dylibs().size(); i++) { 488 | string dylib = mach.dylibs()[i]; 489 | 490 | if (!loaded_dylibs_.insert(dylib).second) 491 | continue; 492 | 493 | if (dylib_to_so_.count(dylib)) { 494 | const vector& sos = dylib_to_so_[dylib]; 495 | for (size_t i = 0; i < sos.size(); ++i) { 496 | const string& so = sos[i]; 497 | LOG << "Loading " << so << " for " << dylib << endl; 498 | if (!dlopen(so.c_str(), RTLD_LAZY | RTLD_GLOBAL)) { 499 | fprintf(stderr, "Couldn't load %s for %s: %s\n", 500 | so.c_str(), dylib.c_str(), dlerror()); 501 | } 502 | } 503 | } 504 | 505 | // For now, we assume a dylib is a system library if its path 506 | // starts with / 507 | // TODO(hamaji): Do something? 508 | if (dylib[0] == '/') { 509 | continue; 510 | } 511 | 512 | unique_ptr dylib_mach(loadDylib(dylib)); 513 | load(*dylib_mach); 514 | } 515 | } 516 | 517 | void doBind(const MachO& mach, intptr slide) { 518 | string last_weak_name = ""; 519 | char* last_weak_sym = NULL; 520 | size_t seen_weak_bind_index = 0; 521 | size_t seen_weak_binds_orig_size = seen_weak_binds_.size(); 522 | 523 | unsigned int common_code_size = (unsigned int)trampoline_.size(); 524 | // Ensure that we won't change the address. 525 | trampoline_.reserve(common_code_size + 526 | (1 + 6 + 5 + 10 + 3 + 2 + 1) * mach.binds().size()); 527 | g_bound_names.resize(mach.binds().size()); 528 | 529 | for (size_t i = 0; i < mach.binds().size(); i++) { 530 | MachO::Bind* bind = mach.binds()[i]; 531 | if (bind->name[0] != '_') { 532 | LOG << bind->name << ": skipping" << endl; 533 | continue; 534 | } 535 | 536 | if (bind->type == BIND_TYPE_POINTER) { 537 | string name = bind->name + 1; 538 | void** ptr = (void**)(bind->vmaddr + slide); 539 | char* sym = NULL; 540 | 541 | if (bind->is_weak) { 542 | if (last_weak_name == name) { 543 | sym = last_weak_sym; 544 | } else { 545 | last_weak_name = name; 546 | if (seen_weak_bind_index != seen_weak_binds_orig_size && 547 | !strcmp(seen_weak_binds_[seen_weak_bind_index].first.c_str(), 548 | name.c_str())) { 549 | last_weak_sym = sym = 550 | seen_weak_binds_[seen_weak_bind_index].second; 551 | seen_weak_bind_index++; 552 | } else { 553 | if (bind->is_classic) { 554 | *ptr = last_weak_sym = (char*)bind->value; 555 | } else { 556 | const Exports::const_iterator export_found = 557 | exports_.find(bind->name); 558 | if (export_found != exports_.end()) { 559 | *ptr = last_weak_sym = (char*)export_found->second.addr; 560 | } else { 561 | last_weak_sym = (char*)*ptr; 562 | } 563 | } 564 | seen_weak_binds_.push_back(make_pair(name, last_weak_sym)); 565 | while (seen_weak_bind_index != seen_weak_binds_orig_size && 566 | strcmp( 567 | seen_weak_binds_[seen_weak_bind_index].first.c_str(), 568 | name.c_str()) <= 0) { 569 | seen_weak_bind_index++; 570 | } 571 | continue; 572 | } 573 | } 574 | } else { 575 | #ifndef __x86_64__ 576 | static const char* SUF_UNIX03 = "$UNIX2003"; 577 | static const size_t SUF_UNIX03_LEN = strlen(SUF_UNIX03); 578 | if (name.size() > SUF_UNIX03_LEN && 579 | !strcmp(name.c_str() + name.size() - SUF_UNIX03_LEN, 580 | SUF_UNIX03)) { 581 | name = name.substr(0, name.size() - SUF_UNIX03_LEN); 582 | } 583 | #endif 584 | 585 | map::const_iterator found = 586 | g_rename.find(name); 587 | if (found != g_rename.end()) { 588 | LOG << "Applying renaming: " << name 589 | << " => " << found->second.c_str() << endl; 590 | name = found->second.c_str(); 591 | } 592 | 593 | const Exports::const_iterator export_found = 594 | exports_.find(bind->name); 595 | if (export_found != exports_.end()) { 596 | sym = (char*)export_found->second.addr; 597 | } 598 | if (!sym) { 599 | sym = (char*)dlsym(RTLD_DEFAULT, name.c_str()); 600 | if (!sym) { 601 | map::const_iterator iter = 602 | symbol_to_so_.find(name); 603 | if (iter != symbol_to_so_.end()) { 604 | if (dlopen(iter->second.c_str(), RTLD_LAZY | RTLD_GLOBAL)) { 605 | sym = (char*)dlsym(RTLD_DEFAULT, name.c_str()); 606 | } else { 607 | fprintf(stderr, "Couldn't load %s for %s: %s\n", 608 | iter->second.c_str(), name.c_str(), dlerror()); 609 | } 610 | } 611 | } 612 | } 613 | if (!sym) { 614 | ERR << name << ": undefined symbol" << endl; 615 | sym = (char*)&undefinedFunction; 616 | } 617 | sym += bind->addend; 618 | } 619 | 620 | LOG << "bind " << name << ": " 621 | << *ptr << " => " << (void*)sym << " @" << ptr << endl; 622 | 623 | if (FLAGS_TRACE_FUNCTIONS && !g_no_trampoline.count(name)) { 624 | LOG << "Generating trampoline for " << name << "..." << endl; 625 | 626 | *ptr = &trampoline_[0] + trampoline_.size(); 627 | g_bound_names[i] = name; 628 | 629 | // push %rax ; to adjust alignment for sse 630 | pushTrampolineCode(0x50); 631 | 632 | // mov $i, %r10d 633 | pushTrampolineCode(0xba41); 634 | pushTrampolineCode32((unsigned int)i); 635 | 636 | // call &trampoline_[0] 637 | pushTrampolineCode(0xe8); 638 | pushTrampolineCode32((unsigned int)(-4-trampoline_.size())); 639 | 640 | // mov $sym, %r10 641 | pushTrampolineCode(0xba49); 642 | pushTrampolineCode64((unsigned long long)(void*)sym); 643 | // call *%r10 644 | pushTrampolineCode(0xd2ff41); 645 | 646 | // pop %r10 647 | pushTrampolineCode(0x5a41); 648 | 649 | // ret 650 | pushTrampolineCode(0xc3); 651 | } else { 652 | *ptr = sym; 653 | } 654 | } else { 655 | fprintf(stderr, "Unknown bind type: %d\n", bind->type); 656 | abort(); 657 | } 658 | } 659 | 660 | inplace_merge(seen_weak_binds_.begin(), 661 | seen_weak_binds_.begin() + seen_weak_binds_orig_size, 662 | seen_weak_binds_.end()); 663 | } 664 | 665 | void loadExports(const MachO& mach, intptr base, Exports* exports) { 666 | exports->rehash(exports->size() + mach.exports().size()); 667 | for (size_t i = 0; i < mach.exports().size(); i++) { 668 | MachO::Export exp = *mach.exports()[i]; 669 | exp.addr += base; 670 | // TODO(hamaji): Not 100% sure, but we may need to consider weak symbols. 671 | if (!exports->insert(make_pair(exp.name, exp)).second) { 672 | fprintf(stderr, "duplicated exported symbol: %s\n", exp.name.c_str()); 673 | } 674 | } 675 | } 676 | 677 | void loadSymbols(const MachO& mach, intptr slide, intptr base) { 678 | g_file_map.add(mach, slide, base); 679 | } 680 | 681 | void load(const MachO& mach, Exports* exports = NULL) { 682 | if (!exports) { 683 | exports = &exports_; 684 | } 685 | intptr slide = 0; 686 | intptr base = 0; 687 | 688 | loadSegments(mach, &slide, &base); 689 | 690 | doRebase(mach, slide); 691 | 692 | loadInitFuncs(mach, slide); 693 | 694 | loadDylibs(mach); 695 | 696 | loadExports(mach, base, exports); 697 | 698 | doBind(mach, slide); 699 | 700 | loadSymbols(mach, slide, base); 701 | } 702 | 703 | void setupDyldData(const MachO& mach) { 704 | if (!mach.dyld_data()) 705 | return; 706 | 707 | void** dyld_data = (void**)mach.dyld_data(); 708 | dyld_data[1] = reinterpret_cast(&lookupDyldFunction); 709 | } 710 | 711 | void runInitFuncs(int argc, char** argv, char** envp, char** apple) { 712 | for (size_t i = 0; i < init_funcs_.size(); i++) { 713 | void** init_func = (void**)init_funcs_[i]; 714 | LOG << "calling initializer function " << *init_func << endl; 715 | if (argc >= 0) { 716 | ((void(*)(int, char**, char**, char**))*init_func)( 717 | argc, argv, envp, apple); 718 | } else { 719 | ((void(*)())*init_func)(); 720 | } 721 | } 722 | init_funcs_.clear(); 723 | } 724 | 725 | void run(MachO& mach, int argc, char** argv, char** envp) { 726 | // I don't understand what it is. 727 | char* apple[2]; 728 | apple[0] = argv[0]; 729 | apple[1] = NULL; 730 | 731 | load(mach); 732 | setupDyldData(mach); 733 | 734 | g_file_map.addWatchDog(last_addr_ + 1); 735 | 736 | char* trampoline_start_addr = 737 | (char*)(((uintptr_t)&trampoline_[0]) & ~0xfff); 738 | uint64_t trampoline_size = 739 | alignMem(&trampoline_[0] + trampoline_.size() - trampoline_start_addr, 740 | 0x1000); 741 | mprotect(trampoline_start_addr, trampoline_size, 742 | PROT_READ | PROT_WRITE | PROT_EXEC); 743 | 744 | g_timer.print(mach.filename().c_str()); 745 | 746 | mach.close(); 747 | 748 | runInitFuncs(argc, argv, envp, apple); 749 | 750 | LOG << "booting from " << (void*)mach.entry() << "..." << endl; 751 | fflush(stdout); 752 | CHECK(argc > 0); 753 | 754 | if (mach.is_lc_main_entry()) { 755 | uint64_t entry = mach.entry() + mach.text_base(); 756 | exit(((int (*)(int, char**, char**))entry)(argc, argv, envp)); 757 | } else { 758 | boot(mach.entry(), argc, argv, envp); 759 | } 760 | /* 761 | int (*fp)(int, char**, char**) = 762 | (int(*)(int, char**, char**))mach.entry(); 763 | int ret = fp(argc, argv, envp); 764 | exit(ret); 765 | */ 766 | } 767 | 768 | private: 769 | // Because .loop64 cannot be redefined. 770 | __attribute__((noinline)) 771 | void boot(uint64_t entry, int argc, char** argv, char** envp); 772 | 773 | void pushTrampolineCode(unsigned int c) { 774 | while (c) { 775 | trampoline_.push_back(c & 255); 776 | c = c >> 8; 777 | } 778 | } 779 | 780 | void pushTrampolineCode64(unsigned long long c) { 781 | for (int i = 0; i < 8; i++) { 782 | trampoline_.push_back(c & 255); 783 | c = c >> 8; 784 | } 785 | } 786 | 787 | void pushTrampolineCode32(unsigned int c) { 788 | for (int i = 0; i < 4; i++) { 789 | trampoline_.push_back(c & 255); 790 | c = c >> 8; 791 | } 792 | } 793 | 794 | string trampoline_; 795 | intptr last_addr_; 796 | vector init_funcs_; 797 | Exports exports_; 798 | vector > seen_weak_binds_; 799 | map > dylib_to_so_; 800 | map symbol_to_so_; 801 | set loaded_dylibs_; 802 | }; 803 | 804 | void MachOLoader::boot( 805 | uint64_t entry, int argc, char** argv, char** envp) { 806 | #ifdef __x86_64__ 807 | // 0x08: argc 808 | // 0x10: argv[0] 809 | // 0x18: argv[1] 810 | // ...: argv[n] 811 | // 0 812 | // envp[0] 813 | // envp[1] 814 | // envp[n] 815 | __asm__ volatile(" mov %1, %%eax;\n" 816 | " mov %2, %%rdx;\n" 817 | " push $0;\n" 818 | // TODO(hamaji): envp 819 | " push $0;\n" 820 | ".loop64:\n" 821 | " sub $8, %%rdx;\n" 822 | " push (%%rdx);\n" 823 | " dec %%eax;\n" 824 | " jnz .loop64;\n" 825 | " mov %1, %%eax;\n" 826 | " push %%rax;\n" 827 | " jmp *%0;\n" 828 | ::"r"(entry), "r"(argc), "r"(argv + argc), "r"(envp) 829 | :"%rax", "%rdx"); 830 | //fprintf(stderr, "done!\n"); 831 | #else 832 | __asm__ volatile(" mov %1, %%eax;\n" 833 | " mov %2, %%edx;\n" 834 | " push $0;\n" 835 | ".loop32:\n" 836 | " sub $4, %%edx;\n" 837 | " push (%%edx);\n" 838 | " dec %%eax;\n" 839 | " jnz .loop32;\n" 840 | " mov %1, %%eax;\n" 841 | " push %%eax;\n" 842 | " jmp *%0;\n" 843 | // TODO(hamaji): Fix parameters 844 | ::"r"(entry), "r"(argc), "r"(argv + argc), "g"(envp) 845 | :"%eax", "%edx"); 846 | #endif 847 | } 848 | 849 | void runMachO(MachO& mach, int argc, char** argv, char** envp) { 850 | MachOLoader loader; 851 | g_loader = &loader; 852 | loader.run(mach, argc, argv, envp); 853 | g_loader = NULL; 854 | } 855 | 856 | #if 0 857 | static int getBacktrace(void** trace, int max_depth) { 858 | typedef struct frame { 859 | struct frame *bp; 860 | void *ret; 861 | } frame; 862 | 863 | int depth; 864 | frame* bp = (frame*)__builtin_frame_address(0); 865 | for (depth = 0; bp && depth < max_depth; depth++) { 866 | trace[depth] = bp->ret; 867 | bp = bp->bp; 868 | } 869 | return depth; 870 | } 871 | #endif 872 | 873 | extern "C" { 874 | const char* dumpSymbol(void* p) { 875 | return g_file_map.dumpSymbol(p); 876 | } 877 | } 878 | 879 | /* signal handler for fatal errors */ 880 | static void handleSignal(int signum, siginfo_t* siginfo, void* vuc) { 881 | ucontext_t *uc = (ucontext_t*)vuc; 882 | void* pc = (void*)uc->uc_mcontext.gregs[ 883 | #ifdef __x86_64__ 884 | REG_RIP 885 | #else 886 | REG_EIP 887 | #endif 888 | ]; 889 | 890 | fprintf(stderr, "%s(%d) %d (@%p) PC: %p\n\n", 891 | strsignal(signum), signum, siginfo->si_code, siginfo->si_addr, pc); 892 | 893 | void* trace[100]; 894 | int len = backtrace(trace, 99); 895 | //int len = getBacktrace(trace, 99); 896 | char** syms = backtrace_symbols(trace, len); 897 | for (int i = len - 1; i > 0; i--) { 898 | if (syms[i] && syms[i][0] != '[') { 899 | fprintf(stderr, "%s\n", syms[i]); 900 | } else { 901 | const char* s = dumpSymbol(trace[i]); 902 | if (s) { 903 | fprintf(stderr, "%s\n", s); 904 | } else { 905 | fprintf(stderr, "%p\n", trace[i]); 906 | } 907 | } 908 | } 909 | } 910 | 911 | /* Generate a stack backtrace when a CPU exception occurs. */ 912 | static void initSignalHandler() { 913 | struct sigaction sigact; 914 | sigact.sa_flags = SA_SIGINFO | SA_RESETHAND; 915 | sigact.sa_sigaction = handleSignal; 916 | sigemptyset(&sigact.sa_mask); 917 | sigaction(SIGFPE, &sigact, NULL); 918 | sigaction(SIGILL, &sigact, NULL); 919 | sigaction(SIGSEGV, &sigact, NULL); 920 | sigaction(SIGBUS, &sigact, NULL); 921 | sigaction(SIGABRT, &sigact, NULL); 922 | } 923 | 924 | static bool loadLibMac(const char* mypath) { 925 | if (dlopen("libmac.so", RTLD_LAZY | RTLD_GLOBAL)) { 926 | return true; 927 | } 928 | 929 | char buf[PATH_MAX + 100]; 930 | strcpy(buf, mypath); 931 | char* p = strrchr(buf, '/'); 932 | if (!p) { 933 | fprintf(stderr, "Weird loader path: %s\n", mypath); 934 | exit(1); 935 | } 936 | strcpy(p, "/libmac.so"); 937 | 938 | if (dlopen(buf, RTLD_LAZY | RTLD_GLOBAL)) { 939 | return true; 940 | } 941 | 942 | sprintf(p, "/libmac%d.so", BITS); 943 | if (dlopen(buf, RTLD_LAZY | RTLD_GLOBAL)) { 944 | return true; 945 | } 946 | 947 | return false; 948 | } 949 | 950 | static void initLibMac() { 951 | char mypath[PATH_MAX + 1]; 952 | ssize_t l = readlink("/proc/self/exe", mypath, PATH_MAX); 953 | if (l < 0) { 954 | err(1, "readlink for /proc/self/exe"); 955 | } 956 | mypath[l] = '\0'; 957 | 958 | if (!loadLibMac(mypath)) { 959 | fprintf(stderr, "libmac not found\n"); 960 | exit(1); 961 | } 962 | 963 | int* LIBMAC_LOG = (int*)dlsym(RTLD_DEFAULT, "LIBMAC_LOG"); 964 | if (LIBMAC_LOG) { 965 | *LIBMAC_LOG = FLAGS_LOG; 966 | } 967 | 968 | char* loader_path = (char*)dlsym(RTLD_DEFAULT, "__loader_path"); 969 | if (!loader_path) { 970 | fprintf(stderr, "wrong libmac: __loader_path not found\n"); 971 | exit(1); 972 | } 973 | strcpy(loader_path, mypath); 974 | } 975 | 976 | static string ld_mac_dlerror_buf; 977 | static bool ld_mac_dlerror_is_set; 978 | 979 | static void* ld_mac_dlopen(const char* filename, int flag) { 980 | LOG << "ld_mac_dlopen: " << filename << " " << flag << endl; 981 | 982 | Timer timer; 983 | timer.start(); 984 | 985 | // TODO(hamaji): Handle failures. 986 | unique_ptr dylib_mach(loadDylib(filename)); 987 | 988 | MachOLoader* loader = g_loader; 989 | CHECK(loader); 990 | Exports* exports = new Exports(); 991 | loader->load(*dylib_mach, exports); 992 | 993 | timer.print(filename); 994 | 995 | loader->runInitFuncs(-1, NULL, NULL, NULL); 996 | return exports; 997 | } 998 | 999 | static int ld_mac_dlclose(void* handle) { 1000 | LOG << "ld_mac_dlclose" << endl; 1001 | 1002 | delete (Exports*)handle; 1003 | return 0; 1004 | } 1005 | 1006 | static const char* ld_mac_dlerror(void) { 1007 | LOG << "ld_mac_dlerror" << endl; 1008 | 1009 | if (!ld_mac_dlerror_is_set) 1010 | return NULL; 1011 | ld_mac_dlerror_is_set = false; 1012 | return ld_mac_dlerror_buf.c_str(); 1013 | } 1014 | 1015 | static void* ld_mac_dlsym(void* handle, const char* symbol) { 1016 | LOG << "ld_mac_dlsym: " << symbol << endl; 1017 | 1018 | Exports* exports = (Exports*)handle; 1019 | Exports::const_iterator found = exports->find(string("_") + symbol); 1020 | if (found == exports->end()) { 1021 | ld_mac_dlerror_is_set = true; 1022 | ld_mac_dlerror_buf = string("undefined symbol: ") + symbol; 1023 | return NULL; 1024 | } 1025 | return (void*)found->second.addr; 1026 | } 1027 | 1028 | void initDlfcn() { 1029 | #define SET_DLFCN_FUNC(f) \ 1030 | do { \ 1031 | void** p = (void**)dlsym(RTLD_DEFAULT, "ld_mac_" #f); \ 1032 | *p = (void*)&ld_mac_ ## f; \ 1033 | } while (0) 1034 | 1035 | SET_DLFCN_FUNC(dlopen); 1036 | SET_DLFCN_FUNC(dlclose); 1037 | SET_DLFCN_FUNC(dlerror); 1038 | SET_DLFCN_FUNC(dlsym); 1039 | } 1040 | 1041 | int main(int argc, char* argv[], char* envp[]) { 1042 | g_timer.start(); 1043 | initSignalHandler(); 1044 | initRename(); 1045 | initNoTrampoline(); 1046 | initLibMac(); 1047 | initDlfcn(); 1048 | 1049 | argc--; 1050 | argv++; 1051 | for (;;) { 1052 | if (argc == 0) { 1053 | fprintf(stderr, "An argument required.\n"); 1054 | exit(1); 1055 | } 1056 | 1057 | const char* arg = argv[0]; 1058 | if (arg[0] != '-') { 1059 | break; 1060 | } 1061 | 1062 | // TODO(hamaji): Do something for switches. 1063 | 1064 | argc--; 1065 | argv++; 1066 | } 1067 | 1068 | g_darwin_executable_path = 1069 | (char*)dlsym(RTLD_DEFAULT, "__darwin_executable_path"); 1070 | if (!realpath(argv[0], g_darwin_executable_path)) { 1071 | } 1072 | 1073 | unique_ptr mach(MachO::read(argv[0], ARCH_NAME)); 1074 | #ifdef __x86_64__ 1075 | if (!mach->is64()) { 1076 | fprintf(stderr, "%s: not 64bit binary\n", argv[0]); 1077 | exit(1); 1078 | } 1079 | #else 1080 | if (mach->is64()) { 1081 | fprintf(stderr, "%s: not 32bit binary\n", argv[0]); 1082 | exit(1); 1083 | } 1084 | #endif 1085 | runMachO(*mach, argc, argv, envp); 1086 | } 1087 | --------------------------------------------------------------------------------