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