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

  1. /* outbin.c    output routines for the Netwide Assembler to produce
  2.  *        flat-form binary 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_BIN
  20.  
  21. static FILE *fp;
  22. static efunc error;
  23.  
  24. static struct Section {
  25.     struct SAA *contents;
  26.     long length;
  27.     long index;
  28. } textsect, datasect;
  29. static long bsslen, bssindex;
  30.  
  31. static struct Reloc {
  32.     struct Reloc *next;
  33.     long posn;
  34.     long bytes;
  35.     long secref;
  36.     long secrel;
  37.     struct Section *target;
  38. } *relocs, **reloctail;
  39.  
  40. static long data_align, bss_align;
  41.  
  42. static long start_point;
  43.  
  44. static void add_reloc (struct Section *s, long bytes, long secref,
  45.                long secrel) {
  46.     struct Reloc *r;
  47.  
  48.     r = *reloctail = nasm_malloc(sizeof(struct Reloc));
  49.     reloctail = &r->next;
  50.     r->next = NULL;
  51.     r->posn = s->length;
  52.     r->bytes = bytes;
  53.     r->secref = secref;
  54.     r->secrel = secrel;
  55.     r->target = s;
  56. }
  57.  
  58. static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) {
  59.     fp = afp;
  60.  
  61.     error = errfunc;
  62.     (void) ldef;               /* placate optimisers */
  63.  
  64.     start_point = 0L;               /* default */
  65.     textsect.contents = saa_init(1L);
  66.     datasect.contents = saa_init(1L);
  67.     textsect.length = datasect.length = 0;
  68.     textsect.index = seg_alloc();
  69.     datasect.index = seg_alloc();
  70.     bsslen = 0;
  71.     bssindex = seg_alloc();
  72.     relocs = NULL;
  73.     reloctail = &relocs;
  74.     data_align = bss_align = 4;
  75. }
  76.  
  77. static void bin_cleanup (void) {
  78.     struct Reloc *r;
  79.     long datapos, datagap, bsspos;
  80.  
  81.     datapos = start_point + textsect.length;
  82.     datapos = (datapos + data_align-1) & ~(data_align-1);
  83.     datagap = datapos - (start_point + textsect.length);
  84.     bsspos = datapos + datasect.length;
  85.     bsspos = (bsspos + bss_align-1) & ~(bss_align-1);
  86.  
  87.     saa_rewind (textsect.contents);
  88.     saa_rewind (datasect.contents);
  89.  
  90.     for (r = relocs; r; r = r->next) {
  91.     unsigned char *p, *q, mydata[4];
  92.     long l;
  93.  
  94.     saa_fread (r->target->contents, r->posn, mydata, r->bytes);
  95.     p = q = mydata;
  96.     l = *p++;
  97.     if (r->bytes > 1) {
  98.         l += ((long)*p++) << 8;
  99.         if (r->bytes == 4) {
  100.         l += ((long)*p++) << 16;
  101.         l += ((long)*p++) << 24;
  102.         }
  103.     }
  104.  
  105.     if (r->secref == textsect.index)
  106.         l += start_point;
  107.     else if (r->secref == datasect.index)
  108.         l += datapos;
  109.     else if (r->secref == bssindex)
  110.         l += bsspos;
  111.  
  112.     if (r->secrel == textsect.index)
  113.         l -= start_point;
  114.     else if (r->secrel == datasect.index)
  115.         l -= datapos;
  116.     else if (r->secrel == bssindex)
  117.         l -= bsspos;
  118.  
  119.     if (r->bytes == 4)
  120.         WRITELONG(q, l);
  121.     else if (r->bytes == 2)
  122.         WRITESHORT(q, l);
  123.     else
  124.         *q++ = l & 0xFF;
  125.     saa_fwrite (r->target->contents, r->posn, mydata, r->bytes);
  126.     }
  127.     saa_fpwrite (textsect.contents, fp);
  128.     if (datasect.length > 0) {
  129.     while (datagap--)
  130.         fputc('\0', fp);
  131.     saa_fpwrite (datasect.contents, fp);
  132.     }
  133.     fclose (fp);
  134.     saa_free (textsect.contents);
  135.     saa_free (datasect.contents);
  136.     while (relocs) {
  137.     r = relocs->next;
  138.     nasm_free (relocs);
  139.     relocs = r;
  140.     }
  141. }
  142.  
  143. static void bin_out (long segto, void *data, unsigned long type,
  144.              long segment, long wrt) {
  145.     unsigned char *p, mydata[4];
  146.     struct Section *s;
  147.     long realbytes;
  148.  
  149.     if (wrt != NO_SEG) {
  150.     wrt = NO_SEG;               /* continue to do _something_ */
  151.     error (ERR_NONFATAL, "WRT not supported by binary output format");
  152.     }
  153.  
  154.     /*
  155.      * handle absolute-assembly (structure definitions)
  156.      */
  157.     if (segto == NO_SEG) {
  158.     if ((type & OUT_TYPMASK) != OUT_RESERVE)
  159.         error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
  160.            " space");
  161.     return;
  162.     }
  163.  
  164.     if (segto == bssindex) {           /* BSS */
  165.     if ((type & OUT_TYPMASK) != OUT_RESERVE)
  166.         error(ERR_WARNING, "attempt to initialise memory in the"
  167.           " BSS section: ignored");
  168.     s = NULL;
  169.     } else if (segto == textsect.index) {
  170.     s = &textsect;
  171.     } else if (segto == datasect.index) {
  172.     s = &datasect;
  173.     } else {
  174.     error(ERR_WARNING, "attempt to assemble code in"
  175.           " segment %d: defaulting to `.text'", segto);
  176.     s = &textsect;
  177.     }
  178.  
  179.     if ((type & OUT_TYPMASK) == OUT_ADDRESS) {
  180.     if (segment != NO_SEG &&
  181.         segment != textsect.index &&
  182.         segment != datasect.index &&
  183.         segment != bssindex) {
  184.         if (segment % 2)
  185.         error(ERR_NONFATAL, "binary output format does not support"
  186.               " segment base references");
  187.         else
  188.         error(ERR_NONFATAL, "binary output format does not support"
  189.               " external references");
  190.         segment = NO_SEG;
  191.     }
  192.     if (s) {
  193.         if (segment != NO_SEG)
  194.         add_reloc (s, type & OUT_SIZMASK, segment, -1L);
  195.         p = mydata;
  196.         if ((type & OUT_SIZMASK) == 4)
  197.         WRITELONG (p, *(long *)data);
  198.         else
  199.         WRITESHORT (p, *(long *)data);
  200.         saa_wbytes (s->contents, mydata, type & OUT_SIZMASK);
  201.         s->length += type & OUT_SIZMASK;
  202.     } else
  203.         bsslen += type & OUT_SIZMASK;
  204.     } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) {
  205.     type &= OUT_SIZMASK;
  206.     p = data;
  207.     if (s) {
  208.         saa_wbytes (s->contents, data, type);
  209.         s->length += type;
  210.     } else
  211.         bsslen += type;
  212.     } else if ((type & OUT_TYPMASK) == OUT_RESERVE) {
  213.     if (s) {
  214.         error(ERR_WARNING, "uninitialised space declared in"
  215.           " %s section: zeroing",
  216.           (segto == textsect.index ? "code" : "data"));
  217.     }
  218.     type &= OUT_SIZMASK;
  219.     if (s) {
  220.         saa_wbytes (s->contents, NULL, type);
  221.         s->length += type;
  222.     } else
  223.         bsslen += type;
  224.     } else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
  225.            (type & OUT_TYPMASK) == OUT_REL4ADR) {
  226.     realbytes = ((type & OUT_TYPMASK) == OUT_REL4ADR ? 4 : 2);
  227.     if (segment != NO_SEG &&
  228.         segment != textsect.index &&
  229.         segment != datasect.index &&
  230.         segment != bssindex) {
  231.         if (segment % 2)
  232.         error(ERR_NONFATAL, "binary output format does not support"
  233.               " segment base references");
  234.         else
  235.         error(ERR_NONFATAL, "binary output format does not support"
  236.               " external references");
  237.         segment = NO_SEG;
  238.     }
  239.     if (s) {
  240.         add_reloc (s, realbytes, segment, segto);
  241.         p = mydata;
  242.         if (realbytes == 4)
  243.         WRITELONG (p, *(long*)data - realbytes - s->length);
  244.         else
  245.         WRITESHORT (p, *(long*)data - realbytes - s->length);
  246.         saa_wbytes (s->contents, mydata, realbytes);
  247.         s->length += realbytes;
  248.     } else
  249.         bsslen += realbytes;
  250.     }
  251. }
  252.  
  253. static void bin_deflabel (char *name, long segment, long offset,
  254.               int is_global, char *special) {
  255.  
  256.     if (special)
  257.     error (ERR_NONFATAL, "binary format does not support any"
  258.            " special symbol types");
  259.  
  260.     if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
  261.     error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
  262.     return;
  263.     }
  264.  
  265.     if (is_global == 2) {
  266.     error (ERR_NONFATAL, "binary output format does not support common"
  267.            " variables");
  268.     }
  269. }
  270.  
  271. static long bin_secname (char *name, int pass, int *bits) {
  272.     int sec_index;
  273.     long *sec_align;
  274.     char *p;
  275.  
  276.     /*
  277.      * Default is 16 bits.
  278.      */
  279.     if (!name)
  280.     *bits = 16;
  281.  
  282.     if (!name)
  283.     return textsect.index;
  284.  
  285.     p = name;
  286.     while (*p && !isspace(*p)) p++;
  287.     if (*p) *p++ = '\0';
  288.     if (!strcmp(name, ".text")) {
  289.     sec_index = textsect.index;
  290.     sec_align = NULL;
  291.     } else if (!strcmp(name, ".data")) {
  292.     sec_index = datasect.index;
  293.     sec_align = &data_align;
  294.     } else if (!strcmp(name, ".bss")) {
  295.     sec_index = bssindex;
  296.     sec_align = &bss_align;
  297.     } else
  298.     return NO_SEG;
  299.  
  300.     if (*p) {
  301.     if (!nasm_strnicmp(p,"align=",6)) {
  302.         if (sec_align == NULL)
  303.         error(ERR_NONFATAL, "cannot specify an alignment to"
  304.               " the `.text' section");
  305.         else if (p[6+strspn(p+6,"0123456789")])
  306.         error(ERR_NONFATAL, "argument to `align' is not numeric");
  307.         else {
  308.         unsigned int align = atoi(p+6);
  309.         if (!align || ((align-1) & align))
  310.             error(ERR_NONFATAL, "argument to `align' is not a"
  311.               " power of two");
  312.         else
  313.             *sec_align = align;
  314.         }
  315.     }
  316.     }
  317.  
  318.     return sec_index;
  319. }
  320.  
  321. static long bin_segbase (long segment) {
  322.     return segment;
  323. }
  324.  
  325. static int bin_directive (char *directive, char *value, int pass) {
  326.     int rn_error;
  327.  
  328.     if (!strcmp(directive, "org")) {
  329.     start_point = readnum (value, &rn_error);
  330.     if (rn_error)
  331.         error (ERR_NONFATAL, "argument to ORG should be numeric");
  332.     return 1;
  333.     } else
  334.     return 0;
  335. }
  336.  
  337. static void bin_filename (char *inname, char *outname, efunc error) {
  338.     standard_extension (inname, outname, "", error);
  339. }
  340.  
  341. static char *bin_stdmac[] = {
  342.     "%define __SECT__ [section .text]",
  343.     "%imacro org 1+.nolist",
  344.     "[org %1]",
  345.     "%endmacro",
  346.     NULL
  347. };
  348.  
  349. struct ofmt of_bin = {
  350.     "flat-form binary files (e.g. DOS .COM, .SYS)",
  351.     "bin",
  352.     bin_stdmac,
  353.     bin_init,
  354.     bin_out,
  355.     bin_deflabel,
  356.     bin_secname,
  357.     bin_segbase,
  358.     bin_directive,
  359.     bin_filename,
  360.     bin_cleanup
  361. };
  362.  
  363. #endif /* OF_BIN */
  364.