Добавлен разбор ELF файлов

This commit is contained in:
Aren 2024-04-25 19:46:03 +03:00
parent e7233a7b4c
commit 40c1604109
4 changed files with 208 additions and 37 deletions

View File

@ -7,37 +7,109 @@
* *
*/ */
#include <log.h>
#include <stddef.h>
#include <stdint.h>
#include <sys.h> #include <sys.h>
#ifndef MOD_H #ifndef MOD_H
#define MOD_H #define MOD_H
// Максимальное количество модулей 16. Позже перепишем на динамический массив, #define EI_MAG0 0
// сейчас для прототипа это не так важно #define ELFMAG0 0x7f
#define MOD_MAX 16 #define EI_MAG1 1
#define ELFMAG1 'E'
#define EI_MAG2 2
#define ELFMAG2 'L'
#define EI_MAG3 3
#define ELFMAG3 'F'
#define SHT_SYMTAB 2
typedef uint64_t elf64_addr_t; // Адрес
typedef uint64_t elf64_offset_t; // Смещение
typedef uint64_t elf64_xword_t; // Целочисленное длинное слово без знака
typedef uint64_t elf64_sxword_t; // Целочисленное длинное слово с знаком
typedef uint32_t elf64_word_t; // Целочисленное слово без знака
typedef uint32_t elf64_sword_t; // Целочисленное слово с знаком
typedef uint16_t elf64_half_t; // Среднее целое число без знака
typedef uint8_t elf64_small_t; // Малое целое число без знака
// Структуры соответствующие ELF заголовкам
typedef struct { typedef struct {
unsigned char e_ident[16]; elf64_small_t e_ident[16]; // Идентификация ELF
uint16_t e_type; elf64_half_t e_type; // Тип объектного файла
uint16_t e_machine; elf64_half_t e_machine; // Тип компьютера
uint32_t e_version; elf64_word_t e_version; // Версия объектного файла
uint64_t e_entry; elf64_addr_t e_entry; // Адрес точки входа
uint64_t e_phoff; elf64_offset_t e_phoff; // Смещение заголовка программы
uint64_t e_shoff; elf64_offset_t e_shoff; // Смещение заголовка раздела
uint32_t e_flags; elf64_word_t e_flags; // Флаги, зависящие от процессора
uint16_t e_ehsize; elf64_half_t e_ehsize; // Размер заголовка ELF
uint16_t e_phentsize; elf64_half_t e_phentsize; // Размер записи заголовка программы
uint16_t e_phnum; elf64_half_t e_phnum; // Количество записей в заголовке программы
uint16_t e_shentsize; elf64_half_t e_shentsize; // Размер записи в заголовке раздела
uint16_t e_shnum; elf64_half_t e_shnum; // Количество записей в заголовке раздела
uint16_t e_shstrndx; elf64_half_t e_shstrndx; // Строковый табличный индекс названия раздела
} elf64_header_t; } elf64_header_t;
typedef struct {
elf64_word_t sh_name; // Название раздела
elf64_word_t sh_type; // Тип раздела
elf64_xword_t sh_flags; // Атрибуты раздела
elf64_addr_t sh_addr; // Виртуальный адрес в памяти
elf64_offset_t sh_offset; // Смещение в файле
elf64_xword_t sh_size; // Размер раздела
elf64_word_t sh_link; // Ссылка на другой раздел
elf64_word_t sh_info; // Дополнительная информация
elf64_xword_t sh_addralign; // Граница выравнивания адреса
elf64_xword_t sh_entsize; // Размер записей, если в разделе есть таблица
} elf64_section_header_t;
typedef struct {
elf64_addr_t r_offset; // Адрес ссылки
elf64_xword_t r_info; // Индекс символа и тип перемещения
} elf64_rel_t;
typedef struct {
elf64_addr_t r_offset; // Адрес ссылки
elf64_xword_t r_info; // Индекс символа и тип перемещения
elf64_sxword_t r_addend; // Постоянная часть выражения
} elf64_rela_t;
typedef struct {
elf64_word_t p_type; // Тип сегмента
elf64_word_t p_flags; // Атрибуты сегмента
elf64_offset_t p_offset; // Смещение в файле
elf64_addr_t p_vaddr; // Виртуальный адрес в памяти
elf64_addr_t p_paddr; // Зарезервирован
elf64_xword_t p_filesz; // Размер сегмента в файле
elf64_xword_t p_memsz; // Размер сегмента в памяти
elf64_xword_t p_align; // Выравнивание сегмента
} elf64_phdr_t;
typedef struct {
elf64_word_t st_name; // Название символа
elf64_small_t st_info; // Тип и атрибуты привязки
elf64_small_t st_other; // Зарезервировано
elf64_half_t st_shndx; // Индекс таблицы разделов
elf64_addr_t st_value; // Значение символа
elf64_xword_t st_size; // Размер объекта (например, общий)
} elf64_sym_t;
typedef struct {
elf64_sxword_t d_tag; // Тип динамического элемента
union {
elf64_xword_t d_val; // Значение динамического элемента
elf64_addr_t d_ptr; // Указатель динамического элемента
} d_un;
} elf64_dyn_t;
void mod_init( ); void mod_init( );
void mod_after_init( ); void mod_after_init( );
void mod_list_show( ); void mod_list_show( );
module_info_t *mod_find(char *tag); module_info_t *mod_find(char *tag);
module_info_t *mod_list_get(uint64_t *count); module_info_t *mod_list_get(uint64_t *count);
void *elf_entry(void *module_bin);
void *elf_parse(elf64_header_t *head);
#endif // mod.h #endif // mod.h

