NASM 0.96
[nasm/avx512.git] / outbin.c
blob3540739f6b429ccd4316e0b3e59d34573da1f80d
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) {
46 struct Reloc *r;
48 r = *reloctail = nasm_malloc(sizeof(struct Reloc));
49 reloctail = &r->next;
50 r->next = NULL;
51 r->posn = s->length;
52 r->bytes = bytes;
53 r->secref = secref;
54 r->secrel = secrel;
55 r->target = s;
58 static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) {
59 fp = afp;
61 error = errfunc;
62 (void) ldef; /* placate optimisers */
64 start_point = 0L; /* default */
65 textsect.contents = saa_init(1L);
66 datasect.contents = saa_init(1L);
67 textsect.length = datasect.length = 0;
68 textsect.index = seg_alloc();
69 datasect.index = seg_alloc();
70 bsslen = 0;
71 bssindex = seg_alloc();
72 relocs = NULL;
73 reloctail = &relocs;
74 data_align = bss_align = 4;
77 static void bin_cleanup (void) {
78 struct Reloc *r;
79 long datapos, datagap, bsspos;
81 datapos = start_point + textsect.length;
82 datapos = (datapos + data_align-1) & ~(data_align-1);
83 datagap = datapos - (start_point + textsect.length);
84 bsspos = datapos + datasect.length;
85 bsspos = (bsspos + bss_align-1) & ~(bss_align-1);
87 saa_rewind (textsect.contents);
88 saa_rewind (datasect.contents);
90 for (r = relocs; r; r = r->next) {
91 unsigned char *p, *q, mydata[4];
92 long l;
94 saa_fread (r->target->contents, r->posn, mydata, r->bytes);
95 p = q = mydata;
96 l = *p++;
97 if (r->bytes > 1) {
98 l += ((long)*p++) << 8;
99 if (r->bytes == 4) {
100 l += ((long)*p++) << 16;
101 l += ((long)*p++) << 24;
105 if (r->secref == textsect.index)
106 l += start_point;
107 else if (r->secref == datasect.index)
108 l += datapos;
109 else if (r->secref == bssindex)
110 l += bsspos;
112 if (r->secrel == textsect.index)
113 l -= start_point;
114 else if (r->secrel == datasect.index)
115 l -= datapos;
116 else if (r->secrel == bssindex)
117 l -= bsspos;
119 if (r->bytes == 4)
120 WRITELONG(q, l);
121 else if (r->bytes == 2)
122 WRITESHORT(q, l);
123 else
124 *q++ = l & 0xFF;
125 saa_fwrite (r->target->contents, r->posn, mydata, r->bytes);
127 saa_fpwrite (textsect.contents, fp);
128 if (datasect.length > 0) {
129 while (datagap--)
130 fputc('\0', fp);
131 saa_fpwrite (datasect.contents, fp);
133 fclose (fp);
134 saa_free (textsect.contents);
135 saa_free (datasect.contents);
136 while (relocs) {
137 r = relocs->next;
138 nasm_free (relocs);
139 relocs = r;
143 static void bin_out (long segto, void *data, unsigned long type,
144 long segment, long wrt) {
145 unsigned char *p, mydata[4];
146 struct Section *s;
147 long realbytes;
149 if (wrt != NO_SEG) {
150 wrt = NO_SEG; /* continue to do _something_ */
151 error (ERR_NONFATAL, "WRT not supported by binary output format");
155 * handle absolute-assembly (structure definitions)
157 if (segto == NO_SEG) {
158 if ((type & OUT_TYPMASK) != OUT_RESERVE)
159 error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
160 " space");
161 return;
164 if (segto == bssindex) { /* BSS */
165 if ((type & OUT_TYPMASK) != OUT_RESERVE)
166 error(ERR_WARNING, "attempt to initialise memory in the"
167 " BSS section: ignored");
168 s = NULL;
169 } else if (segto == textsect.index) {
170 s = &textsect;
171 } else if (segto == datasect.index) {
172 s = &datasect;
173 } else {
174 error(ERR_WARNING, "attempt to assemble code in"
175 " segment %d: defaulting to `.text'", segto);
176 s = &textsect;
179 if ((type & OUT_TYPMASK) == OUT_ADDRESS) {
180 if (segment != NO_SEG &&
181 segment != textsect.index &&
182 segment != datasect.index &&
183 segment != bssindex) {
184 if (segment % 2)
185 error(ERR_NONFATAL, "binary output format does not support"
186 " segment base references");
187 else
188 error(ERR_NONFATAL, "binary output format does not support"
189 " external references");
190 segment = NO_SEG;
192 if (s) {
193 if (segment != NO_SEG)
194 add_reloc (s, type & OUT_SIZMASK, segment, -1L);
195 p = mydata;
196 if ((type & OUT_SIZMASK) == 4)
197 WRITELONG (p, *(long *)data);
198 else
199 WRITESHORT (p, *(long *)data);
200 saa_wbytes (s->contents, mydata, type & OUT_SIZMASK);
201 s->length += type & OUT_SIZMASK;
202 } else
203 bsslen += type & OUT_SIZMASK;
204 } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) {
205 type &= OUT_SIZMASK;
206 p = data;
207 if (s) {
208 saa_wbytes (s->contents, data, type);
209 s->length += type;
210 } else
211 bsslen += type;
212 } else if ((type & OUT_TYPMASK) == OUT_RESERVE) {
213 if (s) {
214 error(ERR_WARNING, "uninitialised space declared in"
215 " %s section: zeroing",
216 (segto == textsect.index ? "code" : "data"));
218 type &= OUT_SIZMASK;
219 if (s) {
220 saa_wbytes (s->contents, NULL, type);
221 s->length += type;
222 } else
223 bsslen += type;
224 } else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
225 (type & OUT_TYPMASK) == OUT_REL4ADR) {
226 realbytes = ((type & OUT_TYPMASK) == OUT_REL4ADR ? 4 : 2);
227 if (segment != NO_SEG &&
228 segment != textsect.index &&
229 segment != datasect.index &&
230 segment != bssindex) {
231 if (segment % 2)
232 error(ERR_NONFATAL, "binary output format does not support"
233 " segment base references");
234 else
235 error(ERR_NONFATAL, "binary output format does not support"
236 " external references");
237 segment = NO_SEG;
239 if (s) {
240 add_reloc (s, realbytes, segment, segto);
241 p = mydata;
242 if (realbytes == 4)
243 WRITELONG (p, *(long*)data - realbytes - s->length);
244 else
245 WRITESHORT (p, *(long*)data - realbytes - s->length);
246 saa_wbytes (s->contents, mydata, realbytes);
247 s->length += realbytes;
248 } else
249 bsslen += realbytes;
253 static void bin_deflabel (char *name, long segment, long offset,
254 int is_global, char *special) {
256 if (special)
257 error (ERR_NONFATAL, "binary format does not support any"
258 " special symbol types");
260 if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
261 error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
262 return;
265 if (is_global == 2) {
266 error (ERR_NONFATAL, "binary output format does not support common"
267 " variables");
271 static long bin_secname (char *name, int pass, int *bits) {
272 int sec_index;
273 long *sec_align;
274 char *p;
277 * Default is 16 bits.
279 if (!name)
280 *bits = 16;
282 if (!name)
283 return textsect.index;
285 p = name;
286 while (*p && !isspace(*p)) p++;
287 if (*p) *p++ = '\0';
288 if (!strcmp(name, ".text")) {
289 sec_index = textsect.index;
290 sec_align = NULL;
291 } else if (!strcmp(name, ".data")) {
292 sec_index = datasect.index;
293 sec_align = &data_align;
294 } else if (!strcmp(name, ".bss")) {
295 sec_index = bssindex;
296 sec_align = &bss_align;
297 } else
298 return NO_SEG;
300 if (*p) {
301 if (!nasm_strnicmp(p,"align=",6)) {
302 if (sec_align == NULL)
303 error(ERR_NONFATAL, "cannot specify an alignment to"
304 " the `.text' section");
305 else if (p[6+strspn(p+6,"0123456789")])
306 error(ERR_NONFATAL, "argument to `align' is not numeric");
307 else {
308 unsigned int align = atoi(p+6);
309 if (!align || ((align-1) & align))
310 error(ERR_NONFATAL, "argument to `align' is not a"
311 " power of two");
312 else
313 *sec_align = align;
318 return sec_index;
321 static long bin_segbase (long segment) {
322 return segment;
325 static int bin_directive (char *directive, char *value, int pass) {
326 int rn_error;
328 if (!strcmp(directive, "org")) {
329 start_point = readnum (value, &rn_error);
330 if (rn_error)
331 error (ERR_NONFATAL, "argument to ORG should be numeric");
332 return 1;
333 } else
334 return 0;
337 static void bin_filename (char *inname, char *outname, efunc error) {
338 standard_extension (inname, outname, "", error);
341 static char *bin_stdmac[] = {
342 "%define __SECT__ [section .text]",
343 "%imacro org 1+.nolist",
344 "[org %1]",
345 "%endmacro",
346 NULL
349 struct ofmt of_bin = {
350 "flat-form binary files (e.g. DOS .COM, .SYS)",
351 "bin",
352 bin_stdmac,
353 bin_init,
354 bin_out,
355 bin_deflabel,
356 bin_secname,
357 bin_segbase,
358 bin_directive,
359 bin_filename,
360 bin_cleanup
363 #endif /* OF_BIN */