usb: mass storage class implementation stub, set_configuration request
[quarnos.git] / modules / elf.cpp
blobd517706eb4b2e847100aed82aed5724b70e7b0a2
1 /* Quarn OS
3 * ELF files loader and dynamic linker
5 * Copyright (C) 2008-2009 Pawel Dziepak
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 /**
24 * @file elf.cpp
25 * ELF files loader
28 #include "loader.h"
29 #include "manes/manec.h"
30 #include "elf.h"
32 #include "resources/fat.h"
34 #define KERNEL_ELF 0x200000
36 /* Types defined in ELF sepcification */
37 typedef unsigned int Elf32_Addr;
38 typedef unsigned short Elf32_Half;
39 typedef unsigned int Elf32_Off;
40 typedef signed int Elf32_Sword;
41 typedef unsigned int Elf32_Word;
43 #define PT_DYNAMIC 2
45 #define SHT_SYMTAB 2
46 #define SHT_STRTAB 3
47 #define SHT_X86_UNWIND 0
49 #define DT_PLTRELSZ 2
50 #define DT_STRTAB 5
51 #define DT_SYMTAB 6
52 #define DT_REL 17
53 #define DT_JMPREL 23
54 #define DT_RELSZ 18
55 #define DT_RELENT 19
57 #define STB_GLOBAL 1
59 /**
60 * Program header
62 typedef struct {
63 Elf32_Word p_type;
64 Elf32_Off p_offset;
65 Elf32_Addr p_vaddr;
66 Elf32_Addr p_paddr;
67 Elf32_Word p_filesz;
68 Elf32_Word p_memsz;
69 Elf32_Word p_flags;
70 Elf32_Word p_align;
71 } Elf32_Phdr;
73 /**
74 * Section header
76 typedef struct {
77 Elf32_Word sh_name;
78 Elf32_Word sh_type;
79 Elf32_Word sh_flags;
80 Elf32_Addr sh_addr;
81 Elf32_Off sh_offset;
82 Elf32_Word sh_size;
83 Elf32_Word sh_link;
84 Elf32_Word sh_info;
85 Elf32_Word sh_addralign;
86 Elf32_Word sh_entsize;
87 } Elf32_Shdr;
89 /**
90 * Dynamic table record
92 typedef struct {
93 Elf32_Sword d_tag;
94 union {
95 Elf32_Word d_val;
96 Elf32_Addr d_ptr;
97 } d_un;
98 } Elf32_Dyn;
101 * Relocation information structure
103 typedef struct {
104 Elf32_Addr r_offset;
105 Elf32_Word r_info;
106 } Elf32_Rel;
108 #define R_386_32 1
109 #define R_386_PC32 2
110 #define R_386_GLOB_DAT 6
111 #define R_386_JMP_SLOT 7
112 #define R_386_RELATIVE 8
115 * Dynamic symbol structure
117 typedef struct {
118 Elf32_Word st_name;
119 Elf32_Addr st_value;
120 Elf32_Word st_size;
121 unsigned char st_info;
122 unsigned char st_other;
123 Elf32_Half st_shndx;
124 } Elf32_Sym;
126 #define ELF32_ST_BIND(i) ((i)>>4)
128 #define ELF32_R_SYM(i) ((i)>>8)
129 #define ELF32_R_TYPE(i) ((unsigned char)(i))
130 #define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t))
132 struct Elf32_DynLinker {
133 void* AT_PHDR;
134 void* AT_PHENT;
135 void* AT_PHNUM;
136 void* AT_ENTRY;
137 void* AT_BASE;
140 #define ELF_NIDENT 16
142 * ELF program header
144 typedef struct {
145 unsigned char e_ident[ELF_NIDENT]; /**< magic number */
146 Elf32_Half e_type; /**< type of elf file */
147 Elf32_Half e_machine; /**< hardware architecture */
148 Elf32_Word e_version; /**< version of elf */
149 Elf32_Addr e_entry; /**< entry point */
150 Elf32_Off e_phoff; /**< offset of first program header */
151 Elf32_Off e_shoff; /**< offset of first section header */
152 Elf32_Word e_flags; /**< flags */
153 Elf32_Half e_ehsize;
154 Elf32_Half e_phentsize;
155 Elf32_Half e_phnum;
156 Elf32_Half e_shentsize;
157 Elf32_Half e_shnum;
158 Elf32_Half e_shstrndx;
159 } Elf32_Ehdr;
161 void *get_eh_frame() {
162 extern void *_eh_frame;
163 void *eh_frame = (void*)&_eh_frame;
164 return eh_frame;
167 Elf32_Sym *quarn_symbols() {
168 Elf32_Ehdr *ehdr = (Elf32_Ehdr*)KERNEL_ELF;
169 Elf32_Shdr *sections = (Elf32_Shdr*)(ehdr->e_shoff + KERNEL_ELF);
171 for (short i = 0; i <= ehdr->e_shnum; i++)
172 if (sections[i].sh_type == SHT_SYMTAB)
173 return (Elf32_Sym*)(sections[i].sh_offset + KERNEL_ELF);
175 critical("elf: kernel symbols table not found");
176 return (Elf32_Sym*)0;
179 int quarn_symnum() {
180 Elf32_Ehdr *ehdr = (Elf32_Ehdr*)KERNEL_ELF;
181 Elf32_Shdr *sections = (Elf32_Shdr*)(ehdr->e_shoff + KERNEL_ELF);
183 for (short i = 0; i <= ehdr->e_shnum; i++)
184 if (sections[i].sh_type == SHT_SYMTAB)
185 return sections[i].sh_size / sizeof(Elf32_Sym);
187 critical("elf: kernel symbols table not found");
188 return 0;
191 char *quarn_strings() {
192 Elf32_Ehdr *ehdr = (Elf32_Ehdr*)KERNEL_ELF;
193 Elf32_Shdr str = ((Elf32_Shdr*)(ehdr->e_shoff + KERNEL_ELF))[ehdr->e_shstrndx + 2];
194 return (char*)(str.sh_offset + KERNEL_ELF);
197 extern "C" int get_symbol_size(void *symbol) {
198 int kern_symnum = quarn_symnum();
199 Elf32_Sym *kern_sym = quarn_symbols();
201 for (int i = 0; i < kern_symnum; i++)
202 if (kern_sym[i].st_value == (Elf32_Word)symbol && kern_sym[i].st_size)
203 return kern_sym[i].st_size;
205 return 0;
207 typedef unsigned int cpu_word;
208 modules::loader::module_entry load_dynamic_elf(const string &prog) {
209 p<resources::file> fp = manes::manec::get()->get<resources::file>((string)"/file," + prog);
210 char *buf = reinterpret_cast<char*>(fp->get_buffer().get_address());
211 Elf32_Ehdr *header = (Elf32_Ehdr*)buf;
212 cpu_word offset = reinterpret_cast<cpu_word>(buf);
214 /* RELPTL (relocation table) [0x17] has to be filled with names addresses */
215 /* They are stored in DYNSYM (symbol table) [6] */
216 /* RELPTL and DYNSYM addresses are in dynamic section */
218 Elf32_Phdr *segments = (Elf32_Phdr*)((int)header->e_phoff + offset);
220 /* Find dynamic segment in program */
221 Elf32_Dyn *dynamic_s = (Elf32_Dyn*)0;
222 for (int i = 0; i < header->e_phnum; i++)
223 if (segments[i].p_type == PT_DYNAMIC)
224 dynamic_s = (Elf32_Dyn*)(segments[i].p_offset + offset);
226 /* Find Quarn symbol table */
227 int kern_symnum = quarn_symnum();
228 Elf32_Sym *kern_sym = quarn_symbols();
229 char *kern_str = quarn_strings();
231 /* Find relocation and symbol tables (sections) */
232 /* Checking for broken ELF files */
233 Elf32_Rel *reldyn_t = 0, *relplt_t = 0;
234 int reldyn_size = 0, relplt_size = 0, rel_esize = 0, reldyn_ent = 0, relplt_ent = 0;
235 Elf32_Sym *symbol_t = 0;
236 char *mod_str = 0;
237 for (int i = 0; dynamic_s[i].d_tag; i++) {
238 switch (dynamic_s[i].d_tag) {
239 case DT_STRTAB : mod_str = (char*)(dynamic_s[i].d_un.d_val + offset); break;
240 case DT_SYMTAB : symbol_t = (Elf32_Sym*)(dynamic_s[i].d_un.d_val + offset); break;
241 case DT_REL : reldyn_t = (Elf32_Rel*)(dynamic_s[i].d_un.d_val + offset); break;
242 case DT_JMPREL : relplt_t = (Elf32_Rel*)(dynamic_s[i].d_un.d_val + offset); break;
243 case DT_RELENT : rel_esize = dynamic_s[i].d_un.d_val; break;
244 case DT_RELSZ : reldyn_size = dynamic_s[i].d_un.d_val; break;
245 case DT_PLTRELSZ : relplt_size = dynamic_s[i].d_un.d_val; break;
250 * FIXME: code reuse!
253 /* Fill offsets in REL (global variables) */
254 reldyn_ent = reldyn_size / rel_esize;
255 for (int i = 0; i < reldyn_ent; i++) {
256 u32 *record = (u32*)(reldyn_t[i].r_offset + offset);
257 if (ELF32_R_TYPE(reldyn_t[i].r_info) == R_386_RELATIVE) {
258 *record += offset;
259 } else if (symbol_t[ELF32_R_SYM(reldyn_t[i].r_info)].st_shndx) {
260 switch (ELF32_R_TYPE(reldyn_t[i].r_info)) {
261 case R_386_PC32:
262 *record += symbol_t[ELF32_R_SYM(reldyn_t[i].r_info)].st_value + offset - (u32)record;
263 break;
264 case R_386_32:
265 *record += symbol_t[ELF32_R_SYM(reldyn_t[i].r_info)].st_value + offset;
266 break;
267 case R_386_GLOB_DAT:
268 *record = symbol_t[ELF32_R_SYM(reldyn_t[i].r_info)].st_value + offset;
269 break;
270 case R_386_RELATIVE:
271 *record += offset;
272 break;
273 default:
274 debug("elf: unknown relocation type");
276 } else {
277 for (int j = 0; j < kern_symnum; j++) {
278 if (!strcmp(&mod_str[symbol_t[ELF32_R_SYM(reldyn_t[i].r_info)].st_name], &kern_str[kern_sym[j].st_name])
279 && mod_str[symbol_t[ELF32_R_SYM(reldyn_t[i].r_info)].st_name]) {
280 switch (ELF32_R_TYPE(reldyn_t[i].r_info)) {
281 case R_386_PC32:
282 *record += kern_sym[j].st_value - (u32)record;
283 break;
284 case R_386_32:
285 *record += kern_sym[j].st_value;
286 break;
287 case R_386_GLOB_DAT:
288 *record = kern_sym[j].st_value;
289 break;
290 default:
291 debug("elf: unknown relocation type");
298 /* Fill offsets in RELPLT (procedures and functions) */
299 relplt_ent = relplt_size / rel_esize;
300 for (int i = 0; i < relplt_ent; i++) {
301 u32 *record = (u32*)(relplt_t[i].r_offset + offset);
302 if (symbol_t[ELF32_R_SYM(relplt_t[i].r_info)].st_shndx) {
303 if (record != 0)
304 __asm__("cli\nhlt"::"a"(record), "b"(symbol_t[ELF32_R_SYM(relplt_t[i].r_info)].st_value));
305 switch (ELF32_R_TYPE(relplt_t[i].r_info)) {
306 case R_386_PC32:
307 *record += symbol_t[ELF32_R_SYM(relplt_t[i].r_info)].st_value + offset - (u32)record;
308 break;
309 case R_386_32:
310 *record += symbol_t[ELF32_R_SYM(relplt_t[i].r_info)].st_value + offset;
311 break;
312 case R_386_JMP_SLOT:
313 *record = symbol_t[ELF32_R_SYM(relplt_t[i].r_info)].st_value + offset;
314 break;
315 default:
316 debug("elf: unknown relocation type");
318 } else {
319 for (int j = 0; j < kern_symnum; j++) {
320 if (!strcmp(&mod_str[symbol_t[ELF32_R_SYM(relplt_t[i].r_info)].st_name], &kern_str[kern_sym[j].st_name])
321 && mod_str[symbol_t[ELF32_R_SYM(relplt_t[i].r_info)].st_name]) {
322 u32 *record = (u32*)(relplt_t[i].r_offset + offset);
323 switch (ELF32_R_TYPE(relplt_t[i].r_info)) {
324 case R_386_PC32:
325 *record += kern_sym[j].st_value - (u32)record;
326 break;
327 case R_386_32:
328 *record += kern_sym[j].st_value;
329 break;
330 case R_386_JMP_SLOT:
331 *record = kern_sym[j].st_value;
332 break;
333 default:
334 debug("elf: unknown relocation type");
341 /* Return entry point */
342 return (modules::loader::module_entry)(header->e_entry + offset);
345 void modules::elf::load(const string &prog) {
346 enter_module = load_dynamic_elf(prog);
350 void modules::elf::register_type() {
351 manes::manec::get()->register_type<modules::elf>("elf", "module");