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