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