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

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