Provide 64-bit support for ORG directive
[nasm/avx512.git] / output / outrdf2.c
blob7fb461597188c2254aaeaedf9b1ba0ed114a543e
1 /*
2 * outrdf2.c output routines for the Netwide Assembler to produce
3 * RDOFF version 2 format object files, which Julian originally
4 * planned to use it in his MOSCOW operating system.
6 * The Netwide Assembler is copyright (C) 1996-1998 Simon Tatham and
7 * Julian Hall. All rights reserved. The software is
8 * redistributable under the licence given in the file "Licence"
9 * distributed in the NASM archive.
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <assert.h>
17 #include <inttypes.h>
19 #include "nasm.h"
20 #include "nasmlib.h"
21 #include "outform.h"
23 /* VERBOSE_WARNINGS: define this to add some extra warnings... */
24 #define VERBOSE_WARNINGS
26 #ifdef OF_RDF2
28 #include "rdoff/rdoff.h"
30 /* This signature is written to start of RDOFF files */
31 static const char *RDOFF2Id = RDOFF2_SIGNATURE;
33 /* Note that whenever a segment is referred to in the RDOFF file, its number
34 * is always half of the segment number that NASM uses to refer to it; this
35 * is because NASM only allocates even numbered segments, so as to not
36 * waste any of the 16 bits of segment number written to the file - this
37 * allows up to 65533 external labels to be defined; otherwise it would be
38 * 32764. */
40 #define COUNT_SEGTYPES 9
42 static char *segmenttypes[COUNT_SEGTYPES] = {
43 "null", "text", "code", "data",
44 "comment", "lcomment", "pcomment",
45 "symdebug", "linedebug"
48 static int segmenttypenumbers[COUNT_SEGTYPES] = {
49 0, 1, 1, 2, 3, 4, 5, 6, 7
52 /* code for managing buffers needed to separate code and data into individual
53 * sections until they are ready to be written to the file.
54 * We'd better hope that it all fits in memory else we're buggered... */
56 #define BUF_BLOCK_LEN 4088 /* selected to match page size (4096)
57 * on 80x86 machines for efficiency */
59 /***********************************************************************
60 * Actual code to deal with RDOFF2 ouput format begins here...
63 /* global variables set during the initialisation phase */
65 static struct SAA *seg[RDF_MAXSEGS]; /* seg 0 = code, seg 1 = data */
66 static struct SAA *header; /* relocation/import/export records */
68 static FILE *ofile;
70 static efunc error;
72 static struct seginfo {
73 char *segname;
74 int segnumber;
75 uint16_t segtype;
76 uint16_t segreserved;
77 int32_t seglength;
78 } segments[RDF_MAXSEGS];
80 static int nsegments;
82 static int32_t bsslength;
83 static int32_t headerlength;
85 static void rdf2_init(FILE * fp, efunc errfunc, ldfunc ldef, evalfunc eval)
88 (void)ldef;
89 (void)eval;
91 maxbits = 64;
93 int segtext, segdata, segbss;
95 /* set up the initial segments */
96 segments[0].segname = ".text";
97 segments[0].segnumber = 0;
98 segments[0].segtype = 1;
99 segments[0].segreserved = 0;
100 segments[0].seglength = 0;
102 segments[1].segname = ".data";
103 segments[1].segnumber = 1;
104 segments[1].segtype = 2;
105 segments[1].segreserved = 0;
106 segments[1].seglength = 0;
108 segments[2].segname = ".bss";
109 segments[2].segnumber = 2;
110 segments[2].segtype = 0xFFFF; /* reserved - should never be produced */
111 segments[2].segreserved = 0;
112 segments[2].seglength = 0;
114 nsegments = 3;
116 ofile = fp;
117 error = errfunc;
119 seg[0] = saa_init(1L);
120 seg[1] = saa_init(1L);
121 seg[2] = NULL; /* special case! */
123 header = saa_init(1L);
125 segtext = seg_alloc();
126 segdata = seg_alloc();
127 segbss = seg_alloc();
128 if (segtext != 0 || segdata != 2 || segbss != 4)
129 error(ERR_PANIC,
130 "rdf segment numbers not allocated as expected (%d,%d,%d)",
131 segtext, segdata, segbss);
132 bsslength = 0;
133 headerlength = 0;
136 static int32_t rdf2_section_names(char *name, int pass, int *bits)
139 (void)pass;
141 int i;
142 char *p, *q;
143 int code = -1;
144 int reserved = 0;
147 * Default is 32 bits, in the text segment.
149 if (!name) {
150 *bits = 32;
151 return 0;
154 /* look for segment type code following segment name */
155 p = name;
156 while (*p && !isspace(*p))
157 p++;
158 if (*p) { /* we're now in whitespace */
159 *p++ = '\0';
160 while (*p && isspace(80))
161 *p++ = '\0';
163 if (*p) { /* we're now in an attribute value */
165 * see if we have an optional ',number' following the type code
167 if ((q = strchr(p, ','))) {
168 *q++ = '\0';
170 reserved = readnum(q, &i);
171 if (i) {
172 error(ERR_NONFATAL,
173 "value following comma must be numeric");
174 reserved = 0;
178 * check it against the text strings in segmenttypes
181 for (i = 0; i < COUNT_SEGTYPES; i++)
182 if (!nasm_stricmp(p, segmenttypes[i])) {
183 code = segmenttypenumbers[i];
184 break;
186 if (code == -1) { /* didn't find anything */
187 code = readnum(p, &i);
188 if (i) {
189 error(ERR_NONFATAL, "unrecognised RDF segment type (%s)",
191 code = 3;
195 for (i = 0; i < nsegments; i++) {
196 if (!strcmp(name, segments[i].segname)) {
197 if (code != -1 || reserved != 0)
198 error(ERR_NONFATAL, "segment attributes specified on"
199 " redeclaration of segment");
200 return segments[i].segnumber * 2;
204 /* declaring a new segment! */
206 if (code == -1) {
207 error(ERR_NONFATAL, "new segment declared without type code");
208 code = 3;
210 if (nsegments == RDF_MAXSEGS) {
211 error(ERR_FATAL, "reached compiled-in maximum segment limit (%d)",
212 RDF_MAXSEGS);
213 return NO_SEG;
216 segments[nsegments].segname = nasm_strdup(name);
217 i = seg_alloc();
218 if (i % 2 != 0)
219 error(ERR_PANIC, "seg_alloc() returned odd number");
220 segments[nsegments].segnumber = i >> 1;
221 segments[nsegments].segtype = code;
222 segments[nsegments].segreserved = reserved;
223 segments[nsegments].seglength = 0;
225 seg[nsegments] = saa_init(1L);
227 return i;
231 * Write relocation record
233 static void write_reloc_rec(struct RelocRec *r)
235 char buf[4], *b;
237 if (r->refseg != (uint16_t) NO_SEG && (r->refseg & 1)) /* segment base ref */
238 r->type = RDFREC_SEGRELOC;
240 r->refseg >>= 1; /* adjust segment nos to RDF rather than NASM */
242 saa_wbytes(header, &r->type, 1);
243 saa_wbytes(header, &r->reclen, 1);
244 saa_wbytes(header, &r->segment, 1);
245 b = buf;
246 WRITELONG(b, r->offset);
247 saa_wbytes(header, buf, 4);
248 saa_wbytes(header, &r->length, 1);
249 b = buf;
250 WRITESHORT(b, r->refseg);
251 saa_wbytes(header, buf, 2);
252 headerlength += r->reclen + 2;
256 * Write export record
258 static void write_export_rec(struct ExportRec *r)
260 char buf[4], *b;
262 r->segment >>= 1;
264 saa_wbytes(header, &r->type, 1);
265 saa_wbytes(header, &r->reclen, 1);
266 saa_wbytes(header, &r->flags, 1);
267 saa_wbytes(header, &r->segment, 1);
268 b = buf;
269 WRITELONG(b, r->offset);
270 saa_wbytes(header, buf, 4);
271 saa_wbytes(header, r->label, strlen(r->label) + 1);
272 headerlength += r->reclen + 2;
275 static void write_import_rec(struct ImportRec *r)
277 char buf[4], *b;
279 r->segment >>= 1;
281 saa_wbytes(header, &r->type, 1);
282 saa_wbytes(header, &r->reclen, 1);
283 saa_wbytes(header, &r->flags, 1);
284 b = buf;
285 WRITESHORT(b, r->segment);
286 saa_wbytes(header, buf, 2);
287 saa_wbytes(header, r->label, strlen(r->label) + 1);
288 headerlength += r->reclen + 2;
292 * Write BSS record
294 static void write_bss_rec(struct BSSRec *r)
296 char buf[4], *b;
298 saa_wbytes(header, &r->type, 1);
299 saa_wbytes(header, &r->reclen, 1);
300 b = buf;
301 WRITELONG(b, r->amount);
302 saa_wbytes(header, buf, 4);
303 headerlength += r->reclen + 2;
307 * Write common variable record
309 static void write_common_rec(struct CommonRec *r)
311 char buf[4], *b;
313 r->segment >>= 1;
315 saa_wbytes(header, &r->type, 1);
316 saa_wbytes(header, &r->reclen, 1);
317 b = buf;
318 WRITESHORT(b, r->segment);
319 saa_wbytes(header, buf, 2);
320 b = buf;
321 WRITELONG(b, r->size);
322 saa_wbytes(header, buf, 4);
323 b = buf;
324 WRITESHORT(b, r->align);
325 saa_wbytes(header, buf, 2);
326 saa_wbytes(header, r->label, strlen(r->label) + 1);
327 headerlength += r->reclen + 2;
331 * Write library record
333 static void write_dll_rec(struct DLLRec *r)
335 saa_wbytes(header, &r->type, 1);
336 saa_wbytes(header, &r->reclen, 1);
337 saa_wbytes(header, r->libname, strlen(r->libname) + 1);
338 headerlength += r->reclen + 2;
342 * Write module name record
344 static void write_modname_rec(struct ModRec *r)
346 saa_wbytes(header, &r->type, 1);
347 saa_wbytes(header, &r->reclen, 1);
348 saa_wbytes(header, r->modname, strlen(r->modname) + 1);
349 headerlength += r->reclen + 2;
353 * Handle export, import and common records.
355 static void rdf2_deflabel(char *name, int32_t segment, int32_t offset,
356 int is_global, char *special)
358 struct ExportRec r;
359 struct ImportRec ri;
360 struct CommonRec ci;
361 static int farsym = 0;
362 static int i;
363 char symflags = 0;
364 int len;
366 /* Check if the label length is OK */
367 if ((len = strlen(name)) >= EXIM_LABEL_MAX) {
368 error(ERR_NONFATAL, "label size exceeds %d bytes", EXIM_LABEL_MAX);
369 return;
371 if (!len) {
372 error(ERR_NONFATAL, "zero-length label");
373 return;
376 if (is_global == 2) {
377 /* Common variable */
378 ci.type = RDFREC_COMMON;
379 ci.size = offset;
380 ci.segment = segment;
381 strcpy(ci.label, name);
382 ci.reclen = 9 + len;
383 ci.align = 0;
386 * Check the special text to see if it's a valid number and power
387 * of two; if so, store it as the alignment for the common variable.
389 if (special) {
390 int err;
391 ci.align = readnum(special, &err);
392 if (err)
393 error(ERR_NONFATAL, "alignment constraint `%s' is not a"
394 " valid number", special);
395 else if ((ci.align | (ci.align - 1)) != 2 * ci.align - 1)
396 error(ERR_NONFATAL, "alignment constraint `%s' is not a"
397 " power of two", special);
399 write_common_rec(&ci);
402 /* We don't care about local labels or fix-up hints */
403 if (is_global != 1)
404 return;
406 if (special) {
407 while (*special == ' ' || *special == '\t')
408 special++;
410 if (!nasm_strnicmp(special, "export", 6)) {
411 special += 6;
412 symflags |= SYM_GLOBAL;
413 } else if (!nasm_strnicmp(special, "import", 6)) {
414 special += 6;
415 symflags |= SYM_IMPORT;
418 if (*special) {
419 while (isspace(*special))
420 special++;
421 if (!nasm_stricmp(special, "far")) {
422 farsym = 1;
423 } else if (!nasm_stricmp(special, "near")) {
424 farsym = 0;
425 } else if (!nasm_stricmp(special, "proc") ||
426 !nasm_stricmp(special, "function")) {
427 symflags |= SYM_FUNCTION;
428 } else if (!nasm_stricmp(special, "data") ||
429 !nasm_stricmp(special, "object")) {
430 symflags |= SYM_DATA;
431 } else
432 error(ERR_NONFATAL, "unrecognised symbol type `%s'",
433 special);
437 if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
438 error(ERR_NONFATAL, "unrecognised special symbol `%s'", name);
439 return;
442 for (i = 0; i < nsegments; i++) {
443 if (segments[i].segnumber == segment >> 1)
444 break;
447 if (i >= nsegments) { /* EXTERN declaration */
448 ri.type = farsym ? RDFREC_FARIMPORT : RDFREC_IMPORT;
449 if (symflags & SYM_GLOBAL)
450 error(ERR_NONFATAL,
451 "symbol type conflict - EXTERN cannot be EXPORT");
452 ri.flags = symflags;
453 ri.segment = segment;
454 strcpy(ri.label, name);
455 ri.reclen = 4 + len;
456 write_import_rec(&ri);
457 } else if (is_global) {
458 r.type = RDFREC_GLOBAL; /* GLOBAL declaration */
459 if (symflags & SYM_IMPORT)
460 error(ERR_NONFATAL,
461 "symbol type conflict - GLOBAL cannot be IMPORT");
462 r.flags = symflags;
463 r.segment = segment;
464 r.offset = offset;
465 strcpy(r.label, name);
466 r.reclen = 7 + len;
467 write_export_rec(&r);
471 static void membufwrite(int segment, const void *data, int bytes)
473 int i;
474 char buf[4], *b;
476 for (i = 0; i < nsegments; i++) {
477 if (segments[i].segnumber == segment)
478 break;
480 if (i == nsegments)
481 error(ERR_PANIC, "can't find segment %d", segment);
483 if (bytes < 0) {
484 b = buf;
485 if (bytes == -2)
486 WRITESHORT(b, *(int16_t *)data);
487 else
488 WRITELONG(b, *(int32_t *)data);
489 data = buf;
490 bytes = -bytes;
492 segments[i].seglength += bytes;
493 saa_wbytes(seg[i], data, bytes);
496 static int getsegmentlength(int segment)
498 int i;
499 for (i = 0; i < nsegments; i++) {
500 if (segments[i].segnumber == segment)
501 break;
503 if (i == nsegments)
504 error(ERR_PANIC, "can't find segment %d", segment);
506 return segments[i].seglength;
509 static void rdf2_out(int32_t segto, const void *data, uint32_t type,
510 int32_t segment, int32_t wrt)
512 int32_t bytes = type & OUT_SIZMASK;
513 struct RelocRec rr;
514 uint8_t databuf[8], *pd;
515 int seg;
517 if (segto == NO_SEG) {
518 if ((type & OUT_TYPMASK) != OUT_RESERVE)
519 error(ERR_NONFATAL,
520 "attempt to assemble code in ABSOLUTE space");
521 return;
524 segto >>= 1; /* convert NASM segment no to RDF number */
526 for (seg = 0; seg < nsegments; seg++) {
527 if (segments[seg].segnumber == segto)
528 break;
530 if (seg >= nsegments) {
531 error(ERR_NONFATAL,
532 "specified segment not supported by rdf output format");
533 return;
536 if (wrt != NO_SEG) {
537 wrt = NO_SEG; /* continue to do _something_ */
538 error(ERR_NONFATAL, "WRT not supported by rdf output format");
541 type &= OUT_TYPMASK;
543 if (segto == 2 && type != OUT_RESERVE) {
544 error(ERR_NONFATAL, "BSS segments may not be initialized");
546 /* just reserve the space for now... */
548 if (type == OUT_REL2ADR)
549 bytes = 2;
550 else
551 bytes = 4;
552 type = OUT_RESERVE;
555 if (type == OUT_RESERVE) {
556 if (segto == 2) /* BSS segment space reserverd */
557 bsslength += bytes;
558 else
559 while (bytes--)
560 membufwrite(segto, databuf, 1);
561 } else if (type == OUT_RAWDATA) {
562 if (segment != NO_SEG)
563 error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
565 membufwrite(segto, data, bytes);
566 } else if (type == OUT_ADDRESS) {
568 /* if segment == NO_SEG then we are writing an address of an
569 object within the same segment - do not produce reloc rec. */
571 /* FIXME - is this behaviour sane? at first glance it doesn't
572 appear to be. Must test this thoroughly...! */
574 if (segment != NO_SEG) {
575 /* it's an address, so we must write a relocation record */
577 rr.type = RDFREC_RELOC; /* type signature */
578 rr.reclen = 8;
579 rr.segment = segto; /* segment we're currently in */
580 rr.offset = getsegmentlength(segto); /* current offset */
581 rr.length = bytes; /* length of reference */
582 rr.refseg = segment; /* segment referred to */
583 write_reloc_rec(&rr);
586 pd = databuf; /* convert address to little-endian */
587 if (bytes == 4)
588 WRITESHORT(pd, *(int32_t *)data);
589 else if (bytes == 8)
590 WRITEDLONG(pd, *(int64_t *)data);
591 else
592 WRITESHORT(pd, *(int32_t *)data);
594 membufwrite(segto, databuf, bytes);
596 } else if (type == OUT_REL2ADR) {
597 if (segment == segto)
598 error(ERR_PANIC, "intra-segment OUT_REL2ADR");
600 rr.reclen = 8;
601 rr.offset = getsegmentlength(segto); /* current offset */
602 rr.length = 2; /* length of reference */
603 rr.refseg = segment; /* segment referred to (will be >>1'd) */
605 if (segment != NO_SEG && segment % 2) {
606 rr.type = RDFREC_SEGRELOC;
607 rr.segment = segto; /* memory base refs *aren't ever* relative! */
608 write_reloc_rec(&rr);
610 /* what do we put in the code? Simply the data. This should almost
611 * always be zero, unless someone's doing segment arithmetic...
613 rr.offset = *(int32_t *)data;
614 } else {
615 rr.type = RDFREC_RELOC; /* type signature */
616 rr.segment = segto + 64; /* segment we're currently in + rel flag */
617 write_reloc_rec(&rr);
619 /* work out what to put in the code: offset of the end of this operand,
620 * subtracted from any data specified, so that loader can just add
621 * address of imported symbol onto it to get address relative to end of
622 * instruction: import_address + data(offset) - end_of_instrn */
624 rr.offset = *(int32_t *)data - (rr.offset + bytes);
627 membufwrite(segto, &rr.offset, -2);
628 } else if (type == OUT_REL4ADR) {
629 if ((segment == segto) && (globalbits != 64))
630 error(ERR_PANIC, "intra-segment OUT_REL4ADR");
631 if (segment != NO_SEG && segment % 2) {
632 error(ERR_PANIC, "erm... 4 byte segment base ref?");
635 rr.type = RDFREC_RELOC; /* type signature */
636 rr.segment = segto + 64; /* segment we're currently in + rel tag */
637 rr.offset = getsegmentlength(segto); /* current offset */
638 rr.length = 4; /* length of reference */
639 rr.refseg = segment; /* segment referred to */
640 rr.reclen = 8;
641 write_reloc_rec(&rr);
643 rr.offset = *(int32_t *)data - (rr.offset + bytes);
645 membufwrite(segto, &rr.offset, -4);
649 static void rdf2_cleanup(int debuginfo)
651 int32_t l;
652 struct BSSRec bs;
653 int i;
655 (void)debuginfo;
657 /* should write imported & exported symbol declarations to header here */
659 /* generate the output file... */
660 fwrite(RDOFF2Id, 6, 1, ofile); /* file type magic number */
662 if (bsslength != 0) { /* reserve BSS */
663 bs.type = RDFREC_BSS;
664 bs.amount = bsslength;
665 bs.reclen = 4;
666 write_bss_rec(&bs);
670 * calculate overall length of the output object
672 l = headerlength + 4;
674 for (i = 0; i < nsegments; i++) {
675 if (i == 2)
676 continue; /* skip BSS segment */
677 l += 10 + segments[i].seglength;
679 l += 10; /* null segment */
681 fwriteint32_t(l, ofile);
683 fwriteint32_t(headerlength, ofile);
684 saa_fpwrite(header, ofile); /* dump header */
685 saa_free(header);
687 for (i = 0; i < nsegments; i++) {
688 if (i == 2)
689 continue;
691 fwriteint16_t(segments[i].segtype, ofile);
692 fwriteint16_t(segments[i].segnumber, ofile);
693 fwriteint16_t(segments[i].segreserved, ofile);
694 fwriteint32_t(segments[i].seglength, ofile);
696 saa_fpwrite(seg[i], ofile);
697 saa_free(seg[i]);
700 /* null segment - write 10 bytes of zero */
701 fwriteint32_t(0, ofile);
702 fwriteint32_t(0, ofile);
703 fwriteint16_t(0, ofile);
705 fclose(ofile);
708 static int32_t rdf2_segbase(int32_t segment)
710 return segment;
714 * Handle RDOFF2 specific directives
716 static int rdf2_directive(char *directive, char *value, int pass)
718 int n;
720 /* Check if the name length is OK */
721 if ((n = strlen(value)) >= MODLIB_NAME_MAX) {
722 error(ERR_NONFATAL, "name size exceeds %d bytes", MODLIB_NAME_MAX);
723 return 0;
726 if (!strcmp(directive, "library")) {
727 if (pass == 1) {
728 struct DLLRec r;
729 r.type = RDFREC_DLL;
730 r.reclen = n + 1;
731 strcpy(r.libname, value);
732 write_dll_rec(&r);
734 return 1;
737 if (!strcmp(directive, "module")) {
738 if (pass == 1) {
739 struct ModRec r;
740 r.type = RDFREC_MODNAME;
741 r.reclen = n + 1;
742 strcpy(r.modname, value);
743 write_modname_rec(&r);
745 return 1;
748 return 0;
751 static void rdf2_filename(char *inname, char *outname, efunc error)
753 standard_extension(inname, outname, ".rdf", error);
756 static const char *rdf2_stdmac[] = {
757 "%define __SECT__ [section .text]",
758 "%imacro library 1+.nolist",
759 "[library %1]",
760 "%endmacro",
761 "%imacro module 1+.nolist",
762 "[module %1]",
763 "%endmacro",
764 "%macro __NASM_CDecl__ 1",
765 "%endmacro",
766 NULL
769 static int rdf2_set_info(enum geninfo type, char **val)
771 (void)type;
772 (void)val;
773 return 0;
776 struct ofmt of_rdf2 = {
777 "Relocatable Dynamic Object File Format v2.0",
778 "rdf",
779 NULL,
780 null_debug_arr,
781 &null_debug_form,
782 rdf2_stdmac,
783 rdf2_init,
784 rdf2_set_info,
785 rdf2_out,
786 rdf2_deflabel,
787 rdf2_section_names,
788 rdf2_segbase,
789 rdf2_directive,
790 rdf2_filename,
791 rdf2_cleanup
794 #endif /* OF_RDF2 */