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 licence given in the file "Licence"
7 * distributed in the NASM archive.
23 int type
; /* 0 = absolute, 1 = seg, 2 = sym */
24 long offset
; /* relative offset */
25 int number
; /* symbol/segment number (4=bss) */
26 long bytes
; /* size of reloc or of absolute data */
27 int relative
; /* TRUE or FALSE */
31 long strpos
; /* string table position of name */
32 int flags
; /* symbol flags */
33 int segment
; /* 4=bss at this point */
34 long value
; /* address, or COMMON variable size */
38 * Section IDs - used in Piece.number and Symbol.segment.
40 #define SECT_TEXT 0 /* text section */
41 #define SECT_DATA 3 /* data section */
42 #define SECT_BSS 4 /* bss section */
45 * Flags used in Symbol.flags.
47 #define SYM_ENTRY (1<<8)
48 #define SYM_EXPORT (1<<7)
49 #define SYM_IMPORT (1<<6)
50 #define SYM_ABSOLUTE (1<<4)
54 unsigned long datalen
, size
, len
;
56 struct Piece
*head
, *last
, **tail
;
59 static char as86_module
[FILENAME_MAX
];
61 static struct Section stext
, sdata
;
62 static unsigned long bsslen
;
65 static struct SAA
*syms
;
66 static unsigned long nsyms
;
68 static struct RAA
*bsym
;
70 static struct SAA
*strs
;
71 static unsigned long strslen
;
73 static int as86_reloc_size
;
78 static void as86_write(void);
79 static void as86_write_section(struct Section
*, int);
80 static int as86_add_string(char *name
);
81 static void as86_sect_write(struct Section
*, const unsigned char *,
84 static void as86_init(FILE * fp
, efunc errfunc
, ldfunc ldef
, evalfunc eval
)
88 (void)ldef
; /* placate optimisers */
89 stext
.data
= saa_init(1L);
91 stext
.head
= stext
.last
= NULL
;
92 stext
.tail
= &stext
.head
;
93 sdata
.data
= saa_init(1L);
95 sdata
.head
= sdata
.last
= NULL
;
96 sdata
.tail
= &sdata
.head
;
98 stext
.len
= stext
.datalen
= stext
.size
=
99 sdata
.len
= sdata
.datalen
= sdata
.size
= 0;
100 stext
.index
= seg_alloc();
101 sdata
.index
= seg_alloc();
102 bssindex
= seg_alloc();
103 syms
= saa_init((long)sizeof(struct Symbol
));
109 as86_add_string(as86_module
);
112 static void as86_cleanup(int debuginfo
)
120 saa_free(stext
.data
);
123 stext
.head
= stext
.head
->next
;
126 saa_free(sdata
.data
);
129 sdata
.head
= sdata
.head
->next
;
137 static long as86_section_names(char *name
, int pass
, int *bits
)
140 * Default is 16 bits.
148 if (!strcmp(name
, ".text"))
150 else if (!strcmp(name
, ".data"))
152 else if (!strcmp(name
, ".bss"))
158 static int as86_add_string(char *name
)
161 int length
= strlen(name
);
163 saa_wbytes(strs
, name
, (long)(length
+ 1));
164 strslen
+= 1 + length
;
169 static void as86_deflabel(char *name
, long segment
, long offset
,
170 int is_global
, char *special
)
175 error(ERR_NONFATAL
, "as86 format does not support any"
176 " special symbol types");
178 if (name
[0] == '.' && name
[1] == '.' && name
[2] != '@') {
179 error(ERR_NONFATAL
, "unrecognised special symbol `%s'", name
);
183 sym
= saa_wstruct(syms
);
185 sym
->strpos
= as86_add_string(name
);
187 if (segment
== NO_SEG
)
188 sym
->flags
|= SYM_ABSOLUTE
, sym
->segment
= 0;
189 else if (segment
== stext
.index
)
190 sym
->segment
= SECT_TEXT
;
191 else if (segment
== sdata
.index
)
192 sym
->segment
= SECT_DATA
;
193 else if (segment
== bssindex
)
194 sym
->segment
= SECT_BSS
;
196 sym
->flags
|= SYM_IMPORT
;
201 sym
->segment
= 3; /* already have IMPORT */
203 if (is_global
&& !(sym
->flags
& SYM_IMPORT
))
204 sym
->flags
|= SYM_EXPORT
;
209 * define the references from external-symbol segment numbers
210 * to these symbol records.
212 if (segment
!= NO_SEG
&& segment
!= stext
.index
&&
213 segment
!= sdata
.index
&& segment
!= bssindex
)
214 bsym
= raa_write(bsym
, segment
, nsyms
);
219 static void as86_add_piece(struct Section
*sect
, int type
, long offset
,
220 long segment
, long bytes
, int relative
)
226 if (type
== 0 && sect
->last
&& sect
->last
->type
== 0) {
227 sect
->last
->bytes
+= bytes
;
231 p
= sect
->last
= *sect
->tail
= nasm_malloc(sizeof(struct Piece
));
232 sect
->tail
= &p
->next
;
238 p
->relative
= relative
;
240 if (type
== 1 && segment
== stext
.index
)
241 p
->number
= SECT_TEXT
;
242 else if (type
== 1 && segment
== sdata
.index
)
243 p
->number
= SECT_DATA
;
244 else if (type
== 1 && segment
== bssindex
)
245 p
->number
= SECT_BSS
;
247 p
->number
= raa_read(bsym
, segment
), p
->type
= 2;
250 static void as86_out(long segto
, const void *data
, unsigned long type
,
251 long segment
, long wrt
)
254 long realbytes
= type
& OUT_SIZMASK
;
256 unsigned char mydata
[4], *p
;
259 wrt
= NO_SEG
; /* continue to do _something_ */
260 error(ERR_NONFATAL
, "WRT not supported by as86 output format");
266 * handle absolute-assembly (structure definitions)
268 if (segto
== NO_SEG
) {
269 if (type
!= OUT_RESERVE
)
270 error(ERR_NONFATAL
, "attempt to assemble code in [ABSOLUTE]"
275 if (segto
== stext
.index
)
277 else if (segto
== sdata
.index
)
279 else if (segto
== bssindex
)
282 error(ERR_WARNING
, "attempt to assemble code in"
283 " segment %d: defaulting to `.text'", segto
);
287 if (!s
&& type
!= OUT_RESERVE
) {
288 error(ERR_WARNING
, "attempt to initialise memory in the"
289 " BSS section: ignored");
290 if (type
== OUT_REL2ADR
)
292 else if (type
== OUT_REL4ADR
)
298 if (type
== OUT_RESERVE
) {
300 error(ERR_WARNING
, "uninitialised space declared in"
301 " %s section: zeroing",
302 (segto
== stext
.index
? "code" : "data"));
303 as86_sect_write(s
, NULL
, realbytes
);
304 as86_add_piece(s
, 0, 0L, 0L, realbytes
, 0);
307 } else if (type
== OUT_RAWDATA
) {
308 if (segment
!= NO_SEG
)
309 error(ERR_PANIC
, "OUT_RAWDATA with other than NO_SEG");
310 as86_sect_write(s
, data
, realbytes
);
311 as86_add_piece(s
, 0, 0L, 0L, realbytes
, 0);
312 } else if (type
== OUT_ADDRESS
) {
313 if (segment
!= NO_SEG
) {
315 error(ERR_NONFATAL
, "as86 format does not support"
316 " segment base references");
318 offset
= *(long *)data
;
319 as86_add_piece(s
, 1, offset
, segment
, realbytes
, 0);
323 WRITELONG(p
, *(long *)data
);
324 as86_sect_write(s
, data
, realbytes
);
325 as86_add_piece(s
, 0, 0L, 0L, realbytes
, 0);
327 } else if (type
== OUT_REL2ADR
) {
328 if (segment
== segto
)
329 error(ERR_PANIC
, "intra-segment OUT_REL2ADR");
330 if (segment
!= NO_SEG
) {
332 error(ERR_NONFATAL
, "as86 format does not support"
333 " segment base references");
335 offset
= *(long *)data
;
336 as86_add_piece(s
, 1, offset
- realbytes
+ 2, segment
, 2L,
340 } else if (type
== OUT_REL4ADR
) {
341 if (segment
== segto
)
342 error(ERR_PANIC
, "intra-segment OUT_REL4ADR");
343 if (segment
!= NO_SEG
) {
345 error(ERR_NONFATAL
, "as86 format does not support"
346 " segment base references");
348 offset
= *(long *)data
;
349 as86_add_piece(s
, 1, offset
- realbytes
+ 4, segment
, 4L,
356 static void as86_write(void)
359 long symlen
, seglen
, segsize
;
362 * First, go through the symbol records working out how big
363 * each will be. Also fix up BSS references at this time, and
364 * set the flags words up completely.
368 for (i
= 0; i
< nsyms
; i
++) {
369 struct Symbol
*sym
= saa_rstruct(syms
);
370 if (sym
->segment
== SECT_BSS
)
371 sym
->segment
= SECT_DATA
, sym
->value
+= sdata
.len
;
372 sym
->flags
|= sym
->segment
;
374 sym
->flags
|= 0 << 14, symlen
+= 4;
375 else if (sym
->value
>= 0 && sym
->value
<= 255)
376 sym
->flags
|= 1 << 14, symlen
+= 5;
377 else if (sym
->value
>= 0 && sym
->value
<= 65535L)
378 sym
->flags
|= 2 << 14, symlen
+= 6;
380 sym
->flags
|= 3 << 14, symlen
+= 8;
384 * Now do the same for the segments, and get the segment size
385 * descriptor word at the same time.
387 seglen
= segsize
= 0;
388 if ((unsigned long)stext
.len
> 65535L)
389 segsize
|= 0x03000000L
, seglen
+= 4;
391 segsize
|= 0x02000000L
, seglen
+= 2;
392 if ((unsigned long)sdata
.len
> 65535L)
393 segsize
|= 0xC0000000L
, seglen
+= 4;
395 segsize
|= 0x80000000L
, seglen
+= 2;
398 * Emit the as86 header.
400 fwritelong(0x000186A3L
, as86fp
);
402 fwritelong(27 + symlen
+ seglen
+ strslen
, as86fp
); /* header length */
403 fwritelong(stext
.len
+ sdata
.len
+ bsslen
, as86fp
);
404 fwriteshort(strslen
, as86fp
);
405 fwriteshort(0, as86fp
); /* class = revision = 0 */
406 fwritelong(0x55555555L
, as86fp
); /* segment max sizes: always this */
407 fwritelong(segsize
, as86fp
); /* segment size descriptors */
408 if (segsize
& 0x01000000L
)
409 fwritelong(stext
.len
, as86fp
);
411 fwriteshort(stext
.len
, as86fp
);
412 if (segsize
& 0x40000000L
)
413 fwritelong(sdata
.len
+ bsslen
, as86fp
);
415 fwriteshort(sdata
.len
+ bsslen
, as86fp
);
416 fwriteshort(nsyms
, as86fp
);
419 * Write the symbol table.
422 for (i
= 0; i
< nsyms
; i
++) {
423 struct Symbol
*sym
= saa_rstruct(syms
);
424 fwriteshort(sym
->strpos
, as86fp
);
425 fwriteshort(sym
->flags
, as86fp
);
426 switch (sym
->flags
& (3 << 14)) {
430 fputc(sym
->value
, as86fp
);
433 fwriteshort(sym
->value
, as86fp
);
436 fwritelong(sym
->value
, as86fp
);
442 * Write out the string table.
444 saa_fpwrite(strs
, as86fp
);
447 * Write the program text.
449 as86_reloc_size
= -1;
450 as86_write_section(&stext
, SECT_TEXT
);
451 as86_write_section(&sdata
, SECT_DATA
);
453 * Append the BSS section to the .data section
455 if (bsslen
> 65535L) {
457 fwritelong(bsslen
, as86fp
);
458 } else if (bsslen
> 255) {
460 fwriteshort(bsslen
, as86fp
);
463 fputc(bsslen
, as86fp
);
466 fputc(0, as86fp
); /* termination */
469 static void as86_set_rsize(int size
)
471 if (as86_reloc_size
!= size
) {
472 switch (as86_reloc_size
= size
) {
483 error(ERR_PANIC
, "bizarre relocation size %d", size
);
488 static void as86_write_section(struct Section
*sect
, int index
)
494 fputc(0x20 + index
, as86fp
); /* select the right section */
496 saa_rewind(sect
->data
);
498 for (p
= sect
->head
; p
; p
= p
->next
)
502 * Absolute data. Emit it in chunks of at most 64
508 long tmplen
= (length
> 64 ? 64 : length
);
509 fputc(0x40 | (tmplen
& 0x3F), as86fp
);
510 saa_rnbytes(sect
->data
, buf
, tmplen
);
511 fwrite(buf
, 1, tmplen
, as86fp
);
513 } while (length
> 0);
517 * A segment-type relocation. First fix up the BSS.
519 if (p
->number
== SECT_BSS
)
520 p
->number
= SECT_DATA
, p
->offset
+= sdata
.len
;
521 as86_set_rsize(p
->bytes
);
522 fputc(0x80 | (p
->relative
? 0x20 : 0) | p
->number
, as86fp
);
523 if (as86_reloc_size
== 2)
524 fwriteshort(p
->offset
, as86fp
);
526 fwritelong(p
->offset
, as86fp
);
530 * A symbol-type relocation.
532 as86_set_rsize(p
->bytes
);
543 (p
->relative
? 0x20 : 0) |
544 (p
->number
> 255 ? 0x04 : 0) | s
, as86fp
);
546 fwriteshort(p
->number
, as86fp
);
548 fputc(p
->number
, as86fp
);
553 fputc(p
->offset
, as86fp
);
556 fwriteshort(p
->offset
, as86fp
);
559 fwritelong(p
->offset
, as86fp
);
566 static void as86_sect_write(struct Section
*sect
,
567 const unsigned char *data
, unsigned long len
)
569 saa_wbytes(sect
->data
, data
, len
);
570 sect
->datalen
+= len
;
573 static long as86_segbase(long segment
)
578 static int as86_directive(char *directive
, char *value
, int pass
)
583 static void as86_filename(char *inname
, char *outname
, efunc error
)
587 if ((p
= strrchr(inname
, '.')) != NULL
) {
588 strncpy(as86_module
, inname
, p
- inname
);
589 as86_module
[p
- inname
] = '\0';
591 strcpy(as86_module
, inname
);
593 standard_extension(inname
, outname
, ".o", error
);
596 static const char *as86_stdmac
[] = {
597 "%define __SECT__ [section .text]",
598 "%macro __NASM_CDecl__ 1",
603 static int as86_set_info(enum geninfo type
, char **val
)
607 void as86_linenumber(char *name
, long segment
, long offset
, int is_main
,
611 struct ofmt of_as86
= {
612 "Linux as86 (bin86 version 0.3) object files",