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

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