outrdf2.c
上传用户:yuppie_zhu
上传日期:2007-01-08
资源大小:535k
文件大小:18k
源码类别:

编译器/解释器

开发平台:

C/C++

  1. /* outrdf2.c output routines for the Netwide Assembler to produce
  2.  * RDOFF version 2 format object files (which are intended
  3.  * mainly for use in proprietary projects, as the code to 
  4.  * load and execute them is very simple). They will also be 
  5.  * used 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-1998 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. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <ctype.h>
  18. #include <assert.h>
  19. #include "nasm.h"
  20. #include "nasmlib.h"
  21. #include "outform.h"
  22. /* VERBOSE_WARNINGS: define this to add some extra warnings... */
  23. #define VERBOSE_WARNINGS     
  24. #ifdef OF_RDF2
  25. #define RDF_MAXSEGS 64 /* maximum number of segments - user configurable */
  26. typedef unsigned short int16;
  27. typedef unsigned char byte;
  28. static const char *RDOFF2Id = "RDOFF2"; /* written to start of RDOFF files */
  29. /* the records that can be found in the RDOFF header */
  30. /* Note that whenever a segment is referred to in the RDOFF file, its number
  31.  * is always half of the segment number that NASM uses to refer to it; this
  32.  * is because NASM only allocates even numbered segments, so as to not
  33.  * waste any of the 16 bits of segment number written to the file - this
  34.  * allows up to 65533 external labels to be defined; otherwise it would be
  35.  * 32764. */
  36. struct RelocRec {
  37.   byte type; /* must be 1, or 6 for segment base ref */
  38.   byte reclen; /* set to 8 */
  39.   byte segment; /* only 0 for code, or 1 for data supported,
  40.  * but add 64 for relative refs (ie do not require
  41.  * reloc @ loadtime, only linkage) */
  42.   long offset; /* from start of segment in which reference is loc'd */
  43.   byte length; /* 1 2 or 4 bytes */
  44.   int16 refseg; /* segment to which reference refers to */
  45. };
  46. struct ImportRec {
  47.   byte  type; /* must be 2, or 7 for FAR import */
  48.   byte reclen; /* equals 3+label length */
  49.   int16 segment; /* segment number allocated to the label for reloc
  50.  * records - label is assumed to be at offset zero
  51.  * in this segment, so linker must fix up with offset
  52.  * of segment and of offset within segment */
  53.   char label[33]; /* zero terminated... should be written to file until
  54.  * the zero, but not after it - max len = 32 chars */
  55. };
  56. struct ExportRec {
  57.   byte type; /* must be 3 */
  58.   byte  reclen; /* equals 6+label length */
  59.   byte segment; /* segment referred to (0/1) */
  60.   long offset; /* offset within segment */
  61.   char label[33]; /* zero terminated as above. max len = 32 chars */
  62. };
  63. struct DLLRec {
  64.   byte type; /* must be 4 */
  65.   byte  reclen; /* equals 1+library name */
  66.   char libname[128]; /* name of library to link with at load time */
  67. };
  68. struct BSSRec {
  69.   byte type; /* must be 5 */
  70.   byte  reclen; /* equeals 4 */
  71.   long amount; /* number of bytes BSS to reserve */
  72. };
  73. #define COUNT_SEGTYPES 9
  74. static char * segmenttypes[COUNT_SEGTYPES] = {
  75.   "null", "text", "code", "data", "comment", "lcomment", "pcomment",
  76.   "symdebug", "linedebug" 
  77. };
  78. static int segmenttypenumbers[COUNT_SEGTYPES] = {
  79.   0, 1, 1, 2, 3, 4, 5, 6, 7
  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. #define BUF_BLOCK_LEN 4088 /* selected to match page size (4096)
  85.                                          * on 80x86 machines for efficiency */
  86. /***********************************************************************
  87.  * Actual code to deal with RDOFF2 ouput format begins here...
  88.  */
  89. /* global variables set during the initialisation phase */
  90. static struct SAA *seg[RDF_MAXSEGS]; /* seg 0 = code, seg 1 = data */
  91. static struct SAA *header; /* relocation/import/export records */
  92. static FILE *ofile;
  93. static efunc error;
  94. static struct seginfo {
  95.   char *segname;
  96.   int   segnumber;
  97.   int16 segtype;
  98.   int16 segreserved;
  99.   long  seglength;
  100. } segments[RDF_MAXSEGS];
  101. static int nsegments;
  102. static long bsslength;
  103. static long headerlength;
  104. static void rdf2_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval)
  105. {
  106.   int segtext, segdata, segbss;
  107.   /* set up the initial segments */
  108.   segments[0].segname = ".text"; 
  109.   segments[0].segnumber = 0;
  110.   segments[0].segtype = 1;
  111.   segments[0].segreserved = 0;
  112.   segments[0].seglength = 0;
  113.   segments[1].segname = ".data";
  114.   segments[1].segnumber = 1;
  115.   segments[1].segtype = 2;
  116.   segments[1].segreserved = 0;
  117.   segments[1].seglength = 0;
  118.   segments[2].segname = ".bss";
  119.   segments[2].segnumber = 2;
  120.   segments[2].segtype = 0xFFFF; /* reserved - should never be produced */
  121.   segments[2].segreserved = 0;
  122.   segments[2].seglength = 0;
  123.   nsegments = 3;
  124.   ofile = fp;
  125.   error = errfunc;
  126.   seg[0] = saa_init(1L);
  127.   seg[1] = saa_init(1L);
  128.   seg[2] = NULL; /* special case! */
  129.   header = saa_init(1L);
  130.   segtext = seg_alloc();
  131.   segdata = seg_alloc();
  132.   segbss = seg_alloc();
  133.   if (segtext != 0 || segdata != 2 || segbss != 4)
  134.     error(ERR_PANIC,"rdf segment numbers not allocated as expected (%d,%d,%d)",
  135.   segtext,segdata,segbss);
  136.   bsslength=0;
  137.   headerlength = 0;
  138. }
  139. static long rdf2_section_names(char *name, int pass, int *bits)
  140. {
  141.   int  i;
  142.   char  * p, * q;
  143.   int code = -1;
  144.   int  reserved = 0;
  145.   /*
  146.    * Default is 32 bits, in the text segment.
  147.    */
  148.   if (!name) {
  149.     *bits = 32;
  150.     return 0;
  151.   }
  152.   /* look for segment type code following segment name */
  153.   p = name;
  154.   while (*p && !isspace(*p)) p++;
  155.   if (*p) { /* we're now in whitespace */
  156.     *p++ = '';
  157.     while (*p && isspace(80)) *p++ = '';
  158.   }
  159.   if (*p) { /* we're now in an attribute value */
  160.     /*
  161.      * see if we have an optional ',number' following the type code
  162.      */
  163.     if ((q = strchr(p, ','))) {
  164.       *q++ = '';
  165.       reserved = readnum(q, &i);
  166.       if (i) {
  167.   error(ERR_NONFATAL, "value following comma must be numeric");
  168.   reserved = 0;
  169.       }
  170.     }
  171.     /*
  172.      * check it against the text strings in segmenttypes 
  173.      */
  174.     for (i = 0; i < COUNT_SEGTYPES; i++)
  175.       if (!nasm_stricmp(p, segmenttypes[i])) {
  176. code = segmenttypenumbers[i];
  177. break;
  178.       }
  179.     if (code == -1) { /* didn't find anything */
  180.       code = readnum(p, &i);
  181.       if (i) {
  182. error(ERR_NONFATAL, "unrecognised RDF segment type (%s)",p);
  183. code = 3;
  184.       }
  185.     }
  186.   }    
  187.   for (i = 0; i < nsegments; i++) {
  188.     if (!strcmp(name, segments[i].segname)) {
  189.       if (code != -1 || reserved != 0) 
  190. error(ERR_NONFATAL, "segment attributes specified on"
  191.       " redeclaration of segment");
  192.       return segments[i].segnumber * 2;
  193.     }
  194.   }
  195.   /* declaring a new segment! */
  196.   if (code == -1) {
  197.     error(ERR_NONFATAL, "new segment declared without type code");
  198.     code = 3;
  199.   }
  200.   if (nsegments == RDF_MAXSEGS) {
  201.     error(ERR_FATAL, "reached compiled-in maximum segment limit (%d)",
  202.   RDF_MAXSEGS);
  203.     return NO_SEG;
  204.   }
  205.   segments[nsegments].segname = nasm_strdup(name);
  206.   i = seg_alloc();
  207.   if (i % 2 != 0)
  208.     error(ERR_PANIC, "seg_alloc() returned odd number");
  209.   segments[nsegments].segnumber = i >> 1;
  210.   segments[nsegments].segtype = code;
  211.   segments[nsegments].segreserved = reserved;
  212.   segments[nsegments].seglength = 0;
  213.   seg[nsegments] = saa_init(1L);
  214.   return i;
  215. }
  216. static void write_reloc_rec(struct RelocRec *r)
  217. {
  218.   char buf[4],*b;
  219.   if (r->refseg != (int16)NO_SEG && (r->refseg & 1)) /* segment base ref */
  220.       r->type = 6;
  221.   r->refseg >>= 1;    /* adjust segment nos to RDF rather than NASM */
  222.   saa_wbytes(header,&r->type,1);
  223.   saa_wbytes(header,&r->reclen,1);
  224.   saa_wbytes(header,&r->segment,1);
  225.   b = buf; WRITELONG(b,r->offset);
  226.   saa_wbytes(header,buf,4);
  227.   saa_wbytes(header,&r->length,1);
  228.   b = buf; WRITESHORT(b,r->refseg);
  229.   saa_wbytes(header,buf,2);
  230.   headerlength += r->reclen + 2;
  231. }
  232. static void write_export_rec(struct ExportRec *r)
  233. {
  234.   char buf[4], *b;
  235.   r->segment >>= 1;
  236.   saa_wbytes(header,&r->type,1);
  237.   saa_wbytes(header,&r->reclen,1);
  238.   saa_wbytes(header,&r->segment,1);
  239.   b = buf; WRITELONG(b,r->offset);
  240.   saa_wbytes(header,buf,4);
  241.   saa_wbytes(header,r->label,strlen(r->label) + 1);
  242.   headerlength += r->reclen + 2;
  243. }
  244. static void write_import_rec(struct ImportRec *r)
  245. {
  246.   char buf[4], *b;
  247.   r->segment >>= 1;
  248.   saa_wbytes(header,&r->type,1);
  249.   saa_wbytes(header,&r->reclen,1);
  250.   b = buf; WRITESHORT(b,r->segment);
  251.   saa_wbytes(header,buf,2);
  252.   saa_wbytes(header,r->label,strlen(r->label) + 1);
  253.   headerlength += r->reclen + 2;
  254. }
  255. static void write_bss_rec(struct BSSRec *r)
  256. {
  257.     char buf[4], *b;
  258.     saa_wbytes(header,&r->type,1);
  259.     saa_wbytes(header,&r->reclen,1);
  260.     b = buf; WRITELONG(b,r->amount);
  261.     saa_wbytes(header,buf,4);
  262.     headerlength += r->reclen + 2;
  263. }
  264. static void write_dll_rec(struct DLLRec *r)
  265. {
  266.     saa_wbytes(header,&r->type,1);
  267.     saa_wbytes(header,&r->reclen,1);
  268.     saa_wbytes(header,r->libname,strlen(r->libname) + 1);
  269.     headerlength += r->reclen + 2;
  270. }
  271. static void rdf2_deflabel(char *name, long segment, long offset,
  272.  int is_global, char *special)
  273. {
  274.   struct ExportRec r;
  275.   struct ImportRec ri;
  276. #ifdef VERBOSE_WARNINGS
  277.   static int warned_common = 0;
  278. #endif
  279.   static int farsym = 0;
  280.   static int i;
  281.   if (special) {
  282.     while(*special == ' ' || *special == 't') special++;
  283.     if (!nasm_stricmp(special, "far")) {
  284.       farsym = 1;
  285.     }
  286.     else if (!nasm_stricmp(special, "near")) {
  287.       farsym = 0;
  288.     }
  289.     else
  290.       error(ERR_NONFATAL, "unrecognised symbol type `%s'", special);
  291.   }
  292.   if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
  293.     error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
  294.     return;
  295.   }
  296.   if (is_global == 2) {
  297. #ifdef VERBOSE_WARNINGS
  298.     if (!warned_common) {
  299.       error(ERR_WARNING,"common declarations not supported: using extern");
  300.       warned_common = 1;
  301.     }
  302. #endif
  303.     is_global = 1;
  304.   }
  305.   for (i = 0; i < nsegments; i++) {
  306.     if (segments[i].segnumber == segment>>1) break;
  307.   }
  308.   if (i >= nsegments) {   /* EXTERN declaration */
  309.     if (farsym)
  310.       ri.type = 7;
  311.     else
  312.       ri.type = 2;
  313.     ri.segment = segment;
  314.     strncpy(ri.label,name,32);
  315.     ri.label[32] = 0;
  316.     ri.reclen = 3 + strlen(ri.label);
  317.     write_import_rec(&ri);
  318.   } else if (is_global) {
  319.     r.type = 3;
  320.     r.segment = segment;
  321.     r.offset = offset;
  322.     strncpy(r.label,name,32);
  323.     r.label[32] = 0;
  324.     r.reclen = 6 + strlen(r.label);
  325.     write_export_rec(&r);
  326.   }
  327. }
  328. static void membufwrite(int segment, void * data, int bytes)
  329. {
  330.   int i;
  331.   char buf[4], * b;
  332.   for (i = 0; i < nsegments; i++) {
  333.     if (segments[i].segnumber == segment) break;
  334.   }
  335.   if (i == nsegments)
  336.     error(ERR_PANIC, "can't find segment %d", segment);
  337.   
  338.   if (bytes < 0) {
  339.     b = buf;
  340.     if (bytes == -2)
  341.       WRITESHORT(b,*(short *)data);
  342.     else
  343.       WRITELONG(b,*(long *)data);
  344.     data = buf;
  345.     bytes = -bytes;
  346.   }
  347.   segments[i].seglength += bytes;
  348.   saa_wbytes(seg[i],data,bytes);
  349. }
  350. static int getsegmentlength(int segment)
  351. {
  352.   int i;
  353.   for (i = 0; i < nsegments; i++) {
  354.     if (segments[i].segnumber == segment) break;
  355.   }
  356.   if (i == nsegments)
  357.     error(ERR_PANIC, "can't find segment %d", segment);
  358.   return segments[i].seglength;
  359. }
  360.     
  361. static void rdf2_out (long segto, void *data, unsigned long type,
  362.      long segment, long wrt)
  363. {
  364.   long bytes = type & OUT_SIZMASK;
  365.   struct RelocRec rr;
  366.   unsigned char databuf[4],*pd;
  367.   int seg;
  368.   if (segto == NO_SEG) {
  369.       if ((type & OUT_TYPMASK) != OUT_RESERVE)
  370.   error (ERR_NONFATAL, "attempt to assemble code in ABSOLUTE space");
  371.       return;
  372.   }
  373.   segto >>= 1;    /* convert NASM segment no to RDF number */
  374.   for (seg = 0; seg < nsegments; seg++) {
  375.     if (segments[seg].segnumber == segto) break;
  376.   }
  377.   if (seg >= nsegments) {
  378.     error(ERR_NONFATAL,"specified segment not supported by rdf output format");
  379.     return;
  380.   }
  381.   if (wrt != NO_SEG) {
  382.     wrt = NO_SEG;        /* continue to do _something_ */
  383.     error (ERR_NONFATAL, "WRT not supported by rdf output format");
  384.   }
  385.   type &= OUT_TYPMASK;
  386.   if (segto == 2 && type != OUT_RESERVE)
  387.   {
  388.       error(ERR_NONFATAL, "BSS segments may not be initialised");
  389.       /* just reserve the space for now... */
  390.       if (type == OUT_REL2ADR)
  391. bytes = 2;
  392.       else
  393. bytes = 4;
  394.       type = OUT_RESERVE;
  395.   }
  396.   if (type == OUT_RESERVE) {
  397.       if (segto == 2) /* BSS segment space reserverd */
  398.   bsslength += bytes;
  399.       else
  400. while (bytes --)
  401.     membufwrite(segto,databuf,1);
  402.   }
  403.   else if (type == OUT_RAWDATA) {
  404.       if (segment != NO_SEG)
  405.   error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
  406.       membufwrite(segto,data,bytes);
  407.   }
  408.   else if (type == OUT_ADDRESS) {
  409.     /* if segment == NO_SEG then we are writing an address of an
  410.        object within the same segment - do not produce reloc rec. */
  411.     /* FIXME - is this behaviour sane? at first glance it doesn't
  412.        appear to be. Must test this thoroughly...! */
  413.     if (segment != NO_SEG)
  414.     {
  415. /* it's an address, so we must write a relocation record */
  416. rr.type = 1; /* type signature */
  417. rr.reclen = 8;
  418. rr.segment = segto; /* segment we're currently in */
  419. rr.offset = getsegmentlength(segto); /* current offset */
  420. rr.length = bytes; /* length of reference */
  421. rr.refseg = segment; /* segment referred to */
  422. write_reloc_rec(&rr);
  423.     }
  424.     pd = databuf; /* convert address to little-endian */
  425.     if (bytes == 2)
  426.       WRITESHORT (pd, *(long *)data);
  427.     else
  428.       WRITELONG (pd, *(long *)data);
  429.     membufwrite(segto,databuf,bytes);
  430.   }
  431.   else if (type == OUT_REL2ADR)
  432.   {
  433.     if (segment == segto)
  434.       error(ERR_PANIC, "intra-segment OUT_REL2ADR");
  435.     rr.reclen = 8;
  436.     rr.offset = getsegmentlength(segto); /* current offset */
  437.     rr.length = 2; /* length of reference */
  438.     rr.refseg = segment; /* segment referred to (will be >>1'd)*/
  439.     if (segment != NO_SEG && segment % 2) {
  440.       rr.type = 6;
  441.       rr.segment = segto; /* memory base refs *aren't ever* relative! */
  442.       write_reloc_rec(&rr);
  443.       /* what do we put in the code? Simply the data. This should almost
  444.        * always be zero, unless someone's doing segment arithmetic...
  445.        */
  446.       rr.offset = *(long *) data;
  447.     }
  448.     else
  449.     {
  450.       rr.type = 1; /* type signature */
  451.       rr.segment = segto+64; /* segment we're currently in + rel flag */
  452.       write_reloc_rec(&rr);
  453.       /* work out what to put in the code: offset of the end of this operand,
  454.        * subtracted from any data specified, so that loader can just add
  455.        * address of imported symbol onto it to get address relative to end of
  456.        * instruction: import_address + data(offset) - end_of_instrn */
  457.       rr.offset = *(long *)data -(rr.offset + bytes);
  458.     }
  459.     
  460.     membufwrite(segto,&rr.offset,-2);
  461.   }
  462.   else if (type == OUT_REL4ADR)
  463.   {
  464.     if (segment == segto)
  465.       error(ERR_PANIC, "intra-segment OUT_REL4ADR");
  466.     if (segment != NO_SEG && segment % 2) {
  467.       error(ERR_PANIC, "erm... 4 byte segment base ref?");
  468.     }
  469.     rr.type = 1; /* type signature */
  470.     rr.segment = segto+64; /* segment we're currently in + rel tag */
  471.     rr.offset = getsegmentlength(segto); /* current offset */
  472.     rr.length = 4; /* length of reference */
  473.     rr.refseg = segment; /* segment referred to */
  474.     rr.reclen = 8;
  475.     write_reloc_rec(&rr);
  476.     rr.offset = *(long *)data -(rr.offset + bytes);
  477.     membufwrite(segto,&rr.offset,-4);
  478.   }
  479. }
  480. static void rdf2_cleanup (int debuginfo) {
  481.   long l;
  482.   struct BSSRec bs;
  483.   int i;
  484.     (void) debuginfo;
  485.   /* should write imported & exported symbol declarations to header here */
  486.   /* generate the output file... */
  487.   fwrite(RDOFF2Id,6,1,ofile); /* file type magic number */
  488.   if (bsslength != 0) /* reserve BSS */
  489.   {
  490.       bs.type = 5;
  491.       bs.amount = bsslength;
  492.       bs.reclen = 4;
  493.       write_bss_rec(&bs);
  494.   }
  495.   /*
  496.    * calculate overall length of the output object
  497.    */
  498.   l = headerlength + 4;
  499.   
  500.   for (i = 0; i < nsegments; i++) {
  501.     if (i == 2) continue; /* skip BSS segment */
  502.     l += 10 + segments[i].seglength;
  503.   }
  504.   l += 10; /* null segment */
  505.   fwritelong(l, ofile);
  506.   fwritelong(headerlength, ofile);
  507.   saa_fpwrite(header,ofile); /* dump header */
  508.   saa_free(header);
  509.   for (i = 0; i < nsegments; i++) {
  510.     if (i == 2) continue;
  511.     fwriteshort(segments[i].segtype, ofile);
  512.     fwriteshort(segments[i].segnumber, ofile);
  513.     fwriteshort(segments[i].segreserved, ofile);
  514.     fwritelong(segments[i].seglength, ofile);
  515.     saa_fpwrite(seg[i], ofile);
  516.     saa_free(seg[i]);
  517.   }
  518.   /* null segment - write 10 bytes of zero */
  519.   fwritelong(0,ofile);
  520.   fwritelong(0,ofile);
  521.   fwriteshort(0,ofile);
  522.   fclose(ofile);
  523. }
  524. static long rdf2_segbase (long segment) {
  525.     return segment;
  526. }
  527. static int rdf2_directive (char *directive, char *value, int pass) {
  528.     struct DLLRec r;
  529.     
  530.     if (! strcmp(directive, "library")) {
  531. if (pass == 1) {
  532.     r.type = 4;
  533.     strcpy(r.libname, value);
  534.     write_dll_rec(&r);
  535. }
  536. return 1;
  537.     }
  538.     return 0;
  539. }
  540. static void rdf2_filename (char *inname, char *outname, efunc error) {
  541.   standard_extension(inname,outname,".rdf",error);
  542. }
  543. static char *rdf2_stdmac[] = {
  544.     "%define __SECT__ [section .text]",
  545.     "%imacro library 1+.nolist",
  546.     "[library %1]",
  547.     "%endmacro",
  548.     "%macro __NASM_CDecl__ 1",
  549.     "%endmacro",
  550.     NULL
  551. };
  552. static int rdf2_set_info(enum geninfo type, char **val)
  553. {
  554.     return 0;
  555. }
  556. struct ofmt of_rdf2 = {
  557.   "Relocatable Dynamic Object File Format v2.0",
  558.   "rdf",
  559.   NULL,
  560.   null_debug_arr,
  561.   &null_debug_form,
  562.   rdf2_stdmac,
  563.   rdf2_init,
  564.   rdf2_set_info,
  565.   rdf2_out,
  566.   rdf2_deflabel,
  567.   rdf2_section_names,
  568.   rdf2_segbase,
  569.   rdf2_directive,
  570.   rdf2_filename,
  571.   rdf2_cleanup
  572. };
  573. #endif /* OF_RDF2 */