* Emit the (modified) ELF binary. */
| 446 | * Emit the (modified) ELF binary. |
| 447 | */ |
| 448 | size_t emitElf(Binary *B, const MappingSet &mappings, size_t mapping_size) |
| 449 | { |
| 450 | uint8_t *data = B->patched.bytes; |
| 451 | size_t size = B->patched.size; |
| 452 | |
| 453 | // Step (0): Round-up to nearest page boundary (zero-fill) |
| 454 | stat_input_file_size = size; |
| 455 | size = (size % PAGE_SIZE == 0? size: |
| 456 | size + PAGE_SIZE - (size % PAGE_SIZE)); |
| 457 | |
| 458 | // Step (1): Refactor the patching (if necessary): |
| 459 | RefactorSet refactors; |
| 460 | size += emitRefactoredPatch(B->original.bytes, data, size, mapping_size, |
| 461 | B->Is, refactors); |
| 462 | |
| 463 | // Step (2): Disable incompatible ELF features: |
| 464 | ElfInfo &info = B->elf; |
| 465 | if (info.features != nullptr) |
| 466 | { |
| 467 | if ((*info.features & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0) |
| 468 | *info.features &= ~GNU_PROPERTY_X86_FEATURE_1_IBT; |
| 469 | if ((*info.features & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0) |
| 470 | *info.features &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK; |
| 471 | } |
| 472 | |
| 473 | // Step (3): Emit all mappings: |
| 474 | for (auto *mapping: mappings) |
| 475 | { |
| 476 | uint8_t *base = data + size; |
| 477 | mapping->offset = (off_t)size; |
| 478 | flattenMapping(B, base, mapping, /*int3=*/0xcc); |
| 479 | size += mapping->size; |
| 480 | } |
| 481 | |
| 482 | // Step (4): Emit the loader: |
| 483 | size = (size % PAGE_SIZE == 0? size: |
| 484 | size + PAGE_SIZE - (size % PAGE_SIZE)); |
| 485 | struct e9_config_s *config = (struct e9_config_s *)(data + size); |
| 486 | size_t config_offset = size; |
| 487 | size += sizeof(struct e9_config_s); |
| 488 | struct e9_config_elf_s *config_elf = |
| 489 | (struct e9_config_elf_s *)(data + size); |
| 490 | size += sizeof(struct e9_config_elf_s); |
| 491 | const char magic[] = "E9PATCH"; |
| 492 | memcpy(config->magic, magic, sizeof(magic)); |
| 493 | const char version[] = STRING(VERSION); |
| 494 | static_assert(sizeof(version) <= sizeof(config->version), |
| 495 | "VERSION string is too long"); |
| 496 | memcpy(config->version, version, sizeof(version)); |
| 497 | config->base = option_loader_base; |
| 498 | if (B->mmap != INTPTR_MIN) |
| 499 | { |
| 500 | config->mmap = BASE_ADDRESS(B->mmap); |
| 501 | config->mmap |= (IS_ABSOLUTE(config->mmap)? E9_ABS_ADDR: 0); |
| 502 | } |
| 503 | std::vector<uint32_t> preinits, postinits; |
| 504 | for (auto preinit: B->preinits) |
| 505 | { |
no test coverage detected