make sure string is 0-terminated
[xorcyst.git] / xlnk.c
blobc130a61dc68005b969ce9ec6e21233e3097b9462
1 /*
2 * $Id: xlnk.c,v 1.20 2007/11/11 22:35:22 khansen Exp $
3 * $Log: xlnk.c,v $
4 * Revision 1.20 2007/11/11 22:35:22 khansen
5 * compile on mac
7 * Revision 1.19 2007/08/12 19:01:11 khansen
8 * xorcyst 1.5.0
10 * Revision 1.18 2007/08/07 22:43:01 khansen
11 * version
13 * Revision 1.17 2007/07/22 13:33:26 khansen
14 * convert tabs to whitespaces
16 * Revision 1.16 2005/01/09 11:19:41 kenth
17 * xorcyst 1.4.5
18 * prints code/data addresses of public symbols when --verbose
20 * Revision 1.15 2005/01/05 09:33:37 kenth
21 * xorcyst 1.4.4
22 * fixed RAM allocator bug
23 * print RAM statistics when --verbose
25 * Revision 1.14 2005/01/05 01:52:19 kenth
26 * xorcyst 1.4.3
28 * Revision 1.13 2005/01/04 21:35:58 kenth
29 * return error code from main() when error count > 0
31 * Revision 1.12 2004/12/29 21:43:55 kenth
32 * xorcyst 1.4.2
34 * Revision 1.11 2004/12/27 06:42:05 kenth
35 * fixed bug in alloc_ram()
37 * Revision 1.10 2004/12/25 02:23:28 kenth
38 * xorcyst 1.4.1
40 * Revision 1.9 2004/12/19 19:58:54 kenth
41 * xorcyst 1.4.0
43 * Revision 1.8 2004/12/18 19:10:39 kenth
44 * relocation improved (I hope)
46 * Revision 1.7 2004/12/18 17:02:00 kenth
47 * CMD_LINE*, CMD_FILE handling, error location printing
48 * CMD_DSW, CMD_DSD gone
50 * Revision 1.6 2004/12/16 13:20:41 kenth
51 * xorcyst 1.3.5
53 * Revision 1.5 2004/12/14 01:50:21 kenth
54 * xorcyst 1.3.0
56 * Revision 1.4 2004/12/11 02:06:18 kenth
57 * xorcyst 1.2.0
59 * Revision 1.3 2004/12/06 04:53:18 kenth
60 * xorcyst 1.1.0
62 * Revision 1.2 2004/06/30 23:38:22 kenth
63 * replaced argp with something else
65 * Revision 1.1 2004/06/30 07:56:04 kenth
66 * Initial revision
68 * Revision 1.1 2004/06/30 07:42:03 kenth
69 * Initial revision
73 /**
74 * (C) 2004 Kent Hansen
76 * The XORcyst is free software; you can redistribute it and/or modify
77 * it under the terms of the GNU General Public License as published by
78 * the Free Software Foundation; either version 2 of the License, or
79 * (at your option) any later version.
81 * The XORcyst is distributed in the hope that it will be useful,
82 * but WITHOUT ANY WARRANTY; without even the implied warranty of
83 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
84 * GNU General Public License for more details.
86 * You should have received a copy of the GNU General Public License
87 * along with The XORcyst; if not, write to the Free Software
88 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
91 /**
92 * This is the 6502 linker program. It takes one or more object files generated
93 * by the 6502 assembler program, and then (rough list)
94 * - maps all data labels to physical 6502 RAM
95 * - relocates code to 6502 address space
96 * - resolves external references
97 * - writes everything to a final binary
99 * The input to the linker is a script file which describes the layout and
100 * contents of the final binary.
103 #include <stdio.h>
104 #include <stdlib.h>
105 #include <stdarg.h>
106 #include <string.h>
107 #include <assert.h>
108 #include "getopt.h"
109 #include "objdef.h"
110 #include "opcode.h"
111 #include "script.h"
112 #include "unit.h"
113 #include "hashtab.h"
115 #define SAFE_FREE(m) if ((m) != NULL) { free(m); m = NULL; }
118 * Parses a string to an integer.
119 * @param s String
120 * @return Integer
122 static int str_to_int(char *s)
124 if (s[0] == '$') {
125 return strtol(&s[1], NULL, 16);
127 else if (s[0] == '%') {
128 return strtol(&s[1], NULL, 2);
130 return strtol(s, NULL, 0);
133 /*--------------------------------------------------------------------------*/
134 /* Argument parsing stuff. */
136 static char program_version[] = "xlnk 1.5.0";
138 struct tag_arguments {
139 char *input_file;
140 int silent;
141 int verbose;
144 typedef struct tag_arguments arguments;
146 /* Argument variables set by arg parser. */
147 static arguments program_args;
149 /* Long options for getopt_long(). */
150 static struct option long_options[] = {
151 { "quiet", no_argument, 0, 'q' },
152 { "silent", no_argument, 0, 's' },
153 { "verbose", no_argument, 0, 'v' },
154 { "help", no_argument, 0, 0 },
155 { "usage", no_argument, 0, 0 },
156 { "version", no_argument, 0, 'V' },
157 { 0 }
160 /* Prints usage message and exits. */
161 static void usage()
163 printf("\
164 Usage: xlnk [-qsvV] [--quiet] [--silent] [--verbose] [--help] [--usage]\n\
165 [--version] FILE\n\
167 exit(0);
170 /* Prints help message and exits. */
171 static void help()
173 printf("\
174 Usage: xlnk [OPTION...] FILE\n\
175 The XORcyst Linker -- it creates quite a stir\n\
177 -q, -s, --quiet, --silent Don't produce any output\n\
178 -v, --verbose Produce verbose output\n\
179 --help Give this help list\n\
180 --usage Give a short usage message\n\
181 -V, --version Print program version\n\
183 Report bugs to <dev@null>.\n\
185 exit(0);
188 /* Prints version and exits. */
189 static void version()
191 printf("%s\n", program_version);
192 exit(0);
195 /* Parses program arguments. */
196 static void
197 parse_arguments (int argc, char **argv)
199 int key;
200 /* getopt_long stores the option index here. */
201 int index = 0;
203 /* Set default values. */
204 program_args.silent = 0;
205 program_args.verbose = 0;
206 program_args.input_file = NULL;
208 /* Parse options. */
209 while ((key = getopt_long(argc, argv, "qsvV", long_options, &index)) != -1) {
210 switch (key) {
211 case 'q': case 's':
212 program_args.silent = 1;
213 break;
215 case 'v':
216 ++program_args.verbose;
217 break;
219 case 0:
220 /* Use index to differentiate between options */
221 if (strcmp(long_options[index].name, "usage") == 0) {
222 usage();
224 else if (strcmp(long_options[index].name, "help") == 0) {
225 help();
227 break;
229 case 'V':
230 version();
231 break;
233 case '?':
234 /* Error message has been printed by getopt_long */
235 exit(1);
236 break;
238 default:
239 /* Forgot to handle a short option, most likely */
240 exit(1);
241 break;
245 /* Must be one additional argument, which is the input file. */
246 if (argc-1 != optind) {
247 printf("Usage: xlnk [OPTION...] FILE\nTry `xlnk --help' or `xlnk --usage' for more information.\n");
248 exit(1);
250 else {
251 program_args.input_file = argv[optind];
255 /*--------------------------------------------------------------------------*/
256 /* Data structures. */
258 /* Describes a local label in the unit. */
259 struct tag_local
261 char *name; /* NULL if not exported */
262 int resolved; /* 0 initially, set to 1 when phys_addr has been assigned */
263 int virt_addr;
264 int phys_addr;
265 int ref_count;
266 int size;
267 struct tag_xunit *owner;
268 unsigned short align;
269 unsigned char flags;
272 typedef struct tag_local local;
274 /* Describes an array of local labels. */
275 struct tag_local_array
277 local *entries;
278 int size;
281 typedef struct tag_local_array local_array;
284 * eXtended unit, has extra info built from basic unit ++
286 struct tag_xunit
288 unit _unit_; /* NB!!! "Superclass", must be first field for casting to work */
289 local_array data_locals;
290 local_array code_locals;
291 int bank_id;
292 int data_size;
293 int code_origin;
294 int code_size;
295 int loaded;
298 typedef struct tag_xunit xunit;
301 * Describes a 6502 RAM block available for allocation.
303 struct tag_avail_ram_block
305 int start; /* Start address in 6502 space */
306 int end; /* End address in 6502 space (not inclusive) */
307 struct tag_avail_ram_block *next;
310 typedef struct tag_avail_ram_block avail_ram_block;
312 /** */
313 struct tag_calc_address_args
315 xunit *xu;
316 int index;
319 typedef struct tag_calc_address_args calc_address_args;
321 /** */
322 struct tag_write_binary_args
324 xunit *xu;
325 FILE *fp;
328 typedef struct tag_write_binary_args write_binary_args;
330 /*--------------------------------------------------------------------------*/
332 /** Array containing the units to link. */
333 static xunit *units;
334 /* Number of units in above array. */
335 static int unit_count;
337 /** Holds the current memory address. */
338 static int pc;
340 /** Hash tables used to lookup symbols. */
341 static hashtab *label_hash;
342 static hashtab *constant_hash;
343 static hashtab *unit_hash;
345 /** Number of errors and warnings during linking */
346 static int err_count;
347 static int warn_count;
349 static int suppress;
351 /* Head of the list of available 6502 RAM blocks (for data allocation). */
352 static avail_ram_block *ram_block_head = NULL;
354 /* Total amount of 6502 RAM (bytes) that was registered */
355 static int total_ram = 0;
357 /* Bank info */
358 static int bank_offset;
359 static int bank_size;
360 static int bank_origin;
361 static int bank_id;
363 /* Debug info */
364 static unsigned char *unit_file = NULL; /* length byte followed by chars */
365 static int unit_line = -1;
367 /* Turn on to produce flat (dis)assembly code. The resulting code can be
368 assembled by xasm using the --pure-binary switch.
369 It's useful for checking that the linker doesn't do anything stupid
370 in binary output mode.
372 static const int generate_assembly = 0;
374 /*--------------------------------------------------------------------------*/
377 * If the object file contains FILE and LINE bytecodes (assembled with
378 * --debug switch), unit_file and unit_line will contain the current
379 * source location. In that case, this function prints the location.
381 static void maybe_print_location()
383 char *str;
384 int len;
385 if (unit_file != NULL) {
386 /* Print source location */
387 len = unit_file[0] + 1;
388 str = (char *)malloc(len + 1);
389 strncpy(str, (char *)&unit_file[1], len);
390 str[len] = '\0';
391 fprintf(stderr, "%s:%d: ", str, unit_line);
392 free(str);
397 * If the object doesn't contain FILE and LINE bytecodes,
398 * unit_file will be <code>NULL</code>. In that case, this
399 * function prints a tip about reassembling with --debug switch.
401 static void maybe_print_debug_tip()
403 if (unit_file == NULL) {
404 fprintf(stderr, "\treassemble with --debug switch to obtain source location\n");
409 * Issues an error.
410 * @param fmt format string for printf
412 static void err(char *fmt, ...)
414 va_list ap;
415 va_start(ap, fmt);
416 if (!suppress) {
417 /* Print error message */
418 fprintf(stderr, "error: ");
419 maybe_print_location();
420 vfprintf(stderr, fmt, ap);
421 fprintf(stderr, "\n");
422 maybe_print_debug_tip();
423 /* Increase total error count */
424 err_count++;
426 va_end(ap);
430 * Issues a warning.
431 * @param fmt format string for printf
433 static void warn(char *fmt, ...)
435 va_list ap;
436 va_start(ap, fmt);
437 if (!suppress) {
438 /* Print warning message */
439 fprintf(stderr, "warning: ");
440 maybe_print_location();
441 vfprintf(stderr, fmt, ap);
442 fprintf(stderr, "\n");
443 maybe_print_debug_tip();
444 /* Increase total warning count */
445 warn_count++;
447 va_end(ap);
451 * Prints a message if --verbose switch was given.
452 * @param level verbosity level
453 * @param fmt format string for printf
455 static void verbose(int level, char *fmt, ...)
457 va_list ap;
458 va_start(ap, fmt);
459 if (!suppress && program_args.verbose >= level) {
460 vfprintf(stdout, fmt, ap);
461 fprintf(stdout, "\n");
463 va_end(ap);
466 /*--------------------------------------------------------------------------*/
467 /* Functions to manage 6502 RAM blocks. */
468 /* The RAM allocator maintains a list of these blocks that are used to
469 map the contents of the units' data segments to memory.
473 * Calculates number of bytes of 6502 RAM left for allocation.
475 static int ram_left()
477 int sum;
478 avail_ram_block *b;
479 for (sum = 0, b = ram_block_head; b != NULL; b = b->next) {
480 sum += b->end - b->start;
482 return sum;
486 * Adds a block of 6502 memory to the list of available memory regions.
487 * When adding multiple blocks they should be added in prioritized order.
488 * @param start Start address of the block
489 * @param end End address of the block (non-inclusive!)
491 static void add_ram_block(int start, int end)
493 avail_ram_block *b;
494 /* Allocate a block struct */
495 avail_ram_block *new_block = (avail_ram_block *)malloc( sizeof(avail_ram_block) );
496 if (new_block != NULL) {
497 /* Set the fields */
498 new_block->start = start;
499 new_block->end = end;
500 new_block->next = NULL;
501 /* Add it to list */
502 if (ram_block_head == NULL) {
503 /* Start the list */
504 ram_block_head = new_block;
506 else {
507 /* Add to end */
508 for (b = ram_block_head; b->next != NULL; b = b->next) ;
509 b->next = new_block;
511 verbose(1, " added RAM block: %.4X-%.4X", new_block->start, new_block->end);
516 * Allocates a chunk of 6502 RAM to a local.
517 * @param l Local
518 * @return 0 if there isn't enough RAM to satisfy the request (fail), 1 otherwise (success)
520 static int alloc_ram(local *l)
522 /* Try the available blocks in order. */
523 /* Use the first one that's sufficient. */
524 avail_ram_block *b;
525 avail_ram_block *p = NULL;
526 for (b = ram_block_head; b != NULL; p = b, b = b->next) {
527 int left;
528 int pad;
529 avail_ram_block *n;
530 /* Check if zero page block required */
531 if (l->flags & LABEL_FLAG_ZEROPAGE) {
532 if (b->start >= 0x100) {
533 continue; /* This block is no good */
536 /* Calculate the # of bytes left in this block */
537 left = b->end - b->start;
538 /* See if it's enough */
539 if (left < l->size) {
540 continue; /* Not enough, sorry */
542 /* Check if alignment required */
543 if (l->flags & LABEL_FLAG_ALIGN) {
544 pad = b->start & ((1 << l->align) - 1);
545 if (pad != 0) {
546 /* This block doesn't match the alignment */
547 /* Break it into two blocks if possible */
548 pad = (1 << l->align) - pad;
549 pad = (left < pad) ? left : pad;
550 if (pad < left) {
551 n = (avail_ram_block *)malloc(sizeof(avail_ram_block));
552 n->start = b->start;
553 n->end = n->start + pad;
554 b->start += pad;
555 n->next = b;
556 if (b == ram_block_head) {
557 ram_block_head = n; /* New head */
559 b = n;
561 continue;
564 /* Pick this one. */
565 l->phys_addr = b->start;
566 /* Decrease block size by moving start address ahead */
567 b->start += l->size;
568 /* If there's no more space left in this block, discard it */
569 if (left == l->size) {
570 /* Remove from linked list */
571 if (p == NULL) {
572 /* Set successor block as new head */
573 ram_block_head = b->next;
575 else {
576 /* Squeeze out */
577 p->next = b->next;
579 /* Free associated memory */
580 SAFE_FREE(b);
582 /* Return with success */
583 return 1;
585 /* Couldn't find a block large enough, return with failure */
586 return 0;
590 * Frees up memory associated with list of RAM blocks.
592 static void finalize_ram_blocks()
594 avail_ram_block *b;
595 avail_ram_block *t;
596 for (b = ram_block_head; b != NULL; b = t) {
597 t = b->next;
598 SAFE_FREE(b);
602 /*--------------------------------------------------------------------------*/
603 /* Functions to get big-endian values from byte buffer. */
605 /* Gets single byte from buffer and increments index. */
606 static unsigned char get_1(unsigned char *b, int *i)
608 return b[(*i)++];
610 /* Gets big-endian short from buffer and increments index. */
611 static unsigned short get_2(unsigned char *b, int *i)
613 unsigned short result = get_1(b, i) << 8;
614 result |= get_1(b, i);
615 return result;
617 /* Gets big-endian 24-bit integer from buffer and increments index. */
618 static unsigned int get_3(unsigned char *b, int *i)
620 unsigned int result = get_2(b, i) << 8;
621 result |= get_1(b, i);
622 return result;
624 /* Gets big-endian int from buffer and increments index. */
625 /*static unsigned int get_4(unsigned char *b, int *i)
627 unsigned int result = get_2(b, i) << 16;
628 result |= get_2(b, i);
629 return result;
632 /*--------------------------------------------------------------------------*/
635 * Calculates the storage occupied by a CMD_LABEL bytecode's arguments.
637 static int label_cmd_args_size(unsigned char *bytes)
639 int size = 1; /* Smallest possible: flag byte */
640 int flags = bytes[0];
641 if (flags & LABEL_FLAG_EXPORT) { size += bytes[1] + 1 + 1; } /* Length byte + string */
642 if (flags & LABEL_FLAG_ALIGN) { size += 1; } /* Alignment */
643 if (flags & LABEL_FLAG_ADDR) { size += 2; } /* Address */
644 return size;
647 /** Signature for procedure to process a bytecode */
648 typedef void (*bytecodeproc)(unsigned char *, void *);
651 * Walks an array of bytecodes, calling corresponding bytecode handlers
652 * along the way.
653 * @param bytes Array of bytecodes, terminated by CMD_END
654 * @param handlers Array of bytecode handlers (entries can be NULL)
655 * @param arg Argument passed to bytecode handler, can be anything
657 static void bytecode_walk(unsigned char *bytes, bytecodeproc *handlers, void *arg)
659 int i;
660 unsigned char cmd;
661 unit_file = NULL;
662 unit_line = -1;
663 if (bytes == NULL) { return; }
664 i = 0;
665 do {
666 /* Get a command */
667 cmd = get_1(bytes, &i);
669 /* Check if debug command */
670 if (cmd < CMD_END) {
671 switch (cmd) {
672 case CMD_FILE:
673 unit_file = &bytes[i];
674 i += get_1(bytes, &i) + 1; /* Skip count and array of bytes */
675 break;
676 case CMD_LINE8: unit_line = get_1(bytes, &i); break;
677 case CMD_LINE16: unit_line = get_2(bytes, &i); break;
678 case CMD_LINE24: unit_line = get_3(bytes, &i); break;
679 case CMD_LINE_INC: unit_line++; break;
681 continue;
684 /* Call bytecode handler if one is present */
685 if (handlers[cmd-CMD_END] != NULL) {
686 handlers[cmd-CMD_END](&bytes[i-1], arg);
688 /* Skip any bytecode arguments */
689 switch (cmd) {
690 case CMD_END: break;
691 case CMD_BIN8: i += get_1(bytes, &i) + 1; break; /* Skip count and array of bytes */
692 case CMD_BIN16: i += get_2(bytes, &i) + 1; break; /* Skip count and array of bytes */
693 case CMD_LABEL: i += label_cmd_args_size(&bytes[i]); break; /* Skip flag byte and possibly name and alignment */
694 case CMD_INSTR: i += 3; break; /* Skip 6502 opcode and 16-bit expr id */
695 case CMD_DB: i += 2; break; /* Skip 16-bit expr id */
696 case CMD_DW: i += 2; break; /* Skip 16-bit expr id */
697 case CMD_DD: i += 2; break; /* Skip 16-bit expr id */
698 case CMD_DSI8: i += 1; break; /* Skip 8-bit count */
699 case CMD_DSI16: i += 2; break; /* Skip 16-bit count */
700 case CMD_DSB: i += 2; break; /* Skip 16-bit expr id */
702 default:
703 /* Invalid opcode */
704 err("invalid bytecode");
705 break;
707 } while (cmd != CMD_END);
710 /*--------------------------------------------------------------------------*/
711 /* Functions for expression evaluation. */
714 * Finalizes a constant.
715 * @param c Constant to finalize
717 static void finalize_constant(constant *c)
719 if (c->type == STRING_CONSTANT) {
720 SAFE_FREE(c->string);
725 * Gets string representation of an operator (OP_*, see objdef.h).
726 * @param op Operator
727 * @return String representation of operator
729 static const char *operator_to_string(int op)
731 switch (op) {
732 case OP_PLUS: return "+";
733 case OP_MINUS: return "-";
734 case OP_MUL: return "*";
735 case OP_DIV: return "/";
736 case OP_MOD: return "%";
737 case OP_SHL: return "<<";
738 case OP_SHR: return ">>";
739 case OP_AND: return "&";
740 case OP_OR: return "|";
741 case OP_XOR: return "^";
742 case OP_EQ: return "==";
743 case OP_NE: return "!=";
744 case OP_LT: return "<";
745 case OP_GT: return ">";
746 case OP_LE: return "<=";
747 case OP_GE: return ">=";
748 case OP_NOT: return "!";
749 case OP_NEG: return "~";
750 case OP_LO: return "<";
751 case OP_HI: return ">";
752 case OP_UMINUS: return "-";
753 case OP_BANK: return "^";
755 return "";
759 * Evaluates an expression recursively.
760 * The result will either be a integer or string literal, indicating successful
761 * evaluation; or an invalid type indicating that a symbol could not be translated
762 * to a constant (in other words, it could not be resolved). In this case,
763 * result->string contains the name of the symbol which couldn't be evaluated.
764 * @param u The unit where the expression is contained
765 * @param e The expression to evaluate
766 * @param result Pointer to resulting value
768 static void eval_recursive(xunit *u, expression *e, constant *result)
770 char *s;
771 local *l;
772 constant *c;
773 constant lhs_result, rhs_result;
774 switch (e->type) {
775 case OPERATOR_EXPRESSION:
776 switch (e->op_expr.operator) {
777 /* Binary operators */
778 case OP_PLUS:
779 case OP_MINUS:
780 case OP_MUL:
781 case OP_DIV:
782 case OP_MOD:
783 case OP_SHL:
784 case OP_SHR:
785 case OP_AND:
786 case OP_OR:
787 case OP_XOR:
788 case OP_EQ:
789 case OP_NE:
790 case OP_LT:
791 case OP_GT:
792 case OP_LE:
793 case OP_GE:
794 /* Evaluate both sides */
795 eval_recursive(u, e->op_expr.lhs, &lhs_result);
796 eval_recursive(u, e->op_expr.rhs, &rhs_result);
797 /* If either side is unresolved, then result is unresolved. */
798 if ((lhs_result.type == -1) || (rhs_result.type == -1)) {
799 result->type = -1;
801 /* If both sides are integer, then result is integer. */
802 else if ((lhs_result.type == INTEGER_CONSTANT) &&
803 (rhs_result.type == INTEGER_CONSTANT)) {
804 result->type = INTEGER_CONSTANT;
805 /* Perform the proper operation to obtain result. */
806 switch (e->op_expr.operator) {
807 case OP_PLUS: result->integer = lhs_result.integer + rhs_result.integer; break;
808 case OP_MINUS: result->integer = lhs_result.integer - rhs_result.integer; break;
809 case OP_MUL: result->integer = lhs_result.integer * rhs_result.integer; break;
810 case OP_DIV: result->integer = lhs_result.integer / rhs_result.integer; break;
811 case OP_MOD: result->integer = lhs_result.integer % rhs_result.integer; break;
812 case OP_SHL: result->integer = lhs_result.integer << rhs_result.integer; break;
813 case OP_SHR: result->integer = lhs_result.integer >> rhs_result.integer; break;
814 case OP_AND: result->integer = lhs_result.integer & rhs_result.integer; break;
815 case OP_OR: result->integer = lhs_result.integer | rhs_result.integer; break;
816 case OP_XOR: result->integer = lhs_result.integer ^ rhs_result.integer; break;
817 case OP_EQ: result->integer = lhs_result.integer == rhs_result.integer; break;
818 case OP_NE: result->integer = lhs_result.integer != rhs_result.integer; break;
819 case OP_LT: result->integer = lhs_result.integer < rhs_result.integer; break;
820 case OP_GT: result->integer = lhs_result.integer > rhs_result.integer; break;
821 case OP_LE: result->integer = lhs_result.integer <= rhs_result.integer; break;
822 case OP_GE: result->integer = lhs_result.integer >= rhs_result.integer; break;
825 /* If both sides are string... */
826 else if ((lhs_result.type == STRING_CONSTANT) &&
827 (rhs_result.type == STRING_CONSTANT)) {
828 switch (e->op_expr.operator) {
829 case OP_PLUS:
830 /* Concatenate */
831 result->string = (char *)malloc(strlen(lhs_result.string)+strlen(rhs_result.string)+1);
832 if (result->string != NULL) {
833 strcpy(result->string, lhs_result.string);
834 strcat(result->string, rhs_result.string);
835 result->type = STRING_CONSTANT;
837 break;
839 /* String comparison: using strcmp() */
840 case OP_EQ: result->integer = strcmp(lhs_result.string, rhs_result.string) == 0; break;
841 case OP_NE: result->integer = strcmp(lhs_result.string, rhs_result.string) != 0; break;
842 case OP_LT: result->integer = strcmp(lhs_result.string, rhs_result.string) < 0; break;
843 case OP_GT: result->integer = strcmp(lhs_result.string, rhs_result.string) > 0; break;
844 case OP_LE: result->integer = strcmp(lhs_result.string, rhs_result.string) <= 0; break;
845 case OP_GE: result->integer = strcmp(lhs_result.string, rhs_result.string) >= 0; break;
847 default:
848 /* Not defined operator for string operation... */
849 break;
852 else {
853 /* Error, operands are incompatible */
854 result->type = -1;
855 err("incompatible operands to `%s' in expression", operator_to_string(e->op_expr.operator) );
857 /* Discard the operands */
858 finalize_constant(&lhs_result);
859 finalize_constant(&rhs_result);
860 break; /* Binary operator */
862 /* Unary operators */
863 case OP_NOT:
864 case OP_NEG:
865 case OP_LO:
866 case OP_HI:
867 case OP_UMINUS:
868 /* Evaluate the single operand */
869 eval_recursive(u, e->op_expr.lhs, &lhs_result);
870 /* If operand is unresolved then result is unresolved. */
871 if (lhs_result.type == -1) {
872 result->type = -1;
874 /* If operand is integer then result is integer. */
875 else if (lhs_result.type == INTEGER_CONSTANT) {
876 result->type = INTEGER_CONSTANT;
877 /* Perform the proper operation to obtain result. */
878 switch (e->op_expr.operator) {
879 case OP_NOT: result->integer = !lhs_result.integer; break;
880 case OP_NEG: result->integer = ~lhs_result.integer; break;
881 case OP_LO: result->integer = lhs_result.integer & 0xFF; break;
882 case OP_HI: result->integer = (lhs_result.integer >> 8) & 0xFF; break;
883 case OP_UMINUS: result->integer = -lhs_result.integer; break;
886 else {
887 /* Error, invalid operand */
888 err("incompatible operand to `%s' in expression", operator_to_string(e->op_expr.operator) );
889 result->type = -1;
891 /* Discard the operand */
892 finalize_constant(&lhs_result);
893 break; /* Unary operator */
895 case OP_BANK:
896 switch (e->op_expr.lhs->type) {
897 case LOCAL_EXPRESSION:
898 /* Simple, it must be in the same (current) bank */
899 result->integer = bank_id;
900 result->type = INTEGER_CONSTANT;
901 break;
903 case EXTERNAL_EXPRESSION:
904 /* Get the name of the external */
905 s = u->_unit_.externals[e->op_expr.lhs->extrn_id].name;
906 /* Look it up */
907 if ((l = (local *)hashtab_get(label_hash, s)) != NULL) {
908 /* It's a label */
909 result->integer = l->owner->bank_id;
910 result->type = INTEGER_CONSTANT;
912 else if ((c = (constant *)hashtab_get(constant_hash, s)) != NULL) {
913 /* It's a constant */
914 result->integer = ((xunit *)c->unit)->bank_id;
915 result->type = INTEGER_CONSTANT;
917 else {
918 result->type = -1;
920 break;
922 default:
923 result->type = -1;
924 break;
926 break;
928 break;
930 case INTEGER_EXPRESSION:
931 /* Copy value to result */
932 result->type = INTEGER_CONSTANT;
933 result->integer = e->integer;
934 break;
936 case STRING_EXPRESSION:
937 /* Copy value to result */
938 result->string = (char *)malloc(strlen(e->string) + 1);
939 if (result->string != NULL) {
940 strcpy(result->string, e->string);
941 result->type = STRING_CONSTANT;
943 break;
945 case LOCAL_EXPRESSION:
946 if (e->local_id >= u->data_locals.size) {
947 /* It's a code local */
948 l = &u->code_locals.entries[e->local_id - u->data_locals.size];
950 else {
951 /* It's a data local */
952 l = &u->data_locals.entries[e->local_id];
954 /* Test if it's resolved */
955 if (l->resolved) {
956 /* Copy address to result */
957 result->type = INTEGER_CONSTANT;
958 result->integer = l->phys_addr;
960 else {
961 /* Not resolved (yet, at least) */
962 result->type = -1;
964 break;
966 case EXTERNAL_EXPRESSION:
967 /* Get the name of the external */
968 s = u->_unit_.externals[e->extrn_id].name;
969 /* Look it up */
970 if ((l = (local *)hashtab_get(label_hash, s)) != NULL) {
971 /* It's a label */
972 /* Test if it's resolved */
973 if (l->resolved) {
974 /* Copy address to result */
975 result->type = INTEGER_CONSTANT;
976 result->integer = l->phys_addr;
978 else {
979 /* Not resolved (yet) */
980 result->type = -1;
983 else if ((c = (constant *)hashtab_get(constant_hash, s)) != NULL) {
984 /* It's a constant */
985 /* Copy value to result */
986 switch (c->type) {
987 case INTEGER_CONSTANT:
988 result->type = INTEGER_CONSTANT;
989 result->integer = c->integer;
990 break;
992 case STRING_CONSTANT:
993 result->string = (char *)malloc(strlen(c->string) + 1);
994 if (result->string != NULL) {
995 strcpy(result->string, c->string);
996 result->type = STRING_CONSTANT;
998 break;
1001 else {
1002 /* Error */
1003 result->type = -1;
1004 err("unknown symbol `%s' referenced from %s", s, u->_unit_.name);
1006 break;
1008 case PC_EXPRESSION:
1009 /* Copy current PC to result */
1010 result->type = INTEGER_CONSTANT;
1011 result->integer = pc;
1012 break;
1017 * Evaluates an expression.
1018 * @param u The unit where the expression is contained
1019 * @param exid The unique ID of the expression
1020 * @param result Where to store the result of the evaluation
1022 static void eval_expression(xunit *u, int exid, constant *result)
1024 /* Get the expression with id exid */
1025 expression *exp = u->_unit_.expressions[exid];
1026 /* Evaluate recursively */
1027 eval_recursive(u, exp, result);
1030 /*--------------------------------------------------------------------------*/
1031 /* Functions for incrementing PC, with error handling for wraparound. */
1034 * Increases PC by amount.
1035 * Issues error if the PC wraps around.
1037 static void inc_pc(int amount, void *arg)
1039 calc_address_args *aargs;
1040 /* Check for 16-bit overflow */
1041 if ((pc <= 0x10000) && ((pc+amount) > 0x10000)) {
1042 aargs = (calc_address_args *)arg;
1043 err("PC went beyond 64K when linking `%s'", aargs->xu->_unit_.name);
1045 /* Add! */
1046 pc += amount;
1050 * Increases PC by 8-bit value immediately following bytecode command.
1052 static void inc_pc_count8(unsigned char *b, void *arg)
1054 int i = 1;
1055 inc_pc( get_1(b, &i) + 1, arg );
1059 * Increases PC by 16-bit value immediately following bytecode command.
1061 static void inc_pc_count16(unsigned char *b, void *arg)
1063 int i = 1;
1064 inc_pc( get_2(b, &i) + 1, arg );
1068 * Increases PC by 1.
1070 static void inc_pc_1(unsigned char *b, void *arg)
1072 inc_pc( 1, arg );
1076 * Increases PC by 2.
1078 static void inc_pc_2(unsigned char *b, void *arg)
1080 inc_pc( 2, arg );
1084 * Increases PC by 4.
1086 static void inc_pc_4(unsigned char *b, void *arg)
1088 inc_pc( 4, arg );
1092 * Increases PC according to size of define data command.
1094 static void inc_pc_dsb(unsigned char *b, void *arg)
1096 constant c;
1097 int exid;
1098 calc_address_args *args = (calc_address_args *)arg;
1099 int i = 1;
1100 /* Get expression ID */
1101 exid = get_2(b, &i);
1102 /* Evaluate expression */
1103 eval_expression(args->xu, exid, &c);
1104 /* Handle the result */
1105 if (c.type == INTEGER_CONSTANT) {
1106 /* An array of bytes will be located here */
1107 /* Advance PC appropriately */
1108 inc_pc( c.integer, arg );
1110 else if (c.type == STRING_CONSTANT) {
1111 /* Error, doesn't make sense here */
1112 err("unexpected string operand (`%s') to storage directive", c.string);
1114 else {
1115 /* Error, unresolved */
1116 //err("unresolved symbol");
1117 assert(0);
1120 finalize_constant(&c);
1124 * Increments PC according to the length of this instruction.
1126 static void inc_pc_instr(unsigned char *b, void *arg)
1128 constant c;
1129 unsigned char op, t;
1130 int exid;
1131 calc_address_args *args = (calc_address_args *)arg;
1132 /* Get opcode */
1133 int i = 1;
1134 op = get_1(b, &i);
1135 /* Get expression ID */
1136 exid = get_2(b, &i);
1137 /* Evaluate it */
1138 eval_expression(args->xu, exid, &c);
1139 /* Handle the result */
1140 if (c.type == INTEGER_CONSTANT) {
1141 /* See if it can be reduced to ZP instruction */
1142 if ((c.integer < 0x100) &&
1143 ((t = opcode_zp_equiv(op)) != 0xFF)) {
1144 /* replace op by ZP-version */
1145 op = t;
1146 b[1] = t;
1149 else if (c.type == STRING_CONSTANT) {
1150 /* Error, string operand doesn't make sense here */
1151 err("invalid instruction operand (string)");
1153 else {
1154 /* Address not available yet (forward reference). */
1155 //err("unresolved symbol");
1157 /* Advance PC */
1158 inc_pc( opcode_length(op), arg );
1161 /*--------------------------------------------------------------------------*/
1162 /* Functions for writing pure 6502 binary from bytecodes. */
1165 * Writes an array of bytes.
1167 static void write_bin8(unsigned char *b, void *arg)
1169 int count;
1170 int i;
1171 write_binary_args *args = (write_binary_args *)arg;
1172 /* Get 8-bit count */
1173 i = 1;
1174 count = get_1(b, &i) + 1;
1175 /* Write data */
1176 fwrite(&b[i], 1, count, args->fp);
1177 /* Advance PC */
1178 inc_pc( count, arg );
1182 * Writes an array of bytes.
1184 static void write_bin16(unsigned char *b, void *arg)
1186 int count;
1187 int i;
1188 write_binary_args *args = (write_binary_args *)arg;
1189 /* Get 16-bit count */
1190 i = 1;
1191 count = get_2(b, &i) + 1;
1192 /* Write data */
1193 fwrite(&b[i], 1, count, args->fp);
1194 /* Advance PC */
1195 inc_pc( count, arg );
1199 * Writes an instruction.
1201 static void write_instr(unsigned char *b, void *arg)
1203 constant c;
1204 unsigned char op;
1205 int i;
1206 int exid;
1207 write_binary_args *args = (write_binary_args *)arg;
1208 /* Get opcode */
1209 i = 1;
1210 op = get_1(b, &i);
1211 assert(opcode_length(op) > 1);
1212 /* Get expression ID */
1213 exid = get_2(b, &i);
1214 /* Evaluate expression */
1215 eval_expression(args->xu, exid, &c);
1216 assert(c.type == INTEGER_CONSTANT);
1217 /* Write the opcode */
1218 fputc(op, args->fp);
1219 if (opcode_length(op) == 2) {
1220 /* Operand must fit in 1 byte */
1221 /* Check if it's a relative jump */
1222 switch (op) {
1223 case 0x10:
1224 case 0x30:
1225 case 0x50:
1226 case 0x70:
1227 case 0x90:
1228 case 0xB0:
1229 case 0xD0:
1230 case 0xF0:
1231 /* Calculate difference between target and address of next instruction */
1232 c.integer = c.integer - (pc + 2);
1233 /* Make sure jump is in range */
1234 if ( (c.integer < -128) || (c.integer > 127) ) {
1235 err("branch out of range");
1237 /* Make it a byte value */
1238 c.integer &= 0xFF;
1239 break;
1241 if (c.integer >= 0x100) {
1242 err("instruction operand doesn't fit in 1 byte");
1244 else {
1245 /* Write it */
1246 fputc(c.integer, args->fp);
1248 } else {
1249 assert(opcode_length(op) == 3);
1250 /* Operand must fit in 2 bytes */
1251 if (c.integer >= 0x10000) {
1252 err("instruction operand doesn't fit in 2 bytes");
1254 else {
1255 /* Write it, low byte first */
1256 fputc(c.integer, args->fp);
1257 fputc(c.integer >> 8, args->fp);
1260 /* Advance PC */
1261 inc_pc( opcode_length(op), arg );
1265 * Writes a byte, word or dword.
1267 static void write_dx(unsigned char *b, void *arg)
1269 constant c;
1270 int i;
1271 int exid;
1272 write_binary_args *args = (write_binary_args *)arg;
1273 /* Get expression ID */
1274 i = 1;
1275 exid = get_2(b, &i);
1276 /* Evaluate expression */
1277 eval_expression(args->xu, exid, &c);
1279 if (c.type == INTEGER_CONSTANT) {
1280 /* Write low byte */
1281 fputc(c.integer, args->fp);
1282 /* If 2+ bytes, write high ones */
1283 switch (b[0]) {
1284 case CMD_DB:
1285 if (c.integer > 0xFF) {
1286 warn("`.DB' operand $%X out of range; truncated", c.integer);
1288 break;
1290 case CMD_DW:
1291 fputc(c.integer >> 8, args->fp);
1292 if (c.integer > 0xFFFF) {
1293 warn("`.DW' operand $%X out of range; truncated", c.integer);
1295 break;
1297 case CMD_DD:
1298 fputc(c.integer >> 8, args->fp);
1299 fputc(c.integer >> 16, args->fp);
1300 fputc(c.integer >> 24, args->fp);
1301 break;
1303 /* Advance PC */
1304 switch (b[0]) {
1305 case CMD_DB: inc_pc( 1, arg ); break;
1306 case CMD_DW: inc_pc( 2, arg ); break;
1307 case CMD_DD: inc_pc( 4, arg ); break;
1310 else if (c.type == STRING_CONSTANT) {
1311 /* Write sequence of characters */
1312 for (i=0; i<strlen(c.string); i++) {
1313 /* Write low byte */
1314 fputc(c.string[i], args->fp);
1315 /* If 2+ bytes, write high ones */
1316 switch (b[0]) {
1317 case CMD_DW:
1318 fputc(0, args->fp);
1319 break;
1321 case CMD_DD:
1322 fputc(0, args->fp);
1323 fputc(0, args->fp);
1324 fputc(0, args->fp);
1325 break;
1327 /* Advance PC */
1328 switch (b[0]) {
1329 case CMD_DB: inc_pc( 1, arg ); break;
1330 case CMD_DW: inc_pc( 2, arg ); break;
1331 case CMD_DD: inc_pc( 4, arg ); break;
1334 } else {
1335 assert(0);
1338 finalize_constant(&c);
1342 * Writes a series of zeroes.
1344 static void write_dsi8(unsigned char *b, void *arg)
1346 int count;
1347 int i;
1348 write_binary_args *args = (write_binary_args *)arg;
1349 /* Get 8-bit count */
1350 i = 1;
1351 count = get_1(b, &i) + 1;
1352 /* Write zeroes */
1353 for (i=0; i<count; i++) {
1354 fputc(0, args->fp);
1356 /* Advance PC */
1357 inc_pc( count, arg );
1361 * Writes a series of zeroes.
1363 static void write_dsi16(unsigned char *b, void *arg)
1365 int count;
1366 int i;
1367 write_binary_args *args = (write_binary_args *)arg;
1368 /* Get 16-bit count */
1369 i = 1;
1370 count = get_2(b, &i) + 1;
1371 /* Write zeroes */
1372 for (i=0; i<count; i++) {
1373 fputc(0, args->fp);
1375 /* Advance PC */
1376 inc_pc( count, arg );
1380 * Writes a series of zeroes.
1382 static void write_dsb(unsigned char *b, void *arg)
1384 constant c;
1385 int i;
1386 int exid;
1387 write_binary_args *args = (write_binary_args *)arg;
1388 /* Get expression ID */
1389 i = 1;
1390 exid = get_2(b, &i);
1391 /* Evaluate expression */
1392 eval_expression(args->xu, exid, &c);
1393 assert(c.type == INTEGER_CONSTANT);
1394 if (c.integer < 0) {
1395 err("negative count");
1396 } else if (c.integer > 0) {
1397 /* Write zeroes */
1398 for (i=0; i<c.integer; i++) {
1399 fputc(0, args->fp);
1401 /* Advance PC */
1402 inc_pc( c.integer, arg );
1407 * Writes a code segment as fully native 6502 code.
1408 * @param fp File handle
1409 * @param u Unit whose code to write
1411 static void write_as_binary(FILE *fp, xunit *u)
1413 write_binary_args args;
1414 /* Table of callback functions for our purpose. */
1415 bytecodeproc handlers[] =
1417 NULL, /* CMD_END */
1418 write_bin8, /* CMD_BIN8 */
1419 write_bin16, /* CMD_BIN16 */
1420 NULL, /* CMD_LABEL */
1421 write_instr, /* CMD_INSTR */
1422 write_dx, /* CMD_DB */
1423 write_dx, /* CMD_DW */
1424 write_dx, /* CMD_DD */
1425 write_dsi8, /* CMD_DSI8 */
1426 write_dsi16, /* CMD_DSI16 */
1427 write_dsb /* CMD_DSB */
1429 /* Fill in args */
1430 args.xu = u;
1431 args.fp = fp;
1432 /* Reset PC */
1433 pc = u->code_origin;
1434 /* Do the walk */
1435 bytecode_walk(u->_unit_.codeseg.bytes, handlers, (void *)&args);
1438 /*--------------------------------------------------------------------------*/
1439 /* Functions for writing 6502 assembly from bytecodes. */
1442 Prints \a size bytes of data defined by \a buf to \a out.
1444 static void print_chunk(FILE *out, const char *label,
1445 const unsigned char *buf, int size, int cols)
1447 int i, j, m;
1448 int pos = 0;
1449 if (label)
1450 fprintf(out, "%s:\n", label);
1451 for (i = 0; i < size / cols; ++i) {
1452 fprintf(out, ".DB ");
1453 for (j = 0; j < cols-1; ++j)
1454 fprintf(out, "$%.2X,", buf[pos++]);
1455 fprintf(out, "$%.2X\n", buf[pos++]);
1457 m = size % cols;
1458 if (m > 0) {
1459 fprintf(out, ".DB ");
1460 for (j = 0; j < m-1; ++j)
1461 fprintf(out, "$%.2X,", buf[pos++]);
1462 fprintf(out, "$%.2X\n", buf[pos++]);
1467 * Writes an array of bytes.
1469 static void asm_write_bin8(unsigned char *b, void *arg)
1471 int count;
1472 int i;
1473 write_binary_args *args = (write_binary_args *)arg;
1474 /* Get 8-bit count */
1475 i = 1;
1476 count = get_1(b, &i) + 1;
1477 /* Write data */
1478 // fprintf(args->fp, "; %d byte(s)\n", count);
1479 print_chunk(args->fp, /*label=*/0, &b[i], count, /*cols=*/16);
1480 /* Advance PC */
1481 inc_pc( count, arg );
1485 * Writes an array of bytes.
1487 static void asm_write_bin16(unsigned char *b, void *arg)
1489 int count;
1490 int i;
1491 write_binary_args *args = (write_binary_args *)arg;
1492 /* Get 16-bit count */
1493 i = 1;
1494 count = get_2(b, &i) + 1;
1495 /* Write data */
1496 // fprintf(args->fp, "; %d byte(s)\n", count);
1497 print_chunk(args->fp, /*label=*/0, &b[i], count, /*cols=*/16);
1498 /* Advance PC */
1499 inc_pc( count, arg );
1503 * Writes a label.
1505 static void asm_write_label(unsigned char *b, void *arg)
1507 unsigned char flags;
1508 int i= 1;
1509 write_binary_args *args = (write_binary_args *)arg;
1510 fprintf(args->fp, "; label");
1511 flags = get_1(b, &i);
1512 if (flags & LABEL_FLAG_EXPORT) {
1513 /* Read and print the name */
1514 char *name;
1515 int len = get_1(b, &i) + 1;
1516 name = (char *)malloc( len + 1 );
1517 assert(name != 0);
1518 memcpy(name, &b[i], len);
1519 name[len] = '\0';
1520 i += len;
1521 fprintf(args->fp, " %s (PC=$%.4X)", name, pc);
1522 free(name);
1523 } else {
1524 fprintf(args->fp, " PC=$%.4X", pc);
1526 fprintf(args->fp, "\n");
1530 * Writes an instruction.
1532 static void asm_write_instr(unsigned char *b, void *arg)
1534 constant c;
1535 unsigned char op;
1536 addressing_mode mode;
1537 int i;
1538 int exid;
1539 write_binary_args *args = (write_binary_args *)arg;
1540 /* Get opcode */
1541 i = 1;
1542 op = get_1(b, &i);
1543 assert(opcode_length(op) > 1);
1544 mode = opcode_addressing_mode(op);
1545 assert(mode != INVALID_MODE);
1546 /* Get expression ID */
1547 exid = get_2(b, &i);
1548 /* Evaluate expression */
1549 eval_expression(args->xu, exid, &c);
1550 assert(c.type == INTEGER_CONSTANT);
1551 /* Write the opcode */
1552 fprintf(args->fp, "%s", opcode_to_string(op));
1553 switch (mode) {
1554 case IMPLIED_MODE:
1555 case ACCUMULATOR_MODE:
1556 break;
1557 case IMMEDIATE_MODE:
1558 fprintf(args->fp, " #$");
1559 break;
1560 case ZEROPAGE_MODE:
1561 case ZEROPAGE_X_MODE:
1562 case ZEROPAGE_Y_MODE:
1563 case ABSOLUTE_MODE:
1564 case ABSOLUTE_X_MODE:
1565 case ABSOLUTE_Y_MODE:
1566 fprintf(args->fp, " $");
1567 break;
1568 case PREINDEXED_INDIRECT_MODE:
1569 case POSTINDEXED_INDIRECT_MODE:
1570 case INDIRECT_MODE:
1571 fprintf(args->fp, " [$");
1572 break;
1573 case RELATIVE_MODE:
1574 fprintf(args->fp, " $");
1575 break;
1576 case INVALID_MODE:
1577 break;
1579 /* Write the operand */
1580 fprintf(args->fp, "%.4X", (unsigned)c.integer);
1581 switch (mode) {
1582 case IMPLIED_MODE:
1583 case ACCUMULATOR_MODE:
1584 case IMMEDIATE_MODE:
1585 case ZEROPAGE_MODE:
1586 break;
1587 case ZEROPAGE_X_MODE:
1588 fprintf(args->fp, ",X");
1589 break;
1590 case ZEROPAGE_Y_MODE:
1591 fprintf(args->fp, ",Y");
1592 break;
1593 case ABSOLUTE_MODE:
1594 break;
1595 case ABSOLUTE_X_MODE:
1596 fprintf(args->fp, ",X");
1597 break;
1598 case ABSOLUTE_Y_MODE:
1599 fprintf(args->fp, ",Y");
1600 break;
1601 case PREINDEXED_INDIRECT_MODE:
1602 fprintf(args->fp, ",X]");
1603 break;
1604 case POSTINDEXED_INDIRECT_MODE:
1605 fprintf(args->fp, "],Y");
1606 break;
1607 case INDIRECT_MODE:
1608 fprintf(args->fp, "]");
1609 break;
1610 case RELATIVE_MODE:
1611 break;
1612 case INVALID_MODE:
1613 break;
1615 /* Write newline */
1616 fprintf(args->fp, "\n");
1617 /* Advance PC */
1618 inc_pc( opcode_length(op), arg );
1622 * Writes a byte, word or dword.
1624 static void asm_write_dx(unsigned char *b, void *arg)
1626 constant c;
1627 int i;
1628 int exid;
1629 write_binary_args *args = (write_binary_args *)arg;
1630 /* Get expression ID */
1631 i = 1;
1632 exid = get_2(b, &i);
1633 /* Evaluate expression */
1634 eval_expression(args->xu, exid, &c);
1635 if (c.type == INTEGER_CONSTANT) {
1636 switch (b[0]) {
1637 case CMD_DB:
1638 fprintf(args->fp, ".DB $%.2X", (unsigned)c.integer);
1639 break;
1640 case CMD_DW:
1641 fprintf(args->fp, ".DW $%.4X", (unsigned)c.integer);
1642 break;
1643 case CMD_DD:
1644 fprintf(args->fp, ".DD $%.8X", (unsigned)c.integer);
1645 break;
1647 /* Advance PC */
1648 switch (b[0]) {
1649 case CMD_DB: inc_pc( 1, arg ); break;
1650 case CMD_DW: inc_pc( 2, arg ); break;
1651 case CMD_DD: inc_pc( 4, arg ); break;
1653 } else if (c.type == STRING_CONSTANT) {
1654 int count = strlen(c.string);
1655 switch (b[0]) {
1656 case CMD_DB:
1657 fprintf(args->fp, ".DB");
1658 break;
1659 case CMD_DW:
1660 fprintf(args->fp, ".DW");
1661 break;
1662 case CMD_DD:
1663 fprintf(args->fp, ".DD");
1664 break;
1666 fprintf(args->fp, " \"%s\"", c.string);
1667 /* Advance PC */
1668 switch (b[0]) {
1669 case CMD_DB: inc_pc( count * 1, arg ); break;
1670 case CMD_DW: inc_pc( count * 2, arg ); break;
1671 case CMD_DD: inc_pc( count * 4, arg ); break;
1673 } else {
1674 assert(0);
1676 fprintf(args->fp, "\n");
1677 finalize_constant(&c);
1681 * Writes a series of zeroes.
1683 static void asm_write_dsi8(unsigned char *b, void *arg)
1685 int count;
1686 int i;
1687 write_binary_args *args = (write_binary_args *)arg;
1688 /* Get 8-bit count */
1689 i = 1;
1690 count = get_1(b, &i) + 1;
1691 /* Pad */
1692 fprintf(args->fp, ".DSB $%X\n", count);
1693 /* Advance PC */
1694 inc_pc( count, arg );
1698 * Writes a series of zeroes.
1700 static void asm_write_dsi16(unsigned char *b, void *arg)
1702 int count;
1703 int i;
1704 write_binary_args *args = (write_binary_args *)arg;
1705 /* Get 16-bit count */
1706 i = 1;
1707 count = get_2(b, &i) + 1;
1708 /* Pad */
1709 fprintf(args->fp, ".DSB $%X\n", count);
1710 /* Advance PC */
1711 inc_pc( count, arg );
1715 * Writes a series of zeroes.
1717 static void asm_write_dsb(unsigned char *b, void *arg)
1719 constant c;
1720 int i;
1721 int exid;
1722 write_binary_args *args = (write_binary_args *)arg;
1723 /* Get expression ID */
1724 i = 1;
1725 exid = get_2(b, &i);
1726 /* Evaluate expression */
1727 eval_expression(args->xu, exid, &c);
1728 assert(c.type == INTEGER_CONSTANT);
1729 if (c.integer < 0) {
1730 err("negative count");
1732 else if (c.integer > 0) {
1733 /* Pad */
1734 fprintf(args->fp, ".DSB $%X\n", (unsigned)c.integer);
1735 /* Advance PC */
1736 inc_pc( c.integer, arg );
1741 * Writes a code segment as fully native 6502 code.
1742 * @param fp File handle
1743 * @param u Unit whose code to write
1745 static void write_as_assembly(FILE *fp, xunit *u)
1747 write_binary_args args;
1748 /* Table of callback functions for our purpose. */
1749 bytecodeproc handlers[] =
1751 NULL, /* CMD_END */
1752 asm_write_bin8, /* CMD_BIN8 */
1753 asm_write_bin16, /* CMD_BIN16 */
1754 asm_write_label, /* CMD_LABEL */
1755 asm_write_instr, /* CMD_INSTR */
1756 asm_write_dx, /* CMD_DB */
1757 asm_write_dx, /* CMD_DW */
1758 asm_write_dx, /* CMD_DD */
1759 asm_write_dsi8, /* CMD_DSI8 */
1760 asm_write_dsi16, /* CMD_DSI16 */
1761 asm_write_dsb /* CMD_DSB */
1763 /* Fill in args */
1764 args.xu = u;
1765 args.fp = fp;
1766 /* Reset PC */
1767 pc = u->code_origin;
1768 fprintf(fp, "; ***************************************\n");
1769 fprintf(fp, "; * %s, PC=$%.4X\n", u->_unit_.name, pc);
1770 fprintf(fp, "; ***************************************\n");
1771 /* Do the walk */
1772 bytecode_walk(u->_unit_.codeseg.bytes, handlers, (void *)&args);
1775 #define XLNK_NO_DEBUG
1776 #ifndef XLNK_NO_DEBUG
1778 /*--------------------------------------------------------------------------*/
1779 /* Functions for debugging bytecodes. */
1782 * Gets string representation of bytecode command.
1783 * @param cmd CMD_*
1784 * @return String representation ("CMD_*")
1786 static const char *bytecode_to_string(unsigned char cmd)
1788 switch (cmd) {
1789 case CMD_FILE: return "CMD_FILE";
1790 case CMD_LINE8: return "CMD_LINE8";
1791 case CMD_LINE16:return "CMD_LINE16";
1792 case CMD_LINE24:return "CMD_LINE24";
1793 case CMD_LINE_INC: return "CMD_LINE_INC";
1794 case CMD_END: return "CMD_END";
1795 case CMD_BIN8: return "CMD_BIN8";
1796 case CMD_BIN16: return "CMD_BIN16";
1797 case CMD_LABEL: return "CMD_LABEL";
1798 case CMD_INSTR: return "CMD_INSTR";
1799 case CMD_DB: return "CMD_DB";
1800 case CMD_DW: return "CMD_DW";
1801 case CMD_DD: return "CMD_DD";
1802 case CMD_DSI8: return "CMD_DSI8";
1803 case CMD_DSI16: return "CMD_DSI16";
1804 case CMD_DSB: return "CMD_DSB";
1806 return "bytecode_to_string: invalid bytecode";
1810 * Print a bytecode.
1811 * @param b Bytecodes
1812 * @param arg Not used
1814 static void print_it(unsigned char *b, void *arg)
1816 printf("%s\n", bytecode_to_string(b[0]) );
1820 * Prints bytecodes.
1821 * @param bytes Bytecodes
1823 static void print_bytecodes(unsigned char *bytes)
1825 bytecodeproc handlers[] =
1827 print_it,print_it,print_it,print_it,print_it,
1828 print_it,print_it,print_it,print_it,print_it,
1829 print_it,print_it,print_it
1831 bytecode_walk(bytes, handlers, NULL);
1835 * Prints a unit.
1836 * @param u Unit
1838 static void print_unit(unit *u)
1840 print_bytecodes(u->dataseg.bytes);
1841 print_bytecodes(u->codeseg.bytes);
1844 #endif /* !XLNK_NO_DEBUG */
1846 /*--------------------------------------------------------------------------*/
1847 /* Functions for managing arrays of unit locals. */
1850 * Creates array of locals.
1851 * @param size Number of locals
1852 * @param la Local array
1854 static void create_local_array(int size, local_array *la)
1856 la->size = size;
1857 /* Allocate space for entries */
1858 if (size > 0) {
1859 la->entries = (local *)malloc(sizeof(local) * size);
1861 else {
1862 la->entries = NULL;
1867 * Finalizes array of locals.
1869 static void finalize_local_array(local_array *la)
1871 int i;
1872 /* Free entry attributes */
1873 for (i=0; i<la->size; i++) {
1874 SAFE_FREE(la->entries[i].name);
1876 /* Free array itself */
1877 SAFE_FREE(la->entries);
1880 /*--------------------------------------------------------------------------*/
1881 /* Functions for counting and registering locals in a unit. */
1882 /* In bytecode expressions, locals are referred to by their index.
1883 In order to not have to go through the bytecodes every time to
1884 find a label definition, the following functions build an array
1885 of structures that can be indexed by the local ID to obtain its
1886 information.
1890 * Counts this local.
1892 static void count_one_local(unsigned char *b, void *arg)
1894 /* Argument points to the counter */
1895 int *count = (int *)arg;
1896 /* Increment count */
1897 (*count)++;
1901 * Counts the number of locals (labels) in an array of bytecodes.
1902 * @param b Bytecodes, terminated by CMD_END
1903 * @return Number of locals counted
1905 static int count_locals(unsigned char *b)
1907 int count;
1908 /* Table of callback functions for our purpose. */
1909 bytecodeproc handlers[] =
1911 NULL, /* CMD_END */
1912 NULL, /* CMD_BIN8 */
1913 NULL, /* CMD_BIN16 */
1914 count_one_local, /* CMD_LABEL */
1915 NULL, /* CMD_INSTR */
1916 NULL, /* CMD_DB */
1917 NULL, /* CMD_DW */
1918 NULL, /* CMD_DD */
1919 NULL, /* CMD_DSI8 */
1920 NULL, /* CMD_DSI16 */
1921 NULL /* CMD_DSB */
1923 /* Reset count */
1924 count = 0;
1925 /* Count the locals now */
1926 bytecode_walk(b, handlers, (void *)&count);
1927 /* Return the number of locals counted */
1928 return count;
1932 * Variable that points to the unit that locals are being registered for.
1934 static xunit *reg_unit = NULL;
1937 * Puts this local into array of locals for current unit.
1939 static void register_one_local(unsigned char *b, void *arg)
1941 int len;
1942 int i= 1;
1943 /* Argument points to a pointer which points to the local struct to fill in */
1944 local **lpptr = (local **)arg;
1945 local *lptr = *lpptr;
1946 /* Initialize some fields */
1947 lptr->resolved = 0;
1948 lptr->ref_count = 0;
1949 lptr->name = NULL;
1950 lptr->align = 1;
1951 lptr->owner = reg_unit;
1952 /* Get flag byte */
1953 lptr->flags = get_1(b, &i);
1954 /* Test export flag */
1955 if (lptr->flags & LABEL_FLAG_EXPORT) {
1956 /* Get the length of the name */
1957 len = get_1(b, &i) + 1;
1958 /* Allocate space for name */
1959 lptr->name = (char *)malloc( len + 1 );
1960 if (lptr->name != NULL) {
1961 /* Copy name from bytecodes */
1962 memcpy(lptr->name, &b[i], len);
1963 /* Zero-terminate string */
1964 lptr->name[len] = '\0';
1966 i += len;
1968 /* Test align flag */
1969 if (lptr->flags & LABEL_FLAG_ALIGN) {
1970 lptr->align = get_1(b, &i);
1972 /* Test address flag */
1973 if (lptr->flags & LABEL_FLAG_ADDR) {
1974 lptr->phys_addr = get_2(b, &i);
1975 lptr->resolved = 1;
1977 #if 0
1978 if (program_args.verbose) {
1979 verbose(1, " %s align=%d resolved=%d",
1980 lptr->name ? lptr->name : "(anonymous)",
1981 lptr->align, lptr->resolved);
1983 #endif
1984 /* Point to next local in array */
1985 *lpptr += 1;
1989 * Puts all locals found in the array of bytecodes into array.
1990 * @param b Bytecodes, terminated by CMD_END
1991 * @param la Pointer to array to receive locals
1992 * @param xu Owner unit
1994 static void register_locals(unsigned char *b, local_array *la, xunit *xu)
1996 local *lptr;
1997 local **lpptr;
1998 /* Table of callback functions for our purpose. */
1999 bytecodeproc handlers[] =
2001 NULL, /* CMD_END */
2002 NULL, /* CMD_BIN8 */
2003 NULL, /* CMD_BIN16 */
2004 register_one_local, /* CMD_LABEL */
2005 NULL, /* CMD_INSTR */
2006 NULL, /* CMD_DB */
2007 NULL, /* CMD_DW */
2008 NULL, /* CMD_DD */
2009 NULL, /* CMD_DSI8 */
2010 NULL, /* CMD_DSI16 */
2011 NULL /* CMD_DSB */
2013 /* Create array of locals */
2014 create_local_array(count_locals(b), la);
2015 /* Prepare args */
2016 lptr = la->entries;
2017 lpptr = &lptr;
2018 reg_unit = xu;
2019 /* Go! */
2020 bytecode_walk(b, handlers, (void *)lpptr);
2023 /*--------------------------------------------------------------------------*/
2024 /* Functions for entering exported symbols into proper hash table. */
2027 * Enters an exported symbol into a hash table.
2028 * @param tab Hash table to enter it into
2029 * @param key Key
2030 * @param data Data
2031 * @param u Owner unit
2033 static void enter_exported_symbol(hashtab *tab, void *key, void *data, unit *u)
2035 /* Make sure symbol doesn't already exist */
2036 if ((hashtab_get(label_hash, key) != NULL)
2037 || (hashtab_get(constant_hash, key) != NULL) ) {
2038 /* Error, duplicate symbol */
2039 err("duplicate symbol `%s' exported from unit `%s'", (char *)key, u->name);
2041 else {
2042 verbose(1, " %s", (char*)key);
2043 /* Enter it */
2044 hashtab_put(tab, key, data);
2049 * Enters all constants in a unit into the proper hash table.
2050 * @param u Unit whose constants to enter
2052 static void enter_exported_constants(unit *u)
2054 int i;
2055 constant *c;
2056 /* Go through all constants in unit */
2057 for (i=0; i<u->const_count; i++) {
2058 c = &u->constants[i];
2059 enter_exported_symbol(constant_hash, (void *)c->name, (void *)c, u);
2064 * Enters locals which should be globally visible into the proper hash table.
2065 * @param la Array of locals
2066 * @param u Owner unit
2068 static void enter_exported_locals(local_array *la, unit *u)
2070 int i;
2071 local *l;
2072 /* Go through all locals */
2073 for (i=0; i<la->size; i++) {
2074 l = &la->entries[i];
2075 /* If it has a name, it is exported */
2076 if (l->name != NULL) {
2077 enter_exported_symbol(label_hash, (void *)l->name, (void *)l, u);
2082 /*--------------------------------------------------------------------------*/
2083 /* Functions for calculating addresses of data labels in a unit. */
2086 * Sets the virtual address of this local to current PC value.
2088 static void set_data_address(unsigned char *b, void *arg)
2090 calc_address_args *args = (calc_address_args *)arg;
2091 /* Get the label */
2092 local *l = &args->xu->data_locals.entries[args->index];
2093 if (!l->resolved) {
2094 /* Set the virtual address */
2095 l->virt_addr = pc;
2096 verbose(2, " %.4X %s", l->virt_addr, l->name ? l->name : "");
2098 /* Increase label index */
2099 args->index++;
2103 * Calculates addresses of labels in a data segment relative to 0.
2104 * Only a small set of bytecode commands are allowed in a data segment:
2105 * - label (which we want to assign a virtual address)
2106 * - storage (constant or variable)
2108 static void calc_data_addresses(xunit *u)
2110 calc_address_args args;
2111 /* Table of callback functions for our purpose. */
2112 bytecodeproc handlers[] =
2114 NULL, /* CMD_END */
2115 NULL, /* CMD_BIN8 */
2116 NULL, /* CMD_BIN16 */
2117 set_data_address, /* CMD_LABEL */
2118 NULL, /* CMD_INSTR */
2119 NULL, /* CMD_DB */
2120 NULL, /* CMD_DW */
2121 NULL, /* CMD_DD */
2122 inc_pc_count8, /* CMD_DSI8 */
2123 inc_pc_count16, /* CMD_DSI16 */
2124 inc_pc_dsb /* CMD_DSB */
2126 /* Fill in args */
2127 args.xu = u;
2128 args.index = 0;
2129 /* Reset PC */
2130 pc = 0;
2131 verbose(1, " %s", u->_unit_.name);
2132 /* Map away! */
2133 bytecode_walk(u->_unit_.dataseg.bytes, handlers, (void *)&args);
2134 /* Store the end address, which is the total size of data */
2135 u->data_size = pc;
2138 /*--------------------------------------------------------------------------*/
2140 /* Constructs 32-bit sort key for local. */
2141 #define SORT_KEY(l) (unsigned long)((((l)->flags & LABEL_FLAG_ZEROPAGE) << 30) | ((l)->align << 24) | (0x10000-(l)->size))
2144 * Array is sorted from high to low value.
2146 static int label_partition(local **a, int p, int r)
2148 int x;
2149 int i;
2150 int j;
2151 x = SORT_KEY(a[r]);
2152 i = p - 1;
2153 local *temp;
2154 for (j=p; j<r; j++) {
2155 if (SORT_KEY(a[j]) >= x) {
2156 i = i + 1;
2157 temp = a[i];
2158 a[i] = a[j];
2159 a[j] = temp;
2162 temp = a[i+1];
2163 a[i+1] = a[r];
2164 a[r] = temp;
2165 return i + 1;
2169 * Quicksort implementation used to sort array of pointers to locals.
2171 static void label_qsort(local **a, int p, int r)
2173 int q;
2174 if (p < r) {
2175 q = label_partition(a, p, r);
2176 label_qsort(a, p, q-1);
2177 label_qsort(a, q+1, r);
2182 * Maps all data labels to 6502 RAM locations.
2183 * This is a very important function. It takes all the data labels from all
2184 * the loaded units and attempts to assign them unique physical addresses.
2185 * The list of target RAM blocks given in the linker script is the premise.
2187 static void map_data_to_ram()
2189 int i, k;
2190 local **total_order;
2191 local *l;
2192 int count;
2193 /* Use a bit array to keep track of allocations,
2194 to ensure that there is no overlap */
2195 unsigned char *allocated;
2196 int ram_base, ram_end;
2198 avail_ram_block *b;
2199 ram_base = 10000000;
2200 ram_end = -10000000;
2201 for (b = ram_block_head; b != NULL; b = b->next) {
2202 if (b->start < ram_base)
2203 ram_base = b->start;
2204 if (b->end > ram_end)
2205 ram_end = b->end;
2208 allocated = (unsigned char *)malloc(((ram_end - ram_base) + 7) / 8);
2209 memset(allocated, 0, ((ram_end - ram_base) + 7) / 8);
2210 /* Calculate total number of labels to map */
2211 count = 0;
2212 for (i=0; i<unit_count; i++) {
2213 count += units[i].data_locals.size;
2215 /* Put pointers to all data labels in one big array */
2216 total_order = (local **)malloc( count * sizeof(local *) );
2217 for (i=0, k=0; i<unit_count; i++) {
2218 int j;
2219 local_array *la;
2220 la = &units[i].data_locals;
2221 for (j=0; j<la->size; j++) {
2222 int size;
2223 /* Use virtual addresses to calculate size from this label to next */
2224 if (j == la->size-1) {
2225 size = units[i].data_size;
2227 else {
2228 size = la->entries[j+1].virt_addr;
2230 la->entries[j].size = size - la->entries[j].virt_addr;
2231 /* Put pointer in array */
2232 total_order[k++] = &la->entries[j];
2235 /* Sort them */
2236 label_qsort(total_order, 0, count-1);
2237 /* Map them */
2238 for (i=0; i<count; i++) {
2239 l = total_order[i];
2240 /* Try to allocate it */
2241 if (alloc_ram(l) == 1) {
2242 /* Good, label mapped successfully */
2243 l->resolved = 1;
2244 verbose(1, " %.4X-%.4X %s (%s)", l->phys_addr,
2245 l->phys_addr + l->size-1, l->name ? l->name : "",
2246 l->owner->_unit_.name);
2248 /* Verify that there's no overlap with other variable */
2249 int a;
2250 for (a = l->phys_addr; a < l->phys_addr + l->size; ++a) {
2251 assert((allocated[(a - ram_base) / 8] & (1 << (a & 7))) == 0);
2252 allocated[(a - ram_base) / 8] |= 1 << (a & 7);
2256 else {
2257 /* Error, couldn't allocate */
2258 err("out of 6502 RAM while allocating unit `%s'", l->owner->_unit_.name);
2259 return;
2262 free(total_order);
2263 free(allocated);
2266 /*--------------------------------------------------------------------------*/
2267 /* Functions for calculating offsets of code labels in a unit. */
2270 * Sets the address of this code label to current PC.
2272 static void set_code_address(unsigned char *b, void *arg)
2274 calc_address_args *args = (calc_address_args *)arg;
2275 /* Get the label */
2276 local *l = &args->xu->code_locals.entries[args->index];
2277 if (!l->resolved) {
2278 /* Set the physical address to current PC */
2279 l->phys_addr = pc;
2280 l->resolved = 1;
2281 if (program_args.verbose) {
2282 fprintf(stdout, " %.4X %s (%s)\n", l->phys_addr,
2283 l->name ? l->name : "", l->owner->_unit_.name);
2286 /* Increase label index */
2287 args->index++;
2291 * Calculates addresses of code labels in a segment.
2292 * NOTE: Only the virtual addresses (relative to 0) are calculated.
2293 * The labels then need to be relocated to obtain the physical address (see below).
2294 * @param u Unit
2296 static void calc_code_addresses(xunit *u)
2298 calc_address_args args;
2299 /* Table of callback functions for our purpose. */
2300 bytecodeproc handlers[] =
2302 NULL, /* CMD_END */
2303 inc_pc_count8, /* CMD_BIN8 */
2304 inc_pc_count16, /* CMD_BIN16 */
2305 set_code_address, /* CMD_LABEL */
2306 inc_pc_instr, /* CMD_INSTR */
2307 inc_pc_1, /* CMD_DB -- TODO, error if string */
2308 inc_pc_2, /* CMD_DW */
2309 inc_pc_4, /* CMD_DD */
2310 inc_pc_count8, /* CMD_DSI8 */
2311 inc_pc_count16, /* CMD_DSI16 */
2312 inc_pc_dsb /* CMD_DSB */
2314 /* Fill in args */
2315 args.xu = u;
2316 args.index = 0;
2317 /* Do the walk */
2318 bytecode_walk(u->_unit_.codeseg.bytes, handlers, (void *)&args);
2319 /* Store the total size of code */
2320 u->code_size = pc - u->code_origin;
2323 /*--------------------------------------------------------------------------*/
2326 * Issues a script error.
2328 static void scripterr(script *s, script_command *c, char *fmt, ...)
2330 va_list ap;
2331 va_start(ap, fmt);
2333 if (!suppress) {
2334 /* Print error message */
2335 fprintf(stderr, "error: %s:%d: `%s': ", s->name, c->line, script_command_type_to_string(c->type) );
2336 vfprintf(stderr, fmt, ap);
2337 fprintf(stderr, "\n");
2338 /* Increase error count */
2339 err_count++;
2341 va_end(ap);
2344 #define require_arg(s, c, a, d) { \
2345 d = script_get_command_arg(c, a); \
2346 if (d == NULL) { \
2347 scripterr(s, c, "missing argument `%s'", a); \
2348 return; \
2352 #define require_arg_in_range(s, c, a, v, l, h) { \
2353 if (((v) < (l)) || ((v) > (h))) { \
2354 scripterr(s, c, "value of argument `%s' is out of range", a); \
2355 return; \
2359 /*--------------------------------------------------------------------------*/
2360 /* Functions for registering RAM blocks in script. */
2363 * Registers one RAM block based on 'ram' script command.
2364 * @param s Linker script
2365 * @param c Command of type RAM_COMMAND
2366 * @param arg Not used
2368 static void register_one_ram_block(script *s, script_command *c, void *arg)
2370 int start;
2371 int end;
2372 char *start_str;
2373 char *end_str;
2374 /* Get arguments */
2375 require_arg(s, c, "start", start_str);
2376 require_arg(s, c, "end", end_str);
2377 /* Convert to integers */
2378 start = str_to_int(start_str);
2379 end = str_to_int(end_str);
2380 /* Check that they are sane */
2381 require_arg_in_range(s, c, "start", start, 0x0000, 0xFFFF);
2382 require_arg_in_range(s, c, "end", end, 0x0000, 0xFFFF);
2383 if (end <= start) {
2384 scripterr(s, c, "`end' is smaller than `start'");
2386 /* Add block */
2387 add_ram_block(start, end);
2391 * Registers RAM blocks based on 'ram' commands in a script.
2392 * @param sc Linker script
2394 static void register_ram_blocks(script *sc)
2396 /* Table of mappings for our purpose */
2397 static script_commandprocmap map[] = {
2398 { RAM_COMMAND, register_one_ram_block },
2399 { BAD_COMMAND, NULL }
2401 /* Do the walk */
2402 script_walk(sc, map, NULL);
2403 /* Calculate total RAM size */
2404 total_ram = ram_left();
2407 /*--------------------------------------------------------------------------*/
2408 /* Functions for loading and initial processing of units in script. */
2411 * Registers (parses etc.) one unit based on 'link' script command.
2412 * @param s Linker script
2413 * @param c Command of type LINK_COMMAND
2414 * @param arg Pointer to unit index
2416 static void register_one_unit(script *s, script_command *c, void *arg)
2418 char *file;
2419 int *i;
2420 xunit *xu;
2421 /* Get unit filename */
2422 require_arg(s, c, "file", file);
2423 /* arg is pointer to unit index */
2424 i = (int *)arg;
2425 /* Get pointer to xunit to fill in */
2426 xu = &units[*i];
2427 /* Read basic unit from file */
2428 if (unit_read(file, &xu->_unit_) == 0) {
2429 /* Something bad happened when trying to read unit */
2430 scripterr(s, c, "failed to load unit `%s'", file);
2431 xu->loaded = 0;
2432 return;
2434 xu->loaded = 1;
2435 verbose(1, " unit `%s' loaded", file);
2436 /* Register locals for both segments */
2437 verbose(1, " registering local symbols...");
2438 register_locals(xu->_unit_.dataseg.bytes, &xu->data_locals, xu);
2439 register_locals(xu->_unit_.codeseg.bytes, &xu->code_locals, xu);
2440 /* Enter exported symbols into hash tables */
2441 verbose(1, " registering public symbols...");
2442 enter_exported_constants(&xu->_unit_);
2443 enter_exported_locals(&xu->data_locals, &xu->_unit_);
2444 enter_exported_locals(&xu->code_locals, &xu->_unit_);
2445 /* Put unit in hash table */
2446 hashtab_put(unit_hash, file, xu);
2447 /* Increment unit index */
2448 (*i)++;
2452 * Registers units based on 'link' commands in script.
2453 * @param sc Linker script
2455 static void register_units(script *sc)
2457 /* Table of mappings for our purpose */
2458 static script_commandprocmap map[] = {
2459 { LINK_COMMAND, register_one_unit },
2460 { BAD_COMMAND, NULL }
2462 int i = 0;
2463 /* Do the walk */
2464 script_walk(sc, map, (void *)&i);
2467 /*--------------------------------------------------------------------------*/
2468 /* Functions for composing a binary file based on a sequential list of
2469 script commands. */
2472 * Sets the output file according to 'output' script command.
2473 * @param s Linker script
2474 * @param c Command of type OUTPUT_COMMAND
2475 * @param arg Pointer to file handle
2477 static void set_output(script *s, script_command *c, void *arg)
2479 char *file;
2480 FILE **fpp;
2481 /* Get the name of new output file */
2482 require_arg(s, c, "file", file);
2483 /* Arg is pointer to file handle pointer */
2484 fpp = (FILE **)arg;
2485 /* Close current file */
2486 if (*fpp != NULL) {
2487 fclose(*fpp);
2489 /* Attempt to open new file */
2490 *fpp = fopen(file, "wb");
2491 if (*fpp == NULL) {
2492 scripterr(s, c, "could not open `%s' for writing", file);
2494 else {
2495 verbose(1, " output goes to `%s'", file);
2500 * Copies a file to output according to 'copy' script command.
2501 * @param s Linker script
2502 * @param c Command of type COPY_COMMAND
2503 * @param arg Pointer to file handle
2505 static void copy_to_output(script *s, script_command *c, void *arg)
2507 char *file;
2508 FILE **fpp;
2509 FILE *cf;
2510 unsigned char k;
2511 /* Arg is pointer to file handle pointer */
2512 fpp = (FILE **)arg;
2513 /* Make sure there is a file to write to */
2514 if (*fpp == NULL) {
2515 scripterr(s, c, "no output open");
2517 else {
2518 /* Get the name of file to copy */
2519 require_arg(s, c, "file", file);
2520 /* Attempt to open the file to copy */
2521 cf = fopen(file, "rb");
2522 if (cf == NULL) {
2523 scripterr(s, c, "could not open `%s' for reading", file);
2525 else {
2526 verbose(1, " copying `%s' to output at position %ld...", file, ftell(*fpp) );
2527 /* Copy it to output, byte for byte */
2528 for (k = fgetc(cf); !feof(cf); k = fgetc(cf) ) {
2529 fputc(k, *fpp);
2531 /* Advance offset */
2532 bank_offset += ftell(cf);
2533 pc += ftell(cf);
2534 /* Close the copied file */
2535 fclose(cf);
2536 /* Check if exceeded bank size */
2537 if (bank_offset > bank_size) {
2538 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2545 * Starts a new bank according to 'bank' script command.
2546 * @param s Linker script
2547 * @param c Command of type BANK_COMMAND
2548 * @param arg Pointer to file handle
2550 static void start_bank(script *s, script_command *c, void *arg)
2552 char *size_str;
2553 char *origin_str;
2554 /* See if size specified */
2555 size_str = script_get_command_arg(c, "size");
2556 if (size_str != NULL) {
2557 /* Set new bank size */
2558 bank_size = str_to_int(size_str);
2559 /* Sanity check */
2560 if (bank_size <= 0) {
2561 scripterr(s, c, "invalid size");
2564 else {
2565 /* Use bank size of previous bank if there was one */
2566 /* Otherwise issue error */
2567 if (bank_size == 0x7FFFFFFF) {
2568 scripterr(s, c, "no bank size set");
2571 /* See if origin specified */
2572 origin_str = script_get_command_arg(c, "origin");
2573 if (origin_str != NULL) {
2574 /* Set new bank origin */
2575 bank_origin = str_to_int(origin_str);
2576 /* Sanity check */
2577 require_arg_in_range(s, c, "origin", bank_origin, 0x0000, 0xFFFF);
2579 else {
2580 /* Use old bank origin */
2582 bank_id++;
2583 /* Reset bank offset and PC */
2584 bank_offset = 0;
2585 pc = bank_origin;
2589 * Writes unit according to 'link' script command.
2590 * @param s Linker script
2591 * @param c Command of type LINK_COMMAND
2592 * @param arg Pointer to file handle
2594 static void write_unit(script *s, script_command *c, void *arg)
2596 FILE **fpp;
2597 xunit *xu;
2598 char *file;
2599 /* Arg is pointer to file handle pointer */
2600 fpp = (FILE **)arg;
2601 /* Make sure there is a file to write to */
2602 if (*fpp == NULL) {
2603 scripterr(s, c, "no output open");
2605 else {
2606 /* Get the name of the unit */
2607 require_arg(s, c, "file", file);
2608 /* Look it up */
2609 xu = (xunit *)hashtab_get(unit_hash, file);
2610 /* Write it */
2611 verbose(1, " appending unit `%s' to output at position %ld...", file, ftell(*fpp));
2612 write_as_binary(*fpp, xu);
2613 /* Advance offset */
2614 bank_offset += xu->code_size;
2615 /* Check if exceeded bank size */
2616 if (bank_offset > bank_size) {
2617 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2623 * Pads output file according to 'pad' script command.
2624 * @param s Linker script
2625 * @param c Command of type PAD_COMMAND
2626 * @param arg Pointer to file handle
2628 static void write_pad(script *s, script_command *c, void *arg)
2630 FILE **fpp;
2631 int i;
2632 int count;
2633 int offset;
2634 int origin;
2635 char *offset_str;
2636 char *origin_str;
2637 char *size_str;
2638 /* Arg is pointer to file handle pointer */
2639 fpp = (FILE **)arg;
2640 /* Make sure there is a file to write to */
2641 if (*fpp == NULL) {
2642 scripterr(s, c, "no output open");
2644 else {
2645 if ((offset_str = script_get_command_arg(c, "offset")) != NULL) {
2646 offset = str_to_int(offset_str);
2647 /* Calculate number of zeroes to write */
2648 count = offset - bank_offset;
2650 else if ((origin_str = script_get_command_arg(c, "origin")) != NULL) {
2651 origin = str_to_int(origin_str);
2652 /* Calculate number of zeroes to write */
2653 count = origin - pc;
2655 else if ((size_str = script_get_command_arg(c, "size")) != NULL) {
2656 count = str_to_int(size_str);
2658 else {
2659 scripterr(s, c, "missing argument");
2660 count = 0;
2662 /* Sanity check */
2663 if (count < 0) {
2664 scripterr(s, c, "cannot pad backwards");
2665 count = 0;
2667 else if (count > 0) {
2668 verbose(1, " padding %d bytes...", count);
2670 /* Write zeroes */
2671 for (i=0; i<count; i++) {
2672 fputc(0, *fpp);
2674 /* Advance offset */
2675 bank_offset += count;
2676 pc += count;
2677 /* Check if exceeded bank size */
2678 if (bank_offset > bank_size) {
2679 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2685 * Pads to end of bank in file if bank size not reached.
2686 * @param s Linker script
2687 * @param c Command of type BANK_COMMAND
2688 * @param fp File handle
2690 static void maybe_pad_bank(script *s, script_command *c, FILE *fp)
2692 int i;
2693 if ( (bank_size != 0x7FFFFFFF) && (bank_offset < bank_size) ) {
2694 /* Make sure there is a file to write to */
2695 if (fp == NULL) {
2696 scripterr(s, c, "no output open");
2698 else {
2699 /* Pad until bank size */
2700 for (i=bank_offset; i<bank_size; i++) {
2701 fputc(0, fp);
2708 * Finishes old bank in output and starts new bank.
2709 * @param s Linker script
2710 * @param c Command of type BANK_COMMAND
2711 * @param arg Pointer to file handle
2713 static void write_bank(script *s, script_command *c, void *arg)
2715 FILE **fpp;
2716 /* Arg is pointer to file handle pointer */
2717 fpp = (FILE **)arg;
2718 /* Pad bank if necessary */
2719 maybe_pad_bank(s, c, *fpp);
2720 /* Start new bank */
2721 start_bank(s, c, arg);
2725 * Generates the final binary output from the linker.
2726 * @param sc Linker script
2728 static void generate_binary_output(script *sc)
2730 FILE *fp = NULL;
2731 /* Table of mappings for our purpose */
2732 static script_commandprocmap map[] = {
2733 { OUTPUT_COMMAND, set_output },
2734 { COPY_COMMAND, copy_to_output },
2735 { BANK_COMMAND, write_bank },
2736 { LINK_COMMAND, write_unit },
2737 { PAD_COMMAND, write_pad },
2738 { BAD_COMMAND, NULL }
2740 /* Reset offsets */
2741 bank_size = 0x7FFFFFFF;
2742 bank_offset = 0;
2743 bank_origin = 0;
2744 bank_id = -1;
2745 pc = 0;
2746 /* Do the walk */
2747 script_walk(sc, map, (void *)&fp);
2748 /* Pad last bank if necessary */
2749 maybe_pad_bank(sc, sc->first_command, fp);
2752 /*--------------------------------------------------------------------------*/
2753 /* Functions for producing assembly code based on a sequential list of
2754 script commands. */
2757 * Sets the output file according to 'output' script command.
2758 * @param s Linker script
2759 * @param c Command of type OUTPUT_COMMAND
2760 * @param arg Pointer to file handle
2762 static void asm_set_output(script *s, script_command *c, void *arg)
2764 /* No-op when generating assembly. */
2768 * Copies a file to output according to 'copy' script command.
2769 * @param s Linker script
2770 * @param c Command of type COPY_COMMAND
2771 * @param arg Pointer to file handle
2773 static void asm_copy_to_output(script *s, script_command *c, void *arg)
2775 char *file;
2776 FILE **fpp;
2777 FILE *cf;
2778 /* Arg is pointer to file handle pointer */
2779 fpp = (FILE **)arg;
2780 /* Get the name of file to copy */
2781 require_arg(s, c, "file", file);
2782 /* Attempt to open the file to copy */
2783 cf = fopen(file, "rb");
2784 if (cf == NULL) {
2785 scripterr(s, c, "could not open `%s' for reading", file);
2786 } else {
2787 unsigned char buf[1024];
2788 int count = fread(buf, 1, 1024, cf);
2789 fprintf(*fpp, "; begin %s\n", file);
2790 while (count > 0) {
2791 print_chunk(*fpp, /*label=*/0, buf, count, /*cols=*/16);
2792 count = fread(buf, 1, 1024, cf);
2794 fprintf(*fpp, "; end %s\n", file);
2795 /* Advance offset */
2796 bank_offset += ftell(cf);
2797 pc += ftell(cf);
2798 /* Close the copied file */
2799 fclose(cf);
2800 /* Check if exceeded bank size */
2801 if (bank_offset > bank_size) {
2802 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2808 * Starts a new bank according to 'bank' script command.
2809 * @param s Linker script
2810 * @param c Command of type BANK_COMMAND
2811 * @param arg Pointer to file handle
2813 static void asm_start_bank(script *s, script_command *c, void *arg)
2815 FILE *fp = *(FILE**)arg;
2816 start_bank(s, c, arg);
2817 fprintf(fp, ".ORG $%.4X\n", pc);
2821 * Writes unit according to 'link' script command.
2822 * @param s Linker script
2823 * @param c Command of type LINK_COMMAND
2824 * @param arg Pointer to file handle
2826 static void asm_write_unit(script *s, script_command *c, void *arg)
2828 FILE **fpp;
2829 xunit *xu;
2830 char *file;
2831 /* Arg is pointer to file handle pointer */
2832 fpp = (FILE **)arg;
2833 /* Get the name of the unit */
2834 require_arg(s, c, "file", file);
2835 /* Look it up */
2836 xu = (xunit *)hashtab_get(unit_hash, file);
2837 /* Write it */
2838 verbose(1, " appending unit `%s' to output at position %ld...", file, ftell(*fpp));
2839 write_as_assembly(*fpp, xu);
2840 /* Advance offset */
2841 bank_offset += xu->code_size;
2842 /* Check if exceeded bank size */
2843 if (bank_offset > bank_size) {
2844 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2849 * Pads output file according to 'pad' script command.
2850 * @param s Linker script
2851 * @param c Command of type PAD_COMMAND
2852 * @param arg Pointer to file handle
2854 static void asm_write_pad(script *s, script_command *c, void *arg)
2856 FILE **fpp;
2857 int count;
2858 int offset;
2859 int origin;
2860 char *offset_str;
2861 char *origin_str;
2862 char *size_str;
2863 /* Arg is pointer to file handle pointer */
2864 fpp = (FILE **)arg;
2865 if ((offset_str = script_get_command_arg(c, "offset")) != NULL) {
2866 offset = str_to_int(offset_str);
2867 /* Calculate number of zeroes to write */
2868 count = offset - bank_offset;
2869 } else if ((origin_str = script_get_command_arg(c, "origin")) != NULL) {
2870 origin = str_to_int(origin_str);
2871 /* Calculate number of zeroes to write */
2872 count = origin - pc;
2873 } else if ((size_str = script_get_command_arg(c, "size")) != NULL) {
2874 count = str_to_int(size_str);
2875 } else {
2876 scripterr(s, c, "missing argument");
2877 count = 0;
2879 /* Sanity check */
2880 if (count < 0) {
2881 scripterr(s, c, "cannot pad backwards");
2882 count = 0;
2883 } else if (count > 0) {
2884 verbose(1, " padding %d bytes...", count);
2886 /* Pad! */
2887 fprintf(*fpp, ".DSB $%X\n", count);
2888 /* Advance offset */
2889 bank_offset += count;
2890 pc += count;
2891 /* Check if exceeded bank size */
2892 if (bank_offset > bank_size) {
2893 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2898 * Pads to end of bank in file if bank size not reached.
2899 * @param s Linker script
2900 * @param c Command of type BANK_COMMAND
2901 * @param fp File handle
2903 static void asm_maybe_pad_bank(script *s, script_command *c, FILE *fp)
2905 if ( (bank_size != 0x7FFFFFFF) && (bank_offset < bank_size) ) {
2906 fprintf(fp, ".DSB $%X\n", bank_size - bank_offset);
2911 * Finishes old bank in output and starts new bank.
2912 * @param s Linker script
2913 * @param c Command of type BANK_COMMAND
2914 * @param arg Pointer to file handle
2916 static void asm_write_bank(script *s, script_command *c, void *arg)
2918 FILE **fpp = (FILE **)arg;
2919 /* Pad bank if necessary */
2920 asm_maybe_pad_bank(s, c, *fpp);
2921 /* Start new bank */
2922 asm_start_bank(s, c, arg);
2925 static void generate_assembly_output(script *sc, FILE *fp)
2927 /* Table of mappings for our purpose */
2928 static script_commandprocmap map[] = {
2929 { OUTPUT_COMMAND, asm_set_output },
2930 { COPY_COMMAND, asm_copy_to_output },
2931 { BANK_COMMAND, asm_write_bank },
2932 { LINK_COMMAND, asm_write_unit },
2933 { PAD_COMMAND, asm_write_pad },
2934 { BAD_COMMAND, NULL }
2936 /* Reset offsets */
2937 bank_size = 0x7FFFFFFF;
2938 bank_offset = 0;
2939 bank_origin = 0;
2940 bank_id = -1;
2941 pc = 0;
2942 fprintf(fp, ".CODESEG\n");
2943 /* Do the walk */
2944 script_walk(sc, map, (void *)&fp);
2945 /* Pad last bank if necessary */
2946 asm_maybe_pad_bank(sc, sc->first_command, fp);
2947 fprintf(fp, ".END\n");
2950 /*--------------------------------------------------------------------------*/
2953 * Increases bank offset and PC according to size of the file specified by
2954 * 'copy' script command.
2955 * @param s Linker script
2956 * @param c Command of type COPY_COMMAND
2957 * @param arg Not used
2959 static void inc_offset_copy(script *s, script_command *c, void *arg)
2961 char *file;
2962 FILE *fp;
2963 /* Get the name of the file */
2964 require_arg(s, c, "file", file);
2965 /* Attempt to it */
2966 fp = fopen(file, "rb");
2967 if (fp == NULL) {
2968 scripterr(s, c, "could not open `%s' for reading", file);
2970 else {
2971 /* Seek to end */
2972 fseek(fp, 0, SEEK_END);
2973 /* Advance offset */
2974 bank_offset += ftell(fp);
2975 pc += ftell(fp);
2976 /* Close the file */
2977 fclose(fp);
2978 /* Check if exceeded bank size */
2979 if (bank_offset > bank_size) {
2980 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2986 * Sets the origin of a unit and relocates its code to this location.
2987 * @param s Linker script
2988 * @param c Command of type LINK_COMMAND
2989 * @param arg Not used
2991 static void set_unit_origin(script *s, script_command *c, void *arg)
2993 xunit *xu;
2994 char *file;
2995 char *origin_str;
2996 int origin;
2997 /* Get the unit filename */
2998 require_arg(s, c, "file", file);
2999 /* Look it up */
3000 xu = (xunit *)hashtab_get(unit_hash, file);
3001 /* Check if origin specified */
3002 origin_str = script_get_command_arg(c, "origin");
3003 if (origin_str != NULL) {
3004 origin = str_to_int(origin_str);
3005 require_arg_in_range(s, c, "origin", origin, 0x0000, 0xFFFF);
3006 xu->code_origin = origin;
3007 pc = origin;
3009 else {
3010 /* No origin specified. Set to PC. */
3011 xu->code_origin = pc;
3013 xu->bank_id = bank_id;
3014 /* Now we can calculate the physical code addresses of the unit. */
3015 calc_code_addresses(xu);
3016 /* Print info if verbose mode */
3017 verbose(1, " unit `%s' relocated to %.4X", xu->_unit_.name, xu->code_origin);
3018 /* Increase bank offset */
3019 bank_offset += xu->code_size;
3023 * Increases bank offset and PC according to 'pad' script command.
3024 * @param s Linker script
3025 * @param c Command of type PAD_COMMAND
3026 * @param arg Not used
3028 static void inc_offset_pad(script *s, script_command *c, void *arg)
3030 int count;
3031 int offset;
3032 int origin;
3033 char *offset_str;
3034 char *origin_str;
3035 char *size_str;
3036 if ((offset_str = script_get_command_arg(c, "offset")) != NULL) {
3037 offset = str_to_int(offset_str);
3038 /* Calculate number of zeroes to write */
3039 count = offset - bank_offset;
3041 else if ((origin_str = script_get_command_arg(c, "origin")) != NULL) {
3042 origin = str_to_int(origin_str);
3043 /* Calculate number of zeroes to write */
3044 count = origin - pc;
3046 else if ((size_str = script_get_command_arg(c, "size")) != NULL) {
3047 count = str_to_int(size_str);
3049 else {
3050 /* Error */
3051 scripterr(s, c, "missing argument");
3052 count = 0;
3054 /* Sanity check */
3055 if (count < 0) {
3056 scripterr(s, c, "cannot pad %d bytes backwards", -count);
3057 count = 0;
3059 /* Advance offset */
3060 bank_offset += count;
3061 pc += count;
3062 /* Check if exceeded bank size */
3063 if (bank_offset > bank_size) {
3064 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
3069 * Relocates code of all units according to script commands and/or their position
3070 * in the final binary.
3071 * @param sc Linker script
3073 static void relocate_units(script *sc)
3075 /* Table of mappings for our purpose */
3076 static script_commandprocmap map[] = {
3077 { COPY_COMMAND, inc_offset_copy },
3078 { BANK_COMMAND, start_bank },
3079 { LINK_COMMAND, set_unit_origin },
3080 { PAD_COMMAND, inc_offset_pad },
3081 { BAD_COMMAND, NULL }
3083 /* Reset offsets */
3084 bank_size = 0x7FFFFFFF;
3085 bank_offset = 0;
3086 bank_origin = 0;
3087 bank_id = -1;
3088 pc = 0;
3089 /* Do the walk */
3090 script_walk(sc, map, NULL);
3096 static void maybe_print_ram_statistics()
3098 int used;
3099 int left;
3100 if (total_ram > 0) {
3101 left = ram_left();
3102 used = total_ram - left;
3103 verbose(1, " total RAM: %d bytes", total_ram);
3104 verbose(1, " RAM used: %d bytes (%d%%)", used, (int)(((float)used / (float)total_ram)*100.0f) );
3105 verbose(1, " RAM left: %d bytes (%d%%)", left, (int)(((float)left / (float)total_ram)*100.0f) );
3109 /*--------------------------------------------------------------------------*/
3112 * Program entrypoint.
3114 int main(int argc, char **argv)
3116 int i;
3117 script sc;
3119 /* Parse our arguments. */
3120 parse_arguments(argc, argv);
3122 suppress = 0;
3123 /* Reset error and warning count */
3124 err_count = 0;
3125 warn_count = 0;
3127 /* Parse the linker script */
3128 verbose(1, "parsing linker script...");
3129 if (script_parse(program_args.input_file, &sc) == 0) {
3130 /* Something bad happened when parsing script, halt */
3131 return(1);
3134 /* Process all ram commands */
3135 verbose(1, "registering RAM blocks...");
3136 register_ram_blocks(&sc);
3138 /* Create hash tables to hold symbols */
3139 constant_hash = hashtab_create(23, HASHTAB_STRKEYHSH, HASHTAB_STRKEYCMP);
3140 label_hash = hashtab_create(23, HASHTAB_STRKEYHSH, HASHTAB_STRKEYCMP);
3141 unit_hash = hashtab_create(11, HASHTAB_STRKEYHSH, HASHTAB_STRKEYCMP);
3143 /* Count units. One unit per link command. */
3144 unit_count = script_count_command_type(&sc, LINK_COMMAND);
3145 /* Allocate array of xunits */
3146 if (unit_count > 0) {
3147 units = (xunit *)malloc( sizeof(xunit) * unit_count );
3149 else {
3150 units = NULL;
3152 /* Process link commands */
3153 verbose(1, "loading units...");
3154 register_units(&sc);
3155 /* Make sure all units were loaded */
3156 if (err_count != 0) {
3157 // TODO
3158 assert(0);
3161 /* Only continue with processing if no unresolved symbols */
3162 if (err_count == 0) {
3163 /* Calculate 0-relative addresses of data labels */
3164 verbose(1, "calculating data addresses...");
3165 for (i=0; i<unit_count; i++) {
3166 calc_data_addresses(&units[i]);
3169 /* TODO: Count references: go through all instructions, find EXTRN and LOCAL operands in expressions */
3170 /* TODO: Find modes of access for each DATA label (i.e. label MUST be allocated in zero page) */
3172 /* Map all data labels to 6502 RAM locations */
3173 verbose(1, "mapping data to RAM...");
3174 map_data_to_ram();
3175 maybe_print_ram_statistics();
3177 /* Only continue with processing if all data labels were mapped */
3178 if (err_count == 0) {
3179 verbose(1, "relocating code...");
3180 suppress = 1;
3181 relocate_units(&sc);
3182 suppress = 0;
3183 relocate_units(&sc);
3185 /* Only continue with processing if all code labels were mapped */
3186 if (err_count == 0) {
3187 verbose(1, "generating output...");
3188 generate_binary_output(&sc);
3189 if (generate_assembly)
3190 generate_assembly_output(&sc, stdout);
3195 /* Cleanup */
3196 verbose(1, "cleaning up...");
3198 /* Finalize units */
3199 for (i=0; i<unit_count; i++) {
3200 if (units[i].loaded) {
3201 finalize_local_array( &units[i].data_locals );
3202 finalize_local_array( &units[i].code_locals );
3203 unit_finalize( &units[i]._unit_ );
3206 /* Finalize hash tables */
3207 hashtab_finalize(label_hash);
3208 hashtab_finalize(constant_hash);
3209 hashtab_finalize(unit_hash);
3210 /* Finalize RAM blocks */
3211 finalize_ram_blocks();
3212 /* Finalize the script */
3213 script_finalize(&sc);
3215 /* All done. */
3216 return (err_count == 0) ? 0 : 1;