1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2009 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ----------------------------------------------------------------------- */
35 * outrdf.c output routines for the Netwide Assembler to produce
36 * RDOFF format object files (which are intended mainly
37 * for use in proprietary projects, as the code to load and
38 * execute them is very simple). They will also be used
39 * for device drivers and possibly some executable files
40 * in the MOSCOW operating system. See Rdoff.txt for
54 #include "output/outform.h"
56 /* VERBOSE_WARNINGS: define this to add some extra warnings... */
57 #define VERBOSE_WARNINGS
61 typedef int16_t int16
; /* not sure if this will be required to be altered
62 at all... best to typedef it just in case */
64 static const char *RDOFFId
= "RDOFF1"; /* written to start of RDOFF files */
66 /* the records that can be found in the RDOFF header */
68 /* Note that whenever a segment is referred to in the RDOFF file, its number
69 * is always half of the segment number that NASM uses to refer to it; this
70 * is because NASM only allocates even numbered segments, so as to not
71 * waste any of the 16 bits of segment number written to the file - this
72 * allows up to 65533 external labels to be defined; otherwise it would be
76 char type
; /* must be 1 */
77 char segment
; /* only 0 for code, or 1 for data supported,
78 * but add 64 for relative refs (ie do not require
79 * reloc @ loadtime, only linkage) */
80 int32_t offset
; /* from start of segment in which reference is loc'd */
81 char length
; /* 1 2 or 4 bytes */
82 int16 refseg
; /* segment to which reference refers to */
86 char type
; /* must be 2 */
87 int16 segment
; /* segment number allocated to the label for reloc
88 * records - label is assumed to be at offset zero
89 * in this segment, so linker must fix up with offset
90 * of segment and of offset within segment */
91 char label
[33]; /* zero terminated... should be written to file until
92 * the zero, but not after it - max len = 32 chars */
96 char type
; /* must be 3 */
97 char segment
; /* segment referred to (0/1) */
98 int32_t offset
; /* offset within segment */
99 char label
[33]; /* zero terminated as above. max len = 32 chars */
103 char type
; /* must be 4 */
104 char libname
[128]; /* name of library to link with at load time */
108 char type
; /* must be 5 */
109 int32_t amount
; /* number of bytes BSS to reserve */
112 /* code for managing buffers needed to seperate code and data into individual
113 * sections until they are ready to be written to the file.
114 * We'd better hope that it all fits in memory else we're buggered... */
116 #define BUF_BLOCK_LEN 4088 /* selected to match page size (4096)
117 * on 80x86 machines for efficiency */
119 typedef struct memorybuffer
{
121 char buffer
[BUF_BLOCK_LEN
];
122 struct memorybuffer
*next
;
125 static memorybuffer
*newmembuf(void)
129 t
= nasm_malloc(sizeof(memorybuffer
));
136 static void membufwrite(memorybuffer
* b
, void *data
, int bytes
)
141 if (b
->next
) { /* memory buffer full - use next buffer */
142 membufwrite(b
->next
, data
, bytes
);
145 if ((bytes
< 0 && b
->length
- bytes
> BUF_BLOCK_LEN
)
146 || (bytes
> 0 && b
->length
+ bytes
> BUF_BLOCK_LEN
)) {
148 /* buffer full and no next allocated... allocate and initialize next
151 b
->next
= newmembuf();
152 membufwrite(b
->next
, data
, bytes
);
157 case -4: /* convert to little-endian */
158 l
= *(int32_t *)data
;
159 b
->buffer
[b
->length
++] = l
& 0xFF;
161 b
->buffer
[b
->length
++] = l
& 0xFF;
163 b
->buffer
[b
->length
++] = l
& 0xFF;
165 b
->buffer
[b
->length
++] = l
& 0xFF;
170 b
->buffer
[b
->length
++] = w
& 0xFF;
172 b
->buffer
[b
->length
++] = w
& 0xFF;
177 b
->buffer
[b
->length
++] = *(*(uint8_t **)&data
);
179 (*(uint8_t **)&data
)++;
185 static void membufdump(memorybuffer
* b
, FILE * fp
)
190 fwrite(b
->buffer
, 1, b
->length
, fp
);
192 membufdump(b
->next
, fp
);
195 static int membuflength(memorybuffer
* b
)
199 return b
->length
+ membuflength(b
->next
);
202 static void freemembuf(memorybuffer
* b
)
210 /***********************************************************************
211 * Actual code to deal with RDOFF ouput format begins here...
214 /* global variables set during the initialisation phase */
216 static memorybuffer
*seg
[2]; /* seg 0 = code, seg 1 = data */
217 static memorybuffer
*header
; /* relocation/import/export records */
223 static int segtext
, segdata
, segbss
;
224 static int32_t bsslength
;
226 static void rdf_init(FILE * fp
, efunc errfunc
, ldfunc ldef
, evalfunc eval
)
231 seg
[0] = newmembuf();
232 seg
[1] = newmembuf();
233 header
= newmembuf();
234 segtext
= seg_alloc();
235 segdata
= seg_alloc();
236 segbss
= seg_alloc();
237 if (segtext
!= 0 || segdata
!= 2 || segbss
!= 4)
239 "rdf segment numbers not allocated as expected (%d,%d,%d)",
240 segtext
, segdata
, segbss
);
244 static int32_t rdf_section_names(char *name
, int pass
, int *bits
)
247 * Default is 32 bits.
254 if (!strcmp(name
, ".text"))
256 else if (!strcmp(name
, ".data"))
258 else if (!strcmp(name
, ".bss"))
264 static void write_reloc_rec(struct RelocRec
*r
)
266 if (r
->refseg
!= NO_SEG
&& (r
->refseg
& 1))
267 error(ERR_NONFATAL
, "RDF format does not support segment base"
270 r
->refseg
>>= 1; /* adjust segment nos to RDF rather than NASM */
272 membufwrite(header
, &r
->type
, 1);
273 membufwrite(header
, &r
->segment
, 1);
274 membufwrite(header
, &r
->offset
, -4);
275 membufwrite(header
, &r
->length
, 1);
276 membufwrite(header
, &r
->refseg
, -2); /* 9 bytes written */
279 static void write_export_rec(struct ExportRec
*r
)
283 membufwrite(header
, &r
->type
, 1);
284 membufwrite(header
, &r
->segment
, 1);
285 membufwrite(header
, &r
->offset
, -4);
286 membufwrite(header
, r
->label
, strlen(r
->label
) + 1);
289 static void write_import_rec(struct ImportRec
*r
)
293 membufwrite(header
, &r
->type
, 1);
294 membufwrite(header
, &r
->segment
, -2);
295 membufwrite(header
, r
->label
, strlen(r
->label
) + 1);
298 static void write_bss_rec(struct BSSRec
*r
)
300 membufwrite(header
, &r
->type
, 1);
301 membufwrite(header
, &r
->amount
, -4);
304 static void write_dll_rec(struct DLLRec
*r
)
306 membufwrite(header
, &r
->type
, 1);
307 membufwrite(header
, r
->libname
, strlen(r
->libname
) + 1);
310 static void rdf_deflabel(char *name
, int32_t segment
, int32_t offset
,
311 int is_global
, char *special
)
315 #ifdef VERBOSE_WARNINGS
316 static int warned_common
= 0;
320 error(ERR_NONFATAL
, "RDOFF format does not support any"
321 " special symbol types");
323 if (name
[0] == '.' && name
[1] == '.' && name
[2] != '@') {
324 error(ERR_NONFATAL
, "unrecognised special symbol `%s'", name
);
328 if (is_global
== 2) {
329 #ifdef VERBOSE_WARNINGS
330 if (!warned_common
) {
332 "common declarations not supported: using extern");
339 if (segment
> 4) { /* EXTERN declaration */
341 ri
.segment
= segment
;
342 strncpy(ri
.label
, name
, 32);
344 write_import_rec(&ri
);
345 } else if (is_global
) {
349 strncpy(r
.label
, name
, 32);
351 write_export_rec(&r
);
355 static void rdf_out(int32_t segto
, void *data
, uint32_t type
,
356 int32_t segment
, int32_t wrt
)
358 int32_t bytes
= type
& OUT_SIZMASK
;
360 uint8_t databuf
[8], *pd
;
362 if (segto
== NO_SEG
) {
363 if ((type
& OUT_TYPMASK
) != OUT_RESERVE
)
365 "attempt to assemble code in ABSOLUTE space");
369 segto
>>= 1; /* convert NASM segment no to RDF number */
371 if (segto
!= 0 && segto
!= 1 && segto
!= 2) {
373 "specified segment not supported by rdf output format");
378 wrt
= NO_SEG
; /* continue to do _something_ */
379 error(ERR_NONFATAL
, "WRT not supported by rdf output format");
384 if (segto
== 2 && type
!= OUT_RESERVE
) {
385 error(ERR_NONFATAL
, "BSS segments may not be initialized");
387 /* just reserve the space for now... */
389 if (type
== OUT_REL2ADR
)
396 if (type
== OUT_RESERVE
) {
397 if (segto
== 2) /* BSS segment space reserverd */
401 membufwrite(seg
[segto
], databuf
, 1);
402 } else if (type
== OUT_RAWDATA
) {
403 if (segment
!= NO_SEG
)
404 error(ERR_PANIC
, "OUT_RAWDATA with other than NO_SEG");
405 membufwrite(seg
[segto
], data
, bytes
);
406 } else if (type
== OUT_ADDRESS
) {
408 /* if segment == NO_SEG then we are writing an address of an
409 object within the same segment - do not produce reloc rec. */
411 if (segment
!= NO_SEG
) {
413 /* it's an address, so we must write a relocation record */
415 rr
.type
= 1; /* type signature */
416 rr
.segment
= segto
; /* segment we're currently in */
417 rr
.offset
= membuflength(seg
[segto
]); /* current offset */
418 rr
.length
= bytes
; /* length of reference */
419 rr
.refseg
= segment
; /* segment referred to */
420 write_reloc_rec(&rr
);
423 pd
= databuf
; /* convert address to little-endian */
424 WRITEADDR(pd
, *(int64_t *)data
, bytes
);
425 membufwrite(seg
[segto
], databuf
, bytes
);
426 } else if (type
== OUT_REL2ADR
) {
427 if (segment
== segto
)
428 error(ERR_PANIC
, "intra-segment OUT_REL2ADR");
429 if (segment
!= NO_SEG
&& segment
% 2) {
431 "rdf format does not support segment base refs");
434 rr
.type
= 1; /* type signature */
435 rr
.segment
= segto
+ 64; /* segment we're currently in + rel flag */
436 rr
.offset
= membuflength(seg
[segto
]); /* current offset */
437 rr
.length
= 2; /* length of reference */
438 rr
.refseg
= segment
; /* segment referred to */
439 write_reloc_rec(&rr
);
441 /* work out what to put in the code: offset of the end of this operand,
442 * subtracted from any data specified, so that loader can just add
443 * address of imported symbol onto it to get address relative to end of
444 * instruction: import_address + data(offset) - end_of_instrn */
446 rr
.offset
= *(int64_t *)data
- (rr
.offset
+ bytes
);
448 membufwrite(seg
[segto
], &rr
.offset
, -2);
449 } else if (type
== OUT_REL4ADR
) {
450 if ((segment
== segto
) && (globalbits
!= 64))
451 error(ERR_PANIC
, "intra-segment OUT_REL4ADR");
452 if (segment
!= NO_SEG
&& segment
% 2) {
454 "rdf format does not support segment base refs");
457 rr
.type
= 1; /* type signature */
458 rr
.segment
= segto
+ 64; /* segment we're currently in + rel tag */
459 rr
.offset
= membuflength(seg
[segto
]); /* current offset */
460 rr
.length
= 4; /* length of reference */
461 rr
.refseg
= segment
; /* segment referred to */
462 write_reloc_rec(&rr
);
464 rr
.offset
= *(int64_t *)data
- (rr
.offset
+ bytes
);
465 membufwrite(seg
[segto
], &rr
.offset
, -4);
469 static void rdf_cleanup(int debuginfo
)
477 /* should write imported & exported symbol declarations to header here */
479 /* generate the output file... */
480 fwrite(RDOFFId
, 6, 1, ofile
); /* file type magic number */
482 if (bsslength
!= 0) { /* reserve BSS */
484 bs
.amount
= bsslength
;
488 l
= membuflength(header
);
492 fwrite(b
, 4, 1, ofile
); /* write length of header */
493 membufdump(header
, ofile
); /* dump header */
495 l
= membuflength(seg
[0]);
496 d
= b
; /* code segment */
499 fwrite(b
, 4, 1, ofile
);
500 membufdump(seg
[0], ofile
);
502 l
= membuflength(seg
[1]);
503 d
= b
; /* data segment */
506 fwrite(b
, 4, 1, ofile
);
507 membufdump(seg
[1], ofile
);
514 static int32_t rdf_segbase(int32_t segment
)
519 static int rdf_directive(char *directive
, char *value
, int pass
)
523 if (!strcmp(directive
, "library")) {
526 strcpy(r
.libname
, value
);
535 static void rdf_filename(char *inname
, char *outname
, efunc error
)
537 standard_extension(inname
, outname
, ".rdf", error
);
540 extern macros_t rdf_stdmac
[];
542 static int rdf_set_info(enum geninfo type
, char **val
)
547 struct ofmt of_rdf
= {
548 "Relocatable Dynamic Object File Format v1.1",