2 * $Id: xlnk.c,v 1.20 2007/11/11 22:35:22 khansen Exp $
4 * Revision 1.20 2007/11/11 22:35:22 khansen
7 * Revision 1.19 2007/08/12 19:01:11 khansen
10 * Revision 1.18 2007/08/07 22:43:01 khansen
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
18 * prints code/data addresses of public symbols when --verbose
20 * Revision 1.15 2005/01/05 09:33:37 kenth
22 * fixed RAM allocator bug
23 * print RAM statistics when --verbose
25 * Revision 1.14 2005/01/05 01:52:19 kenth
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
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
40 * Revision 1.9 2004/12/19 19:58:54 kenth
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
53 * Revision 1.5 2004/12/14 01:50:21 kenth
56 * Revision 1.4 2004/12/11 02:06:18 kenth
59 * Revision 1.3 2004/12/06 04:53:18 kenth
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
68 * Revision 1.1 2004/06/30 07:42:03 kenth
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
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.
115 #define SAFE_FREE(m) if ((m) != NULL) { free(m); m = NULL; }
118 * Parses a string to an integer.
122 static int str_to_int(char *s
)
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
{
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' },
160 /* Prints usage message and exits. */
164 Usage: xlnk [-qsvV] [--quiet] [--silent] [--verbose] [--help] [--usage]\n\
170 /* Prints help message and exits. */
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\
188 /* Prints version and exits. */
189 static void version()
191 printf("%s\n", program_version
);
195 /* Parses program arguments. */
197 parse_arguments (int argc
, char **argv
)
200 /* getopt_long stores the option index here. */
203 /* Set default values. */
204 program_args
.silent
= 0;
205 program_args
.verbose
= 0;
206 program_args
.input_file
= NULL
;
209 while ((key
= getopt_long(argc
, argv
, "qsvV", long_options
, &index
)) != -1) {
212 program_args
.silent
= 1;
216 ++program_args
.verbose
;
220 /* Use index to differentiate between options */
221 if (strcmp(long_options
[index
].name
, "usage") == 0) {
224 else if (strcmp(long_options
[index
].name
, "help") == 0) {
234 /* Error message has been printed by getopt_long */
239 /* Forgot to handle a short option, most likely */
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");
251 program_args
.input_file
= argv
[optind
];
255 /*--------------------------------------------------------------------------*/
256 /* Data structures. */
258 /* Describes a local label in the unit. */
261 char *name
; /* NULL if not exported */
262 int resolved
; /* 0 initially, set to 1 when phys_addr has been assigned */
267 struct tag_xunit
*owner
;
268 unsigned short align
;
272 typedef struct tag_local local
;
274 /* Describes an array of local labels. */
275 struct tag_local_array
281 typedef struct tag_local_array local_array
;
284 * eXtended unit, has extra info built from basic unit ++
288 unit _unit_
; /* NB!!! "Superclass", must be first field for casting to work */
289 local_array data_locals
;
290 local_array code_locals
;
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
;
313 struct tag_calc_address_args
319 typedef struct tag_calc_address_args calc_address_args
;
322 struct tag_write_binary_args
328 typedef struct tag_write_binary_args write_binary_args
;
330 /*--------------------------------------------------------------------------*/
332 /** Array containing the units to link. */
334 /* Number of units in above array. */
335 static int unit_count
;
337 /** Holds the current memory address. */
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
;
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;
358 static int bank_offset
;
359 static int bank_size
;
360 static int bank_origin
;
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()
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
);
391 fprintf(stderr
, "%s:%d: ", str
, unit_line
);
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");
410 * @param fmt format string for printf
412 static void err(char *fmt
, ...)
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 */
431 * @param fmt format string for printf
433 static void warn(char *fmt
, ...)
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 */
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
, ...)
459 if (!suppress
&& program_args
.verbose
>= level
) {
460 vfprintf(stdout
, fmt
, ap
);
461 fprintf(stdout
, "\n");
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()
479 for (sum
= 0, b
= ram_block_head
; b
!= NULL
; b
= b
->next
) {
480 sum
+= b
->end
- b
->start
;
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
)
494 /* Allocate a block struct */
495 avail_ram_block
*new_block
= (avail_ram_block
*)malloc( sizeof(avail_ram_block
) );
496 if (new_block
!= NULL
) {
498 new_block
->start
= start
;
499 new_block
->end
= end
;
500 new_block
->next
= NULL
;
502 if (ram_block_head
== NULL
) {
504 ram_block_head
= new_block
;
508 for (b
= ram_block_head
; b
->next
!= NULL
; b
= b
->next
) ;
511 verbose(1, " added RAM block: %.4X-%.4X", new_block
->start
, new_block
->end
);
516 * Allocates a chunk of 6502 RAM to a 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. */
525 avail_ram_block
*p
= NULL
;
526 for (b
= ram_block_head
; b
!= NULL
; p
= b
, b
= b
->next
) {
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);
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
;
551 n
= (avail_ram_block
*)malloc(sizeof(avail_ram_block
));
553 n
->end
= n
->start
+ pad
;
556 if (b
== ram_block_head
) {
557 ram_block_head
= n
; /* New head */
565 l
->phys_addr
= b
->start
;
566 /* Decrease block size by moving start address ahead */
568 /* If there's no more space left in this block, discard it */
569 if (left
== l
->size
) {
570 /* Remove from linked list */
572 /* Set successor block as new head */
573 ram_block_head
= b
->next
;
579 /* Free associated memory */
582 /* Return with success */
585 /* Couldn't find a block large enough, return with failure */
590 * Frees up memory associated with list of RAM blocks.
592 static void finalize_ram_blocks()
596 for (b
= ram_block_head
; b
!= NULL
; b
= t
) {
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
)
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
);
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
);
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);
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 */
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
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
)
663 if (bytes
== NULL
) { return; }
667 cmd
= get_1(bytes
, &i
);
669 /* Check if debug command */
673 unit_file
= &bytes
[i
];
674 i
+= get_1(bytes
, &i
) + 1; /* Skip count and array of bytes */
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;
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 */
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 */
704 err("invalid bytecode");
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).
727 * @return String representation of operator
729 static const char *operator_to_string(int 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 "^";
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
)
773 constant lhs_result
, rhs_result
;
775 case OPERATOR_EXPRESSION
:
776 switch (e
->op_expr
.operator) {
777 /* Binary operators */
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)) {
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) {
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
;
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;
848 /* Not defined operator for string operation... */
853 /* Error, operands are incompatible */
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 */
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) {
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;
887 /* Error, invalid operand */
888 err("incompatible operand to `%s' in expression", operator_to_string(e
->op_expr
.operator) );
891 /* Discard the operand */
892 finalize_constant(&lhs_result
);
893 break; /* Unary operator */
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
;
903 case EXTERNAL_EXPRESSION
:
904 /* Get the name of the external */
905 s
= u
->_unit_
.externals
[e
->op_expr
.lhs
->extrn_id
].name
;
907 if ((l
= (local
*)hashtab_get(label_hash
, s
)) != NULL
) {
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
;
930 case INTEGER_EXPRESSION
:
931 /* Copy value to result */
932 result
->type
= INTEGER_CONSTANT
;
933 result
->integer
= e
->integer
;
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
;
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
];
951 /* It's a data local */
952 l
= &u
->data_locals
.entries
[e
->local_id
];
954 /* Test if it's resolved */
956 /* Copy address to result */
957 result
->type
= INTEGER_CONSTANT
;
958 result
->integer
= l
->phys_addr
;
961 /* Not resolved (yet, at least) */
966 case EXTERNAL_EXPRESSION
:
967 /* Get the name of the external */
968 s
= u
->_unit_
.externals
[e
->extrn_id
].name
;
970 if ((l
= (local
*)hashtab_get(label_hash
, s
)) != NULL
) {
972 /* Test if it's resolved */
974 /* Copy address to result */
975 result
->type
= INTEGER_CONSTANT
;
976 result
->integer
= l
->phys_addr
;
979 /* Not resolved (yet) */
983 else if ((c
= (constant
*)hashtab_get(constant_hash
, s
)) != NULL
) {
984 /* It's a constant */
985 /* Copy value to result */
987 case INTEGER_CONSTANT
:
988 result
->type
= INTEGER_CONSTANT
;
989 result
->integer
= c
->integer
;
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
;
1004 err("unknown symbol `%s' referenced from %s", s
, u
->_unit_
.name
);
1009 /* Copy current PC to result */
1010 result
->type
= INTEGER_CONSTANT
;
1011 result
->integer
= pc
;
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
);
1050 * Increases PC by 8-bit value immediately following bytecode command.
1052 static void inc_pc_count8(unsigned char *b
, void *arg
)
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
)
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
)
1076 * Increases PC by 2.
1078 static void inc_pc_2(unsigned char *b
, void *arg
)
1084 * Increases PC by 4.
1086 static void inc_pc_4(unsigned char *b
, void *arg
)
1092 * Increases PC according to size of define data command.
1094 static void inc_pc_dsb(unsigned char *b
, void *arg
)
1098 calc_address_args
*args
= (calc_address_args
*)arg
;
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
);
1115 /* Error, unresolved */
1116 //err("unresolved symbol");
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
)
1129 unsigned char op
, t
;
1131 calc_address_args
*args
= (calc_address_args
*)arg
;
1135 /* Get expression ID */
1136 exid
= get_2(b
, &i
);
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 */
1149 else if (c
.type
== STRING_CONSTANT
) {
1150 /* Error, string operand doesn't make sense here */
1151 err("invalid instruction operand (string)");
1154 /* Address not available yet (forward reference). */
1155 //err("unresolved symbol");
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
)
1171 write_binary_args
*args
= (write_binary_args
*)arg
;
1172 /* Get 8-bit count */
1174 count
= get_1(b
, &i
) + 1;
1176 fwrite(&b
[i
], 1, count
, args
->fp
);
1178 inc_pc( count
, arg
);
1182 * Writes an array of bytes.
1184 static void write_bin16(unsigned char *b
, void *arg
)
1188 write_binary_args
*args
= (write_binary_args
*)arg
;
1189 /* Get 16-bit count */
1191 count
= get_2(b
, &i
) + 1;
1193 fwrite(&b
[i
], 1, count
, args
->fp
);
1195 inc_pc( count
, arg
);
1199 * Writes an instruction.
1201 static void write_instr(unsigned char *b
, void *arg
)
1207 write_binary_args
*args
= (write_binary_args
*)arg
;
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 */
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 */
1241 if (c
.integer
>= 0x100) {
1242 err("instruction operand doesn't fit in 1 byte");
1246 fputc(c
.integer
, args
->fp
);
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");
1255 /* Write it, low byte first */
1256 fputc(c
.integer
, args
->fp
);
1257 fputc(c
.integer
>> 8, args
->fp
);
1261 inc_pc( opcode_length(op
), arg
);
1265 * Writes a byte, word or dword.
1267 static void write_dx(unsigned char *b
, void *arg
)
1272 write_binary_args
*args
= (write_binary_args
*)arg
;
1273 /* Get expression ID */
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 */
1285 if (c
.integer
> 0xFF) {
1286 warn("`.DB' operand $%X out of range; truncated", c
.integer
);
1291 fputc(c
.integer
>> 8, args
->fp
);
1292 if (c
.integer
> 0xFFFF) {
1293 warn("`.DW' operand $%X out of range; truncated", c
.integer
);
1298 fputc(c
.integer
>> 8, args
->fp
);
1299 fputc(c
.integer
>> 16, args
->fp
);
1300 fputc(c
.integer
>> 24, args
->fp
);
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 */
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;
1338 finalize_constant(&c
);
1342 * Writes a series of zeroes.
1344 static void write_dsi8(unsigned char *b
, void *arg
)
1348 write_binary_args
*args
= (write_binary_args
*)arg
;
1349 /* Get 8-bit count */
1351 count
= get_1(b
, &i
) + 1;
1353 for (i
=0; i
<count
; i
++) {
1357 inc_pc( count
, arg
);
1361 * Writes a series of zeroes.
1363 static void write_dsi16(unsigned char *b
, void *arg
)
1367 write_binary_args
*args
= (write_binary_args
*)arg
;
1368 /* Get 16-bit count */
1370 count
= get_2(b
, &i
) + 1;
1372 for (i
=0; i
<count
; i
++) {
1376 inc_pc( count
, arg
);
1380 * Writes a series of zeroes.
1382 static void write_dsb(unsigned char *b
, void *arg
)
1387 write_binary_args
*args
= (write_binary_args
*)arg
;
1388 /* Get expression ID */
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) {
1398 for (i
=0; i
<c
.integer
; i
++) {
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
[] =
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 */
1433 pc
= u
->code_origin
;
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
)
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
++]);
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
)
1473 write_binary_args
*args
= (write_binary_args
*)arg
;
1474 /* Get 8-bit count */
1476 count
= get_1(b
, &i
) + 1;
1478 // fprintf(args->fp, "; %d byte(s)\n", count);
1479 print_chunk(args
->fp
, /*label=*/0, &b
[i
], count
, /*cols=*/16);
1481 inc_pc( count
, arg
);
1485 * Writes an array of bytes.
1487 static void asm_write_bin16(unsigned char *b
, void *arg
)
1491 write_binary_args
*args
= (write_binary_args
*)arg
;
1492 /* Get 16-bit count */
1494 count
= get_2(b
, &i
) + 1;
1496 // fprintf(args->fp, "; %d byte(s)\n", count);
1497 print_chunk(args
->fp
, /*label=*/0, &b
[i
], count
, /*cols=*/16);
1499 inc_pc( count
, arg
);
1505 static void asm_write_label(unsigned char *b
, void *arg
)
1507 unsigned char flags
;
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 */
1515 int len
= get_1(b
, &i
) + 1;
1516 name
= (char *)malloc( len
+ 1 );
1518 memcpy(name
, &b
[i
], len
);
1521 fprintf(args
->fp
, " %s (PC=$%.4X)", name
, pc
);
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
)
1536 addressing_mode mode
;
1539 write_binary_args
*args
= (write_binary_args
*)arg
;
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
));
1555 case ACCUMULATOR_MODE
:
1557 case IMMEDIATE_MODE
:
1558 fprintf(args
->fp
, " #$");
1561 case ZEROPAGE_X_MODE
:
1562 case ZEROPAGE_Y_MODE
:
1564 case ABSOLUTE_X_MODE
:
1565 case ABSOLUTE_Y_MODE
:
1566 fprintf(args
->fp
, " $");
1568 case PREINDEXED_INDIRECT_MODE
:
1569 case POSTINDEXED_INDIRECT_MODE
:
1571 fprintf(args
->fp
, " [$");
1574 fprintf(args
->fp
, " $");
1579 /* Write the operand */
1580 fprintf(args
->fp
, "%.4X", (unsigned)c
.integer
);
1583 case ACCUMULATOR_MODE
:
1584 case IMMEDIATE_MODE
:
1587 case ZEROPAGE_X_MODE
:
1588 fprintf(args
->fp
, ",X");
1590 case ZEROPAGE_Y_MODE
:
1591 fprintf(args
->fp
, ",Y");
1595 case ABSOLUTE_X_MODE
:
1596 fprintf(args
->fp
, ",X");
1598 case ABSOLUTE_Y_MODE
:
1599 fprintf(args
->fp
, ",Y");
1601 case PREINDEXED_INDIRECT_MODE
:
1602 fprintf(args
->fp
, ",X]");
1604 case POSTINDEXED_INDIRECT_MODE
:
1605 fprintf(args
->fp
, "],Y");
1608 fprintf(args
->fp
, "]");
1616 fprintf(args
->fp
, "\n");
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
)
1629 write_binary_args
*args
= (write_binary_args
*)arg
;
1630 /* Get expression ID */
1632 exid
= get_2(b
, &i
);
1633 /* Evaluate expression */
1634 eval_expression(args
->xu
, exid
, &c
);
1635 if (c
.type
== INTEGER_CONSTANT
) {
1638 fprintf(args
->fp
, ".DB $%.2X", (unsigned)c
.integer
);
1641 fprintf(args
->fp
, ".DW $%.4X", (unsigned)c
.integer
);
1644 fprintf(args
->fp
, ".DD $%.8X", (unsigned)c
.integer
);
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
);
1657 fprintf(args
->fp
, ".DB");
1660 fprintf(args
->fp
, ".DW");
1663 fprintf(args
->fp
, ".DD");
1666 fprintf(args
->fp
, " \"%s\"", c
.string
);
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;
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
)
1687 write_binary_args
*args
= (write_binary_args
*)arg
;
1688 /* Get 8-bit count */
1690 count
= get_1(b
, &i
) + 1;
1692 fprintf(args
->fp
, ".DSB $%X\n", count
);
1694 inc_pc( count
, arg
);
1698 * Writes a series of zeroes.
1700 static void asm_write_dsi16(unsigned char *b
, void *arg
)
1704 write_binary_args
*args
= (write_binary_args
*)arg
;
1705 /* Get 16-bit count */
1707 count
= get_2(b
, &i
) + 1;
1709 fprintf(args
->fp
, ".DSB $%X\n", count
);
1711 inc_pc( count
, arg
);
1715 * Writes a series of zeroes.
1717 static void asm_write_dsb(unsigned char *b
, void *arg
)
1722 write_binary_args
*args
= (write_binary_args
*)arg
;
1723 /* Get expression ID */
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) {
1734 fprintf(args
->fp
, ".DSB $%X\n", (unsigned)c
.integer
);
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
[] =
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 */
1767 pc
= u
->code_origin
;
1768 fprintf(fp
, "; ***************************************\n");
1769 fprintf(fp
, "; * %s, PC=$%.4X\n", u
->_unit_
.name
, pc
);
1770 fprintf(fp
, "; ***************************************\n");
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.
1784 * @return String representation ("CMD_*")
1786 static const char *bytecode_to_string(unsigned char 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";
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]) );
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
);
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
)
1857 /* Allocate space for entries */
1859 la
->entries
= (local
*)malloc(sizeof(local
) * size
);
1867 * Finalizes array of locals.
1869 static void finalize_local_array(local_array
*la
)
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
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 */
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
)
1908 /* Table of callback functions for our purpose. */
1909 bytecodeproc handlers
[] =
1912 NULL
, /* CMD_BIN8 */
1913 NULL
, /* CMD_BIN16 */
1914 count_one_local
, /* CMD_LABEL */
1915 NULL
, /* CMD_INSTR */
1919 NULL
, /* CMD_DSI8 */
1920 NULL
, /* CMD_DSI16 */
1925 /* Count the locals now */
1926 bytecode_walk(b
, handlers
, (void *)&count
);
1927 /* Return the number of locals counted */
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
)
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 */
1948 lptr
->ref_count
= 0;
1951 lptr
->owner
= reg_unit
;
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';
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
);
1978 if (program_args
.verbose
) {
1979 verbose(1, " %s align=%d resolved=%d",
1980 lptr
->name
? lptr
->name
: "(anonymous)",
1981 lptr
->align
, lptr
->resolved
);
1984 /* Point to next local in array */
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
)
1998 /* Table of callback functions for our purpose. */
1999 bytecodeproc handlers
[] =
2002 NULL
, /* CMD_BIN8 */
2003 NULL
, /* CMD_BIN16 */
2004 register_one_local
, /* CMD_LABEL */
2005 NULL
, /* CMD_INSTR */
2009 NULL
, /* CMD_DSI8 */
2010 NULL
, /* CMD_DSI16 */
2013 /* Create array of locals */
2014 create_local_array(count_locals(b
), la
);
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
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
);
2042 verbose(1, " %s", (char*)key
);
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
)
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
)
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
;
2092 local
*l
= &args
->xu
->data_locals
.entries
[args
->index
];
2094 /* Set the virtual address */
2096 verbose(2, " %.4X %s", l
->virt_addr
, l
->name
? l
->name
: "");
2098 /* Increase label 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
[] =
2115 NULL
, /* CMD_BIN8 */
2116 NULL
, /* CMD_BIN16 */
2117 set_data_address
, /* CMD_LABEL */
2118 NULL
, /* CMD_INSTR */
2122 inc_pc_count8
, /* CMD_DSI8 */
2123 inc_pc_count16
, /* CMD_DSI16 */
2124 inc_pc_dsb
/* CMD_DSB */
2131 verbose(1, " %s", u
->_unit_
.name
);
2133 bytecode_walk(u
->_unit_
.dataseg
.bytes
, handlers
, (void *)&args
);
2134 /* Store the end address, which is the total size of data */
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
)
2154 for (j
=p
; j
<r
; j
++) {
2155 if (SORT_KEY(a
[j
]) >= x
) {
2169 * Quicksort implementation used to sort array of pointers to locals.
2171 static void label_qsort(local
**a
, int p
, int 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()
2190 local
**total_order
;
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
;
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
)
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 */
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
++) {
2220 la
= &units
[i
].data_locals
;
2221 for (j
=0; j
<la
->size
; j
++) {
2223 /* Use virtual addresses to calculate size from this label to next */
2224 if (j
== la
->size
-1) {
2225 size
= units
[i
].data_size
;
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
];
2236 label_qsort(total_order
, 0, count
-1);
2238 for (i
=0; i
<count
; i
++) {
2240 /* Try to allocate it */
2241 if (alloc_ram(l
) == 1) {
2242 /* Good, label mapped successfully */
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 */
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);
2257 /* Error, couldn't allocate */
2258 err("out of 6502 RAM while allocating unit `%s'", l
->owner
->_unit_
.name
);
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
;
2276 local
*l
= &args
->xu
->code_locals
.entries
[args
->index
];
2278 /* Set the physical address to current PC */
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 */
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).
2296 static void calc_code_addresses(xunit
*u
)
2298 calc_address_args args
;
2299 /* Table of callback functions for our purpose. */
2300 bytecodeproc handlers
[] =
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 */
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
, ...)
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 */
2344 #define require_arg(s, c, a, d) { \
2345 d = script_get_command_arg(c, a); \
2347 scripterr(s, c, "missing argument `%s'", a); \
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); \
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
)
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);
2384 scripterr(s
, c
, "`end' is smaller than `start'");
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
}
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
)
2421 /* Get unit filename */
2422 require_arg(s
, c
, "file", file
);
2423 /* arg is pointer to unit index */
2425 /* Get pointer to xunit to fill in */
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
);
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 */
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
}
2464 script_walk(sc
, map
, (void *)&i
);
2467 /*--------------------------------------------------------------------------*/
2468 /* Functions for composing a binary file based on a sequential list of
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
)
2481 /* Get the name of new output file */
2482 require_arg(s
, c
, "file", file
);
2483 /* Arg is pointer to file handle pointer */
2485 /* Close current file */
2489 /* Attempt to open new file */
2490 *fpp
= fopen(file
, "wb");
2492 scripterr(s
, c
, "could not open `%s' for writing", file
);
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
)
2511 /* Arg is pointer to file handle pointer */
2513 /* Make sure there is a file to write to */
2515 scripterr(s
, c
, "no output open");
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");
2523 scripterr(s
, c
, "could not open `%s' for reading", file
);
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
) ) {
2531 /* Advance offset */
2532 bank_offset
+= ftell(cf
);
2534 /* Close the copied file */
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
)
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
);
2560 if (bank_size
<= 0) {
2561 scripterr(s
, c
, "invalid size");
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
);
2577 require_arg_in_range(s
, c
, "origin", bank_origin
, 0x0000, 0xFFFF);
2580 /* Use old bank origin */
2583 /* Reset bank offset and PC */
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
)
2599 /* Arg is pointer to file handle pointer */
2601 /* Make sure there is a file to write to */
2603 scripterr(s
, c
, "no output open");
2606 /* Get the name of the unit */
2607 require_arg(s
, c
, "file", file
);
2609 xu
= (xunit
*)hashtab_get(unit_hash
, file
);
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
)
2638 /* Arg is pointer to file handle pointer */
2640 /* Make sure there is a file to write to */
2642 scripterr(s
, c
, "no output open");
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
);
2659 scripterr(s
, c
, "missing argument");
2664 scripterr(s
, c
, "cannot pad backwards");
2667 else if (count
> 0) {
2668 verbose(1, " padding %d bytes...", count
);
2671 for (i
=0; i
<count
; i
++) {
2674 /* Advance offset */
2675 bank_offset
+= 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
)
2693 if ( (bank_size
!= 0x7FFFFFFF) && (bank_offset
< bank_size
) ) {
2694 /* Make sure there is a file to write to */
2696 scripterr(s
, c
, "no output open");
2699 /* Pad until bank size */
2700 for (i
=bank_offset
; i
<bank_size
; i
++) {
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
)
2716 /* Arg is pointer to file handle pointer */
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
)
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
}
2741 bank_size
= 0x7FFFFFFF;
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
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
)
2778 /* Arg is pointer to file handle pointer */
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");
2785 scripterr(s
, c
, "could not open `%s' for reading", file
);
2787 unsigned char buf
[1024];
2788 int count
= fread(buf
, 1, 1024, cf
);
2789 fprintf(*fpp
, "; begin %s\n", file
);
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
);
2798 /* Close the copied file */
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
)
2831 /* Arg is pointer to file handle pointer */
2833 /* Get the name of the unit */
2834 require_arg(s
, c
, "file", file
);
2836 xu
= (xunit
*)hashtab_get(unit_hash
, file
);
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
)
2863 /* Arg is pointer to file handle pointer */
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
);
2876 scripterr(s
, c
, "missing argument");
2881 scripterr(s
, c
, "cannot pad backwards");
2883 } else if (count
> 0) {
2884 verbose(1, " padding %d bytes...", count
);
2887 fprintf(*fpp
, ".DSB $%X\n", count
);
2888 /* Advance offset */
2889 bank_offset
+= 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
}
2937 bank_size
= 0x7FFFFFFF;
2942 fprintf(fp
, ".CODESEG\n");
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
)
2963 /* Get the name of the file */
2964 require_arg(s
, c
, "file", file
);
2966 fp
= fopen(file
, "rb");
2968 scripterr(s
, c
, "could not open `%s' for reading", file
);
2972 fseek(fp
, 0, SEEK_END
);
2973 /* Advance offset */
2974 bank_offset
+= ftell(fp
);
2976 /* Close the file */
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
)
2997 /* Get the unit filename */
2998 require_arg(s
, c
, "file", file
);
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
;
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
)
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
);
3051 scripterr(s
, c
, "missing argument");
3056 scripterr(s
, c
, "cannot pad %d bytes backwards", -count
);
3059 /* Advance offset */
3060 bank_offset
+= 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
}
3084 bank_size
= 0x7FFFFFFF;
3090 script_walk(sc
, map
, NULL
);
3096 static void maybe_print_ram_statistics()
3100 if (total_ram
> 0) {
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
)
3119 /* Parse our arguments. */
3120 parse_arguments(argc
, argv
);
3123 /* Reset error and warning count */
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 */
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
);
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) {
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...");
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...");
3181 relocate_units(&sc
);
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
);
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
);
3216 return (err_count
== 0) ? 0 : 1;