* Loader initialization code. */
| 335 | * Loader initialization code. |
| 336 | */ |
| 337 | void *e9init(int argc, char **argv, char **envp, const e9_config_s *config) |
| 338 | { |
| 339 | // Step (0): Sanity checks & initialization: |
| 340 | if (config->magic[0] != 'E' || config->magic[1] != '9' || |
| 341 | config->magic[2] != 'P' || config->magic[3] != 'A' || |
| 342 | config->magic[4] != 'T' || config->magic[5] != 'C' || |
| 343 | config->magic[6] != 'H' || config->magic[7] != '\0') |
| 344 | e9panic("missing \"E9PATCH\" magic number"); |
| 345 | const uint8_t *loader_base = (const uint8_t *)config; |
| 346 | const uint8_t *loader_end = loader_base + config->size; |
| 347 | const uint8_t *elf_base = loader_base - config->base; |
| 348 | const void *dynamic = NULL; |
| 349 | const struct e9_config_elf_s *config_elf = |
| 350 | (const struct e9_config_elf_s *)(config + 1); |
| 351 | if (config_elf->dynamic != 0x0) |
| 352 | dynamic = (const void *)(elf_base + config_elf->dynamic); |
| 353 | |
| 354 | // Step (1): Call the pre-initialization routine: |
| 355 | const uint32_t *preinits = |
| 356 | (const uint32_t *)(loader_base + config->preinits); |
| 357 | for (uint32_t i = 0; i < config->num_preinits; i++) |
| 358 | { |
| 359 | init_t preinit = (init_t)(loader_base + preinits[i]); |
| 360 | preinit(argc, argv, envp, dynamic, config); |
| 361 | } |
| 362 | |
| 363 | // Step (2): Find & open the binary: |
| 364 | char buf[BUFSIZ]; |
| 365 | const char *path = "/proc/self/exe"; |
| 366 | if ((config->flags & E9_FLAG_EXE) == 0) |
| 367 | { |
| 368 | // This is a shared object, so use the /proc/self/map_files/ |
| 369 | // method to find the binary. |
| 370 | char *str = buf; |
| 371 | str = e9write_format(str, "/proc/self/map_files/%X-%X", loader_base, |
| 372 | loader_end); |
| 373 | str = e9write_char(str, '\0'); |
| 374 | path = buf; |
| 375 | } |
| 376 | ssize_t len = (ssize_t)e9syscall(SYS_readlink, path, buf, sizeof(buf)); |
| 377 | if (len < 0) |
| 378 | e9panic("readlink(path=\"%s\") failed (errno=%u)", buf, -len); |
| 379 | buf[len] = '\0'; |
| 380 | int fd = (int)e9syscall(SYS_open, buf, O_RDONLY, 0); |
| 381 | if (fd < 0) |
| 382 | e9panic("open(path=\"%s\") failed (errno=%u)", buf, -fd); |
| 383 | |
| 384 | // Step (3): Setup dummy TLS (if necessary): |
| 385 | struct e9scratch_s *scratch = NULL; |
| 386 | uintptr_t tls = 0x0; |
| 387 | intptr_t r = e9syscall(SYS_arch_prctl, ARCH_GET_FS, &tls); |
| 388 | if (r < 0) |
| 389 | e9panic("arch_prctl() failed (errno=%u)", -r); |
| 390 | if (tls == 0x0) |
| 391 | { |
| 392 | // No libc == no tls: |
| 393 | scratch = e9scratch(config, /*alloc=*/true); |
| 394 | tls = (uintptr_t)&scratch->tls; |
nothing calls this directly
no test coverage detected