RAA fix from theowl
[nasm.git] / output / outbin.c
blobd5b0df77c3e73a5dd7eb1b448c56024cd734e37a
1 /* outbin.c output routines for the Netwide Assembler to produce
2 * flat-form binary 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.
8 */
11 * version with multiple sections support
13 * sections go in order defined by their org's if present
14 * if no org present, sections go in sequence they appear.
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <ctype.h>
22 #include "nasm.h"
23 #include "nasmlib.h"
24 #include "outform.h"
26 #ifdef OF_BIN
28 static FILE *fp;
29 static efunc error;
31 static struct Section {
32 struct Section *next;
33 struct SAA *contents;
34 long length;
35 long org; /* assigned org */
36 long pos; /* file position of section ?? */
37 long pad; /* padding bytes to next section in file */
38 long index; /* the NASM section id */
39 long align; /* section alignment, cannot be absolute addr */
40 char *name;
41 } *sections, **sectail;
43 static struct Reloc {
44 struct Reloc *next;
45 long posn;
46 long bytes;
47 long secref;
48 long secrel;
49 struct Section *target;
50 } *relocs, **reloctail;
52 static long current_section;
54 static void add_reloc (struct Section *s, long bytes, long secref,
55 long secrel)
57 struct Reloc *r;
59 r = *reloctail = nasm_malloc(sizeof(struct Reloc));
60 reloctail = &r->next;
61 r->next = NULL;
62 r->posn = s->length;
63 r->bytes = bytes;
64 r->secref = secref;
65 r->secrel = secrel;
66 r->target = s;
69 static struct Section *find_section_by_name(const char *name)
71 struct Section *s;
73 for (s = sections; s; s = s->next)
74 if (!strcmp(s->name,name))
75 break;
77 return s;
80 static struct Section *find_section_by_index(long index)
82 struct Section *s;
84 for (s = sections; s; s = s->next)
85 if ( s->index == index )
86 break;
88 return s;
91 static struct Section *alloc_section(char *name)
93 struct Section *s;
95 s = find_section_by_name(name);
96 if(s)
97 error(ERR_PANIC, "section %s re-defined", name);
99 s = nasm_malloc(sizeof(struct Section));
100 *sectail = s;
101 sectail = &s->next;
102 s->next = NULL;
104 s->contents = saa_init(1L);
105 s->length = 0;
106 s->pos = 0;
107 s->org = -1; /* default org is -1 because we want
108 * to adjust sections one after another
110 s->index = seg_alloc();
111 s->align = 4;
112 s->pad = 0;
113 s->name = nasm_strdup(name);
115 return s;
118 static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval)
120 fp = afp;
121 error = errfunc;
123 (void) eval; /* Don't warn that this parameter is unused */
124 (void) ldef; /* placate optimisers */
126 current_section = -1L;
127 relocs = NULL;
128 reloctail = &relocs;
129 sections = NULL;
130 sectail = &sections;
133 static void bin_cleanup (int debuginfo)
135 struct Section *outsections, **outstail;
136 struct Section *s, *o, *ls, *lo;
137 struct Reloc *r;
138 long least_org;
140 (void) debuginfo;
142 /* sort sections by their orgs
143 * sections without org follow their natural order
144 * after the org'd sections
146 outsections = NULL;
147 outstail = &outsections;
149 while( 1 )
151 least_org = 0x7fffffff;
153 ls = lo = NULL;
154 for( s = sections, o = NULL; s; o = s, s = s->next )
155 if( s->org != -1 && s->org < least_org )
157 least_org = s->org;
158 ls = s;
159 lo = o;
162 if(ls) /* relink to outsections */
164 #ifdef DEBUG
165 fprintf(stdout, "bin_cleanup: relinking section %s org %ld\n", ls->name, ls->org);
166 #endif
167 /* unlink from sections */
168 if(lo)
169 lo->next = ls->next;
170 else
171 if(ls == sections)
172 sections = ls->next;
174 /* link in to outsections */
175 if( ls->length > 0 )
177 *outstail = ls;
178 outstail = &ls->next;
179 ls->next = NULL;
182 else
183 break;
186 /* link outsections at start of sections */
187 *outstail = sections;
188 sections = outsections;
190 /* calculate sections positions */
191 for(s = sections, o = NULL; s; s = s->next)
193 if(!strcmp(s->name,".bss")) continue; /* don't count .bss yet */
195 if(o)
197 /* if section doesn't have its
198 * own org, align from prev section
200 if( s->org == -1 )
201 s->org = o->org + o->length;
203 /* check orgs */
204 if( s->org - o->org < o->length )
205 error( ERR_PANIC, "sections %s and %s overlap!", o->name, s->name );
207 /* align previous section */
208 o->pad = ((o->pos + o->length + o->align-1) & ~(o->align-1)) - (o->pos + o->length);
210 if( s->org - o->org > o->length )
212 #ifdef DEBUG
213 fprintf(stdout, "forced padding: %ld\n", s->org - o->org - o->length);
214 #endif
215 o->pad = s->org - o->org - o->length;
218 s->pos += o->pos + o->length + o->pad;
219 s->org = s->pos + sections->org;
222 #ifdef DEBUG
223 fprintf(stdout, "bin_cleanup: section %s at %ld(%lx) org %ld(%lx) prev <pos %ld(%lx)+size %ld(%lx)+pad %ld(%lx)> size %ld(%lx) align %ld(%lx)\n",
224 s->name, s->pos, s->pos, s->org, s->org, o?o->pos:0, o?o->pos:0,
225 o?o->length:0, o?o->length:0, o?o->pad:0, o?o->pad:0, s->length, s->length,
226 s->align, s->align);
227 #endif
229 /* prepare for relocating by the way */
230 saa_rewind( s->contents );
232 o = s;
235 /* adjust .bss */
236 s = find_section_by_name(".bss");
237 if(s)
239 s->org = o->org + o->length + o->pad;
241 #ifdef DEBUG
242 fprintf(stdout, "bin_cleanup: section %s at %ld org %ld prev (pos %ld+size %ld+pad %ld) size %ld align %ld\n",
243 s->name, s->pos, s->org, o?o->pos:0, o?o->length:0, o?o->pad:0, s->length, s->align);
244 #endif
247 /* apply relocations */
248 for (r = relocs; r; r = r->next)
250 unsigned char *p, *q, mydata[4];
251 long l;
253 saa_fread (r->target->contents, r->posn, mydata, r->bytes);
254 p = q = mydata;
255 l = *p++;
257 if (r->bytes > 1) {
258 l += ((long)*p++) << 8;
259 if (r->bytes == 4) {
260 l += ((long)*p++) << 16;
261 l += ((long)*p++) << 24;
265 s = find_section_by_index(r->secref);
266 if(s)
267 l += s->org;
269 s = find_section_by_index(r->secrel);
270 if(s)
271 l -= s->org;
273 if (r->bytes == 4)
274 WRITELONG(q, l);
275 else if (r->bytes == 2)
276 WRITESHORT(q, l);
277 else
278 *q++ = l & 0xFF;
279 saa_fwrite (r->target->contents, r->posn, mydata, r->bytes);
282 /* write sections to file */
283 for(s = outsections; s; s = s->next)
285 if(s->length > 0 && strcmp(s->name,".bss"))
287 #ifdef DEBUG
288 fprintf(stdout, "bin_cleanup: writing section %s\n", s->name);
289 #endif
290 saa_fpwrite (s->contents, fp);
291 if( s->next )
292 while( s->pad-- > 0 )
293 fputc('\0', fp);
294 /* could pad with nops, since we don't
295 * know if this is code section or not
300 fclose (fp);
302 while (relocs) {
303 r = relocs->next;
304 nasm_free (relocs);
305 relocs = r;
308 while (outsections) {
309 s = outsections->next;
310 saa_free (outsections->contents);
311 nasm_free (outsections->name);
312 nasm_free (outsections);
313 outsections = s;
317 static void bin_out (long segto, const void *data, unsigned long type,
318 long segment, long wrt)
320 unsigned char *p, mydata[4];
321 struct Section *s, *sec;
322 long realbytes;
324 if (wrt != NO_SEG) {
325 wrt = NO_SEG; /* continue to do _something_ */
326 error (ERR_NONFATAL, "WRT not supported by binary output format");
330 * handle absolute-assembly (structure definitions)
332 if (segto == NO_SEG) {
333 if ((type & OUT_TYPMASK) != OUT_RESERVE)
334 error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
335 " space");
336 return;
340 * Find the segment we are targetting.
342 s = find_section_by_index(segto);
343 if (!s)
344 error (ERR_PANIC, "code directed to nonexistent segment?");
346 if (!strcmp(s->name, ".bss")) { /* BSS */
347 if ((type & OUT_TYPMASK) != OUT_RESERVE)
348 error(ERR_WARNING, "attempt to initialise memory in the"
349 " BSS section: ignored");
350 s = NULL;
353 if ((type & OUT_TYPMASK) == OUT_ADDRESS) {
355 if (segment != NO_SEG && !find_section_by_index(segment)) {
356 if (segment % 2)
357 error(ERR_NONFATAL, "binary output format does not support"
358 " segment base references");
359 else
360 error(ERR_NONFATAL, "binary output format does not support"
361 " external references");
362 segment = NO_SEG;
365 if (s) {
366 if (segment != NO_SEG)
367 add_reloc (s, type & OUT_SIZMASK, segment, -1L);
368 p = mydata;
369 if ((type & OUT_SIZMASK) == 4)
370 WRITELONG (p, *(long *)data);
371 else
372 WRITESHORT (p, *(long *)data);
373 saa_wbytes (s->contents, mydata, type & OUT_SIZMASK);
374 s->length += type & OUT_SIZMASK;
375 } else {
376 sec = find_section_by_name(".bss");
377 if(!sec)
378 error(ERR_PANIC, ".bss section is not present");
379 sec->length += type & OUT_SIZMASK;
382 } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) {
383 type &= OUT_SIZMASK;
384 if (s) {
385 saa_wbytes (s->contents, data, type);
386 s->length += type;
387 } else {
388 sec = find_section_by_name(".bss");
389 if(!sec)
390 error(ERR_PANIC, ".bss section is not present");
391 sec->length += type;
394 } else if ((type & OUT_TYPMASK) == OUT_RESERVE) {
395 if (s) {
396 error(ERR_WARNING, "uninitialised space declared in"
397 " %s section: zeroing", s->name);
399 type &= OUT_SIZMASK;
400 if (s) {
401 saa_wbytes (s->contents, NULL, type);
402 s->length += type;
403 } else {
404 sec = find_section_by_name(".bss");
405 if(!sec)
406 error(ERR_PANIC, ".bss section is not present");
407 sec->length += type;
410 else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
411 (type & OUT_TYPMASK) == OUT_REL4ADR)
413 realbytes = ((type & OUT_TYPMASK) == OUT_REL4ADR ? 4 : 2);
415 if (segment != NO_SEG && !find_section_by_index(segment)) {
416 if (segment % 2)
417 error(ERR_NONFATAL, "binary output format does not support"
418 " segment base references");
419 else
420 error(ERR_NONFATAL, "binary output format does not support"
421 " external references");
422 segment = NO_SEG;
425 if (s) {
426 add_reloc (s, realbytes, segment, segto);
427 p = mydata;
428 if (realbytes == 4)
429 WRITELONG (p, *(long*)data - realbytes - s->length);
430 else
431 WRITESHORT (p, *(long*)data - realbytes - s->length);
432 saa_wbytes (s->contents, mydata, realbytes);
433 s->length += realbytes;
434 } else {
435 sec = find_section_by_name(".bss");
436 if(!sec)
437 error(ERR_PANIC, ".bss section is not present");
438 sec->length += realbytes;
443 static void bin_deflabel (char *name, long segment, long offset,
444 int is_global, char *special)
446 (void) segment; /* Don't warn that this parameter is unused */
447 (void) offset; /* Don't warn that this parameter is unused */
449 if (special)
450 error (ERR_NONFATAL, "binary format does not support any"
451 " special symbol types");
453 if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
454 error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
455 return;
458 if (is_global == 2) {
459 error (ERR_NONFATAL, "binary output format does not support common"
460 " variables");
464 static long bin_secname (char *name, int pass, int *bits)
466 int sec_index;
467 long *sec_align;
468 char *p;
469 struct Section *sec;
471 (void) pass; /* Don't warn that this parameter is unused */
474 * Default is 16 bits .text segment
476 if (!name)
478 *bits = 16;
479 sec = find_section_by_name(".text");
480 if(!sec) sec = alloc_section(".text");
481 sec->org = 0; /* default .text org */
482 current_section = sec->index;
483 return sec->index;
486 p = name;
487 while (*p && !isspace(*p)) p++;
488 if (*p) *p++ = '\0';
489 if (!strcmp(name, ".text")) {
490 sec = find_section_by_name(".text");
491 if(!sec) sec = alloc_section(".text");
492 sec_index = sec->index;
493 sec_align = NULL;
494 } else {
495 sec = find_section_by_name(name);
496 if(!sec) sec = alloc_section(name);
497 sec_index = sec->index;
498 sec_align = &sec->align;
501 if (*p) {
502 if (!nasm_strnicmp(p,"align=",6)) {
503 if (sec_align == NULL)
504 error(ERR_NONFATAL, "cannot specify an alignment to"
505 " the .text section");
506 else if (p[6+strspn(p+6,"0123456789")])
507 error(ERR_NONFATAL, "argument to `align' is not numeric");
508 else {
509 unsigned int align = atoi(p+6);
510 if (!align || ((align-1) & align))
511 error(ERR_NONFATAL, "argument to `align' is not a"
512 " power of two");
513 else
514 *sec_align = align;
519 current_section = sec->index;
520 return sec_index;
523 static long bin_segbase (long segment)
525 return segment;
528 static int bin_directive (char *directive, char *value, int pass)
530 struct Section *s;
531 int rn_error;
533 (void) pass; /* Don't warn that this parameter is unused */
535 if (!nasm_stricmp(directive, "org")) {
536 if(current_section == -1)
537 error(ERR_PANIC, "org of cosmic space specified");
539 s = find_section_by_index(current_section);
540 if(!s)
541 error(ERR_PANIC, "current_section points nowhere");
543 s->org = readnum (value, &rn_error);
544 if (rn_error)
545 error (ERR_NONFATAL, "argument to ORG should be numeric");
546 return 1;
549 return 0;
552 static void bin_filename (char *inname, char *outname, efunc error)
554 standard_extension (inname, outname, "", error);
557 static const char *bin_stdmac[] = {
558 "%define __SECT__ [section .text]",
559 "%imacro org 1+.nolist",
560 "[org %1]",
561 "%endmacro",
562 "%macro __NASM_CDecl__ 1",
563 "%endmacro",
564 NULL
567 static int bin_set_info(enum geninfo type, char **val)
569 return 0;
572 struct ofmt of_bin = {
573 "flat-form binary files (e.g. DOS .COM, .SYS) multisection support test",
574 "bin",
575 NULL,
576 null_debug_arr,
577 &null_debug_form,
578 bin_stdmac,
579 bin_init,
580 bin_set_info,
581 bin_out,
582 bin_deflabel,
583 bin_secname,
584 bin_segbase,
585 bin_directive,
586 bin_filename,
587 bin_cleanup
590 #endif /* OF_BIN */