this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add initial code for stubgen64 (Mach-O wrapping of ELF libraries)

+365 -42
+24
src/dyld/32in64.h
··· 1 + #ifndef _32IN64_H 2 + #define _32IN64_H 3 + 4 + #ifdef __x86_64__ 5 + 6 + // Jump to a 32-bit address through segment number 0x23 (32-bit). The 64-bit segment is 0x33. 7 + // Set DS to 0x2B. 8 + #define _64TO32_WITH_STACK(sp, addr) __asm__ volatile("movq %1, %%rsp;" \ 9 + "subq $12, %%rsp;" \ 10 + /*"movq %0, %%rax;"*/ \ 11 + "movl %0, 8(%%rsp);" \ 12 + "movl $0x23, 4(%%rsp);" \ 13 + "leaq 1f, %%rax;" \ 14 + "movl %%eax, (%%rsp);" \ 15 + "lret;" \ 16 + ".code32;\n" \ 17 + "1: push $0x2b;" \ 18 + "pop %%ds;" \ 19 + "ret;" \ 20 + :: "r"((uint32_t)addr), "r"(sp) : "rax") 21 + 22 + #endif 23 + #endif 24 +
+5 -1
src/dyld/CMakeLists.txt
··· 22 22 threads.c 23 23 gdb.c 24 24 commpage.c 25 + elfcalls.c 25 26 ) 26 27 add_executable(mldr ${mldr_sources}) 27 - target_link_libraries(mldr -lpthread -ldl) 28 + target_link_libraries(mldr pthread dl) 29 + 30 + add_executable(stubgen64 stubgen/stubgen64.c) 31 + target_link_libraries(stubgen64 dl) 28 32 29 33 install(TARGETS mldr DESTINATION libexec/darling/bin) 30 34 install(TARGETS darling DESTINATION bin
+65
src/dyld/elfcalls.c
··· 1 + #include <dlfcn.h> 2 + #include <stdio.h> 3 + #include <stdlib.h> 4 + #include "elfcalls.h" 5 + #include "threads.h" 6 + 7 + static void* dlopen_simple(const char* name) 8 + { 9 + return dlopen(name, RTLD_LAZY); 10 + } 11 + 12 + static void* dlopen_fatal(const char* name) 13 + { 14 + void* rv = dlopen_simple(name); 15 + if (!rv) 16 + { 17 + fprintf(stderr, "Cannot load %s (ELF): %s\n", name, dlerror()); 18 + abort(); 19 + } 20 + return rv; 21 + } 22 + 23 + static void* dlsym_fatal(void* handle, const char* sym) 24 + { 25 + void* addr = dlsym(handle, sym); 26 + if (!addr) 27 + { 28 + fprintf(stderr, "Failed to lookup symbol %s (ELF): %s\n", sym, dlerror()); 29 + abort(); 30 + } 31 + return addr; 32 + } 33 + 34 + static int dlclose_fatal(void* handle) 35 + { 36 + if (dlclose(handle) != 0) 37 + { 38 + fprintf(stderr, "Cannot dlclose library (ELF): %s\n", dlerror()); 39 + abort(); 40 + } 41 + return 0; 42 + } 43 + 44 + char* elfcalls_make(void) 45 + { 46 + static char param[32]; 47 + static struct elf_calls calls; 48 + 49 + calls.dlopen = dlopen_simple; 50 + calls.dlclose = dlclose; 51 + calls.dlsym = dlsym; 52 + calls.dlerror = dlerror; 53 + 54 + calls.dlopen_fatal = dlopen_fatal; 55 + calls.dlsym_fatal = dlsym_fatal; 56 + calls.dlclose_fatal = dlclose_fatal; 57 + 58 + calls.darling_thread_create = __darling_thread_create; 59 + calls.darling_thread_terminate = __darling_thread_terminate; 60 + calls.darling_thread_get_stack = __darling_thread_get_stack; 61 + 62 + sprintf(param, "elf_calls=%p", &calls); 63 + return param; 64 + } 65 +
+4
src/dyld/elfcalls.h
··· 15 15 int (*darling_thread_terminate)(void* stackaddr, 16 16 unsigned long freesize, unsigned long pthobj_size); 17 17 void* (*darling_thread_get_stack)(void); 18 + void* (*dlopen_fatal)(const char* name); 19 + int (*dlclose_fatal)(void* lib); 20 + void* (*dlsym_fatal)(void* lib, const char* name); 21 + 18 22 }; 19 23 20 24 #endif
+3 -41
src/dyld/mldr.c
··· 33 33 #include <dlfcn.h> 34 34 #include <endian.h> 35 35 #include "elfcalls.h" 36 - #include "threads.h" 37 36 #include "gdb.h" 38 37 #include "commpage.h" 38 + #include "32in64.h" 39 39 40 40 #ifndef PAGE_SIZE 41 41 # define PAGE_SIZE 4096 ··· 61 61 static void load(const char* path, uint64_t* entryPoint_out, uint64_t* mh_out, cpu_type_t cpu); 62 62 static int native_prot(int prot); 63 63 static void apply_root_path(char* path); 64 - static char* elfcalls_make(void); 64 + char* elfcalls_make(void); 65 65 static char* apple0_make(const char* filepath); 66 66 static void* setup_stack32(void* stack, int argc, const char** argv, const char** envp, const char** apple, uint64_t mh); 67 67 ··· 109 109 #ifdef __x86_64__ 110 110 # define GETSP(ptr) __asm__ volatile("movq %%rsp, %0" : "=r"(ptr) ::) 111 111 # define JUMPX(pushCount, addr) __asm__ volatile("sub %1, %%rsp; jmpq *%0" :: "m"(addr), "r"(pushCount * sizeof(void*)) :) 112 - 113 - // Jump to a 32-bit address through segment number 0x23 (32-bit). The 64-bit segment is 0x33. 114 - // Set DS to 0x2B. 115 - # define JUMPSP(sp, addr) __asm__ volatile("movq %1, %%rsp;" \ 116 - "subq $12, %%rsp;" \ 117 - /*"movq %0, %%rax;"*/ \ 118 - "movl %0, 8(%%rsp);" \ 119 - "movl $0x23, 4(%%rsp);" \ 120 - "leaq 1f, %%rax;" \ 121 - "movl %%eax, (%%rsp);" \ 122 - "lret;" \ 123 - ".code32;\n" \ 124 - "1: push $0x2b;" \ 125 - "pop %%ds;" \ 126 - "ret;" \ 127 - :: "r"((uint32_t)addr), "r"(sp) : "rax") 128 112 #elif defined(__i386__) 129 113 # define GETSP(ptr) __asm__ volatile("movl %%esp, %0" : "=m"(ptr) ::) 130 114 # define JUMPX(pushCount, addr) __asm__ volatile("sub %1, %%esp; jmp *%0" :: "m"(addr), "r"(pushCount * sizeof(void*)) :) ··· 174 158 // move to the top of the stack 175 159 sp += size/sizeof(void*) - 1; 176 160 177 - JUMPSP(setup_stack32(sp, argc, (const char**) argv, (const char**) envp, apple, mh), entryPoint); 161 + _64TO32_WITH_STACK(setup_stack32(sp, argc, (const char**) argv, (const char**) envp, apple, mh), entryPoint); 178 162 } 179 163 180 164 ··· 436 420 } 437 421 } 438 422 while (next != NULL); 439 - } 440 - 441 - static void* dlopen_simple(const char* name) 442 - { 443 - return dlopen(name, RTLD_LAZY); 444 - } 445 - 446 - static char* elfcalls_make(void) 447 - { 448 - static char param[32]; 449 - static struct elf_calls calls; 450 - 451 - calls.dlopen = dlopen_simple; 452 - calls.dlclose = dlclose; 453 - calls.dlsym = dlsym; 454 - calls.dlerror = dlerror; 455 - calls.darling_thread_create = __darling_thread_create; 456 - calls.darling_thread_terminate = __darling_thread_terminate; 457 - calls.darling_thread_get_stack = __darling_thread_get_stack; 458 - 459 - sprintf(param, "elf_calls=%p", &calls); 460 - return param; 461 423 } 462 424 463 425 char* apple0_make(const char* filepath)
+264
src/dyld/stubgen/stubgen64.c
··· 1 + #ifndef _GNU_SOURCE 2 + # define _GNU_SOURCE 3 + #endif 4 + 5 + #include <stdio.h> 6 + #include <stdlib.h> 7 + #include <string.h> 8 + #include <unistd.h> 9 + #include <elf.h> 10 + #include <errno.h> 11 + #include <dlfcn.h> 12 + 13 + #ifndef PATH_MAX 14 + # define PATH_MAX 4096 15 + #endif 16 + 17 + // This is a generator of assembly code for Mach-O 18 + // libraries wrapping ELF libraries. 19 + 20 + // TODO: use stubgen32 to generate 32-bit wrappers. 21 + 22 + const char* get_soname(const char* elf); 23 + void generate_wrapper(const char* soname, const char* symbols); 24 + 25 + int main(int argc, const char** argv) 26 + { 27 + const char* elfLibrary; 28 + const char* symbols; 29 + const char* soname; 30 + 31 + if (argc != 3) 32 + { 33 + fprintf(stderr, "Usage: %s <library-name> <symbols>\n", argv[0]); 34 + fprintf(stderr, "...where symbols should be semicolon-separated (CMake string list)\n"); 35 + exit(1); 36 + } 37 + 38 + elfLibrary = argv[1]; 39 + symbols = argv[2]; 40 + 41 + if (access(elfLibrary, R_OK) == -1) 42 + { 43 + // Try loading the library and then ask the loader where it found the library. 44 + // It is simpler than parsing /etc/ld.so.conf. 45 + 46 + void* handle = dlopen(elfLibrary, RTLD_LAZY | RTLD_LOCAL); 47 + char path[PATH_MAX]; 48 + 49 + if (!handle) 50 + { 51 + fprintf(stderr, "Cannot load %s: %s\n", elfLibrary, dlerror()); 52 + exit(1); 53 + } 54 + 55 + if (dlinfo(handle, RTLD_DI_ORIGIN, path) == 0) 56 + { 57 + strcat(path, "/"); 58 + strcat(path, elfLibrary); 59 + elfLibrary = strdup(path); 60 + } 61 + else 62 + { 63 + fprintf(stderr, "Cannot locate %s: %s.\n", elfLibrary, dlerror()); 64 + exit(1); 65 + } 66 + 67 + dlclose(handle); 68 + } 69 + library_found: 70 + 71 + soname = get_soname(elfLibrary); 72 + 73 + generate_wrapper(soname, symbols); 74 + 75 + return 0; 76 + } 77 + 78 + const char* get_soname(const char* elf) 79 + { 80 + FILE* file; 81 + Elf64_Ehdr ehdr; 82 + 83 + file = fopen(elf, "rb"); 84 + if (!file) 85 + { 86 + fprintf(stderr, "Error opening %s: %s\n", elf, strerror(errno)); 87 + exit(1); 88 + } 89 + 90 + if (fread(&ehdr, 1, sizeof(ehdr), file) != sizeof(ehdr)) 91 + { 92 + fprintf(stderr, "Error reading %s\n", elf); 93 + exit(1); 94 + } 95 + 96 + if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || ehdr.e_ident[EI_CLASS] != ELFCLASS64) 97 + { 98 + fprintf(stderr, "%s is not a 64-bit ELF\n", elf); 99 + exit(1); 100 + } 101 + 102 + if (ehdr.e_type != ET_DYN) 103 + { 104 + fprintf(stderr, "%s is not a dynamic library ELF\n", elf); 105 + exit(1); 106 + } 107 + 108 + if (ehdr.e_machine != EM_X86_64) 109 + { 110 + fprintf(stderr, "%s is not an ELF for x86-64\n", elf); 111 + exit(1); 112 + } 113 + 114 + // Now read program headers, find a PT_DYNAMIC segment type 115 + for (int i = 0; i < ehdr.e_phnum; i++) 116 + { 117 + Elf64_Phdr phdr; 118 + 119 + fseek(file, ehdr.e_phoff + (i * ehdr.e_phentsize), SEEK_SET); 120 + if (fread(&phdr, 1, sizeof(phdr), file) != sizeof(phdr)) 121 + { 122 + fprintf(stderr, "Cannot read ELF phdr in %s\n", elf); 123 + exit(1); 124 + } 125 + 126 + if (phdr.p_type == PT_DYNAMIC) 127 + { 128 + Elf64_Xword off_strtab, off_soname; 129 + 130 + off_strtab = off_soname = 0; 131 + 132 + // Inside the PT_DYNAMIC segment, look for a DT_SONAME tag in Elf64_Dyn.d_tag 133 + fseek(file, phdr.p_offset, SEEK_SET); 134 + 135 + for (int j = 0; j < phdr.p_filesz; j += sizeof(Elf64_Dyn)) 136 + { 137 + Elf64_Dyn dyn; 138 + if (fread(&dyn, 1, sizeof(dyn), file) != sizeof(dyn)) 139 + { 140 + fprintf(stderr, "Cannot read PT_DYNAMIC entry in %s\n", elf); 141 + exit(1); 142 + } 143 + 144 + if (dyn.d_tag == DT_STRTAB) 145 + off_strtab = dyn.d_un.d_val; 146 + else if (dyn.d_tag == DT_SONAME) 147 + off_soname = dyn.d_un.d_val; 148 + } 149 + 150 + if (off_strtab != 0 && off_soname != 0) 151 + { 152 + char soname[256]; 153 + 154 + // Read DT_SONAME value from the string table 155 + fseek(file, off_strtab + off_soname, SEEK_SET); 156 + fread(soname, 1, sizeof(soname)-1, file); 157 + soname[255] = '\0'; 158 + 159 + fclose(file); 160 + 161 + return strdup(soname); 162 + } 163 + 164 + break; 165 + } 166 + } 167 + 168 + fprintf(stderr, "WARNING: No DT_SONAME in %s.\n", elf); 169 + fclose(file); 170 + 171 + const char* slash = strrchr(elf, '/'); 172 + if (slash != NULL) 173 + return slash + 1; 174 + else 175 + return elf; 176 + } 177 + 178 + void define_string(const char* name, const char* value) 179 + { 180 + printf(".section __TEXT,__cstring,cstring_literals\n"); 181 + printf("%s: .asciz \"%s\"\n", name, value); 182 + } 183 + 184 + void print_init_exit(void) 185 + { 186 + puts(".zerofill __DATA,__bss,_lib_handle,8,3\n"); 187 + puts(".section __TEXT,__text,regular,pure_instructions\n"); 188 + 189 + puts("_initializer:\n" 190 + "\tpushq %rdi\n" 191 + "\tmovq __elfcalls@GOTPCREL(%rip), %rax\n" 192 + "\tmovq _library_name(%rip), %rdi\n" 193 + "\tcallq *56(%rax)\n" // dlopen_fatal 194 + "\tmovq %rax, _lib_handle(%rip)\n" 195 + "\tpopq %rdi\n" 196 + "\tret\n"); 197 + 198 + puts("_destructor:\n" 199 + "\tpushq %rdi\n" 200 + "\tmovq __elfcalls@GOTPCREL(%rip), %rcx\n" 201 + "\tmovq _lib_handle(%rip), %rdi\n" 202 + "\tcallq *64(%rcx)\n" // dlclose_fatal 203 + "\tpopq %rdi\n" 204 + "\tret\n"); 205 + 206 + puts(".section __DATA,__mod_init_func,mod_init_funcs\n" 207 + ".align 3\n" 208 + ".long _initializer\n" 209 + ".section __DATA,__mod_term_func,mod_term_funcs\n" 210 + ".align 3\n" 211 + ".long _destructor\n"); 212 + 213 + puts(".macro loadfunc\n" 214 + "\tpushq %rdi\n" 215 + "\tpushq %rsi\n" 216 + "\tmovq _lib_handle(%rip), %rdi\n" 217 + "\tmovq $0(%rip), %rsi\n" 218 + "\tmovq __elfcalls@GOTPCREL(%rip), %rax\n" 219 + "\tcallq *72(%rax)\n" // dlsym_fatal 220 + "\tmovq %rax, $1(%rip)\n" 221 + "\tpopq %rsi\n" 222 + "\tpopq %rdi\n" 223 + ".endmacro\n"); 224 + } 225 + 226 + void generate_wrapper(const char* soname, const char* symbols) 227 + { 228 + char* sym; 229 + char* syms = strdup(symbols); 230 + 231 + printf("#ifdef __x86_64__\n"); 232 + 233 + define_string("_library_name", soname); 234 + 235 + print_init_exit(); 236 + 237 + sym = strtok(syms, ";"); 238 + while (sym != NULL) 239 + { 240 + char name[128]; 241 + 242 + printf(".zerofill __DATA,__bss,_%s_impl,8,3\n", sym); 243 + printf(".section __TEXT,__text,regular,pure_instructions\n\n"); 244 + printf(".globl _%s\n" 245 + "_%s:\n" 246 + "\tmovq _%s_impl(%%rip), %%rax\n" 247 + "\ttestq %%rax, %%rax\n" 248 + "\tjz 1f\n" 249 + "\tjmpq *%%rax\n" 250 + "1:\n" 251 + "\tloadfunc _%s_name, _%s_impl\n" 252 + "\tjmpq *%%rax\n\n", 253 + sym, sym, sym, sym, sym); 254 + 255 + sprintf(name, "_%s_name", sym); 256 + define_string(name, sym); 257 + 258 + sym = strtok(NULL, ";"); 259 + } 260 + 261 + printf("#endif // __x86_64__\n"); 262 + free(syms); 263 + } 264 +