1 | /* ----------------------------------------------------------------------- * |
2 | * |
3 | * Copyright 1996-2017 The NASM Authors - All Rights Reserved |
4 | * See the file AUTHORS included with the NASM distribution for |
5 | * the specific copyright holders. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following |
9 | * conditions are met: |
10 | * |
11 | * * Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. |
13 | * * Redistributions in binary form must reproduce the above |
14 | * copyright notice, this list of conditions and the following |
15 | * disclaimer in the documentation and/or other materials provided |
16 | * with the distribution. |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
19 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
20 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
22 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
25 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
29 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
30 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | * |
32 | * ----------------------------------------------------------------------- */ |
33 | |
34 | /* |
35 | * outbin.c output routines for the Netwide Assembler to produce |
36 | * flat-form binary files |
37 | */ |
38 | |
39 | /* This is the extended version of NASM's original binary output |
40 | * format. It is backward compatible with the original BIN format, |
41 | * and contains support for multiple sections and advanced section |
42 | * ordering. |
43 | * |
44 | * Feature summary: |
45 | * |
46 | * - Users can create an arbitrary number of sections; they are not |
47 | * limited to just ".text", ".data", and ".bss". |
48 | * |
49 | * - Sections can be either progbits or nobits type. |
50 | * |
51 | * - You can specify that they be aligned at a certian boundary |
52 | * following the previous section ("align="), or positioned at an |
53 | * arbitrary byte-granular location ("start="). |
54 | * |
55 | * - You can specify a "virtual" start address for a section, which |
56 | * will be used for the calculation for all address references |
57 | * with respect to that section ("vstart="). |
58 | * |
59 | * - The ORG directive, as well as the section/segment directive |
60 | * arguments ("align=", "start=", "vstart="), can take a critical |
61 | * expression as their value. For example: "align=(1 << 12)". |
62 | * |
63 | * - You can generate map files using the 'map' directive. |
64 | * |
65 | */ |
66 | |
67 | /* Uncomment the following define if you want sections to adapt |
68 | * their progbits/nobits state depending on what type of |
69 | * instructions are issued, rather than defaulting to progbits. |
70 | * Note that this behavior violates the specification. |
71 | |
72 | #define ABIN_SMART_ADAPT |
73 | |
74 | */ |
75 | |
76 | #include "compiler.h" |
77 | |
78 | #include <stdio.h> |
79 | #include <stdlib.h> |
80 | #include <string.h> |
81 | #include <ctype.h> |
82 | |
83 | #include "nasm.h" |
84 | #include "nasmlib.h" |
85 | #include "error.h" |
86 | #include "saa.h" |
87 | #include "stdscan.h" |
88 | #include "labels.h" |
89 | #include "eval.h" |
90 | #include "outform.h" |
91 | #include "outlib.h" |
92 | |
93 | #ifdef OF_BIN |
94 | |
95 | static FILE *rf = NULL; |
96 | static void (*do_output)(void); |
97 | |
98 | /* Section flags keep track of which attributes the user has defined. */ |
99 | #define START_DEFINED 0x001 |
100 | #define ALIGN_DEFINED 0x002 |
101 | #define FOLLOWS_DEFINED 0x004 |
102 | #define VSTART_DEFINED 0x008 |
103 | #define VALIGN_DEFINED 0x010 |
104 | #define VFOLLOWS_DEFINED 0x020 |
105 | #define TYPE_DEFINED 0x040 |
106 | #define TYPE_PROGBITS 0x080 |
107 | #define TYPE_NOBITS 0x100 |
108 | |
109 | /* This struct is used to keep track of symbols for map-file generation. */ |
110 | static struct bin_label { |
111 | char *name; |
112 | struct bin_label *next; |
113 | } *no_seg_labels, **nsl_tail; |
114 | |
115 | static struct Section { |
116 | char *name; |
117 | struct SAA *contents; |
118 | int64_t length; /* section length in bytes */ |
119 | |
120 | /* Section attributes */ |
121 | int flags; /* see flag definitions above */ |
122 | uint64_t align; /* section alignment */ |
123 | uint64_t valign; /* notional section alignment */ |
124 | uint64_t start; /* section start address */ |
125 | uint64_t vstart; /* section virtual start address */ |
126 | char *follows; /* the section that this one will follow */ |
127 | char *vfollows; /* the section that this one will notionally follow */ |
128 | int32_t start_index; /* NASM section id for non-relocated version */ |
129 | int32_t vstart_index; /* the NASM section id */ |
130 | |
131 | struct bin_label *labels; /* linked-list of label handles for map output. */ |
132 | struct bin_label **labels_end; /* Holds address of end of labels list. */ |
133 | struct Section *prev; /* Points to previous section (implicit follows). */ |
134 | struct Section *next; /* This links sections with a defined start address. */ |
135 | |
136 | /* The extended bin format allows for sections to have a "virtual" |
137 | * start address. This is accomplished by creating two sections: |
138 | * one beginning at the Load Memory Address and the other beginning |
139 | * at the Virtual Memory Address. The LMA section is only used to |
140 | * define the section.<section_name>.start label, but there isn't |
141 | * any other good way for us to handle that label. |
142 | */ |
143 | |
144 | } *sections, *last_section; |
145 | |
146 | static struct Reloc { |
147 | struct Reloc *next; |
148 | int32_t posn; |
149 | int32_t bytes; |
150 | int32_t secref; |
151 | int32_t secrel; |
152 | struct Section *target; |
153 | } *relocs, **reloctail; |
154 | |
155 | static uint64_t origin; |
156 | static int origin_defined; |
157 | |
158 | /* Stuff we need for map-file generation. */ |
159 | #define MAP_ORIGIN 1 |
160 | #define MAP_SUMMARY 2 |
161 | #define MAP_SECTIONS 4 |
162 | #define MAP_SYMBOLS 8 |
163 | static int map_control = 0; |
164 | |
165 | extern macros_t bin_stdmac[]; |
166 | |
167 | static void add_reloc(struct Section *s, int32_t bytes, int32_t secref, |
168 | int32_t secrel) |
169 | { |
170 | struct Reloc *r; |
171 | |
172 | r = *reloctail = nasm_malloc(sizeof(struct Reloc)); |
173 | reloctail = &r->next; |
174 | r->next = NULL; |
175 | r->posn = s->length; |
176 | r->bytes = bytes; |
177 | r->secref = secref; |
178 | r->secrel = secrel; |
179 | r->target = s; |
180 | } |
181 | |
182 | static struct Section *find_section_by_name(const char *name) |
183 | { |
184 | struct Section *s; |
185 | |
186 | list_for_each(s, sections) |
187 | if (!strcmp(s->name, name)) |
188 | break; |
189 | return s; |
190 | } |
191 | |
192 | static struct Section *find_section_by_index(int32_t index) |
193 | { |
194 | struct Section *s; |
195 | |
196 | list_for_each(s, sections) |
197 | if ((index == s->vstart_index) || (index == s->start_index)) |
198 | break; |
199 | return s; |
200 | } |
201 | |
202 | static struct Section *create_section(char *name) |
203 | { |
204 | struct Section *s = nasm_zalloc(sizeof(*s)); |
205 | |
206 | s->prev = last_section; |
207 | s->name = nasm_strdup(name); |
208 | s->labels_end = &(s->labels); |
209 | s->contents = saa_init(1L); |
210 | |
211 | /* Register our sections with NASM. */ |
212 | s->vstart_index = seg_alloc(); |
213 | s->start_index = seg_alloc(); |
214 | |
215 | /* FIXME: Append to a tail, we need some helper */ |
216 | last_section->next = s; |
217 | last_section = s; |
218 | |
219 | return last_section; |
220 | } |
221 | |
222 | static void bin_cleanup(void) |
223 | { |
224 | struct Section *g, **gp; |
225 | struct Section *gs = NULL, **gsp; |
226 | struct Section *s, **sp; |
227 | struct Section *nobits = NULL, **nt; |
228 | struct Section *last_progbits; |
229 | struct bin_label *l; |
230 | struct Reloc *r; |
231 | uint64_t pend; |
232 | int h; |
233 | |
234 | #ifdef DEBUG |
235 | nasm_error(ERR_DEBUG, |
236 | "bin_cleanup: Sections were initially referenced in this order:\n" ); |
237 | for (h = 0, s = sections; s; h++, s = s->next) |
238 | fprintf(stdout, "%i. %s\n" , h, s->name); |
239 | #endif |
240 | |
241 | /* Assembly has completed, so now we need to generate the output file. |
242 | * Step 1: Separate progbits and nobits sections into separate lists. |
243 | * Step 2: Sort the progbits sections into their output order. |
244 | * Step 3: Compute start addresses for all progbits sections. |
245 | * Step 4: Compute vstart addresses for all sections. |
246 | * Step 5: Apply relocations. |
247 | * Step 6: Write the sections' data to the output file. |
248 | * Step 7: Generate the map file. |
249 | * Step 8: Release all allocated memory. |
250 | */ |
251 | |
252 | /* To do: Smart section-type adaptation could leave some empty sections |
253 | * without a defined type (progbits/nobits). Won't fix now since this |
254 | * feature will be disabled. */ |
255 | |
256 | /* Step 1: Split progbits and nobits sections into separate lists. */ |
257 | |
258 | nt = &nobits; |
259 | /* Move nobits sections into a separate list. Also pre-process nobits |
260 | * sections' attributes. */ |
261 | for (sp = §ions->next, s = sections->next; s; s = *sp) { /* Skip progbits sections. */ |
262 | if (s->flags & TYPE_PROGBITS) { |
263 | sp = &s->next; |
264 | continue; |
265 | } |
266 | /* Do some special pre-processing on nobits sections' attributes. */ |
267 | if (s->flags & (START_DEFINED | ALIGN_DEFINED | FOLLOWS_DEFINED)) { /* Check for a mixture of real and virtual section attributes. */ |
268 | if (s->flags & (VSTART_DEFINED | VALIGN_DEFINED | |
269 | VFOLLOWS_DEFINED)) |
270 | nasm_fatal(ERR_NOFILE, |
271 | "cannot mix real and virtual attributes" |
272 | " in nobits section (%s)" , s->name); |
273 | /* Real and virtual attributes mean the same thing for nobits sections. */ |
274 | if (s->flags & START_DEFINED) { |
275 | s->vstart = s->start; |
276 | s->flags |= VSTART_DEFINED; |
277 | } |
278 | if (s->flags & ALIGN_DEFINED) { |
279 | s->valign = s->align; |
280 | s->flags |= VALIGN_DEFINED; |
281 | } |
282 | if (s->flags & FOLLOWS_DEFINED) { |
283 | s->vfollows = s->follows; |
284 | s->flags |= VFOLLOWS_DEFINED; |
285 | s->flags &= ~FOLLOWS_DEFINED; |
286 | } |
287 | } |
288 | /* Every section must have a start address. */ |
289 | if (s->flags & VSTART_DEFINED) { |
290 | s->start = s->vstart; |
291 | s->flags |= START_DEFINED; |
292 | } |
293 | /* Move the section into the nobits list. */ |
294 | *sp = s->next; |
295 | s->next = NULL; |
296 | *nt = s; |
297 | nt = &s->next; |
298 | } |
299 | |
300 | /* Step 2: Sort the progbits sections into their output order. */ |
301 | |
302 | /* In Step 2 we move around sections in groups. A group |
303 | * begins with a section (group leader) that has a user- |
304 | * defined start address or follows section. The remainder |
305 | * of the group is made up of the sections that implicitly |
306 | * follow the group leader (i.e., they were defined after |
307 | * the group leader and were not given an explicit start |
308 | * address or follows section by the user). */ |
309 | |
310 | /* For anyone attempting to read this code: |
311 | * g (group) points to a group of sections, the first one of which has |
312 | * a user-defined start address or follows section. |
313 | * gp (g previous) holds the location of the pointer to g. |
314 | * gs (g scan) is a temp variable that we use to scan to the end of the group. |
315 | * gsp (gs previous) holds the location of the pointer to gs. |
316 | * nt (nobits tail) points to the nobits section-list tail. |
317 | */ |
318 | |
319 | /* Link all 'follows' groups to their proper position. To do |
320 | * this we need to know three things: the start of the group |
321 | * to relocate (g), the section it is following (s), and the |
322 | * end of the group we're relocating (gs). */ |
323 | for (gp = §ions, g = sections; g; g = gs) { /* Find the next follows group that is out of place (g). */ |
324 | if (!(g->flags & FOLLOWS_DEFINED)) { |
325 | while (g->next) { |
326 | if ((g->next->flags & FOLLOWS_DEFINED) && |
327 | strcmp(g->name, g->next->follows)) |
328 | break; |
329 | g = g->next; |
330 | } |
331 | if (!g->next) |
332 | break; |
333 | gp = &g->next; |
334 | g = g->next; |
335 | } |
336 | /* Find the section that this group follows (s). */ |
337 | for (sp = §ions, s = sections; |
338 | s && strcmp(s->name, g->follows); |
339 | sp = &s->next, s = s->next) ; |
340 | if (!s) |
341 | nasm_fatal(ERR_NOFILE, "section %s follows an invalid or" |
342 | " unknown section (%s)" , g->name, g->follows); |
343 | if (s->next && (s->next->flags & FOLLOWS_DEFINED) && |
344 | !strcmp(s->name, s->next->follows)) |
345 | nasm_fatal(ERR_NOFILE, "sections %s and %s can't both follow" |
346 | " section %s" , g->name, s->next->name, s->name); |
347 | /* Find the end of the current follows group (gs). */ |
348 | for (gsp = &g->next, gs = g->next; |
349 | gs && (gs != s) && !(gs->flags & START_DEFINED); |
350 | gsp = &gs->next, gs = gs->next) { |
351 | if (gs->next && (gs->next->flags & FOLLOWS_DEFINED) && |
352 | strcmp(gs->name, gs->next->follows)) { |
353 | gsp = &gs->next; |
354 | gs = gs->next; |
355 | break; |
356 | } |
357 | } |
358 | /* Re-link the group after its follows section. */ |
359 | *gsp = s->next; |
360 | s->next = g; |
361 | *gp = gs; |
362 | } |
363 | |
364 | /* Link all 'start' groups to their proper position. Once |
365 | * again we need to know g, s, and gs (see above). The main |
366 | * difference is we already know g since we sort by moving |
367 | * groups from the 'unsorted' list into a 'sorted' list (g |
368 | * will always be the first section in the unsorted list). */ |
369 | for (g = sections, sections = NULL; g; g = gs) { /* Find the section that we will insert this group before (s). */ |
370 | for (sp = §ions, s = sections; s; sp = &s->next, s = s->next) |
371 | if ((s->flags & START_DEFINED) && (g->start < s->start)) |
372 | break; |
373 | /* Find the end of the group (gs). */ |
374 | for (gs = g->next, gsp = &g->next; |
375 | gs && !(gs->flags & START_DEFINED); |
376 | gsp = &gs->next, gs = gs->next) ; |
377 | /* Re-link the group before the target section. */ |
378 | *sp = g; |
379 | *gsp = s; |
380 | } |
381 | |
382 | /* Step 3: Compute start addresses for all progbits sections. */ |
383 | |
384 | /* Make sure we have an origin and a start address for the first section. */ |
385 | if (origin_defined) { |
386 | if (sections->flags & START_DEFINED) { |
387 | /* Make sure this section doesn't begin before the origin. */ |
388 | if (sections->start < origin) |
389 | nasm_fatal(ERR_NOFILE, "section %s begins" |
390 | " before program origin" , sections->name); |
391 | } else if (sections->flags & ALIGN_DEFINED) { |
392 | sections->start = ALIGN(origin, sections->align); |
393 | } else { |
394 | sections->start = origin; |
395 | } |
396 | } else { |
397 | if (!(sections->flags & START_DEFINED)) |
398 | sections->start = 0; |
399 | origin = sections->start; |
400 | } |
401 | sections->flags |= START_DEFINED; |
402 | |
403 | /* Make sure each section has an explicit start address. If it |
404 | * doesn't, then compute one based its alignment and the end of |
405 | * the previous section. */ |
406 | for (pend = sections->start, g = s = sections; g; g = g->next) { /* Find the next section that could cause an overlap situation |
407 | * (has a defined start address, and is not zero length). */ |
408 | if (g == s) |
409 | for (s = g->next; |
410 | s && ((s->length == 0) || !(s->flags & START_DEFINED)); |
411 | s = s->next) ; |
412 | /* Compute the start address of this section, if necessary. */ |
413 | if (!(g->flags & START_DEFINED)) { /* Default to an alignment of 4 if unspecified. */ |
414 | if (!(g->flags & ALIGN_DEFINED)) { |
415 | g->align = 4; |
416 | g->flags |= ALIGN_DEFINED; |
417 | } |
418 | /* Set the section start address. */ |
419 | g->start = ALIGN(pend, g->align); |
420 | g->flags |= START_DEFINED; |
421 | } |
422 | /* Ugly special case for progbits sections' virtual attributes: |
423 | * If there is a defined valign, but no vstart and no vfollows, then |
424 | * we valign after the previous progbits section. This case doesn't |
425 | * really make much sense for progbits sections with a defined start |
426 | * address, but it is possible and we must do *something*. |
427 | * Not-so-ugly special case: |
428 | * If a progbits section has no virtual attributes, we set the |
429 | * vstart equal to the start address. */ |
430 | if (!(g->flags & (VSTART_DEFINED | VFOLLOWS_DEFINED))) { |
431 | if (g->flags & VALIGN_DEFINED) |
432 | g->vstart = ALIGN(pend, g->valign); |
433 | else |
434 | g->vstart = g->start; |
435 | g->flags |= VSTART_DEFINED; |
436 | } |
437 | /* Ignore zero-length sections. */ |
438 | if (g->start < pend) |
439 | continue; |
440 | /* Compute the span of this section. */ |
441 | pend = g->start + g->length; |
442 | /* Check for section overlap. */ |
443 | if (s) { |
444 | if (s->start < origin) |
445 | nasm_fatal(ERR_NOFILE, "section %s beings before program origin" , |
446 | s->name); |
447 | if (g->start > s->start) |
448 | nasm_fatal(ERR_NOFILE, "sections %s ~ %s and %s overlap!" , |
449 | gs->name, g->name, s->name); |
450 | if (pend > s->start) |
451 | nasm_fatal(ERR_NOFILE, "sections %s and %s overlap!" , |
452 | g->name, s->name); |
453 | } |
454 | /* Remember this section as the latest >0 length section. */ |
455 | gs = g; |
456 | } |
457 | |
458 | /* Step 4: Compute vstart addresses for all sections. */ |
459 | |
460 | /* Attach the nobits sections to the end of the progbits sections. */ |
461 | for (s = sections; s->next; s = s->next) ; |
462 | s->next = nobits; |
463 | last_progbits = s; |
464 | /* |
465 | * Scan for sections that don't have a vstart address. If we find |
466 | * one we'll attempt to compute its vstart. If we can't compute |
467 | * the vstart, we leave it alone and come back to it in a |
468 | * subsequent scan. We continue scanning and re-scanning until |
469 | * we've gone one full cycle without computing any vstarts. |
470 | */ |
471 | do { /* Do one full scan of the sections list. */ |
472 | for (h = 0, g = sections; g; g = g->next) { |
473 | if (g->flags & VSTART_DEFINED) |
474 | continue; |
475 | /* Find the section that this one virtually follows. */ |
476 | if (g->flags & VFOLLOWS_DEFINED) { |
477 | for (s = sections; s && strcmp(g->vfollows, s->name); |
478 | s = s->next) ; |
479 | if (!s) |
480 | nasm_fatal(ERR_NOFILE, |
481 | "section %s vfollows unknown section (%s)" , |
482 | g->name, g->vfollows); |
483 | } else if (g->prev != NULL) |
484 | for (s = sections; s && (s != g->prev); s = s->next) ; |
485 | /* The .bss section is the only one with prev = NULL. |
486 | In this case we implicitly follow the last progbits |
487 | section. */ |
488 | else |
489 | s = last_progbits; |
490 | |
491 | /* If the section we're following has a vstart, we can proceed. */ |
492 | if (s->flags & VSTART_DEFINED) { /* Default to virtual alignment of four. */ |
493 | if (!(g->flags & VALIGN_DEFINED)) { |
494 | g->valign = 4; |
495 | g->flags |= VALIGN_DEFINED; |
496 | } |
497 | /* Compute the vstart address. */ |
498 | g->vstart = ALIGN(s->vstart + s->length, g->valign); |
499 | g->flags |= VSTART_DEFINED; |
500 | h++; |
501 | /* Start and vstart mean the same thing for nobits sections. */ |
502 | if (g->flags & TYPE_NOBITS) |
503 | g->start = g->vstart; |
504 | } |
505 | } |
506 | } while (h); |
507 | |
508 | /* Now check for any circular vfollows references, which will manifest |
509 | * themselves as sections without a defined vstart. */ |
510 | for (h = 0, s = sections; s; s = s->next) { |
511 | if (!(s->flags & VSTART_DEFINED)) { /* Non-fatal errors after assembly has completed are generally a |
512 | * no-no, but we'll throw a fatal one eventually so it's ok. */ |
513 | nasm_error(ERR_NONFATAL, "cannot compute vstart for section %s" , |
514 | s->name); |
515 | h++; |
516 | } |
517 | } |
518 | if (h) |
519 | nasm_fatal(ERR_NOFILE, "circular vfollows path detected" ); |
520 | |
521 | #ifdef DEBUG |
522 | nasm_error(ERR_DEBUG, |
523 | "bin_cleanup: Confirm final section order for output file:\n" ); |
524 | for (h = 0, s = sections; s && (s->flags & TYPE_PROGBITS); |
525 | h++, s = s->next) |
526 | fprintf(stdout, "%i. %s\n" , h, s->name); |
527 | #endif |
528 | |
529 | /* Step 5: Apply relocations. */ |
530 | |
531 | /* Prepare the sections for relocating. */ |
532 | list_for_each(s, sections) |
533 | saa_rewind(s->contents); |
534 | /* Apply relocations. */ |
535 | list_for_each(r, relocs) { |
536 | uint8_t *p, mydata[8]; |
537 | int64_t l; |
538 | int b; |
539 | |
540 | nasm_assert(r->bytes <= 8); |
541 | |
542 | memset(mydata, 0, sizeof(mydata)); |
543 | |
544 | saa_fread(r->target->contents, r->posn, mydata, r->bytes); |
545 | p = mydata; |
546 | l = 0; |
547 | for (b = r->bytes - 1; b >= 0; b--) |
548 | l = (l << 8) + mydata[b]; |
549 | |
550 | s = find_section_by_index(r->secref); |
551 | if (s) { |
552 | if (r->secref == s->start_index) |
553 | l += s->start; |
554 | else |
555 | l += s->vstart; |
556 | } |
557 | s = find_section_by_index(r->secrel); |
558 | if (s) { |
559 | if (r->secrel == s->start_index) |
560 | l -= s->start; |
561 | else |
562 | l -= s->vstart; |
563 | } |
564 | |
565 | WRITEADDR(p, l, r->bytes); |
566 | saa_fwrite(r->target->contents, r->posn, mydata, r->bytes); |
567 | } |
568 | |
569 | /* Step 6: Write the section data to the output file. */ |
570 | do_output(); |
571 | |
572 | /* Step 7: Generate the map file. */ |
573 | |
574 | if (map_control) { |
575 | static const char not_defined[] = "not defined" ; |
576 | |
577 | /* Display input and output file names. */ |
578 | fprintf(rf, "\n- NASM Map file " ); |
579 | for (h = 63; h; h--) |
580 | fputc('-', rf); |
581 | fprintf(rf, "\n\nSource file: %s\nOutput file: %s\n\n" , |
582 | inname, outname); |
583 | |
584 | if (map_control & MAP_ORIGIN) { /* Display program origin. */ |
585 | fprintf(rf, "-- Program origin " ); |
586 | for (h = 61; h; h--) |
587 | fputc('-', rf); |
588 | fprintf(rf, "\n\n%08" PRIX64"\n\n" , origin); |
589 | } |
590 | /* Display sections summary. */ |
591 | if (map_control & MAP_SUMMARY) { |
592 | fprintf(rf, "-- Sections (summary) " ); |
593 | for (h = 57; h; h--) |
594 | fputc('-', rf); |
595 | fprintf(rf, "\n\nVstart Start Stop " |
596 | "Length Class Name\n" ); |
597 | list_for_each(s, sections) { |
598 | fprintf(rf, "%16" PRIX64" %16" PRIX64" %16" PRIX64" %08" PRIX64" " , |
599 | s->vstart, s->start, s->start + s->length, |
600 | s->length); |
601 | if (s->flags & TYPE_PROGBITS) |
602 | fprintf(rf, "progbits " ); |
603 | else |
604 | fprintf(rf, "nobits " ); |
605 | fprintf(rf, "%s\n" , s->name); |
606 | } |
607 | fprintf(rf, "\n" ); |
608 | } |
609 | /* Display detailed section information. */ |
610 | if (map_control & MAP_SECTIONS) { |
611 | fprintf(rf, "-- Sections (detailed) " ); |
612 | for (h = 56; h; h--) |
613 | fputc('-', rf); |
614 | fprintf(rf, "\n\n" ); |
615 | list_for_each(s, sections) { |
616 | fprintf(rf, "---- Section %s " , s->name); |
617 | for (h = 65 - strlen(s->name); h; h--) |
618 | fputc('-', rf); |
619 | fprintf(rf, "\n\nclass: " ); |
620 | if (s->flags & TYPE_PROGBITS) |
621 | fprintf(rf, "progbits" ); |
622 | else |
623 | fprintf(rf, "nobits" ); |
624 | fprintf(rf, "\nlength: %16" PRIX64"\nstart: %16" PRIX64"" |
625 | "\nalign: " , s->length, s->start); |
626 | if (s->flags & ALIGN_DEFINED) |
627 | fprintf(rf, "%16" PRIX64"" , s->align); |
628 | else |
629 | fputs(not_defined, rf); |
630 | fprintf(rf, "\nfollows: " ); |
631 | if (s->flags & FOLLOWS_DEFINED) |
632 | fprintf(rf, "%s" , s->follows); |
633 | else |
634 | fputs(not_defined, rf); |
635 | fprintf(rf, "\nvstart: %16" PRIX64"\nvalign: " , s->vstart); |
636 | if (s->flags & VALIGN_DEFINED) |
637 | fprintf(rf, "%16" PRIX64"" , s->valign); |
638 | else |
639 | fputs(not_defined, rf); |
640 | fprintf(rf, "\nvfollows: " ); |
641 | if (s->flags & VFOLLOWS_DEFINED) |
642 | fprintf(rf, "%s" , s->vfollows); |
643 | else |
644 | fputs(not_defined, rf); |
645 | fprintf(rf, "\n\n" ); |
646 | } |
647 | } |
648 | /* Display symbols information. */ |
649 | if (map_control & MAP_SYMBOLS) { |
650 | int32_t segment; |
651 | int64_t offset; |
652 | bool found_label; |
653 | |
654 | fprintf(rf, "-- Symbols " ); |
655 | for (h = 68; h; h--) |
656 | fputc('-', rf); |
657 | fprintf(rf, "\n\n" ); |
658 | if (no_seg_labels) { |
659 | fprintf(rf, "---- No Section " ); |
660 | for (h = 63; h; h--) |
661 | fputc('-', rf); |
662 | fprintf(rf, "\n\nValue Name\n" ); |
663 | list_for_each(l, no_seg_labels) { |
664 | found_label = lookup_label(l->name, &segment, &offset); |
665 | nasm_assert(found_label); |
666 | fprintf(rf, "%08" PRIX64" %s\n" , offset, l->name); |
667 | } |
668 | fprintf(rf, "\n\n" ); |
669 | } |
670 | list_for_each(s, sections) { |
671 | if (s->labels) { |
672 | fprintf(rf, "---- Section %s " , s->name); |
673 | for (h = 65 - strlen(s->name); h; h--) |
674 | fputc('-', rf); |
675 | fprintf(rf, "\n\nReal Virtual Name\n" ); |
676 | list_for_each(l, s->labels) { |
677 | found_label = lookup_label(l->name, &segment, &offset); |
678 | nasm_assert(found_label); |
679 | fprintf(rf, "%16" PRIX64" %16" PRIX64" %s\n" , |
680 | s->start + offset, s->vstart + offset, |
681 | l->name); |
682 | } |
683 | fprintf(rf, "\n" ); |
684 | } |
685 | } |
686 | } |
687 | } |
688 | |
689 | /* Close the report file. */ |
690 | if (map_control && (rf != stdout) && (rf != stderr)) |
691 | fclose(rf); |
692 | |
693 | /* Step 8: Release all allocated memory. */ |
694 | |
695 | /* Free sections, label pointer structs, etc.. */ |
696 | while (sections) { |
697 | s = sections; |
698 | sections = s->next; |
699 | saa_free(s->contents); |
700 | nasm_free(s->name); |
701 | if (s->flags & FOLLOWS_DEFINED) |
702 | nasm_free(s->follows); |
703 | if (s->flags & VFOLLOWS_DEFINED) |
704 | nasm_free(s->vfollows); |
705 | while (s->labels) { |
706 | l = s->labels; |
707 | s->labels = l->next; |
708 | nasm_free(l); |
709 | } |
710 | nasm_free(s); |
711 | } |
712 | |
713 | /* Free no-section labels. */ |
714 | while (no_seg_labels) { |
715 | l = no_seg_labels; |
716 | no_seg_labels = l->next; |
717 | nasm_free(l); |
718 | } |
719 | |
720 | /* Free relocation structures. */ |
721 | while (relocs) { |
722 | r = relocs->next; |
723 | nasm_free(relocs); |
724 | relocs = r; |
725 | } |
726 | } |
727 | |
728 | static void bin_out(int32_t segto, const void *data, |
729 | enum out_type type, uint64_t size, |
730 | int32_t segment, int32_t wrt) |
731 | { |
732 | uint8_t *p, mydata[8]; |
733 | struct Section *s; |
734 | |
735 | if (wrt != NO_SEG) { |
736 | wrt = NO_SEG; /* continue to do _something_ */ |
737 | nasm_error(ERR_NONFATAL, "WRT not supported by binary output format" ); |
738 | } |
739 | |
740 | /* Handle absolute-assembly (structure definitions). */ |
741 | if (segto == NO_SEG) { |
742 | if (type != OUT_RESERVE) |
743 | nasm_error(ERR_NONFATAL, "attempt to assemble code in" |
744 | " [ABSOLUTE] space" ); |
745 | return; |
746 | } |
747 | |
748 | /* Find the segment we are targeting. */ |
749 | s = find_section_by_index(segto); |
750 | if (!s) |
751 | nasm_panic(0, "code directed to nonexistent segment?" ); |
752 | |
753 | /* "Smart" section-type adaptation code. */ |
754 | if (!(s->flags & TYPE_DEFINED)) { |
755 | if (type == OUT_RESERVE) |
756 | s->flags |= TYPE_DEFINED | TYPE_NOBITS; |
757 | else |
758 | s->flags |= TYPE_DEFINED | TYPE_PROGBITS; |
759 | } |
760 | |
761 | if ((s->flags & TYPE_NOBITS) && (type != OUT_RESERVE)) |
762 | nasm_error(ERR_WARNING, "attempt to initialize memory in a" |
763 | " nobits section: ignored" ); |
764 | |
765 | switch (type) { |
766 | case OUT_ADDRESS: |
767 | { |
768 | int asize = abs((int)size); |
769 | |
770 | if (segment != NO_SEG && !find_section_by_index(segment)) { |
771 | if (segment % 2) |
772 | nasm_error(ERR_NONFATAL, "binary output format does not support" |
773 | " segment base references" ); |
774 | else |
775 | nasm_error(ERR_NONFATAL, "binary output format does not support" |
776 | " external references" ); |
777 | segment = NO_SEG; |
778 | } |
779 | if (s->flags & TYPE_PROGBITS) { |
780 | if (segment != NO_SEG) |
781 | add_reloc(s, asize, segment, -1L); |
782 | p = mydata; |
783 | WRITEADDR(p, *(int64_t *)data, asize); |
784 | saa_wbytes(s->contents, mydata, asize); |
785 | } |
786 | |
787 | /* |
788 | * Reassign size with sign dropped, we will need it |
789 | * for section length calculation. |
790 | */ |
791 | size = asize; |
792 | break; |
793 | } |
794 | |
795 | case OUT_RAWDATA: |
796 | if (s->flags & TYPE_PROGBITS) |
797 | saa_wbytes(s->contents, data, size); |
798 | break; |
799 | |
800 | case OUT_RESERVE: |
801 | if (s->flags & TYPE_PROGBITS) { |
802 | nasm_error(ERR_WARNING, "uninitialized space declared in" |
803 | " %s section: zeroing" , s->name); |
804 | saa_wbytes(s->contents, NULL, size); |
805 | } |
806 | break; |
807 | |
808 | case OUT_REL1ADR: |
809 | case OUT_REL2ADR: |
810 | case OUT_REL4ADR: |
811 | case OUT_REL8ADR: |
812 | { |
813 | int64_t addr = *(int64_t *)data - size; |
814 | size = realsize(type, size); |
815 | if (segment != NO_SEG && !find_section_by_index(segment)) { |
816 | if (segment % 2) |
817 | nasm_error(ERR_NONFATAL, "binary output format does not support" |
818 | " segment base references" ); |
819 | else |
820 | nasm_error(ERR_NONFATAL, "binary output format does not support" |
821 | " external references" ); |
822 | segment = NO_SEG; |
823 | } |
824 | if (s->flags & TYPE_PROGBITS) { |
825 | add_reloc(s, size, segment, segto); |
826 | p = mydata; |
827 | WRITEADDR(p, addr - s->length, size); |
828 | saa_wbytes(s->contents, mydata, size); |
829 | } |
830 | break; |
831 | } |
832 | |
833 | default: |
834 | nasm_error(ERR_NONFATAL, "unsupported relocation type %d\n" , type); |
835 | break; |
836 | } |
837 | |
838 | s->length += size; |
839 | } |
840 | |
841 | static void bin_deflabel(char *name, int32_t segment, int64_t offset, |
842 | int is_global, char *special) |
843 | { |
844 | (void)segment; /* Don't warn that this parameter is unused */ |
845 | (void)offset; /* Don't warn that this parameter is unused */ |
846 | |
847 | if (special) |
848 | nasm_error(ERR_NONFATAL, "binary format does not support any" |
849 | " special symbol types" ); |
850 | else if (name[0] == '.' && name[1] == '.' && name[2] != '@') |
851 | nasm_error(ERR_NONFATAL, "unrecognised special symbol `%s'" , name); |
852 | else if (is_global == 2) |
853 | nasm_error(ERR_NONFATAL, "binary output format does not support common" |
854 | " variables" ); |
855 | else { |
856 | struct Section *s; |
857 | struct bin_label ***ltp; |
858 | |
859 | /* Remember label definition so we can look it up later when |
860 | * creating the map file. */ |
861 | s = find_section_by_index(segment); |
862 | if (s) |
863 | ltp = &(s->labels_end); |
864 | else |
865 | ltp = &nsl_tail; |
866 | (**ltp) = nasm_malloc(sizeof(struct bin_label)); |
867 | (**ltp)->name = name; |
868 | (**ltp)->next = NULL; |
869 | *ltp = &((**ltp)->next); |
870 | } |
871 | |
872 | } |
873 | |
874 | /* These constants and the following function are used |
875 | * by bin_secname() to parse attribute assignments. */ |
876 | |
877 | enum { ATTRIB_START, ATTRIB_ALIGN, ATTRIB_FOLLOWS, |
878 | ATTRIB_VSTART, ATTRIB_VALIGN, ATTRIB_VFOLLOWS, |
879 | ATTRIB_NOBITS, ATTRIB_PROGBITS |
880 | }; |
881 | |
882 | static int bin_read_attribute(char **line, int *attribute, |
883 | uint64_t *value) |
884 | { |
885 | expr *e; |
886 | int attrib_name_size; |
887 | struct tokenval tokval; |
888 | char *exp; |
889 | |
890 | /* Skip whitespace. */ |
891 | while (**line && nasm_isspace(**line)) |
892 | (*line)++; |
893 | if (!**line) |
894 | return 0; |
895 | |
896 | /* Figure out what attribute we're reading. */ |
897 | if (!nasm_strnicmp(*line, "align=" , 6)) { |
898 | *attribute = ATTRIB_ALIGN; |
899 | attrib_name_size = 6; |
900 | } else { |
901 | if (!nasm_strnicmp(*line, "start=" , 6)) { |
902 | *attribute = ATTRIB_START; |
903 | attrib_name_size = 6; |
904 | } else if (!nasm_strnicmp(*line, "follows=" , 8)) { |
905 | *attribute = ATTRIB_FOLLOWS; |
906 | *line += 8; |
907 | return 1; |
908 | } else if (!nasm_strnicmp(*line, "vstart=" , 7)) { |
909 | *attribute = ATTRIB_VSTART; |
910 | attrib_name_size = 7; |
911 | } else if (!nasm_strnicmp(*line, "valign=" , 7)) { |
912 | *attribute = ATTRIB_VALIGN; |
913 | attrib_name_size = 7; |
914 | } else if (!nasm_strnicmp(*line, "vfollows=" , 9)) { |
915 | *attribute = ATTRIB_VFOLLOWS; |
916 | *line += 9; |
917 | return 1; |
918 | } else if (!nasm_strnicmp(*line, "nobits" , 6) && |
919 | (nasm_isspace((*line)[6]) || ((*line)[6] == '\0'))) { |
920 | *attribute = ATTRIB_NOBITS; |
921 | *line += 6; |
922 | return 1; |
923 | } else if (!nasm_strnicmp(*line, "progbits" , 8) && |
924 | (nasm_isspace((*line)[8]) || ((*line)[8] == '\0'))) { |
925 | *attribute = ATTRIB_PROGBITS; |
926 | *line += 8; |
927 | return 1; |
928 | } else |
929 | return 0; |
930 | } |
931 | |
932 | /* Find the end of the expression. */ |
933 | if ((*line)[attrib_name_size] != '(') { |
934 | /* Single term (no parenthesis). */ |
935 | exp = *line += attrib_name_size; |
936 | while (**line && !nasm_isspace(**line)) |
937 | (*line)++; |
938 | if (**line) { |
939 | **line = '\0'; |
940 | (*line)++; |
941 | } |
942 | } else { |
943 | char c; |
944 | int pcount = 1; |
945 | |
946 | /* Full expression (delimited by parenthesis) */ |
947 | exp = *line += attrib_name_size + 1; |
948 | while (1) { |
949 | (*line) += strcspn(*line, "()'\"" ); |
950 | if (**line == '(') { |
951 | ++(*line); |
952 | ++pcount; |
953 | } |
954 | if (**line == ')') { |
955 | ++(*line); |
956 | --pcount; |
957 | if (!pcount) |
958 | break; |
959 | } |
960 | if ((**line == '"') || (**line == '\'')) { |
961 | c = **line; |
962 | while (**line) { |
963 | ++(*line); |
964 | if (**line == c) |
965 | break; |
966 | } |
967 | if (!**line) { |
968 | nasm_error(ERR_NONFATAL, |
969 | "invalid syntax in `section' directive" ); |
970 | return -1; |
971 | } |
972 | ++(*line); |
973 | } |
974 | if (!**line) { |
975 | nasm_error(ERR_NONFATAL, "expecting `)'" ); |
976 | return -1; |
977 | } |
978 | } |
979 | *(*line - 1) = '\0'; /* Terminate the expression. */ |
980 | } |
981 | |
982 | /* Check for no value given. */ |
983 | if (!*exp) { |
984 | nasm_error(ERR_WARNING, "No value given to attribute in" |
985 | " `section' directive" ); |
986 | return -1; |
987 | } |
988 | |
989 | /* Read and evaluate the expression. */ |
990 | stdscan_reset(); |
991 | stdscan_set(exp); |
992 | tokval.t_type = TOKEN_INVALID; |
993 | e = evaluate(stdscan, NULL, &tokval, NULL, 1, NULL); |
994 | if (e) { |
995 | if (!is_really_simple(e)) { |
996 | nasm_error(ERR_NONFATAL, "section attribute value must be" |
997 | " a critical expression" ); |
998 | return -1; |
999 | } |
1000 | } else { |
1001 | nasm_error(ERR_NONFATAL, "Invalid attribute value" |
1002 | " specified in `section' directive." ); |
1003 | return -1; |
1004 | } |
1005 | *value = (uint64_t)reloc_value(e); |
1006 | return 1; |
1007 | } |
1008 | |
1009 | static void bin_sectalign(int32_t seg, unsigned int value) |
1010 | { |
1011 | struct Section *s = find_section_by_index(seg); |
1012 | |
1013 | if (!s || !is_power2(value)) |
1014 | return; |
1015 | |
1016 | if (value > s->align) |
1017 | s->align = value; |
1018 | |
1019 | if (!(s->flags & ALIGN_DEFINED)) |
1020 | s->flags |= ALIGN_DEFINED; |
1021 | } |
1022 | |
1023 | static void bin_assign_attributes(struct Section *sec, char *astring) |
1024 | { |
1025 | int attribute, check; |
1026 | uint64_t value; |
1027 | char *p; |
1028 | |
1029 | while (1) { /* Get the next attribute. */ |
1030 | check = bin_read_attribute(&astring, &attribute, &value); |
1031 | /* Skip bad attribute. */ |
1032 | if (check == -1) |
1033 | continue; |
1034 | /* Unknown section attribute, so skip it and warn the user. */ |
1035 | if (!check) { |
1036 | if (!*astring) |
1037 | break; /* End of line. */ |
1038 | else { |
1039 | p = astring; |
1040 | while (*astring && !nasm_isspace(*astring)) |
1041 | astring++; |
1042 | if (*astring) { |
1043 | *astring = '\0'; |
1044 | astring++; |
1045 | } |
1046 | nasm_error(ERR_WARNING, "ignoring unknown section attribute:" |
1047 | " \"%s\"" , p); |
1048 | } |
1049 | continue; |
1050 | } |
1051 | |
1052 | switch (attribute) { /* Handle nobits attribute. */ |
1053 | case ATTRIB_NOBITS: |
1054 | if ((sec->flags & TYPE_DEFINED) |
1055 | && (sec->flags & TYPE_PROGBITS)) |
1056 | nasm_error(ERR_NONFATAL, |
1057 | "attempt to change section type" |
1058 | " from progbits to nobits" ); |
1059 | else |
1060 | sec->flags |= TYPE_DEFINED | TYPE_NOBITS; |
1061 | continue; |
1062 | |
1063 | /* Handle progbits attribute. */ |
1064 | case ATTRIB_PROGBITS: |
1065 | if ((sec->flags & TYPE_DEFINED) && (sec->flags & TYPE_NOBITS)) |
1066 | nasm_error(ERR_NONFATAL, "attempt to change section type" |
1067 | " from nobits to progbits" ); |
1068 | else |
1069 | sec->flags |= TYPE_DEFINED | TYPE_PROGBITS; |
1070 | continue; |
1071 | |
1072 | /* Handle align attribute. */ |
1073 | case ATTRIB_ALIGN: |
1074 | if (!value || ((value - 1) & value)) { |
1075 | nasm_error(ERR_NONFATAL, |
1076 | "argument to `align' is not a power of two" ); |
1077 | } else { |
1078 | /* |
1079 | * Alignment is already satisfied if |
1080 | * the previous align value is greater |
1081 | */ |
1082 | if ((sec->flags & ALIGN_DEFINED) && (value < sec->align)) |
1083 | value = sec->align; |
1084 | |
1085 | /* Don't allow a conflicting align value. */ |
1086 | if ((sec->flags & START_DEFINED) && (sec->start & (value - 1))) { |
1087 | nasm_error(ERR_NONFATAL, |
1088 | "`align' value conflicts with section start address" ); |
1089 | } else { |
1090 | sec->align = value; |
1091 | sec->flags |= ALIGN_DEFINED; |
1092 | } |
1093 | } |
1094 | continue; |
1095 | |
1096 | /* Handle valign attribute. */ |
1097 | case ATTRIB_VALIGN: |
1098 | if (!value || ((value - 1) & value)) |
1099 | nasm_error(ERR_NONFATAL, "argument to `valign' is not a" |
1100 | " power of two" ); |
1101 | else { /* Alignment is already satisfied if the previous |
1102 | * align value is greater. */ |
1103 | if ((sec->flags & VALIGN_DEFINED) && (value < sec->valign)) |
1104 | value = sec->valign; |
1105 | |
1106 | /* Don't allow a conflicting valign value. */ |
1107 | if ((sec->flags & VSTART_DEFINED) |
1108 | && (sec->vstart & (value - 1))) |
1109 | nasm_error(ERR_NONFATAL, |
1110 | "`valign' value conflicts " |
1111 | "with `vstart' address" ); |
1112 | else { |
1113 | sec->valign = value; |
1114 | sec->flags |= VALIGN_DEFINED; |
1115 | } |
1116 | } |
1117 | continue; |
1118 | |
1119 | /* Handle start attribute. */ |
1120 | case ATTRIB_START: |
1121 | if (sec->flags & FOLLOWS_DEFINED) |
1122 | nasm_error(ERR_NONFATAL, "cannot combine `start' and `follows'" |
1123 | " section attributes" ); |
1124 | else if ((sec->flags & START_DEFINED) && (value != sec->start)) |
1125 | nasm_error(ERR_NONFATAL, "section start address redefined" ); |
1126 | else { |
1127 | sec->start = value; |
1128 | sec->flags |= START_DEFINED; |
1129 | if (sec->flags & ALIGN_DEFINED) { |
1130 | if (sec->start & (sec->align - 1)) |
1131 | nasm_error(ERR_NONFATAL, "`start' address conflicts" |
1132 | " with section alignment" ); |
1133 | sec->flags ^= ALIGN_DEFINED; |
1134 | } |
1135 | } |
1136 | continue; |
1137 | |
1138 | /* Handle vstart attribute. */ |
1139 | case ATTRIB_VSTART: |
1140 | if (sec->flags & VFOLLOWS_DEFINED) |
1141 | nasm_error(ERR_NONFATAL, |
1142 | "cannot combine `vstart' and `vfollows'" |
1143 | " section attributes" ); |
1144 | else if ((sec->flags & VSTART_DEFINED) |
1145 | && (value != sec->vstart)) |
1146 | nasm_error(ERR_NONFATAL, |
1147 | "section virtual start address" |
1148 | " (vstart) redefined" ); |
1149 | else { |
1150 | sec->vstart = value; |
1151 | sec->flags |= VSTART_DEFINED; |
1152 | if (sec->flags & VALIGN_DEFINED) { |
1153 | if (sec->vstart & (sec->valign - 1)) |
1154 | nasm_error(ERR_NONFATAL, "`vstart' address conflicts" |
1155 | " with `valign' value" ); |
1156 | sec->flags ^= VALIGN_DEFINED; |
1157 | } |
1158 | } |
1159 | continue; |
1160 | |
1161 | /* Handle follows attribute. */ |
1162 | case ATTRIB_FOLLOWS: |
1163 | p = astring; |
1164 | astring += strcspn(astring, " \t" ); |
1165 | if (astring == p) |
1166 | nasm_error(ERR_NONFATAL, "expecting section name for `follows'" |
1167 | " attribute" ); |
1168 | else { |
1169 | *(astring++) = '\0'; |
1170 | if (sec->flags & START_DEFINED) |
1171 | nasm_error(ERR_NONFATAL, |
1172 | "cannot combine `start' and `follows'" |
1173 | " section attributes" ); |
1174 | sec->follows = nasm_strdup(p); |
1175 | sec->flags |= FOLLOWS_DEFINED; |
1176 | } |
1177 | continue; |
1178 | |
1179 | /* Handle vfollows attribute. */ |
1180 | case ATTRIB_VFOLLOWS: |
1181 | if (sec->flags & VSTART_DEFINED) |
1182 | nasm_error(ERR_NONFATAL, |
1183 | "cannot combine `vstart' and `vfollows'" |
1184 | " section attributes" ); |
1185 | else { |
1186 | p = astring; |
1187 | astring += strcspn(astring, " \t" ); |
1188 | if (astring == p) |
1189 | nasm_error(ERR_NONFATAL, |
1190 | "expecting section name for `vfollows'" |
1191 | " attribute" ); |
1192 | else { |
1193 | *(astring++) = '\0'; |
1194 | sec->vfollows = nasm_strdup(p); |
1195 | sec->flags |= VFOLLOWS_DEFINED; |
1196 | } |
1197 | } |
1198 | continue; |
1199 | } |
1200 | } |
1201 | } |
1202 | |
1203 | static void bin_define_section_labels(void) |
1204 | { |
1205 | static int labels_defined = 0; |
1206 | struct Section *sec; |
1207 | char *label_name; |
1208 | size_t base_len; |
1209 | |
1210 | if (labels_defined) |
1211 | return; |
1212 | list_for_each(sec, sections) { |
1213 | base_len = strlen(sec->name) + 8; |
1214 | label_name = nasm_malloc(base_len + 8); |
1215 | strcpy(label_name, "section." ); |
1216 | strcpy(label_name + 8, sec->name); |
1217 | |
1218 | /* section.<name>.start */ |
1219 | strcpy(label_name + base_len, ".start" ); |
1220 | define_label(label_name, sec->start_index, 0L, false); |
1221 | |
1222 | /* section.<name>.vstart */ |
1223 | strcpy(label_name + base_len, ".vstart" ); |
1224 | define_label(label_name, sec->vstart_index, 0L, false); |
1225 | |
1226 | nasm_free(label_name); |
1227 | } |
1228 | labels_defined = 1; |
1229 | } |
1230 | |
1231 | static int32_t bin_secname(char *name, int pass, int *bits) |
1232 | { |
1233 | char *p; |
1234 | struct Section *sec; |
1235 | |
1236 | /* bin_secname is called with *name = NULL at the start of each |
1237 | * pass. Use this opportunity to establish the default section |
1238 | * (default is BITS-16 ".text" segment). |
1239 | */ |
1240 | if (!name) { /* Reset ORG and section attributes at the start of each pass. */ |
1241 | origin_defined = 0; |
1242 | list_for_each(sec, sections) |
1243 | sec->flags &= ~(START_DEFINED | VSTART_DEFINED | |
1244 | ALIGN_DEFINED | VALIGN_DEFINED); |
1245 | |
1246 | /* Define section start and vstart labels. */ |
1247 | if (pass != 1) |
1248 | bin_define_section_labels(); |
1249 | |
1250 | /* Establish the default (.text) section. */ |
1251 | *bits = 16; |
1252 | sec = find_section_by_name(".text" ); |
1253 | sec->flags |= TYPE_DEFINED | TYPE_PROGBITS; |
1254 | return sec->vstart_index; |
1255 | } |
1256 | |
1257 | /* Attempt to find the requested section. If it does not |
1258 | * exist, create it. */ |
1259 | p = name; |
1260 | while (*p && !nasm_isspace(*p)) |
1261 | p++; |
1262 | if (*p) |
1263 | *p++ = '\0'; |
1264 | sec = find_section_by_name(name); |
1265 | if (!sec) { |
1266 | sec = create_section(name); |
1267 | if (!strcmp(name, ".data" )) |
1268 | sec->flags |= TYPE_DEFINED | TYPE_PROGBITS; |
1269 | else if (!strcmp(name, ".bss" )) { |
1270 | sec->flags |= TYPE_DEFINED | TYPE_NOBITS; |
1271 | sec->prev = NULL; |
1272 | } |
1273 | } |
1274 | |
1275 | /* Handle attribute assignments. */ |
1276 | if (pass != 1) |
1277 | bin_assign_attributes(sec, p); |
1278 | |
1279 | #ifndef ABIN_SMART_ADAPT |
1280 | /* The following line disables smart adaptation of |
1281 | * PROGBITS/NOBITS section types (it forces sections to |
1282 | * default to PROGBITS). */ |
1283 | if ((pass != 1) && !(sec->flags & TYPE_DEFINED)) |
1284 | sec->flags |= TYPE_DEFINED | TYPE_PROGBITS; |
1285 | #endif |
1286 | |
1287 | return sec->vstart_index; |
1288 | } |
1289 | |
1290 | static enum directive_result |
1291 | bin_directive(enum directive directive, char *args, int pass) |
1292 | { |
1293 | switch (directive) { |
1294 | case D_ORG: |
1295 | { |
1296 | struct tokenval tokval; |
1297 | uint64_t value; |
1298 | expr *e; |
1299 | |
1300 | stdscan_reset(); |
1301 | stdscan_set(args); |
1302 | tokval.t_type = TOKEN_INVALID; |
1303 | e = evaluate(stdscan, NULL, &tokval, NULL, 1, NULL); |
1304 | if (e) { |
1305 | if (!is_really_simple(e)) |
1306 | nasm_error(ERR_NONFATAL, "org value must be a critical" |
1307 | " expression" ); |
1308 | else { |
1309 | value = reloc_value(e); |
1310 | /* Check for ORG redefinition. */ |
1311 | if (origin_defined && (value != origin)) |
1312 | nasm_error(ERR_NONFATAL, "program origin redefined" ); |
1313 | else { |
1314 | origin = value; |
1315 | origin_defined = 1; |
1316 | } |
1317 | } |
1318 | } else |
1319 | nasm_error(ERR_NONFATAL, "No or invalid offset specified" |
1320 | " in ORG directive." ); |
1321 | return DIRR_OK; |
1322 | } |
1323 | case D_MAP: |
1324 | { |
1325 | /* The 'map' directive allows the user to generate section |
1326 | * and symbol information to stdout, stderr, or to a file. */ |
1327 | char *p; |
1328 | |
1329 | if (pass != 1) |
1330 | return DIRR_OK; |
1331 | args += strspn(args, " \t" ); |
1332 | while (*args) { |
1333 | p = args; |
1334 | args += strcspn(args, " \t" ); |
1335 | if (*args != '\0') |
1336 | *(args++) = '\0'; |
1337 | if (!nasm_stricmp(p, "all" )) |
1338 | map_control |= |
1339 | MAP_ORIGIN | MAP_SUMMARY | MAP_SECTIONS | MAP_SYMBOLS; |
1340 | else if (!nasm_stricmp(p, "brief" )) |
1341 | map_control |= MAP_ORIGIN | MAP_SUMMARY; |
1342 | else if (!nasm_stricmp(p, "sections" )) |
1343 | map_control |= MAP_ORIGIN | MAP_SUMMARY | MAP_SECTIONS; |
1344 | else if (!nasm_stricmp(p, "segments" )) |
1345 | map_control |= MAP_ORIGIN | MAP_SUMMARY | MAP_SECTIONS; |
1346 | else if (!nasm_stricmp(p, "symbols" )) |
1347 | map_control |= MAP_SYMBOLS; |
1348 | else if (!rf) { |
1349 | if (!nasm_stricmp(p, "stdout" )) |
1350 | rf = stdout; |
1351 | else if (!nasm_stricmp(p, "stderr" )) |
1352 | rf = stderr; |
1353 | else { /* Must be a filename. */ |
1354 | rf = nasm_open_write(p, NF_TEXT); |
1355 | if (!rf) { |
1356 | nasm_error(ERR_WARNING, "unable to open map file `%s'" , |
1357 | p); |
1358 | map_control = 0; |
1359 | return DIRR_OK; |
1360 | } |
1361 | } |
1362 | } else |
1363 | nasm_error(ERR_WARNING, "map file already specified" ); |
1364 | } |
1365 | if (map_control == 0) |
1366 | map_control |= MAP_ORIGIN | MAP_SUMMARY; |
1367 | if (!rf) |
1368 | rf = stdout; |
1369 | return DIRR_OK; |
1370 | } |
1371 | default: |
1372 | return DIRR_UNKNOWN; |
1373 | } |
1374 | } |
1375 | |
1376 | static int32_t bin_segbase(int32_t segment) |
1377 | { |
1378 | return segment; |
1379 | } |
1380 | |
1381 | const struct ofmt of_bin, of_ith, of_srec; |
1382 | static void binfmt_init(void); |
1383 | static void do_output_bin(void); |
1384 | static void do_output_ith(void); |
1385 | static void do_output_srec(void); |
1386 | |
1387 | static void bin_init(void) |
1388 | { |
1389 | do_output = do_output_bin; |
1390 | binfmt_init(); |
1391 | } |
1392 | |
1393 | static void ith_init(void) |
1394 | { |
1395 | do_output = do_output_ith; |
1396 | binfmt_init(); |
1397 | } |
1398 | |
1399 | static void srec_init(void) |
1400 | { |
1401 | do_output = do_output_srec; |
1402 | binfmt_init(); |
1403 | } |
1404 | |
1405 | static void binfmt_init(void) |
1406 | { |
1407 | relocs = NULL; |
1408 | reloctail = &relocs; |
1409 | origin_defined = 0; |
1410 | no_seg_labels = NULL; |
1411 | nsl_tail = &no_seg_labels; |
1412 | |
1413 | /* Create default section (.text). */ |
1414 | sections = last_section = nasm_zalloc(sizeof(struct Section)); |
1415 | last_section->name = nasm_strdup(".text" ); |
1416 | last_section->contents = saa_init(1L); |
1417 | last_section->flags = TYPE_DEFINED | TYPE_PROGBITS; |
1418 | last_section->labels_end = &(last_section->labels); |
1419 | last_section->start_index = seg_alloc(); |
1420 | last_section->vstart_index = seg_alloc(); |
1421 | } |
1422 | |
1423 | /* Generate binary file output */ |
1424 | static void do_output_bin(void) |
1425 | { |
1426 | struct Section *s; |
1427 | uint64_t addr = origin; |
1428 | |
1429 | /* Write the progbits sections to the output file. */ |
1430 | list_for_each(s, sections) { |
1431 | /* Skip non-progbits sections */ |
1432 | if (!(s->flags & TYPE_PROGBITS)) |
1433 | continue; |
1434 | /* Skip zero-length sections */ |
1435 | if (s->length == 0) |
1436 | continue; |
1437 | |
1438 | /* Pad the space between sections. */ |
1439 | nasm_assert(addr <= s->start); |
1440 | fwritezero(s->start - addr, ofile); |
1441 | |
1442 | /* Write the section to the output file. */ |
1443 | saa_fpwrite(s->contents, ofile); |
1444 | |
1445 | /* Keep track of the current file position */ |
1446 | addr = s->start + s->length; |
1447 | } |
1448 | } |
1449 | |
1450 | /* Generate Intel hex file output */ |
1451 | static void write_ith_record(unsigned int len, uint16_t addr, |
1452 | uint8_t type, void *data) |
1453 | { |
1454 | char buf[1+2+4+2+255*2+2+2]; |
1455 | char *p = buf; |
1456 | uint8_t csum, *dptr = data; |
1457 | unsigned int i; |
1458 | |
1459 | nasm_assert(len <= 255); |
1460 | |
1461 | csum = len + addr + (addr >> 8) + type; |
1462 | for (i = 0; i < len; i++) |
1463 | csum += dptr[i]; |
1464 | csum = -csum; |
1465 | |
1466 | p += sprintf(p, ":%02X%04X%02X" , len, addr, type); |
1467 | for (i = 0; i < len; i++) |
1468 | p += sprintf(p, "%02X" , dptr[i]); |
1469 | p += sprintf(p, "%02X\n" , csum); |
1470 | |
1471 | nasm_write(buf, p-buf, ofile); |
1472 | } |
1473 | |
1474 | static void do_output_ith(void) |
1475 | { |
1476 | uint8_t buf[32]; |
1477 | struct Section *s; |
1478 | uint64_t addr, hiaddr, hilba; |
1479 | uint64_t length; |
1480 | unsigned int chunk; |
1481 | |
1482 | /* Write the progbits sections to the output file. */ |
1483 | hilba = 0; |
1484 | list_for_each(s, sections) { |
1485 | /* Skip non-progbits sections */ |
1486 | if (!(s->flags & TYPE_PROGBITS)) |
1487 | continue; |
1488 | /* Skip zero-length sections */ |
1489 | if (s->length == 0) |
1490 | continue; |
1491 | |
1492 | addr = s->start; |
1493 | length = s->length; |
1494 | saa_rewind(s->contents); |
1495 | |
1496 | while (length) { |
1497 | hiaddr = addr >> 16; |
1498 | if (hiaddr != hilba) { |
1499 | buf[0] = hiaddr >> 8; |
1500 | buf[1] = hiaddr; |
1501 | write_ith_record(2, 0, 4, buf); |
1502 | hilba = hiaddr; |
1503 | } |
1504 | |
1505 | chunk = 32 - (addr & 31); |
1506 | if (length < chunk) |
1507 | chunk = length; |
1508 | |
1509 | saa_rnbytes(s->contents, buf, chunk); |
1510 | write_ith_record(chunk, (uint16_t)addr, 0, buf); |
1511 | |
1512 | addr += chunk; |
1513 | length -= chunk; |
1514 | } |
1515 | } |
1516 | |
1517 | /* Write closing record */ |
1518 | write_ith_record(0, 0, 1, NULL); |
1519 | } |
1520 | |
1521 | /* Generate Motorola S-records */ |
1522 | static void write_srecord(unsigned int len, unsigned int alen, |
1523 | uint32_t addr, uint8_t type, void *data) |
1524 | { |
1525 | char buf[2+2+8+255*2+2+2]; |
1526 | char *p = buf; |
1527 | uint8_t csum, *dptr = data; |
1528 | unsigned int i; |
1529 | |
1530 | nasm_assert(len <= 255); |
1531 | |
1532 | switch (alen) { |
1533 | case 2: |
1534 | addr &= 0xffff; |
1535 | break; |
1536 | case 3: |
1537 | addr &= 0xffffff; |
1538 | break; |
1539 | case 4: |
1540 | break; |
1541 | default: |
1542 | nasm_assert(0); |
1543 | break; |
1544 | } |
1545 | |
1546 | csum = (len+alen+1) + addr + (addr >> 8) + (addr >> 16) + (addr >> 24); |
1547 | for (i = 0; i < len; i++) |
1548 | csum += dptr[i]; |
1549 | csum = 0xff-csum; |
1550 | |
1551 | p += sprintf(p, "S%c%02X%0*X" , type, len+alen+1, alen*2, addr); |
1552 | for (i = 0; i < len; i++) |
1553 | p += sprintf(p, "%02X" , dptr[i]); |
1554 | p += sprintf(p, "%02X\n" , csum); |
1555 | |
1556 | nasm_write(buf, p-buf, ofile); |
1557 | } |
1558 | |
1559 | static void do_output_srec(void) |
1560 | { |
1561 | uint8_t buf[32]; |
1562 | struct Section *s; |
1563 | uint64_t addr, maxaddr; |
1564 | uint64_t length; |
1565 | int alen; |
1566 | unsigned int chunk; |
1567 | char dtype, etype; |
1568 | |
1569 | maxaddr = 0; |
1570 | list_for_each(s, sections) { |
1571 | /* Skip non-progbits sections */ |
1572 | if (!(s->flags & TYPE_PROGBITS)) |
1573 | continue; |
1574 | /* Skip zero-length sections */ |
1575 | if (s->length == 0) |
1576 | continue; |
1577 | |
1578 | addr = s->start + s->length - 1; |
1579 | if (addr > maxaddr) |
1580 | maxaddr = addr; |
1581 | } |
1582 | |
1583 | if (maxaddr <= 0xffff) { |
1584 | alen = 2; |
1585 | dtype = '1'; /* S1 = 16-bit data */ |
1586 | etype = '9'; /* S9 = 16-bit end */ |
1587 | } else if (maxaddr <= 0xffffff) { |
1588 | alen = 3; |
1589 | dtype = '2'; /* S2 = 24-bit data */ |
1590 | etype = '8'; /* S8 = 24-bit end */ |
1591 | } else { |
1592 | alen = 4; |
1593 | dtype = '3'; /* S3 = 32-bit data */ |
1594 | etype = '7'; /* S7 = 32-bit end */ |
1595 | } |
1596 | |
1597 | /* Write head record */ |
1598 | write_srecord(0, 2, 0, '0', NULL); |
1599 | |
1600 | /* Write the progbits sections to the output file. */ |
1601 | list_for_each(s, sections) { |
1602 | /* Skip non-progbits sections */ |
1603 | if (!(s->flags & TYPE_PROGBITS)) |
1604 | continue; |
1605 | /* Skip zero-length sections */ |
1606 | if (s->length == 0) |
1607 | continue; |
1608 | |
1609 | addr = s->start; |
1610 | length = s->length; |
1611 | saa_rewind(s->contents); |
1612 | |
1613 | while (length) { |
1614 | chunk = 32 - (addr & 31); |
1615 | if (length < chunk) |
1616 | chunk = length; |
1617 | |
1618 | saa_rnbytes(s->contents, buf, chunk); |
1619 | write_srecord(chunk, alen, (uint32_t)addr, dtype, buf); |
1620 | |
1621 | addr += chunk; |
1622 | length -= chunk; |
1623 | } |
1624 | } |
1625 | |
1626 | /* Write closing record */ |
1627 | write_srecord(0, alen, 0, etype, NULL); |
1628 | } |
1629 | |
1630 | |
1631 | const struct ofmt of_bin = { |
1632 | "flat-form binary files (e.g. DOS .COM, .SYS)" , |
1633 | "bin" , |
1634 | "" , |
1635 | 0, |
1636 | 64, |
1637 | null_debug_arr, |
1638 | &null_debug_form, |
1639 | bin_stdmac, |
1640 | bin_init, |
1641 | null_reset, |
1642 | nasm_do_legacy_output, |
1643 | bin_out, |
1644 | bin_deflabel, |
1645 | bin_secname, |
1646 | NULL, |
1647 | bin_sectalign, |
1648 | bin_segbase, |
1649 | bin_directive, |
1650 | bin_cleanup, |
1651 | NULL /* pragma list */ |
1652 | }; |
1653 | |
1654 | const struct ofmt of_ith = { |
1655 | "Intel hex" , |
1656 | "ith" , |
1657 | ".ith" , /* really should have been ".hex"... */ |
1658 | OFMT_TEXT, |
1659 | 64, |
1660 | null_debug_arr, |
1661 | &null_debug_form, |
1662 | bin_stdmac, |
1663 | ith_init, |
1664 | null_reset, |
1665 | nasm_do_legacy_output, |
1666 | bin_out, |
1667 | bin_deflabel, |
1668 | bin_secname, |
1669 | NULL, |
1670 | bin_sectalign, |
1671 | bin_segbase, |
1672 | bin_directive, |
1673 | bin_cleanup, |
1674 | NULL /* pragma list */ |
1675 | }; |
1676 | |
1677 | const struct ofmt of_srec = { |
1678 | "Motorola S-records" , |
1679 | "srec" , |
1680 | ".srec" , |
1681 | OFMT_TEXT, |
1682 | 64, |
1683 | null_debug_arr, |
1684 | &null_debug_form, |
1685 | bin_stdmac, |
1686 | srec_init, |
1687 | null_reset, |
1688 | nasm_do_legacy_output, |
1689 | bin_out, |
1690 | bin_deflabel, |
1691 | bin_secname, |
1692 | NULL, |
1693 | bin_sectalign, |
1694 | bin_segbase, |
1695 | bin_directive, |
1696 | bin_cleanup, |
1697 | NULL /* pragma list */ |
1698 | }; |
1699 | |
1700 | #endif /* #ifdef OF_BIN */ |
1701 | |