mirror of
https://github.com/encounter/osdev.git
synced 2026-07-10 12:18:43 -07:00
234 lines
7.0 KiB
C
234 lines
7.0 KiB
C
#include "elf.h"
|
|
#include "console.h"
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <malloc.h>
|
|
|
|
// #define ELF_DEBUG
|
|
|
|
bool _check_elf_header(elf_header_t *header) {
|
|
if (header->magic == ELF_HEADER_MAGIC_LE) {
|
|
if (header->arch_bits != ELF_ARCH_BITS_32) {
|
|
return false;
|
|
}
|
|
if (header->endianness != ELF_ENDIANNESS_LITTLE) {
|
|
return false;
|
|
}
|
|
if (header->machine_type != ELF_IS_X86) {
|
|
return false;
|
|
}
|
|
if (header->header_size > sizeof(elf_header_t)) {
|
|
return false;
|
|
}
|
|
if (header->section_header_entry_size > sizeof(elf_section_header_t)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool _elf_read_header(elf_file_t *file) {
|
|
if (file->header != NULL) return true;
|
|
if (fseek(file->fd, 0, SEEK_SET)) return false;
|
|
|
|
void *buf = NULL;
|
|
size_t header_size = sizeof(elf_header_t), read = 0;
|
|
if ((buf = malloc(header_size)) == NULL) {
|
|
errno = ENOMEM;
|
|
return false;
|
|
}
|
|
read = fread(buf, header_size, 1, file->fd);
|
|
if (ferror(file->fd) || !read || !_check_elf_header(buf)) {
|
|
free(buf);
|
|
return false;
|
|
}
|
|
|
|
file->header = buf;
|
|
return true;
|
|
}
|
|
|
|
static bool _elf_read_section_header_table(elf_file_t *file) {
|
|
if (file->sht_start != NULL) return true;
|
|
if (!_elf_read_header(file)) return false;
|
|
|
|
size_t read = 0;
|
|
elf_header_t *header = file->header;
|
|
if (fseek(file->fd, header->section_header_offset, SEEK_SET))
|
|
return false;
|
|
|
|
void *buf = NULL;
|
|
uint16_t sh_table_size = header->section_header_entry_size *
|
|
header->section_header_num_entries;
|
|
if ((buf = malloc(sh_table_size)) == NULL) {
|
|
errno = ENOMEM;
|
|
return false;
|
|
}
|
|
read = fread(buf, sh_table_size, 1, file->fd);
|
|
if (ferror(file->fd) || !read) {
|
|
free(buf);
|
|
return false;
|
|
}
|
|
|
|
file->sht_start = buf;
|
|
return true;
|
|
}
|
|
|
|
static bool _elf_read_sht_str_section(elf_file_t *file) {
|
|
if (file->sht_str_section != NULL) return true;
|
|
if (!_elf_read_header(file)) return false;
|
|
|
|
elf_header_t *header = file->header;
|
|
elf_section_header_t *section_header = elf_get_section(file, header->section_header_section_names_idx);
|
|
if (section_header == NULL) return NULL;
|
|
file->sht_str_section = elf_read_section(file, section_header);
|
|
return file->sht_str_section != NULL;
|
|
}
|
|
|
|
elf_section_header_t *elf_find_section(elf_file_t *file, const char *name) {
|
|
if (!_elf_read_section_header_table(file)
|
|
|| !_elf_read_sht_str_section(file))
|
|
return NULL;
|
|
|
|
uint16_t num_entries = file->header->section_header_num_entries;
|
|
for (uint16_t i = 0; i < num_entries; ++i) {
|
|
elf_section_header_t *section_header = (void *) file->sht_start + file->header->section_header_entry_size * i;
|
|
if (strcmp(name, file->sht_str_section + section_header->name) == 0) return section_header;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
elf_section_header_t *elf_get_section(elf_file_t *file,
|
|
uint16_t index) {
|
|
if (!_elf_read_section_header_table(file))
|
|
return NULL;
|
|
|
|
uint16_t num_entries = file->header->section_header_num_entries;
|
|
if (index > num_entries - 1) return NULL;
|
|
return (void *) file->sht_start + file->header->section_header_entry_size * index;
|
|
}
|
|
|
|
void *elf_read_section(elf_file_t *file, elf_section_header_t *section_header) {
|
|
if (!_elf_read_header(file)) return false;
|
|
|
|
if (section_header == NULL ||
|
|
section_header->size > UINT16_MAX ||
|
|
fseek(file->fd, section_header->offset, SEEK_SET))
|
|
return NULL;
|
|
|
|
void *buf = NULL;
|
|
uint16_t section_size = (uint16_t) section_header->size;
|
|
if ((buf = malloc(section_size)) == NULL) {
|
|
errno = ENOMEM;
|
|
return NULL;
|
|
}
|
|
if (!fread(buf, section_size, 1, file->fd) || ferror(file->fd)) {
|
|
free(buf);
|
|
return NULL;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
static const char *elf_section_type(elf_section_header_type_t type) {
|
|
switch (type) {
|
|
case ELF_SHT_NULL:
|
|
return "SHT_NULL";
|
|
case ELF_SHT_PROGBITS:
|
|
return "SHT_PROGBITS";
|
|
case ELF_SHT_SYMTAB:
|
|
return "SHT_SYMTAB";
|
|
case ELF_SHT_STRTAB:
|
|
return "SHT_STRTAB";
|
|
case ELF_SHT_RELA:
|
|
return "SHT_RELA";
|
|
case ELF_SHT_HASH:
|
|
return "SHT_HASH";
|
|
case ELF_SHT_DYNAMIC:
|
|
return "SHT_DYNAMIC";
|
|
case ELF_SHT_NOTE:
|
|
return "SHT_NOTE";
|
|
case ELF_SHT_NOBITS:
|
|
return "SHT_NOBITS";
|
|
case ELF_SHT_REL:
|
|
return "SHT_REL";
|
|
case ELF_SHT_SHLIB:
|
|
return "SHT_SHLIB";
|
|
case ELF_SHT_DYNSYM:
|
|
return "SHT_DYNSYM";
|
|
case ELF_SHT_LOPROC:
|
|
return "SHT_LOPROC";
|
|
case ELF_SHT_HIPROC:
|
|
return "SHT_HIPROC";
|
|
case ELF_SHT_LOUSER:
|
|
return "SHT_LOUSER";
|
|
case ELF_SHT_HIUSER:
|
|
return "SHT_HIUSER";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
static const char *elf_obj_type(elf_obj_type_t type) {
|
|
switch (type) {
|
|
case ELF_ET_NONE: return "None";
|
|
case ELF_ET_REL: return "Relocatable";
|
|
case ELF_ET_EXEC: return "Executable";
|
|
case ELF_ET_DYN: return "Dynamic";
|
|
case ELF_ET_CORE: return "Core";
|
|
default: return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
void elf_print_sections(elf_file_t *file) {
|
|
if (!_elf_read_header(file)
|
|
|| !_elf_read_section_header_table(file)
|
|
|| !_elf_read_sht_str_section(file))
|
|
return;
|
|
|
|
elf_header_t *header = file->header;
|
|
printf("ELF type: %s\n", elf_obj_type(header->obj_type));
|
|
printf("ELF entry offset: %Xh\n", header->program_entry_offset);
|
|
|
|
uint16_t num_entries = header->section_header_num_entries;
|
|
for (uint16_t i = 0; i < num_entries; ++i) {
|
|
elf_section_header_t *section_header = (void *) file->sht_start + header->section_header_entry_size * i;
|
|
if (section_header->type == ELF_SHT_NULL) continue; // Skip null header
|
|
printf("Section %03d %s: offset "PRIx32", size "PRIx32", VMA "PRIXUPTR", type %s\n",
|
|
i, file->sht_str_section + section_header->name,
|
|
section_header->offset, section_header->size,
|
|
section_header->address,
|
|
elf_section_type(section_header->type));
|
|
}
|
|
}
|
|
|
|
elf_file_t *elf_open(const char *filename) {
|
|
elf_file_t *file = malloc(sizeof(elf_file_t));
|
|
if (file == NULL) {
|
|
errno = ENOMEM;
|
|
return NULL;
|
|
}
|
|
memset(file, 0, sizeof(elf_file_t));
|
|
|
|
file->fd = fopen(filename, "r");
|
|
if (ferror(file->fd)
|
|
|| !_elf_read_header(file)
|
|
|| !_elf_read_section_header_table(file)) {
|
|
elf_close(file);
|
|
return NULL;
|
|
}
|
|
|
|
return file;
|
|
}
|
|
|
|
void elf_close(elf_file_t *file) {
|
|
if (file == NULL) return;
|
|
if (file->fd != NULL) fclose(file->fd);
|
|
free(file->header);
|
|
free(file->sht_start);
|
|
free(file->sht_str_section);
|
|
free(file);
|
|
} |