AcessNative - Clean up ELF loader code
[tpg/acess2.git] / AcessNative / ld-acess_src / elf_load.c
1 /*\r
2  * Acess2 - AcessNative\r
3  *\r
4  * ELF Executable Loader Code\r
5  */\r
6 #define DEBUG   0\r
7 #include <stdlib.h>\r
8 #include <stdio.h>\r
9 #include <string.h>\r
10 #include <unistd.h>\r
11 #include <inttypes.h>   // PRIx64\r
12 #include "common.h"\r
13 #include "elf32.h"\r
14 #include "elf64.h"\r
15 \r
16 #define DEBUG_WARN      1\r
17 \r
18 #define MKPTR(_type,_val)       ((_type*)(uintptr_t)(_val))\r
19 #define PTRMK(_type,_val)       MKPTR(_type,_val)\r
20 #define PTR(_val)       ((void*)(uintptr_t)(_val))\r
21 \r
22 #if DEBUG\r
23 # define ENTER(...)     printf("%s: ---- ENTER ----\n", __func__);\r
24 # define LOG(s, ...)    printf("%s: " s, __func__, __VA_ARGS__)\r
25 # define LOGS(s)        printf("%s: " s, __func__)\r
26 # define LEAVE(...)     printf("%s: ---- LEAVE ----\n", __func__);\r
27 #else\r
28 # define ENTER(...)\r
29 # define LOG(...)\r
30 # define LOGS(...)\r
31 # define LEAVE(...)\r
32 #endif\r
33 \r
34 // === PROTOTYPES ===\r
35 void    *Elf_Load(int FD);\r
36 void    *Elf32Load(int FD, Elf32_Ehdr *hdr);\r
37 void    *Elf64Load(int FD, Elf64_Ehdr *hdr);\r
38 \r
39 // === CODE ===\r
40 void *Elf_Load(int FD)\r
41 {\r
42         Elf64_Ehdr      hdr;\r
43         \r
44         // Read ELF Header\r
45         acess__SysRead(FD, &hdr, sizeof(hdr));\r
46         \r
47         // Check the file type\r
48         if(hdr.e_ident[0] != 0x7F || hdr.e_ident[1] != 'E' || hdr.e_ident[2] != 'L' || hdr.e_ident[3] != 'F') {\r
49                 Warning("Non-ELF File was passed to the ELF loader\n");\r
50                 return NULL;\r
51         }\r
52 \r
53         switch(hdr.e_ident[4])\r
54         {\r
55         case ELFCLASS32:\r
56                 return Elf32Load(FD, (void*)&hdr);\r
57         case ELFCLASS64:\r
58                 return Elf64Load(FD, &hdr);\r
59         default:\r
60                 Warning("Unknown ELF class (%i)", hdr.e_ident[4]);\r
61                 return NULL;\r
62         }\r
63 }\r
64 \r
65 void *Elf32Load(int FD, Elf32_Ehdr *hdr)\r
66 {\r
67         ENTER("iFD", FD);\r
68         \r
69         // Check for a program header\r
70         if(hdr->e_phoff == 0) {\r
71                 #if DEBUG_WARN\r
72                 Warning("ELF File does not contain a program header\n");\r
73                 #endif\r
74                 LEAVE('n');\r
75                 return NULL;\r
76         }\r
77         \r
78         // Read Program Header Table\r
79         Elf32_Phdr* phtab = malloc( sizeof(Elf32_Phdr) * hdr->e_phnum );\r
80         if( !phtab ) {\r
81                 LEAVE('n');\r
82                 return NULL;\r
83         }\r
84         LOG("hdr.e_phoff = 0x%08x\n", hdr->e_phoff);\r
85         acess__SysSeek(FD, hdr->e_phoff, ACESS_SEEK_SET);\r
86         acess__SysRead(FD, phtab, sizeof(Elf32_Phdr) * hdr->e_phnum);\r
87         \r
88         // Count Pages\r
89         unsigned int iPageCount = 0;\r
90         LOG("hdr.e_phnum = %i\n", hdr->e_phnum);\r
91         for( unsigned int i = 0; i < hdr->e_phnum; i++ )\r
92         {\r
93                 // Ignore Non-LOAD types\r
94                 if(phtab[i].p_type != PT_LOAD)\r
95                         continue;\r
96                 iPageCount += ((phtab[i].p_vaddr&0xFFF) + phtab[i].p_memsz + 0xFFF) >> 12;\r
97                 LOG("phtab[%i] = {p_vaddr:0x%x, p_memsz:0x%x}\n", i, phtab[i].p_vaddr, phtab[i].MemSize);\r
98         }\r
99         \r
100         LOG("iPageCount = %i\n", iPageCount);\r
101         \r
102         // Allocate Information Structure\r
103         //ret = malloc( sizeof(tBinary) + sizeof(tBinaryPage)*iPageCount );\r
104         // Fill Info Struct\r
105         //ret->Entry = hdr.entrypoint;\r
106         //ret->Base = -1;               // Set Base to maximum value\r
107         //ret->NumPages = iPageCount;\r
108         //ret->Interpreter = NULL;\r
109 \r
110         // Prescan for base and size\r
111         uint32_t        max = 0;\r
112         uint32_t        base = UINT32_MAX;\r
113         for( unsigned int i = 0; i < hdr->e_phnum; i ++)\r
114         {\r
115                 if( phtab[i].p_type != PT_LOAD )\r
116                         continue;\r
117                 if( phtab[i].p_vaddr < base )\r
118                         base = phtab[i].p_vaddr;\r
119                 if( phtab[i].p_vaddr + phtab[i].p_memsz > max )\r
120                         max = phtab[i].p_vaddr + phtab[i].p_memsz;\r
121         }\r
122 \r
123         LOG("base = %08x, max = %08x\n", base, max);\r
124 \r
125         uint32_t        baseDiff = 0;\r
126         if( base == 0 ) {\r
127                 // Find a nice space (47 address bits allowed)\r
128                 base = FindFreeRange( max, 47 );\r
129                 LOG("new base = %08x\n", base);\r
130                 if( base == 0 ) return NULL;\r
131                 baseDiff = base;\r
132         }\r
133         \r
134         // Load Pages\r
135         for( unsigned int i = 0; i < hdr->e_phnum; i++ )\r
136         {\r
137                 // Get Interpreter Name\r
138                 if( phtab[i].p_type == PT_INTERP )\r
139                 {\r
140                         char *tmp;\r
141                         //if(ret->Interpreter)  continue;\r
142                         tmp = malloc(phtab[i].p_filesz);\r
143                         acess__SysSeek(FD, phtab[i].p_offset, ACESS_SEEK_SET);\r
144                         acess__SysRead(FD, tmp, phtab[i].p_filesz);\r
145                         //ret->Interpreter = Binary_RegInterp(tmp);\r
146                         LOG("Interpreter '%s'\n", tmp);\r
147                         free(tmp);\r
148                         continue;\r
149                 }\r
150                 // Ignore non-LOAD types\r
151                 if(phtab[i].p_type != PT_LOAD)  continue;\r
152                 \r
153                 LOG("phtab[%i] = PT_LOAD {Adj p_vaddr:0x%x, p_offset:0x%x, p_filesz:0x%x, p_memsz:0x%x}\n",\r
154                         i, phtab[i].p_vaddr+baseDiff, phtab[i].p_offset, phtab[i].p_filesz, phtab[i].p_memsz);\r
155                 \r
156                 uint64_t addr = phtab[i].p_vaddr + baseDiff;\r
157 \r
158                 if( AllocateMemory( addr, phtab[i].p_memsz ) ) {\r
159                         fprintf(stderr, "Elf_Load: Unable to map memory at 0x%"PRIx64" (0x%x bytes)\n",\r
160                                 addr, phtab[i].p_memsz);\r
161                         free( phtab );\r
162                         return NULL;\r
163                 }\r
164                 \r
165                 acess__SysSeek(FD, phtab[i].p_offset, ACESS_SEEK_SET);\r
166                 acess__SysRead(FD, PTRMK(void, addr), phtab[i].p_filesz);\r
167                 memset( PTRMK(char, addr) + phtab[i].p_filesz, 0, phtab[i].p_memsz - phtab[i].p_filesz );\r
168         }\r
169         \r
170         // Clean Up\r
171         free(phtab);\r
172         // Return\r
173         LEAVE('p', base);\r
174         return PTRMK(void, base);\r
175 }\r
176 \r
177 void *Elf64Load(int FD, Elf64_Ehdr *hdr)\r
178 {\r
179         ENTER("iFD", FD);\r
180         \r
181         if( sizeof(void*) == 4) {\r
182                 Warning("ELF64 being loaded in 32-bit env, this may not work");\r
183         }\r
184 \r
185         // Check for a program header\r
186         if(hdr->e_phoff == 0) {\r
187                 #if DEBUG_WARN\r
188                 Warning("ELF File does not contain a program header\n");\r
189                 #endif\r
190                 LEAVE('n');\r
191                 return NULL;\r
192         }\r
193         \r
194         // Read Program Header Table\r
195         Elf64_Phdr* phtab = malloc( sizeof(Elf64_Phdr) * hdr->e_phnum );\r
196         if( !phtab ) {\r
197                 LEAVE('n');\r
198                 return NULL;\r
199         }\r
200         LOG("hdr.e_phoff = 0x%08llx\n", (long long)hdr->e_phoff);\r
201         acess__SysSeek(FD, hdr->e_phoff, ACESS_SEEK_SET);\r
202         acess__SysRead(FD, phtab, sizeof(Elf64_Phdr) * hdr->e_phnum);\r
203         \r
204         // Count Pages\r
205         unsigned int iPageCount = 0;\r
206         LOG("hdr.e_phnum = %i\n", hdr->e_phnum);\r
207         for( unsigned int i = 0; i < hdr->e_phnum; i++ )\r
208         {\r
209                 // Ignore Non-LOAD types\r
210                 if(phtab[i].p_type != PT_LOAD)\r
211                         continue;\r
212                 iPageCount += ((phtab[i].p_vaddr&0xFFF) + phtab[i].p_memsz + 0xFFF) >> 12;\r
213                 LOG("phtab[%i] = {p_vaddr:0x%llx, p_memsz:0x%llx}\n",\r
214                         i, (long long)phtab[i].p_vaddr, (long long)phtab[i].p_memsz);\r
215         }\r
216         \r
217         LOG("iPageCount = %i\n", iPageCount);\r
218         \r
219         // Allocate Information Structure\r
220         //ret = malloc( sizeof(tBinary) + sizeof(tBinaryPage)*iPageCount );\r
221         // Fill Info Struct\r
222         //ret->Entry = hdr.entrypoint;\r
223         //ret->Base = -1;               // Set Base to maximum value\r
224         //ret->NumPages = iPageCount;\r
225         //ret->Interpreter = NULL;\r
226 \r
227         // Prescan for base and size\r
228         uint64_t max = 0;\r
229         uint64_t base = UINT64_MAX;\r
230         for( unsigned int i = 0; i < hdr->e_phnum; i ++)\r
231         {\r
232                 if( phtab[i].p_type != PT_LOAD )\r
233                         continue;\r
234                 if( phtab[i].p_vaddr < base )\r
235                         base = phtab[i].p_vaddr;\r
236                 if( phtab[i].p_vaddr + phtab[i].p_memsz > max )\r
237                         max = phtab[i].p_vaddr + phtab[i].p_memsz;\r
238         }\r
239 \r
240         LOG("base = %08lx, max = %08lx\n", base, max);\r
241 \r
242         uint64_t        baseDiff = 0;\r
243         if( base == 0 ) {\r
244                 // Find a nice space (31 address bits allowed)\r
245                 base = FindFreeRange( max, 31 );\r
246                 LOG("new base = %08lx\n", base);\r
247                 if( base == 0 )\r
248                         goto _err;\r
249                 baseDiff = base;\r
250         }\r
251         \r
252         // Load Pages\r
253         for( unsigned int i = 0; i < hdr->e_phnum; i++ )\r
254         {\r
255                 // Get Interpreter Name\r
256                 if( phtab[i].p_type == PT_INTERP )\r
257                 {\r
258                         char *tmp;\r
259                         //if(ret->Interpreter)  continue;\r
260                         tmp = malloc(phtab[i].p_filesz+1);\r
261                         tmp[ phtab[i].p_filesz ] = 0;\r
262                         acess__SysSeek(FD, phtab[i].p_offset, ACESS_SEEK_SET);\r
263                         acess__SysRead(FD, tmp, phtab[i].p_filesz);\r
264                         //ret->Interpreter = Binary_RegInterp(tmp);\r
265                         LOG("Interpreter '%s'\n", tmp);\r
266                         free(tmp);\r
267                         continue;\r
268                 }\r
269                 // Ignore non-LOAD types\r
270                 if(phtab[i].p_type != PT_LOAD)  continue;\r
271                 \r
272                 LOG("phtab[%i] = PT_LOAD {Adj p_vaddr:0x%llx, p_offset:0x%llx, p_filesz:0x%llx, p_memsz:0x%llx}\n",\r
273                         i,\r
274                         (long long)phtab[i].p_vaddr+baseDiff, (long long)phtab[i].p_offset,\r
275                         (long long)phtab[i].p_filesz, (long long)phtab[i].p_memsz\r
276                         );\r
277                 \r
278                 uint64_t addr = phtab[i].p_vaddr + baseDiff;\r
279 \r
280                 if( AllocateMemory( addr, phtab[i].p_memsz ) ) {\r
281                         fprintf(stderr, "Elf_Load: Unable to map memory at %"PRIx64" (0x%"PRIx64" bytes)\n",\r
282                                 (uint64_t)addr, (uint64_t)phtab[i].p_memsz);\r
283                         goto _err;\r
284                 }\r
285                 \r
286                 acess__SysSeek(FD, phtab[i].p_offset, ACESS_SEEK_SET);\r
287                 acess__SysRead(FD, PTRMK(void, addr), phtab[i].p_filesz);\r
288                 memset( PTRMK(char, addr) + phtab[i].p_filesz, 0, phtab[i].p_memsz - phtab[i].p_filesz );\r
289         }\r
290         \r
291         // Clean Up\r
292         free(phtab);\r
293         // Return\r
294         LEAVE('p', base);\r
295         return PTRMK(void, base);\r
296 _err:\r
297         free(phtab);\r
298         LEAVE('n');\r
299         return NULL;\r
300 }\r
301 \r

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