1 /*****************************************************************************/
5 /* Main program for the ld65 linker */
9 /* (C) 1998-2003 Ullrich von Bassewitz */
10 /* Römerstrasse 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 /*****************************************************************************/
71 /*****************************************************************************/
73 /*****************************************************************************/
77 static unsigned ObjFiles = 0; /* Count of object files linked */
78 static unsigned LibFiles = 0; /* Count of library files linked */
82 /*****************************************************************************/
84 /*****************************************************************************/
88 static void Usage (void)
89 /* Print usage information and exit */
92 "Usage: %s [options] module ...\n"
94 " -C name\t\tUse linker config file\n"
95 " -L path\t\tSpecify a library search path\n"
96 " -Ln name\t\tCreate a VICE label file\n"
97 " -Lp\t\t\tMark write protected segments as such (VICE)\n"
98 " -S addr\t\tSet the default start address\n"
99 " -V\t\t\tPrint the linker version\n"
100 " -h\t\t\tHelp (this text)\n"
101 " -m name\t\tCreate a map file\n"
102 " -o name\t\tName the default output file\n"
103 " -t sys\t\tSet the target system\n"
104 " -v\t\t\tVerbose mode\n"
105 " -vm\t\t\tVerbose map file\n"
108 " --cfg-path path\tSpecify a config file search path\n"
109 " --config name\t\tUse linker config file\n"
110 " --dump-config name\tDump a builtin configuration\n"
111 " --help\t\tHelp (this text)\n"
112 " --lib file\t\tLink this library\n"
113 " --lib-path path\tSpecify a library search path\n"
114 " --mapfile name\tCreate a map file\n"
115 " --module-id id\tSpecify a module id\n"
116 " --obj file\t\tLink this object file\n"
117 " --obj-path path\tSpecify an object file search path\n"
118 " --start-addr addr\tSet the default start address\n"
119 " --target sys\t\tSet the target system\n"
120 " --version\t\tPrint the linker version\n",
126 static unsigned long CvtNumber (const char* Arg, const char* Number)
127 /* Convert a number from a string. Allow '$' and '0x' prefixes for hex
135 if (*Number == '$') {
137 Converted = sscanf (Number, "%lx", &Val);
139 Converted = sscanf (Number, "%li", (long*)&Val);
142 /* Check if we do really have a number */
143 if (Converted != 1) {
144 Error ("Invalid number given in argument: %s\n", Arg);
147 /* Return the result */
153 static void LinkFile (const char* Name, FILETYPE Type)
154 /* Handle one file */
161 /* If we don't know the file type, determine it from the extension */
162 if (Type == FILETYPE_UNKNOWN) {
163 Type = GetFileType (Name);
166 /* For known file types, search the file in the directory list */
170 PathName = SearchFile (Name, SEARCH_LIB);
174 PathName = SearchFile (Name, SEARCH_OBJ);
178 PathName = xstrdup (Name); /* Use the name as is */
182 /* We must have a valid name now */
184 Error ("Input file `%s' not found", Name);
187 /* Try to open the file */
188 F = fopen (PathName, "rb");
190 Error ("Cannot open `%s': %s", PathName, strerror (errno));
193 /* Read the magic word */
196 /* Check the magic for known file types. The handling is somewhat weird
197 * since we may have given a file with a ".lib" extension, which was
198 * searched and found in a directory for library files, but we now find
199 * out (by looking at the magic) that it's indeed an object file. We just
200 * ignore the problem and hope no one will notice...
205 ObjAdd (F, PathName);
210 LibAdd (F, PathName);
216 Error ("File `%s' has unknown type", PathName);
220 /* Free allocated memory. */
226 static void OptCfgPath (const char* Opt attribute ((unused)), const char* Arg)
227 /* Specify a config file search path */
229 AddSearchPath (Arg, SEARCH_CFG);
234 static void OptConfig (const char* Opt attribute ((unused)), const char* Arg)
235 /* Define the config file */
240 Error ("Cannot use -C/-t twice");
242 /* Search for the file */
243 PathName = SearchFile (Arg, SEARCH_CFG);
245 Error ("Cannot find config file `%s'", Arg);
247 CfgSetName (PathName);
254 static void OptDbgFile (const char* Opt attribute ((unused)), const char* Arg)
255 /* Give the name of the debug file */
262 static void OptDumpConfig (const char* Opt attribute ((unused)), const char* Arg)
263 /* Dump a builtin linker configuration */
265 /* Map the given target name to its id */
266 target_t T = FindTarget (Arg);
267 if (T == TGT_UNKNOWN) {
268 Error ("Target system `%s' is unknown", Arg);
271 /* Dump the builtin configuration */
272 DumpBuiltinConfig (stdout, T);
277 static void OptHelp (const char* Opt attribute ((unused)),
278 const char* Arg attribute ((unused)))
279 /* Print usage information and exit */
287 static void OptLib (const char* Opt attribute ((unused)), const char* Arg)
290 LinkFile (Arg, FILETYPE_LIB);
295 static void OptLibPath (const char* Opt attribute ((unused)), const char* Arg)
296 /* Specify a library file search path */
298 AddSearchPath (Arg, SEARCH_LIB);
303 static void OptMapFile (const char* Opt attribute ((unused)), const char* Arg)
304 /* Give the name of the map file */
311 static void OptModuleId (const char* Opt, const char* Arg)
312 /* Specify a module id */
314 unsigned long Id = CvtNumber (Opt, Arg);
316 Error ("Range error in module id");
318 ModuleId = (unsigned) Id;
323 static void OptObj (const char* Opt attribute ((unused)), const char* Arg)
324 /* Link an object file */
326 LinkFile (Arg, FILETYPE_OBJ);
331 static void OptObjPath (const char* Opt attribute ((unused)), const char* Arg)
332 /* Specify an object file search path */
334 AddSearchPath (Arg, SEARCH_OBJ);
339 static void OptStartAddr (const char* Opt, const char* Arg)
340 /* Set the default start address */
342 StartAddr = CvtNumber (Opt, Arg);
348 static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
349 /* Set the target system */
353 /* Map the target name to a target id */
354 Target = FindTarget (Arg);
355 if (Target == TGT_UNKNOWN) {
356 Error ("Invalid target name: `%s'", Arg);
359 /* Get the target description record */
360 D = &Targets[Target];
362 /* Set the target data */
363 DefaultBinFmt = D->BinFmt;
369 static void OptVersion (const char* Opt attribute ((unused)),
370 const char* Arg attribute ((unused)))
371 /* Print the assembler version */
374 "ld65 V%u.%u.%u - (C) Copyright 1998-2002 Ullrich von Bassewitz\n",
375 VER_MAJOR, VER_MINOR, VER_PATCH);
380 int main (int argc, char* argv [])
381 /* Assembler main program */
383 /* Program long options */
384 static const LongOpt OptTab[] = {
385 { "--cfg-path", 1, OptCfgPath },
386 { "--config", 1, OptConfig },
387 { "--dbgfile", 1, OptDbgFile },
388 { "--dump-config", 1, OptDumpConfig },
389 { "--help", 0, OptHelp },
390 { "--lib", 1, OptLib },
391 { "--lib-path", 1, OptLibPath },
392 { "--mapfile", 1, OptMapFile },
393 { "--module-id", 1, OptModuleId },
394 { "--obj", 1, OptObj },
395 { "--obj-path", 1, OptObjPath },
396 { "--start-addr", 1, OptStartAddr },
397 { "--target", 1, OptTarget },
398 { "--version", 0, OptVersion },
403 /* Initialize the cmdline module */
404 InitCmdLine (&argc, &argv, "ld65");
406 /* Initialize the input file search paths */
409 /* Initialize the string pool */
412 /* Check the parameters */
414 while (I < ArgCount) {
416 /* Get the argument */
417 const char* Arg = ArgVec[I];
419 /* Check for an option */
420 if (Arg [0] == '-') {
426 LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
435 OptMapFile (Arg, GetArg (&I, 2));
439 OutputName = GetArg (&I, 2);
444 Error ("Cannot use -C/-t twice");
446 OptTarget (Arg, GetArg (&I, 2));
451 case 'm': VerboseMap = 1; break;
452 case '\0': ++Verbosity; break;
453 default: UnknownOption (Arg);
458 OptConfig (Arg, GetArg (&I, 2));
463 /* ## The first two are obsolete and will go */
464 case 'n': LabelFileName = GetArg (&I, 3); break;
465 case 'p': WProtSegs = 1; break;
466 default: OptLibPath (Arg, GetArg (&I, 2)); break;
471 OptStartAddr (Arg, GetArg (&I, 2));
486 LinkFile (Arg, FILETYPE_UNKNOWN);
494 /* Check if we had any object files */
496 Error ("No object files to link");
499 /* Check if we have a valid configuration */
501 Error ("Memory configuration missing");
504 /* Read the config file */
507 /* Create the condes tables if requested */
510 /* Assign start addresses for the segments, define linker symbols */
511 CfgAssignSegments ();
513 /* Check module assertions */
516 /* Create the output file */
519 /* Check for segments not written to the output file */
522 /* If requested, create a map file and a label file for VICE */
533 /* Dump the data for debugging */
539 /* Return an apropriate exit code */