1 /*****************************************************************************/
5 /* Main program for the ld65 linker */
9 /* (C) 1998 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 /*****************************************************************************/
41 #include "../common/libdefs.h"
42 #include "../common/objdefs.h"
43 #include "../common/version.h"
60 /*****************************************************************************/
62 /*****************************************************************************/
66 static unsigned ObjFiles = 0; /* Count of object files linked */
67 static unsigned LibFiles = 0; /* Count of library files linked */
68 static const char* LibPath = 0; /* Search path for modules */
69 static unsigned LibPathLen = 0; /* Length of LibPath */
73 /*****************************************************************************/
75 /*****************************************************************************/
79 static void Usage (void)
80 /* Print usage information and exit */
83 "Usage: %s [options] module ...\n"
85 "\t-m name\t\tCreate a map file\n"
86 "\t-o name\t\tName the default output file\n"
87 "\t-t type\t\tType of target system\n"
88 "\t-v\t\tVerbose mode\n"
89 "\t-vm\t\tVerbose map file\n"
90 "\t-C name\t\tUse linker config file\n"
91 "\t-Ln name\tCreate a VICE label file\n"
92 "\t-Lp\t\tMark write protected segments as such (VICE)\n"
93 "\t-S addr\t\tSet the default start address\n"
94 "\t-V\t\tPrint linker version\n",
101 static void UnknownOption (const char* Arg)
102 /* Print an error about an unknown option. Print usage information and exit */
104 fprintf (stderr, "Unknown option: %s\n", Arg);
110 static void InvNumber (const char* Arg)
111 /* Print an error about an unknown option. Print usage information and exit */
113 fprintf (stderr, "Invalid number given in argument: %s\n", Arg);
119 static unsigned long CvtNumber (const char* Arg, const char* Number)
120 /* Convert a number from a string. Allow '$' and '0x' prefixes for hex
127 if (*Number == '$') {
129 if (sscanf (Number, "%lx", &Val) != 1) {
133 if (sscanf (Number, "%li", (long*)&Val) != 1) {
138 /* Return the result */
144 static const char* GetArg (int* ArgNum, char* argv [], unsigned Len)
145 /* Get an option argument */
147 const char* Arg = argv [*ArgNum];
148 if (Arg [Len] != '\0') {
149 /* Argument appended */
152 /* Separate argument */
153 Arg = argv [*ArgNum + 1];
155 /* End of arguments */
156 fprintf (stderr, "Option requires an argument: %s\n", argv [*ArgNum]);
166 static void LongOption (int* Arg, char* argv [])
167 /* Handle a long command line option */
170 UnknownOption (argv [*Arg]);
175 static int HasPath (const char* Name)
176 /* Check if the given Name has a path component */
178 return strchr (Name, '/') != 0 || strchr (Name, '\\') != 0;
183 static void LinkFile (const char* Name)
184 /* Handle one file */
190 /* Try to open the file */
191 FILE* F = fopen (Name, "rb");
193 /* We couldn't open the file. If the name doesn't have a path, and we
194 * have a search path given, try the name with the search path
197 if (LibPathLen > 0 && !HasPath (Name)) {
198 /* Allocate memory. Account for the trailing zero, and for a
199 * path separator character eventually needed.
202 NewName = Xmalloc (strlen (Name) + Len + 2);
203 /* Build the new name */
204 memcpy (NewName, LibPath, Len);
205 if (NewName [Len-1] != '/' && NewName [Len-1] != '\\') {
206 /* We need an additional path separator */
207 NewName [Len++] = '/';
209 strcpy (NewName + Len, Name);
211 /* Now try to open the new file */
212 F = fopen (NewName, "rb");
216 Error ("Cannot open `%s': %s", Name, strerror (errno));
220 /* Read the magic word */
223 /* Do we know this type of file? */
238 Error ("File `%s' has unknown type", Name);
242 /* If we have allocated memory, free it here. Note: Memory will not always
243 * be freed if we run into an error, but that's no problem. Adding more
244 * code to work around it will use more memory than the chunk that's lost.
251 int main (int argc, char* argv [])
252 /* Assembler main program */
256 /* Evaluate the CC65_LIB environment variable */
257 LibPath = getenv ("CC65_LIB");
259 /* Use some default path */
263 LibPath = "/usr/lib/cc65/lib/";
266 LibPathLen = strlen (LibPath);
268 /* Check the parameters */
272 /* Get the argument */
273 const char* Arg = argv [I];
275 /* Check for an option */
276 if (Arg [0] == '-') {
282 LongOption (&I, argv);
286 MapFileName = GetArg (&I, argv, 2);
290 OutputName = GetArg (&I, argv, 2);
295 Error ("Cannot use -C/-t twice");
297 TgtSet (GetArg (&I, argv, 2));
302 case 'm': VerboseMap = 1; break;
303 case '\0': ++Verbose; break;
304 default: UnknownOption (Arg);
310 Error ("Cannot use -C/-t twice");
312 CfgSetName (GetArg (&I, argv, 2));
317 case 'n': LabelFileName = GetArg (&I, argv, 3); break;
318 case 'p': WProtSegs = 1; break;
319 default: UnknownOption (Arg);
324 StartAddr = CvtNumber (Arg, GetArg (&I, argv, 2));
329 "ld65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n",
330 VER_MAJOR, VER_MINOR, VER_PATCH);
349 /* Check if we had any object files */
351 fprintf (stderr, "No object files to link\n");
355 /* Check if we have a valid configuration */
357 fprintf (stderr, "Memory configuration missing\n");
361 /* Read the config file */
364 /* Assign start addresses for the segments, define linker symbols */
365 CfgAssignSegments ();
367 /* Create the output file */
370 /* Check for segments not written to the output file */
373 /* If requested, create a map file and a label file for VICE */
381 /* Dump the data for debugging */
386 /* Return an apropriate exit code */