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.
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.
31 static struct Section
{
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 */
41 } *sections
, **sectail
;
49 struct Section
*target
;
50 } *relocs
, **reloctail
;
52 static long current_section
;
54 static void add_reloc (struct Section
*s
, long bytes
, long secref
,
59 r
= *reloctail
= nasm_malloc(sizeof(struct Reloc
));
69 static struct Section
*find_section_by_name(char *name
)
73 for (s
= sections
; s
; s
= s
->next
)
74 if (!strcmp(s
->name
,name
))
80 static struct Section
*find_section_by_index(long index
)
84 for (s
= sections
; s
; s
= s
->next
)
85 if ( s
->index
== index
)
91 static struct Section
*alloc_section(char *name
)
95 s
= find_section_by_name(name
);
97 error(ERR_PANIC
, "section %s re-defined", name
);
99 s
= nasm_malloc(sizeof(struct Section
));
104 s
->contents
= saa_init(1L);
107 s
->org
= -1; /* default org is -1 because we want
108 * to adjust sections one after another
110 s
->index
= seg_alloc();
113 s
->name
= nasm_strdup(name
);
118 static void bin_init (FILE *afp
, efunc errfunc
, ldfunc ldef
, evalfunc eval
)
123 (void) eval
; /* Don't warn that this parameter is unused */
124 (void) ldef
; /* placate optimisers */
126 current_section
= -1L;
133 static void bin_cleanup (int debuginfo
)
135 struct Section
*outsections
, **outstail
;
136 struct Section
*s
, *o
, *ls
, *lo
;
142 /* sort sections by their orgs
143 * sections without org follow their natural order
144 * after the org'd sections
147 outstail
= &outsections
;
151 least_org
= 0x7fffffff;
154 for( s
= sections
, o
= NULL
; s
; o
= s
, s
= s
->next
)
155 if( s
->org
!= -1 && s
->org
< least_org
)
162 if(ls
) /* relink to outsections */
165 fprintf(stdout
, "bin_cleanup: relinking section %s org %ld\n", ls
->name
, ls
->org
);
167 /* unlink from sections */
174 /* link in to outsections */
178 outstail
= &ls
->next
;
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 */
197 /* if section doesn't have its
198 * own org, align from prev section
201 s
->org
= o
->org
+ o
->length
;
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
)
213 fprintf(stdout
, "forced padding: %ld\n", s
->org
- o
->org
- o
->length
);
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
;
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
,
229 /* prepare for relocating by the way */
230 saa_rewind( s
->contents
);
236 s
= find_section_by_name(".bss");
239 s
->org
= o
->org
+ o
->length
+ o
->pad
;
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
);
247 /* apply relocations */
248 for (r
= relocs
; r
; r
= r
->next
)
250 unsigned char *p
, *q
, mydata
[4];
253 saa_fread (r
->target
->contents
, r
->posn
, mydata
, r
->bytes
);
258 l
+= ((long)*p
++) << 8;
260 l
+= ((long)*p
++) << 16;
261 l
+= ((long)*p
++) << 24;
265 s
= find_section_by_index(r
->secref
);
269 s
= find_section_by_index(r
->secrel
);
275 else if (r
->bytes
== 2)
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"))
288 fprintf(stdout
, "bin_cleanup: writing section %s\n", s
->name
);
290 saa_fpwrite (s
->contents
, fp
);
292 while( s
->pad
-- > 0 )
294 /* could pad with nops, since we don't
295 * know if this is code section or not
308 while (outsections
) {
309 s
= outsections
->next
;
310 saa_free (outsections
->contents
);
311 nasm_free (outsections
->name
);
312 nasm_free (outsections
);
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
;
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]"
340 * Find the segment we are targetting.
342 s
= find_section_by_index(segto
);
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");
353 if ((type
& OUT_TYPMASK
) == OUT_ADDRESS
) {
355 if (segment
!= NO_SEG
&& !find_section_by_index(segment
)) {
357 error(ERR_NONFATAL
, "binary output format does not support"
358 " segment base references");
360 error(ERR_NONFATAL
, "binary output format does not support"
361 " external references");
366 if (segment
!= NO_SEG
)
367 add_reloc (s
, type
& OUT_SIZMASK
, segment
, -1L);
369 if ((type
& OUT_SIZMASK
) == 4)
370 WRITELONG (p
, *(long *)data
);
372 WRITESHORT (p
, *(long *)data
);
373 saa_wbytes (s
->contents
, mydata
, type
& OUT_SIZMASK
);
374 s
->length
+= type
& OUT_SIZMASK
;
376 sec
= find_section_by_name(".bss");
378 error(ERR_PANIC
, ".bss section is not present");
379 sec
->length
+= type
& OUT_SIZMASK
;
382 } else if ((type
& OUT_TYPMASK
) == OUT_RAWDATA
) {
386 saa_wbytes (s
->contents
, data
, type
);
389 sec
= find_section_by_name(".bss");
391 error(ERR_PANIC
, ".bss section is not present");
395 } else if ((type
& OUT_TYPMASK
) == OUT_RESERVE
) {
397 error(ERR_WARNING
, "uninitialised space declared in"
398 " %s section: zeroing", s
->name
);
402 saa_wbytes (s
->contents
, NULL
, type
);
405 sec
= find_section_by_name(".bss");
407 error(ERR_PANIC
, ".bss section is not present");
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
)) {
418 error(ERR_NONFATAL
, "binary output format does not support"
419 " segment base references");
421 error(ERR_NONFATAL
, "binary output format does not support"
422 " external references");
427 add_reloc (s
, realbytes
, segment
, segto
);
430 WRITELONG (p
, *(long*)data
- realbytes
- s
->length
);
432 WRITESHORT (p
, *(long*)data
- realbytes
- s
->length
);
433 saa_wbytes (s
->contents
, mydata
, realbytes
);
434 s
->length
+= realbytes
;
436 sec
= find_section_by_name(".bss");
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 */
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
);
459 if (is_global
== 2) {
460 error (ERR_NONFATAL
, "binary output format does not support common"
465 static long bin_secname (char *name
, int pass
, int *bits
)
472 (void) pass
; /* Don't warn that this parameter is unused */
475 * Default is 16 bits .text segment
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
;
488 while (*p
&& !isspace(*p
)) p
++;
490 if (!strcmp(name
, ".text")) {
491 sec
= find_section_by_name(".text");
492 if(!sec
) sec
= alloc_section(".text");
493 sec_index
= sec
->index
;
496 sec
= find_section_by_name(name
);
497 if(!sec
) sec
= alloc_section(name
);
498 sec_index
= sec
->index
;
499 sec_align
= &sec
->align
;
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");
510 unsigned int align
= atoi(p
+6);
511 if (!align
|| ((align
-1) & align
))
512 error(ERR_NONFATAL
, "argument to `align' is not a"
520 current_section
= sec
->index
;
524 static long bin_segbase (long segment
)
529 static int bin_directive (char *directive
, char *value
, int pass
)
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
);
542 error(ERR_PANIC
, "current_section points nowhere");
544 s
->org
= readnum (value
, &rn_error
);
546 error (ERR_NONFATAL
, "argument to ORG should be numeric");
553 static void bin_filename (char *inname
, char *outname
, efunc error
)
555 standard_extension (inname
, outname
, "", error
);
558 static char *bin_stdmac
[] = {
559 "%define __SECT__ [section .text]",
560 "%imacro org 1+.nolist",
563 "%macro __NASM_CDecl__ 1",
568 static int bin_set_info(enum geninfo type
, char **val
)
573 struct ofmt of_bin
= {
574 "flat-form binary files (e.g. DOS .COM, .SYS) multisection support test",