1 /*****************************************************************************/
5 /* Main program for the ld65 linker */
9 /* (C) 1998-2013, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
74 /*****************************************************************************/
76 /*****************************************************************************/
80 static unsigned ObjFiles = 0; /* Count of object files linked */
81 static unsigned LibFiles = 0; /* Count of library files linked */
85 /*****************************************************************************/
87 /*****************************************************************************/
91 static void Usage (void)
92 /* Print usage information and exit */
94 printf ("Usage: %s [options] module ...\n"
96 " -(\t\t\tStart a library group\n"
97 " -)\t\t\tEnd a library group\n"
98 " -C name\t\tUse linker config file\n"
99 " -D sym=val\t\tDefine a symbol\n"
100 " -L path\t\tSpecify a library search path\n"
101 " -Ln name\t\tCreate a VICE label file\n"
102 " -S addr\t\tSet the default start address\n"
103 " -V\t\t\tPrint the linker version\n"
104 " -h\t\t\tHelp (this text)\n"
105 " -m name\t\tCreate a map file\n"
106 " -o name\t\tName the default output file\n"
107 " -t sys\t\tSet the target system\n"
108 " -u sym\t\tForce an import of symbol `sym'\n"
109 " -v\t\t\tVerbose mode\n"
110 " -vm\t\t\tVerbose map file\n"
113 " --cfg-path path\tSpecify a config file search path\n"
114 " --config name\t\tUse linker config file\n"
115 " --dbgfile name\tGenerate debug information\n"
116 " --define sym=val\tDefine a symbol\n"
117 " --dump-config name\tDump a builtin configuration\n"
118 " --end-group\t\tEnd a library group\n"
119 " --force-import sym\tForce an import of symbol `sym'\n"
120 " --help\t\tHelp (this text)\n"
121 " --lib file\t\tLink this library\n"
122 " --lib-path path\tSpecify a library search path\n"
123 " --mapfile name\tCreate a map file\n"
124 " --module-id id\tSpecify a module id\n"
125 " --obj file\t\tLink this object file\n"
126 " --obj-path path\tSpecify an object file search path\n"
127 " --start-addr addr\tSet the default start address\n"
128 " --start-group\t\tStart a library group\n"
129 " --target sys\t\tSet the target system\n"
130 " --version\t\tPrint the linker version\n",
136 static unsigned long CvtNumber (const char* Arg, const char* Number)
137 /* Convert a number from a string. Allow '$' and '0x' prefixes for hex
145 if (*Number == '$') {
147 Converted = sscanf (Number, "%lx", &Val);
149 Converted = sscanf (Number, "%li", (long*)&Val);
152 /* Check if we do really have a number */
153 if (Converted != 1) {
154 Error ("Invalid number given in argument: %s\n", Arg);
157 /* Return the result */
163 static void LinkFile (const char* Name, FILETYPE Type)
164 /* Handle one file */
171 /* If we don't know the file type, determine it from the extension */
172 if (Type == FILETYPE_UNKNOWN) {
173 Type = GetFileType (Name);
176 /* For known file types, search the file in the directory list */
180 PathName = SearchFile (LibSearchPath, Name);
182 PathName = SearchFile (LibDefaultPath, Name);
187 PathName = SearchFile (ObjSearchPath, Name);
189 PathName = SearchFile (ObjDefaultPath, Name);
194 PathName = xstrdup (Name); /* Use the name as is */
198 /* We must have a valid name now */
200 Error ("Input file `%s' not found", Name);
203 /* Try to open the file */
204 F = fopen (PathName, "rb");
206 Error ("Cannot open `%s': %s", PathName, strerror (errno));
209 /* Read the magic word */
212 /* Check the magic for known file types. The handling is somewhat weird
213 * since we may have given a file with a ".lib" extension, which was
214 * searched and found in a directory for library files, but we now find
215 * out (by looking at the magic) that it's indeed an object file. We just
216 * ignore the problem and hope no one will notice...
221 ObjAdd (F, PathName);
226 LibAdd (F, PathName);
232 Error ("File `%s' has unknown type", PathName);
236 /* Free allocated memory. */
242 static void DefineSymbol (const char* Def)
243 /* Define a symbol from the command line */
247 StrBuf SymName = AUTO_STRBUF_INITIALIZER;
250 /* The symbol must start with a character or underline */
251 if (Def [0] != '_' && !IsAlpha (Def [0])) {
256 /* Copy the symbol, checking the remainder */
257 while (IsAlNum (*P) || *P == '_') {
258 SB_AppendChar (&SymName, *P++);
260 SB_Terminate (&SymName);
262 /* Do we have a value given? */
266 /* We have a value */
270 if (sscanf (P, "%lx", &Val) != 1) {
274 if (sscanf (P, "%li", &Val) != 1) {
280 /* Define the new symbol */
281 CreateConstExport (GetStringId (SB_GetConstBuf (&SymName)), Val);
286 static void OptCfgPath (const char* Opt attribute ((unused)), const char* Arg)
287 /* Specify a config file search path */
289 AddSearchPath (CfgSearchPath, Arg);
294 static void OptConfig (const char* Opt attribute ((unused)), const char* Arg)
295 /* Define the config file */
300 Error ("Cannot use -C/-t twice");
302 /* Search for the file */
303 PathName = SearchFile (CfgSearchPath, Arg);
305 PathName = SearchFile (CfgDefaultPath, Arg);
308 Error ("Cannot find config file `%s'", Arg);
311 /* Read the config */
312 CfgSetName (PathName);
318 static void OptDbgFile (const char* Opt attribute ((unused)), const char* Arg)
319 /* Give the name of the debug file */
326 static void OptDefine (const char* Opt attribute ((unused)), const char* Arg)
327 /* Define a symbol on the command line */
334 static void OptEndGroup (const char* Opt attribute ((unused)),
335 const char* Arg attribute ((unused)))
336 /* End a library group */
343 static void OptForceImport (const char* Opt attribute ((unused)), const char* Arg)
344 /* Force an import of a symbol */
346 /* An optional address size may be specified */
347 const char* ColPos = strchr (Arg, ':');
350 /* Use default address size (which for now is always absolute
353 InsertImport (GenImport (GetStringId (Arg), ADDR_SIZE_ABS));
359 /* Get the address size and check it */
360 unsigned char AddrSize = AddrSizeFromStr (ColPos+1);
361 if (AddrSize == ADDR_SIZE_INVALID) {
362 Error ("Invalid address size `%s'", ColPos+1);
365 /* Create a copy of the argument */
368 /* We need just the symbol */
369 A[ColPos - Arg] = '\0';
371 /* Generate the import */
372 InsertImport (GenImport (GetStringId (A), AddrSize));
374 /* Delete the copy of the argument */
381 static void OptHelp (const char* Opt attribute ((unused)),
382 const char* Arg attribute ((unused)))
383 /* Print usage information and exit */
391 static void OptLib (const char* Opt attribute ((unused)), const char* Arg)
394 LinkFile (Arg, FILETYPE_LIB);
399 static void OptLibPath (const char* Opt attribute ((unused)), const char* Arg)
400 /* Specify a library file search path */
402 AddSearchPath (LibSearchPath, Arg);
407 static void OptMapFile (const char* Opt attribute ((unused)), const char* Arg)
408 /* Give the name of the map file */
415 static void OptModuleId (const char* Opt, const char* Arg)
416 /* Specify a module id */
418 unsigned long Id = CvtNumber (Opt, Arg);
420 Error ("Range error in module id");
422 ModuleId = (unsigned) Id;
427 static void OptObj (const char* Opt attribute ((unused)), const char* Arg)
428 /* Link an object file */
430 LinkFile (Arg, FILETYPE_OBJ);
435 static void OptObjPath (const char* Opt attribute ((unused)), const char* Arg)
436 /* Specify an object file search path */
438 AddSearchPath (ObjSearchPath, Arg);
443 static void OptOutputName (const char* Opt, const char* Arg)
444 /* Give the name of the output file */
446 /* If the name of the output file has been used in the config before
447 * (by using %O) we're actually changing it later, which - in most cases -
448 * gives unexpected results, so emit a warning in this case.
450 if (OutputNameUsed) {
451 Warning ("Option `%s' should precede options `-t' or `-C'", Opt);
458 static void OptStartAddr (const char* Opt, const char* Arg)
459 /* Set the default start address */
461 StartAddr = CvtNumber (Opt, Arg);
467 static void OptStartGroup (const char* Opt attribute ((unused)),
468 const char* Arg attribute ((unused)))
469 /* Start a library group */
476 static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
477 /* Set the target system */
479 StrBuf FileName = STATIC_STRBUF_INITIALIZER;
482 /* Map the target name to a target id */
483 Target = FindTarget (Arg);
484 if (Target == TGT_UNKNOWN) {
485 Error ("Invalid target name: `%s'", Arg);
488 /* Set the target binary format */
489 DefaultBinFmt = GetTargetProperties (Target)->BinFmt;
491 /* Build config file name from target name */
492 SB_CopyStr (&FileName, GetTargetName (Target));
493 SB_AppendStr (&FileName, ".cfg");
494 SB_Terminate (&FileName);
496 /* Search for the file */
497 PathName = SearchFile (CfgSearchPath, SB_GetBuf (&FileName));
499 PathName = SearchFile (CfgDefaultPath, SB_GetBuf (&FileName));
502 Error ("Cannot find config file `%s'", SB_GetBuf (&FileName));
505 /* Free file name memory */
509 CfgSetName (PathName);
515 static void OptVersion (const char* Opt attribute ((unused)),
516 const char* Arg attribute ((unused)))
517 /* Print the assembler version */
519 fprintf (stderr, "ld65 V%s\n", GetVersionAsString ());
524 int main (int argc, char* argv [])
525 /* Assembler main program */
527 /* Program long options */
528 static const LongOpt OptTab[] = {
529 { "--cfg-path", 1, OptCfgPath },
530 { "--config", 1, OptConfig },
531 { "--dbgfile", 1, OptDbgFile },
532 { "--define", 1, OptDefine },
533 { "--end-group", 0, OptEndGroup },
534 { "--force-import", 1, OptForceImport },
535 { "--help", 0, OptHelp },
536 { "--lib", 1, OptLib },
537 { "--lib-path", 1, OptLibPath },
538 { "--mapfile", 1, OptMapFile },
539 { "--module-id", 1, OptModuleId },
540 { "--obj", 1, OptObj },
541 { "--obj-path", 1, OptObjPath },
542 { "--start-addr", 1, OptStartAddr },
543 { "--start-group", 0, OptStartGroup },
544 { "--target", 1, OptTarget },
545 { "--version", 0, OptVersion },
549 unsigned MemoryAreaOverflows;
551 /* Initialize the cmdline module */
552 InitCmdLine (&argc, &argv, "ld65");
554 /* Initialize the input file search paths */
557 /* Initialize the string pool */
560 /* Initialize the type pool */
563 /* Check the parameters */
565 while (I < ArgCount) {
567 /* Get the argument */
568 const char* Arg = ArgVec[I];
570 /* Check for an option */
571 if (Arg [0] == '-') {
577 LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
581 OptStartGroup (Arg, 0);
585 OptEndGroup (Arg, 0);
594 OptMapFile (Arg, GetArg (&I, 2));
598 OptOutputName (Arg, GetArg (&I, 2));
603 Error ("Cannot use -C/-t twice");
605 OptTarget (Arg, GetArg (&I, 2));
609 OptForceImport (Arg, GetArg (&I, 2));
614 case 'm': VerboseMap = 1; break;
615 case '\0': ++Verbosity; break;
616 default: UnknownOption (Arg);
621 OptConfig (Arg, GetArg (&I, 2));
625 OptDefine (Arg, GetArg (&I, 2));
630 /* ## The first one is obsolete and will go */
631 case 'n': LabelFileName = GetArg (&I, 3); break;
632 default: OptLibPath (Arg, GetArg (&I, 2)); break;
637 OptStartAddr (Arg, GetArg (&I, 2));
652 LinkFile (Arg, FILETYPE_UNKNOWN);
660 /* Check if we had any object files */
662 Error ("No object files to link");
665 /* Check if we have a valid configuration */
667 Error ("Memory configuration missing");
670 /* Check if we have open library groups */
673 /* Create the condes tables if requested */
676 /* Process data from the config file. Assign start addresses for the
677 * segments, define linker symbols. The function will return the number
678 * of memory area overflows (zero on success).
680 MemoryAreaOverflows = CfgProcess ();
682 /* Check module assertions */
685 /* Check for import/export mismatches */
688 /* If we had a memory area overflow before, we cannot generate the output
689 * file. However, we will generate a short map file if requested, since
690 * this will help the user to rearrange segments and fix the overflow.
692 if (MemoryAreaOverflows) {
694 CreateMapFile (SHORT_MAPFILE);
696 Error ("Cannot generate output due to memory area overflow%s",
697 (MemoryAreaOverflows > 1)? "s" : "");
700 /* Create the output file */
703 /* Check for segments not written to the output file */
706 /* If requested, create a map file and a label file for VICE */
708 CreateMapFile (LONG_MAPFILE);
717 /* Dump the data for debugging */
723 /* Return an apropriate exit code */