elf64_loader.c 3.37 KB
#include <elf64_loader.h>

int8_t IsElf64(Elf64_Ehdr *elf64_header) {
    // check magic numbers
    if (elf64_header->e_ident[EI_MAG0] == ELFMAG0 && elf64_header->e_ident[EI_MAG1] == ELFMAG1 &&
        elf64_header->e_ident[EI_MAG2] == ELFMAG2 &&
        elf64_header->e_ident[EI_CLASS] == ELFCLASS64) {
        return 1;
    }
    return 0;
}

int LoadElf64(const int file_descriptor, const char *section_name) {
    Elf64_Ehdr elf64_header;

    if (file_descriptor == PT_NULL || section_name == NULL) {
        return EINVAL;  // Invalid argument
    }

    // read file headers
    if (read(file_descriptor, &elf64_header, sizeof(Elf64_Ehdr)) != sizeof(Elf64_Ehdr)) {
        close(file_descriptor);
        return EIO;  // Input/output error
    }

    if (!IsElf64(&elf64_header)) {
        return EINVAL;  // Invalid argument (it's not an ELF file)
    }

    // jump through the header
    if (lseek(file_descriptor, (off_t)elf64_header.e_phoff, SEEK_SET) == -1) {
        close(file_descriptor);
        return errno;
    }

    Elf64_Phdr program_headers[elf64_header.e_phnum];  // e_phnum - the number of program headers
    size_t program_headers_size = sizeof(Elf64_Phdr) * elf64_header.e_phnum;
    uint16_t program_headers_length = elf64_header.e_phnum;

    if (read(file_descriptor, program_headers, program_headers_size) != program_headers_size) {
        close(file_descriptor);
        return errno;
    }

    int status_code = MapSegments(file_descriptor, program_headers, program_headers_length);

    if (status_code != SUCCESS) {
        close(file_descriptor);
        return status_code;
    }

    // move ptr to the section header table starting point
    if (lseek(file_descriptor, (off_t)elf64_header.e_shoff, SEEK_SET) == -1) {
        close(file_descriptor);
        return errno;
    }

    Elf64_Shdr section_headers[elf64_header.e_shnum];  // e_shnum - the number of section headers
    size_t section_headers_size = sizeof(Elf64_Shdr) * elf64_header.e_shnum;
    uint16_t section_headers_length = elf64_header.e_shnum;

    if (read(file_descriptor, section_headers, section_headers_size) != section_headers_size) {
        close(file_descriptor);
        return EIO;
    }

    // e_shstrndx is a section number that contains the string table containing sections' names
    Elf64_Shdr *section_names_header = &section_headers[elf64_header.e_shstrndx];
    char *section_header_ptr = NULL;

    status_code = MapSection(file_descriptor, section_names_header, &section_header_ptr);

    if (status_code != SUCCESS) {
        close(file_descriptor);
        return status_code;
    }

    // find section which we want to give control
    Elf64_Shdr *start_section = PT_NULL;
    for (uint64_t i = 0; i < section_headers_length; i++) {
        if (StringEquals(section_header_ptr + section_headers[i].sh_name, section_name)) {
            start_section = &section_headers[i];
        }
    }

    // check whether start_section is executable
    if (start_section == PT_NULL || !(start_section->sh_flags & SHF_EXECINSTR)) {
        close(file_descriptor);
        return EINVAL;
    }

    close(file_descriptor);

    // give control to the section
    uintptr_t entry_point_as_int = (uintptr_t)start_section->sh_addr;
    EntryPointFunc entry_point = (EntryPointFunc)entry_point_as_int; // NOLINT
    if (entry_point != NULL) {
        entry_point();
    } else {
        return EINVAL;
    }

    return 0;
}