User/Kernel - ARMv7 fixes (relocation of .text)
[tpg/acess2.git] / KernelLand / Kernel / bin / elf.c
1 /*\r
2  * Acess v0.1\r
3  * ELF Executable Loader Code\r
4  */\r
5 #define DEBUG   0\r
6 #include <acess.h>\r
7 #include <binary.h>\r
8 \r
9 #define _COMMON_H\r
10 #define SysDebug(v...)  LOG(v)\r
11 #if BITS <= 32\r
12 # define DISABLE_ELF64\r
13 #endif\r
14 static int      GetSymbol(const char *Name, void **Value, size_t *Size);\r
15 static int      GetSymbol(const char *Name, void **Value, size_t *Size) {\r
16         Uint val;\r
17         if(Binary_GetSymbol(Name, &val))\r
18                 return 0;\r
19         if(Size)\r
20                 *Size=0;\r
21         *Value = (void*)val;\r
22         return 1;\r
23 }\r
24 #define AddLoaded(a,b)  do{}while(0)\r
25 #define LoadLibrary(a,b,c)      (Log_Debug("ELF", "Module requested lib '%s'",a),0)\r
26 #define SysSetMemFlags(ad,f,m)  do{}while(0)\r
27 #include "../../../Usermode/Libraries/ld-acess.so_src/elf.c"\r
28 \r
29 #define DEBUG_WARN      1\r
30 \r
31 // === PROTOTYPES ===\r
32 tBinary *Elf_Load(int fp);\r
33 tBinary *Elf_Load64(int fp, Elf64_Ehdr *hdr);\r
34 tBinary *Elf_Load32(int fp, Elf32_Ehdr *hdr);\r
35  int    Elf_Relocate(void *Base);\r
36  int    Elf_GetSymbol(void *Base, const char *Name, Uint *Ret);\r
37 Uint    Elf_Int_HashString(const char *str);\r
38 \r
39 // === GLOBALS ===\r
40 tBinaryType     gELF_Info = {\r
41         NULL,\r
42         0x464C457F, 0xFFFFFFFF, // '\x7FELF'\r
43         "ELF",\r
44         Elf_Load, Elf_Relocate, Elf_GetSymbol\r
45         };\r
46 \r
47 // === CODE ===\r
48 tBinary *Elf_Load(int fp)\r
49 {\r
50         Elf64_Ehdr      hdr;\r
51         \r
52         // Read ELF Header\r
53         VFS_Read(fp, sizeof(hdr), &hdr);\r
54         \r
55         // Check the file type\r
56         if(hdr.e_ident[0] != 0x7F || hdr.e_ident[1] != 'E' || hdr.e_ident[2] != 'L' || hdr.e_ident[3] != 'F') {\r
57                 Log_Warning("ELF", "Non-ELF File was passed to the ELF loader");\r
58                 return NULL;\r
59         }\r
60 \r
61         switch(hdr.e_ident[4])  // EI_CLASS\r
62         {\r
63         case ELFCLASS32:\r
64                 return Elf_Load32(fp, (void*)&hdr);\r
65         case ELFCLASS64:\r
66                 return Elf_Load64(fp, &hdr);\r
67         default:\r
68                 Log_Warning("ELF", "Unknown EI_CLASS value %i", hdr.e_ident[4]);\r
69                 return NULL;\r
70         }\r
71 }\r
72 \r
73 tBinary *Elf_Load64(int FD, Elf64_Ehdr *Header)\r
74 {\r
75         tBinary *ret;\r
76         Elf64_Phdr      phtab[Header->e_phnum];\r
77          int    nLoadSegments;\r
78          int    i, j;\r
79         \r
80         // Sanity check\r
81         if( Header->e_phoff == 0 )\r
82         {\r
83                 Log_Warning("ELF", "No program header, panic!");\r
84                 return NULL;\r
85         }\r
86         if( Header->e_shentsize != sizeof(Elf64_Shdr) ) {\r
87                 Log_Warning("ELF", "Header gives shentsize as %i, my type is %i",\r
88                         Header->e_shentsize, sizeof(Elf64_Shdr) );\r
89         }\r
90         if( Header->e_phentsize != sizeof(Elf64_Phdr) ) {\r
91                 Log_Warning("ELF", "Header gives phentsize as %i, my type is %i",\r
92                         Header->e_phentsize, sizeof(Elf64_Phdr) );\r
93         }\r
94 \r
95         LOG("Header = {");\r
96         LOG("  e_ident = %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",\r
97                 Header->e_ident[0], Header->e_ident[1], Header->e_ident[2], Header->e_ident[3],\r
98                 Header->e_ident[4], Header->e_ident[5], Header->e_ident[6], Header->e_ident[7],\r
99                 Header->e_ident[8], Header->e_ident[9], Header->e_ident[10], Header->e_ident[11],\r
100                 Header->e_ident[12], Header->e_ident[13], Header->e_ident[14], Header->e_ident[15]\r
101                 );\r
102         LOG("  e_type = %i", Header->e_type);\r
103         LOG("  e_machine = %i", Header->e_machine);\r
104         LOG("  e_version = %i", Header->e_version);\r
105         LOG("  e_entry   = 0x%llx", Header->e_entry);\r
106         LOG("  e_phoff   = 0x%llx", Header->e_phoff);\r
107         LOG("  e_shoff   = 0x%llx", Header->e_shoff);\r
108         LOG("  e_flags   = 0x%x", Header->e_flags);\r
109         LOG("  e_ehsize  = %i", Header->e_ehsize);\r
110         LOG("  e_phentsize = %i", Header->e_phentsize);\r
111         LOG("  e_phnum   = %i", Header->e_phnum);\r
112         LOG("  e_shentsize = %i", Header->e_shentsize);\r
113         LOG("  e_shnum   = %i", Header->e_shnum);\r
114         LOG("  e_shstrndx = %i", Header->e_shstrndx);\r
115         LOG("}");\r
116 \r
117         // Load Program Header table\r
118         VFS_Seek(FD, Header->e_phoff, SEEK_SET);\r
119         VFS_Read(FD, sizeof(Elf64_Phdr)*Header->e_phnum, phtab);\r
120 \r
121         // Count load segments\r
122         nLoadSegments = 0;\r
123         for( i = 0; i < Header->e_phnum; i ++ )\r
124         {\r
125                 if( phtab[i].p_type != PT_LOAD )        continue ;\r
126                 nLoadSegments ++;\r
127         }\r
128         \r
129         // Allocate Information Structure\r
130         ret = malloc( sizeof(tBinary) + sizeof(tBinarySection)*nLoadSegments );\r
131         // Fill Info Struct\r
132         ret->Entry = Header->e_entry;\r
133         ret->Base = -1;         // Set Base to maximum value\r
134         ret->NumSections = nLoadSegments;\r
135         ret->Interpreter = NULL;\r
136 \r
137         j = 0;  // LoadSections[] index\r
138         for( i = 0; i < Header->e_phnum; i ++ )\r
139         {\r
140                 LOG("phtab[%i] = {", i);\r
141                 LOG("  .p_type   = %i", phtab[i].p_type);\r
142                 LOG("  .p_flags  = 0x%x", phtab[i].p_flags);\r
143                 LOG("  .p_offset = 0x%llx", phtab[i].p_offset);\r
144                 LOG("  .p_vaddr  = 0x%llx", phtab[i].p_vaddr);\r
145                 LOG("  .p_paddr  = 0x%llx", phtab[i].p_paddr);\r
146                 LOG("  .p_filesz = 0x%llx", phtab[i].p_filesz);\r
147                 LOG("  .p_memsz  = 0x%llx", phtab[i].p_memsz);\r
148                 LOG("  .p_align  = 0x%llx", phtab[i].p_align);\r
149                 LOG("}");\r
150 \r
151                 // Get Interpreter Name\r
152                 if( phtab[i].p_type == PT_INTERP )\r
153                 {\r
154                         char *tmp;\r
155                         if(ret->Interpreter)    continue;\r
156                         tmp = malloc(phtab[i].p_filesz);\r
157                         VFS_Seek(FD, phtab[i].p_offset, 1);\r
158                         VFS_Read(FD, phtab[i].p_filesz, tmp);\r
159                         ret->Interpreter = Binary_RegInterp(tmp);\r
160                         LOG("Interpreter '%s'", tmp);\r
161                         free(tmp);\r
162                         continue;\r
163                 }\r
164                 \r
165                 if( phtab[i].p_type != PT_LOAD )        continue ;\r
166                 \r
167                 // Find the executable base\r
168                 if( phtab[i].p_vaddr < ret->Base )      ret->Base = phtab[i].p_vaddr;\r
169 \r
170                 ret->LoadSections[j].Offset = phtab[i].p_offset;\r
171                 ret->LoadSections[j].Virtual = phtab[i].p_vaddr;\r
172                 ret->LoadSections[j].FileSize = phtab[i].p_filesz;\r
173                 ret->LoadSections[j].MemSize = phtab[i].p_memsz;\r
174                 \r
175                 ret->LoadSections[j].Flags = 0;\r
176                 if( !(phtab[i].p_flags & PF_W) )\r
177                         ret->LoadSections[j].Flags |= BIN_SECTFLAG_RO;\r
178                 if( phtab[i].p_flags & PF_X )\r
179                         ret->LoadSections[j].Flags |= BIN_SECTFLAG_EXEC;\r
180                 j ++;\r
181         }\r
182 \r
183         return ret;\r
184 }\r
185 \r
186 tBinary *Elf_Load32(int FD, Elf32_Ehdr *Header)\r
187 {\r
188         tBinary *ret;\r
189         Elf32_Phdr      *phtab;\r
190          int    i, j;\r
191          int    iLoadCount;\r
192 \r
193         ENTER("xFD", FD);\r
194 \r
195         // Check architecture with current CPU\r
196         // - TODO: Support kernel level emulation\r
197         #if ARCH_IS_x86\r
198         if( Header->machine != EM_386 )\r
199         {\r
200                 Log_Warning("ELF", "Unknown architecure on ELF-32");\r
201                 LEAVE_RET('n');\r
202                 return NULL;\r
203         }\r
204         #endif\r
205 \r
206         // Check for a program header\r
207         if(Header->phoff == 0) {\r
208                 #if DEBUG_WARN\r
209                 Log_Warning("ELF", "File does not contain a program header (phoff == 0)");\r
210                 #endif\r
211                 LEAVE('n');\r
212                 return NULL;\r
213         }\r
214         \r
215         // Read Program Header Table\r
216         phtab = malloc( sizeof(Elf32_Phdr) * Header->phentcount );\r
217         if( !phtab ) {\r
218                 LEAVE('n');\r
219                 return NULL;\r
220         }\r
221         LOG("hdr.phoff = 0x%08x", Header->phoff);\r
222         VFS_Seek(FD, Header->phoff, SEEK_SET);\r
223         VFS_Read(FD, sizeof(Elf32_Phdr)*Header->phentcount, phtab);\r
224         \r
225         // Count Pages\r
226         iLoadCount = 0;\r
227         LOG("Header->phentcount = %i", Header->phentcount);\r
228         for( i = 0; i < Header->phentcount; i++ )\r
229         {\r
230                 // Ignore Non-LOAD types\r
231                 if(phtab[i].Type != PT_LOAD)\r
232                         continue;\r
233                 iLoadCount ++;\r
234                 LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}", i, phtab[i].VAddr, phtab[i].MemSize);\r
235         }\r
236         \r
237         LOG("iLoadCount = %i", iLoadCount);\r
238         \r
239         // Allocate Information Structure\r
240         ret = malloc( sizeof(tBinary) + sizeof(tBinarySection)*iLoadCount );\r
241         // Fill Info Struct\r
242         ret->Entry = Header->entrypoint;\r
243         ret->Base = -1;         // Set Base to maximum value\r
244         ret->NumSections = iLoadCount;\r
245         ret->Interpreter = NULL;\r
246         \r
247         // Load Pages\r
248         j = 0;\r
249         for( i = 0; i < Header->phentcount; i++ )\r
250         {\r
251                 //LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type);\r
252                 LOG("phtab[%i] = {", i);\r
253                 LOG(" .Type = 0x%08x", phtab[i].Type);\r
254                 LOG(" .Offset = 0x%08x", phtab[i].Offset);\r
255                 LOG(" .VAddr = 0x%08x", phtab[i].VAddr);\r
256                 LOG(" .PAddr = 0x%08x", phtab[i].PAddr);\r
257                 LOG(" .FileSize = 0x%08x", phtab[i].FileSize);\r
258                 LOG(" .MemSize = 0x%08x", phtab[i].MemSize);\r
259                 LOG(" .Flags = 0x%08x", phtab[i].Flags);\r
260                 LOG(" .Align = 0x%08x", phtab[i].Align);\r
261                 LOG(" }");\r
262                 // Get Interpreter Name\r
263                 if( phtab[i].Type == PT_INTERP )\r
264                 {\r
265                         char *tmp;\r
266                         if(ret->Interpreter)    continue;\r
267                         tmp = malloc(phtab[i].FileSize);\r
268                         VFS_Seek(FD, phtab[i].Offset, 1);\r
269                         VFS_Read(FD, phtab[i].FileSize, tmp);\r
270                         ret->Interpreter = Binary_RegInterp(tmp);\r
271                         LOG("Interpreter '%s'", tmp);\r
272                         free(tmp);\r
273                         continue;\r
274                 }\r
275                 // Ignore non-LOAD types\r
276                 if(phtab[i].Type != PT_LOAD)    continue;\r
277                 \r
278                 // Find Base\r
279                 if(phtab[i].VAddr < ret->Base)  ret->Base = phtab[i].VAddr;\r
280                 \r
281                 LOG("phtab[%i] = {VAddr:0x%x,Offset:0x%x,FileSize:0x%x}",\r
282                         i, phtab[i].VAddr, phtab[i].Offset, phtab[i].FileSize);\r
283                 \r
284                 ret->LoadSections[j].Offset = phtab[i].Offset;\r
285                 ret->LoadSections[j].FileSize = phtab[i].FileSize;\r
286                 ret->LoadSections[j].Virtual = phtab[i].VAddr;\r
287                 ret->LoadSections[j].MemSize = phtab[i].MemSize;\r
288                 ret->LoadSections[j].Flags = 0;\r
289                 if( !(phtab[i].Flags & PF_W) )\r
290                         ret->LoadSections[j].Flags |= BIN_SECTFLAG_RO;\r
291                 if( phtab[i].Flags & PF_X )\r
292                         ret->LoadSections[j].Flags |= BIN_SECTFLAG_EXEC;\r
293                 j ++;\r
294         }\r
295         \r
296         // Clean Up\r
297         free(phtab);\r
298         // Return\r
299         LEAVE('p', ret);\r
300         return ret;\r
301 }\r
302 \r
303 int Elf_Relocate(void *Base)\r
304 {\r
305         return ElfRelocate(Base, (char**){NULL}, "") != NULL;\r
306 }\r
307 int Elf_GetSymbol(void *Base, const char *Name, Uint *ret)\r
308 {\r
309         return ElfGetSymbol(Base, Name, (void**)ret, NULL);\r
310 }\r
311 \r

UCC git Repository :: git.ucc.asn.au