home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / nasm097s.zip / OUTAS86.C < prev    next >
C/C++ Source or Header  |  1997-10-02  |  15KB  |  560 lines

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