r4722@vps: verhaegs | 2007-05-06 13:11:19 -0400
[cake.git] / rom / dos / internalloadseg_aout.c
blob8dd46f186350ceb3144f83330c0fbc514a4ad56d
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Load an a.out format image into memory.
6 Lang: English.
8 1997/12/13: Changed filename to internalloadseg_aout.c
9 Original file was created by digulla (iaint actually).
11 #include <exec/memory.h>
12 #include <proto/exec.h>
13 #include <dos/dosasl.h>
14 #include <proto/dos.h>
15 #include <proto/arossupport.h>
16 #include "dos_intern.h"
17 #include <aros/debug.h>
18 #include <aros/asmcall.h>
19 #include "internalloadseg.h"
21 extern struct DosLibrary * DOSBase;
24 a.out files are much simpler than ELF format files or AmigaOS files.
25 This is probably due to the age of the format (AT&T V7 I think).
27 We load the text and combined data/bss segments randomly into memory
28 in two huge chunks. This is because it would be rather tricky to split
29 them up, as they are designed really for virtual memory based-machines
30 (so they can be loaded at the same address).
32 This has the unfortunate side effect of that for large programs, if
33 your memory is quite fragmented, you will not have enough memory to
34 load the program into memory.
38 /* The structure defining the file */
39 struct aout_hdr
41 UWORD a_magic; /* Magic number */
42 UWORD a_mid; /* Machine ID and flags (flags not used */
43 ULONG a_text; /* Length of text segment */
44 ULONG a_data; /* Length of data segment */
45 ULONG a_bss; /* Length of BSS space required */
46 ULONG a_syms; /* Symbol table length (bytes) */
47 ULONG a_entry; /* Program start point */
48 ULONG a_trsize; /* Size of text relocations (bytes) */
49 ULONG a_drsize; /* Size of data relocations (bytes) */
52 /* A relocation record */
53 struct reloc
55 LONG r_address; /* Offset in the section to the reloc */
56 ULONG r_symbolnum : 24, /* Actually the segment number */
57 r_pcrel : 1, /* PC relative (do nothing) */
58 r_length : 2, /* Length of relocation - should be 2 */
59 r_extern : 1, /* External relocation - not supported */
60 r_pad : 4;
63 #define OMAGIC 0407 /* Not used */
64 #define NMAGIC 0410 /* The format we use. */
65 #define ZMAGIC 0413 /* Not used */
67 #define MID_i386 134 /* i386 binary (386BSD) */
69 #define N_EXT 0x01 /* External flag - symbol can be accessed
70 externally */
71 #define N_ABS 0x02 /* Absolute Symbol - Not used */
72 #define N_TEXT 0x04 /* Text symbol */
73 #define N_DATA 0x06 /* Data symbol */
74 #define N_BSS 0x08 /* BSS symbol */
76 /* This is used so that we can jump over any constant stuff at the
77 beginning of the text hunk.
79 GCC tends to put string constants for a function before the function
80 in the text segment, so the very first byte of the text segment is
81 not actually code, but a string. This jumps over that.
83 struct JumpHunk
85 ULONG size;
86 BPTR next;
87 struct JumpVec vec;
90 /* relocate(exec, reloc, current, refer):
91 exec - The files exec header.
92 reloc - The relocation data.
93 current - The base of the hunk we are currently relocating in.
94 refer - The base of the hunk that the data references.
96 The hunk bases point to the "next hunk pointer", so we have to
97 add the size of a BPTR to the hunk to get the real address.
99 PC relative relocations are do-nothings because, no matter what the
100 load address of the code is, the data at that location is still the
101 same.
104 static LONG relocate( struct aout_hdr *head,
105 struct reloc *reloc,
106 UBYTE *currentHunk,
107 UBYTE *referHunk
110 /* I don't test whether the currentHunk is valid, since if it isn't
111 we should never have got here.
113 It could however be possible to say get a reference into a
114 data or bss hunk that doesn't exist.
116 if(referHunk == NULL)
118 D(bug("LoadSeg_AOUT: Trying to refer to a non-existant hunk.\n"));
119 return ERROR_BAD_HUNK;
123 References are relative to the file offset, so if this is a data
124 or BSS hunk, then we have to subtract the text segment size from
125 the address. It is effectively added back on by the stored value.
127 If BSS hunks were not contiguous with the data hunk then we would
128 have to do a similar thing there.
130 if(reloc->r_symbolnum != N_TEXT)
132 /* We should check whether we are doing a non-text PC rel here. */
133 referHunk -= head->a_text;
136 if(reloc->r_length != 2)
138 D(bug("LoadSeg_AOUT: Cannot relocate, bad reloc length at offset %ld\n",
139 reloc->r_address));
140 return ERROR_BAD_HUNK;
143 /* If we try this on a PC relative reloc, nothing will work */
144 if(!reloc->r_pcrel)
145 *(ULONG *)&currentHunk[reloc->r_address] += (ULONG)referHunk;
147 return 0;
150 BPTR InternalLoadSeg_AOUT(BPTR file,
151 BPTR table,
152 LONG * functionarray,
153 LONG * stack,
154 struct DosLibrary * DOSBase)
156 /* Currently the only parameter passed to this function that is
157 actually used is file. The rest is there for completeness.
158 Functionarray will *soon* be used! */
160 struct reloc rel;
161 UBYTE *texthunk = NULL;
162 UBYTE *datahunk = NULL;
163 struct JumpHunk *jumphunk = NULL;
164 struct aout_hdr header;
165 LONG rel_remain;
166 LONG err;
167 LONG *error = &(((struct Process *)FindTask(NULL))->pr_Result2);
169 #define ERROR(a) { *error = a; goto end; }
171 /* In case we have already had something attempt to load the file. */
172 Seek(file, 0, OFFSET_BEGINNING);
174 if ( AROS_CALL3(LONG, functionarray[0] /* Read */,
175 AROS_LCA(BPTR , file , D1),
176 AROS_LCA(void *, &header , D2),
177 AROS_LCA(LONG , sizeof(struct aout_hdr) , D3),
178 struct Library *, (struct Library *)DOSBase) !=
179 sizeof(struct aout_hdr))
181 D(bug("LoadSeg_AOUT: Can't read all of header\n"));
182 ERROR(ERROR_FILE_NOT_OBJECT);
186 The format that we use is an NMAGIC format with relocation
187 information. The important things about this is that the
188 text/data/bss segments are not page aligned (although that
189 doesn't really matter at this point in time). And most
190 importantly, the file thinks its being loaded at address
191 0x00000000 (rather than 0x00001000 for ZMAGIC files).
193 if( ((header.a_mid) != MID_i386) || (header.a_magic != NMAGIC))
195 D(bug("LoadSeg_AOUT: Bad magic number 0x%4x 0x%4x\n", header.a_magic, header.a_mid));
196 ERROR(ERROR_OBJECT_WRONG_TYPE);
199 /* It appears that GCC is putting some constant strings in the text
200 segment before the entry point. So what we have to do is jump
201 over those strings to the actual entry. To do this I will use
202 a struct JumpVec (yes the same as in the the library bases).
204 jumphunk = AROS_CALL2(void *, functionarray[1] /* AllocMem */,
205 AROS_LCA(ULONG, sizeof(struct JumpHunk) , D0),
206 AROS_LCA(ULONG, MEMF_CLEAR|MEMF_ANY , D1),
207 struct Library *, (struct Library *)SysBase);
208 if(jumphunk == NULL)
209 ERROR(ERROR_NO_FREE_STORE);
211 /* Text segment is required. */
212 texthunk = AROS_CALL2(void *, functionarray[1] /* AllocMem */,
213 AROS_LCA(ULONG, header.a_text+sizeof(ULONG)+sizeof(BPTR) , D0),
214 AROS_LCA(ULONG, MEMF_CLEAR|MEMF_ANY , D1),
215 struct Library *, (struct Library *)SysBase);
217 if(texthunk == NULL)
218 ERROR(ERROR_NO_FREE_STORE);
220 *((ULONG *)texthunk) = header.a_text + sizeof(ULONG) + sizeof(BPTR);
221 /* Link and Bump the text hunk past the next hunk pointer. */
222 jumphunk->size = sizeof(struct JumpHunk);
223 jumphunk->next = MKBADDR(texthunk + sizeof(ULONG));
224 texthunk += sizeof(ULONG) + sizeof(BPTR);
226 #ifdef __AROS_SET_JMP
227 __AROS_SET_JMP(&jumphunk->vec);
228 #endif
229 __AROS_SET_VEC(&jumphunk->vec, texthunk + header.a_entry);
231 if ( AROS_CALL3(LONG, functionarray[0] /* Read */,
232 AROS_LCA(BPTR , file , D1),
233 AROS_LCA(void *, texthunk , D2),
234 AROS_LCA(LONG , header.a_text , D3),
235 struct Library *, (struct Library *)DOSBase) !=
236 header.a_text)
238 D(bug("LoadSeg_AOUT: Can't read all of text segment\n"));
239 ERROR(ERROR_BAD_HUNK);
243 Data hunk is not required, but probably exists.
244 It doesn't for a number of disk based libs and devs that I looked at
246 if(header.a_data)
248 /* Include BSS with the data hunk. */
249 datahunk = AROS_CALL2(void *, functionarray[1] /* AllocMem */,
250 AROS_LCA(ULONG, header.a_data+header.a_bss+sizeof(ULONG)+sizeof(BPTR) , D0),
251 AROS_LCA(ULONG, MEMF_CLEAR|MEMF_ANY , D1),
252 struct Library *, (struct Library *)SysBase);
254 if(datahunk == NULL)
255 ERROR(ERROR_NO_FREE_STORE);
256 /* write the size of allocated memory */
257 *((ULONG *)datahunk) = header.a_data + header.a_bss + sizeof(ULONG) + sizeof(BPTR);
259 datahunk += sizeof(ULONG) + sizeof(BPTR);
261 if ( AROS_CALL3(LONG, functionarray[0] /* Read */,
262 AROS_LCA(BPTR , file , D1),
263 AROS_LCA(void *, datahunk , D2),
264 AROS_LCA(LONG , header.a_data , D3),
265 struct Library *, (struct Library *)DOSBase) !=
266 header.a_data)
268 D(bug("LoadSeg_AOUT: Can't read all of data segment\n"));
269 ERROR(ERROR_BAD_HUNK);
272 else if(header.a_bss)
274 datahunk = AROS_CALL2(void *, functionarray[1] /* AllocMem */,
275 AROS_LCA(ULONG, header.a_bss+sizeof(ULONG)+sizeof(BPTR) , D0),
276 AROS_LCA(ULONG, MEMF_CLEAR|MEMF_ANY , D1),
277 struct Library *, (struct Library *)SysBase);
279 if(datahunk == NULL)
280 ERROR(ERROR_NO_FREE_STORE);
281 /* write the size of allocated memory */
282 *datahunk = header.a_bss + sizeof(ULONG) + sizeof(BPTR);
284 datahunk += sizeof(ULONG) + sizeof(BPTR);
287 /* Link hunks together. If no data or bss, datahunk == NULL */
288 ((BPTR *)texthunk)[-1] = MKBADDR( (BPTR *)datahunk -1);
290 if(datahunk)
291 ((BPTR *)datahunk)[-1] = (BPTR)NULL;
293 /* First of all, text relocations. */
294 rel_remain = header.a_trsize / sizeof(struct reloc);
295 for(; rel_remain > 0; rel_remain-- )
297 if ( AROS_CALL3(LONG, functionarray[0] /* Read */,
298 AROS_LCA(BPTR , file , D1),
299 AROS_LCA(void *, &rel , D2),
300 AROS_LCA(LONG , sizeof(struct reloc) , D3),
301 struct Library *, (struct Library *)DOSBase) !=
302 sizeof(struct reloc))
305 D(bug("LoadSeg_AOUT: Can't load a text relocation.\n"));
306 ERROR(ERROR_BAD_HUNK);
309 if(rel.r_extern)
311 D(bug("LoadSeg_AOUT: Can't relocate external symbols.\n"));
312 ERROR(ERROR_BAD_HUNK);
315 switch(rel.r_symbolnum)
317 case N_TEXT | N_EXT:
318 case N_TEXT:
319 err = relocate(&header, &rel, texthunk, texthunk);
320 break;
322 case N_DATA | N_EXT:
323 case N_DATA:
324 case N_BSS | N_EXT: /* this is a bit silly */
325 case N_BSS:
326 err = relocate(&header, &rel, texthunk, datahunk);
327 break;
329 default:
330 D(bug("LoadSeg_AOUT: Can't relocate! Invalid Text SymNum\n"));
331 ERROR(ERROR_FILE_NOT_OBJECT);
333 if(err)
335 ERROR(err);
337 } /* for(relocation entry) */
339 /* Next of all, data relocations. */
340 rel_remain = header.a_drsize / sizeof(struct reloc);
341 for(; rel_remain > 0; rel_remain-- )
343 if ( AROS_CALL3(LONG, functionarray[0] /* Read */,
344 AROS_LCA(BPTR , file , D1),
345 AROS_LCA(void *, &rel , D2),
346 AROS_LCA(LONG , sizeof(struct reloc) , D3),
347 struct Library *, (struct Library *)DOSBase) !=
348 sizeof(struct reloc))
350 D(bug("LoadSeg_AOUT: Can't load a text relocation.\n"));
351 ERROR(ERROR_BAD_HUNK);
354 if(rel.r_extern)
356 D(bug("LoadSeg_AOUT: Can't relocate external symbols.\n"));
357 ERROR(ERROR_FILE_NOT_OBJECT);
359 switch(rel.r_symbolnum)
361 case N_TEXT|N_EXT:
362 case N_TEXT:
363 err = relocate(&header, &rel, datahunk, texthunk);
364 break;
366 case N_DATA|N_EXT:
367 case N_DATA:
368 case N_BSS|N_EXT:
369 case N_BSS:
370 err = relocate(&header, &rel, datahunk, datahunk);
371 break;
373 default:
374 D(bug("LoadSeg_AOUT: Can't relocate! Invalid Data SymNum\n"));
375 ERROR(ERROR_FILE_NOT_OBJECT);
377 if(err)
379 ERROR(err);
383 /* Flush the caches */
384 CacheClearE(texthunk - sizeof(ULONG) - sizeof(BPTR),
385 header.a_text + sizeof(ULONG) + sizeof(BPTR),
386 CACRF_ClearI|CACRF_ClearD);
388 if(datahunk)
389 CacheClearE(datahunk - sizeof(ULONG) - sizeof(BPTR),
390 header.a_data + header.a_bss + sizeof(ULONG) + sizeof(BPTR),
391 CACRF_ClearI|CACRF_ClearD);
393 /* Ok, it is relocated, and ready to run. Remember to subtract
394 next hunk pointer from the text hunk.
397 D(bug("Text Address = %p\tData Address = %p\n", texthunk, datahunk));
399 if(header.a_entry != 0)
401 /* jumphunk is the address of the next hunk pointer. */
402 return MKBADDR(&jumphunk->next);
404 else
406 /* We don't need it */
407 AROS_CALL2(void *, functionarray[2] /* FreeMem */,
408 AROS_LCA(void *, jumphunk , A1),
409 AROS_LCA(ULONG , sizeof(struct JumpHunk) , D0),
410 struct Library *, (struct Library *)SysBase);
412 return MKBADDR((BPTR *)texthunk - 1);
415 end:
416 /* If we allocated a text or data hunk, then we should free them */
417 if(datahunk)
418 AROS_CALL2(void *, functionarray[2] /* FreeMem */,
419 AROS_LCA(void *, datahunk - sizeof(BPTR) - sizeof(ULONG) , A1),
420 AROS_LCA(ULONG , *(ULONG *)((ULONG)datahunk - sizeof(BPTR) - sizeof(ULONG)) , D0),
421 struct Library *, (struct Library *)SysBase);
423 if(texthunk)
424 AROS_CALL2(void *, functionarray[2] /* FreeMem */,
425 AROS_LCA(void *, texthunk - sizeof(BPTR) - sizeof(ULONG) , A1),
426 AROS_LCA(ULONG , *(ULONG *)((ULONG)texthunk - sizeof(BPTR) - sizeof(ULONG)) , D0),
427 struct Library *, (struct Library *)SysBase);
429 if(jumphunk)
430 AROS_CALL2(void *, functionarray[2] /* FreeMem */,
431 AROS_LCA(void *, jumphunk , A1),
432 AROS_LCA(ULONG , sizeof(struct JumpHunk) , D0),
433 struct Library *, (struct Library *)SysBase);
435 return (BPTR)NULL;