From c2edb94eadbb68503bdb6ee3cfda06e0de1833c6 Mon Sep 17 00:00:00 2001 From: Matheus Afonso Martins Moreira Date: Mon, 12 Aug 2024 13:13:03 -0300 Subject: [PATCH] embed: refactor program header adjuster function Use the new lone ELF functions to handle arbitrary input ELF files without needing to maintain multiple versions of the algorithm for each ELF class and data encoding. --- source/tools/lone-embed.c | 136 +++++++++++++++----------------------- 1 file changed, 53 insertions(+), 83 deletions(-) diff --git a/source/tools/lone-embed.c b/source/tools/lone-embed.c index 3055a11..19f1d76 100644 --- a/source/tools/lone-embed.c +++ b/source/tools/lone-embed.c @@ -15,6 +15,9 @@ #define REQUIRED_PT_NULLS 2 #define LONE_TOOLS_EMBED_EXIT_INVALID_ELF 8 +#define LONE_TOOLS_EMBED_EXIT_MISSING_NULL_ENTRY 9 +#define LONE_TOOLS_EMBED_EXIT_MULTIPLE_PHDR_ENTRIES 10 +#define LONE_TOOLS_EMBED_EXIT_MISSING_PHDR_ENTRY 11 #define LONE_TOOLS_EMBED_EXIT_OVERFLOW 250 struct elf { @@ -335,98 +338,65 @@ static void analyze(struct elf *elf) static void adjust_phdr_entry(struct elf *elf) { - size_t entry_count = elf->segments.table.segment.count; - void *table = elf->segments.memory.pointer; - Elf32_Phdr *phdr32, *phdr32_entry, *phdr32_load; - Elf64_Phdr *phdr64, *phdr64_entry, *phdr64_load; - size_t i; + size_t entry_count, i; + struct lone_elf_header *header; + struct lone_elf_segment *segments, *segment, *phdr, *load; + lone_elf_umax alignment, size, size_aligned, offset, virtual, physical; + lone_u32 type; - switch (elf->class) { - case ELFCLASS64: - phdr64_entry = 0; - phdr64_load = 0; + header = elf->header.pointer; + segments = elf->segments.table.segments; + entry_count = elf->segments.table.segment.count; + phdr = 0; + load = 0; - for (i = 0; i < entry_count; ++i) { - phdr64 = ((Elf64_Phdr *) table) + i; - - if (phdr64->p_type == PT_PHDR) { - if (phdr64_entry) { - /* Multiple PT_PHDR entries, invalid */ linux_exit(10); - } else { - phdr64_entry = phdr64; - } - } else if (phdr64->p_type == PT_NULL) { - phdr64_load = phdr64; - break; - } - } - - if (!phdr64_entry) { - /* Missing PT_PHDR entry */ linux_exit(11); - } - - if (!phdr64_load) { - /* Missing required PT_NULL entry */ linux_exit(9); - } - - phdr64_entry->p_offset = elf->program_header_table.offset; - phdr64_entry->p_vaddr = align_to_page(elf, elf->limits.end.virtual); - phdr64_entry->p_paddr = align_to_page(elf, elf->limits.end.physical); - phdr64_entry->p_filesz = phdr64_entry->p_memsz = pht_size(elf); - - phdr64_load->p_type = PT_LOAD; - phdr64_load->p_offset = elf->program_header_table.offset; - phdr64_load->p_vaddr = phdr64_entry->p_vaddr; - phdr64_load->p_paddr = phdr64_entry->p_paddr; - phdr64_load->p_filesz = phdr64_load->p_memsz = align_to_page(elf, pht_size(elf)); - phdr64_load->p_align = elf->page_size; - phdr64_load->p_flags = PF_R; - - break; - case ELFCLASS32: - phdr32_entry = 0; - phdr32_load = 0; + for (i = 0; i < entry_count; ++i) { + segment = lone_elf_segment_at(elf->segments.table, i); + if (!segment) { overflow(); } - for (i = 0; i < entry_count; ++i) { - phdr32 = ((Elf32_Phdr *) table) + i; + type = segment_read_u32(header, segment, lone_elf_segment_read_type); - if (phdr32->p_type == PT_PHDR) { - if (phdr32_entry) { - /* Multiple PT_PHDR entries, invalid */ linux_exit(10); - } else { - phdr32_entry = phdr32; - } - } else if (phdr32->p_type == PT_NULL) { - phdr32_load = phdr32; - break; + if (type == LONE_ELF_SEGMENT_TYPE_PHDR) { + if (phdr) { + linux_exit(LONE_TOOLS_EMBED_EXIT_MULTIPLE_PHDR_ENTRIES); + } else { + phdr = segment; } + } else if (type == LONE_ELF_SEGMENT_TYPE_NULL) { + load = segment; + break; } + } - if (!phdr32_entry) { - /* Missing PT_PHDR entry */ linux_exit(11); - } - - if (!phdr32_load) { - /* Missing required PT_NULL entry */ linux_exit(9); - } - - phdr32_entry->p_offset = elf->program_header_table.offset; - phdr32_entry->p_vaddr = align_to_page(elf, elf->limits.end.virtual); - phdr32_entry->p_paddr = align_to_page(elf, elf->limits.end.physical); - phdr32_entry->p_filesz = phdr32_entry->p_memsz = pht_size(elf); - - phdr32_load->p_type = PT_LOAD; - phdr32_load->p_offset = elf->program_header_table.offset; - phdr32_load->p_vaddr = phdr32_entry->p_vaddr; - phdr32_load->p_paddr = phdr32_entry->p_paddr; - phdr32_load->p_filesz = phdr32_load->p_memsz = align_to_page(elf, pht_size(elf)); - phdr32_load->p_align = elf->page_size; - phdr32_load->p_flags = PF_R; + if (!phdr) { + linux_exit(LONE_TOOLS_EMBED_EXIT_MISSING_PHDR_ENTRY); + } - break; - default: - /* Invalid ELF class but somehow made it here? */ linux_exit(8); + if (!load) { + linux_exit(LONE_TOOLS_EMBED_EXIT_MISSING_NULL_ENTRY); } + + alignment = elf->page_size; + size = pht_size(elf); + size_aligned = align_to_page(elf, size); + offset = elf->segments.offset; + virtual = align_to_page(elf, elf->limits.end.virtual); + physical = align_to_page(elf, elf->limits.end.physical); + + segment_write_umax(header, phdr, lone_elf_segment_write_file_offset, offset); + segment_write_umax(header, phdr, lone_elf_segment_write_virtual_address, virtual); + segment_write_umax(header, phdr, lone_elf_segment_write_physical_address, physical); + segment_write_umax(header, phdr, lone_elf_segment_write_size_in_file, size); + segment_write_umax(header, phdr, lone_elf_segment_write_size_in_memory, size); + + segment_write_u32(header, load, lone_elf_segment_write_type, LONE_ELF_SEGMENT_TYPE_LOAD); + segment_write_u32(header, load, lone_elf_segment_write_flags, LONE_ELF_SEGMENT_FLAGS_R); + segment_write_umax(header, load, lone_elf_segment_write_file_offset, offset); + segment_write_umax(header, load, lone_elf_segment_write_virtual_address, virtual); + segment_write_umax(header, load, lone_elf_segment_write_physical_address, physical); + segment_write_umax(header, load, lone_elf_segment_write_size_in_file, size_aligned); + segment_write_umax(header, load, lone_elf_segment_write_size_in_memory, size_aligned); + segment_write_umax(header, load, lone_elf_segment_write_alignment, alignment); } static void move_and_expand_pht_if_needed(struct elf *elf)