c5edc4a5c17049e3eabc083cd82cceae7f326c39
[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         Elf32_Phdr      *phtab;\r
68          int    i;\r
69          int    iPageCount;\r
70         uint32_t        max, base;\r
71         uint32_t        addr;\r
72         uint32_t        baseDiff = 0;\r
73         \r
74         ENTER("iFD", FD);\r
75         \r
76         // Check for a program header\r
77         if(hdr->e_phoff == 0) {\r
78                 #if DEBUG_WARN\r
79                 Warning("ELF File does not contain a program header\n");\r
80                 #endif\r
81                 LEAVE('n');\r
82                 return NULL;\r
83         }\r
84         \r
85         // Read Program Header Table\r
86         phtab = malloc( sizeof(Elf32_Phdr) * hdr->e_phnum );\r
87         if( !phtab ) {\r
88                 LEAVE('n');\r
89                 return NULL;\r
90         }\r
91         LOG("hdr.e_phoff = 0x%08x\n", hdr->e_phoff);\r
92         acess__SysSeek(FD, hdr->e_phoff, ACESS_SEEK_SET);\r
93         acess__SysRead(FD, phtab, sizeof(Elf32_Phdr) * hdr->e_phnum);\r
94         \r
95         // Count Pages\r
96         iPageCount = 0;\r
97         LOG("hdr.e_phnum = %i\n", hdr->e_phnum);\r
98         for( i = 0; i < hdr->e_phnum; i++ )\r
99         {\r
100                 // Ignore Non-LOAD types\r
101                 if(phtab[i].p_type != PT_LOAD)\r
102                         continue;\r
103                 iPageCount += ((phtab[i].p_vaddr&0xFFF) + phtab[i].p_memsz + 0xFFF) >> 12;\r
104                 LOG("phtab[%i] = {p_vaddr:0x%x, p_memsz:0x%x}\n", i, phtab[i].p_vaddr, phtab[i].MemSize);\r
105         }\r
106         \r
107         LOG("iPageCount = %i\n", iPageCount);\r
108         \r
109         // Allocate Information Structure\r
110         //ret = malloc( sizeof(tBinary) + sizeof(tBinaryPage)*iPageCount );\r
111         // Fill Info Struct\r
112         //ret->Entry = hdr.entrypoint;\r
113         //ret->Base = -1;               // Set Base to maximum value\r
114         //ret->NumPages = iPageCount;\r
115         //ret->Interpreter = NULL;\r
116 \r
117         // Prescan for base and size\r
118         max = 0;\r
119         base = 0xFFFFFFFF;\r
120         for( i = 0; i < hdr->e_phnum; i ++)\r
121         {\r
122                 if( phtab[i].p_type != PT_LOAD )\r
123                         continue;\r
124                 if( phtab[i].p_vaddr < base )\r
125                         base = phtab[i].p_vaddr;\r
126                 if( phtab[i].p_vaddr + phtab[i].p_memsz > max )\r
127                         max = phtab[i].p_vaddr + phtab[i].p_memsz;\r
128         }\r
129 \r
130         LOG("base = %08x, max = %08x\n", base, max);\r
131 \r
132         if( base == 0 ) {\r
133                 // Find a nice space (47 address bits allowed)\r
134                 base = FindFreeRange( max, 47 );\r
135                 LOG("new base = %08x\n", base);\r
136                 if( base == 0 ) return NULL;\r
137                 baseDiff = base;\r
138         }\r
139         \r
140         // Load Pages\r
141         for( i = 0; i < hdr->e_phnum; i++ )\r
142         {\r
143                 // Get Interpreter Name\r
144                 if( phtab[i].p_type == PT_INTERP )\r
145                 {\r
146                         char *tmp;\r
147                         //if(ret->Interpreter)  continue;\r
148                         tmp = malloc(phtab[i].p_filesz);\r
149                         acess__SysSeek(FD, phtab[i].p_offset, ACESS_SEEK_SET);\r
150                         acess__SysRead(FD, tmp, phtab[i].p_filesz);\r
151                         //ret->Interpreter = Binary_RegInterp(tmp);\r
152                         LOG("Interpreter '%s'\n", tmp);\r
153                         free(tmp);\r
154                         continue;\r
155                 }\r
156                 // Ignore non-LOAD types\r
157                 if(phtab[i].p_type != PT_LOAD)  continue;\r
158                 \r
159                 LOG("phtab[%i] = PT_LOAD {Adj p_vaddr:0x%x, p_offset:0x%x, p_filesz:0x%x, p_memsz:0x%x}\n",\r
160                         i, phtab[i].p_vaddr+baseDiff, phtab[i].p_offset, phtab[i].p_filesz, phtab[i].p_memsz);\r
161                 \r
162                 addr = phtab[i].p_vaddr + baseDiff;\r
163 \r
164                 if( AllocateMemory( addr, phtab[i].p_memsz ) ) {\r
165                         fprintf(stderr, "Elf_Load: Unable to map memory at %x (0x%x bytes)\n",\r
166                                 addr, phtab[i].p_memsz);\r
167                         free( phtab );\r
168                         return NULL;\r
169                 }\r
170                 \r
171                 acess__SysSeek(FD, phtab[i].p_offset, ACESS_SEEK_SET);\r
172                 acess__SysRead(FD, PTRMK(void, addr), phtab[i].p_filesz);\r
173                 memset( PTRMK(char, addr) + phtab[i].p_filesz, 0, phtab[i].p_memsz - phtab[i].p_filesz );\r
174         }\r
175         \r
176         // Clean Up\r
177         free(phtab);\r
178         // Return\r
179         LEAVE('p', base);\r
180         return PTRMK(void, base);\r
181 }\r
182 \r
183 void *Elf64Load(int FD, Elf64_Ehdr *hdr)\r
184 {\r
185         Elf64_Phdr      *phtab;\r
186          int    i;\r
187          int    iPageCount;\r
188         uint64_t        max, base;\r
189         uint64_t        addr;\r
190         uint64_t        baseDiff = 0;\r
191         \r
192         ENTER("iFD", FD);\r
193         \r
194         if( sizeof(void*) == 4) {\r
195                 Warning("ELF64 being loaded in 32-bit env, this may not work");\r
196         }\r
197 \r
198         // Check for a program header\r
199         if(hdr->e_phoff == 0) {\r
200                 #if DEBUG_WARN\r
201                 Warning("ELF File does not contain a program header\n");\r
202                 #endif\r
203                 LEAVE('n');\r
204                 return NULL;\r
205         }\r
206         \r
207         // Read Program Header Table\r
208         phtab = malloc( sizeof(Elf64_Phdr) * hdr->e_phnum );\r
209         if( !phtab ) {\r
210                 LEAVE('n');\r
211                 return NULL;\r
212         }\r
213         LOG("hdr.e_phoff = 0x%08llx\n", (long long)hdr->e_phoff);\r
214         acess__SysSeek(FD, hdr->e_phoff, ACESS_SEEK_SET);\r
215         acess__SysRead(FD, phtab, sizeof(Elf64_Phdr) * hdr->e_phnum);\r
216         \r
217         // Count Pages\r
218         iPageCount = 0;\r
219         LOG("hdr.e_phnum = %i\n", hdr->e_phnum);\r
220         for( i = 0; i < hdr->e_phnum; i++ )\r
221         {\r
222                 // Ignore Non-LOAD types\r
223                 if(phtab[i].p_type != PT_LOAD)\r
224                         continue;\r
225                 iPageCount += ((phtab[i].p_vaddr&0xFFF) + phtab[i].p_memsz + 0xFFF) >> 12;\r
226                 LOG("phtab[%i] = {p_vaddr:0x%llx, p_memsz:0x%llx}\n",\r
227                         i, (long long)phtab[i].p_vaddr, (long long)phtab[i].p_memsz);\r
228         }\r
229         \r
230         LOG("iPageCount = %i\n", iPageCount);\r
231         \r
232         // Allocate Information Structure\r
233         //ret = malloc( sizeof(tBinary) + sizeof(tBinaryPage)*iPageCount );\r
234         // Fill Info Struct\r
235         //ret->Entry = hdr.entrypoint;\r
236         //ret->Base = -1;               // Set Base to maximum value\r
237         //ret->NumPages = iPageCount;\r
238         //ret->Interpreter = NULL;\r
239 \r
240         // Prescan for base and size\r
241         max = 0;\r
242         base = 0xFFFFFFFF;\r
243         for( i = 0; i < hdr->e_phnum; i ++)\r
244         {\r
245                 if( phtab[i].p_type != PT_LOAD )\r
246                         continue;\r
247                 if( phtab[i].p_vaddr < base )\r
248                         base = phtab[i].p_vaddr;\r
249                 if( phtab[i].p_vaddr + phtab[i].p_memsz > max )\r
250                         max = phtab[i].p_vaddr + phtab[i].p_memsz;\r
251         }\r
252 \r
253         LOG("base = %08lx, max = %08lx\n", base, max);\r
254 \r
255         if( base == 0 ) {\r
256                 // Find a nice space (31 address bits allowed)\r
257                 base = FindFreeRange( max, 31 );\r
258                 LOG("new base = %08lx\n", base);\r
259                 if( base == 0 ) return NULL;\r
260                 baseDiff = base;\r
261         }\r
262         \r
263         // Load Pages\r
264         for( i = 0; i < hdr->e_phnum; i++ )\r
265         {\r
266                 // Get Interpreter Name\r
267                 if( phtab[i].p_type == PT_INTERP )\r
268                 {\r
269                         char *tmp;\r
270                         //if(ret->Interpreter)  continue;\r
271                         tmp = malloc(phtab[i].p_filesz+1);\r
272                         tmp[ phtab[i].p_filesz ] = 0;\r
273                         acess__SysSeek(FD, phtab[i].p_offset, ACESS_SEEK_SET);\r
274                         acess__SysRead(FD, tmp, phtab[i].p_filesz);\r
275                         //ret->Interpreter = Binary_RegInterp(tmp);\r
276                         LOG("Interpreter '%s'\n", tmp);\r
277                         free(tmp);\r
278                         continue;\r
279                 }\r
280                 // Ignore non-LOAD types\r
281                 if(phtab[i].p_type != PT_LOAD)  continue;\r
282                 \r
283                 LOG("phtab[%i] = PT_LOAD {Adj p_vaddr:0x%llx, p_offset:0x%llx, p_filesz:0x%llx, p_memsz:0x%llx}\n",\r
284                         i,\r
285                         (long long)phtab[i].p_vaddr+baseDiff, (long long)phtab[i].p_offset,\r
286                         (long long)phtab[i].p_filesz, (long long)phtab[i].p_memsz\r
287                         );\r
288                 \r
289                 addr = phtab[i].p_vaddr + baseDiff;\r
290 \r
291                 if( AllocateMemory( addr, phtab[i].p_memsz ) ) {\r
292                         fprintf(stderr, "Elf_Load: Unable to map memory at %"PRIx64" (0x%"PRIx64" bytes)\n",\r
293                                 (uint64_t)addr, (uint64_t)phtab[i].p_memsz);\r
294                         free( phtab );\r
295                         return NULL;\r
296                 }\r
297                 \r
298                 acess__SysSeek(FD, phtab[i].p_offset, ACESS_SEEK_SET);\r
299                 acess__SysRead(FD, PTRMK(void, addr), phtab[i].p_filesz);\r
300                 memset( PTRMK(char, addr) + phtab[i].p_filesz, 0, phtab[i].p_memsz - phtab[i].p_filesz );\r
301         }\r
302         \r
303         // Clean Up\r
304         free(phtab);\r
305         // Return\r
306         LEAVE('p', base);\r
307         return PTRMK(void, base);\r
308 }\r
309 \r

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