elf: supporting R_386_PC32 relocation type
[quarnos.git] / modules / elf.cpp
blob7137c356d14e1cfab3010c4cb1ba7c0fb7a5cda5
1 /**
2 * @file elf.cpp
3 * ELF files loader
4 */
6 #include "loader.h"
7 #include "manes/manec.h"
9 #include "resources/fat.h"
11 typedef unsigned int Elf32_Addr;
12 typedef unsigned short Elf32_Half;
13 typedef unsigned int Elf32_Off;
14 typedef signed int Elf32_Sword;
15 typedef unsigned int Elf32_Word;
17 #define PT_DYNAMIC 2
19 #define DT_PLTRELSZ 2
20 #define DT_SYMTAB 6
21 #define DT_REL 17
22 #define DT_JMPREL 23
23 #define DT_RELSZ 18
24 #define DT_RELENT 19
26 typedef struct {
27 Elf32_Word p_type;
28 Elf32_Off p_offset;
29 Elf32_Addr p_vaddr;
30 Elf32_Addr p_paddr;
31 Elf32_Word p_filesz;
32 Elf32_Word p_memsz;
33 Elf32_Word p_flags;
34 Elf32_Word p_align;
35 } Elf32_Phdr;
37 typedef struct {
38 Elf32_Word sh_name;
39 Elf32_Word sh_type;
40 Elf32_Word sh_flags;
41 Elf32_Addr sh_addr;
42 Elf32_Off sh_offset;
43 Elf32_Word sh_size;
44 Elf32_Word sh_link;
45 Elf32_Word sh_info;
46 Elf32_Word sh_addralign;
47 Elf32_Word sh_entsize;
48 } Elf32_Shdr;
50 typedef struct {
51 Elf32_Sword d_tag;
52 union {
53 Elf32_Word d_val;
54 Elf32_Addr d_ptr;
55 } d_un;
56 } Elf32_Dyn;
58 typedef struct {
59 Elf32_Addr r_offset;
60 Elf32_Word r_info;
61 } Elf32_Rel;
63 #define R_386_32 1
64 #define R_386_PC32 2
65 #define R_386_GLOB_DAT 6
66 #define R_386_JMP_SLOT 7
68 typedef struct {
69 Elf32_Word st_name;
70 Elf32_Addr st_value;
71 Elf32_Word st_size;
72 unsigned char st_info;
73 unsigned char st_other;
74 Elf32_Half st_shndx;
75 } Elf32_Sym;
77 #define ELF32_R_SYM(i) ((i)>>8)
78 #define ELF32_R_TYPE(i) ((unsigned char)(i))
79 #define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t))
81 struct Elf32_DynLinker {
82 void* AT_PHDR;
83 void* AT_PHENT;
84 void* AT_PHNUM;
85 void* AT_ENTRY;
86 void* AT_BASE;
89 #define ELF_NIDENT 16
90 /**
91 * ELF program header
93 typedef struct {
94 unsigned char e_ident[ELF_NIDENT]; /**< magic number */
95 Elf32_Half e_type; /**< type of elf file */
96 Elf32_Half e_machine; /**< hardware architecture */
97 Elf32_Word e_version; /**< version of elf */
98 Elf32_Addr e_entry; /**< entry point */
99 Elf32_Off e_phoff; /**< offset of first program header */
100 Elf32_Off e_shoff; /**< offset of first section header */
101 Elf32_Word e_flags; /**< flags */
102 Elf32_Half e_ehsize;
103 Elf32_Half e_phentsize;
104 Elf32_Half e_phnum;
105 Elf32_Half e_shentsize;
106 Elf32_Half e_shnum;
107 Elf32_Half e_shstrndx;
108 } Elf32_Ehdr;
110 modules::loader::module_entry load_dynamic_elf(const char *prog) {
111 char *buffer = new char[0x1000 * 10];
112 Elf32_Ehdr *header = (Elf32_Ehdr*)buffer;
113 int offset = (int)buffer;
115 /* Load file */
116 resources::fs *fs_floppy = manes::manec::get()->get_component(manes::component_name((manes::type_name)"fat",0))->get<resources::fs>();
117 fs_floppy->load_file(prog, buffer);
119 /* RELPTL (relocation table) [0x17] has to be filled with names addresses */
120 /* They are stored in DYNSYM (symbol table) [6] */
121 /* RELPTL and DYNSYM addresses are in dynamic section */
123 Elf32_Phdr *segments = (Elf32_Phdr*)((int)header->e_phoff + offset);
125 /* Find dynamic segment in program */
126 Elf32_Dyn *dynamic_s = (Elf32_Dyn*)0;
127 for (int i = 0; i < header->e_phnum; i++)
128 if (segments[i].p_type == PT_DYNAMIC)
129 dynamic_s = (Elf32_Dyn*)(segments[i].p_offset + offset);
131 /* Find relocation and symbol tables (sections) */
132 /* Checking for broken ELF files */
133 Elf32_Rel *reldyn_t = 0, *relplt_t = 0;
134 int reldyn_size = 0, relplt_size = 0, rel_esize = 0, reldyn_ent = 0, relplt_ent = 0;
135 Elf32_Sym *symbol_t = 0;
136 for (int i = 0; dynamic_s[i].d_tag; i++) {
137 switch (dynamic_s[i].d_tag) {
138 case DT_SYMTAB : symbol_t = (Elf32_Sym*)(dynamic_s[i].d_un.d_val + offset); break;
139 case DT_REL : reldyn_t = (Elf32_Rel*)(dynamic_s[i].d_un.d_val + offset); break;
140 case DT_JMPREL : relplt_t = (Elf32_Rel*)(dynamic_s[i].d_un.d_val + offset); break;
141 case DT_RELENT : rel_esize = dynamic_s[i].d_un.d_val; break;
142 case DT_RELSZ : reldyn_size = dynamic_s[i].d_un.d_val; break;
143 case DT_PLTRELSZ : relplt_size = dynamic_s[i].d_un.d_val; break;
147 /* Fill offsets in REL (global variables) */
148 reldyn_ent = reldyn_size / rel_esize;
149 for (int i = 0; i < reldyn_ent; i++) {
150 u32 *record = (u32*)(reldyn_t[i].r_offset + offset);
151 switch (ELF32_R_TYPE(reldyn_t[i].r_info)) {
152 case R_386_PC32:
153 *record += symbol_t[ELF32_R_SYM(reldyn_t[i].r_info)].st_value + offset - (u32)record;
154 break;
155 case R_386_32:
156 default:
157 *record += symbol_t[ELF32_R_SYM(reldyn_t[i].r_info)].st_value + offset;
161 /* Fill offsets in RELPLT (procedures and functions) */
162 relplt_ent = relplt_size / rel_esize;
163 for (int i = 0; i < relplt_ent; i++) {
164 u32 *record = (u32*)(relplt_t[i].r_offset + offset);
165 switch (ELF32_R_TYPE(relplt_t[i].r_info)) {
166 case R_386_PC32:
167 *record = symbol_t[ELF32_R_SYM(relplt_t[i].r_info)].st_value + offset - (u32)record;
168 break;
169 case R_386_32:
170 default:
171 *record = symbol_t[ELF32_R_SYM(relplt_t[i].r_info)].st_value + offset;
175 /* Return entry point */
176 return (modules::loader::module_entry)(header->e_entry + offset);