├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── elf_loader.c ├── elf_loader.h ├── hello.c ├── main.c ├── makefile.hello └── wheelc ├── list.c ├── list.h ├── log.h └── wheelc.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | *.su 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 elemeta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -Wall -g -o elfloader elf_loader.c main.c wheelc/list.c -ldl -lpthread 3 | 4 | clean: 5 | rm -rf *.o wheelc/*.o elfloader 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # elfloader 2 | load so file into current memory space and run function 3 | 4 | # run 5 | 6 | # create example, hello.so 7 | make -f makefile.hello 8 | 9 | # make elfloader 10 | make 11 | 12 | # run function main1 in hello.so 13 | ./elfloader ./hello.so main1 14 | 15 | 16 | elemeta47 at gmail dot com -------------------------------------------------------------------------------- /elf_loader.c: -------------------------------------------------------------------------------- 1 | #include "elf_loader.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define powerof2(x) ((((x)-1)&(x))==0) 13 | 14 | #define PAGE_START(x) ((x) & PAGE_MASK) 15 | #define PAGE_OFFSET(x) ((x) & ~PAGE_MASK) 16 | #define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE-1)) 17 | 18 | static LIST_HEAD(mod_list); 19 | 20 | static struct elf_module *elf_module_alloc(const char *name) 21 | { 22 | struct elf_module *m; 23 | 24 | if (strlen(name) >= ELF_MODULE_NAME_LEN) { 25 | LOG_ERR("ELF name to long"); 26 | return NULL; 27 | } 28 | 29 | m = malloc(sizeof(*m)); 30 | if (m == NULL) { 31 | LOG_ERR("\"%s\" elf module memory alloc failed: %s", name, strerror(errno)); 32 | return NULL; 33 | } 34 | 35 | memset(m, 0, sizeof(*m)); 36 | strncpy(m->name, name, sizeof(m->name) - 1); 37 | INIT_LIST_HEAD(&m->list); 38 | m->refcnt = 1; 39 | 40 | LOG_DEBUG("name %s: allocated struct elf_module @ %p", name, m); 41 | return m; 42 | } 43 | 44 | static void elf_module_free(struct elf_module *m) 45 | { 46 | if (!m) 47 | return; 48 | 49 | LOG_DEBUG("name %s: freeing soinfo @ %p", m->name, m); 50 | 51 | if (m->base) 52 | munmap((void *)m->base, m->size); 53 | free(m); 54 | } 55 | 56 | static struct elf_module *find_module(const char *name) 57 | { 58 | struct list_head *pos; 59 | struct elf_module *m = NULL, *tmp; 60 | 61 | list_for_each(pos, &mod_list) { 62 | tmp = list_entry(pos, struct elf_module, list); 63 | if (!strcmp(name, tmp->name)) { 64 | m = tmp; 65 | break; 66 | } 67 | } 68 | 69 | if (m != NULL) { 70 | if (m->flags & FLAG_LINKED) 71 | return m; 72 | LOG_ERR("OOPS: recursive link to \"%s\"", m->name); 73 | return NULL; 74 | } 75 | 76 | LOG_DEBUG("[ \"%s\" has not been loaded yet ]", name); 77 | return NULL; 78 | } 79 | 80 | // 81 | // elf info 82 | // 83 | 84 | struct elf_info { 85 | const char *name; 86 | const ElfW(Ehdr) *hdr; 87 | size_t len; 88 | 89 | ElfW(Phdr) *phdr_table; 90 | }; 91 | 92 | #if defined(__x86_64__) 93 | #define elf_check_arch(x) ((x)->e_machine == EM_X86_64) 94 | #elif defined(__i386__) 95 | #define elf_check_arch(x) ((x)->e_machine == EM_386) 96 | #endif 97 | 98 | static bool verify_elf_header(struct elf_info *info) 99 | { 100 | int elf_class; 101 | 102 | if (info->len < sizeof(*(info->hdr))) { 103 | LOG_ERR("\"%s\" is too small to be an ELF executable. Expected at least %zu bytes, " 104 | "only found %zu bytes", info->name, sizeof(*(info->hdr)), info->len); 105 | return false; 106 | } 107 | if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG)) { 108 | LOG_ERR("\"%s\" has bad ELF magic", info->name); 109 | return false; 110 | } 111 | 112 | // Try to give a clear diagnostic for ELF class mismatches, since they're 113 | // an easy mistake to make during the 32-bit/64-bit transition period. 114 | elf_class = info->hdr->e_ident[EI_CLASS]; 115 | #if defined(__LP64__) 116 | if (elf_class != ELFCLASS64) { 117 | if (elf_class == ELFCLASS32) { 118 | LOG_ERR("\"%s\" is 32-bit instead of 64-bit", info->name); 119 | } else { 120 | LOG_ERR("\"%s\" has unknown ELF class: %d", info->name, elf_class); 121 | } 122 | return false; 123 | } 124 | #else 125 | if (elf_class != ELFCLASS32) { 126 | if (elf_class == ELFCLASS64) { 127 | LOG_ERR("\"%s\" is 64-bit instead of 32-bit", info->name); 128 | } else { 129 | LOG_ERR("\"%s\" has unknown ELF class: %d", info->name, elf_class); 130 | } 131 | return false; 132 | } 133 | #endif 134 | 135 | if (info->hdr->e_ident[EI_DATA] != ELFDATA2LSB) { 136 | LOG_ERR("\"%s\" not little-endian: %d", info->name, info->hdr->e_ident[EI_DATA]); 137 | return false; 138 | } 139 | 140 | if (info->hdr->e_type != ET_EXEC && info->hdr->e_type != ET_DYN) { 141 | LOG_ERR("\"%s\" has unexpected e_type: %d", info->name, info->hdr->e_type); 142 | return false; 143 | } 144 | 145 | if (info->hdr->e_version != EV_CURRENT) { 146 | LOG_ERR("\"%s\" has unexpected e_version: %d", info->name, info->hdr->e_version); 147 | return false; 148 | } 149 | 150 | if (!elf_check_arch(info->hdr)) { 151 | LOG_ERR("\"%s\" has unexpected e_machine: %d", info->name, info->hdr->e_machine); 152 | return false; 153 | } 154 | 155 | LOG_DEBUG("\"%s\" verify elf header done.", info->name); 156 | return true; 157 | } 158 | 159 | static bool read_program_headers(struct elf_info *info) 160 | { 161 | if (info->hdr->e_phoff == 0) { 162 | LOG_ERR("\"%s\" has no program header table", info->name); 163 | return false; 164 | } 165 | 166 | if (info->hdr->e_phnum < 1 || info->hdr->e_phnum > (65536U / sizeof(ElfW(Phdr)))) { 167 | LOG_ERR("\"%s\" has invalid e_phnum: %d", info->name, info->hdr->e_phnum); 168 | return false; 169 | } 170 | 171 | if (info->hdr->e_phentsize != sizeof(ElfW(Phdr))) { 172 | LOG_ERR("\"%s\" has invalid e_phentsize", info->name); 173 | return false; 174 | } 175 | 176 | if (info->hdr->e_phoff >= info->len 177 | || (info->hdr->e_phnum * sizeof(ElfW(Phdr)) > info->len - info->hdr->e_phoff)) { 178 | LOG_ERR("\"%s\" has invalid offset/size of program header table", info->name); 179 | return false; 180 | } 181 | 182 | info->phdr_table = (ElfW(Phdr) *)((char *)info->hdr + info->hdr->e_phoff); 183 | LOG_DEBUG("\"%s\" read program header done.", info->name); 184 | return true; 185 | } 186 | 187 | // 188 | // symbol 189 | // 190 | static bool is_symbol_global_and_defined(const struct elf_module *m, const ElfW(Sym) *s) 191 | { 192 | if (ELFW(ST_BIND)(s->st_info) == STB_GLOBAL || ELFW(ST_BIND)(s->st_info) == STB_WEAK) 193 | return s->st_shndx != SHN_UNDEF; 194 | return false; 195 | } 196 | 197 | static uint32_t elfhash(const char *name) 198 | { 199 | const uint8_t *name_bytes = (const uint8_t *)name; 200 | uint32_t h = 0, g; 201 | 202 | while (*name_bytes) { 203 | h = (h << 4) + *name_bytes++; 204 | g = h & 0xf0000000; 205 | h ^= g; 206 | h ^= g >> 24; 207 | } 208 | 209 | return h; 210 | } 211 | 212 | static ElfW(Sym) *elfhash_lookup(struct elf_module *m, const char *name) 213 | { 214 | uint32_t n; 215 | uint32_t hash = elfhash(name); 216 | ElfW(Sym) *symtab = m->symtab; 217 | const char *strtab = m->strtab; 218 | 219 | LOG_DEBUG("SEARCH %s in %s@0x%zx %08x %zu", name, m->name, m->base, hash, hash % m->nbucket); 220 | 221 | for (n = m->bucket[hash % m->nbucket]; n != 0; n = m->chain[n]) { 222 | ElfW(Sym) *s = symtab + n; 223 | if (strcmp(strtab + s->st_name, name)) 224 | continue; 225 | 226 | if (is_symbol_global_and_defined(m, s)) { 227 | LOG_DEBUG("FOUND %s in %s (%zx) %zu", name, m->name, s->st_value, s->st_size); 228 | return s; 229 | } 230 | } 231 | 232 | return NULL; 233 | } 234 | 235 | // https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections 236 | static uint32_t gnuhash(const char *name) 237 | { 238 | const uint8_t *name_bytes = (const uint8_t *)name; 239 | uint32_t h = 5381; 240 | 241 | while (*name_bytes != 0) 242 | h += (h << 5) + *name_bytes++; // h*33 + c = h + h * 32 + c = h + h << 5 + c 243 | 244 | return h; 245 | } 246 | 247 | static ElfW(Sym) *gnuhash_lookup(struct elf_module *m, const char *name) 248 | { 249 | uint32_t n; 250 | uint32_t hash = gnuhash(name); 251 | uint32_t h2 = hash >> m->gnu_shift2; 252 | uint32_t bloom_mask_bits = sizeof(ElfW(Addr)) * 8; 253 | uint32_t word_num = (hash / bloom_mask_bits) & m->gnu_maskwords; 254 | ElfW(Addr) bloom_word = m->gnu_bloom_filter[word_num]; 255 | ElfW(Sym) *symtab = m->symtab; 256 | const char *strtab = m->strtab; 257 | 258 | LOG_DEBUG("SEARCH %s in %s@%p (gnu)", name, m->name, (void *)m->base); 259 | 260 | // test against bloom filter 261 | if ((1 & (bloom_word >> (hash % bloom_mask_bits)) & (bloom_word >> (h2 % bloom_mask_bits))) == 0) { 262 | LOG_DEBUG("NOT FOUND %s in %s@%p (gnu)", name, m->name, (void *)m->base); 263 | return NULL; 264 | } 265 | 266 | // bloom test says "probably yes"... 267 | n = m->gnu_bucket[hash % m->gnu_nbucket]; 268 | if (n == 0) { 269 | LOG_DEBUG("NOT FOUND %s in %s@%p (gun)", name, m->name, (void *)m->base); 270 | return NULL; 271 | } 272 | 273 | do { 274 | ElfW(Sym) *s = symtab + n; 275 | if (((m->gnu_chain[n] ^ hash) >> 1) != 0) 276 | continue; 277 | if (strcmp(strtab + s->st_name, name)) 278 | continue; 279 | 280 | if (is_symbol_global_and_defined(m, s)) { 281 | LOG_DEBUG("FOUND %s in %s (%p) %zd", name, m->name, (void *)s->st_value, (size_t)s->st_size); 282 | return s; 283 | } 284 | } while ((m->gnu_chain[n++] & 1) == 0); 285 | 286 | return NULL; 287 | } 288 | 289 | ElfW(Sym) *lookup_symbol_in_module(struct elf_module *m, const char *name) 290 | { 291 | return (m->flags & FLAG_GNU_HASH) ? gnuhash_lookup(m, name) : elfhash_lookup(m, name); 292 | } 293 | 294 | ElfW(Sym) *lookup_symbol_in_needed(struct elf_module *m, const char *name, 295 | struct elf_module **m_from, struct elf_module *needed[]) 296 | { 297 | int i; 298 | ElfW(Sym) *s = NULL; 299 | 300 | // 1. look for local first 301 | s = lookup_symbol_in_module(m, name); 302 | if (s) { 303 | *m_from = m; 304 | goto done; 305 | } 306 | 307 | // 2. TODO: look for it in the preloads 308 | 309 | // 3. look for needed module 310 | for (i = 0; needed[i] != NULL; i++) { 311 | LOG_DEBUG("%s: looking up %s in %s", m->name, name, needed[i]->name); 312 | s = lookup_symbol_in_module(needed[i], name); 313 | if (s != NULL) { 314 | *m_from = needed[i]; 315 | goto done; 316 | } 317 | } 318 | 319 | done: 320 | if (s != NULL) { 321 | LOG_DEBUG("elf module %s sym %s s->st_value = 0x%zx, " 322 | "found in %s, base = 0x%zx, load_bias = 0x%zx", 323 | m->name, name, s->st_value, 324 | (*m_from)->name, (*m_from)->base, (*m_from)->load_bias); 325 | return s; 326 | } 327 | 328 | return NULL; 329 | } 330 | 331 | // 332 | // relocate 333 | // 334 | 335 | #if defined(__x86_64__) 336 | 337 | static bool apply_relocate_add(struct elf_module *m, Elf64_Rela *rela, size_t count, struct elf_module *needed[]) 338 | { 339 | Elf64_Sym *symtab = m->symtab; 340 | const char *strtab = m->strtab; 341 | size_t i; 342 | struct elf_module *m_from; 343 | 344 | for (i = 0; i < count; ++i, ++rela) { 345 | uint32_t type = ELF64_R_TYPE(rela->r_info); 346 | uint32_t sym = ELF64_R_SYM(rela->r_info); 347 | Elf64_Addr reloc = (Elf64_Addr)(rela->r_offset + m->load_bias); 348 | Elf64_Addr sym_addr = 0; 349 | char *sym_name = NULL; 350 | Elf64_Addr addend = rela->r_addend; 351 | 352 | LOG_DEBUG("Processing '%s' relocation at index %zu", m->name, i); 353 | if (type == 0) /* R_*_NONE */ 354 | continue; 355 | 356 | if (sym != 0) { 357 | Elf64_Sym *s; 358 | sym_name = (char *)(strtab + symtab[sym].st_name); 359 | s = lookup_symbol_in_needed(m, sym_name, &m_from, needed); 360 | if (s == NULL) { 361 | sym_addr = (Elf64_Addr)dlsym((void *)0 /*RTLD_DEFAULT*/, sym_name); 362 | if (sym_addr) { 363 | LOG_DEBUG("dlsym(%s) = 0x%zx", sym_name, sym_addr); 364 | } else { 365 | /* We only allow an undefined symbol if this is a weak reference.. */ 366 | s = &symtab[sym]; 367 | if (ELF64_ST_BIND(s->st_info) != STB_WEAK) { 368 | LOG_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, m->name); 369 | return false; 370 | } 371 | 372 | switch (type) { 373 | case R_X86_64_JUMP_SLOT: 374 | case R_X86_64_GLOB_DAT: 375 | case R_X86_64_RELATIVE: 376 | case R_X86_64_IRELATIVE: 377 | case R_X86_64_32: 378 | case R_X86_64_64: 379 | break; 380 | case R_X86_64_PC32: 381 | sym_addr = reloc; 382 | break; 383 | default: 384 | LOG_ERR("unknown weak reloc type %d @ %p (%zu)", type, rela, i); 385 | return false; 386 | } 387 | } 388 | } else { /* s != NULL*/ 389 | sym_addr = (Elf64_Addr)(s->st_value + m_from->load_bias); 390 | } 391 | } 392 | 393 | switch (type) { 394 | case R_X86_64_NONE: 395 | break; 396 | case R_X86_64_RELATIVE: 397 | LOG_DEBUG("RELO RELATIVE %16p <- %16p", 398 | (void *)reloc, (void *)(m->load_bias + addend)); 399 | *(uint64_t *)reloc = (m->load_bias + addend); 400 | break; 401 | case R_X86_64_JUMP_SLOT: 402 | LOG_DEBUG("RELO JMP_SLOT %16p <- %16p %s", 403 | (void *)reloc, (void *)(sym_addr), sym_name); 404 | *(uint64_t *)reloc = sym_addr; 405 | break; 406 | case R_X86_64_GLOB_DAT: 407 | LOG_DEBUG("RELO GLOB_DAT %16p <- %16p %s", 408 | (void *)reloc, (void *)(sym_addr), sym_name); 409 | *(uint64_t *)reloc = sym_addr; 410 | break; 411 | case R_X86_64_COPY: 412 | LOG_DEBUG("RELO R_X86_64_COPY %16p <- %16p %s", 413 | (void *)reloc, (void *)(sym_addr), sym_name); 414 | *(uint64_t *)reloc = sym_addr; 415 | break; 416 | case R_X86_64_64: 417 | LOG_DEBUG("RELO R_X86_64_64 %08zx <- +%08zx %s", 418 | (size_t)reloc, (size_t)(sym_addr + addend), sym_name); 419 | *(uint64_t *)reloc = sym_addr + addend; 420 | break; 421 | case R_X86_64_32: 422 | LOG_DEBUG("RELO R_X86_64_32 %08zx <- +%08zx %s", 423 | (size_t)reloc, (size_t)(sym_addr + addend), sym_name); 424 | *(uint32_t *)reloc = sym_addr + addend; 425 | break; 426 | case R_X86_64_32S: 427 | LOG_DEBUG("RELO R_X86_64_32S %08zx <- +%08zx %s", 428 | (size_t)reloc, (size_t)(sym_addr + addend), sym_name); 429 | *(int32_t *)reloc = sym_addr + addend; 430 | break; 431 | case R_X86_64_PC32: 432 | LOG_DEBUG("RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s", 433 | (size_t)reloc, (size_t)(sym_addr - reloc), 434 | (size_t)sym_addr, (size_t)reloc, sym_name); 435 | *(uint32_t *)reloc = sym_addr + addend - reloc; 436 | break; 437 | default: 438 | LOG_ERR("unknown reloc type %d @ %p (%zu)", type, rela, i); 439 | return false; 440 | } 441 | } 442 | return true; 443 | } 444 | 445 | #else /* __x86_32 */ 446 | 447 | static bool apply_relocate(struct elf_module *m, Elf32_Rel *rel, size_t count, struct elf_module *needed[]) 448 | { 449 | Elf32_Sym *symtab = m->symtab; 450 | const char *strtab = m->strtab; 451 | size_t i; 452 | struct elf_module *m_from; 453 | 454 | for (i = 0; i < count; ++i, ++rel) { 455 | unsigned type = ELF32_R_TYPE(rel->r_info); 456 | unsigned sym = ELF32_R_SYM(rel->r_info); 457 | Elf32_Addr reloc = (Elf32_Addr)(rel->r_offset + m->load_bias); 458 | Elf32_Addr sym_addr = 0; 459 | char *sym_name = NULL; 460 | 461 | LOG_DEBUG("Processing '%s' relocation at index %d", m->name, i); 462 | 463 | if (type == 0) /* R_*_NONE */ 464 | continue; 465 | 466 | if (sym != 0) { 467 | Elf32_Sym *s; 468 | sym_name = (char *)(strtab + symtab[sym].st_name); 469 | s = lookup_symbol_in_needed(m, sym_name, &m_from, needed); 470 | if (s == NULL) { 471 | sym_addr = (Elf32_Addr)dlsym((void *)0 /*RTLD_DEFAULT*/, sym_name); 472 | if (sym_addr) { 473 | LOG_DEBUG("dlsym(%s) = 0x%x", sym_name, sym_addr); 474 | } else { 475 | /* We only allow an undefined symbol if this is a weak reference.. */ 476 | s = &symtab[sym]; 477 | if (ELF32_ST_BIND(s->st_info) != STB_WEAK) { 478 | LOG_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, m->name); 479 | return false; 480 | } 481 | switch (type) { 482 | case R_386_JMP_SLOT: 483 | case R_386_GLOB_DAT: 484 | case R_386_RELATIVE: 485 | case R_386_IRELATIVE: 486 | case R_386_32: 487 | break; 488 | case R_386_PC32: 489 | sym_addr = reloc; 490 | break; 491 | default: 492 | LOG_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, i); 493 | return false; 494 | } 495 | } 496 | } else { /* s != NULL*/ 497 | sym_addr = (Elf32_Addr)(s->st_value + m_from->load_bias); 498 | } 499 | } 500 | 501 | switch (type) { 502 | case R_386_JMP_SLOT: 503 | LOG_DEBUG("RELO JMP_SLOT %p <- %p %s\n", 504 | (void *)reloc, (void *)(sym_addr), sym_name); 505 | *(uint32_t *)reloc = sym_addr; 506 | break; 507 | case R_386_GLOB_DAT: 508 | LOG_DEBUG("RELO GLOB_DAT %p <- %p %s\n", 509 | (void *)reloc, (void *)(sym_addr), sym_name); 510 | *(uint32_t *)reloc = sym_addr; 511 | break; 512 | case R_386_RELATIVE: 513 | LOG_DEBUG("RELO RELATIVE %p <- %p\n", 514 | (void *)reloc, (void *)(m->load_bias)); 515 | *(uint32_t *)reloc = m->load_bias + *(uint32_t *)reloc; 516 | break; 517 | case R_386_32: 518 | LOG_DEBUG("RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name); 519 | *(uint32_t *)reloc += sym_addr; 520 | break; 521 | case R_386_PC32: 522 | LOG_DEBUG("RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s", 523 | reloc, (sym_addr - reloc), sym_addr, reloc, sym_name); 524 | *(uint32_t *)reloc += (sym_addr - reloc); 525 | break; 526 | default: 527 | LOG_ERR("unknown reloc type %d @ %p (%u)", type, rel, i); 528 | return false; 529 | } 530 | } 531 | return true; 532 | } 533 | 534 | #endif /* defined(__x86_64__) */ 535 | 536 | /* Returns the size of the extent of all the possibly non-contiguous 537 | * loadable segments in an ELF program header table. This corresponds 538 | * to the page-aligned size in bytes that needs to be reserved in the 539 | * process' address space. If there are no loadable segments, 0 is 540 | * returned. 541 | * 542 | * If out_min_vaddr or out_max_vaddr are not null, they will be 543 | * set to the minimum and maximum addresses of pages to be reserved, 544 | * or 0 if there is nothing to load. 545 | */ 546 | static size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count, 547 | ElfW(Addr)* out_min_vaddr, ElfW(Addr)* out_max_vaddr) 548 | { 549 | ElfW(Addr) min_vaddr = UINTPTR_MAX; 550 | ElfW(Addr) max_vaddr = 0; 551 | bool found_pt_load = false; 552 | size_t i; 553 | 554 | for (i = 0; i < phdr_count; ++i) { 555 | const ElfW(Phdr)* phdr = &phdr_table[i]; 556 | 557 | if (phdr->p_type != PT_LOAD) 558 | continue; 559 | 560 | found_pt_load = true; 561 | 562 | if (phdr->p_vaddr < min_vaddr) 563 | min_vaddr = phdr->p_vaddr; 564 | 565 | if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) 566 | max_vaddr = phdr->p_vaddr + phdr->p_memsz; 567 | } 568 | if (!found_pt_load) 569 | min_vaddr = 0; 570 | 571 | min_vaddr = PAGE_START(min_vaddr); 572 | max_vaddr = PAGE_END(max_vaddr); 573 | 574 | if (out_min_vaddr != NULL) 575 | *out_min_vaddr = min_vaddr; 576 | if (out_max_vaddr != NULL) 577 | *out_max_vaddr = max_vaddr; 578 | return max_vaddr - min_vaddr; 579 | } 580 | 581 | /* Return the address and size of the ELF file's .dynamic section in memory, 582 | * or null if missing. 583 | * 584 | * Input: 585 | * phdr_table -> program header table 586 | * phdr_count -> number of entries in tables 587 | * load_bias -> load bias 588 | * Output: 589 | * dynamic -> address of table in memory (null on failure). 590 | * dynamic_flags -> protection flags for section (unset on failure) 591 | * Return: 592 | * void 593 | */ 594 | static void phdr_table_get_dynamic_section(const ElfW(Phdr) *phdr_table, size_t phdr_count, 595 | ElfW(Addr) load_bias, ElfW(Dyn) **dynamic, 596 | ElfW(Word) *dynamic_flags) 597 | { 598 | size_t i; 599 | 600 | *dynamic = NULL; 601 | for (i = 0; i < phdr_count; ++i) { 602 | const ElfW(Phdr) *phdr = &phdr_table[i]; 603 | if (phdr->p_type == PT_DYNAMIC) { 604 | *dynamic = (ElfW(Dyn) *)(load_bias + phdr->p_vaddr); 605 | if (dynamic_flags) 606 | *dynamic_flags = phdr->p_flags; 607 | return; 608 | } 609 | } 610 | } 611 | 612 | static ElfW(Phdr) *find_loaded_phdr(struct elf_module *m, struct elf_info *info) 613 | { 614 | size_t i; 615 | ElfW(Addr) loaded_phdr = 0; 616 | const ElfW(Phdr) *pphdr; 617 | 618 | // If there is a PT_PHDR, use it directly. 619 | for (i = 0, pphdr = info->phdr_table; i < info->hdr->e_phnum; ++i, ++pphdr) { 620 | if (pphdr->p_type == PT_PHDR) { 621 | loaded_phdr = (ElfW(Addr))(m->load_bias + pphdr->p_vaddr); 622 | break; 623 | } 624 | } 625 | 626 | // Otherwise, check the first loadable segment. If its file offset 627 | // is 0, it starts with the ELF header, and we can trivially find the 628 | // loaded program header from it. 629 | if (loaded_phdr == 0) { 630 | for (i = 0, pphdr = info->phdr_table; i < info->hdr->e_phnum; ++i, ++pphdr) { 631 | if (pphdr->p_type == PT_LOAD) { 632 | if (pphdr->p_offset == 0) { 633 | const ElfW(Ehdr) *ehdr = (const ElfW(Ehdr) *)(m->load_bias + pphdr->p_vaddr); 634 | loaded_phdr = (ElfW(Addr))((char *)ehdr + ehdr->e_phoff); 635 | break; 636 | } 637 | break; 638 | } 639 | } 640 | } 641 | 642 | if (loaded_phdr == 0) { 643 | LOG_ERR("can't find loaded phdr for \"%s\"", m->name); 644 | return false; 645 | } 646 | 647 | // Ensures that our program header is actually within a loadable 648 | // segment. This should help catch badly-formed ELF files that 649 | // would cause the linker to crash later when trying to access it. 650 | for (i = 0, pphdr = info->phdr_table; i < info->hdr->e_phnum; ++i, ++pphdr) { 651 | ElfW(Addr) seg_start, seg_end; 652 | 653 | if (pphdr->p_type != PT_LOAD) 654 | continue; 655 | seg_start = m->load_bias + pphdr->p_vaddr; 656 | seg_end = seg_start + pphdr->p_filesz; 657 | if (seg_start <= loaded_phdr 658 | && (loaded_phdr + info->hdr->e_phnum * sizeof(ElfW(Phdr)) <= seg_end)) { 659 | LOG_DEBUG("find loaded phdr for \"%s\" done", m->name); 660 | return (ElfW(Phdr) *)loaded_phdr; 661 | } 662 | } 663 | 664 | LOG_ERR("\"%s\" loaded phdr 0x%zx not in loadable segment", m->name, loaded_phdr); 665 | return NULL; 666 | } 667 | 668 | static bool layout_segments(struct elf_module *m, struct elf_info *info) 669 | { 670 | ElfW(Addr) min_vaddr; 671 | void *mm_start; 672 | size_t i; 673 | 674 | m->size = phdr_table_get_load_size(info->phdr_table, info->hdr->e_phnum, &min_vaddr, NULL); 675 | if (m->size == 0) { 676 | LOG_ERR("\"%s\" has no loadable segments", m->name); 677 | return false; 678 | } 679 | 680 | mm_start = mmap(NULL, 681 | m->size, 682 | PROT_READ | PROT_WRITE | PROT_EXEC, 683 | MAP_PRIVATE | MAP_ANONYMOUS, 684 | -1, 685 | 0); // munmap in elf_module_free() 686 | if (mm_start == MAP_FAILED) { 687 | LOG_ERR("couldn't map \"%s\" address space, %s", m->name, strerror(errno)); 688 | return false; 689 | } 690 | 691 | memset(mm_start, 0, m->size); 692 | m->base = (ElfW(Addr))mm_start; 693 | m->load_bias = (char *)mm_start - (char *)min_vaddr; 694 | 695 | for (i = 0; i < info->hdr->e_phnum; ++i) { 696 | const ElfW(Phdr) *phdr = &info->phdr_table[i]; 697 | if (phdr->p_type != PT_LOAD) 698 | continue; 699 | if (phdr->p_offset + phdr->p_filesz > info->len) { 700 | LOG_ERR("\"%s\" has invalid segment[%zu]:" 701 | "p_offset (%zx) + p_filesz (%zx) past end of %zx)", 702 | m->name, i, phdr->p_offset, phdr->p_filesz, info->len); 703 | return false; 704 | } 705 | memcpy((char *)m->load_bias + phdr->p_vaddr, 706 | (char *)info->hdr + phdr->p_offset, phdr->p_filesz); 707 | } 708 | 709 | return true; 710 | } 711 | 712 | static bool load_dynamic(struct elf_module *m) 713 | { 714 | ElfW(Dyn) *d; 715 | 716 | m->needed_count = 0; 717 | for (d = m->dynamic; d->d_tag != DT_NULL; ++d) { 718 | LOG_DEBUG("d = %p, d[0](tag) = 0x%p d[1](val) = 0x%p", 719 | d, (void *)d->d_tag, (void *)d->d_un.d_val); 720 | 721 | switch (d->d_tag) { 722 | case DT_HASH: 723 | m->nbucket = ((uint32_t *)(m->load_bias + d->d_un.d_ptr))[0]; 724 | m->nchain = ((uint32_t *)(m->load_bias + d->d_un.d_ptr))[1]; 725 | m->bucket = (uint32_t *)(m->load_bias + d->d_un.d_ptr + 8); 726 | m->chain = (uint32_t *)(m->load_bias + d->d_un.d_ptr + 8 + m->nbucket *4); 727 | break; 728 | case DT_GNU_HASH: 729 | m->gnu_nbucket = ((uint32_t *)(m->load_bias + d->d_un.d_ptr))[0]; 730 | // skip symndx 731 | m->gnu_maskwords = ((uint32_t *)(m->load_bias + d->d_un.d_ptr))[2]; 732 | m->gnu_shift2 = ((uint32_t *)(m->load_bias + d->d_un.d_ptr))[3]; 733 | 734 | m->gnu_bloom_filter = (ElfW(Addr) *)(m->load_bias + d->d_un.d_ptr + 16); 735 | m->gnu_bucket = (uint32_t *)(m->gnu_bloom_filter + m->gnu_maskwords); 736 | // amend chain for symndx = header[1] 737 | m->gnu_chain = m->gnu_bucket + m->gnu_nbucket - 738 | ((uint32_t *)(m->load_bias + d->d_un.d_ptr))[1]; 739 | 740 | if (!powerof2(m->gnu_maskwords)) { 741 | LOG_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two", 742 | m->gnu_maskwords, m->name); 743 | return false; 744 | } 745 | m->gnu_maskwords--; 746 | m->flags |= FLAG_GNU_HASH; 747 | break; 748 | case DT_STRTAB: 749 | m->strtab = (char *)(m->load_bias + d->d_un.d_ptr); 750 | break; 751 | case DT_STRSZ: 752 | m->strtab_size = d->d_un.d_val; 753 | break; 754 | case DT_SYMTAB: 755 | m->symtab = (ElfW(Sym) *)(m->load_bias + d->d_un.d_ptr); 756 | break; 757 | case DT_SYMENT: 758 | if (d->d_un.d_val != sizeof(ElfW(Sym))) { 759 | LOG_ERR("invalid DT_SYMENT: %zu in \"%s\"", (size_t)d->d_un.d_val, m->name); 760 | return false; 761 | } 762 | break; 763 | #if defined(__x86_64__) 764 | case DT_PLTREL: 765 | if (d->d_un.d_val != DT_RELA) { 766 | LOG_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", m->name); 767 | return false; 768 | } 769 | break; 770 | case DT_JMPREL: 771 | m->plt_rela = (ElfW(Rela) *)(m->load_bias + d->d_un.d_ptr); 772 | break; 773 | case DT_PLTRELSZ: 774 | m->plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); 775 | break; 776 | case DT_RELA: 777 | m->rela = (ElfW(Rela) *)(m->load_bias + d->d_un.d_ptr); 778 | break; 779 | case DT_RELASZ: 780 | m->rela_count = d->d_un.d_val /sizeof(ElfW(Rela)); 781 | break; 782 | case DT_RELAENT: 783 | if (d->d_un.d_val != sizeof(ElfW(Rela))) { 784 | LOG_ERR("invalid DT_RELAENT: %zu", (size_t)d->d_un.d_val); 785 | return false; 786 | } 787 | break; 788 | case DT_REL: 789 | LOG_ERR("unsupported DT_REL in \"%s\"", m->name); 790 | return false; 791 | case DT_RELSZ: 792 | LOG_ERR("unsupported DT_RELSZ in \"%s\"", m->name); 793 | return false; 794 | #else 795 | case DT_PLTREL: 796 | if (d->d_un.d_val != DT_REL) { 797 | LOG_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", m->name); 798 | return false; 799 | } 800 | break; 801 | case DT_JMPREL: 802 | m->plt_rel = (ElfW(Rel) *)(m->load_bias + d->d_un.d_ptr); 803 | break; 804 | case DT_PLTRELSZ: 805 | m->plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); 806 | break; 807 | case DT_REL: 808 | m->rel = (ElfW(Rel) *)(m->load_bias + d->d_un.d_ptr); 809 | break; 810 | case DT_RELSZ: 811 | m->rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); 812 | break; 813 | case DT_RELENT: 814 | if (d->d_un.d_val != sizeof(ElfW(Rel))) { 815 | LOG_ERR("invalid DT_RELENT: %zu", (size_t)d->d_un.d_val); 816 | return false; 817 | } 818 | break; 819 | case DT_RELA: 820 | LOG_ERR("unsupported DT_RELA in \"%s\"", m->name); 821 | return false; 822 | case DT_RELASZ: 823 | LOG_ERR("unsupported DT_RELASZ in \"%s\"", m->name); 824 | return false; 825 | #endif 826 | case DT_NEEDED: 827 | m->needed_count++; 828 | break; 829 | default: 830 | LOG_DEBUG("\"%s\" unused DT entry: type %p arg %p", 831 | m->name, (void *)d->d_tag, (void *)d->d_un.d_val); 832 | break; 833 | }; 834 | } 835 | 836 | LOG_DEBUG("mod->base = %zx, mod->strtab = %p, mod->symtab = %p", 837 | m->base, m->strtab, m->symtab); 838 | 839 | // Sanity checks. 840 | if (m->nbucket == 0 && m->gnu_nbucket == 0) { 841 | LOG_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" " 842 | "(new hash type from the future?)", m->name); 843 | return false; 844 | } 845 | if (m->strtab == 0) { 846 | LOG_ERR("empty/missing DT_STRTAB in \"%s\"", m->name); 847 | return false; 848 | } 849 | if (m->symtab == 0) { 850 | LOG_ERR("empty/missing DT_SYMTAB in \"%s\"", m->name); 851 | return false; 852 | } 853 | 854 | return true; 855 | } 856 | 857 | static bool elf_link(struct elf_module *m) 858 | { 859 | bool ret = false; 860 | ElfW(Dyn) *d; 861 | struct elf_module **needed; 862 | struct elf_module **pneeded; 863 | 864 | LOG_DEBUG("[ linking %s ]", m->name); 865 | LOG_DEBUG("mod->base = %zx mod->flags = 0x%08x", m->base, m->flags); 866 | 867 | /* load needed module */ 868 | pneeded = needed = (struct elf_module **)malloc((1 + m->needed_count) * sizeof(struct elf_module *)); 869 | if (needed == NULL) { 870 | LOG_ERR("\"%s\"malloc for needed array failed", m->name); 871 | return false; 872 | } 873 | 874 | for (d = m->dynamic; d->d_tag != DT_NULL; ++d) { 875 | if (d->d_tag == DT_NEEDED) { 876 | struct elf_module *need_mod; 877 | const char *need_name = m->strtab + d->d_un.d_val; 878 | LOG_DEBUG("%s needs %s", m->name, need_name); 879 | need_mod = find_module(need_name); 880 | if (need_mod != NULL) { 881 | need_mod->refcnt++; 882 | *pneeded++ = need_mod; 883 | continue; 884 | } 885 | LOG_DEBUG("load module %s use dlopen()", m->name); 886 | if (dlopen(need_name, RTLD_NOW | RTLD_GLOBAL) == NULL) { 887 | LOG_ERR("could not load module \"%s\" needed by \"%s\"", need_name, m->name); 888 | return false; 889 | } 890 | } 891 | } 892 | *pneeded = NULL; 893 | 894 | #if defined(__x86_64__) 895 | if (m->rela != NULL) { 896 | LOG_DEBUG("[ relocating %s ]", m->name); 897 | if (!apply_relocate_add(m, m->rela, m->rela_count, needed)) 898 | goto out; 899 | } 900 | 901 | if (m->plt_rela != NULL) { 902 | LOG_DEBUG("[ relocating %s plt ]", m->name); 903 | if (!apply_relocate_add(m, m->plt_rela, m->plt_rela_count, needed)) 904 | goto out; 905 | } 906 | #else 907 | if (m->rel != NULL) { 908 | LOG_DEBUG("[ relocating %s ]", m->name); 909 | if (!apply_relocate(m, m->rel, m->rel_count, needed)) 910 | goto out; 911 | } 912 | 913 | if (m->plt_rel != NULL) { 914 | LOG_DEBUG("[ relocating %s plt ]", m->name ); 915 | if (!apply_relocate(m, m->plt_rel, m->plt_rel_count, needed)) 916 | goto out; 917 | } 918 | #endif 919 | 920 | m->flags |= FLAG_LINKED; 921 | ret = true; 922 | out: 923 | free(needed); 924 | LOG_DEBUG("[ finished linking %s, ret=%d ]", m->name, ret); 925 | return ret; 926 | } 927 | 928 | struct elf_module *load_elf_module(const char *name, const void *elf_data, size_t elf_len) 929 | { 930 | struct elf_info info = { .name = name, .hdr = elf_data, .len = elf_len }; 931 | struct elf_module *m; 932 | 933 | LOG_DEBUG("load_elf_module: name=%s, bin=%p, len=%zu", name, elf_data, elf_len); 934 | 935 | if (find_module(name)) { 936 | LOG_ERR("\"%s\" already exist", name); 937 | return NULL; 938 | } 939 | 940 | if (!verify_elf_header(&info) || !read_program_headers(&info)) 941 | return NULL; 942 | 943 | m = elf_module_alloc(name); 944 | if (m == NULL) 945 | return NULL; 946 | 947 | if (!layout_segments(m, &info)) 948 | goto out_free; 949 | 950 | m->phdr = find_loaded_phdr(m, &info); 951 | if (m->phdr == NULL) 952 | goto out_free; 953 | m->phnum = info.hdr->e_phnum; 954 | m->entry = m->load_bias + info.hdr->e_entry; 955 | 956 | phdr_table_get_dynamic_section(m->phdr, m->phnum, m->load_bias, &m->dynamic, NULL); 957 | if (m->dynamic) { 958 | if (!load_dynamic(m)) 959 | goto out_free; 960 | 961 | if (!elf_link(m)) 962 | goto out_free; 963 | } 964 | 965 | list_add_tail(&m->list, &mod_list); 966 | 967 | LOG_DEBUG("[ \"%s\" load done, base=0x%zx sz=0x%zx entry=0x%zx ]", 968 | m->name, m->base, m->size, m->entry); 969 | return m; 970 | 971 | out_free: 972 | elf_module_free(m); 973 | return NULL; 974 | } 975 | 976 | void unload_elf_module(const char *name) 977 | { 978 | struct elf_module *m; 979 | ElfW(Dyn) *d; 980 | 981 | m = find_module(name); 982 | if (m == NULL) 983 | return; 984 | 985 | if (m->refcnt == 1) { 986 | LOG_DEBUG("unloading \"%s\"", m->name); 987 | 988 | list_del(&m->list); 989 | 990 | for (d = m->dynamic; d->d_tag != DT_NULL; ++d) { 991 | if (d->d_tag == DT_NEEDED) { 992 | const char *need_name = m->strtab + d->d_un.d_val; 993 | LOG_DEBUG("%s needs to unload %s", m->name, need_name); 994 | unload_elf_module(need_name); 995 | } 996 | } 997 | 998 | elf_module_free(m); 999 | } else { 1000 | m->refcnt--; 1001 | LOG_DEBUG("not unloading \"%s\", decrementing refcnt to %zu", m->name, m->refcnt); 1002 | } 1003 | } 1004 | 1005 | typedef int (*main_func_t)(void); 1006 | 1007 | int run_elf_module(struct elf_module *m, const char *func) 1008 | { 1009 | ElfW(Sym *) s = lookup_symbol_in_module(m, func); 1010 | main_func_t fn; 1011 | 1012 | if (!s) { 1013 | LOG_ERR("not found function %s", func); 1014 | return -1; 1015 | } 1016 | 1017 | fn = (void *)(m->load_bias + s->st_value); 1018 | 1019 | return fn(); 1020 | } 1021 | -------------------------------------------------------------------------------- /elf_loader.h: -------------------------------------------------------------------------------- 1 | #ifndef _ELF_LOADER_H_ 2 | #define _ELF_LOADER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "wheelc/wheelc.h" 10 | 11 | #if defined(__LP64__) 12 | #define ElfW(what) Elf64_ ## what 13 | #define ELFW(what) ELF64_ ## what 14 | #else 15 | #define ElfW(what) Elf32_ ## what 16 | #define ELFW(what) ELF32_ ## what 17 | #endif 18 | 19 | #define FLAG_LINKED 0x00000001 20 | #define FLAG_GNU_HASH 0x00000002 21 | 22 | #define ELF_MODULE_NAME_LEN 128 23 | 24 | struct elf_module { 25 | char name[ELF_MODULE_NAME_LEN]; 26 | 27 | ElfW(Addr) entry; 28 | ElfW(Addr) base; 29 | size_t size; 30 | ElfW(Addr) load_bias; 31 | 32 | ElfW(Phdr) *phdr; 33 | size_t phnum; 34 | ElfW(Dyn) *dynamic; 35 | const char *strtab; 36 | size_t strtab_size; 37 | ElfW(Sym) *symtab; 38 | 39 | /* ELF hash*/ 40 | size_t nbucket; 41 | size_t nchain; 42 | uint32_t *bucket; 43 | uint32_t *chain; 44 | 45 | /* GUN Hash */ 46 | size_t gnu_nbucket; 47 | uint32_t *gnu_bucket; 48 | uint32_t *gnu_chain; 49 | uint32_t gnu_maskwords; 50 | uint32_t gnu_shift2; 51 | ElfW(Addr) *gnu_bloom_filter; 52 | 53 | #if defined(__x86_64__) 54 | ElfW(Rela) *plt_rela; 55 | size_t plt_rela_count; 56 | ElfW(Rela) *rela; 57 | size_t rela_count; 58 | #else 59 | ElfW(Rel) *plt_rel; 60 | size_t plt_rel_count; 61 | ElfW(Rel) *rel; 62 | size_t rel_count; 63 | #endif 64 | 65 | size_t needed_count; 66 | uint32_t flags; 67 | size_t refcnt; 68 | 69 | struct list_head list; 70 | }; 71 | 72 | struct elf_module *load_elf_module(const char *name, const void *elf_data, size_t elf_len); 73 | void unload_elf_module(const char *name); 74 | int run_elf_module(struct elf_module *m, const char *func); 75 | 76 | #endif /* _ELF_LOADER_H_ */ 77 | -------------------------------------------------------------------------------- /hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | void *worker(void *arg) 8 | { 9 | printf("%d: hello world!\n", (unsigned long)arg); 10 | } 11 | 12 | void main1(void) 13 | { 14 | int i; 15 | pthread_t th[10]; 16 | 17 | for (i = 0; i < 10; ++i) 18 | pthread_create(&th[i], NULL, worker, (unsigned long)i); 19 | 20 | sleep(1); 21 | } 22 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "elf_loader.h" 9 | #include "wheelc/wheelc.h" 10 | 11 | static bool read_file(const char *fname, void **buf, size_t *len) 12 | { 13 | int fd = -1; 14 | struct stat st; 15 | char *tmp_buf; 16 | off_t pos; 17 | ssize_t read_bytes; 18 | 19 | if (stat(fname, &st) == -1) { 20 | LOG_ERR("fstat: error - %s", strerror(errno)); 21 | return false; 22 | } 23 | if (st.st_size == 0) { 24 | LOG_ERR("fstat: error - st.st_size = 0"); 25 | return false; 26 | } 27 | 28 | tmp_buf = malloc(st.st_size); 29 | if (tmp_buf == NULL) { 30 | LOG_ERR("out of memory when alloc size=%lu", st.st_size); 31 | return false; 32 | } 33 | 34 | fd = open(fname, O_RDONLY | O_CLOEXEC, 0); 35 | if (fd < 0) { 36 | LOG_ERR("open file %s error, %s", fname, strerror(errno)); 37 | goto out_free; 38 | } 39 | 40 | pos = 0; 41 | while (pos < st.st_size) { 42 | read_bytes = read(fd, tmp_buf + pos, st.st_size - pos); 43 | if (read_bytes < 0) { 44 | LOG_ERR("read error - %s", strerror(errno)); 45 | goto out_free; 46 | } 47 | if (read_bytes == 0) 48 | break; 49 | pos += read_bytes; 50 | } 51 | 52 | if (pos != st.st_size) { 53 | LOG_ERR("read file incomplete, read %lu, size=%lu", pos, st.st_size); 54 | goto out_free; 55 | } 56 | 57 | *buf = tmp_buf; 58 | *len = st.st_size; 59 | return true; 60 | 61 | out_free: 62 | free(tmp_buf); 63 | if (fd >= 0) 64 | close(fd); 65 | return false; 66 | } 67 | 68 | int main(int argc, char *argv[]) 69 | { 70 | struct elf_module *m; 71 | void *bin; 72 | size_t len; 73 | const char *fname; 74 | const char *bname; 75 | 76 | if (argc != 3) { 77 | LOG_ERR("need one param"); 78 | return 0; 79 | } 80 | 81 | fname = argv[1]; 82 | bname = filename_from_path(fname); 83 | 84 | if (!read_file(fname, &bin, &len)) { 85 | free(bin); 86 | return 0; 87 | } 88 | 89 | m = load_elf_module(bname, bin, len); 90 | if (m == NULL) { 91 | free(bin); 92 | LOG_ERR("load_elf_module %s failed", bname); 93 | return 0; 94 | } 95 | 96 | free(bin); 97 | 98 | run_elf_module(m, argv[2]); 99 | 100 | LOG_INFO("module %s run done", m->name); 101 | 102 | return 0; 103 | } 104 | -------------------------------------------------------------------------------- /makefile.hello: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -shared -fPIC -lpthread -o hello.so hello.c 3 | 4 | clean: 5 | rm -rf hello.o hello.so 6 | -------------------------------------------------------------------------------- /wheelc/list.c: -------------------------------------------------------------------------------- 1 | #include "list.h" 2 | 3 | /* 4 | * Insert a new entry between two known consecutive entries. 5 | * 6 | * This is only for internal list manipulation where we know 7 | * the prev/next entries already! 8 | */ 9 | void __list_add(struct list_head * new, 10 | struct list_head * prev, 11 | struct list_head * next) 12 | { 13 | next->prev = new; 14 | new->next = next; 15 | new->prev = prev; 16 | prev->next = new; 17 | } 18 | 19 | /** 20 | * list_add - add a new entry 21 | * @new: new entry to be added 22 | * @head: list head to add it after 23 | * 24 | * Insert a new entry after the specified head. 25 | * This is good for implementing stacks. 26 | */ 27 | void list_add(struct list_head *new, struct list_head *head) 28 | { 29 | __list_add(new, head, head->next); 30 | } 31 | 32 | /** 33 | * list_add_tail - add a new entry 34 | * @new: new entry to be added 35 | * @head: list head to add it before 36 | * 37 | * Insert a new entry before the specified head. 38 | * This is useful for implementing queues. 39 | */ 40 | void list_add_tail(struct list_head *new, struct list_head *head) 41 | { 42 | __list_add(new, head->prev, head); 43 | } 44 | 45 | /* 46 | * Delete a list entry by making the prev/next entries 47 | * point to each other. 48 | * 49 | * This is only for internal list manipulation where we know 50 | * the prev/next entries already! 51 | */ 52 | void __list_del(struct list_head * prev, 53 | struct list_head * next) 54 | { 55 | next->prev = prev; 56 | prev->next = next; 57 | } 58 | 59 | /** 60 | * list_del - deletes entry from list. 61 | * @entry: the element to delete from the list. 62 | * Note: list_empty on entry does not return true after this, the entry is in an undefined state. 63 | */ 64 | void list_del(struct list_head *entry) 65 | { 66 | __list_del(entry->prev, entry->next); 67 | } 68 | 69 | /** 70 | * list_del_init - deletes entry from list and reinitialize it. 71 | * @entry: the element to delete from the list. 72 | */ 73 | void list_del_init(struct list_head *entry) 74 | { 75 | __list_del(entry->prev, entry->next); 76 | INIT_LIST_HEAD(entry); 77 | } 78 | 79 | /** 80 | * list_empty - tests whether a list is empty 81 | * @head: the list to test. 82 | */ 83 | int list_empty(struct list_head *head) 84 | { 85 | return head->next == head; 86 | } 87 | 88 | /** 89 | * list_splice - join two lists 90 | * @list: the new list to add. 91 | * @head: the place to add it in the first list. 92 | */ 93 | void list_splice(struct list_head *list, struct list_head *head) 94 | { 95 | struct list_head *first = list->next; 96 | 97 | if (first != list) { 98 | struct list_head *last = list->prev; 99 | struct list_head *at = head->next; 100 | 101 | first->prev = head; 102 | head->next = first; 103 | 104 | last->next = at; 105 | at->prev = last; 106 | } 107 | } 108 | 109 | 110 | // 111 | // hlist 112 | // 113 | 114 | static void __hlist_del(struct hlist_node *n) 115 | { 116 | struct hlist_node *next = n->next; 117 | struct hlist_node **pprev = n->pprev; 118 | *pprev = next; 119 | if (next) 120 | next->pprev = pprev; 121 | } 122 | 123 | void hlist_del(struct hlist_node *n) 124 | { 125 | __hlist_del(n); 126 | n->next = LIST_POISON1; 127 | n->pprev = LIST_POISON2; 128 | } 129 | 130 | void hlist_del_init(struct hlist_node *n) 131 | { 132 | if (!hlist_unhashed(n)) { 133 | __hlist_del(n); 134 | INIT_HLIST_NODE(n); 135 | } 136 | } 137 | 138 | void hlist_add_head(struct hlist_node *n, struct hlist_head *h) 139 | { 140 | struct hlist_node *first = h->first; 141 | n->next = first; 142 | if (first) 143 | first->pprev = &n->next; 144 | h->first = n; 145 | n->pprev = &h->first; 146 | } 147 | 148 | /* next must be != NULL */ 149 | void hlist_add_before(struct hlist_node *n, 150 | struct hlist_node *next) 151 | { 152 | n->pprev = next->pprev; 153 | n->next = next; 154 | next->pprev = &n->next; 155 | *(n->pprev) = n; 156 | } 157 | 158 | void hlist_add_behind(struct hlist_node *n, 159 | struct hlist_node *prev) 160 | { 161 | n->next = prev->next; 162 | prev->next = n; 163 | n->pprev = &prev->next; 164 | 165 | if (n->next) 166 | n->next->pprev = &n->next; 167 | } 168 | 169 | /* after that we'll appear to be on some hlist and hlist_del will work */ 170 | void hlist_add_fake(struct hlist_node *n) 171 | { 172 | n->pprev = &n->next; 173 | } 174 | 175 | int hlist_fake(struct hlist_node *h) 176 | { 177 | return h->pprev == &h->next; 178 | } 179 | 180 | /* 181 | * Move a list from one list head to another. Fixup the pprev 182 | * reference of the first entry if it exists. 183 | */ 184 | void hlist_move_list(struct hlist_head *old, 185 | struct hlist_head *new) 186 | { 187 | new->first = old->first; 188 | if (new->first) 189 | new->first->pprev = &new->first; 190 | old->first = NULL; 191 | } 192 | -------------------------------------------------------------------------------- /wheelc/list.h: -------------------------------------------------------------------------------- 1 | /** 2 | * from linux kenrel source 3 | */ 4 | 5 | #ifndef _WHEELC_LIST_H_ 6 | #define _WHEELC_LIST_H_ 7 | 8 | #ifndef NULL 9 | #define NULL 0 10 | #endif 11 | 12 | /* 13 | * These are non-NULL pointers that will result in page faults 14 | * under normal circumstances, used to verify that nobody uses 15 | * non-initialized list entries. 16 | */ 17 | #define LIST_POISON1 ((void *) 0x00100100) 18 | #define LIST_POISON2 ((void *) 0x00200200) 19 | 20 | /* 21 | * Simple doubly linked list implementation. 22 | * 23 | * Some of the internal functions ("__xxx") are useful when 24 | * manipulating whole lists rather than single entries, as 25 | * sometimes we already know the next/prev entries and we can 26 | * generate better code by using them directly rather than 27 | * using the generic single-entry routines. 28 | */ 29 | 30 | struct list_head { 31 | struct list_head *next, *prev; 32 | }; 33 | 34 | #define LIST_HEAD_INIT(name) { &(name), &(name) } 35 | 36 | #define LIST_HEAD(name) \ 37 | struct list_head name = LIST_HEAD_INIT(name) 38 | 39 | #define INIT_LIST_HEAD(ptr) do { \ 40 | (ptr)->next = (ptr); (ptr)->prev = (ptr); \ 41 | } while (0) 42 | 43 | /* 44 | * Insert a new entry between two known consecutive entries. 45 | * 46 | * This is only for internal list manipulation where we know 47 | * the prev/next entries already! 48 | */ 49 | void __list_add(struct list_head * new, 50 | struct list_head * prev, 51 | struct list_head * next); 52 | 53 | /** 54 | * list_add - add a new entry 55 | * @new: new entry to be added 56 | * @head: list head to add it after 57 | * 58 | * Insert a new entry after the specified head. 59 | * This is good for implementing stacks. 60 | */ 61 | void list_add(struct list_head *new, struct list_head *head); 62 | 63 | /** 64 | * list_add_tail - add a new entry 65 | * @new: new entry to be added 66 | * @head: list head to add it before 67 | * 68 | * Insert a new entry before the specified head. 69 | * This is useful for implementing queues. 70 | */ 71 | void list_add_tail(struct list_head *new, struct list_head *head); 72 | 73 | /* 74 | * Delete a list entry by making the prev/next entries 75 | * point to each other. 76 | * 77 | * This is only for internal list manipulation where we know 78 | * the prev/next entries already! 79 | */ 80 | void __list_del(struct list_head * prev, 81 | struct list_head * next); 82 | 83 | /** 84 | * list_del - deletes entry from list. 85 | * @entry: the element to delete from the list. 86 | * Note: list_empty on entry does not return true after this, the entry is in an undefined state. 87 | */ 88 | void list_del(struct list_head *entry); 89 | 90 | /** 91 | * list_del_init - deletes entry from list and reinitialize it. 92 | * @entry: the element to delete from the list. 93 | */ 94 | void list_del_init(struct list_head *entry); 95 | 96 | /** 97 | * list_empty - tests whether a list is empty 98 | * @head: the list to test. 99 | */ 100 | int list_empty(struct list_head *head); 101 | 102 | /** 103 | * list_splice - join two lists 104 | * @list: the new list to add. 105 | * @head: the place to add it in the first list. 106 | */ 107 | void list_splice(struct list_head *list, struct list_head *head); 108 | 109 | /** 110 | * list_entry - get the struct for this entry 111 | * @ptr: the &struct list_head pointer. 112 | * @type: the type of the struct this is embedded in. 113 | * @member: the name of the list_struct within the struct. 114 | */ 115 | #define list_entry(ptr, type, member) \ 116 | ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) 117 | 118 | /** 119 | * list_first_entry - get the first element from a list 120 | * @ptr: the list head to take the element from. 121 | * @type: the type of the struct this is embedded in. 122 | * @member: the name of the list_head within the struct. 123 | * 124 | * Note, that list is expected to be not empty. 125 | */ 126 | #define list_first_entry(ptr, type, member) \ 127 | list_entry((ptr)->next, type, member) 128 | 129 | /** 130 | * list_last_entry - get the last element from a list 131 | * @ptr: the list head to take the element from. 132 | * @type: the type of the struct this is embedded in. 133 | * @member: the name of the list_head within the struct. 134 | * 135 | * Note, that list is expected to be not empty. 136 | */ 137 | #define list_last_entry(ptr, type, member) \ 138 | list_entry((ptr)->prev, type, member) 139 | 140 | /** 141 | * list_first_entry_or_null - get the first element from a list 142 | * @ptr: the list head to take the element from. 143 | * @type: the type of the struct this is embedded in. 144 | * @member: the name of the list_head within the struct. 145 | * 146 | * Note that if the list is empty, it returns NULL. 147 | */ 148 | #define list_first_entry_or_null(ptr, type, member) \ 149 | (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) 150 | 151 | /** 152 | * list_for_each - iterate over a list 153 | * @pos: the &struct list_head to use as a loop counter. 154 | * @head: the head for your list. 155 | */ 156 | #define list_for_each(pos, head) \ 157 | for (pos = (head)->next; pos != (head); pos = pos->next) 158 | 159 | /** 160 | * list_for_each_safe - iterate over a list safe against removal of list entry 161 | * @pos: the &struct list_head to use as a loop counter. 162 | * @n: another &struct list_head to use as temporary storage 163 | * @head: the head for your list. 164 | */ 165 | #define list_for_each_safe(pos, n, head) \ 166 | for (pos = (head)->next, n = pos->next; pos != (head); \ 167 | pos = n, n = pos->next) 168 | 169 | /** 170 | * list_for_each_prev - iterate over a list in reverse order 171 | * @pos: the &struct list_head to use as a loop counter. 172 | * @head: the head for your list. 173 | */ 174 | #define list_for_each_prev(pos, head) \ 175 | for (pos = (head)->prev; pos != (head); pos = pos->prev) 176 | 177 | /* 178 | * Double linked lists with a single pointer list head. 179 | * Mostly useful for hash tables where the two pointer list head is 180 | * too wasteful. 181 | * You lose the ability to access the tail in O(1). 182 | */ 183 | 184 | struct hlist_node { 185 | struct hlist_node *next, **pprev; 186 | }; 187 | 188 | struct hlist_head { 189 | struct hlist_node *first; 190 | }; 191 | 192 | #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) 193 | #define INIT_HLIST_NODE(h) \ 194 | { \ 195 | h->next = NULL; \ 196 | h->pprev = NULL; \ 197 | } 198 | 199 | #define hlist_unhashed(h) (!h->pprev) 200 | 201 | #define hlist_empty(h) (!h->first) 202 | 203 | void hlist_del(struct hlist_node *n); 204 | void hlist_del_init(struct hlist_node *n); 205 | void hlist_add_head(struct hlist_node *n, struct hlist_head *h); 206 | 207 | /* next must be != NULL */ 208 | void hlist_add_before(struct hlist_node *n, struct hlist_node *next); 209 | void hlist_add_behind(struct hlist_node *n, struct hlist_node *prev); 210 | /* after that we'll appear to be on some hlist and hlist_del will work */ 211 | void hlist_add_fake(struct hlist_node *n); 212 | int hlist_fake(struct hlist_node *h); 213 | 214 | /* 215 | * Move a list from one list head to another. Fixup the pprev 216 | * reference of the first entry if it exists. 217 | */ 218 | void hlist_move_list(struct hlist_head *old, struct hlist_head *new); 219 | 220 | #define hlist_entry(ptr, type, member) \ 221 | ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) 222 | 223 | #define hlist_for_each(pos, head) \ 224 | for (pos = (head)->first; pos ; pos = pos->next) 225 | 226 | #define hlist_for_each_safe(pos, n, head) \ 227 | for (pos = (head)->first; pos && ({ n = pos->next; 1; }); pos = n) 228 | 229 | 230 | #endif // _WHEELC_LIST_H_ 231 | -------------------------------------------------------------------------------- /wheelc/log.h: -------------------------------------------------------------------------------- 1 | #ifndef _WHEELC_LOG_H_ 2 | #define _WHEELC_LOG_H_ 3 | 4 | #include 5 | 6 | static inline const char *filename_from_path(const char *path) 7 | { 8 | const char *bname = strrchr(path, '/'); 9 | return (bname != NULL) ? bname + 1 : path; 10 | } 11 | 12 | #define LOG_DEBUG(fmt, ...) \ 13 | printf("[DEBUG %s:%d] " fmt "\n", filename_from_path(__FILE__), __LINE__, ## __VA_ARGS__) 14 | 15 | #define LOG_INFO(fmt, ...) \ 16 | printf("[INFO %s:%d] " fmt "\n", filename_from_path(__FILE__), __LINE__, ## __VA_ARGS__) 17 | 18 | #define LOG_WARN(fmt, ...) \ 19 | printf("[WARN %s:%d] " fmt "\n", filename_from_path(__FILE__), __LINE__, ## __VA_ARGS__) 20 | 21 | #define LOG_ERR(fmt, ...) \ 22 | printf("[ERROR %s:%d] " fmt "\n", filename_from_path(__FILE__), __LINE__, ## __VA_ARGS__) 23 | 24 | #endif // _WHEELC_LOG_H_ 25 | -------------------------------------------------------------------------------- /wheelc/wheelc.h: -------------------------------------------------------------------------------- 1 | #ifndef _WHEELC_H_ 2 | #define _WHEELC_H_ 3 | 4 | #include "log.h" 5 | #include "list.h" 6 | 7 | #endif // _WHEELC_H_ 8 | --------------------------------------------------------------------------------