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

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