home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / nasm097s.zip / OUTRDF.C < prev    next >
C/C++ Source or Header  |  1997-11-22  |  14KB  |  517 lines

  1. /* outrdf.c    output routines for the Netwide Assembler to produce
  2.  *        RDOFF format object files (which are intended mainly
  3.  *        for use in proprietary projects, as the code to load and
  4.  *        execute them is very simple). They will also be used
  5.  *        for device drivers and possibly some executable files
  6.  *        in the MOSCOW operating system. See Rdoff.txt for
  7.  *        details.
  8.  *
  9.  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  10.  * Julian Hall. All rights reserved. The software is
  11.  * redistributable under the licence given in the file "Licence"
  12.  * distributed in the NASM archive.
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19. #include <assert.h>
  20.  
  21. #include "nasm.h"
  22. #include "nasmlib.h"
  23. #include "outform.h"
  24.  
  25. /* VERBOSE_WARNINGS: define this to add some extra warnings... */
  26. #define VERBOSE_WARNINGS     
  27.  
  28. #ifdef OF_RDF
  29.  
  30. typedef short int16;    /* not sure if this will be required to be altered
  31.                at all... best to typedef it just in case */
  32.  
  33. static const char *RDOFFId = "RDOFF1";    /* written to start of RDOFF files */
  34.  
  35. /* the records that can be found in the RDOFF header */
  36.  
  37. /* Note that whenever a segment is referred to in the RDOFF file, its number
  38.  * is always half of the segment number that NASM uses to refer to it; this
  39.  * is because NASM only allocates even numbered segments, so as to not
  40.  * waste any of the 16 bits of segment number written to the file - this
  41.  * allows up to 65533 external labels to be defined; otherwise it would be
  42.  * 32764. */
  43.  
  44. struct RelocRec {
  45.   char    type;        /* must be 1 */
  46.   char    segment;    /* only 0 for code, or 1 for data supported,
  47.              * but add 64 for relative refs (ie do not require
  48.              * reloc @ loadtime, only linkage) */
  49.   long    offset;        /* from start of segment in which reference is loc'd */
  50.   char    length;        /* 1 2 or 4 bytes */
  51.   int16    refseg;        /* segment to which reference refers to */
  52. };
  53.  
  54. struct ImportRec {
  55.   char     type;        /* must be 2 */
  56.   int16    segment;    /* segment number allocated to the label for reloc
  57.              * records - label is assumed to be at offset zero
  58.              * in this segment, so linker must fix up with offset
  59.              * of segment and of offset within segment */
  60.   char    label[33];    /* zero terminated... should be written to file until
  61.              * the zero, but not after it - max len = 32 chars */
  62. };
  63.  
  64. struct ExportRec {
  65.   char    type;        /* must be 3 */
  66.   char    segment;    /* segment referred to (0/1) */
  67.   long    offset;        /* offset within segment */
  68.   char    label[33];    /* zero terminated as above. max len = 32 chars */
  69. };
  70.  
  71. struct DLLRec {
  72.   char    type;        /* must be 4 */
  73.   char    libname[128];    /* name of library to link with at load time */
  74. };
  75.  
  76. struct BSSRec {
  77.   char    type;        /* must be 5 */
  78.   long    amount;        /* number of bytes BSS to reserve */
  79. };
  80.  
  81. /* code for managing buffers needed to seperate code and data into individual
  82.  * sections until they are ready to be written to the file.
  83.  * We'd better hope that it all fits in memory else we're buggered... */
  84.  
  85. #define BUF_BLOCK_LEN 4088        /* selected to match page size (4096)
  86.                                          * on 80x86 machines for efficiency */
  87.  
  88. typedef struct memorybuffer {
  89.   int length;
  90.   char buffer[BUF_BLOCK_LEN];
  91.   struct memorybuffer *next;
  92. } memorybuffer;
  93.  
  94. static memorybuffer * newmembuf(void){
  95.   memorybuffer * t;
  96.  
  97.   t = nasm_malloc(sizeof(memorybuffer));
  98.  
  99.   t->length = 0;
  100.   t->next = NULL;
  101.   return t;
  102. }
  103.  
  104. static void membufwrite(memorybuffer *b, void *data, int bytes) {
  105.   int16 w;
  106.   long l;
  107.  
  108.   if (b->next) {     /* memory buffer full - use next buffer */
  109.     membufwrite(b->next,data,bytes);
  110.     return;
  111.   }
  112.   if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN)
  113.       || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN)) {
  114.  
  115.     /* buffer full and no next allocated... allocate and initialise next
  116.      * buffer */
  117.  
  118.     b->next = newmembuf();
  119.     membufwrite(b->next,data,bytes);
  120.     return;
  121.   }
  122.  
  123.   switch(bytes) {
  124.   case -4:        /* convert to little-endian */
  125.     l = * (long *) data ;
  126.     b->buffer[b->length++] = l & 0xFF;
  127.     l >>= 8 ;
  128.     b->buffer[b->length++] = l & 0xFF;
  129.     l >>= 8 ;
  130.     b->buffer[b->length++] = l & 0xFF;
  131.     l >>= 8 ;
  132.     b->buffer[b->length++] = l & 0xFF;
  133.     break;
  134.  
  135.   case -2:
  136.     w = * (int16 *) data ;
  137.     b->buffer[b->length++] = w & 0xFF;
  138.     w >>= 8 ;
  139.     b->buffer[b->length++] = w & 0xFF;
  140.     break;
  141.  
  142.   default:
  143.     while(bytes--) {
  144.       b->buffer[b->length++] = *(* (unsigned char **) &data);
  145.  
  146.       (* (unsigned char **) &data)++ ;
  147.     }
  148.     break;
  149.   }
  150. }
  151.  
  152. static void membufdump(memorybuffer *b,FILE *fp)
  153. {
  154.   if (!b) return;
  155.  
  156.   fwrite (b->buffer, 1, b->length, fp);
  157.  
  158.   membufdump(b->next,fp);
  159. }
  160.  
  161. static int membuflength(memorybuffer *b)
  162. {
  163.   if (!b) return 0;
  164.   return b->length + membuflength(b->next);
  165. }
  166.  
  167. static void freemembuf(memorybuffer *b)
  168. {
  169.   if (!b) return;
  170.   freemembuf(b->next);
  171.   nasm_free(b);
  172. }
  173.  
  174. /***********************************************************************
  175.  * Actual code to deal with RDOFF ouput format begins here...
  176.  */
  177.  
  178. /* global variables set during the initialisation phase */
  179.  
  180. static memorybuffer *seg[2];    /* seg 0 = code, seg 1 = data */
  181. static memorybuffer *header;    /* relocation/import/export records */
  182.  
  183. static FILE *ofile;
  184.  
  185. static efunc error;
  186.  
  187. static int segtext,segdata,segbss;
  188. static long bsslength;
  189.  
  190. static void rdf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval)
  191. {
  192.   ofile = fp;
  193.   error = errfunc;
  194.   seg[0] = newmembuf();
  195.   seg[1] = newmembuf();
  196.   header = newmembuf();
  197.   segtext = seg_alloc();
  198.   segdata = seg_alloc();
  199.   segbss = seg_alloc();
  200.   if (segtext != 0 || segdata != 2 || segbss != 4)
  201.     error(ERR_PANIC,"rdf segment numbers not allocated as expected (%d,%d,%d)",
  202.       segtext,segdata,segbss);
  203.   bsslength=0;
  204. }
  205.  
  206. static long rdf_section_names(char *name, int pass, int *bits)
  207. {
  208.   /*
  209.    * Default is 32 bits.
  210.    */
  211.   if (!name)
  212.     *bits = 32;
  213.  
  214.   if (!name) return 0;
  215.   if (!strcmp(name, ".text"))        return 0;
  216.   else if (!strcmp(name, ".data"))    return 2;
  217.   else if (!strcmp(name, ".bss"))    return 4;
  218.   else
  219.     return NO_SEG;
  220. }
  221.  
  222. static void write_reloc_rec(struct RelocRec *r)
  223. {
  224.   if (r->refseg != NO_SEG && (r->refseg & 1))
  225.     error (ERR_NONFATAL, "RDF format does not support segment base"
  226.        " references");
  227.  
  228.   r->refseg >>= 1;    /* adjust segment nos to RDF rather than NASM */
  229.  
  230.   membufwrite(header,&r->type,1);
  231.   membufwrite(header,&r->segment,1);
  232.   membufwrite(header,&r->offset,-4);
  233.   membufwrite(header,&r->length,1);
  234.   membufwrite(header,&r->refseg,-2);    /* 9 bytes written */
  235. }
  236.  
  237. static void write_export_rec(struct ExportRec *r)
  238. {
  239.   r->segment >>= 1;
  240.  
  241.   membufwrite(header,&r->type,1);
  242.   membufwrite(header,&r->segment,1);
  243.   membufwrite(header,&r->offset,-4);
  244.   membufwrite(header,r->label,strlen(r->label) + 1);
  245. }
  246.  
  247. static void write_import_rec(struct ImportRec *r)
  248. {
  249.   r->segment >>= 1;
  250.  
  251.   membufwrite(header,&r->type,1);
  252.   membufwrite(header,&r->segment,-2);
  253.   membufwrite(header,r->label,strlen(r->label) + 1);
  254. }
  255.  
  256. static void write_bss_rec(struct BSSRec *r)
  257. {
  258.     membufwrite(header,&r->type,1);
  259.     membufwrite(header,&r->amount,-4);
  260. }
  261.  
  262. static void write_dll_rec(struct DLLRec *r)
  263. {
  264.     membufwrite(header,&r->type,1);
  265.     membufwrite(header,r->libname,strlen(r->libname) + 1);
  266. }
  267.  
  268. static void rdf_deflabel(char *name, long segment, long offset,
  269.              int is_global, char *special)
  270. {
  271.   struct ExportRec r;
  272.   struct ImportRec ri;
  273. #ifdef VERBOSE_WARNINGS
  274.   static int warned_common = 0;
  275. #endif
  276.  
  277.   if (special)
  278.     error (ERR_NONFATAL, "RDOFF format does not support any"
  279.        " special symbol types");
  280.  
  281.   if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
  282.     error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
  283.     return;
  284.   }
  285.  
  286.   if (is_global == 2) {
  287. #ifdef VERBOSE_WARNINGS
  288.     if (!warned_common) {
  289.       error(ERR_WARNING,"common declarations not supported: using extern");
  290.       warned_common = 1;
  291.     }
  292. #endif
  293.     is_global = 1;
  294.   }
  295.  
  296.   if (segment > 4) {   /* EXTERN declaration */
  297.     ri.type = 2;
  298.     ri.segment = segment;
  299.     strncpy(ri.label,name,32);
  300.     ri.label[32] = 0;
  301.     write_import_rec(&ri);
  302.   } else if (is_global) {
  303.     r.type = 3;
  304.     r.segment = segment;
  305.     r.offset = offset;
  306.     strncpy(r.label,name,32);
  307.     r.label[32] = 0;
  308.     write_export_rec(&r);
  309.   }
  310. }
  311.  
  312. static void rdf_out (long segto, void *data, unsigned long type,
  313.              long segment, long wrt)
  314. {
  315.   long bytes = type & OUT_SIZMASK;
  316.   struct RelocRec rr;
  317.   unsigned char databuf[4],*pd;
  318.  
  319.   segto >>= 1;    /* convert NASM segment no to RDF number */
  320.  
  321.   if (segto != 0 && segto != 1 && segto != 2) {
  322.     error(ERR_NONFATAL,"specified segment not supported by rdf output format");
  323.     return;
  324.   }
  325.  
  326.   if (wrt != NO_SEG) {
  327.     wrt = NO_SEG;               /* continue to do _something_ */
  328.     error (ERR_NONFATAL, "WRT not supported by rdf output format");
  329.   }
  330.  
  331.   type &= OUT_TYPMASK;
  332.  
  333.   if (segto == 2 && type != OUT_RESERVE)
  334.   {
  335.       error(ERR_NONFATAL, "BSS segments may not be initialised");
  336.  
  337.       /* just reserve the space for now... */
  338.  
  339.       if (type == OUT_REL2ADR)
  340.     bytes = 2;
  341.       else
  342.     bytes = 4;
  343.       type = OUT_RESERVE;
  344.   }
  345.  
  346.   if (type == OUT_RESERVE) {
  347.       if (segto == 2)        /* BSS segment space reserverd */
  348.       bsslength += bytes;
  349.       else
  350.     while (bytes --)
  351.         membufwrite(seg[segto],databuf,1);
  352.   }
  353.   else if (type == OUT_RAWDATA) {
  354.       if (segment != NO_SEG)
  355.       error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
  356.       membufwrite(seg[segto],data,bytes);
  357.   }
  358.   else if (type == OUT_ADDRESS) {
  359.  
  360.     /* if segment == NO_SEG then we are writing an address of an
  361.        object within the same segment - do not produce reloc rec. */
  362.  
  363.     if (segment != NO_SEG)
  364.     {
  365.  
  366.     /* it's an address, so we must write a relocation record */
  367.  
  368.     rr.type = 1;        /* type signature */
  369.     rr.segment = segto;        /* segment we're currently in */
  370.     rr.offset = membuflength(seg[segto]);    /* current offset */
  371.     rr.length = bytes;        /* length of reference */
  372.     rr.refseg = segment;    /* segment referred to */
  373.     write_reloc_rec(&rr);
  374.     }
  375.  
  376.     pd = databuf;    /* convert address to little-endian */
  377.     if (bytes == 2)
  378.       WRITESHORT (pd, *(long *)data);
  379.     else
  380.       WRITELONG (pd, *(long *)data);
  381.  
  382.     membufwrite(seg[segto],databuf,bytes);
  383.  
  384.   }
  385.   else if (type == OUT_REL2ADR)
  386.   {
  387.     if (segment == segto)
  388.       error(ERR_PANIC, "intra-segment OUT_REL2ADR");
  389.     if (segment != NO_SEG && segment % 2) {
  390.       error(ERR_NONFATAL, "rdf format does not support segment base refs");
  391.     }
  392.  
  393.     rr.type = 1;        /* type signature */
  394.     rr.segment = segto+64;    /* segment we're currently in + rel flag */
  395.     rr.offset = membuflength(seg[segto]);    /* current offset */
  396.     rr.length = 2;        /* length of reference */
  397.     rr.refseg = segment;    /* segment referred to */
  398.     write_reloc_rec(&rr);
  399.  
  400.     /* work out what to put in the code: offset of the end of this operand,
  401.      * subtracted from any data specified, so that loader can just add
  402.      * address of imported symbol onto it to get address relative to end of
  403.      * instruction: import_address + data(offset) - end_of_instrn */
  404.  
  405.     rr.offset = *(long *)data -(rr.offset + bytes);
  406.  
  407.     membufwrite(seg[segto],&rr.offset,-2);
  408.   }
  409.   else if (type == OUT_REL4ADR)
  410.   {
  411.     if (segment == segto)
  412.       error(ERR_PANIC, "intra-segment OUT_REL4ADR");
  413.     if (segment != NO_SEG && segment % 2) {
  414.       error(ERR_NONFATAL, "rdf format does not support segment base refs");
  415.     }
  416.  
  417.     rr.type = 1;        /* type signature */
  418.     rr.segment = segto+64;    /* segment we're currently in + rel tag */
  419.     rr.offset = membuflength(seg[segto]);    /* current offset */
  420.     rr.length = 4;        /* length of reference */
  421.     rr.refseg = segment;    /* segment referred to */
  422.     write_reloc_rec(&rr);
  423.  
  424.     rr.offset = *(long *)data -(rr.offset + bytes);
  425.     membufwrite(seg[segto],&rr.offset,-4);
  426.   }
  427. }
  428.  
  429. static void rdf_cleanup (void) {
  430.   long        l;
  431.   unsigned char b[4],*d;
  432.   struct BSSRec    bs;
  433.  
  434.  
  435.   /* should write imported & exported symbol declarations to header here */
  436.  
  437.   /* generate the output file... */
  438.   fwrite(RDOFFId,6,1,ofile);    /* file type magic number */
  439.  
  440.   if (bsslength != 0)        /* reserve BSS */
  441.   {
  442.       bs.type = 5;
  443.       bs.amount = bsslength;
  444.       write_bss_rec(&bs);
  445.   }
  446.  
  447.   l = membuflength(header);d=b;
  448.   WRITELONG(d,l);
  449.  
  450.   fwrite(b,4,1,ofile);        /* write length of header */
  451.   membufdump(header,ofile);    /* dump header */
  452.  
  453.   l = membuflength(seg[0]);d=b;    /* code segment */
  454.   WRITELONG(d,l);
  455.  
  456.   fwrite(b,4,1,ofile);
  457.   membufdump(seg[0],ofile);
  458.  
  459.   l = membuflength(seg[1]);d=b;    /* data segment */
  460.   WRITELONG(d,l);
  461.  
  462.   fwrite(b,4,1,ofile);
  463.   membufdump(seg[1],ofile);
  464.  
  465.   freemembuf(header);
  466.   freemembuf(seg[0]);
  467.   freemembuf(seg[1]);
  468.   fclose(ofile);
  469. }
  470.  
  471. static long rdf_segbase (long segment) {
  472.     return segment;
  473. }
  474.  
  475. static int rdf_directive (char *directive, char *value, int pass) {
  476.     struct DLLRec r;
  477.     
  478.     if (! strcmp(directive, "library")) {
  479.     if (pass == 1) {
  480.         r.type = 4;
  481.         strcpy(r.libname, value);
  482.         write_dll_rec(&r);
  483.     }
  484.     return 1;
  485.     }
  486.  
  487.     return 0;
  488. }
  489.  
  490. static void rdf_filename (char *inname, char *outname, efunc error) {
  491.   standard_extension(inname,outname,".rdf",error);
  492. }
  493.  
  494. static char *rdf_stdmac[] = {
  495.     "%define __SECT__ [section .text]",
  496.     "%imacro library 1+.nolist",
  497.     "[library %1]",
  498.     "%endmacro",
  499.     NULL
  500. };
  501.  
  502. struct ofmt of_rdf = {
  503.   "Relocatable Dynamic Object File Format v1.1",
  504.   "rdf",
  505.   rdf_stdmac,
  506.   rdf_init,
  507.   rdf_out,
  508.   rdf_deflabel,
  509.   rdf_section_names,
  510.   rdf_segbase,
  511.   rdf_directive,
  512.   rdf_filename,
  513.   rdf_cleanup
  514. };
  515.  
  516. #endif /* OF_RDF */
  517.