Hash even backend-specific directives, unify null functions
[platform/upstream/nasm.git] / output / outas86.c
1 /* ----------------------------------------------------------------------- *
2  *   
3  *   Copyright 1996-2009 The NASM Authors - All Rights Reserved
4  *   See the file AUTHORS included with the NASM distribution for
5  *   the specific copyright holders.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following
9  *   conditions are met:
10  *
11  *   * Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17  *     
18  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * ----------------------------------------------------------------------- */
33
34 /* 
35  * outas86.c    output routines for the Netwide Assembler to produce
36  *              Linux as86 (bin86-0.3) object files
37  */
38
39 #include "compiler.h"
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <ctype.h>
45 #include <inttypes.h>
46
47 #include "nasm.h"
48 #include "nasmlib.h"
49 #include "saa.h"
50 #include "raa.h"
51 #include "output/outform.h"
52 #include "output/outlib.h"
53
54 #ifdef OF_AS86
55
56 struct Piece {
57     struct Piece *next;
58     int type;                   /* 0 = absolute, 1 = seg, 2 = sym */
59     int32_t offset;             /* relative offset */
60     int number;                 /* symbol/segment number (4=bss) */
61     int32_t bytes;              /* size of reloc or of absolute data */
62     bool relative;              /* relative address? */
63 };
64
65 struct Symbol {
66     int32_t strpos;             /* string table position of name */
67     int flags;                  /* symbol flags */
68     int segment;                /* 4=bss at this point */
69     int32_t value;              /* address, or COMMON variable size */
70 };
71
72 /*
73  * Section IDs - used in Piece.number and Symbol.segment.
74  */
75 #define SECT_TEXT 0             /* text section */
76 #define SECT_DATA 3             /* data section */
77 #define SECT_BSS 4              /* bss section */
78
79 /*
80  * Flags used in Symbol.flags.
81  */
82 #define SYM_ENTRY (1<<8)
83 #define SYM_EXPORT (1<<7)
84 #define SYM_IMPORT (1<<6)
85 #define SYM_ABSOLUTE (1<<4)
86
87 struct Section {
88     struct SAA *data;
89     uint32_t datalen, size, len;
90     int32_t index;
91     struct Piece *head, *last, **tail;
92 };
93
94 static char as86_module[FILENAME_MAX];
95
96 static struct Section stext, sdata;
97 static uint32_t bsslen;
98 static int32_t bssindex;
99
100 static struct SAA *syms;
101 static uint32_t nsyms;
102
103 static struct RAA *bsym;
104
105 static struct SAA *strs;
106 static uint32_t strslen;
107
108 static int as86_reloc_size;
109
110 static FILE *as86fp;
111 static efunc error;
112
113 static void as86_write(void);
114 static void as86_write_section(struct Section *, int);
115 static int as86_add_string(char *name);
116 static void as86_sect_write(struct Section *, const uint8_t *,
117                             uint32_t);
118
119 static void as86_init(FILE * fp, efunc errfunc, ldfunc ldef, evalfunc eval)
120 {
121     as86fp = fp;
122     error = errfunc;
123     (void)ldef;                 /* placate optimisers */
124     (void)eval;
125     stext.data = saa_init(1L);
126     stext.datalen = 0L;
127     stext.head = stext.last = NULL;
128     stext.tail = &stext.head;
129     sdata.data = saa_init(1L);
130     sdata.datalen = 0L;
131     sdata.head = sdata.last = NULL;
132     sdata.tail = &sdata.head;
133     bsslen =
134         stext.len = stext.datalen = stext.size =
135         sdata.len = sdata.datalen = sdata.size = 0;
136     stext.index = seg_alloc();
137     sdata.index = seg_alloc();
138     bssindex = seg_alloc();
139     syms = saa_init((int32_t)sizeof(struct Symbol));
140     nsyms = 0;
141     bsym = raa_init();
142     strs = saa_init(1L);
143     strslen = 0;
144
145     as86_add_string(as86_module);
146 }
147
148 static void as86_cleanup(int debuginfo)
149 {
150     struct Piece *p;
151
152     (void)debuginfo;
153
154     as86_write();
155     saa_free(stext.data);
156     while (stext.head) {
157         p = stext.head;
158         stext.head = stext.head->next;
159         nasm_free(p);
160     }
161     saa_free(sdata.data);
162     while (sdata.head) {
163         p = sdata.head;
164         sdata.head = sdata.head->next;
165         nasm_free(p);
166     }
167     saa_free(syms);
168     raa_free(bsym);
169     saa_free(strs);
170 }
171
172 static int32_t as86_section_names(char *name, int pass, int *bits)
173 {
174
175     (void)pass;
176
177     /*
178      * Default is 16 bits.
179      */
180     if (!name)
181         *bits = 16;
182
183     if (!name)
184         return stext.index;
185
186     if (!strcmp(name, ".text"))
187         return stext.index;
188     else if (!strcmp(name, ".data"))
189         return sdata.index;
190     else if (!strcmp(name, ".bss"))
191         return bssindex;
192     else
193         return NO_SEG;
194 }
195
196 static int as86_add_string(char *name)
197 {
198     int pos = strslen;
199     int length = strlen(name);
200
201     saa_wbytes(strs, name, (int32_t)(length + 1));
202     strslen += 1 + length;
203
204     return pos;
205 }
206
207 static void as86_deflabel(char *name, int32_t segment, int64_t offset,
208                           int is_global, char *special)
209 {
210     bool is_start = false;
211     struct Symbol *sym;
212
213     if (special)
214         error(ERR_NONFATAL, "as86 format does not support any"
215               " special symbol types");
216
217
218     if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
219         if (strcmp(name, "..start")) {
220             error(ERR_NONFATAL, "unrecognised special symbol `%s'", name);
221             return;
222         } else {
223             is_start = true;
224         }
225     }
226
227     sym = saa_wstruct(syms);
228
229     sym->strpos = as86_add_string(name);
230     sym->flags = 0;
231
232     if (is_start)
233       sym->flags = SYM_ENTRY;
234
235     if (segment == NO_SEG)
236         sym->flags |= SYM_ABSOLUTE, sym->segment = 0;
237     else if (segment == stext.index)
238         sym->segment = SECT_TEXT;
239     else if (segment == sdata.index)
240         sym->segment = SECT_DATA;
241     else if (segment == bssindex)
242         sym->segment = SECT_BSS;
243     else {
244         sym->flags |= SYM_IMPORT;
245         sym->segment = 15;
246     }
247
248     if (is_global == 2)
249         sym->segment = 3;       /* already have IMPORT */
250
251     if (is_global && !(sym->flags & SYM_IMPORT))
252         sym->flags |= SYM_EXPORT;
253
254     sym->value = offset;
255
256     /*
257      * define the references from external-symbol segment numbers
258      * to these symbol records.
259      */
260     if (segment != NO_SEG && segment != stext.index &&
261         segment != sdata.index && segment != bssindex)
262         bsym = raa_write(bsym, segment, nsyms);
263
264     nsyms++;
265 }
266
267 static void as86_add_piece(struct Section *sect, int type, int32_t offset,
268                            int32_t segment, int32_t bytes, int relative)
269 {
270     struct Piece *p;
271
272     sect->len += bytes;
273
274     if (type == 0 && sect->last && sect->last->type == 0) {
275         sect->last->bytes += bytes;
276         return;
277     }
278
279     p = sect->last = *sect->tail = nasm_malloc(sizeof(struct Piece));
280     sect->tail = &p->next;
281     p->next = NULL;
282
283     p->type = type;
284     p->offset = offset;
285     p->bytes = bytes;
286     p->relative = relative;
287
288     if (type == 1 && segment == stext.index)
289         p->number = SECT_TEXT;
290     else if (type == 1 && segment == sdata.index)
291         p->number = SECT_DATA;
292     else if (type == 1 && segment == bssindex)
293         p->number = SECT_BSS;
294     else if (type == 1)
295         p->number = raa_read(bsym, segment), p->type = 2;
296 }
297
298 static void as86_out(int32_t segto, const void *data,
299                      enum out_type type, uint64_t size,
300                      int32_t segment, int32_t wrt)
301 {
302     struct Section *s;
303     int32_t offset;
304     uint8_t mydata[4], *p;
305
306     if (wrt != NO_SEG) {
307         wrt = NO_SEG;           /* continue to do _something_ */
308         error(ERR_NONFATAL, "WRT not supported by as86 output format");
309     }
310
311     /*
312      * handle absolute-assembly (structure definitions)
313      */
314     if (segto == NO_SEG) {
315         if (type != OUT_RESERVE)
316             error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
317                   " space");
318         return;
319     }
320
321     if (segto == stext.index)
322         s = &stext;
323     else if (segto == sdata.index)
324         s = &sdata;
325     else if (segto == bssindex)
326         s = NULL;
327     else {
328         error(ERR_WARNING, "attempt to assemble code in"
329               " segment %d: defaulting to `.text'", segto);
330         s = &stext;
331     }
332
333     if (!s && type != OUT_RESERVE) {
334         error(ERR_WARNING, "attempt to initialize memory in the"
335               " BSS section: ignored");
336         bsslen += realsize(type, size);
337         return;
338     }
339
340     if (type == OUT_RESERVE) {
341         if (s) {
342             error(ERR_WARNING, "uninitialized space declared in"
343                   " %s section: zeroing",
344                   (segto == stext.index ? "code" : "data"));
345             as86_sect_write(s, NULL, size);
346             as86_add_piece(s, 0, 0L, 0L, size, 0);
347         } else
348             bsslen += size;
349     } else if (type == OUT_RAWDATA) {
350         if (segment != NO_SEG)
351             error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
352         as86_sect_write(s, data, size);
353         as86_add_piece(s, 0, 0L, 0L, size, 0);
354     } else if (type == OUT_ADDRESS) {
355         if (segment != NO_SEG) {
356             if (segment % 2) {
357                 error(ERR_NONFATAL, "as86 format does not support"
358                       " segment base references");
359             } else {
360                 offset = *(int64_t *)data;
361                 as86_add_piece(s, 1, offset, segment, size, 0);
362             }
363         } else {
364             p = mydata;
365             WRITELONG(p, *(int64_t *)data);
366             as86_sect_write(s, data, size);
367             as86_add_piece(s, 0, 0L, 0L, size, 0);
368         }
369     } else if (type == OUT_REL2ADR) {
370         if (segment == segto)
371             error(ERR_PANIC, "intra-segment OUT_REL2ADR");
372         if (segment != NO_SEG) {
373             if (segment % 2) {
374                 error(ERR_NONFATAL, "as86 format does not support"
375                       " segment base references");
376             } else {
377                 offset = *(int64_t *)data;
378                 as86_add_piece(s, 1, offset - size + 2, segment, 2L,
379                                1);
380             }
381         }
382     } else if (type == OUT_REL4ADR) {
383         if (segment == segto)
384             error(ERR_PANIC, "intra-segment OUT_REL4ADR");
385         if (segment != NO_SEG) {
386             if (segment % 2) {
387                 error(ERR_NONFATAL, "as86 format does not support"
388                       " segment base references");
389             } else {
390                 offset = *(int64_t *)data;
391                 as86_add_piece(s, 1, offset - size + 4, segment, 4L,
392                                1);
393             }
394         }
395     }
396 }
397
398 static void as86_write(void)
399 {
400     uint32_t i;
401     int32_t symlen, seglen, segsize;
402
403     /*
404      * First, go through the symbol records working out how big
405      * each will be. Also fix up BSS references at this time, and
406      * set the flags words up completely.
407      */
408     symlen = 0;
409     saa_rewind(syms);
410     for (i = 0; i < nsyms; i++) {
411         struct Symbol *sym = saa_rstruct(syms);
412         if (sym->segment == SECT_BSS)
413             sym->segment = SECT_DATA, sym->value += sdata.len;
414         sym->flags |= sym->segment;
415         if (sym->value == 0)
416             sym->flags |= 0 << 14, symlen += 4;
417         else if (sym->value >= 0 && sym->value <= 255)
418             sym->flags |= 1 << 14, symlen += 5;
419         else if (sym->value >= 0 && sym->value <= 65535L)
420             sym->flags |= 2 << 14, symlen += 6;
421         else
422             sym->flags |= 3 << 14, symlen += 8;
423     }
424
425     /*
426      * Now do the same for the segments, and get the segment size
427      * descriptor word at the same time.
428      */
429     seglen = segsize = 0;
430     if ((uint32_t)stext.len > 65535L)
431         segsize |= 0x03000000L, seglen += 4;
432     else
433         segsize |= 0x02000000L, seglen += 2;
434     if ((uint32_t)sdata.len > 65535L)
435         segsize |= 0xC0000000L, seglen += 4;
436     else
437         segsize |= 0x80000000L, seglen += 2;
438
439     /*
440      * Emit the as86 header.
441      */
442     fwriteint32_t(0x000186A3L, as86fp);
443     fputc(0x2A, as86fp);
444     fwriteint32_t(27 + symlen + seglen + strslen, as86fp); /* header length */
445     fwriteint32_t(stext.len + sdata.len + bsslen, as86fp);
446     fwriteint16_t(strslen, as86fp);
447     fwriteint16_t(0, as86fp);     /* class = revision = 0 */
448     fwriteint32_t(0x55555555L, as86fp);    /* segment max sizes: always this */
449     fwriteint32_t(segsize, as86fp);        /* segment size descriptors */
450     if (segsize & 0x01000000L)
451         fwriteint32_t(stext.len, as86fp);
452     else
453         fwriteint16_t(stext.len, as86fp);
454     if (segsize & 0x40000000L)
455         fwriteint32_t(sdata.len + bsslen, as86fp);
456     else
457         fwriteint16_t(sdata.len + bsslen, as86fp);
458     fwriteint16_t(nsyms, as86fp);
459
460     /*
461      * Write the symbol table.
462      */
463     saa_rewind(syms);
464     for (i = 0; i < nsyms; i++) {
465         struct Symbol *sym = saa_rstruct(syms);
466         fwriteint16_t(sym->strpos, as86fp);
467         fwriteint16_t(sym->flags, as86fp);
468         switch (sym->flags & (3 << 14)) {
469         case 0 << 14:
470             break;
471         case 1 << 14:
472             fputc(sym->value, as86fp);
473             break;
474         case 2 << 14:
475             fwriteint16_t(sym->value, as86fp);
476             break;
477         case 3 << 14:
478             fwriteint32_t(sym->value, as86fp);
479             break;
480         }
481     }
482
483     /*
484      * Write out the string table.
485      */
486     saa_fpwrite(strs, as86fp);
487
488     /*
489      * Write the program text.
490      */
491     as86_reloc_size = -1;
492     as86_write_section(&stext, SECT_TEXT);
493     as86_write_section(&sdata, SECT_DATA);
494     /*
495      * Append the BSS section to the .data section
496      */
497     if (bsslen > 65535L) {
498         fputc(0x13, as86fp);
499         fwriteint32_t(bsslen, as86fp);
500     } else if (bsslen > 255) {
501         fputc(0x12, as86fp);
502         fwriteint16_t(bsslen, as86fp);
503     } else if (bsslen) {
504         fputc(0x11, as86fp);
505         fputc(bsslen, as86fp);
506     }
507
508     fputc(0, as86fp);           /* termination */
509 }
510
511 static void as86_set_rsize(int size)
512 {
513     if (as86_reloc_size != size) {
514         switch (as86_reloc_size = size) {
515         case 1:
516             fputc(0x01, as86fp);
517             break;
518         case 2:
519             fputc(0x02, as86fp);
520             break;
521         case 4:
522             fputc(0x03, as86fp);
523             break;
524         default:
525             error(ERR_PANIC, "bizarre relocation size %d", size);
526         }
527     }
528 }
529
530 static void as86_write_section(struct Section *sect, int index)
531 {
532     struct Piece *p;
533     uint32_t s;
534     int32_t length;
535
536     fputc(0x20 + index, as86fp);        /* select the right section */
537
538     saa_rewind(sect->data);
539
540     for (p = sect->head; p; p = p->next)
541         switch (p->type) {
542         case 0:
543             /*
544              * Absolute data. Emit it in chunks of at most 64
545              * bytes.
546              */
547             length = p->bytes;
548             do {
549                 char buf[64];
550                 int32_t tmplen = (length > 64 ? 64 : length);
551                 fputc(0x40 | (tmplen & 0x3F), as86fp);
552                 saa_rnbytes(sect->data, buf, tmplen);
553                 fwrite(buf, 1, tmplen, as86fp);
554                 length -= tmplen;
555             } while (length > 0);
556             break;
557         case 1:
558             /*
559              * A segment-type relocation. First fix up the BSS.
560              */
561             if (p->number == SECT_BSS)
562                 p->number = SECT_DATA, p->offset += sdata.len;
563             as86_set_rsize(p->bytes);
564             fputc(0x80 | (p->relative ? 0x20 : 0) | p->number, as86fp);
565             if (as86_reloc_size == 2)
566                 fwriteint16_t(p->offset, as86fp);
567             else
568                 fwriteint32_t(p->offset, as86fp);
569             break;
570         case 2:
571             /*
572              * A symbol-type relocation.
573              */
574             as86_set_rsize(p->bytes);
575             s = p->offset;
576             if (s > 65535L)
577                 s = 3;
578             else if (s > 255)
579                 s = 2;
580             else if (s > 0)
581                 s = 1;
582             else
583                 s = 0;
584             fputc(0xC0 |
585                   (p->relative ? 0x20 : 0) |
586                   (p->number > 255 ? 0x04 : 0) | s, as86fp);
587             if (p->number > 255)
588                 fwriteint16_t(p->number, as86fp);
589             else
590                 fputc(p->number, as86fp);
591             switch ((int)s) {
592             case 0:
593                 break;
594             case 1:
595                 fputc(p->offset, as86fp);
596                 break;
597             case 2:
598                 fwriteint16_t(p->offset, as86fp);
599                 break;
600             case 3:
601                 fwriteint32_t(p->offset, as86fp);
602                 break;
603             }
604             break;
605         }
606 }
607
608 static void as86_sect_write(struct Section *sect,
609                             const uint8_t *data, uint32_t len)
610 {
611     saa_wbytes(sect->data, data, len);
612     sect->datalen += len;
613 }
614
615 static int32_t as86_segbase(int32_t segment)
616 {
617     return segment;
618 }
619
620 static void as86_filename(char *inname, char *outname, efunc error)
621 {
622     char *p;
623
624     if ((p = strrchr(inname, '.')) != NULL) {
625         strncpy(as86_module, inname, p - inname);
626         as86_module[p - inname] = '\0';
627     } else
628         strcpy(as86_module, inname);
629
630     standard_extension(inname, outname, ".o", error);
631 }
632
633 extern macros_t as86_stdmac[];
634
635 struct ofmt of_as86 = {
636     "Linux as86 (bin86 version 0.3) object files",
637     "as86",
638     0,
639     null_debug_arr,
640     &null_debug_form,
641     as86_stdmac,
642     as86_init,
643     null_setinfo,
644     as86_out,
645     as86_deflabel,
646     as86_section_names,
647     as86_segbase,
648     null_directive,
649     as86_filename,
650     as86_cleanup
651 };
652
653 #endif                          /* OF_AS86 */