]> git.saurik.com Git - apple/boot.git/blob - i386/nasm/outas86.c
boot-80.1.tar.gz
[apple/boot.git] / i386 / nasm / outas86.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /* outas86.c output routines for the Netwide Assembler to produce
25 * Linux as86 (bin86-0.3) object files
26 *
27 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
28 * Julian Hall. All rights reserved. The software is
29 * redistributable under the licence given in the file "Licence"
30 * distributed in the NASM archive.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37
38 #include "nasm.h"
39 #include "nasmlib.h"
40 #include "outform.h"
41
42 #ifdef OF_AS86
43
44 struct Piece {
45 struct Piece *next;
46 int type; /* 0 = absolute, 1 = seg, 2 = sym */
47 long offset; /* relative offset */
48 int number; /* symbol/segment number (4=bss) */
49 long bytes; /* size of reloc or of absolute data */
50 int relative; /* TRUE or FALSE */
51 };
52
53 struct Symbol {
54 long strpos; /* string table position of name */
55 int flags; /* symbol flags */
56 int segment; /* 4=bss at this point */
57 long value; /* address, or COMMON variable size */
58 };
59
60 /*
61 * Section IDs - used in Piece.number and Symbol.segment.
62 */
63 #define SECT_TEXT 0 /* text section */
64 #define SECT_DATA 3 /* data section */
65 #define SECT_BSS 4 /* bss section */
66
67 /*
68 * Flags used in Symbol.flags.
69 */
70 #define SYM_ENTRY (1<<8)
71 #define SYM_EXPORT (1<<7)
72 #define SYM_IMPORT (1<<6)
73 #define SYM_ABSOLUTE (1<<4)
74
75 struct Section {
76 struct SAA *data;
77 unsigned long datalen, size, len;
78 long index;
79 struct Piece *head, *last, **tail;
80 };
81
82 static char as86_module[FILENAME_MAX];
83
84 static struct Section stext, sdata;
85 static unsigned long bsslen;
86 static long bssindex;
87
88 static struct SAA *syms;
89 static unsigned long nsyms;
90
91 static struct RAA *bsym;
92
93 static struct SAA *strs;
94 static unsigned long strslen;
95
96 static int as86_reloc_size;
97
98 static FILE *as86fp;
99 static efunc error;
100
101 static void as86_write(void);
102 static void as86_write_section (struct Section *, int);
103 static int as86_add_string (char *name);
104 static void as86_sect_write(struct Section *, unsigned char *, unsigned long);
105
106 static void as86_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
107 as86fp = fp;
108 error = errfunc;
109 (void) ldef; /* placate optimisers */
110 stext.data = saa_init(1L); stext.datalen = 0L;
111 stext.head = stext.last = NULL;
112 stext.tail = &stext.head;
113 sdata.data = saa_init(1L); sdata.datalen = 0L;
114 sdata.head = sdata.last = NULL;
115 sdata.tail = &sdata.head;
116 bsslen =
117 stext.len = stext.datalen = stext.size =
118 sdata.len = sdata.datalen = sdata.size = 0;
119 stext.index = seg_alloc();
120 sdata.index = seg_alloc();
121 bssindex = seg_alloc();
122 syms = saa_init((long)sizeof(struct Symbol));
123 nsyms = 0;
124 bsym = raa_init();
125 strs = saa_init(1L);
126 strslen = 0;
127
128 as86_add_string (as86_module);
129 }
130
131 static void as86_cleanup(void) {
132 struct Piece *p;
133
134 as86_write();
135 fclose (as86fp);
136 saa_free (stext.data);
137 while (stext.head) {
138 p = stext.head;
139 stext.head = stext.head->next;
140 nasm_free (p);
141 }
142 saa_free (sdata.data);
143 while (sdata.head) {
144 p = sdata.head;
145 sdata.head = sdata.head->next;
146 nasm_free (p);
147 }
148 saa_free (syms);
149 raa_free (bsym);
150 saa_free (strs);
151 }
152
153 static long as86_section_names (char *name, int pass, int *bits) {
154 /*
155 * Default is 16 bits.
156 */
157 if (!name)
158 *bits = 16;
159
160 if (!name)
161 return stext.index;
162
163 if (!strcmp(name, ".text"))
164 return stext.index;
165 else if (!strcmp(name, ".data"))
166 return sdata.index;
167 else if (!strcmp(name, ".bss"))
168 return bssindex;
169 else
170 return NO_SEG;
171 }
172
173 static int as86_add_string (char *name) {
174 int pos = strslen;
175 int length = strlen(name);
176
177 saa_wbytes (strs, name, (long)(length+1));
178 strslen += 1+length;
179
180 return pos;
181 }
182
183 static void as86_deflabel (char *name, long segment, long offset,
184 int is_global, char *special) {
185 struct Symbol *sym;
186
187 if (special)
188 error (ERR_NONFATAL, "as86 format does not support any"
189 " special symbol types");
190
191 if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
192 error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
193 return;
194 }
195
196 sym = saa_wstruct (syms);
197
198 sym->strpos = as86_add_string (name);
199 sym->flags = 0;
200 if (segment == NO_SEG)
201 sym->flags |= SYM_ABSOLUTE, sym->segment = 0;
202 else if (segment == stext.index)
203 sym->segment = SECT_TEXT;
204 else if (segment == sdata.index)
205 sym->segment = SECT_DATA;
206 else if (segment == bssindex)
207 sym->segment = SECT_BSS;
208 else {
209 sym->flags |= SYM_IMPORT;
210 sym->segment = 15;
211 }
212
213 if (is_global == 2)
214 sym->segment = 3; /* already have IMPORT */
215
216 if (is_global && !(sym->flags & SYM_IMPORT))
217 sym->flags |= SYM_EXPORT;
218
219 sym->value = offset;
220
221 /*
222 * define the references from external-symbol segment numbers
223 * to these symbol records.
224 */
225 if (segment != NO_SEG && segment != stext.index &&
226 segment != sdata.index && segment != bssindex)
227 bsym = raa_write (bsym, segment, nsyms);
228
229 nsyms++;
230 }
231
232 static void as86_add_piece (struct Section *sect, int type, long offset,
233 long segment, long bytes, int relative) {
234 struct Piece *p;
235
236 sect->len += bytes;
237
238 if (type == 0 && sect->last && sect->last->type == 0) {
239 sect->last->bytes += bytes;
240 return;
241 }
242
243 p = sect->last = *sect->tail = nasm_malloc(sizeof(struct Piece));
244 sect->tail = &p->next;
245 p->next = NULL;
246
247 p->type = type;
248 p->offset = offset;
249 p->bytes = bytes;
250 p->relative = relative;
251
252 if (type == 1 && segment == stext.index)
253 p->number = SECT_TEXT;
254 else if (type == 1 && segment == sdata.index)
255 p->number = SECT_DATA;
256 else if (type == 1 && segment == bssindex)
257 p->number = SECT_BSS;
258 else if (type == 1)
259 p->number = raa_read (bsym, segment), p->type = 2;
260 }
261
262 static void as86_out (long segto, void *data, unsigned long type,
263 long segment, long wrt) {
264 struct Section *s;
265 long realbytes = type & OUT_SIZMASK;
266 long offset;
267 unsigned char mydata[4], *p;
268
269 if (wrt != NO_SEG) {
270 wrt = NO_SEG; /* continue to do _something_ */
271 error (ERR_NONFATAL, "WRT not supported by as86 output format");
272 }
273
274 type &= OUT_TYPMASK;
275
276 /*
277 * handle absolute-assembly (structure definitions)
278 */
279 if (segto == NO_SEG) {
280 if (type != OUT_RESERVE)
281 error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
282 " space");
283 return;
284 }
285
286 if (segto == stext.index)
287 s = &stext;
288 else if (segto == sdata.index)
289 s = &sdata;
290 else if (segto == bssindex)
291 s = NULL;
292 else {
293 error(ERR_WARNING, "attempt to assemble code in"
294 " segment %d: defaulting to `.text'", segto);
295 s = &stext;
296 }
297
298 if (!s && type != OUT_RESERVE) {
299 error(ERR_WARNING, "attempt to initialise memory in the"
300 " BSS section: ignored");
301 if (type == OUT_REL2ADR)
302 realbytes = 2;
303 else if (type == OUT_REL4ADR)
304 realbytes = 4;
305 bsslen += realbytes;
306 return;
307 }
308
309 if (type == OUT_RESERVE) {
310 if (s) {
311 error(ERR_WARNING, "uninitialised space declared in"
312 " %s section: zeroing",
313 (segto == stext.index ? "code" : "data"));
314 as86_sect_write (s, NULL, realbytes);
315 as86_add_piece (s, 0, 0L, 0L, realbytes, 0);
316 } else
317 bsslen += realbytes;
318 } else if (type == OUT_RAWDATA) {
319 if (segment != NO_SEG)
320 error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
321 as86_sect_write (s, data, realbytes);
322 as86_add_piece (s, 0, 0L, 0L, realbytes, 0);
323 } else if (type == OUT_ADDRESS) {
324 if (segment != NO_SEG) {
325 if (segment % 2) {
326 error(ERR_NONFATAL, "as86 format does not support"
327 " segment base references");
328 } else{
329 offset = * (long *) data;
330 as86_add_piece (s, 1, offset, segment, realbytes, 0);
331 }
332 } else {
333 p = mydata;
334 WRITELONG (p, * (long *) data);
335 as86_sect_write (s, data, realbytes);
336 as86_add_piece (s, 0, 0L, 0L, realbytes, 0);
337 }
338 } else if (type == OUT_REL2ADR) {
339 if (segment == segto)
340 error(ERR_PANIC, "intra-segment OUT_REL2ADR");
341 if (segment != NO_SEG) {
342 if (segment % 2) {
343 error(ERR_NONFATAL, "as86 format does not support"
344 " segment base references");
345 } else {
346 offset = * (long *) data;
347 as86_add_piece (s, 1, offset-realbytes+2, segment, 2L, 1);
348 }
349 }
350 } else if (type == OUT_REL4ADR) {
351 if (segment == segto)
352 error(ERR_PANIC, "intra-segment OUT_REL4ADR");
353 if (segment != NO_SEG) {
354 if (segment % 2) {
355 error(ERR_NONFATAL, "as86 format does not support"
356 " segment base references");
357 } else {
358 offset = * (long *) data;
359 as86_add_piece (s, 1, offset-realbytes+4, segment, 4L, 1);
360 }
361 }
362 }
363 }
364
365 static void as86_write(void) {
366 int i;
367 long symlen, seglen, segsize;
368
369 /*
370 * First, go through the symbol records working out how big
371 * each will be. Also fix up BSS references at this time, and
372 * set the flags words up completely.
373 */
374 symlen = 0;
375 saa_rewind (syms);
376 for (i = 0; i < nsyms; i++) {
377 struct Symbol *sym = saa_rstruct (syms);
378 if (sym->segment == SECT_BSS)
379 sym->segment = SECT_DATA, sym->value += sdata.len;
380 sym->flags |= sym->segment;
381 if (sym->value == 0)
382 sym->flags |= 0 << 14, symlen += 4;
383 else if (sym->value >= 0 && sym->value <= 255)
384 sym->flags |= 1 << 14, symlen += 5;
385 else if (sym->value >= 0 && sym->value <= 65535L)
386 sym->flags |= 2 << 14, symlen += 6;
387 else
388 sym->flags |= 3 << 14, symlen += 8;
389 }
390
391 /*
392 * Now do the same for the segments, and get the segment size
393 * descriptor word at the same time.
394 */
395 seglen = segsize = 0;
396 if ((unsigned long) stext.len > 65535L)
397 segsize |= 0x03000000L, seglen += 4;
398 else
399 segsize |= 0x02000000L, seglen += 2;
400 if ((unsigned long) sdata.len > 65535L)
401 segsize |= 0xC0000000L, seglen += 4;
402 else
403 segsize |= 0x80000000L, seglen += 2;
404
405 /*
406 * Emit the as86 header.
407 */
408 fwritelong (0x000186A3L, as86fp);
409 fputc (0x2A, as86fp);
410 fwritelong (27+symlen+seglen+strslen, as86fp); /* header length */
411 fwritelong (stext.len+sdata.len, as86fp);
412 fwriteshort (strslen, as86fp);
413 fwriteshort (0, as86fp); /* class = revision = 0 */
414 fwritelong (0x55555555L, as86fp); /* segment max sizes: always this */
415 fwritelong (segsize, as86fp); /* segment size descriptors */
416 if (segsize & 0x01000000L)
417 fwritelong (stext.len, as86fp);
418 else
419 fwriteshort (stext.len, as86fp);
420 if (segsize & 0x40000000L)
421 fwritelong (sdata.len, as86fp);
422 else
423 fwriteshort (sdata.len, as86fp);
424 fwriteshort (nsyms, as86fp);
425
426 /*
427 * Write the symbol table.
428 */
429 saa_rewind (syms);
430 for (i = 0; i < nsyms; i++) {
431 struct Symbol *sym = saa_rstruct (syms);
432 fwriteshort (sym->strpos, as86fp);
433 fwriteshort (sym->flags, as86fp);
434 switch (sym->flags & (3<<14)) {
435 case 0<<14: break;
436 case 1<<14: fputc (sym->value, as86fp); break;
437 case 2<<14: fwriteshort (sym->value, as86fp); break;
438 case 3<<14: fwritelong (sym->value, as86fp); break;
439 }
440 }
441
442 /*
443 * Write out the string table.
444 */
445 saa_fpwrite (strs, as86fp);
446
447 /*
448 * Write the program text.
449 */
450 as86_reloc_size = -1;
451 as86_write_section (&stext, SECT_TEXT);
452 as86_write_section (&sdata, SECT_DATA);
453 fputc (0, as86fp); /* termination */
454 }
455
456 static void as86_set_rsize (int size) {
457 if (as86_reloc_size != size) {
458 switch (as86_reloc_size = size) {
459 case 1: fputc (0x01, as86fp); break;
460 case 2: fputc (0x02, as86fp); break;
461 case 4: fputc (0x03, as86fp); break;
462 default: error (ERR_PANIC, "bizarre relocation size %d", size);
463 }
464 }
465 }
466
467 static void as86_write_section (struct Section *sect, int index) {
468 struct Piece *p;
469 unsigned long s;
470 long length;
471
472 fputc (0x20+index, as86fp); /* select the right section */
473
474 saa_rewind (sect->data);
475
476 for (p = sect->head; p; p = p->next)
477 switch (p->type) {
478 case 0:
479 /*
480 * Absolute data. Emit it in chunks of at most 64
481 * bytes.
482 */
483 length = p->bytes;
484 do {
485 char buf[64];
486 long tmplen = (length > 64 ? 64 : length);
487 fputc (0x40 | (tmplen & 0x3F), as86fp);
488 saa_rnbytes (sect->data, buf, tmplen);
489 fwrite (buf, 1, tmplen, as86fp);
490 length -= tmplen;
491 } while (length > 0);
492 break;
493 case 1:
494 /*
495 * A segment-type relocation. First fix up the BSS.
496 */
497 if (p->number == SECT_BSS)
498 p->number = SECT_DATA, p->offset += sdata.len;
499 as86_set_rsize (p->bytes);
500 fputc (0x80 | (p->relative ? 0x20 : 0) | p->number, as86fp);
501 if (as86_reloc_size == 2)
502 fwriteshort (p->offset, as86fp);
503 else
504 fwritelong (p->offset, as86fp);
505 break;
506 case 2:
507 /*
508 * A symbol-type relocation.
509 */
510 as86_set_rsize (p->bytes);
511 s = p->offset;
512 if (s > 65535L)
513 s = 3;
514 else if (s > 255)
515 s = 2;
516 else if (s > 0)
517 s = 1;
518 else
519 s = 0;
520 fputc (0xC0 |
521 (p->relative ? 0x20 : 0) |
522 (p->number > 255 ? 0x04 : 0) | s, as86fp);
523 if (p->number > 255)
524 fwriteshort (p->number, as86fp);
525 else
526 fputc (p->number, as86fp);
527 switch ((int)s) {
528 case 0: break;
529 case 1: fputc (p->offset, as86fp); break;
530 case 2: fwriteshort (p->offset, as86fp); break;
531 case 3: fwritelong (p->offset, as86fp); break;
532 }
533 break;
534 }
535 }
536
537 static void as86_sect_write (struct Section *sect,
538 unsigned char *data, unsigned long len) {
539 saa_wbytes (sect->data, data, len);
540 sect->datalen += len;
541 }
542
543 static long as86_segbase (long segment) {
544 return segment;
545 }
546
547 static int as86_directive (char *directive, char *value, int pass) {
548 return 0;
549 }
550
551 static void as86_filename (char *inname, char *outname, efunc error) {
552 char *p;
553
554 if ( (p = strrchr (inname, '.')) != NULL) {
555 strncpy (as86_module, inname, p-inname);
556 as86_module[p-inname] = '\0';
557 } else
558 strcpy (as86_module, inname);
559
560 standard_extension (inname, outname, ".o", error);
561 }
562
563 static char *as86_stdmac[] = {
564 "%define __SECT__ [section .text]",
565 NULL
566 };
567
568 struct ofmt of_as86 = {
569 "Linux as86 (bin86 version 0.3) object files",
570 "as86",
571 as86_stdmac,
572 as86_init,
573 as86_out,
574 as86_deflabel,
575 as86_section_names,
576 as86_segbase,
577 as86_directive,
578 as86_filename,
579 as86_cleanup
580 };
581
582 #endif /* OF_AS86 */