4 * Created on: Aug 11, 2008
5 * Author: Stefan Bucur <stefanb@zytor.com>
16 #include <linux/list.h>
17 #include <sys/module.h>
21 #include "../common.h"
25 * The implementation assumes that the loadable segments are present
26 * in the PHT sorted by their offsets, so that only forward seeks would
29 int load_segments(struct elf_module
*module
, Elf_Ehdr
*elf_hdr
) {
37 Elf32_Addr min_addr
= 0x00000000; // Min. ELF vaddr
38 Elf32_Addr max_addr
= 0x00000000; // Max. ELF vaddr
39 Elf32_Word max_align
= sizeof(void*); // Min. align of posix_memalign()
40 Elf32_Addr min_alloc
, max_alloc
; // Min. and max. aligned allocables
42 Elf32_Addr dyn_addr
= 0x00000000;
45 image_seek(elf_hdr
->e_phoff
, module
);
48 pht
= malloc(elf_hdr
->e_phnum
* elf_hdr
->e_phentsize
);
52 image_read(pht
, elf_hdr
->e_phnum
* elf_hdr
->e_phentsize
, module
);
54 // Compute the memory needings of the module
55 for (i
=0; i
< elf_hdr
->e_phnum
; i
++) {
56 cr_pht
= (Elf32_Phdr
*)(pht
+ i
* elf_hdr
->e_phentsize
);
58 switch (cr_pht
->p_type
) {
61 min_addr
= cr_pht
->p_vaddr
;
63 min_addr
= MIN(min_addr
, cr_pht
->p_vaddr
);
66 max_addr
= MAX(max_addr
, cr_pht
->p_vaddr
+ cr_pht
->p_memsz
);
67 max_align
= MAX(max_align
, cr_pht
->p_align
);
70 dyn_addr
= cr_pht
->p_vaddr
;
73 // Unsupported - ignore
78 if (max_addr
- min_addr
== 0) {
79 // No loadable segments
80 DBG_PRINT("No loadable segments found\n");
85 DBG_PRINT("No dynamic information segment found\n");
89 // The minimum address that should be allocated
90 min_alloc
= min_addr
- (min_addr
% max_align
);
92 // The maximum address that should be allocated
93 max_alloc
= max_addr
- (max_addr
% max_align
);
94 if (max_addr
% max_align
> 0)
95 max_alloc
+= max_align
;
98 if (elf_malloc(&module
->module_addr
,
100 max_alloc
-min_alloc
) != 0) {
102 DBG_PRINT("Could not allocate segments\n");
106 module
->base_addr
= (Elf32_Addr
)(module
->module_addr
) - min_alloc
;
107 module
->module_size
= max_alloc
- min_alloc
;
109 // Zero-initialize the memory
110 memset(module
->module_addr
, 0, module
->module_size
);
112 for (i
= 0; i
< elf_hdr
->e_phnum
; i
++) {
113 cr_pht
= (Elf32_Phdr
*)(pht
+ i
* elf_hdr
->e_phentsize
);
115 if (cr_pht
->p_type
== PT_LOAD
) {
116 // Copy the segment at its destination
117 if (cr_pht
->p_offset
< module
->u
.l
._cr_offset
) {
118 // The segment contains data before the current offset
119 // It can be discarded without worry - it would contain only
121 Elf32_Off aux_off
= module
->u
.l
._cr_offset
- cr_pht
->p_offset
;
123 if (image_read((char *)module_get_absolute(cr_pht
->p_vaddr
, module
) + aux_off
,
124 cr_pht
->p_filesz
- aux_off
, module
) < 0) {
129 if (image_seek(cr_pht
->p_offset
, module
) < 0) {
134 if (image_read(module_get_absolute(cr_pht
->p_vaddr
, module
),
135 cr_pht
->p_filesz
, module
) < 0) {
142 DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n",
145 (Elf32_Addr)module_get_absolute(cr_pht->p_vaddr, module));
151 image_seek(elf_hdr
->e_shoff
, module
);
154 sht
= malloc(elf_hdr
->e_shnum
* elf_hdr
->e_shentsize
);
160 image_read(sht
, elf_hdr
->e_shnum
* elf_hdr
->e_shentsize
, module
);
162 // Setup the symtable size
163 for (i
= 0; i
< elf_hdr
->e_shnum
; i
++) {
164 cr_sht
= (Elf32_Shdr
*)(sht
+ i
* elf_hdr
->e_shentsize
);
166 if (cr_sht
->sh_type
== SHT_DYNSYM
) {
167 module
->symtable_size
= cr_sht
->sh_size
;
174 // Setup dynamic segment location
175 module
->dyn_table
= module_get_absolute(dyn_addr
, module
);
178 DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr,
180 DBG_PRINT("Module size: 0x%08x\n", module->module_size);
184 // Free up allocated memory
191 int perform_relocation(struct elf_module
*module
, Elf_Rel
*rel
) {
192 Elf32_Word
*dest
= module_get_absolute(rel
->r_offset
, module
);
194 // The symbol reference index
195 Elf32_Word sym
= ELF32_R_SYM(rel
->r_info
);
196 unsigned char type
= ELF32_R_TYPE(rel
->r_info
);
198 // The symbol definition (if applicable)
199 Elf32_Sym
*sym_def
= NULL
;
200 struct elf_module
*sym_module
= NULL
;
201 Elf32_Addr sym_addr
= 0x0;
204 // Find out details about the symbol
206 // The symbol reference
207 Elf32_Sym
*sym_ref
= symbol_get_entry(module
, sym
);
209 // The symbol definition
211 global_find_symbol(module
->str_table
+ sym_ref
->st_name
,
214 if (sym_def
== NULL
) {
215 DBG_PRINT("Cannot perform relocation for symbol %s\n",
216 module
->str_table
+ sym_ref
->st_name
);
218 if (ELF32_ST_BIND(sym_ref
->st_info
) != STB_WEAK
)
221 // This must be a derivative-specific
222 // function. We're OK as long as we never
223 // execute the function.
224 sym_def
= global_find_symbol("undefined_symbol", &sym_module
);
227 // Compute the absolute symbol virtual address
228 sym_addr
= (Elf32_Addr
)module_get_absolute(sym_def
->st_value
, sym_module
);
230 if (sym_module
!= module
) {
231 // Create a dependency
232 enforce_dependency(sym_module
, module
);
244 *dest
+= sym_addr
- (Elf32_Addr
)dest
;
248 memcpy((void*)dest
, (void*)sym_addr
, sym_def
->st_size
);
253 // Maybe TODO: Keep track of the GOT entries allocations
257 *dest
+= module
->base_addr
;
260 DBG_PRINT("Relocation type %d not supported\n", type
);
267 int resolve_symbols(struct elf_module
*module
) {
268 Elf32_Dyn
*dyn_entry
= module
->dyn_table
;
272 Elf32_Word plt_rel_size
= 0;
273 char *plt_rel
= NULL
;
276 Elf32_Word rel_size
= 0;
277 Elf32_Word rel_entry
= 0;
279 // The current relocation
282 while (dyn_entry
->d_tag
!= DT_NULL
) {
283 switch(dyn_entry
->d_tag
) {
285 // PLT relocation information
287 plt_rel_size
= dyn_entry
->d_un
.d_val
;
290 if (dyn_entry
->d_un
.d_val
!= DT_REL
) {
291 DBG_PRINT("Unsupported PLT relocation\n");
295 plt_rel
= module_get_absolute(dyn_entry
->d_un
.d_ptr
, module
);
298 // Standard relocation information
300 rel
= module_get_absolute(dyn_entry
->d_un
.d_ptr
, module
);
303 rel_size
= dyn_entry
->d_un
.d_val
;
306 rel_entry
= dyn_entry
->d_un
.d_val
;
309 // Module initialization and termination
311 // TODO Implement initialization functions
314 // TODO Implement finalization functions
322 // Process standard relocations
323 for (i
= 0; i
< rel_size
/rel_entry
; i
++) {
324 crt_rel
= (Elf32_Rel
*)(rel
+ i
*rel_entry
);
326 res
= perform_relocation(module
, crt_rel
);
334 if (plt_rel_size
> 0) {
335 // TODO: Permit this lazily
336 // Process PLT relocations
337 for (i
= 0; i
< plt_rel_size
/sizeof(Elf32_Rel
); i
++) {
338 crt_rel
= (Elf32_Rel
*)(plt_rel
+ i
*sizeof(Elf32_Rel
));
340 res
= perform_relocation(module
, crt_rel
);