View File

@ -1,3 +1,3 @@
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_BUILD 57 #define VERSION_BUILD 58

116
kernel/elf.c Normal file
View File

@ -0,0 +1,116 @@
/**
* elf.c
* Функции работы с ELF64
*
* Инструменты для парсинга и анализа ELF файлов
*
*/
#include <mod.h>
#include <stdint.h>
elf64_header_t *elf64_get_header(void *data) {
return (elf64_header_t *)(data);
}
static inline elf64_section_header_t *elf64_sheader(elf64_header_t *hdr) {
return (elf64_section_header_t *)((elf64_addr_t)hdr + hdr->e_shoff);
}
static inline elf64_section_header_t *elf64_section(elf64_header_t *hdr, elf64_offset_t idx) {
return &elf64_sheader(hdr)[idx];
}
static inline char *elf64_str_table(elf64_header_t *hdr) {
if (hdr->e_shstrndx == 0x0) return NULL;
return (char *)hdr + elf64_section(hdr, hdr->e_shstrndx)->sh_offset;
}
static inline char *elf64_lookup_string(elf64_header_t *hdr, elf64_offset_t offset) {
char *strtab = elf64_str_table(hdr);
if (strtab == NULL) return NULL;
return strtab + offset;
}
static elf64_sym_t *elf64_get_symval(elf64_header_t *hdr, elf64_offset_t table, elf64_offset_t idx) {
if (table == 0 || idx == 0) return 0;
elf64_section_header_t *symtab = elf64_section(hdr, table);
uint32_t symtab_entries = symtab->sh_size / symtab->sh_entsize;
if (idx >= symtab_entries) {
LOG("Индекс символа вне допустимых пределов (%u:%u).\n", table, idx);
return NULL;
}
uintptr_t symaddr = (uint64_t)hdr + symtab->sh_offset;
return (elf64_sym_t *)&((elf64_sym_t *)symaddr)[idx];
}
unsigned long elf64_hash(unsigned char *name) {
unsigned long h = 0, g;
// Вычисление хэша
while (*name) {
h = (h << 4) + *name++;
// Проверка на overflow
if (g = h & 0xf0000000) h ^= g >> 24;
// Ограничение хэша
h &= 0xffffffff;
}
return h;
}
// Получение адреса точки входа
void *elf_entry(void *module_bin) {
// Приводим заголовок ELF файла к типу elf64_header_t
elf64_header_t *elf_header = (elf64_header_t *)module_bin;
LOG("(uint64_t)elf_header->e_entry = 0x%x, тип = %u\n", (uint64_t)elf_header->e_entry, elf_header->e_type);
if (elf_header->e_type != 2) {
LOG("\t\tОшибка! Модуль неправильно собран!\n");
for (;;) { asm volatile("pause"); }
}
elf_parse((elf64_header_t *)module_bin);
// Возвращаем указатель на точку входа
return (void *)((uint64_t)elf_header->e_entry + (uint64_t)module_bin);
}
void *elf_parse(elf64_header_t *head) {
elf64_section_header_t *symtab = NULL;
if (head->e_ident[0] != ELFMAG0 || head->e_ident[1] != ELFMAG1 || head->e_ident[2] != ELFMAG2 ||
head->e_ident[3] != ELFMAG3) {
LOG("Ошибка: Неправильный формат!\n");
return -1;
}
LOG("Точка входа: 0x%x\n", head->e_entry);
elf64_section_header_t *symtab_section = NULL;
char *string_table = NULL;
for (int i = 0; i < head->e_shnum; i++) {
elf64_section_header_t *shdr = elf64_section(head, i);
if (shdr->sh_type == SHT_SYMTAB) {
symtab_section = shdr;
elf64_section_header_t *strtab_section = elf64_section(head, shdr->sh_link);
string_table = (char *)head + strtab_section->sh_offset;
break;
}
}
if (symtab_section && string_table) {
LOG("\nТаблица символов:\n");
LOG("%s %s %s %s\n", "Индекс", "Значение", "Размер", "Наименование");
int num_symbols = symtab_section->sh_size / symtab_section->sh_entsize;
for (int i = 0; i < num_symbols; i++) {
elf64_sym_t *sym = elf64_get_symval(head, symtab_section - elf64_sheader(head), i);
if (sym) { LOG("%6u %8x %6x %s\n", i, sym->st_value, sym->st_size, string_table + sym->st_name); }
}
} else {
LOG("Таблица символов не найдена!\n");
}
return (void *)0;
}

