this repo has no description
1
fork

Configure Feed

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

Rename stubgen to wrapgen, improve wrapgen to read all symbols from ELF file, produce symbol resolvers instead of assembly

+255 -264
src/dyld/stubgen/produce_stubs_example.h src/dyld/wrapgen/produce_stubs_example.h
src/dyld/stubgen/stubgen32.cpp src/dyld/wrapgen/stubgen32.cpp
-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 -
+255
src/dyld/wrapgen/wrapgen.cpp
··· 1 + #include <string> 2 + #include <iostream> 3 + #include <set> 4 + #include <string.h> 5 + #include <unistd.h> 6 + #include <fcntl.h> 7 + #include <elf.h> 8 + #include <errno.h> 9 + #include <dlfcn.h> 10 + #include <sys/mman.h> 11 + #include <sstream> 12 + #include <stdexcept> 13 + 14 + #ifndef PATH_MAX 15 + # define PATH_MAX 4096 16 + #endif 17 + 18 + // This is a generator of assembly code for Mach-O 19 + // libraries wrapping ELF libraries. 20 + 21 + // TODO: use wrapgen32 to generate 32-bit wrappers. 22 + 23 + void parse_elf(const char* elf, std::string& soname_out, std::set<std::string>& symbols_out); 24 + void generate_wrapper(const char* soname, const std::set<std::string>& symbols); 25 + 26 + int main(int argc, const char** argv) 27 + { 28 + std::string elfLibrary; 29 + std::set<std::string> symbols; 30 + std::string soname; 31 + 32 + if (argc != 2) 33 + { 34 + std::cerr << "Usage: " << argv[0] << " <library-name>\n"; 35 + return 1; 36 + } 37 + 38 + elfLibrary = argv[1]; 39 + 40 + try 41 + { 42 + if (access(elfLibrary.c_str(), R_OK) == -1) 43 + { 44 + // Try loading the library and then ask the loader where it found the library. 45 + // It is simpler than parsing /etc/ld.so.conf. 46 + 47 + void* handle = dlopen(elfLibrary.c_str(), RTLD_LAZY | RTLD_LOCAL); 48 + char path[PATH_MAX]; 49 + 50 + if (!handle) 51 + { 52 + std::stringstream ss; 53 + ss << "Cannot load " << elfLibrary << ": " << dlerror(); 54 + throw std::runtime_error(ss.str()); 55 + } 56 + 57 + if (dlinfo(handle, RTLD_DI_ORIGIN, path) == 0) 58 + { 59 + elfLibrary.insert(0, "/"); 60 + elfLibrary.insert(0, path); 61 + } 62 + else 63 + { 64 + std::stringstream ss; 65 + std::cerr << "Cannot locate " << elfLibrary << ": " << dlerror(); 66 + throw std::runtime_error(ss.str()); 67 + } 68 + 69 + dlclose(handle); 70 + } 71 + 72 + parse_elf(elfLibrary.c_str(), soname, symbols); 73 + generate_wrapper(soname.c_str(), symbols); 74 + } 75 + catch (const std::exception& e) 76 + { 77 + std::cerr << e.what() << std::endl; 78 + return 1; 79 + } 80 + 81 + return 0; 82 + } 83 + 84 + void parse_elf(const char* elf, std::string& soname, std::set<std::string>& symbols) 85 + { 86 + int fd; 87 + const Elf64_Ehdr* ehdr; 88 + const char* strings = NULL; 89 + uint64_t length; 90 + 91 + fd = open(elf, O_RDONLY); 92 + if (fd < 0) 93 + { 94 + std::stringstream ss; 95 + ss << "Error opening " << elf << ": " << strerror(errno); 96 + throw std::runtime_error(ss.str()); 97 + } 98 + 99 + length = lseek(fd, 0, SEEK_END); 100 + 101 + ehdr = (Elf64_Ehdr*) mmap(NULL, length, PROT_READ, MAP_SHARED, fd, 0); 102 + if (ehdr == MAP_FAILED) 103 + { 104 + std::stringstream ss; 105 + ss << "Cannot mmap ELF file: " << strerror(errno); 106 + throw std::runtime_error(ss.str()); 107 + } 108 + 109 + close(fd); 110 + 111 + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0 || ehdr->e_ident[EI_CLASS] != ELFCLASS64) 112 + { 113 + std::stringstream ss; 114 + ss << elf << " is not a 64-bit ELF"; 115 + throw std::runtime_error(ss.str()); 116 + } 117 + 118 + if (ehdr->e_type != ET_DYN) 119 + { 120 + std::stringstream ss; 121 + ss << elf << " is not a dynamic library ELF"; 122 + throw std::runtime_error(ss.str()); 123 + } 124 + 125 + if (ehdr->e_machine != EM_X86_64) 126 + { 127 + std::stringstream ss; 128 + ss << elf << " is not an ELF for x86-64"; 129 + throw std::runtime_error(ss.str()); 130 + } 131 + 132 + // Now read program headers, find a PT_DYNAMIC segment type 133 + for (int i = 0; i < ehdr->e_phnum; i++) 134 + { 135 + const Elf64_Phdr* phdr; 136 + 137 + phdr = (const Elf64_Phdr*) (((char*) ehdr) + ehdr->e_phoff + (i * ehdr->e_phentsize)); 138 + 139 + if (phdr->p_type == PT_DYNAMIC) 140 + { 141 + Elf64_Xword off_strtab, off_soname; 142 + 143 + off_strtab = off_soname = 0; 144 + 145 + for (int j = 0; j < phdr->p_filesz; j += sizeof(Elf64_Dyn)) 146 + { 147 + const Elf64_Dyn* dyn; 148 + 149 + dyn = (const Elf64_Dyn*) (((char*) ehdr) + phdr->p_offset + j); 150 + 151 + switch (dyn->d_tag) 152 + { 153 + case DT_STRTAB: 154 + off_strtab = dyn->d_un.d_val; 155 + break; 156 + case DT_SONAME: 157 + off_soname = dyn->d_un.d_val; 158 + break; 159 + case DT_NULL: 160 + goto end_dyn; 161 + } 162 + } 163 + end_dyn: 164 + 165 + if (off_strtab != 0) 166 + { 167 + strings = (const char*) ((char*) ehdr) + off_strtab; 168 + 169 + if (off_soname != 0) 170 + { 171 + // Read DT_SONAME value from the string table 172 + soname = strings + off_soname; 173 + } 174 + } 175 + 176 + break; 177 + } 178 + } 179 + 180 + if (strings != NULL) 181 + { 182 + // Load symbol list 183 + const Elf64_Shdr* shdr; 184 + 185 + for (int i = 0; i < ehdr->e_shnum; i++) 186 + { 187 + shdr = (const Elf64_Shdr*) (((char*) ehdr) + ehdr->e_shoff + (i * ehdr->e_shentsize)); 188 + if (shdr->sh_type == SHT_DYNSYM) 189 + { 190 + for (int j = 0; j < shdr->sh_size; j += sizeof(Elf64_Sym)) 191 + { 192 + const Elf64_Sym* sym; 193 + 194 + sym = (const Elf64_Sym*) (((char*) ehdr) + shdr->sh_offset + j); 195 + 196 + if (ELF64_ST_TYPE(sym->st_info) != STT_OBJECT && ELF64_ST_TYPE(sym->st_info) != STT_FUNC) 197 + continue; 198 + if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL) 199 + continue; 200 + if (sym->st_shndx == SHN_UNDEF || sym->st_value == 0) 201 + continue; 202 + if (ELF64_ST_VISIBILITY(sym->st_other) != STV_DEFAULT) 203 + continue; 204 + 205 + symbols.insert(strings + sym->st_name); 206 + } 207 + 208 + break; 209 + } 210 + } 211 + } 212 + 213 + if (soname.empty()) 214 + { 215 + std::cerr << "WARNING: No DT_SONAME in " << elf << ".\n"; 216 + 217 + const char* slash = strrchr(elf, '/'); 218 + if (slash != NULL) 219 + soname = slash + 1; 220 + else 221 + soname = elf; 222 + } 223 + if (symbols.empty()) 224 + { 225 + std::stringstream ss; 226 + ss << "No symbols found in " << elf; 227 + throw std::runtime_error(ss.str()); 228 + } 229 + 230 + munmap((void*) ehdr, length); 231 + } 232 + 233 + void generate_wrapper(const char* soname, const std::set<std::string>& symbols) 234 + { 235 + std::cout << "#include <elfcalls.h>\n" 236 + "extern struct elf_calls* _elfcalls;\n\n"; 237 + 238 + std::cout << "static void* lib_handle;\n" 239 + "__attribute__((constructor)) static void initializer() {\n" 240 + "\tlib_handle = _elfcalls->dlopen_fatal(\"" << soname << "\");\n" 241 + "}\n\n"; 242 + 243 + std::cout << "__attribute__((destructor)) static void destructor() {\n" 244 + "\t_elfcalls->dlclose_fatal(lib_handle);\n" 245 + "}\n\n"; 246 + 247 + for (const std::string& sym : symbols) 248 + { 249 + std::cout << "void* " << sym << "() {\n" 250 + "\t__asm__(\".symbol_resolver _" << sym << "\");\n" 251 + "\treturn _elfcalls->dlsym_fatal(lib_handle, \"" << sym << "\");\n" 252 + "}\n\n"; 253 + } 254 + } 255 +