NASM 0.98p7
[nasm.git] / outbin.c
bloba3289cfc2f536502461eb0309a452c462198798e
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 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
15 #include "nasm.h"
16 #include "nasmlib.h"
17 #include "outform.h"
19 #ifdef OF_BIN
21 static FILE *fp;
22 static efunc error;
24 static struct Section {
25 struct SAA *contents;
26 long length;
27 long index;
28 } textsect, datasect;
29 static long bsslen, bssindex;
31 static struct Reloc {
32 struct Reloc *next;
33 long posn;
34 long bytes;
35 long secref;
36 long secrel;
37 struct Section *target;
38 } *relocs, **reloctail;
40 static long data_align, bss_align;
42 static long start_point;
44 static void add_reloc (struct Section *s, long bytes, long secref,
45 long secrel)
47 struct Reloc *r;
49 r = *reloctail = nasm_malloc(sizeof(struct Reloc));
50 reloctail = &r->next;
51 r->next = NULL;
52 r->posn = s->length;
53 r->bytes = bytes;
54 r->secref = secref;
55 r->secrel = secrel;
56 r->target = s;
59 static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval)
61 fp = afp;
63 (void) eval; /* Don't warn that this parameter is unused */
65 error = errfunc;
66 (void) ldef; /* placate optimisers */
68 start_point = 0L; /* default */
69 textsect.contents = saa_init(1L);
70 datasect.contents = saa_init(1L);
71 textsect.length = datasect.length = 0;
72 textsect.index = seg_alloc();
73 datasect.index = seg_alloc();
74 bsslen = 0;
75 bssindex = seg_alloc();
76 relocs = NULL;
77 reloctail = &relocs;
78 data_align = bss_align = 4;
81 static void bin_cleanup (int debuginfo)
83 struct Reloc *r;
84 long datapos, datagap, bsspos;
86 (void) debuginfo;
88 datapos = start_point + textsect.length;
89 datapos = (datapos + data_align-1) & ~(data_align-1);
90 datagap = datapos - (start_point + textsect.length);
91 bsspos = datapos + datasect.length;
92 bsspos = (bsspos + bss_align-1) & ~(bss_align-1);
94 saa_rewind (textsect.contents);
95 saa_rewind (datasect.contents);
97 for (r = relocs; r; r = r->next)
99 unsigned char *p, *q, mydata[4];
100 long l;
102 saa_fread (r->target->contents, r->posn, mydata, r->bytes);
103 p = q = mydata;
104 l = *p++;
105 if (r->bytes > 1) {
106 l += ((long)*p++) << 8;
107 if (r->bytes == 4) {
108 l += ((long)*p++) << 16;
109 l += ((long)*p++) << 24;
113 if (r->secref == textsect.index)
114 l += start_point;
115 else if (r->secref == datasect.index)
116 l += datapos;
117 else if (r->secref == bssindex)
118 l += bsspos;
120 if (r->secrel == textsect.index)
121 l -= start_point;
122 else if (r->secrel == datasect.index)
123 l -= datapos;
124 else if (r->secrel == bssindex)
125 l -= bsspos;
127 if (r->bytes == 4)
128 WRITELONG(q, l);
129 else if (r->bytes == 2)
130 WRITESHORT(q, l);
131 else
132 *q++ = l & 0xFF;
133 saa_fwrite (r->target->contents, r->posn, mydata, r->bytes);
135 saa_fpwrite (textsect.contents, fp);
136 if (datasect.length > 0) {
137 while (datagap--)
138 fputc('\0', fp);
139 saa_fpwrite (datasect.contents, fp);
141 fclose (fp);
142 saa_free (textsect.contents);
143 saa_free (datasect.contents);
144 while (relocs) {
145 r = relocs->next;
146 nasm_free (relocs);
147 relocs = r;
151 static void bin_out (long segto, void *data, unsigned long type,
152 long segment, long wrt)
154 unsigned char *p, mydata[4];
155 struct Section *s;
156 long realbytes;
158 if (wrt != NO_SEG) {
159 wrt = NO_SEG; /* continue to do _something_ */
160 error (ERR_NONFATAL, "WRT not supported by binary output format");
164 * handle absolute-assembly (structure definitions)
166 if (segto == NO_SEG) {
167 if ((type & OUT_TYPMASK) != OUT_RESERVE)
168 error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
169 " space");
170 return;
173 if (segto == bssindex) { /* BSS */
174 if ((type & OUT_TYPMASK) != OUT_RESERVE)
175 error(ERR_WARNING, "attempt to initialise memory in the"
176 " BSS section: ignored");
177 s = NULL;
178 } else if (segto == textsect.index) {
179 s = &textsect;
180 } else if (segto == datasect.index) {
181 s = &datasect;
182 } else {
183 error(ERR_WARNING, "attempt to assemble code in"
184 " segment %d: defaulting to `.text'", segto);
185 s = &textsect;
188 if ((type & OUT_TYPMASK) == OUT_ADDRESS) {
189 if (segment != NO_SEG &&
190 segment != textsect.index &&
191 segment != datasect.index &&
192 segment != bssindex) {
193 if (segment % 2)
194 error(ERR_NONFATAL, "binary output format does not support"
195 " segment base references");
196 else
197 error(ERR_NONFATAL, "binary output format does not support"
198 " external references");
199 segment = NO_SEG;
201 if (s) {
202 if (segment != NO_SEG)
203 add_reloc (s, type & OUT_SIZMASK, segment, -1L);
204 p = mydata;
205 if ((type & OUT_SIZMASK) == 4)
206 WRITELONG (p, *(long *)data);
207 else
208 WRITESHORT (p, *(long *)data);
209 saa_wbytes (s->contents, mydata, type & OUT_SIZMASK);
210 s->length += type & OUT_SIZMASK;
211 } else
212 bsslen += type & OUT_SIZMASK;
213 } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) {
214 type &= OUT_SIZMASK;
215 p = data;
216 if (s) {
217 saa_wbytes (s->contents, data, type);
218 s->length += type;
219 } else
220 bsslen += type;
221 } else if ((type & OUT_TYPMASK) == OUT_RESERVE) {
222 if (s) {
223 error(ERR_WARNING, "uninitialised space declared in"
224 " %s section: zeroing",
225 (segto == textsect.index ? "code" : "data"));
227 type &= OUT_SIZMASK;
228 if (s) {
229 saa_wbytes (s->contents, NULL, type);
230 s->length += type;
231 } else
232 bsslen += type;
234 else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
235 (type & OUT_TYPMASK) == OUT_REL4ADR)
237 realbytes = ((type & OUT_TYPMASK) == OUT_REL4ADR ? 4 : 2);
238 if (segment != NO_SEG &&
239 segment != textsect.index &&
240 segment != datasect.index &&
241 segment != bssindex) {
242 if (segment % 2)
243 error(ERR_NONFATAL, "binary output format does not support"
244 " segment base references");
245 else
246 error(ERR_NONFATAL, "binary output format does not support"
247 " external references");
248 segment = NO_SEG;
250 if (s) {
251 add_reloc (s, realbytes, segment, segto);
252 p = mydata;
253 if (realbytes == 4)
254 WRITELONG (p, *(long*)data - realbytes - s->length);
255 else
256 WRITESHORT (p, *(long*)data - realbytes - s->length);
257 saa_wbytes (s->contents, mydata, realbytes);
258 s->length += realbytes;
259 } else
260 bsslen += realbytes;
264 static void bin_deflabel (char *name, long segment, long offset,
265 int is_global, char *special)
268 (void) segment; /* Don't warn that this parameter is unused */
269 (void) offset; /* Don't warn that this parameter is unused */
271 if (special)
272 error (ERR_NONFATAL, "binary format does not support any"
273 " special symbol types");
275 if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
276 error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
277 return;
280 if (is_global == 2) {
281 error (ERR_NONFATAL, "binary output format does not support common"
282 " variables");
286 static long bin_secname (char *name, int pass, int *bits)
288 int sec_index;
289 long *sec_align;
290 char *p;
292 (void) pass; /* Don't warn that this parameter is unused */
295 * Default is 16 bits.
297 if (!name)
298 *bits = 16;
300 if (!name)
301 return textsect.index;
303 p = name;
304 while (*p && !isspace(*p)) p++;
305 if (*p) *p++ = '\0';
306 if (!strcmp(name, ".text")) {
307 sec_index = textsect.index;
308 sec_align = NULL;
309 } else if (!strcmp(name, ".data")) {
310 sec_index = datasect.index;
311 sec_align = &data_align;
312 } else if (!strcmp(name, ".bss")) {
313 sec_index = bssindex;
314 sec_align = &bss_align;
315 } else
316 return NO_SEG;
318 if (*p) {
319 if (!nasm_strnicmp(p,"align=",6)) {
320 if (sec_align == NULL)
321 error(ERR_NONFATAL, "cannot specify an alignment to"
322 " the `.text' section");
323 else if (p[6+strspn(p+6,"0123456789")])
324 error(ERR_NONFATAL, "argument to `align' is not numeric");
325 else {
326 unsigned int align = atoi(p+6);
327 if (!align || ((align-1) & align))
328 error(ERR_NONFATAL, "argument to `align' is not a"
329 " power of two");
330 else
331 *sec_align = align;
336 return sec_index;
339 static long bin_segbase (long segment)
341 return segment;
344 static int bin_directive (char *directive, char *value, int pass)
346 int rn_error;
348 (void) pass; /* Don't warn that this parameter is unused */
350 if (!strcmp(directive, "org")) {
351 start_point = readnum (value, &rn_error);
352 if (rn_error)
353 error (ERR_NONFATAL, "argument to ORG should be numeric");
354 return 1;
355 } else
356 return 0;
359 static void bin_filename (char *inname, char *outname, efunc error)
361 standard_extension (inname, outname, "", error);
364 static char *bin_stdmac[] = {
365 "%define __SECT__ [section .text]",
366 "%imacro org 1+.nolist",
367 "[org %1]",
368 "%endmacro",
369 "%macro __NASM_CDecl__ 1",
370 "%endmacro",
371 NULL
374 static int bin_set_info(enum geninfo type, char **val)
376 return 0;
378 struct ofmt of_bin = {
379 "flat-form binary files (e.g. DOS .COM, .SYS)",
380 "bin",
381 NULL,
382 null_debug_arr,
383 &null_debug_form,
384 bin_stdmac,
385 bin_init,
386 bin_set_info,
387 bin_out,
388 bin_deflabel,
389 bin_secname,
390 bin_segbase,
391 bin_directive,
392 bin_filename,
393 bin_cleanup
396 #endif /* OF_BIN */