NASM 0.98.26
[platform/upstream/nasm.git] / outrdf2.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
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_RDF2
29
30 #define RDF_MAXSEGS 64  /* maximum number of segments - user configurable */
31
32 typedef unsigned short int16;
33 typedef unsigned char byte;
34
35 static const char *RDOFF2Id = "RDOFF2"; /* written to start of RDOFF files */
36
37
38 /* the records that can be found in the RDOFF header */
39
40 /* Note that whenever a segment is referred to in the RDOFF file, its number
41  * is always half of the segment number that NASM uses to refer to it; this
42  * is because NASM only allocates even numbered segments, so as to not
43  * waste any of the 16 bits of segment number written to the file - this
44  * allows up to 65533 external labels to be defined; otherwise it would be
45  * 32764. */
46  
47 #define RDFREC_RELOC            1
48 #define RDFREC_IMPORT           2
49 #define RDFREC_GLOBAL           3
50 #define RDFREC_DLL              4
51 #define RDFREC_BSS              5
52 #define RDFREC_SEGRELOC         6
53 #define RDFREC_FARIMPORT        7
54 #define RDFREC_MODNAME          8
55 #define RDFREC_MULTIBOOTHDR     9
56 #define RDFREC_GENERIC          0
57
58
59 struct RelocRec {
60   byte  type;           /* must be 1, or 6 for segment base ref */
61   byte  reclen;         /* set to 8 */
62   byte  segment;        /* only 0 for code, or 1 for data supported,
63                          * but add 64 for relative refs (ie do not require
64                          * reloc @ loadtime, only linkage) */
65   long  offset;         /* from start of segment in which reference is loc'd */
66   byte  length;         /* 1 2 or 4 bytes */
67   int16 refseg;         /* segment to which reference refers to */
68 };
69
70 struct ImportRec {
71   byte  type;           /* must be 2, or 7 for FAR import */
72   byte  reclen;         /* equals 3+label length */
73   int16 segment;        /* segment number allocated to the label for reloc
74                          * records - label is assumed to be at offset zero
75                          * in this segment, so linker must fix up with offset
76                          * of segment and of offset within segment */
77   char  label[33];      /* zero terminated... should be written to file until
78                          * the zero, but not after it - max len = 32 chars */
79 };
80
81 struct ExportRec {
82   byte  type;           /* must be 3 */
83   byte  reclen;         /* equals 7+label length */
84   byte  flags;          /* SYM_* flags (see below) */
85   byte  segment;        /* segment referred to (0/1) */
86   long  offset;         /* offset within segment */
87   char  label[33];      /* zero terminated as above. max len = 32 chars */
88 };
89
90 struct BSSRec {
91   byte  type;           /* must be 5 */
92   byte  reclen;         /* equals 4 */
93   long  amount;         /* number of bytes BSS to reserve */
94 };
95
96 struct DLLModRec {
97   byte type;            /* 4 for DLLRec, 8 for ModRec */
98   byte reclen;          /* 1+lib name length for DLLRec, 1+mod name length */
99   char name[128];       /* library to link at load time or module name */
100 };
101
102 /* Flags for ExportRec */
103 #define SYM_DATA        0x01
104 #define SYM_FUNCTION    0x02
105 #define SYM_GLOBAL      0x04
106
107 #define COUNT_SEGTYPES 9
108
109 static char * segmenttypes[COUNT_SEGTYPES] = {
110   "null", "text", "code", "data", "comment", "lcomment", "pcomment",
111   "symdebug", "linedebug" 
112 };
113
114 static int segmenttypenumbers[COUNT_SEGTYPES] = {
115   0, 1, 1, 2, 3, 4, 5, 6, 7
116 };
117
118 /* code for managing buffers needed to seperate code and data into individual
119  * sections until they are ready to be written to the file.
120  * We'd better hope that it all fits in memory else we're buggered... */
121
122 #define BUF_BLOCK_LEN 4088              /* selected to match page size (4096)
123                                          * on 80x86 machines for efficiency */
124
125 /***********************************************************************
126  * Actual code to deal with RDOFF2 ouput format begins here...
127  */
128
129 /* global variables set during the initialisation phase */
130
131 static struct SAA *seg[RDF_MAXSEGS];    /* seg 0 = code, seg 1 = data */
132 static struct SAA *header;      /* relocation/import/export records */
133
134 static FILE *ofile;
135
136 static efunc error;
137
138 static struct seginfo {
139   char *segname;
140   int   segnumber;
141   int16 segtype;
142   int16 segreserved;
143   long  seglength;
144 } segments[RDF_MAXSEGS];
145
146 static int nsegments;
147
148 static long bsslength;
149 static long headerlength;
150
151 static void rdf2_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval)
152 {
153   int segtext, segdata, segbss;
154
155   /* set up the initial segments */
156   segments[0].segname = ".text"; 
157   segments[0].segnumber = 0;
158   segments[0].segtype = 1;
159   segments[0].segreserved = 0;
160   segments[0].seglength = 0;
161
162   segments[1].segname = ".data";
163   segments[1].segnumber = 1;
164   segments[1].segtype = 2;
165   segments[1].segreserved = 0;
166   segments[1].seglength = 0;
167
168   segments[2].segname = ".bss";
169   segments[2].segnumber = 2;
170   segments[2].segtype = 0xFFFF; /* reserved - should never be produced */
171   segments[2].segreserved = 0;
172   segments[2].seglength = 0;
173
174   nsegments = 3;
175
176   ofile = fp;
177   error = errfunc;
178
179   seg[0] = saa_init(1L);
180   seg[1] = saa_init(1L);
181   seg[2] = NULL;                /* special case! */
182
183   header = saa_init(1L);
184
185   segtext = seg_alloc();
186   segdata = seg_alloc();
187   segbss = seg_alloc();
188   if (segtext != 0 || segdata != 2 || segbss != 4)
189     error(ERR_PANIC,"rdf segment numbers not allocated as expected (%d,%d,%d)",
190           segtext,segdata,segbss);
191   bsslength=0;
192   headerlength = 0;
193 }
194
195 static long rdf2_section_names(char *name, int pass, int *bits)
196 {
197   int   i;
198   char  * p, * q;
199   int   code = -1;
200   int   reserved = 0;
201
202   /*
203    * Default is 32 bits, in the text segment.
204    */
205   if (!name) {
206     *bits = 32;
207     return 0;
208   }
209
210   /* look for segment type code following segment name */
211   p = name;
212   while (*p && !isspace(*p)) p++;
213   if (*p) {     /* we're now in whitespace */
214     *p++ = '\0';
215     while (*p && isspace(80)) *p++ = '\0';
216   }
217   if (*p) {     /* we're now in an attribute value */
218     /*
219      * see if we have an optional ',number' following the type code
220      */
221     if ((q = strchr(p, ','))) {
222       *q++ = '\0';
223
224       reserved = readnum(q, &i);
225       if (i) {
226           error(ERR_NONFATAL, "value following comma must be numeric");
227           reserved = 0;
228       }
229     }
230     /*
231      * check it against the text strings in segmenttypes 
232      */
233
234     for (i = 0; i < COUNT_SEGTYPES; i++)
235       if (!nasm_stricmp(p, segmenttypes[i])) {
236         code = segmenttypenumbers[i];
237         break;
238       }
239     if (code == -1) {   /* didn't find anything */
240       code = readnum(p, &i);
241       if (i) {
242         error(ERR_NONFATAL, "unrecognised RDF segment type (%s)",p);
243         code = 3;
244       }
245     }
246   }    
247   for (i = 0; i < nsegments; i++) {
248     if (!strcmp(name, segments[i].segname)) {
249       if (code != -1 || reserved != 0) 
250         error(ERR_NONFATAL, "segment attributes specified on"
251               " redeclaration of segment");
252       return segments[i].segnumber * 2;
253     }
254   }
255
256   /* declaring a new segment! */
257
258   if (code == -1) {
259     error(ERR_NONFATAL, "new segment declared without type code");
260     code = 3;
261   }
262   if (nsegments == RDF_MAXSEGS) {
263     error(ERR_FATAL, "reached compiled-in maximum segment limit (%d)",
264           RDF_MAXSEGS);
265     return NO_SEG;
266   }
267
268   segments[nsegments].segname = nasm_strdup(name);
269   i = seg_alloc();
270   if (i % 2 != 0)
271     error(ERR_PANIC, "seg_alloc() returned odd number");
272   segments[nsegments].segnumber = i >> 1;
273   segments[nsegments].segtype = code;
274   segments[nsegments].segreserved = reserved;
275   segments[nsegments].seglength = 0;
276
277   seg[nsegments] = saa_init(1L);
278
279   return i;
280 }
281
282 static void write_reloc_rec(struct RelocRec *r)
283 {
284   char buf[4],*b;
285
286   if (r->refseg != (int16)NO_SEG && (r->refseg & 1)) /* segment base ref */
287       r->type = RDFREC_SEGRELOC;
288
289   r->refseg >>= 1;    /* adjust segment nos to RDF rather than NASM */
290
291   saa_wbytes(header,&r->type,1);
292   saa_wbytes(header,&r->reclen,1);
293   saa_wbytes(header,&r->segment,1);
294   b = buf; WRITELONG(b,r->offset);
295   saa_wbytes(header,buf,4);
296   saa_wbytes(header,&r->length,1);
297   b = buf; WRITESHORT(b,r->refseg);
298   saa_wbytes(header,buf,2);
299   headerlength += r->reclen + 2;
300 }
301
302 static void write_export_rec(struct ExportRec *r)
303 {
304   char buf[4], *b;
305
306   r->segment >>= 1;
307
308   saa_wbytes(header,&r->type,1);
309   saa_wbytes(header,&r->reclen,1);
310   saa_wbytes(header,&r->flags,1);
311   saa_wbytes(header,&r->segment,1);
312   b = buf; WRITELONG(b,r->offset);
313   saa_wbytes(header,buf,4);
314   saa_wbytes(header,r->label,strlen(r->label) + 1);
315   headerlength += r->reclen + 2;
316 }
317
318 static void write_import_rec(struct ImportRec *r)
319 {
320   char buf[4], *b;
321
322   r->segment >>= 1;
323
324   saa_wbytes(header,&r->type,1);
325   saa_wbytes(header,&r->reclen,1);
326   b = buf; WRITESHORT(b,r->segment);
327   saa_wbytes(header,buf,2);
328   saa_wbytes(header,r->label,strlen(r->label) + 1);
329   headerlength += r->reclen + 2;
330 }
331
332 static void write_bss_rec(struct BSSRec *r)
333 {
334     char buf[4], *b;
335
336     saa_wbytes(header,&r->type,1);
337     saa_wbytes(header,&r->reclen,1);
338     b = buf; WRITELONG(b,r->amount);
339     saa_wbytes(header,buf,4);
340     headerlength += r->reclen + 2;
341 }
342
343 /*
344  * Write library record. Also used for module name records.
345  */
346 static void write_dllmod_rec(struct DLLModRec *r)
347 {
348     saa_wbytes(header,&r->type,1);
349     saa_wbytes(header,&r->reclen,1);
350     saa_wbytes(header,r->name,strlen(r->name) + 1);
351     headerlength += r->reclen + 2;
352 }
353
354 static void rdf2_deflabel(char *name, long segment, long offset,
355                          int is_global, char *special)
356 {
357   struct ExportRec r;
358   struct ImportRec ri;
359   static int farsym = 0;
360   static int i;
361   byte export_flags = 0;
362
363   if (is_global != 1) return;
364
365   if (special) {
366     while(*special == ' ' || *special == '\t') special++;
367     
368     if (!nasm_strnicmp(special, "export", 6)) {
369       special += 6;
370       export_flags |= SYM_GLOBAL;  
371     }
372
373     if (*special) {
374       while(isspace(*special)) special++;
375       if (!nasm_stricmp(special, "far")) {
376         farsym = 1;
377       }
378       else if (!nasm_stricmp(special, "near")) {
379         farsym = 0;
380       }
381       else if (!nasm_stricmp(special, "proc") || 
382                !nasm_stricmp(special, "function")) {
383         export_flags |= SYM_FUNCTION;  
384       }
385       else if (!nasm_stricmp(special, "data") ||
386                !nasm_stricmp(special, "object")) {
387         export_flags |= SYM_DATA;
388       }
389       else
390         error(ERR_NONFATAL, "unrecognised symbol type `%s'", special);
391     }   
392   }
393
394   if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
395     error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
396     return;
397   }
398
399   for (i = 0; i < nsegments; i++) {
400     if (segments[i].segnumber == segment>>1) break;
401   }
402   if (i >= nsegments) {   /* EXTERN declaration */
403     if (farsym)
404       ri.type = RDFREC_FARIMPORT;
405     else
406       ri.type = RDFREC_IMPORT;
407     ri.segment = segment;
408     strncpy(ri.label,name,32);
409     ri.label[32] = 0;
410     ri.reclen = 3 + strlen(ri.label);
411     write_import_rec(&ri);
412   } else if (is_global) {
413     r.type = RDFREC_GLOBAL;
414     r.flags = export_flags;
415     r.segment = segment;
416     r.offset = offset;
417     strncpy(r.label,name,32);
418     r.label[32] = 0;
419     r.reclen = 7 + strlen(r.label);
420     write_export_rec(&r);
421   }
422 }
423
424 static void membufwrite(int segment, void * data, int bytes)
425 {
426   int i;
427   char buf[4], * b;
428
429   for (i = 0; i < nsegments; i++) {
430     if (segments[i].segnumber == segment) break;
431   }
432   if (i == nsegments)
433     error(ERR_PANIC, "can't find segment %d", segment);
434   
435   if (bytes < 0) {
436     b = buf;
437     if (bytes == -2)
438       WRITESHORT(b,*(short *)data);
439     else
440       WRITELONG(b,*(long *)data);
441     data = buf;
442     bytes = -bytes;
443   }
444   segments[i].seglength += bytes;
445   saa_wbytes(seg[i],data,bytes);
446 }
447
448 static int getsegmentlength(int segment)
449 {
450   int i;
451   for (i = 0; i < nsegments; i++) {
452     if (segments[i].segnumber == segment) break;
453   }
454   if (i == nsegments)
455     error(ERR_PANIC, "can't find segment %d", segment);
456
457   return segments[i].seglength;
458 }
459     
460 static void rdf2_out (long segto, void *data, unsigned long type,
461                      long segment, long wrt)
462 {
463   long bytes = type & OUT_SIZMASK;
464   struct RelocRec rr;
465   unsigned char databuf[4],*pd;
466   int seg;
467
468   if (segto == NO_SEG) {
469       if ((type & OUT_TYPMASK) != OUT_RESERVE)
470           error (ERR_NONFATAL, "attempt to assemble code in ABSOLUTE space");
471       return;
472   }
473
474   segto >>= 1;    /* convert NASM segment no to RDF number */
475
476   for (seg = 0; seg < nsegments; seg++) {
477     if (segments[seg].segnumber == segto) break;
478   }
479   if (seg >= nsegments) {
480     error(ERR_NONFATAL,"specified segment not supported by rdf output format");
481     return;
482   }
483
484   if (wrt != NO_SEG) {
485     wrt = NO_SEG;                      /* continue to do _something_ */
486     error (ERR_NONFATAL, "WRT not supported by rdf output format");
487   }
488
489   type &= OUT_TYPMASK;
490
491   if (segto == 2 && type != OUT_RESERVE)
492   {
493       error(ERR_NONFATAL, "BSS segments may not be initialised");
494
495       /* just reserve the space for now... */
496
497       if (type == OUT_REL2ADR)
498         bytes = 2;
499       else
500         bytes = 4;
501       type = OUT_RESERVE;
502   }
503
504   if (type == OUT_RESERVE) {
505       if (segto == 2)           /* BSS segment space reserverd */
506           bsslength += bytes;
507       else
508         while (bytes --)
509             membufwrite(segto,databuf,1);
510   }
511   else if (type == OUT_RAWDATA) {
512       if (segment != NO_SEG)
513           error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
514
515       membufwrite(segto,data,bytes);
516   }
517   else if (type == OUT_ADDRESS) {
518
519     /* if segment == NO_SEG then we are writing an address of an
520        object within the same segment - do not produce reloc rec. */
521
522     /* FIXME - is this behaviour sane? at first glance it doesn't
523        appear to be. Must test this thoroughly...! */
524
525     if (segment != NO_SEG)
526     {
527         /* it's an address, so we must write a relocation record */
528
529         rr.type = RDFREC_RELOC;                 /* type signature */
530         rr.reclen = 8;
531         rr.segment = segto;                     /* segment we're currently in */
532         rr.offset = getsegmentlength(segto);    /* current offset */
533         rr.length = bytes;                      /* length of reference */
534         rr.refseg = segment;                    /* segment referred to */
535         write_reloc_rec(&rr);
536     }
537
538     pd = databuf;       /* convert address to little-endian */
539     if (bytes == 2)
540       WRITESHORT (pd, *(long *)data);
541     else
542       WRITELONG (pd, *(long *)data);
543
544     membufwrite(segto,databuf,bytes);
545
546   }
547   else if (type == OUT_REL2ADR)
548   {
549     if (segment == segto)
550       error(ERR_PANIC, "intra-segment OUT_REL2ADR");
551
552     rr.reclen = 8;
553     rr.offset = getsegmentlength(segto);        /* current offset */
554     rr.length = 2;              /* length of reference */
555     rr.refseg = segment;        /* segment referred to (will be >>1'd)*/
556
557     if (segment != NO_SEG && segment % 2) {
558       rr.type = RDFREC_SEGRELOC;
559       rr.segment = segto;       /* memory base refs *aren't ever* relative! */
560       write_reloc_rec(&rr);
561
562       /* what do we put in the code? Simply the data. This should almost
563        * always be zero, unless someone's doing segment arithmetic...
564        */
565       rr.offset = *(long *) data;
566     }
567     else
568     {
569       rr.type = RDFREC_RELOC;   /* type signature */
570       rr.segment = segto+64;    /* segment we're currently in + rel flag */
571       write_reloc_rec(&rr);
572
573       /* work out what to put in the code: offset of the end of this operand,
574        * subtracted from any data specified, so that loader can just add
575        * address of imported symbol onto it to get address relative to end of
576        * instruction: import_address + data(offset) - end_of_instrn */
577
578       rr.offset = *(long *)data -(rr.offset + bytes);
579     }
580     
581     membufwrite(segto,&rr.offset,-2);
582   }
583   else if (type == OUT_REL4ADR)
584   {
585     if (segment == segto)
586       error(ERR_PANIC, "intra-segment OUT_REL4ADR");
587     if (segment != NO_SEG && segment % 2) {
588       error(ERR_PANIC, "erm... 4 byte segment base ref?");
589     }
590
591     rr.type = RDFREC_RELOC;     /* type signature */
592     rr.segment = segto+64;      /* segment we're currently in + rel tag */
593     rr.offset = getsegmentlength(segto);        /* current offset */
594     rr.length = 4;              /* length of reference */
595     rr.refseg = segment;        /* segment referred to */
596     rr.reclen = 8;
597     write_reloc_rec(&rr);
598
599     rr.offset = *(long *)data -(rr.offset + bytes);
600
601     membufwrite(segto,&rr.offset,-4);
602   }
603 }
604
605 static void rdf2_cleanup (int debuginfo) {
606   long          l;
607   struct BSSRec bs;
608   int           i;
609
610     (void) debuginfo;
611
612   /* should write imported & exported symbol declarations to header here */
613
614   /* generate the output file... */
615   fwrite(RDOFF2Id,6,1,ofile);   /* file type magic number */
616
617   if (bsslength != 0)           /* reserve BSS */
618   {
619       bs.type = RDFREC_BSS;
620       bs.amount = bsslength;
621       bs.reclen = 4;
622       write_bss_rec(&bs);
623   }
624
625   /*
626    * calculate overall length of the output object
627    */
628   l = headerlength + 4;
629   
630   for (i = 0; i < nsegments; i++) {
631     if (i == 2) continue;       /* skip BSS segment */
632     l += 10 + segments[i].seglength;
633   }
634   l += 10;      /* null segment */
635
636   fwritelong(l, ofile);
637
638   fwritelong(headerlength, ofile);
639   saa_fpwrite(header,ofile);    /* dump header */
640   saa_free(header);
641
642   for (i = 0; i < nsegments; i++) {
643     if (i == 2) continue;
644
645     fwriteshort(segments[i].segtype, ofile);
646     fwriteshort(segments[i].segnumber, ofile);
647     fwriteshort(segments[i].segreserved, ofile);
648     fwritelong(segments[i].seglength, ofile);
649
650     saa_fpwrite(seg[i], ofile);
651     saa_free(seg[i]);
652   }
653
654   /* null segment - write 10 bytes of zero */
655   fwritelong(0,ofile);
656   fwritelong(0,ofile);
657   fwriteshort(0,ofile);
658
659   fclose(ofile);
660 }
661
662 static long rdf2_segbase (long segment) {
663     return segment;
664 }
665
666 static int rdf2_directive (char *directive, char *value, int pass) {
667     struct DLLModRec r;
668
669     if (! strcmp(directive, "library")) {
670         if (pass == 1) {
671             r.type = RDFREC_DLL;
672             r.reclen=strlen(value)+1;
673             strcpy(r.name, value);
674             write_dllmod_rec(&r);
675         }
676         return 1;
677     }
678
679     if (! strcmp(directive, "module")) {
680         if (pass == 1) {
681             r.type = RDFREC_MODNAME;
682             r.reclen=strlen(value)+1;
683             strcpy(r.name, value);
684             write_dllmod_rec(&r);
685         }
686         return 1;
687     }
688     
689     return 0;
690 }
691
692 static void rdf2_filename (char *inname, char *outname, efunc error) {
693   standard_extension(inname,outname,".rdf",error);
694 }
695
696 static char *rdf2_stdmac[] = {
697     "%define __SECT__ [section .text]",
698     "%imacro library 1+.nolist",
699     "[library %1]",
700     "%endmacro",
701     "%imacro module 1+.nolist",
702     "[module %1]",
703     "%endmacro",
704     "%macro __NASM_CDecl__ 1",
705     "%endmacro",
706     NULL
707 };
708
709 static int rdf2_set_info(enum geninfo type, char **val)
710 {
711     return 0;
712 }
713
714
715 struct ofmt of_rdf2 = {
716   "Relocatable Dynamic Object File Format v2.0",
717   "rdf",
718   NULL,
719   null_debug_arr,
720   &null_debug_form,
721   rdf2_stdmac,
722   rdf2_init,
723   rdf2_set_info,
724   rdf2_out,
725   rdf2_deflabel,
726   rdf2_section_names,
727   rdf2_segbase,
728   rdf2_directive,
729   rdf2_filename,
730   rdf2_cleanup
731 };
732
733 #endif /* OF_RDF2 */