Skip to content

Commit

Permalink
embed: refactor program header adjuster function
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
matheusmoreira committed Aug 12, 2024
1 parent d81c572 commit c2edb94
Showing 1 changed file with 53 additions and 83 deletions.
136 changes: 53 additions & 83 deletions source/tools/lone-embed.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit c2edb94

Please sign in to comment.