Automatically make a specfile
[nasm.git] / output / outbin.c
blob424b4f4443c3b468bb8b2190ffb3ab1ad84dd7b7
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, 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 p = data;
385 if (s) {
386 saa_wbytes (s->contents, data, type);
387 s->length += type;
388 } else {
389 sec = find_section_by_name(".bss");
390 if(!sec)
391 error(ERR_PANIC, ".bss section is not present");
392 sec->length += type;
395 } else if ((type & OUT_TYPMASK) == OUT_RESERVE) {
396 if (s) {
397 error(ERR_WARNING, "uninitialised space declared in"
398 " %s section: zeroing", s->name);
400 type &= OUT_SIZMASK;
401 if (s) {
402 saa_wbytes (s->contents, NULL, type);
403 s->length += type;
404 } else {
405 sec = find_section_by_name(".bss");
406 if(!sec)
407 error(ERR_PANIC, ".bss section is not present");
408 sec->length += type;
411 else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
412 (type & OUT_TYPMASK) == OUT_REL4ADR)
414 realbytes = ((type & OUT_TYPMASK) == OUT_REL4ADR ? 4 : 2);
416 if (segment != NO_SEG && !find_section_by_index(segment)) {
417 if (segment % 2)
418 error(ERR_NONFATAL, "binary output format does not support"
419 " segment base references");
420 else
421 error(ERR_NONFATAL, "binary output format does not support"
422 " external references");
423 segment = NO_SEG;
426 if (s) {
427 add_reloc (s, realbytes, segment, segto);
428 p = mydata;
429 if (realbytes == 4)
430 WRITELONG (p, *(long*)data - realbytes - s->length);
431 else
432 WRITESHORT (p, *(long*)data - realbytes - s->length);
433 saa_wbytes (s->contents, mydata, realbytes);
434 s->length += realbytes;
435 } else {
436 sec = find_section_by_name(".bss");
437 if(!sec)
438 error(ERR_PANIC, ".bss section is not present");
439 sec->length += realbytes;
444 static void bin_deflabel (char *name, long segment, long offset,
445 int is_global, char *special)
447 (void) segment; /* Don't warn that this parameter is unused */
448 (void) offset; /* Don't warn that this parameter is unused */
450 if (special)
451 error (ERR_NONFATAL, "binary format does not support any"
452 " special symbol types");
454 if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
455 error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
456 return;
459 if (is_global == 2) {
460 error (ERR_NONFATAL, "binary output format does not support common"
461 " variables");
465 static long bin_secname (char *name, int pass, int *bits)
467 int sec_index;
468 long *sec_align;
469 char *p;
470 struct Section *sec;
472 (void) pass; /* Don't warn that this parameter is unused */
475 * Default is 16 bits .text segment
477 if (!name)
479 *bits = 16;
480 sec = find_section_by_name(".text");
481 if(!sec) sec = alloc_section(".text");
482 sec->org = 0; /* default .text org */
483 current_section = sec->index;
484 return sec->index;
487 p = name;
488 while (*p && !isspace(*p)) p++;
489 if (*p) *p++ = '\0';
490 if (!strcmp(name, ".text")) {
491 sec = find_section_by_name(".text");
492 if(!sec) sec = alloc_section(".text");
493 sec_index = sec->index;
494 sec_align = NULL;
495 } else {
496 sec = find_section_by_name(name);
497 if(!sec) sec = alloc_section(name);
498 sec_index = sec->index;
499 sec_align = &sec->align;
502 if (*p) {
503 if (!nasm_strnicmp(p,"align=",6)) {
504 if (sec_align == NULL)
505 error(ERR_NONFATAL, "cannot specify an alignment to"
506 " the .text section");
507 else if (p[6+strspn(p+6,"0123456789")])
508 error(ERR_NONFATAL, "argument to `align' is not numeric");
509 else {
510 unsigned int align = atoi(p+6);
511 if (!align || ((align-1) & align))
512 error(ERR_NONFATAL, "argument to `align' is not a"
513 " power of two");
514 else
515 *sec_align = align;
520 current_section = sec->index;
521 return sec_index;
524 static long bin_segbase (long segment)
526 return segment;
529 static int bin_directive (char *directive, char *value, int pass)
531 struct Section *s;
532 int rn_error;
534 (void) pass; /* Don't warn that this parameter is unused */
536 if (!nasm_stricmp(directive, "org")) {
537 if(current_section == -1)
538 error(ERR_PANIC, "org of cosmic space specified");
540 s = find_section_by_index(current_section);
541 if(!s)
542 error(ERR_PANIC, "current_section points nowhere");
544 s->org = readnum (value, &rn_error);
545 if (rn_error)
546 error (ERR_NONFATAL, "argument to ORG should be numeric");
547 return 1;
550 return 0;
553 static void bin_filename (char *inname, char *outname, efunc error)
555 standard_extension (inname, outname, "", error);
558 static const char *bin_stdmac[] = {
559 "%define __SECT__ [section .text]",
560 "%imacro org 1+.nolist",
561 "[org %1]",
562 "%endmacro",
563 "%macro __NASM_CDecl__ 1",
564 "%endmacro",
565 NULL
568 static int bin_set_info(enum geninfo type, char **val)
570 return 0;
573 struct ofmt of_bin = {
574 "flat-form binary files (e.g. DOS .COM, .SYS) multisection support test",
575 "bin",
576 NULL,
577 null_debug_arr,
578 &null_debug_form,
579 bin_stdmac,
580 bin_init,
581 bin_set_info,
582 bin_out,
583 bin_deflabel,
584 bin_secname,
585 bin_segbase,
586 bin_directive,
587 bin_filename,
588 bin_cleanup
591 #endif /* OF_BIN */