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 */
83 /* struct InputFile.Type definitions */
84 #define INPUT_FILES_FILE 0 /* Entry is a file (unknown type) */
85 #define INPUT_FILES_FILE_OBJ 1 /* Entry is a object file */
86 #define INPUT_FILES_FILE_LIB 2 /* Entry is a library file */
87 #define INPUT_FILES_SGROUP 3 /* Entry is 'StartGroup' */
88 #define INPUT_FILES_EGROUP 4 /* Entry is 'EndGroup' */
90 #define MAX_INPUTFILES 256
92 /* Array of inputs (libraries and object files) */
93 static struct InputFile {
97 static unsigned InputFilesCount = 0;
98 static const char *CmdlineCfgFile = NULL,
99 *CmdlineTarget = NULL;
103 /*****************************************************************************/
105 /*****************************************************************************/
109 static void Usage (void)
110 /* Print usage information and exit */
112 printf ("Usage: %s [options] module ...\n"
114 " -(\t\t\tStart a library group\n"
115 " -)\t\t\tEnd a library group\n"
116 " -C name\t\tUse linker config file\n"
117 " -D sym=val\t\tDefine a symbol\n"
118 " -L path\t\tSpecify a library search path\n"
119 " -Ln name\t\tCreate a VICE label file\n"
120 " -S addr\t\tSet the default start address\n"
121 " -V\t\t\tPrint the linker version\n"
122 " -h\t\t\tHelp (this text)\n"
123 " -m name\t\tCreate a map file\n"
124 " -o name\t\tName the default output file\n"
125 " -t sys\t\tSet the target system\n"
126 " -u sym\t\tForce an import of symbol 'sym'\n"
127 " -v\t\t\tVerbose mode\n"
128 " -vm\t\t\tVerbose map file\n"
131 " --allow-multiple-definition\tAllow multiple definitions\n"
132 " --cfg-path path\t\tSpecify a config file search path\n"
133 " --config name\t\t\tUse linker config file\n"
134 " --dbgfile name\t\tGenerate debug information\n"
135 " --define sym=val\t\tDefine a symbol\n"
136 " --end-group\t\t\tEnd a library group\n"
137 " --force-import sym\t\tForce an import of symbol 'sym'\n"
138 " --help\t\t\tHelp (this text)\n"
139 " --lib file\t\t\tLink this library\n"
140 " --lib-path path\t\tSpecify a library search path\n"
141 " --mapfile name\t\tCreate a map file\n"
142 " --module-id id\t\tSpecify a module id\n"
143 " --obj file\t\t\tLink this object file\n"
144 " --obj-path path\t\tSpecify an object file search path\n"
145 " --start-addr addr\t\tSet the default start address\n"
146 " --start-group\t\t\tStart a library group\n"
147 " --target sys\t\t\tSet the target system\n"
148 " --version\t\t\tPrint the linker version\n",
154 static unsigned long CvtNumber (const char* Arg, const char* Number)
155 /* Convert a number from a string. Allow '$' and '0x' prefixes for hex
163 if (*Number == '$') {
165 Converted = sscanf (Number, "%lx", &Val);
167 Converted = sscanf (Number, "%li", (long*)&Val);
170 /* Check if we do really have a number */
171 if (Converted != 1) {
172 Error ("Invalid number given in argument: %s\n", Arg);
175 /* Return the result */
181 static void LinkFile (const char* Name, FILETYPE Type)
182 /* Handle one file */
189 /* If we don't know the file type, determine it from the extension */
190 if (Type == FILETYPE_UNKNOWN) {
191 Type = GetFileType (Name);
194 /* For known file types, search the file in the directory list */
198 PathName = SearchFile (LibSearchPath, Name);
200 PathName = SearchFile (LibDefaultPath, Name);
205 PathName = SearchFile (ObjSearchPath, Name);
207 PathName = SearchFile (ObjDefaultPath, Name);
212 PathName = xstrdup (Name); /* Use the name as is */
216 /* We must have a valid name now */
218 Error ("Input file '%s' not found", Name);
221 /* Try to open the file */
222 F = fopen (PathName, "rb");
224 Error ("Cannot open '%s': %s", PathName, strerror (errno));
227 /* Read the magic word */
230 /* Check the magic for known file types. The handling is somewhat weird
231 ** since we may have given a file with a ".lib" extension, which was
232 ** searched and found in a directory for library files, but we now find
233 ** out (by looking at the magic) that it's indeed an object file. We just
234 ** ignore the problem and hope no one will notice...
239 ObjAdd (F, PathName);
244 LibAdd (F, PathName);
250 Error ("File '%s' has unknown type", PathName);
254 /* Free allocated memory. */
260 static void DefineSymbol (const char* Def)
261 /* Define a symbol from the command line */
265 StrBuf SymName = AUTO_STRBUF_INITIALIZER;
268 /* The symbol must start with a character or underline */
269 if (Def [0] != '_' && !IsAlpha (Def [0])) {
274 /* Copy the symbol, checking the remainder */
275 while (IsAlNum (*P) || *P == '_') {
276 SB_AppendChar (&SymName, *P++);
278 SB_Terminate (&SymName);
280 /* Do we have a value given? */
284 /* We have a value */
288 if (sscanf (P, "%lx", &Val) != 1) {
292 if (sscanf (P, "%li", &Val) != 1) {
298 /* Define the new symbol */
299 CreateConstExport (GetStringId (SB_GetConstBuf (&SymName)), Val);
304 static void OptCfgPath (const char* Opt attribute ((unused)), const char* Arg)
305 /* Specify a config file search path */
307 AddSearchPath (CfgSearchPath, Arg);
312 static void OptConfig (const char* Opt attribute ((unused)), const char* Arg)
313 /* Define the config file */
318 Error ("Cannot use -C/-t twice");
320 /* Search for the file */
321 PathName = SearchFile (CfgSearchPath, Arg);
323 PathName = SearchFile (CfgDefaultPath, Arg);
326 Error ("Cannot find config file '%s'", Arg);
329 /* Read the config */
330 CfgSetName (PathName);
336 static void OptDbgFile (const char* Opt attribute ((unused)), const char* Arg)
337 /* Give the name of the debug file */
344 static void OptDefine (const char* Opt attribute ((unused)), const char* Arg)
345 /* Define a symbol on the command line */
352 static void OptEndGroup (const char* Opt attribute ((unused)),
353 const char* Arg attribute ((unused)))
354 /* End a library group */
361 static void OptForceImport (const char* Opt attribute ((unused)), const char* Arg)
362 /* Force an import of a symbol */
364 /* An optional address size may be specified */
365 const char* ColPos = strchr (Arg, ':');
368 /* Use default address size (which for now is always absolute
371 InsertImport (GenImport (GetStringId (Arg), ADDR_SIZE_ABS));
377 /* Get the address size and check it */
378 unsigned char AddrSize = AddrSizeFromStr (ColPos+1);
379 if (AddrSize == ADDR_SIZE_INVALID) {
380 Error ("Invalid address size '%s'", ColPos+1);
383 /* Create a copy of the argument */
386 /* We need just the symbol */
387 A[ColPos - Arg] = '\0';
389 /* Generate the import */
390 InsertImport (GenImport (GetStringId (A), AddrSize));
392 /* Delete the copy of the argument */
399 static void OptHelp (const char* Opt attribute ((unused)),
400 const char* Arg attribute ((unused)))
401 /* Print usage information and exit */
409 static void OptLib (const char* Opt attribute ((unused)), const char* Arg)
412 InputFiles[InputFilesCount].Type = INPUT_FILES_FILE_LIB;
413 InputFiles[InputFilesCount].FileName = Arg;
414 if (++InputFilesCount >= MAX_INPUTFILES)
415 Error ("Too many input files");
420 static void OptLibPath (const char* Opt attribute ((unused)), const char* Arg)
421 /* Specify a library file search path */
423 AddSearchPath (LibSearchPath, Arg);
428 static void OptMapFile (const char* Opt attribute ((unused)), const char* Arg)
429 /* Give the name of the map file */
432 Error ("Cannot use -m twice");
439 static void OptModuleId (const char* Opt, const char* Arg)
440 /* Specify a module id */
442 unsigned long Id = CvtNumber (Opt, Arg);
444 Error ("Range error in module id");
446 ModuleId = (unsigned) Id;
451 static void OptObj (const char* Opt attribute ((unused)), const char* Arg)
452 /* Link an object file */
454 InputFiles[InputFilesCount].Type = INPUT_FILES_FILE_OBJ;
455 InputFiles[InputFilesCount].FileName = Arg;
456 if (++InputFilesCount >= MAX_INPUTFILES)
457 Error ("Too many input files");
462 static void OptObjPath (const char* Opt attribute ((unused)), const char* Arg)
463 /* Specify an object file search path */
465 AddSearchPath (ObjSearchPath, Arg);
470 static void OptOutputName (const char* Opt attribute ((unused)), const char* Arg)
471 /* Give the name of the output file */
473 static int OutputNameSeen = 0;
474 if (OutputNameSeen) {
475 Error ("Cannot use -o twice");
483 static void OptStartAddr (const char* Opt, const char* Arg)
484 /* Set the default start address */
487 Error ("Cannot use -S twice");
489 StartAddr = CvtNumber (Opt, Arg);
495 static void OptStartGroup (const char* Opt attribute ((unused)),
496 const char* Arg attribute ((unused)))
497 /* Start a library group */
504 static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
505 /* Set the target system */
507 StrBuf FileName = STATIC_STRBUF_INITIALIZER;
510 /* Map the target name to a target id */
511 Target = FindTarget (Arg);
512 if (Target == TGT_UNKNOWN) {
513 Error ("Invalid target name: '%s'", Arg);
516 /* Set the target binary format */
517 DefaultBinFmt = GetTargetProperties (Target)->BinFmt;
519 /* Build config file name from target name */
520 SB_CopyStr (&FileName, GetTargetName (Target));
521 SB_AppendStr (&FileName, ".cfg");
522 SB_Terminate (&FileName);
524 /* Search for the file */
525 PathName = SearchFile (CfgSearchPath, SB_GetBuf (&FileName));
527 PathName = SearchFile (CfgDefaultPath, SB_GetBuf (&FileName));
530 Error ("Cannot find config file '%s'", SB_GetBuf (&FileName));
533 /* Free file name memory */
537 CfgSetName (PathName);
543 static void OptVersion (const char* Opt attribute ((unused)),
544 const char* Arg attribute ((unused)))
545 /* Print the assembler version */
547 fprintf (stderr, "%s V%s\n", ProgName, GetVersionAsString ());
553 static void OptMultDef (const char* Opt attribute ((unused)),
554 const char* Arg attribute ((unused)))
555 /* Print the assembler version */
562 static void CmdlOptStartGroup (const char* Opt attribute ((unused)),
563 const char* Arg attribute ((unused)))
564 /* Remember 'start group' occurrence in input files array */
566 InputFiles[InputFilesCount].Type = INPUT_FILES_SGROUP;
567 InputFiles[InputFilesCount].FileName = Arg; /* Unused */
568 if (++InputFilesCount >= MAX_INPUTFILES)
569 Error ("Too many input files");
574 static void CmdlOptEndGroup (const char* Opt attribute ((unused)),
575 const char* Arg attribute ((unused)))
576 /* Remember 'end group' occurrence in input files array */
578 InputFiles[InputFilesCount].Type = INPUT_FILES_EGROUP;
579 InputFiles[InputFilesCount].FileName = Arg; /* Unused */
580 if (++InputFilesCount >= MAX_INPUTFILES)
581 Error ("Too many input files");
586 static void CmdlOptConfig (const char* Opt attribute ((unused)), const char* Arg)
587 /* Set 'config file' command line parameter */
589 if (CmdlineCfgFile || CmdlineTarget) {
590 Error ("Cannot use -C/-t twice");
592 CmdlineCfgFile = Arg;
597 static void CmdlOptTarget (const char* Opt attribute ((unused)), const char* Arg)
598 /* Set 'target' command line parameter */
600 if (CmdlineCfgFile || CmdlineTarget) {
601 Error ("Cannot use -C/-t twice");
608 static void ParseCommandLine(void)
610 /* Program long options */
611 static const LongOpt OptTab[] = {
612 { "--allow-multiple-definition", 0, OptMultDef },
613 { "--cfg-path", 1, OptCfgPath },
614 { "--config", 1, CmdlOptConfig },
615 { "--dbgfile", 1, OptDbgFile },
616 { "--define", 1, OptDefine },
617 { "--end-group", 0, CmdlOptEndGroup },
618 { "--force-import", 1, OptForceImport },
619 { "--help", 0, OptHelp },
620 { "--lib", 1, OptLib },
621 { "--lib-path", 1, OptLibPath },
622 { "--mapfile", 1, OptMapFile },
623 { "--module-id", 1, OptModuleId },
624 { "--obj", 1, OptObj },
625 { "--obj-path", 1, OptObjPath },
626 { "--start-addr", 1, OptStartAddr },
627 { "--start-group", 0, CmdlOptStartGroup },
628 { "--target", 1, CmdlOptTarget },
629 { "--version", 0, OptVersion },
633 unsigned LabelFileGiven = 0;
635 /* Allocate memory for input file array */
636 InputFiles = xmalloc (MAX_INPUTFILES * sizeof (struct InputFile));
638 /* Defer setting of config/target and input files until all options are parsed */
640 while (I < ArgCount) {
642 /* Get the argument */
643 const char* Arg = ArgVec[I];
645 /* Check for an option */
646 if (Arg [0] == '-') {
652 LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
656 CmdlOptStartGroup (Arg, 0);
660 CmdlOptEndGroup (Arg, 0);
669 OptMapFile (Arg, GetArg (&I, 2));
673 OptOutputName (NULL, GetArg (&I, 2));
677 CmdlOptTarget (Arg, GetArg (&I, 2));
681 OptForceImport (Arg, GetArg (&I, 2));
686 case 'm': VerboseMap = 1; break;
687 case '\0': ++Verbosity; break;
688 default: UnknownOption (Arg);
693 CmdlOptConfig (Arg, GetArg (&I, 2));
697 OptDefine (Arg, GetArg (&I, 2));
703 /* ## This one is obsolete and will go */
704 if (LabelFileGiven) {
705 Error ("Cannot use -Ln twice");
708 LabelFileName = GetArg (&I, 3);
711 OptLibPath (Arg, GetArg (&I, 2));
717 OptStartAddr (Arg, GetArg (&I, 2));
732 InputFiles[InputFilesCount].Type = INPUT_FILES_FILE;
733 InputFiles[InputFilesCount].FileName = Arg;
734 if (++InputFilesCount >= MAX_INPUTFILES)
735 Error ("Too many input files");
744 OptTarget (NULL, CmdlineTarget);
745 } else if (CmdlineCfgFile) {
746 OptConfig (NULL, CmdlineCfgFile);
749 /* Process input files */
750 for (I = 0; I < InputFilesCount; ++I) {
751 switch (InputFiles[I].Type) {
752 case INPUT_FILES_FILE:
753 LinkFile (InputFiles[I].FileName, FILETYPE_UNKNOWN);
755 case INPUT_FILES_FILE_LIB:
756 LinkFile (InputFiles[I].FileName, FILETYPE_LIB);
758 case INPUT_FILES_FILE_OBJ:
759 LinkFile (InputFiles[I].FileName, FILETYPE_OBJ);
761 case INPUT_FILES_SGROUP:
762 OptStartGroup (NULL, 0);
764 case INPUT_FILES_EGROUP:
765 OptEndGroup (NULL, 0);
772 /* Free memory used for input file array */
778 int main (int argc, char* argv [])
779 /* Linker main program */
781 unsigned MemoryAreaOverflows;
783 /* Initialize the cmdline module */
784 InitCmdLine (&argc, &argv, "ld65");
786 /* Initialize the input file search paths */
789 /* Initialize the string pool */
792 /* Initialize the type pool */
795 /* Parse the command line */
798 /* Check if we had any object files */
800 Error ("No object files to link");
803 /* Check if we have a valid configuration */
805 Error ("Memory configuration missing");
808 /* Check if we have open library groups */
811 /* Create the condes tables if requested */
814 /* Process data from the config file. Assign start addresses for the
815 ** segments, define linker symbols. The function will return the number
816 ** of memory area overflows (zero on success).
818 MemoryAreaOverflows = CfgProcess ();
820 /* Check module assertions */
823 /* Check for import/export mismatches */
826 /* If we had a memory area overflow before, we cannot generate the output
827 ** file. However, we will generate a short map file if requested, since
828 ** this will help the user to rearrange segments and fix the overflow.
830 if (MemoryAreaOverflows) {
832 CreateMapFile (SHORT_MAPFILE);
834 Error ("Cannot generate most of the files due to memory area overflow%c",
835 (MemoryAreaOverflows > 1) ? 's' : ' ');
838 /* Create the output file */
841 /* Check for segments not written to the output file */
844 /* If requested, create a map file and a label file for VICE */
846 CreateMapFile (LONG_MAPFILE);
855 /* Dump the data for debugging */
861 /* Return an apropriate exit code */