1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2013 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 * outas86.c output routines for the Netwide Assembler to produce
36 * Linux as86 (bin86-0.3) object files
51 #include "output/outform.h"
52 #include "output/outlib.h"
58 int type
; /* 0 = absolute, 1 = seg, 2 = sym */
59 int32_t offset
; /* relative offset */
60 int number
; /* symbol/segment number (4=bss) */
61 int32_t bytes
; /* size of reloc or of absolute data */
62 bool relative
; /* relative address? */
66 int32_t strpos
; /* string table position of name */
67 int flags
; /* symbol flags */
68 int segment
; /* 4=bss at this point */
69 int32_t value
; /* address, or COMMON variable size */
73 * Section IDs - used in Piece.number and Symbol.segment.
75 #define SECT_TEXT 0 /* text section */
76 #define SECT_DATA 3 /* data section */
77 #define SECT_BSS 4 /* bss section */
80 * Flags used in Symbol.flags.
82 #define SYM_ENTRY (1<<8)
83 #define SYM_EXPORT (1<<7)
84 #define SYM_IMPORT (1<<6)
85 #define SYM_ABSOLUTE (1<<4)
89 uint32_t datalen
, size
, len
;
91 struct Piece
*head
, *last
, **tail
;
94 static char as86_module
[FILENAME_MAX
];
96 static struct Section stext
, sdata
;
97 static uint32_t bsslen
;
98 static int32_t bssindex
;
100 static struct SAA
*syms
;
101 static uint32_t nsyms
;
103 static struct RAA
*bsym
;
105 static struct SAA
*strs
;
106 static uint32_t strslen
;
108 static int as86_reloc_size
;
110 static void as86_write(void);
111 static void as86_write_section(struct Section
*, int);
112 static int as86_add_string(char *name
);
113 static void as86_sect_write(struct Section
*, const uint8_t *,
116 static void as86_init(void)
118 stext
.data
= saa_init(1L);
120 stext
.head
= stext
.last
= NULL
;
121 stext
.tail
= &stext
.head
;
122 sdata
.data
= saa_init(1L);
124 sdata
.head
= sdata
.last
= NULL
;
125 sdata
.tail
= &sdata
.head
;
127 stext
.len
= stext
.datalen
= stext
.size
=
128 sdata
.len
= sdata
.datalen
= sdata
.size
= 0;
129 stext
.index
= seg_alloc();
130 sdata
.index
= seg_alloc();
131 bssindex
= seg_alloc();
132 syms
= saa_init((int32_t)sizeof(struct Symbol
));
138 as86_add_string(as86_module
);
141 static void as86_cleanup(int debuginfo
)
148 saa_free(stext
.data
);
151 stext
.head
= stext
.head
->next
;
154 saa_free(sdata
.data
);
157 sdata
.head
= sdata
.head
->next
;
165 static int32_t as86_section_names(char *name
, int pass
, int *bits
)
171 * Default is 16 bits.
179 if (!strcmp(name
, ".text"))
181 else if (!strcmp(name
, ".data"))
183 else if (!strcmp(name
, ".bss"))
189 static int as86_add_string(char *name
)
192 int length
= strlen(name
);
194 saa_wbytes(strs
, name
, (int32_t)(length
+ 1));
195 strslen
+= 1 + length
;
200 static void as86_deflabel(char *name
, int32_t segment
, int64_t offset
,
201 int is_global
, char *special
)
203 bool is_start
= false;
207 nasm_error(ERR_NONFATAL
, "as86 format does not support any"
208 " special symbol types");
211 if (name
[0] == '.' && name
[1] == '.' && name
[2] != '@') {
212 if (strcmp(name
, "..start")) {
213 nasm_error(ERR_NONFATAL
, "unrecognised special symbol `%s'", name
);
220 sym
= saa_wstruct(syms
);
222 sym
->strpos
= as86_add_string(name
);
226 sym
->flags
= SYM_ENTRY
;
228 if (segment
== NO_SEG
)
229 sym
->flags
|= SYM_ABSOLUTE
, sym
->segment
= 0;
230 else if (segment
== stext
.index
)
231 sym
->segment
= SECT_TEXT
;
232 else if (segment
== sdata
.index
)
233 sym
->segment
= SECT_DATA
;
234 else if (segment
== bssindex
)
235 sym
->segment
= SECT_BSS
;
237 sym
->flags
|= SYM_IMPORT
;
242 sym
->segment
= 3; /* already have IMPORT */
244 if (is_global
&& !(sym
->flags
& SYM_IMPORT
))
245 sym
->flags
|= SYM_EXPORT
;
250 * define the references from external-symbol segment numbers
251 * to these symbol records.
253 if (segment
!= NO_SEG
&& segment
!= stext
.index
&&
254 segment
!= sdata
.index
&& segment
!= bssindex
)
255 bsym
= raa_write(bsym
, segment
, nsyms
);
260 static void as86_add_piece(struct Section
*sect
, int type
, int32_t offset
,
261 int32_t segment
, int32_t bytes
, int relative
)
267 if (type
== 0 && sect
->last
&& sect
->last
->type
== 0) {
268 sect
->last
->bytes
+= bytes
;
272 p
= sect
->last
= *sect
->tail
= nasm_malloc(sizeof(struct Piece
));
273 sect
->tail
= &p
->next
;
279 p
->relative
= relative
;
281 if (type
== 1 && segment
== stext
.index
)
282 p
->number
= SECT_TEXT
;
283 else if (type
== 1 && segment
== sdata
.index
)
284 p
->number
= SECT_DATA
;
285 else if (type
== 1 && segment
== bssindex
)
286 p
->number
= SECT_BSS
;
288 p
->number
= raa_read(bsym
, segment
), p
->type
= 2;
291 static void as86_out(int32_t segto
, const void *data
,
292 enum out_type type
, uint64_t size
,
293 int32_t segment
, int32_t wrt
)
297 uint8_t mydata
[4], *p
;
300 wrt
= NO_SEG
; /* continue to do _something_ */
301 nasm_error(ERR_NONFATAL
, "WRT not supported by as86 output format");
305 * handle absolute-assembly (structure definitions)
307 if (segto
== NO_SEG
) {
308 if (type
!= OUT_RESERVE
)
309 nasm_error(ERR_NONFATAL
, "attempt to assemble code in [ABSOLUTE]"
314 if (segto
== stext
.index
)
316 else if (segto
== sdata
.index
)
318 else if (segto
== bssindex
)
321 nasm_error(ERR_WARNING
, "attempt to assemble code in"
322 " segment %d: defaulting to `.text'", segto
);
326 if (!s
&& type
!= OUT_RESERVE
) {
327 nasm_error(ERR_WARNING
, "attempt to initialize memory in the"
328 " BSS section: ignored");
329 bsslen
+= realsize(type
, size
);
333 memset(mydata
, 0, sizeof(mydata
));
335 if (type
== OUT_RESERVE
) {
337 nasm_error(ERR_WARNING
, "uninitialized space declared in"
338 " %s section: zeroing",
339 (segto
== stext
.index
? "code" : "data"));
340 as86_sect_write(s
, NULL
, size
);
341 as86_add_piece(s
, 0, 0L, 0L, size
, 0);
344 } else if (type
== OUT_RAWDATA
) {
345 if (segment
!= NO_SEG
)
346 nasm_error(ERR_PANIC
, "OUT_RAWDATA with other than NO_SEG");
347 as86_sect_write(s
, data
, size
);
348 as86_add_piece(s
, 0, 0L, 0L, size
, 0);
349 } else if (type
== OUT_ADDRESS
) {
350 int asize
= abs((int)size
);
351 if (segment
!= NO_SEG
) {
353 nasm_error(ERR_NONFATAL
, "as86 format does not support"
354 " segment base references");
356 offset
= *(int64_t *)data
;
357 as86_add_piece(s
, 1, offset
, segment
, asize
, 0);
361 WRITELONG(p
, *(int64_t *)data
);
362 as86_sect_write(s
, data
, asize
);
363 as86_add_piece(s
, 0, 0L, 0L, asize
, 0);
365 } else if (type
== OUT_REL2ADR
) {
366 if (segment
== segto
)
367 nasm_error(ERR_PANIC
, "intra-segment OUT_REL2ADR");
368 if (segment
!= NO_SEG
) {
370 nasm_error(ERR_NONFATAL
, "as86 format does not support"
371 " segment base references");
373 offset
= *(int64_t *)data
;
374 as86_add_piece(s
, 1, offset
- size
+ 2, segment
, 2L,
378 } else if (type
== OUT_REL4ADR
) {
379 if (segment
== segto
)
380 nasm_error(ERR_PANIC
, "intra-segment OUT_REL4ADR");
381 if (segment
!= NO_SEG
) {
383 nasm_error(ERR_NONFATAL
, "as86 format does not support"
384 " segment base references");
386 offset
= *(int64_t *)data
;
387 as86_add_piece(s
, 1, offset
- size
+ 4, segment
, 4L,
394 static void as86_write(void)
397 int32_t symlen
, seglen
, segsize
;
400 * First, go through the symbol records working out how big
401 * each will be. Also fix up BSS references at this time, and
402 * set the flags words up completely.
406 for (i
= 0; i
< nsyms
; i
++) {
407 struct Symbol
*sym
= saa_rstruct(syms
);
408 if (sym
->segment
== SECT_BSS
)
409 sym
->segment
= SECT_DATA
, sym
->value
+= sdata
.len
;
410 sym
->flags
|= sym
->segment
;
412 sym
->flags
|= 0 << 14, symlen
+= 4;
413 else if (sym
->value
>= 0 && sym
->value
<= 255)
414 sym
->flags
|= 1 << 14, symlen
+= 5;
415 else if (sym
->value
>= 0 && sym
->value
<= 65535L)
416 sym
->flags
|= 2 << 14, symlen
+= 6;
418 sym
->flags
|= 3 << 14, symlen
+= 8;
422 * Now do the same for the segments, and get the segment size
423 * descriptor word at the same time.
425 seglen
= segsize
= 0;
426 if ((uint32_t)stext
.len
> 65535L)
427 segsize
|= 0x03000000L
, seglen
+= 4;
429 segsize
|= 0x02000000L
, seglen
+= 2;
430 if ((uint32_t)sdata
.len
> 65535L)
431 segsize
|= 0xC0000000L
, seglen
+= 4;
433 segsize
|= 0x80000000L
, seglen
+= 2;
436 * Emit the as86 header.
438 fwriteint32_t(0x000186A3L
, ofile
);
440 fwriteint32_t(27 + symlen
+ seglen
+ strslen
, ofile
); /* header length */
441 fwriteint32_t(stext
.len
+ sdata
.len
+ bsslen
, ofile
);
442 fwriteint16_t(strslen
, ofile
);
443 fwriteint16_t(0, ofile
); /* class = revision = 0 */
444 fwriteint32_t(0x55555555L
, ofile
); /* segment max sizes: always this */
445 fwriteint32_t(segsize
, ofile
); /* segment size descriptors */
446 if (segsize
& 0x01000000L
)
447 fwriteint32_t(stext
.len
, ofile
);
449 fwriteint16_t(stext
.len
, ofile
);
450 if (segsize
& 0x40000000L
)
451 fwriteint32_t(sdata
.len
+ bsslen
, ofile
);
453 fwriteint16_t(sdata
.len
+ bsslen
, ofile
);
454 fwriteint16_t(nsyms
, ofile
);
457 * Write the symbol table.
460 for (i
= 0; i
< nsyms
; i
++) {
461 struct Symbol
*sym
= saa_rstruct(syms
);
462 fwriteint16_t(sym
->strpos
, ofile
);
463 fwriteint16_t(sym
->flags
, ofile
);
464 switch (sym
->flags
& (3 << 14)) {
468 fputc(sym
->value
, ofile
);
471 fwriteint16_t(sym
->value
, ofile
);
474 fwriteint32_t(sym
->value
, ofile
);
480 * Write out the string table.
482 saa_fpwrite(strs
, ofile
);
485 * Write the program text.
487 as86_reloc_size
= -1;
488 as86_write_section(&stext
, SECT_TEXT
);
489 as86_write_section(&sdata
, SECT_DATA
);
491 * Append the BSS section to the .data section
493 if (bsslen
> 65535L) {
495 fwriteint32_t(bsslen
, ofile
);
496 } else if (bsslen
> 255) {
498 fwriteint16_t(bsslen
, ofile
);
501 fputc(bsslen
, ofile
);
504 fputc(0, ofile
); /* termination */
507 static void as86_set_rsize(int size
)
509 if (as86_reloc_size
!= size
) {
510 switch (as86_reloc_size
= size
) {
521 nasm_error(ERR_PANIC
, "bizarre relocation size %d", size
);
527 static void as86_write_section(struct Section
*sect
, int index
)
533 fputc(0x20 + index
, ofile
); /* select the right section */
535 saa_rewind(sect
->data
);
537 for (p
= sect
->head
; p
; p
= p
->next
)
541 * Absolute data. Emit it in chunks of at most 64
547 int32_t tmplen
= (length
> 64 ? 64 : length
);
548 fputc(0x40 | (tmplen
& 0x3F), ofile
);
549 saa_rnbytes(sect
->data
, buf
, tmplen
);
550 nasm_write(buf
, tmplen
, ofile
);
552 } while (length
> 0);
556 * A segment-type relocation. First fix up the BSS.
558 if (p
->number
== SECT_BSS
)
559 p
->number
= SECT_DATA
, p
->offset
+= sdata
.len
;
560 as86_set_rsize(p
->bytes
);
561 fputc(0x80 | (p
->relative
? 0x20 : 0) | p
->number
, ofile
);
562 if (as86_reloc_size
== 2)
563 fwriteint16_t(p
->offset
, ofile
);
565 fwriteint32_t(p
->offset
, ofile
);
569 * A symbol-type relocation.
571 as86_set_rsize(p
->bytes
);
582 (p
->relative
? 0x20 : 0) |
583 (p
->number
> 255 ? 0x04 : 0) | s
, ofile
);
585 fwriteint16_t(p
->number
, ofile
);
587 fputc(p
->number
, ofile
);
592 fputc(p
->offset
, ofile
);
595 fwriteint16_t(p
->offset
, ofile
);
598 fwriteint32_t(p
->offset
, ofile
);
605 static void as86_sect_write(struct Section
*sect
,
606 const uint8_t *data
, uint32_t len
)
608 saa_wbytes(sect
->data
, data
, len
);
609 sect
->datalen
+= len
;
612 static int32_t as86_segbase(int32_t segment
)
617 static void as86_filename(char *inname
, char *outname
)
621 if ((p
= strrchr(inname
, '.')) != NULL
) {
622 strncpy(as86_module
, inname
, p
- inname
);
623 as86_module
[p
- inname
] = '\0';
625 strcpy(as86_module
, inname
);
627 standard_extension(inname
, outname
, ".o");
630 extern macros_t as86_stdmac
[];
632 struct ofmt of_as86
= {
633 "Linux as86 (bin86 version 0.3) object files",