]>
Commit | Line | Data |
---|---|---|
14c7c974 A |
1 | /* |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights | |
7 | * Reserved. This file contains Original Code and/or Modifications of | |
8 | * Original Code as defined in and that are subject to the Apple Public | |
9 | * Source License Version 1.1 (the "License"). You may not use this file | |
10 | * except in compliance with the License. Please obtain a copy of the | |
11 | * License at http://www.apple.com/publicsource and read it before using | |
12 | * this file. | |
13 | * | |
14 | * The Original Code and all software distributed under the License are | |
15 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the | |
19 | * License for the specific language governing rights and limitations | |
20 | * under the License. | |
21 | * | |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | /* outbin.c output routines for the Netwide Assembler to produce | |
25 | * flat-form binary files | |
26 | * | |
27 | * The Netwide Assembler is copyright (C) 1996 Simon Tatham and | |
28 | * Julian Hall. All rights reserved. The software is | |
29 | * redistributable under the licence given in the file "Licence" | |
30 | * distributed in the NASM archive. | |
31 | */ | |
32 | ||
33 | #include <stdio.h> | |
34 | #include <stdlib.h> | |
35 | #include <string.h> | |
36 | #include <ctype.h> | |
37 | ||
38 | #include "nasm.h" | |
39 | #include "nasmlib.h" | |
40 | #include "outform.h" | |
41 | ||
42 | #ifdef OF_BIN | |
43 | ||
44 | static FILE *fp; | |
45 | static efunc error; | |
46 | ||
47 | static struct Section { | |
48 | struct SAA *contents; | |
49 | long length; | |
50 | long index; | |
51 | } textsect, datasect; | |
52 | static long bsslen, bssindex; | |
53 | ||
54 | static struct Reloc { | |
55 | struct Reloc *next; | |
56 | long posn; | |
57 | long bytes; | |
58 | long secref; | |
59 | long secrel; | |
60 | struct Section *target; | |
61 | } *relocs, **reloctail; | |
62 | ||
63 | static long data_align, bss_align; | |
64 | ||
65 | static long start_point; | |
66 | ||
67 | static void add_reloc (struct Section *s, long bytes, long secref, | |
68 | long secrel) { | |
69 | struct Reloc *r; | |
70 | ||
71 | r = *reloctail = nasm_malloc(sizeof(struct Reloc)); | |
72 | reloctail = &r->next; | |
73 | r->next = NULL; | |
74 | r->posn = s->length; | |
75 | r->bytes = bytes; | |
76 | r->secref = secref; | |
77 | r->secrel = secrel; | |
78 | r->target = s; | |
79 | } | |
80 | ||
81 | static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) { | |
82 | fp = afp; | |
83 | ||
84 | error = errfunc; | |
85 | (void) ldef; /* placate optimisers */ | |
86 | ||
87 | start_point = 0L; /* default */ | |
88 | textsect.contents = saa_init(1L); | |
89 | datasect.contents = saa_init(1L); | |
90 | textsect.length = datasect.length = 0; | |
91 | textsect.index = seg_alloc(); | |
92 | datasect.index = seg_alloc(); | |
93 | bsslen = 0; | |
94 | bssindex = seg_alloc(); | |
95 | relocs = NULL; | |
96 | reloctail = &relocs; | |
97 | data_align = bss_align = 4; | |
98 | } | |
99 | ||
100 | static void bin_cleanup (void) { | |
101 | struct Reloc *r; | |
102 | long datapos, datagap, bsspos; | |
103 | ||
104 | datapos = start_point + textsect.length; | |
105 | datapos = (datapos + data_align-1) & ~(data_align-1); | |
106 | datagap = datapos - (start_point + textsect.length); | |
107 | bsspos = datapos + datasect.length; | |
108 | bsspos = (bsspos + bss_align-1) & ~(bss_align-1); | |
109 | ||
110 | saa_rewind (textsect.contents); | |
111 | saa_rewind (datasect.contents); | |
112 | ||
113 | for (r = relocs; r; r = r->next) { | |
114 | unsigned char *p, *q, mydata[4]; | |
115 | long l; | |
116 | ||
117 | saa_fread (r->target->contents, r->posn, mydata, r->bytes); | |
118 | p = q = mydata; | |
119 | l = *p++; | |
120 | if (r->bytes > 1) { | |
121 | l += ((long)*p++) << 8; | |
122 | if (r->bytes == 4) { | |
123 | l += ((long)*p++) << 16; | |
124 | l += ((long)*p++) << 24; | |
125 | } | |
126 | } | |
127 | ||
128 | if (r->secref == textsect.index) | |
129 | l += start_point; | |
130 | else if (r->secref == datasect.index) | |
131 | l += datapos; | |
132 | else if (r->secref == bssindex) | |
133 | l += bsspos; | |
134 | ||
135 | if (r->secrel == textsect.index) | |
136 | l -= start_point; | |
137 | else if (r->secrel == datasect.index) | |
138 | l -= datapos; | |
139 | else if (r->secrel == bssindex) | |
140 | l -= bsspos; | |
141 | ||
142 | if (r->bytes == 4) | |
143 | WRITELONG(q, l); | |
144 | else if (r->bytes == 2) | |
145 | WRITESHORT(q, l); | |
146 | else | |
147 | *q++ = l & 0xFF; | |
148 | saa_fwrite (r->target->contents, r->posn, mydata, r->bytes); | |
149 | } | |
150 | saa_fpwrite (textsect.contents, fp); | |
151 | if (datasect.length > 0) { | |
152 | while (datagap--) | |
153 | fputc('\0', fp); | |
154 | saa_fpwrite (datasect.contents, fp); | |
155 | } | |
156 | fclose (fp); | |
157 | saa_free (textsect.contents); | |
158 | saa_free (datasect.contents); | |
159 | while (relocs) { | |
160 | r = relocs->next; | |
161 | nasm_free (relocs); | |
162 | relocs = r; | |
163 | } | |
164 | } | |
165 | ||
166 | static void bin_out (long segto, void *data, unsigned long type, | |
167 | long segment, long wrt) { | |
168 | unsigned char *p, mydata[4]; | |
169 | struct Section *s; | |
170 | long realbytes; | |
171 | ||
172 | if (wrt != NO_SEG) { | |
173 | wrt = NO_SEG; /* continue to do _something_ */ | |
174 | error (ERR_NONFATAL, "WRT not supported by binary output format"); | |
175 | } | |
176 | ||
177 | /* | |
178 | * handle absolute-assembly (structure definitions) | |
179 | */ | |
180 | if (segto == NO_SEG) { | |
181 | if ((type & OUT_TYPMASK) != OUT_RESERVE) | |
182 | error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" | |
183 | " space"); | |
184 | return; | |
185 | } | |
186 | ||
187 | if (segto == bssindex) { /* BSS */ | |
188 | if ((type & OUT_TYPMASK) != OUT_RESERVE) | |
189 | error(ERR_WARNING, "attempt to initialise memory in the" | |
190 | " BSS section: ignored"); | |
191 | s = NULL; | |
192 | } else if (segto == textsect.index) { | |
193 | s = &textsect; | |
194 | } else if (segto == datasect.index) { | |
195 | s = &datasect; | |
196 | } else { | |
197 | error(ERR_WARNING, "attempt to assemble code in" | |
198 | " segment %d: defaulting to `.text'", segto); | |
199 | s = &textsect; | |
200 | } | |
201 | ||
202 | if ((type & OUT_TYPMASK) == OUT_ADDRESS) { | |
203 | if (segment != NO_SEG && | |
204 | segment != textsect.index && | |
205 | segment != datasect.index && | |
206 | segment != bssindex) { | |
207 | if (segment % 2) | |
208 | error(ERR_NONFATAL, "binary output format does not support" | |
209 | " segment base references"); | |
210 | else | |
211 | error(ERR_NONFATAL, "binary output format does not support" | |
212 | " external references"); | |
213 | segment = NO_SEG; | |
214 | } | |
215 | if (s) { | |
216 | if (segment != NO_SEG) | |
217 | add_reloc (s, type & OUT_SIZMASK, segment, -1L); | |
218 | p = mydata; | |
219 | if ((type & OUT_SIZMASK) == 4) | |
220 | WRITELONG (p, *(long *)data); | |
221 | else | |
222 | WRITESHORT (p, *(long *)data); | |
223 | saa_wbytes (s->contents, mydata, type & OUT_SIZMASK); | |
224 | s->length += type & OUT_SIZMASK; | |
225 | } else | |
226 | bsslen += type & OUT_SIZMASK; | |
227 | } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) { | |
228 | type &= OUT_SIZMASK; | |
229 | p = data; | |
230 | if (s) { | |
231 | saa_wbytes (s->contents, data, type); | |
232 | s->length += type; | |
233 | } else | |
234 | bsslen += type; | |
235 | } else if ((type & OUT_TYPMASK) == OUT_RESERVE) { | |
236 | if (s) { | |
237 | error(ERR_WARNING, "uninitialised space declared in" | |
238 | " %s section: zeroing", | |
239 | (segto == textsect.index ? "code" : "data")); | |
240 | } | |
241 | type &= OUT_SIZMASK; | |
242 | if (s) { | |
243 | saa_wbytes (s->contents, NULL, type); | |
244 | s->length += type; | |
245 | } else | |
246 | bsslen += type; | |
247 | } else if ((type & OUT_TYPMASK) == OUT_REL2ADR || | |
248 | (type & OUT_TYPMASK) == OUT_REL4ADR) { | |
249 | realbytes = ((type & OUT_TYPMASK) == OUT_REL4ADR ? 4 : 2); | |
250 | if (segment != NO_SEG && | |
251 | segment != textsect.index && | |
252 | segment != datasect.index && | |
253 | segment != bssindex) { | |
254 | if (segment % 2) | |
255 | error(ERR_NONFATAL, "binary output format does not support" | |
256 | " segment base references"); | |
257 | else | |
258 | error(ERR_NONFATAL, "binary output format does not support" | |
259 | " external references"); | |
260 | segment = NO_SEG; | |
261 | } | |
262 | if (s) { | |
263 | add_reloc (s, realbytes, segment, segto); | |
264 | p = mydata; | |
265 | if (realbytes == 4) | |
266 | WRITELONG (p, *(long*)data - realbytes - s->length); | |
267 | else | |
268 | WRITESHORT (p, *(long*)data - realbytes - s->length); | |
269 | saa_wbytes (s->contents, mydata, realbytes); | |
270 | s->length += realbytes; | |
271 | } else | |
272 | bsslen += realbytes; | |
273 | } | |
274 | } | |
275 | ||
276 | static void bin_deflabel (char *name, long segment, long offset, | |
277 | int is_global, char *special) { | |
278 | ||
279 | if (special) | |
280 | error (ERR_NONFATAL, "binary format does not support any" | |
281 | " special symbol types"); | |
282 | ||
283 | if (name[0] == '.' && name[1] == '.' && name[2] != '@') { | |
284 | error (ERR_NONFATAL, "unrecognised special symbol `%s'", name); | |
285 | return; | |
286 | } | |
287 | ||
288 | if (is_global == 2) { | |
289 | error (ERR_NONFATAL, "binary output format does not support common" | |
290 | " variables"); | |
291 | } | |
292 | } | |
293 | ||
294 | static long bin_secname (char *name, int pass, int *bits) { | |
295 | int sec_index; | |
296 | long *sec_align; | |
297 | char *p; | |
298 | ||
299 | /* | |
300 | * Default is 16 bits. | |
301 | */ | |
302 | if (!name) | |
303 | *bits = 16; | |
304 | ||
305 | if (!name) | |
306 | return textsect.index; | |
307 | ||
308 | p = name; | |
309 | while (*p && !isspace(*p)) p++; | |
310 | if (*p) *p++ = '\0'; | |
311 | if (!strcmp(name, ".text")) { | |
312 | sec_index = textsect.index; | |
313 | sec_align = NULL; | |
314 | } else if (!strcmp(name, ".data")) { | |
315 | sec_index = datasect.index; | |
316 | sec_align = &data_align; | |
317 | } else if (!strcmp(name, ".bss")) { | |
318 | sec_index = bssindex; | |
319 | sec_align = &bss_align; | |
320 | } else | |
321 | return NO_SEG; | |
322 | ||
323 | if (*p) { | |
324 | if (!nasm_strnicmp(p,"align=",6)) { | |
325 | if (sec_align == NULL) | |
326 | error(ERR_NONFATAL, "cannot specify an alignment to" | |
327 | " the `.text' section"); | |
328 | else if (p[6+strspn(p+6,"0123456789")]) | |
329 | error(ERR_NONFATAL, "argument to `align' is not numeric"); | |
330 | else { | |
331 | unsigned int align = atoi(p+6); | |
332 | if (!align || ((align-1) & align)) | |
333 | error(ERR_NONFATAL, "argument to `align' is not a" | |
334 | " power of two"); | |
335 | else | |
336 | *sec_align = align; | |
337 | } | |
338 | } | |
339 | } | |
340 | ||
341 | return sec_index; | |
342 | } | |
343 | ||
344 | static long bin_segbase (long segment) { | |
345 | return segment; | |
346 | } | |
347 | ||
348 | static int bin_directive (char *directive, char *value, int pass) { | |
349 | int rn_error; | |
350 | ||
351 | if (!strcmp(directive, "org")) { | |
352 | start_point = readnum (value, &rn_error); | |
353 | if (rn_error) | |
354 | error (ERR_NONFATAL, "argument to ORG should be numeric"); | |
355 | return 1; | |
356 | } else | |
357 | return 0; | |
358 | } | |
359 | ||
360 | static void bin_filename (char *inname, char *outname, efunc error) { | |
361 | standard_extension (inname, outname, "", error); | |
362 | } | |
363 | ||
364 | static char *bin_stdmac[] = { | |
365 | "%define __SECT__ [section .text]", | |
366 | "%imacro org 1+.nolist", | |
367 | "[org %1]", | |
368 | "%endmacro", | |
369 | NULL | |
370 | }; | |
371 | ||
372 | struct ofmt of_bin = { | |
373 | "flat-form binary files (e.g. DOS .COM, .SYS)", | |
374 | "bin", | |
375 | bin_stdmac, | |
376 | bin_init, | |
377 | bin_out, | |
378 | bin_deflabel, | |
379 | bin_secname, | |
380 | bin_segbase, | |
381 | bin_directive, | |
382 | bin_filename, | |
383 | bin_cleanup | |
384 | }; | |
385 | ||
386 | #endif /* OF_BIN */ |