1 /*
2  * Flat-format binary object format
3  *
4  *  Copyright (C) 2002-2007  Peter Johnson
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include <util.h>
28 
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #include <libyasm.h>
33 
34 
35 #define REGULAR_OUTBUF_SIZE     1024
36 
37 typedef struct bin_section_data {
38     int bss;                    /* aka nobits */
39 
40     /* User-provided alignment */
41     yasm_intnum *align, *valign;
42 
43     /* User-provided starts */
44     /*@null@*/ /*@owned@*/ yasm_expr *start, *vstart;
45 
46     /* User-provided follows */
47     /*@null@*/ /*@owned@*/ char *follows, *vfollows;
48 
49     /* Calculated (final) starts, used only during output() */
50     /*@null@*/ /*@owned@*/ yasm_intnum *istart, *ivstart;
51 
52     /* Calculated (final) length, used only during output() */
53     /*@null@*/ /*@owned@*/ yasm_intnum *length;
54 } bin_section_data;
55 
56 typedef struct yasm_objfmt_bin {
57     yasm_objfmt_base objfmt;            /* base structure */
58 
59     enum {
60         NO_MAP = 0,
61         MAP_NONE = 0x01,
62         MAP_BRIEF = 0x02,
63         MAP_SECTIONS = 0x04,
64         MAP_SYMBOLS = 0x08
65     } map_flags;
66     /*@null@*/ /*@only@*/ char *map_filename;
67 
68     /*@null@*/ /*@only@*/ yasm_expr *org;
69 } yasm_objfmt_bin;
70 
71 /* symrec data is used only for the special symbols section<sectname>.start,
72  * section<sectname>.vstart, and section<sectname>.length
73  */
74 typedef struct bin_symrec_data {
75     yasm_section *section;          /* referenced section */
76     enum bin_ssym {
77         SSYM_START,
78         SSYM_VSTART,
79         SSYM_LENGTH
80     } which;
81 } bin_symrec_data;
82 
83 static void bin_section_data_destroy(/*@only@*/ void *d);
84 static void bin_section_data_print(void *data, FILE *f, int indent_level);
85 
86 static const yasm_assoc_data_callback bin_section_data_cb = {
87     bin_section_data_destroy,
88     bin_section_data_print
89 };
90 
91 static void bin_symrec_data_destroy(/*@only@*/ void *d);
92 static void bin_symrec_data_print(void *data, FILE *f, int indent_level);
93 
94 static const yasm_assoc_data_callback bin_symrec_data_cb = {
95     bin_symrec_data_destroy,
96     bin_symrec_data_print
97 };
98 
99 yasm_objfmt_module yasm_bin_LTX_objfmt;
100 
101 
102 static yasm_objfmt *
bin_objfmt_create(yasm_object * object)103 bin_objfmt_create(yasm_object *object)
104 {
105     yasm_objfmt_bin *objfmt_bin = yasm_xmalloc(sizeof(yasm_objfmt_bin));
106     objfmt_bin->objfmt.module = &yasm_bin_LTX_objfmt;
107 
108     objfmt_bin->map_flags = NO_MAP;
109     objfmt_bin->map_filename = NULL;
110     objfmt_bin->org = NULL;
111 
112     return (yasm_objfmt *)objfmt_bin;
113 }
114 
115 typedef TAILQ_HEAD(bin_group_head, bin_group) bin_groups;
116 
117 typedef struct bin_group {
118     TAILQ_ENTRY(bin_group) link;
119     yasm_section *section;
120     bin_section_data *bsd;
121 
122     /* Groups that (in parallel) logically come immediately after this
123      * group's section.
124      */
125     bin_groups follow_groups;
126 } bin_group;
127 
128 /* Recursive function to find group containing named section. */
129 static bin_group *
find_group_by_name(bin_groups * groups,const char * name)130 find_group_by_name(bin_groups *groups, const char *name)
131 {
132     bin_group *group, *found;
133     TAILQ_FOREACH(group, groups, link) {
134         if (strcmp(yasm_section_get_name(group->section), name) == 0)
135             return group;
136         /* Recurse to loop through follow groups */
137         found = find_group_by_name(&group->follow_groups, name);
138         if (found)
139             return found;
140     }
141     return NULL;
142 }
143 
144 /* Recursive function to find group.  Returns NULL if not found. */
145 static bin_group *
find_group_by_section(bin_groups * groups,yasm_section * section)146 find_group_by_section(bin_groups *groups, yasm_section *section)
147 {
148     bin_group *group, *found;
149     TAILQ_FOREACH(group, groups, link) {
150         if (group->section == section)
151             return group;
152         /* Recurse to loop through follow groups */
153         found = find_group_by_section(&group->follow_groups, section);
154         if (found)
155             return found;
156     }
157     return NULL;
158 }
159 
160 #if 0
161 /* Debugging function */
162 static void
163 print_groups(const bin_groups *groups, int indent_level)
164 {
165     bin_group *group;
166     TAILQ_FOREACH(group, groups, link) {
167         printf("%*sSection `%s':\n", indent_level, "",
168                yasm_section_get_name(group->section));
169         bin_section_data_print(group->bsd, stdout, indent_level+1);
170         if (!TAILQ_EMPTY(&group->follow_groups)) {
171             printf("%*sFollowing groups:\n", indent_level, "");
172             print_groups(&group->follow_groups, indent_level+1);
173         }
174     }
175 }
176 #endif
177 
178 static void
bin_group_destroy(bin_group * group)179 bin_group_destroy(/*@only@*/ bin_group *group)
180 {
181     bin_group *follow, *group_temp;
182     TAILQ_FOREACH_SAFE(follow, &group->follow_groups, link, group_temp)
183         bin_group_destroy(follow);
184     yasm_xfree(group);
185 }
186 
187 typedef struct bin_objfmt_output_info {
188     yasm_object *object;
189     yasm_errwarns *errwarns;
190     /*@dependent@*/ FILE *f;
191     /*@only@*/ unsigned char *buf;
192     /*@observer@*/ const yasm_section *sect;
193     unsigned long start;        /* what normal variables go against */
194 
195     yasm_intnum *origin;
196     yasm_intnum *tmp_intn;      /* temporary working intnum */
197 
198     bin_groups lma_groups, vma_groups;
199 } bin_objfmt_output_info;
200 
201 static int
bin_objfmt_check_sym(yasm_symrec * sym,void * d)202 bin_objfmt_check_sym(yasm_symrec *sym, /*@null@*/ void *d)
203 {
204     /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
205     yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
206     assert(info != NULL);
207 
208     /* Don't check internally-generated symbols.  Only internally generated
209      * symbols have symrec data, so simply check for its presence.
210      */
211     if (yasm_symrec_get_data(sym, &bin_symrec_data_cb))
212         return 0;
213 
214     if (vis & YASM_SYM_EXTERN) {
215         yasm_warn_set(YASM_WARN_GENERAL,
216             N_("binary object format does not support extern variables"));
217         yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
218     } else if (vis & YASM_SYM_GLOBAL) {
219         yasm_warn_set(YASM_WARN_GENERAL,
220             N_("binary object format does not support global variables"));
221         yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
222     } else if (vis & YASM_SYM_COMMON) {
223         yasm_error_set(YASM_ERROR_TYPE,
224             N_("binary object format does not support common variables"));
225         yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
226     }
227     return 0;
228 }
229 
230 static int
bin_lma_create_group(yasm_section * sect,void * d)231 bin_lma_create_group(yasm_section *sect, /*@null@*/ void *d)
232 {
233     bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
234     bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb);
235     unsigned long align = yasm_section_get_align(sect);
236     bin_group *group;
237 
238     assert(info != NULL);
239     assert(bsd != NULL);
240 
241     group = yasm_xmalloc(sizeof(bin_group));
242     group->section = sect;
243     group->bsd = bsd;
244     TAILQ_INIT(&group->follow_groups);
245 
246     /* Determine section alignment as necessary. */
247     if (!bsd->align)
248         bsd->align = yasm_intnum_create_uint(align > 4 ? align : 4);
249     else {
250         yasm_intnum *align_intn = yasm_intnum_create_uint(align);
251         if (yasm_intnum_compare(align_intn, bsd->align) > 0) {
252             yasm_warn_set(YASM_WARN_GENERAL,
253                 N_("section `%s' internal align of %lu is greater than `%s' of %lu; using `%s'"),
254                 yasm_section_get_name(sect),
255                 yasm_intnum_get_uint(align_intn),
256                 N_("align"),
257                 yasm_intnum_get_uint(bsd->align),
258                 N_("align"));
259             yasm_errwarn_propagate(info->errwarns, 0);
260         }
261         yasm_intnum_destroy(align_intn);
262     }
263 
264     /* Calculate section integer start. */
265     if (bsd->start) {
266         bsd->istart = yasm_expr_get_intnum(&bsd->start, 0);
267         if (!bsd->istart) {
268             yasm_error_set(YASM_ERROR_TOO_COMPLEX,
269                            N_("start expression is too complex"));
270             yasm_errwarn_propagate(info->errwarns, bsd->start->line);
271             return 1;
272         } else
273             bsd->istart = yasm_intnum_copy(bsd->istart);
274     } else
275         bsd->istart = NULL;
276 
277     /* Calculate section integer vstart. */
278     if (bsd->vstart) {
279         bsd->ivstart = yasm_expr_get_intnum(&bsd->vstart, 0);
280         if (!bsd->ivstart) {
281             yasm_error_set(YASM_ERROR_TOO_COMPLEX,
282                            N_("vstart expression is too complex"));
283             yasm_errwarn_propagate(info->errwarns, bsd->vstart->line);
284             return 1;
285         } else
286             bsd->ivstart = yasm_intnum_copy(bsd->ivstart);
287     } else
288         bsd->ivstart = NULL;
289 
290     /* Calculate section integer length. */
291     bsd->length = yasm_calc_bc_dist(yasm_section_bcs_first(sect),
292                                     yasm_section_bcs_last(sect));
293 
294     TAILQ_INSERT_TAIL(&info->lma_groups, group, link);
295     return 0;
296 }
297 
298 static int
bin_vma_create_group(yasm_section * sect,void * d)299 bin_vma_create_group(yasm_section *sect, /*@null@*/ void *d)
300 {
301     bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
302     bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb);
303     bin_group *group;
304 
305     assert(info != NULL);
306     assert(bsd != NULL);
307 
308     group = yasm_xmalloc(sizeof(bin_group));
309     group->section = sect;
310     group->bsd = bsd;
311     TAILQ_INIT(&group->follow_groups);
312 
313     TAILQ_INSERT_TAIL(&info->vma_groups, group, link);
314     return 0;
315 }
316 
317 /* Calculates new start address based on alignment constraint.
318  * Start is modified (rounded up) to the closest aligned value greater than
319  * what was passed in.
320  * Align must be a power of 2.
321  */
322 static void
bin_objfmt_align(yasm_intnum * start,const yasm_intnum * align)323 bin_objfmt_align(yasm_intnum *start, const yasm_intnum *align)
324 {
325     /* Because alignment is always a power of two, we can use some bit
326      * trickery to do this easily.
327      */
328     yasm_intnum *align_intn =
329         yasm_intnum_create_uint(yasm_intnum_get_uint(align)-1);
330     yasm_intnum_calc(align_intn, YASM_EXPR_AND, start);
331     if (!yasm_intnum_is_zero(align_intn)) {
332         /* start = (start & ~(align-1)) + align; */
333         yasm_intnum_set_uint(align_intn, yasm_intnum_get_uint(align)-1);
334         yasm_intnum_calc(align_intn, YASM_EXPR_NOT, NULL);
335         yasm_intnum_calc(align_intn, YASM_EXPR_AND, start);
336         yasm_intnum_set(start, align);
337         yasm_intnum_calc(start, YASM_EXPR_ADD, align_intn);
338     }
339     yasm_intnum_destroy(align_intn);
340 }
341 
342 /* Recursive function to assign start addresses.
343  * Updates start, last, and vdelta parameters as it goes along.
344  * The tmp parameter is just a working intnum so one doesn't have to be
345  * locally allocated for this purpose.
346  */
347 static void
group_assign_start_recurse(bin_group * group,yasm_intnum * start,yasm_intnum * last,yasm_intnum * vdelta,yasm_intnum * tmp,yasm_errwarns * errwarns)348 group_assign_start_recurse(bin_group *group, yasm_intnum *start,
349                            yasm_intnum *last, yasm_intnum *vdelta,
350                            yasm_intnum *tmp, yasm_errwarns *errwarns)
351 {
352     bin_group *follow_group;
353 
354     /* Determine LMA */
355     if (group->bsd->istart) {
356         yasm_intnum_set(group->bsd->istart, start);
357         if (group->bsd->align) {
358             bin_objfmt_align(group->bsd->istart, group->bsd->align);
359             if (yasm_intnum_compare(start, group->bsd->istart) != 0) {
360                 yasm_warn_set(YASM_WARN_GENERAL,
361                     N_("start inconsistent with align; using aligned value"));
362                 yasm_errwarn_propagate(errwarns, group->bsd->start->line);
363             }
364         }
365     } else {
366         group->bsd->istart = yasm_intnum_copy(start);
367         if (group->bsd->align != 0)
368             bin_objfmt_align(group->bsd->istart, group->bsd->align);
369     }
370 
371     /* Determine VMA if either just valign specified or if no v* specified */
372     if (!group->bsd->vstart) {
373         if (!group->bsd->vfollows && !group->bsd->valign) {
374             /* No v* specified, set VMA=LMA+vdelta. */
375             group->bsd->ivstart = yasm_intnum_copy(group->bsd->istart);
376             yasm_intnum_calc(group->bsd->ivstart, YASM_EXPR_ADD, vdelta);
377         } else if (!group->bsd->vfollows) {
378             /* Just valign specified: set VMA=LMA+vdelta, align VMA, then add
379              * delta between unaligned and aligned to vdelta parameter.
380              */
381             group->bsd->ivstart = yasm_intnum_copy(group->bsd->istart);
382             yasm_intnum_calc(group->bsd->ivstart, YASM_EXPR_ADD, vdelta);
383             yasm_intnum_set(tmp, group->bsd->ivstart);
384             bin_objfmt_align(group->bsd->ivstart, group->bsd->valign);
385             yasm_intnum_calc(vdelta, YASM_EXPR_ADD, group->bsd->ivstart);
386             yasm_intnum_calc(vdelta, YASM_EXPR_SUB, tmp);
387         }
388     }
389 
390     /* Find the maximum end value */
391     yasm_intnum_set(tmp, group->bsd->istart);
392     yasm_intnum_calc(tmp, YASM_EXPR_ADD, group->bsd->length);
393     if (yasm_intnum_compare(tmp, last) > 0)     /* tmp > last */
394         yasm_intnum_set(last, tmp);
395 
396     /* Recurse for each following group. */
397     TAILQ_FOREACH(follow_group, &group->follow_groups, link) {
398         /* Following sections have to follow this one,
399          * so add length to start.
400          */
401         yasm_intnum_set(start, group->bsd->istart);
402         yasm_intnum_calc(start, YASM_EXPR_ADD, group->bsd->length);
403 
404         group_assign_start_recurse(follow_group, start, last, vdelta, tmp,
405                                    errwarns);
406     }
407 }
408 
409 /* Recursive function to assign start addresses.
410  * Updates start parameter as it goes along.
411  * The tmp parameter is just a working intnum so one doesn't have to be
412  * locally allocated for this purpose.
413  */
414 static void
group_assign_vstart_recurse(bin_group * group,yasm_intnum * start,yasm_errwarns * errwarns)415 group_assign_vstart_recurse(bin_group *group, yasm_intnum *start,
416                             yasm_errwarns *errwarns)
417 {
418     bin_group *follow_group;
419 
420     /* Determine VMA section alignment as necessary.
421      * Default to LMA alignment if not specified.
422      */
423     if (!group->bsd->valign)
424         group->bsd->valign = yasm_intnum_copy(group->bsd->align);
425     else {
426         unsigned long align = yasm_section_get_align(group->section);
427         yasm_intnum *align_intn = yasm_intnum_create_uint(align);
428         if (yasm_intnum_compare(align_intn, group->bsd->valign) > 0) {
429             yasm_warn_set(YASM_WARN_GENERAL,
430                 N_("section `%s' internal align of %lu is greater than `%s' of %lu; using `%s'"),
431                 yasm_section_get_name(group->section),
432                 yasm_intnum_get_uint(align_intn),
433                 N_("valign"),
434                 yasm_intnum_get_uint(group->bsd->valign),
435                 N_("valign"));
436             yasm_errwarn_propagate(errwarns, 0);
437         }
438         yasm_intnum_destroy(align_intn);
439     }
440 
441     /* Determine VMA */
442     if (group->bsd->ivstart) {
443         yasm_intnum_set(group->bsd->ivstart, start);
444         if (group->bsd->valign) {
445             bin_objfmt_align(group->bsd->ivstart, group->bsd->valign);
446             if (yasm_intnum_compare(start, group->bsd->ivstart) != 0) {
447                 yasm_error_set(YASM_ERROR_VALUE,
448                                N_("vstart inconsistent with valign"));
449                 yasm_errwarn_propagate(errwarns, group->bsd->vstart->line);
450             }
451         }
452     } else {
453         group->bsd->ivstart = yasm_intnum_copy(start);
454         if (group->bsd->valign)
455             bin_objfmt_align(group->bsd->ivstart, group->bsd->valign);
456     }
457 
458     /* Recurse for each following group. */
459     TAILQ_FOREACH(follow_group, &group->follow_groups, link) {
460         /* Following sections have to follow this one,
461          * so add length to start.
462          */
463         yasm_intnum_set(start, group->bsd->ivstart);
464         yasm_intnum_calc(start, YASM_EXPR_ADD, group->bsd->length);
465 
466         group_assign_vstart_recurse(follow_group, start, errwarns);
467     }
468 }
469 
470 static /*@null@*/ const yasm_intnum *
get_ssym_value(yasm_symrec * sym)471 get_ssym_value(yasm_symrec *sym)
472 {
473     bin_symrec_data *bsymd = yasm_symrec_get_data(sym, &bin_symrec_data_cb);
474     bin_section_data *bsd;
475 
476     if (!bsymd)
477         return NULL;
478 
479     bsd = yasm_section_get_data(bsymd->section, &bin_section_data_cb);
480     assert(bsd != NULL);
481 
482     switch (bsymd->which) {
483         case SSYM_START: return bsd->istart;
484         case SSYM_VSTART: return bsd->ivstart;
485         case SSYM_LENGTH: return bsd->length;
486     }
487     return NULL;
488 }
489 
490 static /*@only@*/ yasm_expr *
bin_objfmt_expr_xform(yasm_expr * e,void * d)491 bin_objfmt_expr_xform(/*@returned@*/ /*@only@*/ yasm_expr *e,
492                       /*@unused@*/ /*@null@*/ void *d)
493 {
494     int i;
495     for (i=0; i<e->numterms; i++) {
496         /*@dependent@*/ yasm_section *sect;
497         /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
498         /*@null@*/ yasm_intnum *dist;
499         /*@null@*/ const yasm_intnum *ssymval;
500 
501         /* Transform symrecs or precbcs that reference sections into
502          * vstart + intnum(dist).
503          */
504         if (((e->terms[i].type == YASM_EXPR_SYM &&
505              yasm_symrec_get_label(e->terms[i].data.sym, &precbc)) ||
506             (e->terms[i].type == YASM_EXPR_PRECBC &&
507              (precbc = e->terms[i].data.precbc))) &&
508             (sect = yasm_bc_get_section(precbc)) &&
509             (dist = yasm_calc_bc_dist(yasm_section_bcs_first(sect), precbc))) {
510             bin_section_data *bsd;
511             bsd = yasm_section_get_data(sect, &bin_section_data_cb);
512             assert(bsd != NULL);
513             yasm_intnum_calc(dist, YASM_EXPR_ADD, bsd->ivstart);
514             e->terms[i].type = YASM_EXPR_INT;
515             e->terms[i].data.intn = dist;
516         }
517 
518         /* Transform our special symrecs into the appropriate value */
519         if (e->terms[i].type == YASM_EXPR_SYM &&
520             (ssymval = get_ssym_value(e->terms[i].data.sym))) {
521             e->terms[i].type = YASM_EXPR_INT;
522             e->terms[i].data.intn = yasm_intnum_copy(ssymval);
523         }
524     }
525 
526     return e;
527 }
528 
529 typedef struct map_output_info {
530     /* address width */
531     int bytes;
532 
533     /* intnum output static data areas */
534     unsigned char *buf;
535     yasm_intnum *intn;
536 
537     /* symrec output information */
538     unsigned long count;
539     yasm_section *section;  /* NULL for EQUs */
540 
541     yasm_object *object;    /* object */
542     FILE *f;                /* map output file */
543 } map_output_info;
544 
545 static int
map_prescan_bytes(yasm_section * sect,void * d)546 map_prescan_bytes(yasm_section *sect, void *d)
547 {
548     bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb);
549     map_output_info *info = (map_output_info *)d;
550 
551     assert(bsd != NULL);
552     assert(info != NULL);
553 
554     while (!yasm_intnum_check_size(bsd->length, info->bytes * 8, 0, 0))
555         info->bytes *= 2;
556     while (!yasm_intnum_check_size(bsd->istart, info->bytes * 8, 0, 0))
557         info->bytes *= 2;
558     while (!yasm_intnum_check_size(bsd->ivstart, info->bytes * 8, 0, 0))
559         info->bytes *= 2;
560 
561     return 0;
562 }
563 
564 static void
map_print_intnum(const yasm_intnum * intn,map_output_info * info)565 map_print_intnum(const yasm_intnum *intn, map_output_info *info)
566 {
567     size_t i;
568     yasm_intnum_get_sized(intn, info->buf, info->bytes, info->bytes*8, 0, 0,
569                           0);
570     for (i=info->bytes; i != 0; i--)
571         fprintf(info->f, "%02X", info->buf[i-1]);
572 }
573 
574 static void
map_sections_summary(bin_groups * groups,map_output_info * info)575 map_sections_summary(bin_groups *groups, map_output_info *info)
576 {
577     bin_group *group;
578     TAILQ_FOREACH(group, groups, link) {
579         bin_section_data *bsd = group->bsd;
580 
581         assert(bsd != NULL);
582         assert(info != NULL);
583 
584         map_print_intnum(bsd->ivstart, info);
585         fprintf(info->f, "  ");
586 
587         yasm_intnum_set(info->intn, bsd->ivstart);
588         yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->length);
589         map_print_intnum(info->intn, info);
590         fprintf(info->f, "  ");
591 
592         map_print_intnum(bsd->istart, info);
593         fprintf(info->f, "  ");
594 
595         yasm_intnum_set(info->intn, bsd->istart);
596         yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->length);
597         map_print_intnum(info->intn, info);
598         fprintf(info->f, "  ");
599 
600         map_print_intnum(bsd->length, info);
601         fprintf(info->f, "  ");
602 
603         fprintf(info->f, "%-*s", 10, bsd->bss ? "nobits" : "progbits");
604         fprintf(info->f, "%s\n", yasm_section_get_name(group->section));
605 
606         /* Recurse to loop through follow groups */
607         map_sections_summary(&group->follow_groups, info);
608     }
609 }
610 
611 static void
map_sections_detail(bin_groups * groups,map_output_info * info)612 map_sections_detail(bin_groups *groups, map_output_info *info)
613 {
614     bin_group *group;
615     TAILQ_FOREACH(group, groups, link) {
616         bin_section_data *bsd = group->bsd;
617         size_t i;
618         const char *s;
619 
620         s = yasm_section_get_name(group->section);
621         fprintf(info->f, "---- Section %s ", s);
622         for (i=0; i<(65-strlen(s)); i++)
623             fputc('-', info->f);
624 
625         fprintf(info->f, "\n\nclass:     %s",
626                 bsd->bss ? "nobits" : "progbits");
627         fprintf(info->f, "\nlength:    ");
628         map_print_intnum(bsd->length, info);
629         fprintf(info->f, "\nstart:     ");
630         map_print_intnum(bsd->istart, info);
631         fprintf(info->f, "\nalign:     ");
632         map_print_intnum(bsd->align, info);
633         fprintf(info->f, "\nfollows:   %s",
634                 bsd->follows ? bsd->follows : "not defined");
635         fprintf(info->f, "\nvstart:    ");
636         map_print_intnum(bsd->ivstart, info);
637         fprintf(info->f, "\nvalign:    ");
638         map_print_intnum(bsd->valign, info);
639         fprintf(info->f, "\nvfollows:  %s\n\n",
640                 bsd->vfollows ? bsd->vfollows : "not defined");
641 
642         /* Recurse to loop through follow groups */
643         map_sections_detail(&group->follow_groups, info);
644     }
645 }
646 
647 static int
map_symrec_count(yasm_symrec * sym,void * d)648 map_symrec_count(yasm_symrec *sym, void *d)
649 {
650     map_output_info *info = (map_output_info *)d;
651     /*@dependent@*/ yasm_bytecode *precbc;
652 
653     assert(info != NULL);
654 
655     /* TODO: autodetect wider size */
656     if (!info->section && yasm_symrec_get_equ(sym)) {
657         info->count++;
658     } else if (yasm_symrec_get_label(sym, &precbc) &&
659                yasm_bc_get_section(precbc) == info->section) {
660         info->count++;
661     }
662     return 0;
663 }
664 
665 static int
map_symrec_output(yasm_symrec * sym,void * d)666 map_symrec_output(yasm_symrec *sym, void *d)
667 {
668     map_output_info *info = (map_output_info *)d;
669     const yasm_expr *equ;
670     /*@dependent@*/ yasm_bytecode *precbc;
671     /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object);
672 
673     assert(info != NULL);
674 
675     if (!info->section && (equ = yasm_symrec_get_equ(sym))) {
676         yasm_expr *realequ = yasm_expr_copy(equ);
677         realequ = yasm_expr__level_tree
678             (realequ, 1, 1, 1, 0, bin_objfmt_expr_xform, NULL);
679         yasm_intnum_set(info->intn, yasm_expr_get_intnum(&realequ, 0));
680         yasm_expr_destroy(realequ);
681         map_print_intnum(info->intn, info);
682         fprintf(info->f, "  %s\n", name);
683     } else if (yasm_symrec_get_label(sym, &precbc) &&
684                yasm_bc_get_section(precbc) == info->section) {
685         bin_section_data *bsd =
686             yasm_section_get_data(info->section, &bin_section_data_cb);
687 
688         /* Real address */
689         yasm_intnum_set_uint(info->intn, yasm_bc_next_offset(precbc));
690         yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->istart);
691         map_print_intnum(info->intn, info);
692         fprintf(info->f, "  ");
693 
694         /* Virtual address */
695         yasm_intnum_set_uint(info->intn, yasm_bc_next_offset(precbc));
696         yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->ivstart);
697         map_print_intnum(info->intn, info);
698 
699         /* Name */
700         fprintf(info->f, "  %s\n", name);
701     }
702     yasm_xfree(name);
703     return 0;
704 }
705 
706 static void
map_sections_symbols(bin_groups * groups,map_output_info * info)707 map_sections_symbols(bin_groups *groups, map_output_info *info)
708 {
709     bin_group *group;
710     TAILQ_FOREACH(group, groups, link) {
711         info->count = 0;
712         info->section = group->section;
713         yasm_symtab_traverse(info->object->symtab, info, map_symrec_count);
714 
715         if (info->count > 0) {
716             const char *s = yasm_section_get_name(group->section);
717             size_t i;
718             fprintf(info->f, "---- Section %s ", s);
719             for (i=0; i<(65-strlen(s)); i++)
720                 fputc('-', info->f);
721             fprintf(info->f, "\n\n%-*s%-*s%s\n",
722                     info->bytes*2+2, "Real",
723                     info->bytes*2+2, "Virtual",
724                     "Name");
725             yasm_symtab_traverse(info->object->symtab, info,
726                                  map_symrec_output);
727             fprintf(info->f, "\n\n");
728         }
729 
730         /* Recurse to loop through follow groups */
731         map_sections_symbols(&group->follow_groups, info);
732     }
733 }
734 
735 static void
output_map(bin_objfmt_output_info * info)736 output_map(bin_objfmt_output_info *info)
737 {
738     yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)info->object->objfmt;
739     FILE *f;
740     int i;
741     map_output_info mapinfo;
742 
743     if (objfmt_bin->map_flags == NO_MAP)
744         return;
745 
746     if (objfmt_bin->map_flags == MAP_NONE)
747         objfmt_bin->map_flags = MAP_BRIEF;          /* default to brief */
748 
749     if (!objfmt_bin->map_filename)
750         f = stdout;                                 /* default to stdout */
751     else {
752         f = fopen(objfmt_bin->map_filename, "wt");
753         if (!f) {
754             yasm_warn_set(YASM_WARN_GENERAL,
755                           N_("unable to open map file `%s'"),
756                           objfmt_bin->map_filename);
757             yasm_errwarn_propagate(info->errwarns, 0);
758             return;
759         }
760     }
761 
762     mapinfo.object = info->object;
763     mapinfo.f = f;
764 
765     /* Temporary intnum */
766     mapinfo.intn = info->tmp_intn;
767 
768     /* Prescan all values to figure out what width we should make the output
769      * fields.  Start with a minimum of 4.
770      */
771     mapinfo.bytes = 4;
772     while (!yasm_intnum_check_size(info->origin, mapinfo.bytes * 8, 0, 0))
773         mapinfo.bytes *= 2;
774     yasm_object_sections_traverse(info->object, &mapinfo, map_prescan_bytes);
775     mapinfo.buf = yasm_xmalloc(mapinfo.bytes);
776 
777     fprintf(f, "\n- YASM Map file ");
778     for (i=0; i<63; i++)
779         fputc('-', f);
780     fprintf(f, "\n\nSource file:  %s\n", info->object->src_filename);
781     fprintf(f, "Output file:  %s\n\n", info->object->obj_filename);
782 
783     fprintf(f, "-- Program origin ");
784     for (i=0; i<61; i++)
785         fputc('-', f);
786     fprintf(f, "\n\n");
787     map_print_intnum(info->origin, &mapinfo);
788     fprintf(f, "\n\n");
789 
790     if (objfmt_bin->map_flags & MAP_BRIEF) {
791         fprintf(f, "-- Sections (summary) ");
792         for (i=0; i<57; i++)
793             fputc('-', f);
794         fprintf(f, "\n\n%-*s%-*s%-*s%-*s%-*s%-*s%s\n",
795                 mapinfo.bytes*2+2, "Vstart",
796                 mapinfo.bytes*2+2, "Vstop",
797                 mapinfo.bytes*2+2, "Start",
798                 mapinfo.bytes*2+2, "Stop",
799                 mapinfo.bytes*2+2, "Length",
800                 10, "Class", "Name");
801 
802         map_sections_summary(&info->lma_groups, &mapinfo);
803         fprintf(f, "\n");
804     }
805 
806     if (objfmt_bin->map_flags & MAP_SECTIONS) {
807         fprintf(f, "-- Sections (detailed) ");
808         for (i=0; i<56; i++)
809             fputc('-', f);
810         fprintf(f, "\n\n");
811         map_sections_detail(&info->lma_groups, &mapinfo);
812     }
813 
814     if (objfmt_bin->map_flags & MAP_SYMBOLS) {
815         fprintf(f, "-- Symbols ");
816         for (i=0; i<68; i++)
817             fputc('-', f);
818         fprintf(f, "\n\n");
819 
820         /* We do two passes for EQU and each section; the first pass
821          * determines the byte width to use for the value and whether any
822          * symbols are present, the second pass actually outputs the text.
823          */
824 
825         /* EQUs */
826         mapinfo.count = 0;
827         mapinfo.section = NULL;
828         yasm_symtab_traverse(info->object->symtab, &mapinfo, map_symrec_count);
829 
830         if (mapinfo.count > 0) {
831             fprintf(f, "---- No Section ");
832             for (i=0; i<63; i++)
833                 fputc('-', f);
834             fprintf(f, "\n\n%-*s%s\n", mapinfo.bytes*2+2, "Value", "Name");
835             yasm_symtab_traverse(info->object->symtab, &mapinfo,
836                                  map_symrec_output);
837             fprintf(f, "\n\n");
838         }
839 
840         /* Other sections */
841         map_sections_symbols(&info->lma_groups, &mapinfo);
842     }
843 
844     if (f != stdout)
845         fclose(f);
846 
847     yasm_xfree(mapinfo.buf);
848 }
849 
850 /* Check for LMA overlap using a simple N^2 algorithm. */
851 static int
check_lma_overlap(yasm_section * sect,void * d)852 check_lma_overlap(yasm_section *sect, /*@null@*/ void *d)
853 {
854     bin_section_data *bsd, *bsd2;
855     yasm_section *other = (yasm_section *)d;
856     yasm_intnum *overlap;
857 
858     if (!d)
859         return yasm_object_sections_traverse(yasm_section_get_object(sect),
860                                              sect, check_lma_overlap);
861     if (sect == other)
862         return 0;
863 
864     bsd = yasm_section_get_data(sect, &bin_section_data_cb);
865     bsd2 = yasm_section_get_data(other, &bin_section_data_cb);
866 
867     if (yasm_intnum_is_zero(bsd->length) ||
868         yasm_intnum_is_zero(bsd2->length))
869         return 0;
870 
871     if (yasm_intnum_compare(bsd->istart, bsd2->istart) <= 0) {
872         overlap = yasm_intnum_copy(bsd->istart);
873         yasm_intnum_calc(overlap, YASM_EXPR_ADD, bsd->length);
874         yasm_intnum_calc(overlap, YASM_EXPR_SUB, bsd2->istart);
875     } else {
876         overlap = yasm_intnum_copy(bsd2->istart);
877         yasm_intnum_calc(overlap, YASM_EXPR_ADD, bsd2->length);
878         yasm_intnum_calc(overlap, YASM_EXPR_SUB, bsd->istart);
879     }
880 
881     if (yasm_intnum_sign(overlap) > 0) {
882         yasm_error_set(YASM_ERROR_GENERAL,
883                        N_("sections `%s' and `%s' overlap by %lu bytes"),
884                        yasm_section_get_name(sect),
885                        yasm_section_get_name(other),
886                        yasm_intnum_get_uint(overlap));
887         yasm_intnum_destroy(overlap);
888         return -1;
889     }
890 
891     yasm_intnum_destroy(overlap);
892     return 0;
893 }
894 
895 static int
bin_objfmt_output_value(yasm_value * value,unsigned char * buf,unsigned int destsize,unsigned long offset,yasm_bytecode * bc,int warn,void * d)896 bin_objfmt_output_value(yasm_value *value, unsigned char *buf,
897                         unsigned int destsize,
898                         /*@unused@*/ unsigned long offset, yasm_bytecode *bc,
899                         int warn, /*@null@*/ void *d)
900 {
901     /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
902     /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
903     /*@dependent@*/ yasm_section *sect;
904 
905     assert(info != NULL);
906 
907     /* Binary objects we need to resolve against object, not against section. */
908     if (value->rel) {
909         unsigned int rshift = (unsigned int)value->rshift;
910         yasm_expr *syme;
911         /*@null@*/ const yasm_intnum *ssymval;
912 
913         if (yasm_symrec_is_abs(value->rel)) {
914             syme = yasm_expr_create_ident(yasm_expr_int(
915                 yasm_intnum_create_uint(0)), bc->line);
916         } else if (yasm_symrec_get_label(value->rel, &precbc)
917                    && (sect = yasm_bc_get_section(precbc))) {
918             syme = yasm_expr_create_ident(yasm_expr_sym(value->rel), bc->line);
919         } else if ((ssymval = get_ssym_value(value->rel))) {
920             syme = yasm_expr_create_ident(yasm_expr_int(
921                 yasm_intnum_copy(ssymval)), bc->line);
922         } else
923             goto done;
924 
925         /* Handle PC-relative */
926         if (value->curpos_rel) {
927             yasm_expr *sube;
928             sube = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_precbc(bc),
929                 yasm_expr_int(yasm_intnum_create_uint(bc->len*bc->mult_int)),
930                 bc->line);
931             syme = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(syme),
932                                     yasm_expr_expr(sube), bc->line);
933             value->curpos_rel = 0;
934             value->ip_rel = 0;
935         }
936 
937         if (value->rshift > 0)
938             syme = yasm_expr_create(YASM_EXPR_SHR, yasm_expr_expr(syme),
939                 yasm_expr_int(yasm_intnum_create_uint(rshift)), bc->line);
940 
941         /* Add into absolute portion */
942         if (!value->abs)
943             value->abs = syme;
944         else
945             value->abs =
946                 yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(value->abs),
947                                  yasm_expr_expr(syme), bc->line);
948         value->rel = NULL;
949         value->rshift = 0;
950     }
951 done:
952     /* Simplify absolute portion of value, transforming symrecs */
953     if (value->abs)
954         value->abs = yasm_expr__level_tree
955             (value->abs, 1, 1, 1, 0, bin_objfmt_expr_xform, NULL);
956 
957     /* Output */
958     switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
959                                     info->object->arch)) {
960         case -1:
961             return 1;
962         case 0:
963             break;
964         default:
965             return 0;
966     }
967 
968     /* Couldn't output, assume it contains an external reference. */
969     yasm_error_set(YASM_ERROR_GENERAL,
970         N_("binary object format does not support external references"));
971     return 1;
972 }
973 
974 static int
bin_objfmt_output_bytecode(yasm_bytecode * bc,void * d)975 bin_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
976 {
977     /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
978     /*@null@*/ /*@only@*/ unsigned char *bigbuf;
979     unsigned long size = REGULAR_OUTBUF_SIZE;
980     int gap;
981 
982     assert(info != NULL);
983 
984     bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info,
985                              bin_objfmt_output_value, NULL);
986 
987     /* Don't bother doing anything else if size ended up being 0. */
988     if (size == 0) {
989         if (bigbuf)
990             yasm_xfree(bigbuf);
991         return 0;
992     }
993 
994     /* Warn that gaps are converted to 0 and write out the 0's. */
995     if (gap) {
996         unsigned long left;
997         yasm_warn_set(YASM_WARN_UNINIT_CONTENTS,
998             N_("uninitialized space declared in code/data section: zeroing"));
999         /* Write out in chunks */
1000         memset(info->buf, 0, REGULAR_OUTBUF_SIZE);
1001         left = size;
1002         while (left > REGULAR_OUTBUF_SIZE) {
1003             fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f);
1004             left -= REGULAR_OUTBUF_SIZE;
1005         }
1006         fwrite(info->buf, left, 1, info->f);
1007     } else {
1008         /* Output buf (or bigbuf if non-NULL) to file */
1009         fwrite(bigbuf ? bigbuf : info->buf, (size_t)size, 1, info->f);
1010     }
1011 
1012     /* If bigbuf was allocated, free it */
1013     if (bigbuf)
1014         yasm_xfree(bigbuf);
1015 
1016     return 0;
1017 }
1018 
1019 /* Check to ensure bytecode is res* (for BSS sections) */
1020 static int
bin_objfmt_no_output_bytecode(yasm_bytecode * bc,void * d)1021 bin_objfmt_no_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
1022 {
1023     /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
1024     /*@null@*/ /*@only@*/ unsigned char *bigbuf;
1025     unsigned long size = REGULAR_OUTBUF_SIZE;
1026     int gap;
1027 
1028     assert(info != NULL);
1029 
1030     bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info,
1031                              bin_objfmt_output_value, NULL);
1032 
1033     /* If bigbuf was allocated, free it */
1034     if (bigbuf)
1035         yasm_xfree(bigbuf);
1036 
1037     /* Don't bother doing anything else if size ended up being 0. */
1038     if (size == 0)
1039         return 0;
1040 
1041     /* Warn if not a gap. */
1042     if (!gap) {
1043         yasm_warn_set(YASM_WARN_GENERAL,
1044             N_("initialized space declared in nobits section: ignoring"));
1045     }
1046 
1047     return 0;
1048 }
1049 
1050 static int
bin_objfmt_output_section(yasm_section * sect,void * d)1051 bin_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
1052 {
1053     bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb);
1054     /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
1055 
1056     assert(bsd != NULL);
1057     assert(info != NULL);
1058 
1059     if (bsd->bss) {
1060         yasm_section_bcs_traverse(sect, info->errwarns,
1061                                   info, bin_objfmt_no_output_bytecode);
1062     } else {
1063         yasm_intnum_set(info->tmp_intn, bsd->istart);
1064         yasm_intnum_calc(info->tmp_intn, YASM_EXPR_SUB, info->origin);
1065         if (yasm_intnum_sign(info->tmp_intn) < 0) {
1066             yasm_error_set(YASM_ERROR_VALUE,
1067                            N_("section `%s' starts before origin (ORG)"),
1068                            yasm_section_get_name(sect));
1069             yasm_errwarn_propagate(info->errwarns, 0);
1070             return 0;
1071         }
1072         if (!yasm_intnum_check_size(info->tmp_intn, sizeof(long)*8, 0, 1)) {
1073             yasm_error_set(YASM_ERROR_VALUE,
1074                            N_("section `%s' start value too large"),
1075                            yasm_section_get_name(sect));
1076             yasm_errwarn_propagate(info->errwarns, 0);
1077             return 0;
1078         }
1079         if (fseek(info->f, yasm_intnum_get_int(info->tmp_intn) + info->start,
1080                   SEEK_SET) < 0)
1081             yasm__fatal(N_("could not seek on output file"));
1082         yasm_section_bcs_traverse(sect, info->errwarns,
1083                                   info, bin_objfmt_output_bytecode);
1084     }
1085 
1086     return 0;
1087 }
1088 
1089 static void
bin_objfmt_cleanup(bin_objfmt_output_info * info)1090 bin_objfmt_cleanup(bin_objfmt_output_info *info)
1091 {
1092     bin_group *group, *group_temp;
1093 
1094     yasm_xfree(info->buf);
1095     yasm_intnum_destroy(info->origin);
1096     yasm_intnum_destroy(info->tmp_intn);
1097 
1098     TAILQ_FOREACH_SAFE(group, &info->lma_groups, link, group_temp)
1099         bin_group_destroy(group);
1100 
1101     TAILQ_FOREACH_SAFE(group, &info->vma_groups, link, group_temp)
1102         bin_group_destroy(group);
1103 }
1104 
1105 static void
bin_objfmt_output(yasm_object * object,FILE * f,int all_syms,yasm_errwarns * errwarns)1106 bin_objfmt_output(yasm_object *object, FILE *f, /*@unused@*/ int all_syms,
1107                   yasm_errwarns *errwarns)
1108 {
1109     yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt;
1110     bin_objfmt_output_info info;
1111     bin_group *group, *lma_group, *vma_group, *group_temp;
1112     yasm_intnum *start, *last, *vdelta;
1113     bin_groups unsorted_groups, bss_groups;
1114 
1115     info.start = ftell(f);
1116 
1117     /* Set ORG to 0 unless otherwise specified */
1118     if (objfmt_bin->org) {
1119         info.origin = yasm_expr_get_intnum(&objfmt_bin->org, 0);
1120         if (!info.origin) {
1121             yasm_error_set(YASM_ERROR_TOO_COMPLEX,
1122                            N_("ORG expression is too complex"));
1123             yasm_errwarn_propagate(errwarns, objfmt_bin->org->line);
1124             return;
1125         }
1126         if (yasm_intnum_sign(info.origin) < 0) {
1127             yasm_error_set(YASM_ERROR_VALUE, N_("ORG expression is negative"));
1128             yasm_errwarn_propagate(errwarns, objfmt_bin->org->line);
1129             return;
1130         }
1131         info.origin = yasm_intnum_copy(info.origin);
1132     } else
1133         info.origin = yasm_intnum_create_uint(0);
1134 
1135     info.object = object;
1136     info.errwarns = errwarns;
1137     info.f = f;
1138     info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
1139     info.tmp_intn = yasm_intnum_create_uint(0);
1140     TAILQ_INIT(&info.lma_groups);
1141     TAILQ_INIT(&info.vma_groups);
1142 
1143     /* Check symbol table */
1144     yasm_symtab_traverse(object->symtab, &info, bin_objfmt_check_sym);
1145 
1146     /* Create section groups */
1147     if (yasm_object_sections_traverse(object, &info, bin_lma_create_group)) {
1148         bin_objfmt_cleanup(&info);
1149         return;     /* error detected */
1150     }
1151 
1152     /* Determine section order according to LMA.
1153      * Sections can be ordered either by (priority):
1154      *  - follows
1155      *  - start
1156      *  - progbits/nobits setting
1157      *  - order in the input file
1158      */
1159 
1160     /* Look at each group with follows specified, and find the section
1161      * that group is supposed to follow.
1162      */
1163     TAILQ_FOREACH_SAFE(lma_group, &info.lma_groups, link, group_temp) {
1164         if (lma_group->bsd->follows) {
1165             bin_group *found;
1166             /* Need to find group containing section this section follows. */
1167             found =
1168                 find_group_by_name(&info.lma_groups, lma_group->bsd->follows);
1169             if (!found) {
1170                 yasm_error_set(YASM_ERROR_VALUE,
1171                                N_("section `%s' follows an invalid or unknown section `%s'"),
1172                                yasm_section_get_name(lma_group->section),
1173                                lma_group->bsd->follows);
1174                 yasm_errwarn_propagate(errwarns, 0);
1175                 bin_objfmt_cleanup(&info);
1176                 return;
1177             }
1178 
1179             /* Check for loops */
1180             if (lma_group->section == found->section ||
1181                 find_group_by_section(&lma_group->follow_groups,
1182                                       found->section)) {
1183                 yasm_error_set(YASM_ERROR_VALUE,
1184                                N_("follows loop between section `%s' and section `%s'"),
1185                                yasm_section_get_name(lma_group->section),
1186                                yasm_section_get_name(found->section));
1187                 yasm_errwarn_propagate(errwarns, 0);
1188                 bin_objfmt_cleanup(&info);
1189                 return;
1190             }
1191 
1192             /* Remove this section from main lma groups list */
1193             TAILQ_REMOVE(&info.lma_groups, lma_group, link);
1194             /* Add it after the section it's supposed to follow. */
1195             TAILQ_INSERT_TAIL(&found->follow_groups, lma_group, link);
1196         }
1197     }
1198 
1199     /* Sort the top-level groups according to their start address.
1200      * Use Shell sort for ease of implementation.
1201      * If no start address is specified for a section, don't change the order,
1202      * and move BSS sections to a separate list so they can be moved to the
1203      * end of the lma list after all other sections are sorted.
1204      */
1205     unsorted_groups = info.lma_groups;  /* structure copy */
1206     TAILQ_INIT(&info.lma_groups);
1207     TAILQ_INIT(&bss_groups);
1208     TAILQ_FOREACH_SAFE(lma_group, &unsorted_groups, link, group_temp) {
1209         bin_group *before;
1210 
1211         if (!lma_group->bsd->istart) {
1212             if (lma_group->bsd->bss)
1213                 TAILQ_INSERT_TAIL(&bss_groups, lma_group, link);
1214             else
1215                 TAILQ_INSERT_TAIL(&info.lma_groups, lma_group, link);
1216             continue;
1217         }
1218 
1219         before = NULL;
1220         TAILQ_FOREACH(group, &info.lma_groups, link) {
1221             if (!group->bsd->istart)
1222                 continue;
1223             if (yasm_intnum_compare(group->bsd->istart,
1224                                     lma_group->bsd->istart) > 0) {
1225                 before = group;
1226                 break;
1227             }
1228         }
1229         if (before)
1230             TAILQ_INSERT_BEFORE(before, lma_group, link);
1231         else
1232             TAILQ_INSERT_TAIL(&info.lma_groups, lma_group, link);
1233     }
1234 
1235     /* Move the pure-BSS sections to the end of the LMA list. */
1236     TAILQ_FOREACH_SAFE(group, &bss_groups, link, group_temp)
1237         TAILQ_INSERT_TAIL(&info.lma_groups, group, link);
1238     TAILQ_INIT(&bss_groups);    /* For sanity */
1239 
1240     /* Assign a LMA start address to every section.
1241      * Also assign VMA=LMA unless otherwise specified.
1242      *
1243      * We need to assign VMA=LMA here (while walking the tree) for the case:
1244      *  sect1 start=0 (size=0x11)
1245      *  sect2 follows=sect1 valign=16 (size=0x104)
1246      *  sect3 follows=sect2 valign=16
1247      * Where the valign of sect2 will result in a sect3 vaddr higher than a
1248      * naive segment-by-segment interpretation (where sect3 and sect2 would
1249      * have a VMA overlap).
1250      *
1251      * Algorithm for VMA=LMA setting:
1252      * Start with delta=0.
1253      * If there's no virtual attributes, we simply set VMA = LMA+delta.
1254      * If there's only valign specified, we set VMA = aligned LMA, and add
1255      * any new alignment difference to delta.
1256      *
1257      * We could do the LMA start and VMA=LMA steps in two separate steps,
1258      * but it's easier to just recurse once.
1259      */
1260     start = yasm_intnum_copy(info.origin);
1261     last = yasm_intnum_copy(info.origin);
1262     vdelta = yasm_intnum_create_uint(0);
1263     TAILQ_FOREACH(lma_group, &info.lma_groups, link) {
1264         if (lma_group->bsd->istart)
1265             yasm_intnum_set(start, lma_group->bsd->istart);
1266         group_assign_start_recurse(lma_group, start, last, vdelta,
1267                                    info.tmp_intn, errwarns);
1268         yasm_intnum_set(start, last);
1269     }
1270     yasm_intnum_destroy(last);
1271     yasm_intnum_destroy(vdelta);
1272 
1273     /*
1274      * Determine section order according to VMA
1275      */
1276 
1277     /* Create section groups */
1278     if (yasm_object_sections_traverse(object, &info, bin_vma_create_group)) {
1279         yasm_intnum_destroy(start);
1280         bin_objfmt_cleanup(&info);
1281         return;     /* error detected */
1282     }
1283 
1284     /* Look at each group with vfollows specified, and find the section
1285      * that group is supposed to follow.
1286      */
1287     TAILQ_FOREACH_SAFE(vma_group, &info.vma_groups, link, group_temp) {
1288         if (vma_group->bsd->vfollows) {
1289             bin_group *found;
1290             /* Need to find group containing section this section follows. */
1291             found = find_group_by_name(&info.vma_groups,
1292                                        vma_group->bsd->vfollows);
1293             if (!found) {
1294                 yasm_error_set(YASM_ERROR_VALUE,
1295                                N_("section `%s' vfollows an invalid or unknown section `%s'"),
1296                                yasm_section_get_name(vma_group->section),
1297                                vma_group->bsd->vfollows);
1298                 yasm_errwarn_propagate(errwarns, 0);
1299                 yasm_intnum_destroy(start);
1300                 bin_objfmt_cleanup(&info);
1301                 return;
1302             }
1303 
1304             /* Check for loops */
1305             if (vma_group->section == found->section ||
1306                 find_group_by_section(&vma_group->follow_groups,
1307                                       found->section)) {
1308                 yasm_error_set(YASM_ERROR_VALUE,
1309                                N_("vfollows loop between section `%s' and section `%s'"),
1310                                yasm_section_get_name(vma_group->section),
1311                                yasm_section_get_name(found->section));
1312                 yasm_errwarn_propagate(errwarns, 0);
1313                 bin_objfmt_cleanup(&info);
1314                 return;
1315             }
1316 
1317             /* Remove this section from main lma groups list */
1318             TAILQ_REMOVE(&info.vma_groups, vma_group, link);
1319             /* Add it after the section it's supposed to follow. */
1320             TAILQ_INSERT_TAIL(&found->follow_groups, vma_group, link);
1321         }
1322     }
1323 
1324     /* Due to the combination of steps above, we now know that all top-level
1325      * groups have integer ivstart:
1326      * Vstart Vfollows Valign   Handled by
1327      *     No       No     No   group_assign_start_recurse()
1328      *     No       No    Yes   group_assign_start_recurse()
1329      *     No      Yes    -     vfollows loop (above)
1330      *    Yes      -      -     bin_lma_create_group()
1331      */
1332     TAILQ_FOREACH(vma_group, &info.vma_groups, link) {
1333         yasm_intnum_set(start, vma_group->bsd->ivstart);
1334         group_assign_vstart_recurse(vma_group, start, errwarns);
1335     }
1336 
1337     /* Output map file */
1338     output_map(&info);
1339 
1340     /* Ensure we don't have overlapping progbits LMAs.
1341      * Use a dumb O(N^2) algorithm as the number of sections is essentially
1342      * always low.
1343      */
1344     if (yasm_object_sections_traverse(object, NULL, check_lma_overlap)) {
1345         yasm_errwarn_propagate(errwarns, 0);
1346         yasm_intnum_destroy(start);
1347         bin_objfmt_cleanup(&info);
1348         return;
1349     }
1350 
1351     /* Output sections */
1352     yasm_object_sections_traverse(object, &info, bin_objfmt_output_section);
1353 
1354     /* Clean up */
1355     yasm_intnum_destroy(start);
1356     bin_objfmt_cleanup(&info);
1357 }
1358 
1359 static void
bin_objfmt_destroy(yasm_objfmt * objfmt)1360 bin_objfmt_destroy(yasm_objfmt *objfmt)
1361 {
1362     yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)objfmt;
1363     if (objfmt_bin->map_filename)
1364         yasm_xfree(objfmt_bin->map_filename);
1365     yasm_expr_destroy(objfmt_bin->org);
1366     yasm_xfree(objfmt);
1367 }
1368 
1369 static void
define_section_symbol(yasm_symtab * symtab,yasm_section * sect,const char * sectname,const char * suffix,enum bin_ssym which,unsigned long line)1370 define_section_symbol(yasm_symtab *symtab, yasm_section *sect,
1371                       const char *sectname, const char *suffix,
1372                       enum bin_ssym which, unsigned long line)
1373 {
1374     yasm_symrec *sym;
1375     bin_symrec_data *bsymd = yasm_xmalloc(sizeof(bin_symrec_data));
1376     char *symname = yasm_xmalloc(8+strlen(sectname)+strlen(suffix)+1);
1377 
1378     strcpy(symname, "section.");
1379     strcat(symname, sectname);
1380     strcat(symname, suffix);
1381 
1382     bsymd->section = sect;
1383     bsymd->which = which;
1384 
1385     sym = yasm_symtab_declare(symtab, symname, YASM_SYM_EXTERN, line);
1386     yasm_xfree(symname);
1387     yasm_symrec_add_data(sym, &bin_symrec_data_cb, bsymd);
1388 }
1389 
1390 static void
bin_objfmt_init_new_section(yasm_section * sect,unsigned long line)1391 bin_objfmt_init_new_section(yasm_section *sect, unsigned long line)
1392 {
1393     yasm_object *object = yasm_section_get_object(sect);
1394     const char *sectname = yasm_section_get_name(sect);
1395     /*yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt;*/
1396     bin_section_data *data;
1397 
1398     data = yasm_xmalloc(sizeof(bin_section_data));
1399     data->bss = 0;
1400     data->align = NULL;
1401     data->valign = NULL;
1402     data->start = NULL;
1403     data->vstart = NULL;
1404     data->follows = NULL;
1405     data->vfollows = NULL;
1406     data->istart = NULL;
1407     data->ivstart = NULL;
1408     data->length = NULL;
1409     yasm_section_add_data(sect, &bin_section_data_cb, data);
1410 
1411     define_section_symbol(object->symtab, sect, sectname, ".start",
1412                           SSYM_START, line);
1413     define_section_symbol(object->symtab, sect, sectname, ".vstart",
1414                           SSYM_VSTART, line);
1415     define_section_symbol(object->symtab, sect, sectname, ".length",
1416                           SSYM_LENGTH, line);
1417 }
1418 
1419 static yasm_section *
bin_objfmt_add_default_section(yasm_object * object)1420 bin_objfmt_add_default_section(yasm_object *object)
1421 {
1422     yasm_section *retval;
1423     int isnew;
1424 
1425     retval = yasm_object_get_general(object, ".text", 0, 1, 0, &isnew, 0);
1426     if (isnew)
1427         yasm_section_set_default(retval, 1);
1428     return retval;
1429 }
1430 
1431 /* GAS-style flags */
1432 static int
bin_helper_gasflags(void * obj,yasm_valparam * vp,unsigned long line,void * d,uintptr_t arg)1433 bin_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d,
1434                     /*@unused@*/ uintptr_t arg)
1435 {
1436     /* TODO */
1437     return 0;
1438 }
1439 
1440 static /*@observer@*/ /*@null@*/ yasm_section *
bin_objfmt_section_switch(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)1441 bin_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
1442                           /*@unused@*/ /*@null@*/
1443                           yasm_valparamhead *objext_valparams,
1444                           unsigned long line)
1445 {
1446     yasm_valparam *vp;
1447     yasm_section *retval;
1448     int isnew;
1449     int flags_override = 0;
1450     const char *sectname;
1451     bin_section_data *bsd = NULL;
1452 
1453     struct bin_section_switch_data {
1454         /*@only@*/ /*@null@*/ char *follows;
1455         /*@only@*/ /*@null@*/ char *vfollows;
1456         /*@only@*/ /*@null@*/ yasm_expr *start;
1457         /*@only@*/ /*@null@*/ yasm_expr *vstart;
1458         /*@only@*/ /*@null@*/ yasm_intnum *align;
1459         /*@only@*/ /*@null@*/ yasm_intnum *valign;
1460         unsigned long bss;
1461         unsigned long code;
1462     } data;
1463 
1464     static const yasm_dir_help help[] = {
1465         { "follows", 1, yasm_dir_helper_string,
1466           offsetof(struct bin_section_switch_data, follows), 0 },
1467         { "vfollows", 1, yasm_dir_helper_string,
1468           offsetof(struct bin_section_switch_data, vfollows), 0 },
1469         { "start", 1, yasm_dir_helper_expr,
1470           offsetof(struct bin_section_switch_data, start), 0 },
1471         { "vstart", 1, yasm_dir_helper_expr,
1472           offsetof(struct bin_section_switch_data, vstart), 0 },
1473         { "align", 1, yasm_dir_helper_intn,
1474           offsetof(struct bin_section_switch_data, align), 0 },
1475         { "valign", 1, yasm_dir_helper_intn,
1476           offsetof(struct bin_section_switch_data, valign), 0 },
1477         { "nobits", 0, yasm_dir_helper_flag_set,
1478           offsetof(struct bin_section_switch_data, bss), 1 },
1479         { "progbits", 0, yasm_dir_helper_flag_set,
1480           offsetof(struct bin_section_switch_data, bss), 0 },
1481         { "code", 0, yasm_dir_helper_flag_set,
1482           offsetof(struct bin_section_switch_data, code), 1 },
1483         { "data", 0, yasm_dir_helper_flag_set,
1484           offsetof(struct bin_section_switch_data, code), 0 },
1485         { "execute", 0, yasm_dir_helper_flag_set,
1486           offsetof(struct bin_section_switch_data, code), 1 },
1487         { "noexecute", 0, yasm_dir_helper_flag_set,
1488           offsetof(struct bin_section_switch_data, code), 0 },
1489         { "gasflags", 1, bin_helper_gasflags, 0, 0 }
1490     };
1491 
1492     vp = yasm_vps_first(valparams);
1493     sectname = yasm_vp_string(vp);
1494     if (!sectname)
1495         return NULL;
1496     vp = yasm_vps_next(vp);
1497 
1498     retval = yasm_object_find_general(object, sectname);
1499     if (retval) {
1500         bsd = yasm_section_get_data(retval, &bin_section_data_cb);
1501         assert(bsd != NULL);
1502         data.follows = bsd->follows;
1503         data.vfollows = bsd->vfollows;
1504         data.start = bsd->start;
1505         data.vstart = bsd->vstart;
1506         data.align = NULL;
1507         data.valign = NULL;
1508         data.bss = bsd->bss;
1509         data.code = yasm_section_is_code(retval);
1510     } else {
1511         data.follows = NULL;
1512         data.vfollows = NULL;
1513         data.start = NULL;
1514         data.vstart = NULL;
1515         data.align = NULL;
1516         data.valign = NULL;
1517         data.bss = strcmp(sectname, ".bss") == 0;
1518         data.code = strcmp(sectname, ".text") == 0;
1519     }
1520 
1521     flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help),
1522                                      &data, yasm_dir_helper_valparam_warn);
1523     if (flags_override < 0)
1524         return NULL;    /* error occurred */
1525 
1526     if (data.start && data.follows) {
1527         yasm_error_set(YASM_ERROR_GENERAL,
1528             N_("cannot combine `start' and `follows' section attributes"));
1529         return NULL;
1530     }
1531 
1532     if (data.vstart && data.vfollows) {
1533         yasm_error_set(YASM_ERROR_GENERAL,
1534             N_("cannot combine `vstart' and `vfollows' section attributes"));
1535         return NULL;
1536     }
1537 
1538     if (data.align) {
1539         unsigned long align = yasm_intnum_get_uint(data.align);
1540 
1541         /* Alignments must be a power of two. */
1542         if (!is_exp2(align)) {
1543             yasm_error_set(YASM_ERROR_VALUE,
1544                            N_("argument to `%s' is not a power of two"),
1545                            "align");
1546             return NULL;
1547         }
1548     } else
1549         data.align = bsd ? bsd->align : NULL;
1550 
1551     if (data.valign) {
1552         unsigned long valign = yasm_intnum_get_uint(data.valign);
1553 
1554         /* Alignments must be a power of two. */
1555         if (!is_exp2(valign)) {
1556             yasm_error_set(YASM_ERROR_VALUE,
1557                            N_("argument to `%s' is not a power of two"),
1558                            "valign");
1559             return NULL;
1560         }
1561     } else
1562         data.valign = bsd ? bsd->valign : NULL;
1563 
1564     retval = yasm_object_get_general(object, sectname, 0, (int)data.code,
1565                                      (int)data.bss, &isnew, line);
1566 
1567     bsd = yasm_section_get_data(retval, &bin_section_data_cb);
1568 
1569     if (isnew || yasm_section_is_default(retval)) {
1570         yasm_section_set_default(retval, 0);
1571     }
1572 
1573     /* Update section flags */
1574     bsd->bss = data.bss;
1575     bsd->align = data.align;
1576     bsd->valign = data.valign;
1577     bsd->start = data.start;
1578     bsd->vstart = data.vstart;
1579     bsd->follows = data.follows;
1580     bsd->vfollows = data.vfollows;
1581 
1582     return retval;
1583 }
1584 
1585 static /*@observer@*/ /*@null@*/ yasm_symrec *
bin_objfmt_get_special_sym(yasm_object * object,const char * name,const char * parser)1586 bin_objfmt_get_special_sym(yasm_object *object, const char *name,
1587                            const char *parser)
1588 {
1589     return NULL;
1590 }
1591 
1592 static void
bin_objfmt_dir_org(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)1593 bin_objfmt_dir_org(yasm_object *object,
1594                    /*@null@*/ yasm_valparamhead *valparams,
1595                    /*@unused@*/ /*@null@*/
1596                    yasm_valparamhead *objext_valparams, unsigned long line)
1597 {
1598     yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt;
1599     yasm_valparam *vp;
1600 
1601     /* We only allow a single ORG in a program. */
1602     if (objfmt_bin->org) {
1603         yasm_error_set(YASM_ERROR_GENERAL, N_("program origin redefined"));
1604         return;
1605     }
1606 
1607     /* ORG takes just a simple expression as param */
1608     vp = yasm_vps_first(valparams);
1609     objfmt_bin->org = yasm_vp_expr(vp, object->symtab, line);
1610     if (!objfmt_bin->org) {
1611         yasm_error_set(YASM_ERROR_SYNTAX,
1612                        N_("argument to ORG must be expression"));
1613         return;
1614     }
1615 }
1616 
1617 struct bin_dir_map_data {
1618     unsigned long flags;
1619     /*@only@*/ /*@null@*/ char *filename;
1620 };
1621 
1622 static int
dir_map_filename(void * obj,yasm_valparam * vp,unsigned long line,void * data)1623 dir_map_filename(void *obj, yasm_valparam *vp, unsigned long line, void *data)
1624 {
1625     struct bin_dir_map_data *mdata = (struct bin_dir_map_data *)data;
1626     const char *filename;
1627 
1628     if (mdata->filename) {
1629         yasm_warn_set(YASM_WARN_GENERAL, N_("map file already specified"));
1630         return 0;
1631     }
1632 
1633     filename = yasm_vp_string(vp);
1634     if (!filename) {
1635         yasm_error_set(YASM_ERROR_SYNTAX,
1636                        N_("unexpected expression in [map]"));
1637         return -1;
1638     }
1639     mdata->filename = yasm__xstrdup(filename);
1640 
1641     return 1;
1642 }
1643 
1644 static void
bin_objfmt_dir_map(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)1645 bin_objfmt_dir_map(yasm_object *object,
1646                    /*@null@*/ yasm_valparamhead *valparams,
1647                    /*@unused@*/ /*@null@*/
1648                    yasm_valparamhead *objext_valparams, unsigned long line)
1649 {
1650     yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt;
1651 
1652     struct bin_dir_map_data data;
1653 
1654     static const yasm_dir_help help[] = {
1655         { "all", 0, yasm_dir_helper_flag_or,
1656           offsetof(struct bin_dir_map_data, flags),
1657           MAP_BRIEF|MAP_SECTIONS|MAP_SYMBOLS },
1658         { "brief", 0, yasm_dir_helper_flag_or,
1659           offsetof(struct bin_dir_map_data, flags), MAP_BRIEF },
1660         { "sections", 0, yasm_dir_helper_flag_or,
1661           offsetof(struct bin_dir_map_data, flags), MAP_SECTIONS },
1662         { "segments", 0, yasm_dir_helper_flag_or,
1663           offsetof(struct bin_dir_map_data, flags), MAP_SECTIONS },
1664         { "symbols", 0, yasm_dir_helper_flag_or,
1665           offsetof(struct bin_dir_map_data, flags), MAP_SYMBOLS }
1666     };
1667 
1668     data.flags = objfmt_bin->map_flags | MAP_NONE;
1669     data.filename = objfmt_bin->map_filename;
1670 
1671     if (valparams && yasm_dir_helper(object, yasm_vps_first(valparams), line, help,
1672                                      NELEMS(help), &data, dir_map_filename) < 0)
1673         return;     /* error occurred */
1674 
1675     objfmt_bin->map_flags = data.flags;
1676     objfmt_bin->map_filename = data.filename;
1677 }
1678 
1679 static void
bin_section_data_destroy(void * data)1680 bin_section_data_destroy(void *data)
1681 {
1682     bin_section_data *bsd = (bin_section_data *)data;
1683     if (bsd->start)
1684         yasm_expr_destroy(bsd->start);
1685     if (bsd->vstart)
1686         yasm_expr_destroy(bsd->vstart);
1687     if (bsd->follows)
1688         yasm_xfree(bsd->follows);
1689     if (bsd->vfollows)
1690         yasm_xfree(bsd->vfollows);
1691     if (bsd->istart)
1692         yasm_intnum_destroy(bsd->istart);
1693     if (bsd->ivstart)
1694         yasm_intnum_destroy(bsd->ivstart);
1695     if (bsd->length)
1696         yasm_intnum_destroy(bsd->length);
1697     yasm_xfree(data);
1698 }
1699 
1700 static void
bin_section_data_print(void * data,FILE * f,int indent_level)1701 bin_section_data_print(void *data, FILE *f, int indent_level)
1702 {
1703     bin_section_data *bsd = (bin_section_data *)data;
1704 
1705     fprintf(f, "%*sbss=%d\n", indent_level, "", bsd->bss);
1706 
1707     fprintf(f, "%*salign=", indent_level, "");
1708     if (bsd->align)
1709         yasm_intnum_print(bsd->align, f);
1710     else
1711         fprintf(f, "(nil)");
1712     fprintf(f, "\n%*svalign=", indent_level, "");
1713     if (bsd->valign)
1714         yasm_intnum_print(bsd->valign, f);
1715     else
1716         fprintf(f, "(nil)");
1717 
1718     fprintf(f, "\n%*sstart=", indent_level, "");
1719     yasm_expr_print(bsd->start, f);
1720     fprintf(f, "\n%*svstart=", indent_level, "");
1721     yasm_expr_print(bsd->vstart, f);
1722 
1723     fprintf(f, "\n%*sfollows=", indent_level, "");
1724     if (bsd->follows)
1725         fprintf(f, "\"%s\"", bsd->follows);
1726     else
1727         fprintf(f, "(nil)");
1728     fprintf(f, "\n%*svfollows=", indent_level, "");
1729     if (bsd->vfollows)
1730         fprintf(f, "\"%s\"", bsd->vfollows);
1731     else
1732         fprintf(f, "(nil)");
1733 
1734     fprintf(f, "\n%*sistart=", indent_level, "");
1735     if (bsd->istart)
1736         yasm_intnum_print(bsd->istart, f);
1737     else
1738         fprintf(f, "(nil)");
1739     fprintf(f, "\n%*sivstart=", indent_level, "");
1740     if (bsd->ivstart)
1741         yasm_intnum_print(bsd->ivstart, f);
1742     else
1743         fprintf(f, "(nil)");
1744 
1745     fprintf(f, "\n%*slength=", indent_level, "");
1746     if (bsd->length)
1747         yasm_intnum_print(bsd->length, f);
1748     else
1749         fprintf(f, "(nil)");
1750     fprintf(f, "\n");
1751 }
1752 
1753 static void
bin_symrec_data_destroy(void * data)1754 bin_symrec_data_destroy(void *data)
1755 {
1756     yasm_xfree(data);
1757 }
1758 
1759 static void
bin_symrec_data_print(void * data,FILE * f,int indent_level)1760 bin_symrec_data_print(void *data, FILE *f, int indent_level)
1761 {
1762     bin_symrec_data *bsymd = (bin_symrec_data *)data;
1763 
1764     fprintf(f, "%*ssection=\"%s\"\n", indent_level, "",
1765             yasm_section_get_name(bsymd->section));
1766     fprintf(f, "%*swhich=", indent_level, "");
1767     switch (bsymd->which) {
1768         case SSYM_START: fprintf(f, "START"); break;
1769         case SSYM_VSTART: fprintf(f, "VSTART"); break;
1770         case SSYM_LENGTH: fprintf(f, "LENGTH"); break;
1771     }
1772     fprintf(f, "\n");
1773 }
1774 
1775 
1776 /* Define valid debug formats to use with this object format */
1777 static const char *bin_objfmt_dbgfmt_keywords[] = {
1778     "null",
1779     NULL
1780 };
1781 
1782 static const yasm_directive bin_objfmt_directives[] = {
1783     { "org",    "nasm", bin_objfmt_dir_org,     YASM_DIR_ARG_REQUIRED },
1784     { "map",    "nasm", bin_objfmt_dir_map,     YASM_DIR_ANY },
1785     { NULL, NULL, NULL, 0 }
1786 };
1787 
1788 static const char *bin_nasm_stdmac[] = {
1789     "%imacro org 1+.nolist",
1790     "[org %1]",
1791     "%endmacro",
1792     NULL
1793 };
1794 
1795 static const yasm_stdmac bin_objfmt_stdmacs[] = {
1796     { "nasm", "nasm", bin_nasm_stdmac },
1797     { "tasm", "tasm", bin_nasm_stdmac },
1798     { NULL, NULL, NULL }
1799 };
1800 
1801 /* Define objfmt structure -- see objfmt.h for details */
1802 yasm_objfmt_module yasm_bin_LTX_objfmt = {
1803     "Flat format binary",
1804     "bin",
1805     NULL,
1806     16,
1807     0,
1808     bin_objfmt_dbgfmt_keywords,
1809     "null",
1810     bin_objfmt_directives,
1811     bin_objfmt_stdmacs,
1812     bin_objfmt_create,
1813     bin_objfmt_output,
1814     bin_objfmt_destroy,
1815     bin_objfmt_add_default_section,
1816     bin_objfmt_init_new_section,
1817     bin_objfmt_section_switch,
1818     bin_objfmt_get_special_sym
1819 };
1820 
1821 #define EXE_HEADER_SIZE 0x200
1822 
1823 /* DOS .EXE binaries are just raw binaries with a header */
1824 yasm_objfmt_module yasm_dosexe_LTX_objfmt;
1825 
1826 static yasm_objfmt *
dosexe_objfmt_create(yasm_object * object)1827 dosexe_objfmt_create(yasm_object *object)
1828 {
1829     yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *) bin_objfmt_create(object);
1830     objfmt_bin->objfmt.module = &yasm_dosexe_LTX_objfmt;
1831     return (yasm_objfmt *)objfmt_bin;
1832 }
1833 
1834 static unsigned long
get_sym(yasm_object * object,const char * name)1835 get_sym(yasm_object *object, const char *name) {
1836     yasm_symrec *symrec = yasm_symtab_get(object->symtab, name);
1837     yasm_bytecode *prevbc;
1838     if (!symrec)
1839         return 0;
1840     if (!yasm_symrec_get_label(symrec, &prevbc))
1841         return 0;
1842     return prevbc->offset + prevbc->len;
1843 }
1844 
1845 static void
dosexe_objfmt_output(yasm_object * object,FILE * f,int all_syms,yasm_errwarns * errwarns)1846 dosexe_objfmt_output(yasm_object *object, FILE *f, /*@unused@*/ int all_syms,
1847                   yasm_errwarns *errwarns)
1848 {
1849     unsigned long tot_size, size, bss_size;
1850     unsigned long start, bss;
1851     unsigned char c;
1852 
1853     fseek(f, EXE_HEADER_SIZE, SEEK_SET);
1854 
1855     bin_objfmt_output(object, f, all_syms, errwarns);
1856 
1857     tot_size = ftell(f);
1858 
1859     /* if there is a __bss_start symbol, data after it is 0, no need to write
1860      * it.  */
1861     bss = get_sym(object, "__bss_start");
1862     if (bss)
1863         size = bss;
1864     else
1865         size = tot_size;
1866     bss_size = tot_size - size;
1867 #ifdef HAVE_FTRUNCATE
1868     if (size != tot_size)
1869         ftruncate(fileno(f), EXE_HEADER_SIZE + size);
1870 #endif
1871     fseek(f, 0, SEEK_SET);
1872 
1873     /* magic */
1874     fwrite("MZ", 1, 2, f);
1875 
1876     /* file size */
1877     c = size & 0xff;
1878     fwrite(&c, 1, 1, f);
1879     c = !!(size & 0x100);
1880     fwrite(&c, 1, 1, f);
1881     c = ((size + 511) >> 9) & 0xff;
1882     fwrite(&c, 1, 1, f);
1883     c = ((size + 511) >> 17) & 0xff;
1884     fwrite(&c, 1, 1, f);
1885 
1886     /* relocation # */
1887     c = 0;
1888     fwrite(&c, 1, 1, f);
1889     fwrite(&c, 1, 1, f);
1890 
1891     /* header size */
1892     c = EXE_HEADER_SIZE / 16;
1893     fwrite(&c, 1, 1, f);
1894     c = 0;
1895     fwrite(&c, 1, 1, f);
1896 
1897     /* minimum paragraph # */
1898     bss_size = (bss_size + 15) >> 4;
1899     c = bss_size & 0xff;
1900     fwrite(&c, 1, 1, f);
1901     c = (bss_size >> 8) & 0xff;
1902     fwrite(&c, 1, 1, f);
1903 
1904     /* maximum paragraph # */
1905     c = 0xFF;
1906     fwrite(&c, 1, 1, f);
1907     fwrite(&c, 1, 1, f);
1908 
1909     /* relative value of stack segment */
1910     c = 0;
1911     fwrite(&c, 1, 1, f);
1912     fwrite(&c, 1, 1, f);
1913 
1914     /* SP at start */
1915     c = 0;
1916     fwrite(&c, 1, 1, f);
1917     fwrite(&c, 1, 1, f);
1918 
1919     /* header checksum */
1920     c = 0;
1921     fwrite(&c, 1, 1, f);
1922     fwrite(&c, 1, 1, f);
1923 
1924     /* IP at start */
1925     start = get_sym(object, "start");
1926     if (!start) {
1927         yasm_error_set(YASM_ERROR_GENERAL,
1928                 N_("%s: could not find symbol `start'"));
1929         return;
1930     }
1931     c = start & 0xff;
1932     fwrite(&c, 1, 1, f);
1933     c = (start >> 8) & 0xff;
1934     fwrite(&c, 1, 1, f);
1935 
1936     /* CS start */
1937     c = 0;
1938     fwrite(&c, 1, 1, f);
1939     fwrite(&c, 1, 1, f);
1940 
1941     /* reloc start */
1942     c = 0x22;
1943     fwrite(&c, 1, 1, f);
1944     c = 0;
1945     fwrite(&c, 1, 1, f);
1946 
1947     /* Overlay number */
1948     c = 0;
1949     fwrite(&c, 1, 1, f);
1950     fwrite(&c, 1, 1, f);
1951 }
1952 
1953 
1954 /* Define objfmt structure -- see objfmt.h for details */
1955 yasm_objfmt_module yasm_dosexe_LTX_objfmt = {
1956     "DOS .EXE format binary",
1957     "dosexe",
1958     "exe",
1959     16,
1960     0,
1961     bin_objfmt_dbgfmt_keywords,
1962     "null",
1963     bin_objfmt_directives,
1964     bin_objfmt_stdmacs,
1965     dosexe_objfmt_create,
1966     dosexe_objfmt_output,
1967     bin_objfmt_destroy,
1968     bin_objfmt_add_default_section,
1969     bin_objfmt_init_new_section,
1970     bin_objfmt_section_switch,
1971     bin_objfmt_get_special_sym
1972 };
1973