From 40c1604109962cd34cb527bde071a29e1a40c1c1 Mon Sep 17 00:00:00 2001 From: Aren Date: Thu, 25 Apr 2024 19:46:03 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D1=80=D0=B0=D0=B7=D0=B1=D0=BE=D1=80=20ELF=20=D1=84?= =?UTF-8?q?=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mod.h | 108 +++++++++++++++++++++++++++++++++++------- include/version.h | 2 +- kernel/elf.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++ kernel/mod.c | 19 +------- 4 files changed, 208 insertions(+), 37 deletions(-) create mode 100644 kernel/elf.c diff --git a/include/mod.h b/include/mod.h index 186085e..402e48a 100644 --- a/include/mod.h +++ b/include/mod.h @@ -7,37 +7,109 @@ * */ +#include +#include +#include #include #ifndef MOD_H #define MOD_H -// Максимальное количество модулей 16. Позже перепишем на динамический массив, -// сейчас для прототипа это не так важно -#define MOD_MAX 16 +#define EI_MAG0 0 +#define ELFMAG0 0x7f +#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 { - unsigned char e_ident[16]; - uint16_t e_type; - uint16_t e_machine; - uint32_t e_version; - uint64_t e_entry; - uint64_t e_phoff; - uint64_t e_shoff; - uint32_t e_flags; - uint16_t e_ehsize; - uint16_t e_phentsize; - uint16_t e_phnum; - uint16_t e_shentsize; - uint16_t e_shnum; - uint16_t e_shstrndx; + elf64_small_t e_ident[16]; // Идентификация ELF + elf64_half_t e_type; // Тип объектного файла + elf64_half_t e_machine; // Тип компьютера + elf64_word_t e_version; // Версия объектного файла + elf64_addr_t e_entry; // Адрес точки входа + elf64_offset_t e_phoff; // Смещение заголовка программы + elf64_offset_t e_shoff; // Смещение заголовка раздела + elf64_word_t e_flags; // Флаги, зависящие от процессора + elf64_half_t e_ehsize; // Размер заголовка ELF + elf64_half_t e_phentsize; // Размер записи заголовка программы + elf64_half_t e_phnum; // Количество записей в заголовке программы + elf64_half_t e_shentsize; // Размер записи в заголовке раздела + elf64_half_t e_shnum; // Количество записей в заголовке раздела + elf64_half_t e_shstrndx; // Строковый табличный индекс названия раздела } 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_after_init( ); void mod_list_show( ); module_info_t *mod_find(char *tag); 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 \ No newline at end of file diff --git a/include/version.h b/include/version.h index b843d1c..5807446 100644 --- a/include/version.h +++ b/include/version.h @@ -1,3 +1,3 @@ #define VERSION_MAJOR 0 #define VERSION_MINOR 2 -#define VERSION_BUILD 57 +#define VERSION_BUILD 58 diff --git a/kernel/elf.c b/kernel/elf.c new file mode 100644 index 0000000..a1328e1 --- /dev/null +++ b/kernel/elf.c @@ -0,0 +1,116 @@ +/** + * elf.c + * Функции работы с ELF64 + * + * Инструменты для парсинга и анализа ELF файлов + * + */ + +#include +#include + +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; +} \ No newline at end of file diff --git a/kernel/mod.c b/kernel/mod.c index fb08d1f..ca2ba6c 100644 --- a/kernel/mod.c +++ b/kernel/mod.c @@ -29,22 +29,6 @@ static env_t main_env; void *bootpng_ptr; 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( ) { for (uint64_t i = 0; i < modules_count; i++) { @@ -133,8 +117,7 @@ void mod_init( ) { continue; } - module_info_t (*module_init)(env_t *env) = - (module_info_t(*)(env_t * env)) elf_entry((elf64_header_t *)module_ptr->address); + module_info_t (*module_init)(env_t *env) = (module_info_t(*)(env_t * env)) elf_entry(module_ptr->address); // LOG("\t->Точка входа: 0x%x\n", module_init);