initialize repository
[xorcyst.git] / xlnk.c
blob3561d63e0e613beea019dfd8600c6402d2cae187
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 "getopt.h"
108 #include "objdef.h"
109 #include "opcode.h"
110 #include "script.h"
111 #include "unit.h"
112 #include "hashtab.h"
114 #define SAFE_FREE(m) if ((m) != NULL) { free(m); m = NULL; }
117 * Parses a string to an integer.
118 * @param s String
119 * @return Integer
121 static int str_to_int(char *s)
123 if (s[0] == '$') {
124 return strtol(&s[1], NULL, 16);
126 else if (s[0] == '%') {
127 return strtol(&s[1], NULL, 2);
129 return strtol(s, NULL, 0);
132 /*--------------------------------------------------------------------------*/
133 /* Argument parsing stuff. */
135 static char program_version[] = "xlnk 1.5.0";
137 struct tag_arguments {
138 char *input_file;
139 int silent;
140 int verbose;
143 typedef struct tag_arguments arguments;
145 /* Argument variables set by arg parser. */
146 static arguments program_args;
148 /* Long options for getopt_long(). */
149 static struct option long_options[] = {
150 { "quiet", no_argument, 0, 'q' },
151 { "silent", no_argument, 0, 's' },
152 { "verbose", no_argument, 0, 'v' },
153 { "help", no_argument, 0, 0 },
154 { "usage", no_argument, 0, 0 },
155 { "version", no_argument, 0, 'V' },
156 { 0 }
159 /* Prints usage message and exits. */
160 static void usage()
162 printf("\
163 Usage: xlnk [-qsvV] [--quiet] [--silent] [--verbose] [--help] [--usage]\n\
164 [--version] FILE\n\
166 exit(0);
169 /* Prints help message and exits. */
170 static void help()
172 printf("\
173 Usage: xlnk [OPTION...] FILE\n\
174 The XORcyst Linker -- it creates quite a stir\n\
176 -q, -s, --quiet, --silent Don't produce any output\n\
177 -v, --verbose Produce verbose output\n\
178 --help Give this help list\n\
179 --usage Give a short usage message\n\
180 -V, --version Print program version\n\
182 Report bugs to <dev@null>.\n\
184 exit(0);
187 /* Prints version and exits. */
188 static void version()
190 printf("%s\n", program_version);
191 exit(0);
194 /* Parses program arguments. */
195 static void
196 parse_arguments (int argc, char **argv)
198 int key;
199 /* getopt_long stores the option index here. */
200 int index = 0;
202 /* Set default values. */
203 program_args.silent = 0;
204 program_args.verbose = 0;
205 program_args.input_file = NULL;
207 /* Parse options. */
208 while ((key = getopt_long(argc, argv, "qsvV", long_options, &index)) != -1) {
209 switch (key) {
210 case 'q': case 's':
211 program_args.silent = 1;
212 break;
214 case 'v':
215 program_args.verbose = 1;
216 break;
218 case 0:
219 /* Use index to differentiate between options */
220 if (strcmp(long_options[index].name, "usage") == 0) {
221 usage();
223 else if (strcmp(long_options[index].name, "help") == 0) {
224 help();
226 break;
228 case 'V':
229 version();
230 break;
232 case '?':
233 /* Error message has been printed by getopt_long */
234 exit(1);
235 break;
237 default:
238 /* Forgot to handle a short option, most likely */
239 exit(1);
240 break;
244 /* Must be one additional argument, which is the input file. */
245 if (argc-1 != optind) {
246 printf("Usage: xlnk [OPTION...] FILE\nTry `xlnk --help' or `xlnk --usage' for more information.\n");
247 exit(1);
249 else {
250 program_args.input_file = argv[optind];
254 /*--------------------------------------------------------------------------*/
255 /* Data structures. */
257 /* Describes a local label in the unit. */
258 struct tag_local
260 char *name; /* NULL if not exported */
261 int resolved; /* 0 initially, set to 1 when phys_addr has been assigned */
262 int virt_addr;
263 int phys_addr;
264 int ref_count;
265 int size;
266 struct tag_xunit *owner;
267 unsigned short align;
268 unsigned char flags;
271 typedef struct tag_local local;
273 /* Describes an array of local labels. */
274 struct tag_local_array
276 local *entries;
277 int size;
280 typedef struct tag_local_array local_array;
283 * eXtended unit, has extra info built from basic unit ++
285 struct tag_xunit
287 unit _unit_; /* NB!!! "Superclass", must be first field for casting to work */
288 local_array data_locals;
289 local_array code_locals;
290 int bank_id;
291 int data_size;
292 int code_origin;
293 int code_size;
294 int loaded;
297 typedef struct tag_xunit xunit;
300 * Describes a 6502 RAM block available for allocation.
302 struct tag_avail_block
304 int start; /* Start address in 6502 space */
305 int end; /* End address in 6502 space */
306 struct tag_avail_block *next;
309 typedef struct tag_avail_block avail_block;
311 /** */
312 struct tag_calc_address_args
314 xunit *xu;
315 int index;
318 typedef struct tag_calc_address_args calc_address_args;
320 /** */
321 struct tag_write_binary_args
323 xunit *xu;
324 FILE *fp;
327 typedef struct tag_write_binary_args write_binary_args;
329 /*--------------------------------------------------------------------------*/
331 /** Array containing the units to link. */
332 static xunit *units;
333 /* Number of units in above array. */
334 static int unit_count;
336 /** Holds the current memory address. */
337 static int pc;
339 /** Hash tables used to lookup symbols. */
340 static hashtab *label_hash;
341 static hashtab *constant_hash;
342 static hashtab *unit_hash;
344 /** Number of errors and warnings during linking */
345 static int err_count;
346 static int warn_count;
348 static int suppress;
350 /* Head of the list of available 6502 RAM blocks (for data allocation). */
351 static avail_block *first_block = NULL;
353 static int total_ram = 0;
355 /* Bank info */
356 static int bank_offset;
357 static int bank_size;
358 static int bank_origin;
359 static int bank_id;
361 /* Debug info */
362 static unsigned char *unit_file = NULL; /* length byte followed by chars */
363 static int unit_line = -1;
365 /*--------------------------------------------------------------------------*/
368 * If the object file contains FILE and LINE bytecodes (assembled with
369 * --debug switch), unit_file and unit_line will contain the current
370 * source location. In that case, this function prints the location.
372 static void maybe_print_location()
374 char *str;
375 int len;
376 if (unit_file != NULL) {
377 /* Print source location */
378 len = unit_file[0] + 1;
379 str = (char *)malloc(len + 1);
380 strncpy(str, (char *)&unit_file[1], len);
381 str[len] = '\0';
382 fprintf(stderr, "%s:%d: ", str, unit_line);
383 free(str);
388 * If the object doesn't contain FILE and LINE bytecodes,
389 * unit_file will be <code>NULL</code>. In that case, this
390 * function prints a tip about reassembling with --debug switch.
392 static void maybe_print_debug_tip()
394 if (unit_file == NULL) {
395 fprintf(stderr, "\treassemble with --debug switch to obtain source location\n");
400 * Issues an error.
401 * @param fmt format string for printf
403 static void err(char *fmt, ...)
405 va_list ap;
406 va_start(ap, fmt);
407 if (!suppress) {
408 /* Print error message */
409 fprintf(stderr, "error: ");
410 maybe_print_location();
411 vfprintf(stderr, fmt, ap);
412 fprintf(stderr, "\n");
413 maybe_print_debug_tip();
414 /* Increase total error count */
415 err_count++;
417 va_end(ap);
421 * Issues a warning.
422 * @param fmt format string for printf
424 static void warn(char *fmt, ...)
426 va_list ap;
427 va_start(ap, fmt);
428 if (!suppress) {
429 /* Print warning message */
430 fprintf(stderr, "warning: ");
431 maybe_print_location();
432 vfprintf(stderr, fmt, ap);
433 fprintf(stderr, "\n");
434 maybe_print_debug_tip();
435 /* Increase total warning count */
436 warn_count++;
438 va_end(ap);
442 * Prints a message if --verbose switch was given.
443 * @param fmt format string for printf
445 static void verbose(char *fmt, ...)
447 va_list ap;
448 va_start(ap, fmt);
449 if (!suppress && program_args.verbose) {
450 vfprintf(stdout, fmt, ap);
451 fprintf(stdout, "\n");
453 va_end(ap);
456 /*--------------------------------------------------------------------------*/
457 /* Functions to manage 6502 RAM blocks. */
458 /* The RAM allocator maintains a list of these blocks that are used to
459 map the contents of the units' data segments to memory.
463 * Calculates number of bytes of 6502 RAM left for allocation.
465 static int ram_left()
467 int sum;
468 avail_block *b;
469 for (sum = 0, b = first_block; b != NULL; b = b->next) {
470 sum += b->end - b->start;
472 return sum;
476 * Adds a block of 6502 memory to the list of available memory regions.
477 * When adding multiple blocks they should be added in prioritized order.
478 * @param start Start address of the block
479 * @param end End address of the block (non-inclusive!)
481 static void add_ram_block(int start, int end)
483 avail_block *b;
484 /* Allocate a block struct */
485 avail_block *new_block = (avail_block *)malloc( sizeof(avail_block) );
486 if (new_block != NULL) {
487 /* Set the fields */
488 new_block->start = start;
489 new_block->end = end;
490 new_block->next = NULL;
491 /* Add it to list */
492 if (first_block == NULL) {
493 /* Start the list */
494 first_block = new_block;
496 else {
497 /* Add to end */
498 for (b = first_block; b->next != NULL; b = b->next) ;
499 b->next = new_block;
501 verbose(" added RAM block: %X-%X", new_block->start, new_block->end);
506 * Allocates a chunk of 6502 RAM to a local.
507 * @param l Local
508 * @return 0 if there isn't enough RAM to satisfy the request (fail), 1 otherwise (success)
510 static int alloc_ram(local *l)
512 int left;
513 int pad;
514 /* Try the available blocks in order. */
515 /* Use the first one that's sufficient. */
516 avail_block *b;
517 avail_block *n;
518 avail_block *p = NULL;
519 for (b = first_block; b != NULL; p = b, b = b->next) {
520 /* Check if zero page block required */
521 if (l->flags & LABEL_FLAG_ZEROPAGE) {
522 if (b->start >= 0x100) {
523 continue; /* This block is no good */
526 /* Calculate the # of bytes left in this block */
527 left = b->end - b->start;
528 /* See if it's enough */
529 if (left < l->size) {
530 continue; /* Not enough, sorry */
532 /* Check if alignment required */
533 if (l->flags & LABEL_FLAG_ALIGN) {
534 pad = b->start & ((1 << l->align) - 1);
535 if (pad != 0) {
536 /* This block doesn't match the alignment */
537 /* Break it into two blocks if possible */
538 pad = (1 << l->align) - pad;
539 pad = (left < pad) ? left : pad;
540 if (pad < left) {
541 n = (avail_block *)malloc(sizeof(avail_block));
542 n->start = b->start;
543 n->end = n->start + pad;
544 b->start += pad;
545 n->next = b;
546 if (b == first_block) {
547 first_block = n; /* New head */
549 b = n;
551 continue;
554 /* Pick this one. */
555 l->phys_addr = b->start;
556 /* Decrease block size by moving start address ahead */
557 b->start += l->size;
558 /* If there's no more space left in this block, discard it */
559 if (left == l->size) {
560 /* Remove from linked list */
561 if (p == NULL) {
562 /* Set successor block as new head */
563 first_block = b->next;
565 else {
566 /* Squeeze out */
567 p->next = b->next;
569 /* Free associated memory */
570 SAFE_FREE(b);
572 /* Return with success */
573 return 1;
575 /* Couldn't find a block large enough, return with failure */
576 return 0;
580 * Frees up memory associated with list of RAM blocks.
582 static void finalize_ram_blocks()
584 avail_block *b;
585 avail_block *t;
586 for (b = first_block; b != NULL; b = t) {
587 t = b->next;
588 SAFE_FREE(b);
592 /*--------------------------------------------------------------------------*/
593 /* Functions to get big-endian values from byte buffer. */
595 /* Gets single byte from buffer and increments index. */
596 static unsigned char get_1(unsigned char *b, int *i)
598 return b[(*i)++];
600 /* Gets big-endian short from buffer and increments index. */
601 static unsigned short get_2(unsigned char *b, int *i)
603 unsigned short result = get_1(b, i) << 8;
604 result |= get_1(b, i);
605 return result;
607 /* Gets big-endian 24-bit integer from buffer and increments index. */
608 static unsigned int get_3(unsigned char *b, int *i)
610 unsigned int result = get_2(b, i) << 8;
611 result |= get_1(b, i);
612 return result;
614 /* Gets big-endian int from buffer and increments index. */
615 /*static unsigned int get_4(unsigned char *b, int *i)
617 unsigned int result = get_2(b, i) << 16;
618 result |= get_2(b, i);
619 return result;
622 /*--------------------------------------------------------------------------*/
625 * Calculates the storage occupied by a CMD_LABEL bytecode's arguments.
627 static int label_cmd_args_size(unsigned char *bytes)
629 int size = 1; /* Smallest possible: flag byte */
630 int flags = bytes[0];
631 if (flags & LABEL_FLAG_EXPORT) { size += bytes[1] + 1 + 1; } /* Length byte + string */
632 if (flags & LABEL_FLAG_ALIGN) { size += 1; } /* Alignment */
633 if (flags & LABEL_FLAG_ADDR) { size += 2; } /* Address */
634 return size;
637 /** Signature for procedure to process a bytecode */
638 typedef void (*bytecodeproc)(unsigned char *, void *);
641 * Walks an array of bytecodes, calling corresponding bytecode handlers
642 * along the way.
643 * @param bytes Array of bytecodes, terminated by CMD_END
644 * @param handlers Array of bytecode handlers (entries can be NULL)
645 * @param arg Argument passed to bytecode handler, can be anything
647 static void bytecode_walk(unsigned char *bytes, bytecodeproc *handlers, void *arg)
649 int i;
650 unsigned char cmd;
651 unit_file = NULL;
652 unit_line = -1;
653 if (bytes == NULL) { return; }
654 i = 0;
655 do {
656 /* Get a command */
657 cmd = get_1(bytes, &i);
659 /* Check if debug command */
660 if (cmd < CMD_END) {
661 switch (cmd) {
662 case CMD_FILE:
663 unit_file = &bytes[i];
664 i += get_1(bytes, &i) + 1; /* Skip count and array of bytes */
665 break;
666 case CMD_LINE8: unit_line = get_1(bytes, &i); break;
667 case CMD_LINE16: unit_line = get_2(bytes, &i); break;
668 case CMD_LINE24: unit_line = get_3(bytes, &i); break;
669 case CMD_LINE_INC: unit_line++; break;
671 continue;
674 /* Call bytecode handler if one is present */
675 if (handlers[cmd-CMD_END] != NULL) {
676 handlers[cmd-CMD_END](&bytes[i-1], arg);
678 /* Skip any bytecode arguments */
679 switch (cmd) {
680 case CMD_END: break;
681 case CMD_BIN8: i += get_1(bytes, &i) + 1; break; /* Skip count and array of bytes */
682 case CMD_BIN16: i += get_2(bytes, &i) + 1; break; /* Skip count and array of bytes */
683 case CMD_LABEL: i += label_cmd_args_size(&bytes[i]); break; /* Skip flag byte and possibly name and alignment */
684 case CMD_INSTR: i += 3; break; /* Skip 6502 opcode and 16-bit expr id */
685 case CMD_DB: i += 2; break; /* Skip 16-bit expr id */
686 case CMD_DW: i += 2; break; /* Skip 16-bit expr id */
687 case CMD_DD: i += 2; break; /* Skip 16-bit expr id */
688 case CMD_DSI8: i += 1; break; /* Skip 8-bit count */
689 case CMD_DSI16: i += 2; break; /* Skip 16-bit count */
690 case CMD_DSB: i += 2; break; /* Skip 16-bit expr id */
692 default:
693 /* Invalid opcode */
694 err("invalid bytecode");
695 break;
697 } while (cmd != CMD_END);
700 /*--------------------------------------------------------------------------*/
701 /* Functions for expression evaluation. */
704 * Finalizes a constant.
705 * @param c Constant to finalize
707 static void finalize_constant(constant *c)
709 if (c->type == STRING_CONSTANT) {
710 SAFE_FREE(c->string);
715 * Gets string representation of an operator (OP_*, see objdef.h).
716 * @param op Operator
717 * @return String representation of operator
719 static const char *operator_to_string(int op)
721 switch (op) {
722 case OP_PLUS: return "+";
723 case OP_MINUS: return "-";
724 case OP_MUL: return "*";
725 case OP_DIV: return "/";
726 case OP_MOD: return "%";
727 case OP_SHL: return "<<";
728 case OP_SHR: return ">>";
729 case OP_AND: return "&";
730 case OP_OR: return "|";
731 case OP_XOR: return "^";
732 case OP_EQ: return "==";
733 case OP_NE: return "!=";
734 case OP_LT: return "<";
735 case OP_GT: return ">";
736 case OP_LE: return "<=";
737 case OP_GE: return ">=";
738 case OP_NOT: return "!";
739 case OP_NEG: return "~";
740 case OP_LO: return "<";
741 case OP_HI: return ">";
742 case OP_UMINUS: return "-";
743 case OP_BANK: return "^";
745 return "";
749 * Evaluates an expression recursively.
750 * The result will either be a integer or string literal, indicating successful
751 * evaluation; or an invalid type indicating that a symbol could not be translated
752 * to a constant (in other words, it could not be resolved). In this case,
753 * result->string contains the name of the symbol which couldn't be evaluated.
754 * @param u The unit where the expression is contained
755 * @param e The expression to evaluate
756 * @param result Pointer to resulting value
758 static void eval_recursive(xunit *u, expression *e, constant *result)
760 char *s;
761 local *l;
762 constant *c;
763 constant lhs_result, rhs_result;
764 switch (e->type) {
765 case OPERATOR_EXPRESSION:
766 switch (e->op_expr.operator) {
767 /* Binary operators */
768 case OP_PLUS:
769 case OP_MINUS:
770 case OP_MUL:
771 case OP_DIV:
772 case OP_MOD:
773 case OP_SHL:
774 case OP_SHR:
775 case OP_AND:
776 case OP_OR:
777 case OP_XOR:
778 case OP_EQ:
779 case OP_NE:
780 case OP_LT:
781 case OP_GT:
782 case OP_LE:
783 case OP_GE:
784 /* Evaluate both sides */
785 eval_recursive(u, e->op_expr.lhs, &lhs_result);
786 eval_recursive(u, e->op_expr.rhs, &rhs_result);
787 /* If either side is unresolved, then result is unresolved. */
788 if ((lhs_result.type == -1) || (rhs_result.type == -1)) {
789 result->type = -1;
791 /* If both sides are integer, then result is integer. */
792 else if ((lhs_result.type == INTEGER_CONSTANT) &&
793 (rhs_result.type == INTEGER_CONSTANT)) {
794 result->type = INTEGER_CONSTANT;
795 /* Perform the proper operation to obtain result. */
796 switch (e->op_expr.operator) {
797 case OP_PLUS: result->integer = lhs_result.integer + rhs_result.integer; break;
798 case OP_MINUS: result->integer = lhs_result.integer - rhs_result.integer; break;
799 case OP_MUL: result->integer = lhs_result.integer * rhs_result.integer; break;
800 case OP_DIV: result->integer = lhs_result.integer / rhs_result.integer; break;
801 case OP_MOD: result->integer = lhs_result.integer % rhs_result.integer; break;
802 case OP_SHL: result->integer = lhs_result.integer << rhs_result.integer; break;
803 case OP_SHR: result->integer = lhs_result.integer >> rhs_result.integer; break;
804 case OP_AND: result->integer = lhs_result.integer & rhs_result.integer; break;
805 case OP_OR: result->integer = lhs_result.integer | rhs_result.integer; break;
806 case OP_XOR: result->integer = lhs_result.integer ^ rhs_result.integer; break;
807 case OP_EQ: result->integer = lhs_result.integer == rhs_result.integer; break;
808 case OP_NE: result->integer = lhs_result.integer != rhs_result.integer; break;
809 case OP_LT: result->integer = lhs_result.integer < rhs_result.integer; break;
810 case OP_GT: result->integer = lhs_result.integer > rhs_result.integer; break;
811 case OP_LE: result->integer = lhs_result.integer <= rhs_result.integer; break;
812 case OP_GE: result->integer = lhs_result.integer >= rhs_result.integer; break;
815 /* If both sides are string... */
816 else if ((lhs_result.type == STRING_CONSTANT) &&
817 (rhs_result.type == STRING_CONSTANT)) {
818 switch (e->op_expr.operator) {
819 case OP_PLUS:
820 /* Concatenate */
821 result->string = (char *)malloc(strlen(lhs_result.string)+strlen(rhs_result.string)+1);
822 if (result->string != NULL) {
823 strcpy(result->string, lhs_result.string);
824 strcat(result->string, rhs_result.string);
825 result->type = STRING_CONSTANT;
827 break;
829 /* String comparison: using strcmp() */
830 case OP_EQ: result->integer = strcmp(lhs_result.string, rhs_result.string) == 0; break;
831 case OP_NE: result->integer = strcmp(lhs_result.string, rhs_result.string) != 0; break;
832 case OP_LT: result->integer = strcmp(lhs_result.string, rhs_result.string) < 0; break;
833 case OP_GT: result->integer = strcmp(lhs_result.string, rhs_result.string) > 0; break;
834 case OP_LE: result->integer = strcmp(lhs_result.string, rhs_result.string) <= 0; break;
835 case OP_GE: result->integer = strcmp(lhs_result.string, rhs_result.string) >= 0; break;
837 default:
838 /* Not defined operator for string operation... */
839 break;
842 else {
843 /* Error, operands are incompatible */
844 result->type = -1;
845 err("incompatible operands to `%s' in expression", operator_to_string(e->op_expr.operator) );
847 /* Discard the operands */
848 finalize_constant(&lhs_result);
849 finalize_constant(&rhs_result);
850 break; /* Binary operator */
852 /* Unary operators */
853 case OP_NOT:
854 case OP_NEG:
855 case OP_LO:
856 case OP_HI:
857 case OP_UMINUS:
858 /* Evaluate the single operand */
859 eval_recursive(u, e->op_expr.lhs, &lhs_result);
860 /* If operand is unresolved then result is unresolved. */
861 if (lhs_result.type == -1) {
862 result->type = -1;
864 /* If operand is integer then result is integer. */
865 else if (lhs_result.type == INTEGER_CONSTANT) {
866 result->type = INTEGER_CONSTANT;
867 /* Perform the proper operation to obtain result. */
868 switch (e->op_expr.operator) {
869 case OP_NOT: result->integer = !lhs_result.integer; break;
870 case OP_NEG: result->integer = ~lhs_result.integer; break;
871 case OP_LO: result->integer = lhs_result.integer & 0xFF; break;
872 case OP_HI: result->integer = (lhs_result.integer >> 8) & 0xFF; break;
873 case OP_UMINUS: result->integer = -lhs_result.integer; break;
876 else {
877 /* Error, invalid operand */
878 err("incompatible operand to `%s' in expression", operator_to_string(e->op_expr.operator) );
879 result->type = -1;
881 /* Discard the operand */
882 finalize_constant(&lhs_result);
883 break; /* Unary operator */
885 case OP_BANK:
886 switch (e->op_expr.lhs->type) {
887 case LOCAL_EXPRESSION:
888 /* Simple, it must be in the same (current) bank */
889 result->integer = bank_id;
890 result->type = INTEGER_CONSTANT;
891 break;
893 case EXTERNAL_EXPRESSION:
894 /* Get the name of the external */
895 s = u->_unit_.externals[e->op_expr.lhs->extrn_id].name;
896 /* Look it up */
897 if ((l = (local *)hashtab_get(label_hash, s)) != NULL) {
898 /* It's a label */
899 result->integer = l->owner->bank_id;
900 result->type = INTEGER_CONSTANT;
902 else if ((c = (constant *)hashtab_get(constant_hash, s)) != NULL) {
903 /* It's a constant */
904 result->integer = ((xunit *)c->unit)->bank_id;
905 result->type = INTEGER_CONSTANT;
907 else {
908 result->type = -1;
910 break;
912 default:
913 result->type = -1;
914 break;
916 break;
918 break;
920 case INTEGER_EXPRESSION:
921 /* Copy value to result */
922 result->type = INTEGER_CONSTANT;
923 result->integer = e->integer;
924 break;
926 case STRING_EXPRESSION:
927 /* Copy value to result */
928 result->string = (char *)malloc(strlen(e->string) + 1);
929 if (result->string != NULL) {
930 strcpy(result->string, e->string);
931 result->type = STRING_CONSTANT;
933 break;
935 case LOCAL_EXPRESSION:
936 if (e->local_id >= u->data_locals.size) {
937 /* It's a code local */
938 l = &u->code_locals.entries[e->local_id - u->data_locals.size];
940 else {
941 /* It's a data local */
942 l = &u->data_locals.entries[e->local_id];
944 /* Test if it's resolved */
945 if (l->resolved) {
946 /* Copy address to result */
947 result->type = INTEGER_CONSTANT;
948 result->integer = l->phys_addr;
950 else {
951 /* Not resolved (yet, at least) */
952 result->type = -1;
954 break;
956 case EXTERNAL_EXPRESSION:
957 /* Get the name of the external */
958 s = u->_unit_.externals[e->extrn_id].name;
959 /* Look it up */
960 if ((l = (local *)hashtab_get(label_hash, s)) != NULL) {
961 /* It's a label */
962 /* Test if it's resolved */
963 if (l->resolved) {
964 /* Copy address to result */
965 result->type = INTEGER_CONSTANT;
966 result->integer = l->phys_addr;
968 else {
969 /* Not resolved (yet) */
970 result->type = -1;
973 else if ((c = (constant *)hashtab_get(constant_hash, s)) != NULL) {
974 /* It's a constant */
975 /* Copy value to result */
976 switch (c->type) {
977 case INTEGER_CONSTANT:
978 result->type = INTEGER_CONSTANT;
979 result->integer = c->integer;
980 break;
982 case STRING_CONSTANT:
983 result->string = (char *)malloc(strlen(c->string) + 1);
984 if (result->string != NULL) {
985 strcpy(result->string, c->string);
986 result->type = STRING_CONSTANT;
988 break;
991 else {
992 /* Error */
993 result->type = -1;
994 err("unknown symbol `%s' referenced from %s", s, u->_unit_.name);
996 break;
998 case PC_EXPRESSION:
999 /* Copy current PC to result */
1000 result->type = INTEGER_CONSTANT;
1001 result->integer = pc;
1002 break;
1007 * Evaluates an expression.
1008 * @param u The unit where the expression is contained
1009 * @param exid The unique ID of the expression
1010 * @param result Where to store the result of the evaluation
1012 static void eval_expression(xunit *u, int exid, constant *result)
1014 /* Get the expression with id exid */
1015 expression *exp = u->_unit_.expressions[exid];
1016 /* Evaluate recursively */
1017 eval_recursive(u, exp, result);
1020 /*--------------------------------------------------------------------------*/
1021 /* Functions for incrementing PC, with error handling for wraparound. */
1024 * Increases PC by amount.
1025 * Issues error if the PC wraps around.
1027 static void inc_pc(int amount, void *arg)
1029 calc_address_args *aargs;
1030 /* Check for 16-bit overflow */
1031 if ((pc <= 0x10000) && ((pc+amount) > 0x10000)) {
1032 aargs = (calc_address_args *)arg;
1033 err("PC went beyond 64K when linking `%s'", aargs->xu->_unit_.name);
1035 /* Add! */
1036 pc += amount;
1040 * Increases PC by 8-bit value immediately following bytecode command.
1042 static void inc_pc_count8(unsigned char *b, void *arg)
1044 int i = 1;
1045 inc_pc( get_1(b, &i) + 1, arg );
1049 * Increases PC by 16-bit value immediately following bytecode command.
1051 static void inc_pc_count16(unsigned char *b, void *arg)
1053 int i = 1;
1054 inc_pc( get_2(b, &i) + 1, arg );
1058 * Increases PC by 1.
1060 static void inc_pc_1(unsigned char *b, void *arg)
1062 inc_pc( 1, arg );
1066 * Increases PC by 2.
1068 static void inc_pc_2(unsigned char *b, void *arg)
1070 inc_pc( 2, arg );
1074 * Increases PC by 4.
1076 static void inc_pc_4(unsigned char *b, void *arg)
1078 inc_pc( 4, arg );
1082 * Increases PC according to size of define data command.
1084 static void inc_pc_dsb(unsigned char *b, void *arg)
1086 constant c;
1087 int exid;
1088 calc_address_args *args = (calc_address_args *)arg;
1089 int i = 1;
1090 /* Get expression ID */
1091 exid = get_2(b, &i);
1092 /* Evaluate expression */
1093 eval_expression(args->xu, exid, &c);
1094 /* Handle the result */
1095 if (c.type == INTEGER_CONSTANT) {
1096 /* An array of bytes will be located here */
1097 /* Advance PC appropriately */
1098 inc_pc( c.integer, arg );
1100 else if (c.type == STRING_CONSTANT) {
1101 /* Error, doesn't make sense here */
1102 err("unexpected string operand (`%s') to storage directive", c.string);
1104 else {
1105 /* Error, unresolved */
1106 //err("unresolved symbol");
1109 finalize_constant(&c);
1113 * Increments PC according to the length of this instruction.
1115 static void inc_pc_instr(unsigned char *b, void *arg)
1117 constant c;
1118 unsigned char op, t;
1119 int exid;
1120 calc_address_args *args = (calc_address_args *)arg;
1121 /* Get opcode */
1122 int i = 1;
1123 op = get_1(b, &i);
1124 /* Get expression ID */
1125 exid = get_2(b, &i);
1126 /* Evaluate it */
1127 eval_expression(args->xu, exid, &c);
1128 /* Handle the result */
1129 if (c.type == INTEGER_CONSTANT) {
1130 /* See if it can be reduced to ZP instruction */
1131 if ((c.integer < 0x100) &&
1132 ((t = opcode_zp_equiv(op)) != 0xFF)) {
1133 /* replace op by ZP-version */
1134 op = t;
1135 b[1] = t;
1138 else if (c.type == STRING_CONSTANT) {
1139 /* Error, string operand doesn't make sense here */
1140 err("invalid instruction operand (string)");
1142 else {
1143 /* Address not available yet (forward reference). */
1144 //err("unresolved symbol");
1146 /* Advance PC */
1147 inc_pc( opcode_length(op), arg );
1150 /*--------------------------------------------------------------------------*/
1151 /* Functions for writing pure 6502 binary from bytecodes. */
1154 * Writes an array of bytes.
1156 static void write_bin8(unsigned char *b, void *arg)
1158 int count;
1159 int i;
1160 write_binary_args *args = (write_binary_args *)arg;
1161 /* Get 8-bit count */
1162 i = 1;
1163 count = get_1(b, &i) + 1;
1164 /* Write data */
1165 fwrite(&b[i], 1, count, args->fp);
1166 /* Advance PC */
1167 inc_pc( count, arg );
1171 * Writes an array of bytes.
1173 static void write_bin16(unsigned char *b, void *arg)
1175 int count;
1176 int i;
1177 write_binary_args *args = (write_binary_args *)arg;
1178 /* Get 16-bit count */
1179 i = 1;
1180 count = get_2(b, &i) + 1;
1181 /* Write data */
1182 fwrite(&b[i], 1, count, args->fp);
1183 /* Advance PC */
1184 inc_pc( count, arg );
1188 * Writes an instruction.
1190 static void write_instr(unsigned char *b, void *arg)
1192 constant c;
1193 unsigned char op;
1194 int i;
1195 int exid;
1196 write_binary_args *args = (write_binary_args *)arg;
1197 /* Get opcode */
1198 i = 1;
1199 op = get_1(b, &i);
1200 /* Get expression ID */
1201 exid = get_2(b, &i);
1202 /* Evaluate expression */
1203 eval_expression(args->xu, exid, &c);
1205 /* Write the opcode */
1206 fputc(op, args->fp);
1208 if (opcode_length(op) == 2) {
1209 /* Operand must fit in 1 byte */
1210 /* Check if it's a relative jump */
1211 switch (op) {
1212 case 0x10:
1213 case 0x30:
1214 case 0x50:
1215 case 0x70:
1216 case 0x90:
1217 case 0xB0:
1218 case 0xD0:
1219 case 0xF0:
1220 /* Calculate difference between target and address of next instruction */
1221 c.integer = c.integer - (pc + 2);
1222 /* Make sure jump is in range */
1223 if ( (c.integer < -128) || (c.integer > 127) ) {
1224 err("branch out of range");
1226 /* Make it a byte value */
1227 c.integer &= 0xFF;
1228 break;
1230 if (c.integer >= 0x100) {
1231 err("instruction operand doesn't fit in 1 byte");
1233 else {
1234 /* Write it */
1235 fputc(c.integer, args->fp);
1238 else {
1239 /* Operand must fit in 2 bytes */
1240 if (c.integer >= 0x10000) {
1241 err("instruction operand doesn't fit in 2 bytes");
1243 else {
1244 /* Write it, low byte first */
1245 fputc(c.integer, args->fp);
1246 fputc(c.integer >> 8, args->fp);
1249 /* Advance PC */
1250 inc_pc( opcode_length(op), arg );
1254 * Writes a byte, word or dword.
1256 static void write_dx(unsigned char *b, void *arg)
1258 constant c;
1259 int i;
1260 int exid;
1261 write_binary_args *args = (write_binary_args *)arg;
1262 /* Get expression ID */
1263 i = 1;
1264 exid = get_2(b, &i);
1265 /* Evaluate expression */
1266 eval_expression(args->xu, exid, &c);
1268 if (c.type == INTEGER_CONSTANT) {
1269 /* Write low byte */
1270 fputc(c.integer, args->fp);
1271 /* If 2+ bytes, write high ones */
1272 switch (b[0]) {
1273 case CMD_DB:
1274 if (c.integer > 0xFF) {
1275 warn("`.DB' operand $%X out of range; truncated", c.integer);
1277 break;
1279 case CMD_DW:
1280 fputc(c.integer >> 8, args->fp);
1281 if (c.integer > 0xFFFF) {
1282 warn("`.DW' operand $%X out of range; truncated", c.integer);
1284 break;
1286 case CMD_DD:
1287 fputc(c.integer >> 8, args->fp);
1288 fputc(c.integer >> 16, args->fp);
1289 fputc(c.integer >> 24, args->fp);
1290 break;
1292 /* Advance PC */
1293 switch (b[0]) {
1294 case CMD_DB: inc_pc( 1, arg ); break;
1295 case CMD_DW: inc_pc( 2, arg ); break;
1296 case CMD_DD: inc_pc( 4, arg ); break;
1299 else if (c.type == STRING_CONSTANT) {
1300 /* Write sequence of characters */
1301 for (i=0; i<strlen(c.string); i++) {
1302 /* Write low byte */
1303 fputc(c.string[i], args->fp);
1304 /* If 2+ bytes, write high ones */
1305 switch (b[0]) {
1306 case CMD_DW:
1307 fputc(0, args->fp);
1308 break;
1310 case CMD_DD:
1311 fputc(0, args->fp);
1312 fputc(0, args->fp);
1313 fputc(0, args->fp);
1314 break;
1316 /* Advance PC */
1317 switch (b[0]) {
1318 case CMD_DB: inc_pc( 1, arg ); break;
1319 case CMD_DW: inc_pc( 2, arg ); break;
1320 case CMD_DD: inc_pc( 4, arg ); break;
1325 finalize_constant(&c);
1329 * Writes a series of zeroes.
1331 static void write_dsi8(unsigned char *b, void *arg)
1333 int count;
1334 int i;
1335 write_binary_args *args = (write_binary_args *)arg;
1336 /* Get 8-bit count */
1337 i = 1;
1338 count = get_1(b, &i) + 1;
1339 /* Write zeroes */
1340 for (i=0; i<count; i++) {
1341 fputc(0, args->fp);
1343 /* Advance PC */
1344 inc_pc( count, arg );
1348 * Writes a series of zeroes.
1350 static void write_dsi16(unsigned char *b, void *arg)
1352 int count;
1353 int i;
1354 write_binary_args *args = (write_binary_args *)arg;
1355 /* Get 16-bit count */
1356 i = 1;
1357 count = get_2(b, &i) + 1;
1358 /* Write zeroes */
1359 for (i=0; i<count; i++) {
1360 fputc(0, args->fp);
1362 /* Advance PC */
1363 inc_pc( count, arg );
1367 * Writes a series of zeroes.
1369 static void write_dsb(unsigned char *b, void *arg)
1371 constant c;
1372 int i;
1373 int exid;
1374 write_binary_args *args = (write_binary_args *)arg;
1375 /* Get expression ID */
1376 i = 1;
1377 exid = get_2(b, &i);
1378 /* Evaluate expression */
1379 eval_expression(args->xu, exid, &c);
1380 if (c.integer < 0) {
1381 err("negative count");
1383 else if (c.integer > 0) {
1384 /* Write zeroes */
1385 for (i=0; i<c.integer; i++) {
1386 fputc(0, args->fp);
1388 /* Advance PC */
1389 inc_pc( c.integer, arg );
1394 * Writes a code segment as fully native 6502 code.
1395 * @param fp File handle
1396 * @param u Unit whose code to write
1398 static void write_as_binary(FILE *fp, xunit *u)
1400 write_binary_args args;
1401 /* Table of callback functions for our purpose. */
1402 bytecodeproc handlers[] =
1404 NULL, /* CMD_END */
1405 write_bin8, /* CMD_BIN8 */
1406 write_bin16, /* CMD_BIN16 */
1407 NULL, /* CMD_LABEL */
1408 write_instr, /* CMD_INSTR */
1409 write_dx, /* CMD_DB */
1410 write_dx, /* CMD_DW */
1411 write_dx, /* CMD_DD */
1412 write_dsi8, /* CMD_DSI8 */
1413 write_dsi16, /* CMD_DSI16 */
1414 write_dsb /* CMD_DSB */
1416 /* Fill in args */
1417 args.xu = u;
1418 args.fp = fp;
1419 /* Reset PC */
1420 pc = u->code_origin;
1421 /* Do the walk */
1422 bytecode_walk(u->_unit_.codeseg.bytes, handlers, (void *)&args);
1425 #define XLNK_NO_DEBUG
1426 #ifndef XLNK_NO_DEBUG
1428 /*--------------------------------------------------------------------------*/
1429 /* Functions for debugging bytecodes. */
1432 * Gets string representation of bytecode command.
1433 * @param cmd CMD_*
1434 * @return String representation ("CMD_*")
1436 static const char *bytecode_to_string(unsigned char cmd)
1438 switch (cmd) {
1439 case CMD_FILE: return "CMD_FILE";
1440 case CMD_LINE8: return "CMD_LINE8";
1441 case CMD_LINE16:return "CMD_LINE16";
1442 case CMD_LINE24:return "CMD_LINE24";
1443 case CMD_LINE_INC: return "CMD_LINE_INC";
1444 case CMD_END: return "CMD_END";
1445 case CMD_BIN8: return "CMD_BIN8";
1446 case CMD_BIN16: return "CMD_BIN16";
1447 case CMD_LABEL: return "CMD_LABEL";
1448 case CMD_INSTR: return "CMD_INSTR";
1449 case CMD_DB: return "CMD_DB";
1450 case CMD_DW: return "CMD_DW";
1451 case CMD_DD: return "CMD_DD";
1452 case CMD_DSI8: return "CMD_DSI8";
1453 case CMD_DSI16: return "CMD_DSI16";
1454 case CMD_DSB: return "CMD_DSB";
1456 return "bytecode_to_string: invalid bytecode";
1460 * Print a bytecode.
1461 * @param b Bytecodes
1462 * @param arg Not used
1464 static void print_it(unsigned char *b, void *arg)
1466 printf("%s\n", bytecode_to_string(b[0]) );
1470 * Prints bytecodes.
1471 * @param bytes Bytecodes
1473 static void print_bytecodes(unsigned char *bytes)
1475 bytecodeproc handlers[] =
1477 print_it,print_it,print_it,print_it,print_it,
1478 print_it,print_it,print_it,print_it,print_it,
1479 print_it,print_it,print_it
1481 bytecode_walk(bytes, handlers, NULL);
1485 * Prints a unit.
1486 * @param u Unit
1488 static void print_unit(unit *u)
1490 print_bytecodes(u->dataseg.bytes);
1491 print_bytecodes(u->codeseg.bytes);
1494 #endif /* !XLNK_NO_DEBUG */
1496 /*--------------------------------------------------------------------------*/
1497 /* Functions for managing arrays of unit locals. */
1500 * Creates array of locals.
1501 * @param size Number of locals
1502 * @param la Local array
1504 static void create_local_array(int size, local_array *la)
1506 la->size = size;
1507 /* Allocate space for entries */
1508 if (size > 0) {
1509 la->entries = (local *)malloc(sizeof(local) * size);
1511 else {
1512 la->entries = NULL;
1517 * Finalizes array of locals.
1519 static void finalize_local_array(local_array *la)
1521 int i;
1522 /* Free entry attributes */
1523 for (i=0; i<la->size; i++) {
1524 SAFE_FREE(la->entries[i].name);
1526 /* Free array itself */
1527 SAFE_FREE(la->entries);
1530 /*--------------------------------------------------------------------------*/
1531 /* Functions for counting and registering locals in a unit. */
1532 /* In bytecode expressions, locals are referred to by their index.
1533 In order to not have to go through the bytecodes every time to
1534 find a label definition, the following functions build an array
1535 of structures that can be indexed by the local ID to obtain its
1536 information.
1540 * Counts this local.
1542 static void count_one_local(unsigned char *b, void *arg)
1544 /* Argument points to the counter */
1545 int *count = (int *)arg;
1546 /* Increment count */
1547 (*count)++;
1551 * Counts the number of locals (labels) in an array of bytecodes.
1552 * @param b Bytecodes, terminated by CMD_END
1553 * @return Number of locals counted
1555 static int count_locals(unsigned char *b)
1557 int count;
1558 /* Table of callback functions for our purpose. */
1559 bytecodeproc handlers[] =
1561 NULL, /* CMD_END */
1562 NULL, /* CMD_BIN8 */
1563 NULL, /* CMD_BIN16 */
1564 count_one_local, /* CMD_LABEL */
1565 NULL, /* CMD_INSTR */
1566 NULL, /* CMD_DB */
1567 NULL, /* CMD_DW */
1568 NULL, /* CMD_DD */
1569 NULL, /* CMD_DSI8 */
1570 NULL, /* CMD_DSI16 */
1571 NULL /* CMD_DSB */
1573 /* Reset count */
1574 count = 0;
1575 /* Count the locals now */
1576 bytecode_walk(b, handlers, (void *)&count);
1577 /* Return the number of locals counted */
1578 return count;
1581 static xunit *reg_unit = NULL;
1584 * Puts this local into array of locals for current unit.
1586 static void register_one_local(unsigned char *b, void *arg)
1588 int len;
1589 int i= 1;
1590 /* Argument points to a pointer which points to the local struct to fill in */
1591 local **lpptr = (local **)arg;
1592 local *lptr = *lpptr;
1593 /* Initialize some fields */
1594 lptr->resolved = 0;
1595 lptr->ref_count = 0;
1596 lptr->name = NULL;
1597 lptr->align = 1;
1598 lptr->owner = reg_unit;
1599 /* Get flag byte */
1600 lptr->flags = get_1(b, &i);
1601 /* Test export flag */
1602 if (lptr->flags & LABEL_FLAG_EXPORT) {
1603 /* Get the length of the name */
1604 len = get_1(b, &i) + 1;
1605 /* Allocate space for name */
1606 lptr->name = (char *)malloc( len + 1 );
1607 if (lptr->name != NULL) {
1608 /* Copy name from bytecodes */
1609 memcpy(lptr->name, &b[i], len);
1610 /* Zero-terminate string */
1611 lptr->name[len] = '\0';
1613 i += len;
1615 /* Test align flag */
1616 if (lptr->flags & LABEL_FLAG_ALIGN) {
1617 lptr->align = get_1(b, &i);
1619 /* Test address flag */
1620 if (lptr->flags & LABEL_FLAG_ADDR) {
1621 lptr->phys_addr = get_2(b, &i);
1622 lptr->resolved = 1;
1624 /* Point to next local in array */
1625 *lpptr += 1;
1629 * Puts all locals found in the array of bytecodes into array.
1630 * @param b Bytecodes, terminated by CMD_END
1631 * @param la Pointer to array to receive locals
1632 * @param xu Owner unit
1634 static void register_locals(unsigned char *b, local_array *la, xunit *xu)
1636 local *lptr;
1637 local **lpptr;
1638 /* Table of callback functions for our purpose. */
1639 bytecodeproc handlers[] =
1641 NULL, /* CMD_END */
1642 NULL, /* CMD_BIN8 */
1643 NULL, /* CMD_BIN16 */
1644 register_one_local, /* CMD_LABEL */
1645 NULL, /* CMD_INSTR */
1646 NULL, /* CMD_DB */
1647 NULL, /* CMD_DW */
1648 NULL, /* CMD_DD */
1649 NULL, /* CMD_DSI8 */
1650 NULL, /* CMD_DSI16 */
1651 NULL /* CMD_DSB */
1653 /* Create array of locals */
1654 create_local_array(count_locals(b), la);
1655 /* Prepare args */
1656 lptr = la->entries;
1657 lpptr = &lptr;
1658 reg_unit = xu;
1659 /* Go! */
1660 bytecode_walk(b, handlers, (void *)lpptr);
1663 /*--------------------------------------------------------------------------*/
1664 /* Functions for entering exported symbols into proper hash table. */
1667 * Enters an exported symbol into a hash table.
1668 * @param tab Hash table to enter it into
1669 * @param key Key
1670 * @param data Data
1671 * @param u Owner unit
1673 static void enter_exported_symbol(hashtab *tab, void *key, void *data, unit *u)
1675 /* Make sure symbol doesn't already exist */
1676 if ((hashtab_get(label_hash, key) != NULL) ||
1677 (hashtab_get(constant_hash, key) != NULL) ) {
1678 /* Error, duplicate symbol */
1679 err("duplicate symbol `%s' exported from unit `%s'", (char *)key, u->name);
1681 else {
1682 /* Enter it */
1683 hashtab_put(tab, key, data);
1688 * Enters all constants in a unit into the proper hash table.
1689 * @param u Unit whose constants to enter
1691 static void enter_exported_constants(unit *u)
1693 int i;
1694 constant *c;
1695 /* Go through all constants in unit */
1696 for (i=0; i<u->const_count; i++) {
1697 c = &u->constants[i];
1698 enter_exported_symbol(constant_hash, (void *)c->name, (void *)c, u);
1703 * Enters locals which should be globally visible into the proper hash table.
1704 * @param la Array of locals
1705 * @param u Owner unit
1707 static void enter_exported_locals(local_array *la, unit *u)
1709 int i;
1710 local *l;
1711 /* Go through all locals */
1712 for (i=0; i<la->size; i++) {
1713 l = &la->entries[i];
1714 /* If it has a name, it is exported */
1715 if (l->name != NULL) {
1716 enter_exported_symbol(label_hash, (void *)l->name, (void *)l, u);
1721 /*--------------------------------------------------------------------------*/
1722 /* Functions for calculating addresses of data labels in a unit. */
1725 * Sets the virtual address of this local to current PC value.
1727 static void set_data_address(unsigned char *b, void *arg)
1729 calc_address_args *args = (calc_address_args *)arg;
1730 /* Get the label */
1731 local *l = &args->xu->data_locals.entries[args->index];
1732 if (!l->resolved) {
1733 /* Set the virtual address */
1734 l->virt_addr = pc;
1736 /* Increase label index */
1737 args->index++;
1741 * Calculates addresses of labels in a data segment relative to 0.
1742 * Only a small set of bytecode commands are allowed in a data segment:
1743 * - label (which we want to assign a virtual address)
1744 * - storage (constant or variable)
1746 static void calc_data_addresses(xunit *u)
1748 calc_address_args args;
1749 /* Table of callback functions for our purpose. */
1750 bytecodeproc handlers[] =
1752 NULL, /* CMD_END */
1753 NULL, /* CMD_BIN8 */
1754 NULL, /* CMD_BIN16 */
1755 set_data_address, /* CMD_LABEL */
1756 NULL, /* CMD_INSTR */
1757 NULL, /* CMD_DB */
1758 NULL, /* CMD_DW */
1759 NULL, /* CMD_DD */
1760 inc_pc_count8, /* CMD_DSI8 */
1761 inc_pc_count16, /* CMD_DSI16 */
1762 inc_pc_dsb /* CMD_DSB */
1764 /* Fill in args */
1765 args.xu = u;
1766 args.index = 0;
1767 /* Reset PC */
1768 pc = 0;
1769 /* Map away! */
1770 bytecode_walk(u->_unit_.dataseg.bytes, handlers, (void *)&args);
1771 /* Store the end address, which is the total size of data */
1772 u->data_size = pc;
1775 /*--------------------------------------------------------------------------*/
1777 /* Constructs 32-bit sort key for local. */
1778 #define SORT_KEY(l) (unsigned long)((((l)->flags & LABEL_FLAG_ZEROPAGE) << 30) | ((l)->align << 24) | (0x10000-(l)->size))
1781 * Array is sorted from high to low value.
1783 static int label_partition(local **a, int p, int r)
1785 int x;
1786 int i;
1787 int j;
1788 x = SORT_KEY(a[r]);
1789 i = p - 1;
1790 local *temp;
1791 for (j=p; j<r; j++) {
1792 if (SORT_KEY(a[j]) >= x) {
1793 i = i + 1;
1794 temp = a[i];
1795 a[i] = a[j];
1796 a[j] = temp;
1799 temp = a[i+1];
1800 a[i+1] = a[r];
1801 a[r] = temp;
1802 return i + 1;
1806 * Quicksort implementation used to sort array of pointers to locals.
1808 static void label_qsort(local **a, int p, int r)
1810 int q;
1811 if (p < r) {
1812 q = label_partition(a, p, r);
1813 label_qsort(a, p, q-1);
1814 label_qsort(a, q+1, r);
1819 * Maps all data labels to 6502 RAM locations.
1820 * This is a very important function. It takes all the data labels from all
1821 * the loaded units and attempts to assign them unique physical addresses.
1822 * The list of target RAM blocks given in the linker script is the premise.
1824 static void map_data_to_ram()
1826 int i, j, k;
1827 local_array *la;
1828 local **total_order;
1829 local *l;
1830 int count;
1831 int size;
1832 /* Calculate total number of labels to map */
1833 count = 0;
1834 for (i=0; i<unit_count; i++) {
1835 count += units[i].data_locals.size;
1837 /* Put pointers to all data labels in one big array */
1838 total_order = (local **)malloc( count * sizeof(local *) );
1839 for (i=0, k=0; i<unit_count; i++) {
1840 la = &units[i].data_locals;
1841 for (j=0; j<la->size; j++) {
1842 /* Use virtual addresses to calculate size from this label to next */
1843 if (j == la->size-1) {
1844 size = units[i].data_size;
1846 else {
1847 size = la->entries[j+1].virt_addr;
1849 la->entries[j].size = size - la->entries[j].virt_addr;
1850 /* Put pointer in array */
1851 total_order[k++] = &la->entries[j];
1854 /* Sort them */
1855 label_qsort(total_order, 0, count-1);
1856 /* Map them */
1857 for (i=0; i<count; i++) {
1858 l = total_order[i];
1859 /* Try to allocate it */
1860 if (alloc_ram(l) == 1) {
1861 /* Good, label mapped successfully */
1862 l->resolved = 1;
1863 if (l->name != NULL) {
1864 verbose(" %.4X-%.4X %s", l->phys_addr, l->phys_addr + l->size-1, l->name);
1867 else {
1868 /* Error, couldn't allocate */
1869 err("out of 6502 RAM while allocating unit `%s'", l->owner->_unit_.name);
1870 return;
1873 free(total_order);
1876 /*--------------------------------------------------------------------------*/
1877 /* Functions for calculating offsets of code labels in a unit. */
1880 * Sets the address of this code label to current PC.
1882 static void set_code_address(unsigned char *b, void *arg)
1884 calc_address_args *args = (calc_address_args *)arg;
1885 /* Get the label */
1886 local *l = &args->xu->code_locals.entries[args->index];
1887 if (!l->resolved) {
1888 /* Set the physical address to current PC */
1889 l->phys_addr = pc;
1890 l->resolved = 1;
1891 if ((l->name != NULL) && program_args.verbose) {
1892 printf(" %.4X %s\n", l->phys_addr, l->name);
1895 /* Increase label index */
1896 args->index++;
1900 * Calculates addresses of code labels in a segment.
1901 * NOTE: Only the virtual addresses (relative to 0) are calculated.
1902 * The labels then need to be relocated to obtain the physical address (see below).
1903 * @param u Unit
1905 static void calc_code_addresses(xunit *u)
1907 calc_address_args args;
1908 /* Table of callback functions for our purpose. */
1909 bytecodeproc handlers[] =
1911 NULL, /* CMD_END */
1912 inc_pc_count8, /* CMD_BIN8 */
1913 inc_pc_count16, /* CMD_BIN16 */
1914 set_code_address, /* CMD_LABEL */
1915 inc_pc_instr, /* CMD_INSTR */
1916 inc_pc_1, /* CMD_DB -- TODO, error if string */
1917 inc_pc_2, /* CMD_DW */
1918 inc_pc_4, /* CMD_DD */
1919 inc_pc_count8, /* CMD_DSI8 */
1920 inc_pc_count16, /* CMD_DSI16 */
1921 inc_pc_dsb /* CMD_DSB */
1923 /* Fill in args */
1924 args.xu = u;
1925 args.index = 0;
1926 /* Do the walk */
1927 bytecode_walk(u->_unit_.codeseg.bytes, handlers, (void *)&args);
1928 /* Store the total size of code */
1929 u->code_size = pc - u->code_origin;
1932 /*--------------------------------------------------------------------------*/
1935 * Issues a script error.
1937 static void scripterr(script *s, script_command *c, char *fmt, ...)
1939 va_list ap;
1940 va_start(ap, fmt);
1942 /* Print error message */
1943 fprintf(stderr, "error: %s:%d: `%s': ", s->name, c->line, script_command_type_to_string(c->type) );
1944 vfprintf(stderr, fmt, ap);
1945 fprintf(stderr, "\n");
1947 va_end(ap);
1949 /* Increase error count */
1950 err_count++;
1953 #define require_arg(s, c, a, d) { \
1954 d = script_get_command_arg(c, a); \
1955 if (d == NULL) { \
1956 scripterr(s, c, "missing argument `%s'", a); \
1957 return; \
1961 #define require_arg_in_range(s, c, a, v, l, h) { \
1962 if (((v) < (l)) || ((v) > (h))) { \
1963 scripterr(s, c, "value of argument `%s' is out of range", a); \
1964 return; \
1968 /*--------------------------------------------------------------------------*/
1969 /* Functions for registering RAM blocks in script. */
1972 * Registers one RAM block based on 'ram' script command.
1973 * @param s Linker script
1974 * @param c Command of type RAM_COMMAND
1975 * @param arg Not used
1977 static void register_one_ram_block(script *s, script_command *c, void *arg)
1979 int start;
1980 int end;
1981 char *start_str;
1982 char *end_str;
1983 /* Get arguments */
1984 require_arg(s, c, "start", start_str);
1985 require_arg(s, c, "end", end_str);
1986 /* Convert to integers */
1987 start = str_to_int(start_str);
1988 end = str_to_int(end_str);
1989 /* Check that they are sane */
1990 require_arg_in_range(s, c, "start", start, 0x0000, 0xFFFF);
1991 require_arg_in_range(s, c, "end", end, 0x0000, 0xFFFF);
1992 if (end <= start) {
1993 scripterr(s, c, "`end' is smaller than `start'");
1995 /* Add block */
1996 add_ram_block(start, end);
2000 * Registers RAM blocks based on 'ram' commands in a script.
2001 * @param sc Linker script
2003 static void register_ram_blocks(script *sc)
2005 /* Table of mappings for our purpose */
2006 static script_commandprocmap map[] = {
2007 { RAM_COMMAND, register_one_ram_block },
2008 { BAD_COMMAND, NULL }
2010 /* Do the walk */
2011 script_walk(sc, map, NULL);
2012 /* Calculate total RAM size */
2013 total_ram = ram_left();
2016 /*--------------------------------------------------------------------------*/
2017 /* Functions for loading and initial processing of units in script. */
2020 * Registers (parses etc.) one unit based on 'link' script command.
2021 * @param s Linker script
2022 * @param c Command of type LINK_COMMAND
2023 * @param arg Pointer to unit index
2025 static void register_one_unit(script *s, script_command *c, void *arg)
2027 char *file;
2028 int *i;
2029 xunit *xu;
2030 /* Get unit filename */
2031 require_arg(s, c, "file", file);
2032 /* arg is pointer to unit index */
2033 i = (int *)arg;
2034 /* Get pointer to xunit to fill in */
2035 xu = &units[*i];
2036 /* Read basic unit from file */
2037 if (unit_read(file, &xu->_unit_) == 0) {
2038 /* Something bad happened when trying to read unit */
2039 scripterr(s, c, "failed to load unit `%s'", file);
2040 xu->loaded = 0;
2041 return;
2043 xu->loaded = 1;
2044 verbose(" unit `%s' loaded", file);
2045 /* Register locals for both segments */
2046 verbose(" registering local symbols...");
2047 register_locals(xu->_unit_.dataseg.bytes, &xu->data_locals, xu);
2048 register_locals(xu->_unit_.codeseg.bytes, &xu->code_locals, xu);
2049 /* Enter exported symbols into hash tables */
2050 verbose(" registering public symbols...");
2051 enter_exported_constants(&xu->_unit_);
2052 enter_exported_locals(&xu->data_locals, &xu->_unit_);
2053 enter_exported_locals(&xu->code_locals, &xu->_unit_);
2054 /* Put unit in hash table */
2055 hashtab_put(unit_hash, file, xu);
2056 /* Increment unit index */
2057 (*i)++;
2061 * Registers units based on 'link' commands in script.
2062 * @param sc Linker script
2064 static void register_units(script *sc)
2066 /* Table of mappings for our purpose */
2067 static script_commandprocmap map[] = {
2068 { LINK_COMMAND, register_one_unit },
2069 { BAD_COMMAND, NULL }
2071 int i = 0;
2072 /* Do the walk */
2073 script_walk(sc, map, (void *)&i);
2076 /*--------------------------------------------------------------------------*/
2077 /* Functions for composing a binary file based on a sequential list of
2078 script commands. */
2081 * Sets the output file according to 'output' script command.
2082 * @param s Linker script
2083 * @param c Command of type OUTPUT_COMMAND
2084 * @param arg Pointer to file handle
2086 static void set_output(script *s, script_command *c, void *arg)
2088 char *file;
2089 FILE **fpp;
2090 /* Get the name of new output file */
2091 require_arg(s, c, "file", file);
2092 /* Arg is pointer to file handle pointer */
2093 fpp = (FILE **)arg;
2094 /* Close current file */
2095 if (*fpp != NULL) {
2096 fclose(*fpp);
2098 /* Attempt to open new file */
2099 *fpp = fopen(file, "wb");
2100 if (*fpp == NULL) {
2101 scripterr(s, c, "could not open `%s' for writing", file);
2103 else {
2104 verbose(" output goes to `%s'", file);
2109 * Copies a file to output according to 'copy' script command.
2110 * @param s Linker script
2111 * @param c Command of type COPY_COMMAND
2112 * @param arg Pointer to file handle
2114 static void copy_to_output(script *s, script_command *c, void *arg)
2116 char *file;
2117 FILE **fpp;
2118 FILE *cf;
2119 unsigned char k;
2120 /* Arg is pointer to file handle pointer */
2121 fpp = (FILE **)arg;
2122 /* Make sure there is a file to write to */
2123 if (*fpp == NULL) {
2124 scripterr(s, c, "no output open");
2126 else {
2127 /* Get the name of file to copy */
2128 require_arg(s, c, "file", file);
2129 /* Attempt to open the file to copy */
2130 cf = fopen(file, "rb");
2131 if (cf == NULL) {
2132 scripterr(s, c, "could not open `%s' for reading", file);
2134 else {
2135 verbose(" copying `%s' to output at position %ld...", file, ftell(*fpp) );
2136 /* Copy it to output, byte for byte */
2137 for (k = fgetc(cf); !feof(cf); k = fgetc(cf) ) {
2138 fputc(k, *fpp);
2140 /* Advance offset */
2141 bank_offset += ftell(cf);
2142 pc += ftell(cf);
2143 /* Close the copied file */
2144 fclose(cf);
2145 /* Check if exceeded bank size */
2146 if (bank_offset > bank_size) {
2147 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2154 * Starts a new bank according to 'bank' script command.
2155 * @param s Linker script
2156 * @param c Command of type BANK_COMMAND
2157 * @param arg Pointer to file handle
2159 static void start_bank(script *s, script_command *c, void *arg)
2161 char *size_str;
2162 char *origin_str;
2163 /* See if size specified */
2164 size_str = script_get_command_arg(c, "size");
2165 if (size_str != NULL) {
2166 /* Set new bank size */
2167 bank_size = str_to_int(size_str);
2168 /* Sanity check */
2169 if (bank_size <= 0) {
2170 scripterr(s, c, "invalid size");
2173 else {
2174 /* Use bank size of previous bank if there was one */
2175 /* Otherwise issue error */
2176 if (bank_size == 0x7FFFFFFF) {
2177 scripterr(s, c, "no bank size set");
2180 /* See if origin specified */
2181 origin_str = script_get_command_arg(c, "origin");
2182 if (origin_str != NULL) {
2183 /* Set new bank origin */
2184 bank_origin = str_to_int(origin_str);
2185 /* Sanity check */
2186 require_arg_in_range(s, c, "origin", bank_origin, 0x0000, 0xFFFF);
2188 else {
2189 /* Use old bank origin */
2191 bank_id++;
2192 /* Reset bank offset and PC */
2193 bank_offset = 0;
2194 pc = bank_origin;
2198 * Writes unit according to 'link' script command.
2199 * @param s Linker script
2200 * @param c Command of type LINK_COMMAND
2201 * @param arg Pointer to file handle
2203 static void write_unit(script *s, script_command *c, void *arg)
2205 FILE **fpp;
2206 xunit *xu;
2207 char *file;
2208 /* Arg is pointer to file handle pointer */
2209 fpp = (FILE **)arg;
2210 /* Make sure there is a file to write to */
2211 if (*fpp == NULL) {
2212 scripterr(s, c, "no output open");
2214 else {
2215 /* Get the name of the unit */
2216 require_arg(s, c, "file", file);
2217 /* Look it up */
2218 xu = (xunit *)hashtab_get(unit_hash, file);
2219 /* Write it */
2220 verbose(" appending unit `%s' to output at position %ld...", file, ftell(*fpp));
2221 write_as_binary(*fpp, xu);
2222 /* Advance offset */
2223 bank_offset += xu->code_size;
2224 /* Check if exceeded bank size */
2225 if (bank_offset > bank_size) {
2226 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2232 * Pads output file according to 'pad' script command.
2233 * @param s Linker script
2234 * @param c Command of type PAD_COMMAND
2235 * @param arg Pointer to file handle
2237 static void write_pad(script *s, script_command *c, void *arg)
2239 FILE **fpp;
2240 int i;
2241 int count;
2242 int offset;
2243 int origin;
2244 char *offset_str;
2245 char *origin_str;
2246 char *size_str;
2247 /* Arg is pointer to file handle pointer */
2248 fpp = (FILE **)arg;
2249 /* Make sure there is a file to write to */
2250 if (*fpp == NULL) {
2251 scripterr(s, c, "no output open");
2253 else {
2254 if ((offset_str = script_get_command_arg(c, "offset")) != NULL) {
2255 offset = str_to_int(offset_str);
2256 /* Calculate number of zeroes to write */
2257 count = offset - bank_offset;
2259 else if ((origin_str = script_get_command_arg(c, "origin")) != NULL) {
2260 origin = str_to_int(origin_str);
2261 /* Calculate number of zeroes to write */
2262 count = origin - pc;
2264 else if ((size_str = script_get_command_arg(c, "size")) != NULL) {
2265 count = str_to_int(size_str);
2267 else {
2268 scripterr(s, c, "missing argument");
2269 count = 0;
2271 /* Sanity check */
2272 if (count < 0) {
2273 scripterr(s, c, "cannot pad backwards");
2274 count = 0;
2276 else if (count > 0) {
2277 verbose(" padding %d bytes...", count);
2279 /* Write zeroes */
2280 for (i=0; i<count; i++) {
2281 fputc(0, *fpp);
2283 /* Advance offset */
2284 bank_offset += count;
2285 pc += count;
2286 /* Check if exceeded bank size */
2287 if (bank_offset > bank_size) {
2288 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2294 * Pads to end of bank in file if bank size not reached.
2295 * @param s Linker script
2296 * @param c Command of type BANK_COMMAND
2297 * @param fp File handle
2299 static void maybe_pad_bank(script *s, script_command *c, FILE *fp)
2301 int i;
2302 if ( (bank_size != 0x7FFFFFFF) && (bank_offset < bank_size) ) {
2303 /* Make sure there is a file to write to */
2304 if (fp == NULL) {
2305 scripterr(s, c, "no output open");
2307 else {
2308 /* Pad until bank size */
2309 for (i=bank_offset; i<bank_size; i++) {
2310 fputc(0, fp);
2317 * Finishes old bank in output and starts new bank.
2318 * @param s Linker script
2319 * @param c Command of type BANK_COMMAND
2320 * @param arg Pointer to file handle
2322 static void write_bank(script *s, script_command *c, void *arg)
2324 FILE **fpp;
2325 /* Arg is pointer to file handle pointer */
2326 fpp = (FILE **)arg;
2327 /* Pad bank if necessary */
2328 maybe_pad_bank(s, c, *fpp);
2329 /* Start new bank */
2330 start_bank(s, c, arg);
2334 * Generates the final binary output from the linker.
2335 * @param sc Linker script
2337 static void generate_output(script *sc)
2339 FILE *fp = NULL;
2340 /* Table of mappings for our purpose */
2341 static script_commandprocmap map[] = {
2342 { OUTPUT_COMMAND, set_output },
2343 { COPY_COMMAND, copy_to_output },
2344 { BANK_COMMAND, write_bank },
2345 { LINK_COMMAND, write_unit },
2346 { PAD_COMMAND, write_pad },
2347 { BAD_COMMAND, NULL }
2349 /* Reset offsets */
2350 bank_size = 0x7FFFFFFF;
2351 bank_offset = 0;
2352 bank_origin = 0;
2353 bank_id = -1;
2354 pc = 0;
2355 /* Do the walk */
2356 script_walk(sc, map, (void *)&fp);
2357 /* Pad last bank if necessary */
2358 maybe_pad_bank(sc, sc->first_command, fp);
2361 /*--------------------------------------------------------------------------*/
2364 * Increases bank offset and PC according to size of the file specified by
2365 * 'copy' script command.
2366 * @param s Linker script
2367 * @param c Command of type COPY_COMMAND
2368 * @param arg Not used
2370 static void inc_offset_copy(script *s, script_command *c, void *arg)
2372 char *file;
2373 FILE *fp;
2374 /* Get the name of the file */
2375 require_arg(s, c, "file", file);
2376 /* Attempt to it */
2377 fp = fopen(file, "rb");
2378 if (fp == NULL) {
2379 scripterr(s, c, "could not open `%s' for reading", file);
2381 else {
2382 /* Seek to end */
2383 fseek(fp, 0, SEEK_END);
2384 /* Advance offset */
2385 bank_offset += ftell(fp);
2386 pc += ftell(fp);
2387 /* Close the file */
2388 fclose(fp);
2389 /* Check if exceeded bank size */
2390 if (bank_offset > bank_size) {
2391 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2397 * Sets the origin of a unit and relocates its code to this location.
2398 * @param s Linker script
2399 * @param c Command of type LINK_COMMAND
2400 * @param arg Not used
2402 static void set_unit_origin(script *s, script_command *c, void *arg)
2404 xunit *xu;
2405 char *file;
2406 char *origin_str;
2407 int origin;
2408 /* Get the unit filename */
2409 require_arg(s, c, "file", file);
2410 /* Look it up */
2411 xu = (xunit *)hashtab_get(unit_hash, file);
2412 /* Check if origin specified */
2413 origin_str = script_get_command_arg(c, "origin");
2414 if (origin_str != NULL) {
2415 origin = str_to_int(origin_str);
2416 require_arg_in_range(s, c, "origin", origin, 0x0000, 0xFFFF);
2417 xu->code_origin = origin;
2418 pc = origin;
2420 else {
2421 /* No origin specified. Set to PC. */
2422 xu->code_origin = pc;
2424 xu->bank_id = bank_id;
2425 /* Now we can calculate the physical code addresses of the unit. */
2426 calc_code_addresses(xu);
2427 /* Print info if verbose mode */
2428 verbose(" unit `%s' relocated to %.4X", xu->_unit_.name, xu->code_origin);
2429 /* Increase bank offset */
2430 bank_offset += xu->code_size;
2434 * Increases bank offset and PC according to 'pad' script command.
2435 * @param s Linker script
2436 * @param c Command of type PAD_COMMAND
2437 * @param arg Not used
2439 static void inc_offset_pad(script *s, script_command *c, void *arg)
2441 int count;
2442 int offset;
2443 int origin;
2444 char *offset_str;
2445 char *origin_str;
2446 char *size_str;
2447 if ((offset_str = script_get_command_arg(c, "offset")) != NULL) {
2448 offset = str_to_int(offset_str);
2449 /* Calculate number of zeroes to write */
2450 count = offset - bank_offset;
2452 else if ((origin_str = script_get_command_arg(c, "origin")) != NULL) {
2453 origin = str_to_int(origin_str);
2454 /* Calculate number of zeroes to write */
2455 count = origin - pc;
2457 else if ((size_str = script_get_command_arg(c, "size")) != NULL) {
2458 count = str_to_int(size_str);
2460 else {
2461 /* Error */
2462 scripterr(s, c, "missing argument");
2463 count = 0;
2465 /* Sanity check */
2466 if (count < 0) {
2467 scripterr(s, c, "cannot pad %d bytes backwards", -count);
2468 count = 0;
2470 /* Advance offset */
2471 bank_offset += count;
2472 pc += count;
2473 /* Check if exceeded bank size */
2474 if (bank_offset > bank_size) {
2475 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2480 * Relocates code of all units according to script commands and/or their position
2481 * in the final binary.
2482 * @param sc Linker script
2484 static void relocate_units(script *sc)
2486 /* Table of mappings for our purpose */
2487 static script_commandprocmap map[] = {
2488 { COPY_COMMAND, inc_offset_copy },
2489 { BANK_COMMAND, start_bank },
2490 { LINK_COMMAND, set_unit_origin },
2491 { PAD_COMMAND, inc_offset_pad },
2492 { BAD_COMMAND, NULL }
2494 /* Reset offsets */
2495 bank_size = 0x7FFFFFFF;
2496 bank_offset = 0;
2497 bank_origin = 0;
2498 bank_id = -1;
2499 pc = 0;
2500 /* Do the walk */
2501 script_walk(sc, map, NULL);
2507 static void maybe_print_ram_statistics()
2509 int used;
2510 int left;
2511 if (total_ram > 0) {
2512 left = ram_left();
2513 used = total_ram - left;
2514 verbose(" total RAM: %d bytes", total_ram);
2515 verbose(" RAM used: %d bytes (%d%%)", used, (int)(((float)used / (float)total_ram)*100.0f) );
2516 verbose(" RAM left: %d bytes (%d%%)", left, (int)(((float)left / (float)total_ram)*100.0f) );
2520 /*--------------------------------------------------------------------------*/
2523 * Program entrypoint.
2525 int main(int argc, char **argv)
2527 int i;
2528 script sc;
2530 /* Parse our arguments. */
2531 parse_arguments(argc, argv);
2533 suppress = 0;
2534 /* Reset error and warning count */
2535 err_count = 0;
2536 warn_count = 0;
2538 /* Parse the linker script */
2539 verbose("parsing linker script...");
2540 if (script_parse(program_args.input_file, &sc) == 0) {
2541 /* Something bad happened when parsing script, halt */
2542 return(1);
2545 /* Process all ram commands */
2546 verbose("registering RAM blocks...");
2547 register_ram_blocks(&sc);
2549 /* Create hash tables to hold symbols */
2550 constant_hash = hashtab_create(23, HASHTAB_STRKEYHSH, HASHTAB_STRKEYCMP);
2551 label_hash = hashtab_create(23, HASHTAB_STRKEYHSH, HASHTAB_STRKEYCMP);
2552 unit_hash = hashtab_create(11, HASHTAB_STRKEYHSH, HASHTAB_STRKEYCMP);
2554 /* Count units. One unit per link command. */
2555 unit_count = script_count_command_type(&sc, LINK_COMMAND);
2556 /* Allocate array of xunits */
2557 if (unit_count > 0) {
2558 units = (xunit *)malloc( sizeof(xunit) * unit_count );
2560 else {
2561 units = NULL;
2563 /* Process link commands */
2564 verbose("loading units...");
2565 register_units(&sc);
2566 /* Make sure all units were loaded */
2567 if (err_count != 0) {
2568 // TODO
2571 /* Only continue with processing if no unresolved symbols */
2572 if (err_count == 0) {
2573 /* Calculate 0-relative addresses of data labels */
2574 verbose("calculating data addresses...");
2575 for (i=0; i<unit_count; i++) {
2576 calc_data_addresses(&units[i]);
2579 // TODO: Count references: go through all instructions, find EXTRN and LOCAL operands in expressions
2580 // TODO: Find modes of access for each DATA label (i.e. label MUST be allocated in zero page)
2582 /* Map all data labels to 6502 RAM locations */
2583 verbose("mapping data to RAM...");
2584 map_data_to_ram();
2585 maybe_print_ram_statistics();
2587 /* Only continue with processing if all data labels were mapped */
2588 if (err_count == 0) {
2589 verbose("relocating code...");
2590 suppress = 1;
2591 relocate_units(&sc);
2592 suppress = 0;
2593 relocate_units(&sc);
2595 /* Only continue with processing if all code labels were mapped */
2596 if (err_count == 0) {
2597 verbose("generating output...");
2598 generate_output(&sc);
2603 /* Cleanup */
2604 verbose("cleaning up...");
2606 /* Finalize units */
2607 for (i=0; i<unit_count; i++) {
2608 if (units[i].loaded) {
2609 finalize_local_array( &units[i].data_locals );
2610 finalize_local_array( &units[i].code_locals );
2611 unit_finalize( &units[i]._unit_ );
2614 /* Finalize hash tables */
2615 hashtab_finalize(label_hash);
2616 hashtab_finalize(constant_hash);
2617 hashtab_finalize(unit_hash);
2618 /* Finalize RAM blocks */
2619 finalize_ram_blocks();
2620 /* Finalize the script */
2621 script_finalize(&sc);
2623 /* All done. */
2624 return (err_count == 0) ? 0 : 1;