Add new strings.
[AROS.git] / rom / dos / internalloadseg_aout.c
blob068a7ba030441e373ebba7d0e802cc9d07f03e64
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 SIPTR * functionarray,
153 SIPTR * stack,
154 struct MinList *seginfos,
155 struct DosLibrary * DOSBase)
157 /* Currently the only parameter passed to this function that is
158 actually used is file. The rest is there for completeness.
159 Functionarray will *soon* be used! */
161 struct reloc rel;
162 UBYTE *texthunk = NULL;
163 UBYTE *datahunk = NULL;
164 struct JumpHunk *jumphunk = NULL;
165 struct aout_hdr header;
166 LONG rel_remain;
167 LONG err;
168 LONG *error = &(((struct Process *)FindTask(NULL))->pr_Result2);
170 #define ERROR(a) { *error = a; goto end; }
172 /* In case we have already had something attempt to load the file. */
173 Seek(file, 0, OFFSET_BEGINNING);
175 if ( AROS_CALL3(LONG, functionarray[0] /* Read */,
176 AROS_LCA(BPTR , file , D1),
177 AROS_LCA(void *, &header , D2),
178 AROS_LCA(LONG , sizeof(struct aout_hdr) , D3),
179 struct Library *, (struct Library *)DOSBase) !=
180 sizeof(struct aout_hdr))
182 D(bug("LoadSeg_AOUT: Can't read all of header\n"));
183 ERROR(ERROR_FILE_NOT_OBJECT);
187 The format that we use is an NMAGIC format with relocation
188 information. The important things about this is that the
189 text/data/bss segments are not page aligned (although that
190 doesn't really matter at this point in time). And most
191 importantly, the file thinks its being loaded at address
192 0x00000000 (rather than 0x00001000 for ZMAGIC files).
194 if( ((header.a_mid) != MID_i386) || (header.a_magic != NMAGIC))
196 D(bug("LoadSeg_AOUT: Bad magic number 0x%4x 0x%4x\n", header.a_magic, header.a_mid));
197 ERROR(ERROR_OBJECT_WRONG_TYPE);
200 /* It appears that GCC is putting some constant strings in the text
201 segment before the entry point. So what we have to do is jump
202 over those strings to the actual entry. To do this I will use
203 a struct JumpVec (yes the same as in the the library bases).
205 jumphunk = AROS_CALL2(void *, functionarray[1] /* AllocMem */,
206 AROS_LCA(ULONG, sizeof(struct JumpHunk) , D0),
207 AROS_LCA(ULONG, MEMF_CLEAR|MEMF_ANY , D1),
208 struct Library *, (struct Library *)SysBase);
209 if(jumphunk == NULL)
210 ERROR(ERROR_NO_FREE_STORE);
212 /* Text segment is required. */
213 texthunk = AROS_CALL2(void *, functionarray[1] /* AllocMem */,
214 AROS_LCA(ULONG, header.a_text+sizeof(ULONG)+sizeof(BPTR) , D0),
215 AROS_LCA(ULONG, MEMF_CLEAR|MEMF_ANY , D1),
216 struct Library *, (struct Library *)SysBase);
218 if(texthunk == NULL)
219 ERROR(ERROR_NO_FREE_STORE);
221 *((ULONG *)texthunk) = header.a_text + sizeof(ULONG) + sizeof(BPTR);
222 /* Link and Bump the text hunk past the next hunk pointer. */
223 jumphunk->size = sizeof(struct JumpHunk);
224 jumphunk->next = MKBADDR(texthunk + sizeof(ULONG));
225 texthunk += sizeof(ULONG) + sizeof(BPTR);
227 #ifdef __AROS_SET_JMP
228 __AROS_SET_JMP(&jumphunk->vec);
229 #endif
230 jumphunk->vec.vec = texthunk + header.a_entry;
232 if ( AROS_CALL3(LONG, functionarray[0] /* Read */,
233 AROS_LCA(BPTR , file , D1),
234 AROS_LCA(void *, texthunk , D2),
235 AROS_LCA(LONG , header.a_text , D3),
236 struct Library *, (struct Library *)DOSBase) !=
237 header.a_text)
239 D(bug("LoadSeg_AOUT: Can't read all of text segment\n"));
240 ERROR(ERROR_BAD_HUNK);
244 Data hunk is not required, but probably exists.
245 It doesn't for a number of disk based libs and devs that I looked at
247 if(header.a_data)
249 /* Include BSS with the data hunk. */
250 datahunk = AROS_CALL2(void *, functionarray[1] /* AllocMem */,
251 AROS_LCA(ULONG, header.a_data+header.a_bss+sizeof(ULONG)+sizeof(BPTR) , D0),
252 AROS_LCA(ULONG, MEMF_CLEAR|MEMF_ANY , D1),
253 struct Library *, (struct Library *)SysBase);
255 if(datahunk == NULL)
256 ERROR(ERROR_NO_FREE_STORE);
257 /* write the size of allocated memory */
258 *((ULONG *)datahunk) = header.a_data + header.a_bss + sizeof(ULONG) + sizeof(BPTR);
260 datahunk += sizeof(ULONG) + sizeof(BPTR);
262 if ( AROS_CALL3(LONG, functionarray[0] /* Read */,
263 AROS_LCA(BPTR , file , D1),
264 AROS_LCA(void *, datahunk , D2),
265 AROS_LCA(LONG , header.a_data , D3),
266 struct Library *, (struct Library *)DOSBase) !=
267 header.a_data)
269 D(bug("LoadSeg_AOUT: Can't read all of data segment\n"));
270 ERROR(ERROR_BAD_HUNK);
273 else if(header.a_bss)
275 datahunk = AROS_CALL2(void *, functionarray[1] /* AllocMem */,
276 AROS_LCA(ULONG, header.a_bss+sizeof(ULONG)+sizeof(BPTR) , D0),
277 AROS_LCA(ULONG, MEMF_CLEAR|MEMF_ANY , D1),
278 struct Library *, (struct Library *)SysBase);
280 if(datahunk == NULL)
281 ERROR(ERROR_NO_FREE_STORE);
282 /* write the size of allocated memory */
283 *datahunk = header.a_bss + sizeof(ULONG) + sizeof(BPTR);
285 datahunk += sizeof(ULONG) + sizeof(BPTR);
288 /* Link hunks together. If no data or bss, datahunk == NULL */
289 ((BPTR *)texthunk)[-1] = MKBADDR( (BPTR *)datahunk -1);
291 if(datahunk)
292 ((BPTR *)datahunk)[-1] = (BPTR)NULL;
294 /* First of all, text relocations. */
295 rel_remain = header.a_trsize / sizeof(struct reloc);
296 for(; rel_remain > 0; rel_remain-- )
298 if ( AROS_CALL3(LONG, functionarray[0] /* Read */,
299 AROS_LCA(BPTR , file , D1),
300 AROS_LCA(void *, &rel , D2),
301 AROS_LCA(LONG , sizeof(struct reloc) , D3),
302 struct Library *, (struct Library *)DOSBase) !=
303 sizeof(struct reloc))
306 D(bug("LoadSeg_AOUT: Can't load a text relocation.\n"));
307 ERROR(ERROR_BAD_HUNK);
310 if(rel.r_extern)
312 D(bug("LoadSeg_AOUT: Can't relocate external symbols.\n"));
313 ERROR(ERROR_BAD_HUNK);
316 switch(rel.r_symbolnum)
318 case N_TEXT | N_EXT:
319 case N_TEXT:
320 err = relocate(&header, &rel, texthunk, texthunk);
321 break;
323 case N_DATA | N_EXT:
324 case N_DATA:
325 case N_BSS | N_EXT: /* this is a bit silly */
326 case N_BSS:
327 err = relocate(&header, &rel, texthunk, datahunk);
328 break;
330 default:
331 D(bug("LoadSeg_AOUT: Can't relocate! Invalid Text SymNum\n"));
332 ERROR(ERROR_FILE_NOT_OBJECT);
334 if(err)
336 ERROR(err);
338 } /* for(relocation entry) */
340 /* Next of all, data relocations. */
341 rel_remain = header.a_drsize / sizeof(struct reloc);
342 for(; rel_remain > 0; rel_remain-- )
344 if ( AROS_CALL3(LONG, functionarray[0] /* Read */,
345 AROS_LCA(BPTR , file , D1),
346 AROS_LCA(void *, &rel , D2),
347 AROS_LCA(LONG , sizeof(struct reloc) , D3),
348 struct Library *, (struct Library *)DOSBase) !=
349 sizeof(struct reloc))
351 D(bug("LoadSeg_AOUT: Can't load a text relocation.\n"));
352 ERROR(ERROR_BAD_HUNK);
355 if(rel.r_extern)
357 D(bug("LoadSeg_AOUT: Can't relocate external symbols.\n"));
358 ERROR(ERROR_FILE_NOT_OBJECT);
360 switch(rel.r_symbolnum)
362 case N_TEXT|N_EXT:
363 case N_TEXT:
364 err = relocate(&header, &rel, datahunk, texthunk);
365 break;
367 case N_DATA|N_EXT:
368 case N_DATA:
369 case N_BSS|N_EXT:
370 case N_BSS:
371 err = relocate(&header, &rel, datahunk, datahunk);
372 break;
374 default:
375 D(bug("LoadSeg_AOUT: Can't relocate! Invalid Data SymNum\n"));
376 ERROR(ERROR_FILE_NOT_OBJECT);
378 if(err)
380 ERROR(err);
384 /* Flush the caches */
385 CacheClearE(texthunk - sizeof(ULONG) - sizeof(BPTR),
386 header.a_text + sizeof(ULONG) + sizeof(BPTR),
387 CACRF_ClearI|CACRF_ClearD);
389 if(datahunk)
390 CacheClearE(datahunk - sizeof(ULONG) - sizeof(BPTR),
391 header.a_data + header.a_bss + sizeof(ULONG) + sizeof(BPTR),
392 CACRF_ClearI|CACRF_ClearD);
394 /* Ok, it is relocated, and ready to run. Remember to subtract
395 next hunk pointer from the text hunk.
398 D(bug("Text Address = %p\tData Address = %p\n", texthunk, datahunk));
400 if(header.a_entry != 0)
402 /* jumphunk is the address of the next hunk pointer. */
403 return MKBADDR(&jumphunk->next);
405 else
407 /* We don't need it */
408 AROS_CALL2(void *, functionarray[2] /* FreeMem */,
409 AROS_LCA(void *, jumphunk , A1),
410 AROS_LCA(ULONG , sizeof(struct JumpHunk) , D0),
411 struct Library *, (struct Library *)SysBase);
413 return MKBADDR((BPTR *)texthunk - 1);
416 end:
417 /* If we allocated a text or data hunk, then we should free them */
418 if(datahunk)
419 AROS_CALL2(void *, functionarray[2] /* FreeMem */,
420 AROS_LCA(void *, datahunk - sizeof(BPTR) - sizeof(ULONG) , A1),
421 AROS_LCA(ULONG , *(ULONG *)((ULONG)datahunk - sizeof(BPTR) - sizeof(ULONG)) , D0),
422 struct Library *, (struct Library *)SysBase);
424 if(texthunk)
425 AROS_CALL2(void *, functionarray[2] /* FreeMem */,
426 AROS_LCA(void *, texthunk - sizeof(BPTR) - sizeof(ULONG) , A1),
427 AROS_LCA(ULONG , *(ULONG *)((ULONG)texthunk - sizeof(BPTR) - sizeof(ULONG)) , D0),
428 struct Library *, (struct Library *)SysBase);
430 if(jumphunk)
431 AROS_CALL2(void *, functionarray[2] /* FreeMem */,
432 AROS_LCA(void *, jumphunk , A1),
433 AROS_LCA(ULONG , sizeof(struct JumpHunk) , D0),
434 struct Library *, (struct Library *)SysBase);
436 return (BPTR)NULL;