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.
29 #include "manes/manec.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
;
47 #define SHT_X86_UNWIND 0
85 Elf32_Word sh_addralign
;
86 Elf32_Word sh_entsize
;
90 * Dynamic table record
101 * Relocation information structure
110 #define R_386_GLOB_DAT 6
111 #define R_386_JMP_SLOT 7
112 #define R_386_RELATIVE 8
115 * Dynamic symbol structure
121 unsigned char st_info
;
122 unsigned char st_other
;
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
{
140 #define ELF_NIDENT 16
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 */
154 Elf32_Half e_phentsize
;
156 Elf32_Half e_shentsize
;
158 Elf32_Half e_shstrndx
;
161 void *get_eh_frame() {
162 extern void *_eh_frame
;
163 void *eh_frame
= (void*)&_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;
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");
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
;
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;
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;
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
) {
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
)) {
262 *record
+= symbol_t
[ELF32_R_SYM(reldyn_t
[i
].r_info
)].st_value
+ offset
- (u32
)record
;
265 *record
+= symbol_t
[ELF32_R_SYM(reldyn_t
[i
].r_info
)].st_value
+ offset
;
268 *record
= symbol_t
[ELF32_R_SYM(reldyn_t
[i
].r_info
)].st_value
+ offset
;
274 debug("elf: unknown relocation type");
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
)) {
282 *record
+= kern_sym
[j
].st_value
- (u32
)record
;
285 *record
+= kern_sym
[j
].st_value
;
288 *record
= kern_sym
[j
].st_value
;
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
) {
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
)) {
307 *record
+= symbol_t
[ELF32_R_SYM(relplt_t
[i
].r_info
)].st_value
+ offset
- (u32
)record
;
310 *record
+= symbol_t
[ELF32_R_SYM(relplt_t
[i
].r_info
)].st_value
+ offset
;
313 *record
= symbol_t
[ELF32_R_SYM(relplt_t
[i
].r_info
)].st_value
+ offset
;
316 debug("elf: unknown relocation type");
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
)) {
325 *record
+= kern_sym
[j
].st_value
- (u32
)record
;
328 *record
+= kern_sym
[j
].st_value
;
331 *record
= kern_sym
[j
].st_value
;
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");