1 /* outas86.c output routines for the Netwide Assembler to produce
2 * Linux as86 (bin86-0.3) object files
4 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
5 * Julian Hall. All rights reserved. The software is
6 * redistributable under the license given in the file "LICENSE"
7 * distributed in the NASM archive.
29 int type
; /* 0 = absolute, 1 = seg, 2 = sym */
30 int32_t offset
; /* relative offset */
31 int number
; /* symbol/segment number (4=bss) */
32 int32_t bytes
; /* size of reloc or of absolute data */
33 bool relative
; /* relative address? */
37 int32_t strpos
; /* string table position of name */
38 int flags
; /* symbol flags */
39 int segment
; /* 4=bss at this point */
40 int32_t value
; /* address, or COMMON variable size */
44 * Section IDs - used in Piece.number and Symbol.segment.
46 #define SECT_TEXT 0 /* text section */
47 #define SECT_DATA 3 /* data section */
48 #define SECT_BSS 4 /* bss section */
51 * Flags used in Symbol.flags.
53 #define SYM_ENTRY (1<<8)
54 #define SYM_EXPORT (1<<7)
55 #define SYM_IMPORT (1<<6)
56 #define SYM_ABSOLUTE (1<<4)
60 uint32_t datalen
, size
, len
;
62 struct Piece
*head
, *last
, **tail
;
65 static char as86_module
[FILENAME_MAX
];
67 static struct Section stext
, sdata
;
68 static uint32_t bsslen
;
69 static int32_t bssindex
;
71 static struct SAA
*syms
;
72 static uint32_t nsyms
;
74 static struct RAA
*bsym
;
76 static struct SAA
*strs
;
77 static uint32_t strslen
;
79 static int as86_reloc_size
;
84 static void as86_write(void);
85 static void as86_write_section(struct Section
*, int);
86 static int as86_add_string(char *name
);
87 static void as86_sect_write(struct Section
*, const uint8_t *,
90 static void as86_init(FILE * fp
, efunc errfunc
, ldfunc ldef
, evalfunc eval
)
94 (void)ldef
; /* placate optimisers */
96 stext
.data
= saa_init(1L);
98 stext
.head
= stext
.last
= NULL
;
99 stext
.tail
= &stext
.head
;
100 sdata
.data
= saa_init(1L);
102 sdata
.head
= sdata
.last
= NULL
;
103 sdata
.tail
= &sdata
.head
;
105 stext
.len
= stext
.datalen
= stext
.size
=
106 sdata
.len
= sdata
.datalen
= sdata
.size
= 0;
107 stext
.index
= seg_alloc();
108 sdata
.index
= seg_alloc();
109 bssindex
= seg_alloc();
110 syms
= saa_init((int32_t)sizeof(struct Symbol
));
116 as86_add_string(as86_module
);
119 static void as86_cleanup(int debuginfo
)
127 saa_free(stext
.data
);
130 stext
.head
= stext
.head
->next
;
133 saa_free(sdata
.data
);
136 sdata
.head
= sdata
.head
->next
;
144 static int32_t as86_section_names(char *name
, int pass
, int *bits
)
150 * Default is 16 bits.
158 if (!strcmp(name
, ".text"))
160 else if (!strcmp(name
, ".data"))
162 else if (!strcmp(name
, ".bss"))
168 static int as86_add_string(char *name
)
171 int length
= strlen(name
);
173 saa_wbytes(strs
, name
, (int32_t)(length
+ 1));
174 strslen
+= 1 + length
;
179 static void as86_deflabel(char *name
, int32_t segment
, int64_t offset
,
180 int is_global
, char *special
)
182 bool is_start
= false;
186 error(ERR_NONFATAL
, "as86 format does not support any"
187 " special symbol types");
190 if (name
[0] == '.' && name
[1] == '.' && name
[2] != '@') {
191 if (strcmp(name
, "..start")) {
192 error(ERR_NONFATAL
, "unrecognised special symbol `%s'", name
);
199 sym
= saa_wstruct(syms
);
201 sym
->strpos
= as86_add_string(name
);
205 sym
->flags
= SYM_ENTRY
;
207 if (segment
== NO_SEG
)
208 sym
->flags
|= SYM_ABSOLUTE
, sym
->segment
= 0;
209 else if (segment
== stext
.index
)
210 sym
->segment
= SECT_TEXT
;
211 else if (segment
== sdata
.index
)
212 sym
->segment
= SECT_DATA
;
213 else if (segment
== bssindex
)
214 sym
->segment
= SECT_BSS
;
216 sym
->flags
|= SYM_IMPORT
;
221 sym
->segment
= 3; /* already have IMPORT */
223 if (is_global
&& !(sym
->flags
& SYM_IMPORT
))
224 sym
->flags
|= SYM_EXPORT
;
229 * define the references from external-symbol segment numbers
230 * to these symbol records.
232 if (segment
!= NO_SEG
&& segment
!= stext
.index
&&
233 segment
!= sdata
.index
&& segment
!= bssindex
)
234 bsym
= raa_write(bsym
, segment
, nsyms
);
239 static void as86_add_piece(struct Section
*sect
, int type
, int32_t offset
,
240 int32_t segment
, int32_t bytes
, int relative
)
246 if (type
== 0 && sect
->last
&& sect
->last
->type
== 0) {
247 sect
->last
->bytes
+= bytes
;
251 p
= sect
->last
= *sect
->tail
= nasm_malloc(sizeof(struct Piece
));
252 sect
->tail
= &p
->next
;
258 p
->relative
= relative
;
260 if (type
== 1 && segment
== stext
.index
)
261 p
->number
= SECT_TEXT
;
262 else if (type
== 1 && segment
== sdata
.index
)
263 p
->number
= SECT_DATA
;
264 else if (type
== 1 && segment
== bssindex
)
265 p
->number
= SECT_BSS
;
267 p
->number
= raa_read(bsym
, segment
), p
->type
= 2;
270 static void as86_out(int32_t segto
, const void *data
,
271 enum out_type type
, uint64_t size
,
272 int32_t segment
, int32_t wrt
)
276 uint8_t mydata
[4], *p
;
279 wrt
= NO_SEG
; /* continue to do _something_ */
280 error(ERR_NONFATAL
, "WRT not supported by as86 output format");
284 * handle absolute-assembly (structure definitions)
286 if (segto
== NO_SEG
) {
287 if (type
!= OUT_RESERVE
)
288 error(ERR_NONFATAL
, "attempt to assemble code in [ABSOLUTE]"
293 if (segto
== stext
.index
)
295 else if (segto
== sdata
.index
)
297 else if (segto
== bssindex
)
300 error(ERR_WARNING
, "attempt to assemble code in"
301 " segment %d: defaulting to `.text'", segto
);
305 if (!s
&& type
!= OUT_RESERVE
) {
306 error(ERR_WARNING
, "attempt to initialize memory in the"
307 " BSS section: ignored");
308 bsslen
+= realsize(type
, size
);
312 if (type
== OUT_RESERVE
) {
314 error(ERR_WARNING
, "uninitialized space declared in"
315 " %s section: zeroing",
316 (segto
== stext
.index
? "code" : "data"));
317 as86_sect_write(s
, NULL
, size
);
318 as86_add_piece(s
, 0, 0L, 0L, size
, 0);
321 } else if (type
== OUT_RAWDATA
) {
322 if (segment
!= NO_SEG
)
323 error(ERR_PANIC
, "OUT_RAWDATA with other than NO_SEG");
324 as86_sect_write(s
, data
, size
);
325 as86_add_piece(s
, 0, 0L, 0L, size
, 0);
326 } else if (type
== OUT_ADDRESS
) {
327 if (segment
!= NO_SEG
) {
329 error(ERR_NONFATAL
, "as86 format does not support"
330 " segment base references");
332 offset
= *(int64_t *)data
;
333 as86_add_piece(s
, 1, offset
, segment
, size
, 0);
337 WRITELONG(p
, *(int64_t *)data
);
338 as86_sect_write(s
, data
, size
);
339 as86_add_piece(s
, 0, 0L, 0L, size
, 0);
341 } else if (type
== OUT_REL2ADR
) {
342 if (segment
== segto
)
343 error(ERR_PANIC
, "intra-segment OUT_REL2ADR");
344 if (segment
!= NO_SEG
) {
346 error(ERR_NONFATAL
, "as86 format does not support"
347 " segment base references");
349 offset
= *(int64_t *)data
;
350 as86_add_piece(s
, 1, offset
- size
+ 2, segment
, 2L,
354 } else if (type
== OUT_REL4ADR
) {
355 if (segment
== segto
)
356 error(ERR_PANIC
, "intra-segment OUT_REL4ADR");
357 if (segment
!= NO_SEG
) {
359 error(ERR_NONFATAL
, "as86 format does not support"
360 " segment base references");
362 offset
= *(int64_t *)data
;
363 as86_add_piece(s
, 1, offset
- size
+ 4, segment
, 4L,
370 static void as86_write(void)
373 int32_t symlen
, seglen
, segsize
;
376 * First, go through the symbol records working out how big
377 * each will be. Also fix up BSS references at this time, and
378 * set the flags words up completely.
382 for (i
= 0; i
< nsyms
; i
++) {
383 struct Symbol
*sym
= saa_rstruct(syms
);
384 if (sym
->segment
== SECT_BSS
)
385 sym
->segment
= SECT_DATA
, sym
->value
+= sdata
.len
;
386 sym
->flags
|= sym
->segment
;
388 sym
->flags
|= 0 << 14, symlen
+= 4;
389 else if (sym
->value
>= 0 && sym
->value
<= 255)
390 sym
->flags
|= 1 << 14, symlen
+= 5;
391 else if (sym
->value
>= 0 && sym
->value
<= 65535L)
392 sym
->flags
|= 2 << 14, symlen
+= 6;
394 sym
->flags
|= 3 << 14, symlen
+= 8;
398 * Now do the same for the segments, and get the segment size
399 * descriptor word at the same time.
401 seglen
= segsize
= 0;
402 if ((uint32_t)stext
.len
> 65535L)
403 segsize
|= 0x03000000L
, seglen
+= 4;
405 segsize
|= 0x02000000L
, seglen
+= 2;
406 if ((uint32_t)sdata
.len
> 65535L)
407 segsize
|= 0xC0000000L
, seglen
+= 4;
409 segsize
|= 0x80000000L
, seglen
+= 2;
412 * Emit the as86 header.
414 fwriteint32_t(0x000186A3L
, as86fp
);
416 fwriteint32_t(27 + symlen
+ seglen
+ strslen
, as86fp
); /* header length */
417 fwriteint32_t(stext
.len
+ sdata
.len
+ bsslen
, as86fp
);
418 fwriteint16_t(strslen
, as86fp
);
419 fwriteint16_t(0, as86fp
); /* class = revision = 0 */
420 fwriteint32_t(0x55555555L
, as86fp
); /* segment max sizes: always this */
421 fwriteint32_t(segsize
, as86fp
); /* segment size descriptors */
422 if (segsize
& 0x01000000L
)
423 fwriteint32_t(stext
.len
, as86fp
);
425 fwriteint16_t(stext
.len
, as86fp
);
426 if (segsize
& 0x40000000L
)
427 fwriteint32_t(sdata
.len
+ bsslen
, as86fp
);
429 fwriteint16_t(sdata
.len
+ bsslen
, as86fp
);
430 fwriteint16_t(nsyms
, as86fp
);
433 * Write the symbol table.
436 for (i
= 0; i
< nsyms
; i
++) {
437 struct Symbol
*sym
= saa_rstruct(syms
);
438 fwriteint16_t(sym
->strpos
, as86fp
);
439 fwriteint16_t(sym
->flags
, as86fp
);
440 switch (sym
->flags
& (3 << 14)) {
444 fputc(sym
->value
, as86fp
);
447 fwriteint16_t(sym
->value
, as86fp
);
450 fwriteint32_t(sym
->value
, as86fp
);
456 * Write out the string table.
458 saa_fpwrite(strs
, as86fp
);
461 * Write the program text.
463 as86_reloc_size
= -1;
464 as86_write_section(&stext
, SECT_TEXT
);
465 as86_write_section(&sdata
, SECT_DATA
);
467 * Append the BSS section to the .data section
469 if (bsslen
> 65535L) {
471 fwriteint32_t(bsslen
, as86fp
);
472 } else if (bsslen
> 255) {
474 fwriteint16_t(bsslen
, as86fp
);
477 fputc(bsslen
, as86fp
);
480 fputc(0, as86fp
); /* termination */
483 static void as86_set_rsize(int size
)
485 if (as86_reloc_size
!= size
) {
486 switch (as86_reloc_size
= size
) {
497 error(ERR_PANIC
, "bizarre relocation size %d", size
);
502 static void as86_write_section(struct Section
*sect
, int index
)
508 fputc(0x20 + index
, as86fp
); /* select the right section */
510 saa_rewind(sect
->data
);
512 for (p
= sect
->head
; p
; p
= p
->next
)
516 * Absolute data. Emit it in chunks of at most 64
522 int32_t tmplen
= (length
> 64 ? 64 : length
);
523 fputc(0x40 | (tmplen
& 0x3F), as86fp
);
524 saa_rnbytes(sect
->data
, buf
, tmplen
);
525 fwrite(buf
, 1, tmplen
, as86fp
);
527 } while (length
> 0);
531 * A segment-type relocation. First fix up the BSS.
533 if (p
->number
== SECT_BSS
)
534 p
->number
= SECT_DATA
, p
->offset
+= sdata
.len
;
535 as86_set_rsize(p
->bytes
);
536 fputc(0x80 | (p
->relative
? 0x20 : 0) | p
->number
, as86fp
);
537 if (as86_reloc_size
== 2)
538 fwriteint16_t(p
->offset
, as86fp
);
540 fwriteint32_t(p
->offset
, as86fp
);
544 * A symbol-type relocation.
546 as86_set_rsize(p
->bytes
);
557 (p
->relative
? 0x20 : 0) |
558 (p
->number
> 255 ? 0x04 : 0) | s
, as86fp
);
560 fwriteint16_t(p
->number
, as86fp
);
562 fputc(p
->number
, as86fp
);
567 fputc(p
->offset
, as86fp
);
570 fwriteint16_t(p
->offset
, as86fp
);
573 fwriteint32_t(p
->offset
, as86fp
);
580 static void as86_sect_write(struct Section
*sect
,
581 const uint8_t *data
, uint32_t len
)
583 saa_wbytes(sect
->data
, data
, len
);
584 sect
->datalen
+= len
;
587 static int32_t as86_segbase(int32_t segment
)
592 static int as86_directive(char *directive
, char *value
, int pass
)
600 static void as86_filename(char *inname
, char *outname
, efunc error
)
604 if ((p
= strrchr(inname
, '.')) != NULL
) {
605 strncpy(as86_module
, inname
, p
- inname
);
606 as86_module
[p
- inname
] = '\0';
608 strcpy(as86_module
, inname
);
610 standard_extension(inname
, outname
, ".o", error
);
613 extern macros_t as86_stdmac
[];
615 static int as86_set_info(enum geninfo type
, char **val
)
621 void as86_linenumber(char *name
, int32_t segment
, int32_t offset
, int is_main
,
630 struct ofmt of_as86
= {
631 "Linux as86 (bin86 version 0.3) object files",