1 /*****************************************************************************/
5 /* Main program for the ld65 linker */
9 /* (C) 1998-2002 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@musoftware.de */
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 /*****************************************************************************/
67 /*****************************************************************************/
69 /*****************************************************************************/
73 static unsigned ObjFiles = 0; /* Count of object files linked */
74 static unsigned LibFiles = 0; /* Count of library files linked */
75 static const char* LibPath = 0; /* Search path for modules */
76 static unsigned LibPathLen = 0; /* Length of LibPath */
80 /*****************************************************************************/
82 /*****************************************************************************/
86 static void Usage (void)
87 /* Print usage information and exit */
90 "Usage: %s [options] module ...\n"
92 " -C name\t\tUse linker config file\n"
93 " -Ln name\t\tCreate a VICE label file\n"
94 " -Lp\t\t\tMark write protected segments as such (VICE)\n"
95 " -S addr\t\tSet the default start address\n"
96 " -V\t\t\tPrint the linker version\n"
97 " -h\t\t\tHelp (this text)\n"
98 " -m name\t\tCreate a map file\n"
99 " -o name\t\tName the default output file\n"
100 " -t sys\t\tSet the target system\n"
101 " -v\t\t\tVerbose mode\n"
102 " -vm\t\t\tVerbose map file\n"
105 " --config name\tUse linker config file\n"
106 " --help\t\tHelp (this text)\n"
107 " --mapfile name\tCreate a map file\n"
108 " --module-id id\tSpecify a module id\n"
109 " --start-addr addr\tSet the default start address\n"
110 " --target sys\t\tSet the target system\n"
111 " --version\t\tPrint the linker version\n",
117 static unsigned long CvtNumber (const char* Arg, const char* Number)
118 /* Convert a number from a string. Allow '$' and '0x' prefixes for hex
126 if (*Number == '$') {
128 Converted = sscanf (Number, "%lx", &Val);
130 Converted = sscanf (Number, "%li", (long*)&Val);
133 /* Check if we do really have a number */
134 if (Converted != 1) {
135 Error ("Invalid number given in argument: %s\n", Arg);
138 /* Return the result */
144 static int HasPath (const char* Name)
145 /* Check if the given Name has a path component */
147 return strchr (Name, '/') != 0 || strchr (Name, '\\') != 0;
152 static void LinkFile (const char* Name)
153 /* Handle one file */
159 /* Try to open the file */
160 FILE* F = fopen (Name, "rb");
162 /* We couldn't open the file. If the name doesn't have a path, and we
163 * have a search path given, try the name with the search path
166 if (LibPathLen > 0 && !HasPath (Name)) {
167 /* Allocate memory. Account for the trailing zero, and for a
168 * path separator character eventually needed.
171 NewName = xmalloc (strlen (Name) + Len + 2);
172 /* Build the new name */
173 memcpy (NewName, LibPath, Len);
174 if (NewName [Len-1] != '/' && NewName [Len-1] != '\\') {
175 /* We need an additional path separator */
176 NewName [Len++] = '/';
178 strcpy (NewName + Len, Name);
180 /* Now try to open the new file */
181 F = fopen (NewName, "rb");
185 Error ("Cannot open `%s': %s", Name, strerror (errno));
189 /* Read the magic word */
192 /* Do we know this type of file? */
207 Error ("File `%s' has unknown type", Name);
211 /* If we have allocated memory, free it here. Note: Memory will not always
212 * be freed if we run into an error, but that's no problem. Adding more
213 * code to work around it will use more memory than the chunk that's lost.
220 static void OptConfig (const char* Opt attribute ((unused)), const char* Arg)
221 /* Define the config file */
224 Error ("Cannot use -C/-t twice");
231 static void OptDbgFile (const char* Opt attribute ((unused)), const char* Arg)
232 /* Give the name of the debug file */
239 static void OptHelp (const char* Opt attribute ((unused)),
240 const char* Arg attribute ((unused)))
241 /* Print usage information and exit */
249 static void OptMapFile (const char* Opt attribute ((unused)), const char* Arg)
250 /* Give the name of the map file */
257 static void OptModuleId (const char* Opt, const char* Arg)
258 /* Specify a module id */
260 unsigned long Id = CvtNumber (Opt, Arg);
262 Error ("Range error in module id");
264 ModuleId = (unsigned) Id;
269 static void OptStartAddr (const char* Opt, const char* Arg)
270 /* Set the default start address */
272 StartAddr = CvtNumber (Opt, Arg);
277 static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
278 /* Set the target system */
282 /* Map the target name to a target id */
283 Target = FindTarget (Arg);
284 if (Target == TGT_UNKNOWN) {
285 Error ("Invalid target name: `%s'", Arg);
288 /* Get the target description record */
289 D = &Targets[Target];
291 /* Set the target data */
292 DefaultBinFmt = D->BinFmt;
298 static void OptVersion (const char* Opt attribute ((unused)),
299 const char* Arg attribute ((unused)))
300 /* Print the assembler version */
303 "ld65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n",
304 VER_MAJOR, VER_MINOR, VER_PATCH);
309 int main (int argc, char* argv [])
310 /* Assembler main program */
312 /* Program long options */
313 static const LongOpt OptTab[] = {
314 { "--config", 1, OptConfig },
315 { "--dbgfile", 1, OptDbgFile },
316 { "--help", 0, OptHelp },
317 { "--mapfile", 1, OptMapFile },
318 { "--module-id", 1, OptModuleId },
319 { "--start-addr", 1, OptStartAddr },
320 { "--target", 1, OptTarget },
321 { "--version", 0, OptVersion },
326 /* Initialize the cmdline module */
327 InitCmdLine (&argc, &argv, "ld65");
329 /* Evaluate the CC65_LIB environment variable */
330 LibPath = getenv ("CC65_LIB");
332 /* Use some default path */
336 LibPath = "/usr/lib/cc65/lib/";
339 LibPathLen = strlen (LibPath);
341 /* Check the parameters */
343 while (I < ArgCount) {
345 /* Get the argument */
346 const char* Arg = ArgVec[I];
348 /* Check for an option */
349 if (Arg [0] == '-') {
355 LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
364 OptMapFile (Arg, GetArg (&I, 2));
368 OutputName = GetArg (&I, 2);
373 Error ("Cannot use -C/-t twice");
375 OptTarget (Arg, GetArg (&I, 2));
380 case 'm': VerboseMap = 1; break;
381 case '\0': ++Verbosity; break;
382 default: UnknownOption (Arg);
387 OptConfig (Arg, GetArg (&I, 2));
392 case 'n': LabelFileName = GetArg (&I, 3); break;
393 case 'p': WProtSegs = 1; break;
394 default: UnknownOption (Arg); break;
399 OptStartAddr (Arg, GetArg (&I, 2));
422 /* Check if we had any object files */
424 Error ("No object files to link");
427 /* Check if we have a valid configuration */
429 Error ("Memory configuration missing");
432 /* Read the config file */
435 /* Create the condes tables if requested */
438 /* Assign start addresses for the segments, define linker symbols */
439 CfgAssignSegments ();
441 /* Create the output file */
444 /* Check for segments not written to the output file */
447 /* If requested, create a map file and a label file for VICE */
458 /* Dump the data for debugging */
464 /* Return an apropriate exit code */