View File

@ -29,22 +29,6 @@ static env_t main_env;
void *bootpng_ptr; void *bootpng_ptr;
uint64_t bootpng_size; uint64_t bootpng_size;
// Получение адреса точки входа
static void *elf_entry(elf64_header_t *module_bin) {
// Приводим заголовок ELF файла к типу elf64_header_t
elf64_header_t *elf_header = (elf64_header_t *)module_bin;
LOG("(uint64_t)elf_header->e_entry = 0x%x, тип = %u\n", (uint64_t)elf_header->e_entry, elf_header->e_type);
if (elf_header->e_type != 2) {
LOG("\t\tОшибка! Модуль неправильно собран!\n");
for (;;) { asm volatile("pause"); }
}
// Возвращаем указатель на точку входа
return (void *)((uint64_t)elf_header->e_entry + (uint64_t)module_bin);
}
// Вывод списка модулей в отладчик // Вывод списка модулей в отладчик
void mod_list_show( ) { void mod_list_show( ) {
for (uint64_t i = 0; i < modules_count; i++) { for (uint64_t i = 0; i < modules_count; i++) {
@ -133,8 +117,7 @@ void mod_init( ) {
continue; continue;
} }
module_info_t (*module_init)(env_t *env) = module_info_t (*module_init)(env_t *env) = (module_info_t(*)(env_t * env)) elf_entry(module_ptr->address);
(module_info_t(*)(env_t * env)) elf_entry((elf64_header_t *)module_ptr->address);
// LOG("\t->Точка входа: 0x%x\n", module_init); // LOG("\t->Точка входа: 0x%x\n", module_init);