1 /* outaout.c output routines for the Netwide Assembler to produce
2 * Linux a.out 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 long address
; /* relative to _start_ of section */
24 long symbol
; /* symbol number or -ve section id */
25 int bytes
; /* 2 or 4 */
26 int relative
; /* TRUE or FALSE */
30 long strpos
; /* string table position of name */
31 int type
; /* symbol type - see flags below */
32 long value
; /* address, or COMMON variable size */
36 * Section IDs - used in Reloc.symbol when negative, and in
37 * Symbol.type when positive.
39 #define SECT_ABS 2 /* absolute value */
40 #define SECT_TEXT 4 /* text section */
41 #define SECT_DATA 6 /* data section */
42 #define SECT_BSS 8 /* bss section */
43 #define SECT_MASK 0xE /* mask out any of the above */
46 * Another flag used in Symbol.type.
48 #define SYM_GLOBAL 1 /* it's a global symbol */
51 * Bit more explanation of symbol types: SECT_xxx denotes a local
52 * symbol. SECT_xxx|SYM_GLOBAL denotes a global symbol, defined in
53 * this module. Just SYM_GLOBAL, with zero value, denotes an
54 * external symbol referenced in this module. And just SYM_GLOBAL,
55 * but with a non-zero value, declares a C `common' variable, of
61 unsigned long len
, size
, nrelocs
;
63 struct Reloc
*head
, **tail
;
66 static struct Section stext
, sdata
;
67 static unsigned long bsslen
;
70 static struct SAA
*syms
;
71 static unsigned long nsyms
;
73 static struct RAA
*bsym
;
75 static struct SAA
*strs
;
76 static unsigned long strslen
;
81 static void aout_write(void);
82 static void aout_write_relocs(struct Reloc
*);
83 static void aout_write_syms(void);
84 static void aout_sect_write(struct Section
*, unsigned char *, unsigned long);
85 static void aout_pad_sections(void);
86 static void aout_fixup_relocs(struct Section
*);
88 static void aout_init(FILE *fp
, efunc errfunc
, ldfunc ldef
) {
91 (void) ldef
; /* placate optimisers */
92 stext
.data
= saa_init(1L); stext
.head
= NULL
; stext
.tail
= &stext
.head
;
93 sdata
.data
= saa_init(1L); sdata
.head
= NULL
; sdata
.tail
= &sdata
.head
;
94 stext
.len
= stext
.size
= sdata
.len
= sdata
.size
= bsslen
= 0;
95 stext
.nrelocs
= sdata
.nrelocs
= 0;
96 stext
.index
= seg_alloc();
97 sdata
.index
= seg_alloc();
98 bssindex
= seg_alloc();
99 syms
= saa_init((long)sizeof(struct Symbol
));
106 static void aout_cleanup(void) {
110 aout_fixup_relocs(&stext
);
111 aout_fixup_relocs(&sdata
);
114 saa_free (stext
.data
);
117 stext
.head
= stext
.head
->next
;
120 saa_free (sdata
.data
);
123 sdata
.head
= sdata
.head
->next
;
131 static long aout_section_names (char *name
, int pass
, int *bits
) {
133 * Default to 32 bits.
141 if (!strcmp(name
, ".text"))
143 else if (!strcmp(name
, ".data"))
145 else if (!strcmp(name
, ".bss"))
151 static void aout_deflabel (char *name
, long segment
, long offset
,
156 if (name
[0] == '.' && name
[1] == '.') {
160 saa_wbytes (strs
, name
, (long)(1+strlen(name
)));
161 strslen
+= 1+strlen(name
);
163 sym
= saa_wstruct (syms
);
166 sym
->type
= is_global
? SYM_GLOBAL
: 0;
167 if (segment
== NO_SEG
)
168 sym
->type
|= SECT_ABS
;
169 else if (segment
== stext
.index
)
170 sym
->type
|= SECT_TEXT
;
171 else if (segment
== sdata
.index
)
172 sym
->type
|= SECT_DATA
;
173 else if (segment
== bssindex
)
174 sym
->type
|= SECT_BSS
;
176 sym
->type
= SYM_GLOBAL
;
180 sym
->value
= (sym
->type
== SYM_GLOBAL
? 0 : offset
);
183 * define the references from external-symbol segment numbers
184 * to these symbol records.
186 if (segment
!= NO_SEG
&& segment
!= stext
.index
&&
187 segment
!= sdata
.index
&& segment
!= bssindex
)
188 bsym
= raa_write (bsym
, segment
, nsyms
);
193 static void aout_add_reloc (struct Section
*sect
, long segment
,
194 int relative
, int bytes
) {
197 r
= *sect
->tail
= nasm_malloc(sizeof(struct Reloc
));
198 sect
->tail
= &r
->next
;
201 r
->address
= sect
->len
;
202 r
->symbol
= (segment
== NO_SEG
? -SECT_ABS
:
203 segment
== stext
.index
? -SECT_TEXT
:
204 segment
== sdata
.index
? -SECT_DATA
:
205 segment
== bssindex
? -SECT_BSS
:
206 raa_read(bsym
, segment
));
207 r
->relative
= relative
;
213 static void aout_out (long segto
, void *data
, unsigned long type
,
214 long segment
, long wrt
) {
216 long realbytes
= type
& OUT_SIZMASK
;
217 unsigned char mydata
[4], *p
;
220 wrt
= NO_SEG
; /* continue to do _something_ */
221 error (ERR_NONFATAL
, "WRT not supported by a.out output format");
227 * handle absolute-assembly (structure definitions)
229 if (segto
== NO_SEG
) {
230 if (type
!= OUT_RESERVE
)
231 error (ERR_NONFATAL
, "attempt to assemble code in [ABSOLUTE]"
236 if (segto
== stext
.index
)
238 else if (segto
== sdata
.index
)
240 else if (segto
== bssindex
)
243 error(ERR_WARNING
, "attempt to assemble code in"
244 " segment %d: defaulting to `.text'", segto
);
248 if (!s
&& type
!= OUT_RESERVE
) {
249 error(ERR_WARNING
, "attempt to initialise memory in the"
250 " BSS section: ignored");
251 if (type
== OUT_REL2ADR
)
253 else if (type
== OUT_REL4ADR
)
259 if (type
== OUT_RESERVE
) {
261 error(ERR_WARNING
, "uninitialised space declared in"
262 " %s section: zeroing",
263 (segto
== stext
.index
? "code" : "data"));
264 aout_sect_write (s
, NULL
, realbytes
);
267 } else if (type
== OUT_RAWDATA
) {
268 if (segment
!= NO_SEG
)
269 error(ERR_PANIC
, "OUT_RAWDATA with other than NO_SEG");
270 aout_sect_write (s
, data
, realbytes
);
271 } else if (type
== OUT_ADDRESS
) {
272 if (segment
!= NO_SEG
) {
274 error(ERR_NONFATAL
, "a.out format does not support"
275 " segment base references");
277 aout_add_reloc (s
, segment
, FALSE
, realbytes
);
281 WRITESHORT (p
, *(long *)data
);
283 WRITELONG (p
, *(long *)data
);
284 aout_sect_write (s
, mydata
, realbytes
);
285 } else if (type
== OUT_REL2ADR
) {
286 if (segment
== segto
)
287 error(ERR_PANIC
, "intra-segment OUT_REL2ADR");
288 if (segment
!= NO_SEG
&& segment
% 2) {
289 error(ERR_NONFATAL
, "a.out format does not support"
290 " segment base references");
292 aout_add_reloc (s
, segment
, TRUE
, 2);
294 WRITESHORT (p
, *(long*)data
-(realbytes
+ s
->len
));
295 aout_sect_write (s
, mydata
, 2L);
296 } else if (type
== OUT_REL4ADR
) {
297 if (segment
== segto
)
298 error(ERR_PANIC
, "intra-segment OUT_REL4ADR");
299 if (segment
!= NO_SEG
&& segment
% 2) {
300 error(ERR_NONFATAL
, "a.out format does not support"
301 " segment base references");
303 aout_add_reloc (s
, segment
, TRUE
, 4);
305 WRITELONG (p
, *(long*)data
-(realbytes
+ s
->len
));
306 aout_sect_write (s
, mydata
, 4L);
310 static void aout_pad_sections(void) {
311 static unsigned char pad
[] = { 0x90, 0x90, 0x90, 0x90 };
313 * Pad each of the text and data sections with NOPs until their
314 * length is a multiple of four. (NOP == 0x90.) Also increase
315 * the length of the BSS section similarly.
317 aout_sect_write (&stext
, pad
, (-stext
.len
) & 3);
318 aout_sect_write (&sdata
, pad
, (-sdata
.len
) & 3);
319 bsslen
= (bsslen
+ 3) & ~3;
323 * a.out files have the curious property that all references to
324 * things in the data or bss sections are done by addresses which
325 * are actually relative to the start of the _text_ section, in the
326 * _file_. (No relation to what happens after linking. No idea why
327 * this should be so. It's very strange.) So we have to go through
328 * the relocation table, _after_ the final size of each section is
329 * known, and fix up the relocations pointed to.
331 static void aout_fixup_relocs(struct Section
*sect
) {
334 saa_rewind (sect
->data
);
335 for (r
= sect
->head
; r
; r
= r
->next
) {
336 unsigned char *p
, *q
, blk
[4];
339 saa_fread (sect
->data
, r
->address
, blk
, (long)r
->bytes
);
342 l
+= ((long)*p
++) << 8;
344 l
+= ((long)*p
++) << 16;
345 l
+= ((long)*p
++) << 24;
347 if (r
->symbol
== -SECT_DATA
)
349 else if (r
->symbol
== -SECT_BSS
)
350 l
+= stext
.len
+ sdata
.len
;
355 saa_fwrite (sect
->data
, r
->address
, blk
, (long)r
->bytes
);
359 static void aout_write(void) {
361 * Emit the a.out header.
363 fwritelong (0x640107L
, aoutfp
); /* OMAGIC, M_386, no flags */
364 fwritelong (stext
.len
, aoutfp
);
365 fwritelong (sdata
.len
, aoutfp
);
366 fwritelong (bsslen
, aoutfp
);
367 fwritelong (nsyms
* 12, aoutfp
); /* length of symbol table */
368 fwritelong (0L, aoutfp
); /* object files have no entry point */
369 fwritelong (stext
.nrelocs
* 8, aoutfp
); /* size of text relocs */
370 fwritelong (sdata
.nrelocs
* 8, aoutfp
); /* size of data relocs */
373 * Write out the code section and the data section.
375 saa_fpwrite (stext
.data
, aoutfp
);
376 saa_fpwrite (sdata
.data
, aoutfp
);
379 * Write out the relocations.
381 aout_write_relocs (stext
.head
);
382 aout_write_relocs (sdata
.head
);
385 * Write the symbol table.
390 * And the string table.
392 fwritelong (strslen
+4, aoutfp
); /* length includes length count */
393 saa_fpwrite (strs
, aoutfp
);
396 static void aout_write_relocs (struct Reloc
*r
) {
400 fwritelong (r
->address
, aoutfp
);
403 word2
= r
->symbol
| 0x8000000L
;
408 word2
|= (r
->bytes
== 2 ? 0x2000000L
: 0x4000000L
);
409 fwritelong (word2
, aoutfp
);
415 static void aout_write_syms (void) {
419 for (i
=0; i
<nsyms
; i
++) {
420 struct Symbol
*sym
= saa_rstruct(syms
);
421 fwritelong (sym
->strpos
, aoutfp
);
422 fwritelong ((long)sym
->type
, aoutfp
);
424 * Fix up the symbol value now we know the final section
427 if ((sym
->type
& SECT_MASK
) == SECT_DATA
)
428 sym
->value
+= stext
.len
;
429 if ((sym
->type
& SECT_MASK
) == SECT_BSS
)
430 sym
->value
+= stext
.len
+ sdata
.len
;
431 fwritelong (sym
->value
, aoutfp
);
435 static void aout_sect_write (struct Section
*sect
,
436 unsigned char *data
, unsigned long len
) {
437 saa_wbytes (sect
->data
, data
, len
);
441 static long aout_segbase (long segment
) {
445 static int aout_directive (char *directive
, char *value
, int pass
) {
449 static void aout_filename (char *inname
, char *outname
, efunc error
) {
450 standard_extension (inname
, outname
, ".o", error
);
453 struct ofmt of_aout
= {
454 "GNU a.out (i386) object files (e.g. Linux)",