]> git.sur5r.net Git - cc65/blob - src/ld65/main.c
4500889713638af43ac65680bcf9a06ab3d44acf
[cc65] / src / ld65 / main.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  main.c                                   */
4 /*                                                                           */
5 /*                     Main program for the ld65 linker                      */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2002 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
13 /*                                                                           */
14 /*                                                                           */
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.                                    */
18 /*                                                                           */
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:                            */
22 /*                                                                           */
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              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40
41 /* common */
42 #include "cmdline.h"
43 #include "libdefs.h"
44 #include "objdefs.h"
45 #include "print.h"
46 #include "target.h"
47 #include "version.h"
48 #include "xmalloc.h"
49
50 /* ld65 */
51 #include "binfmt.h"
52 #include "condes.h"
53 #include "config.h"
54 #include "error.h"
55 #include "exports.h"
56 #include "fileio.h"
57 #include "global.h"
58 #include "library.h"
59 #include "mapfile.h"
60 #include "objfile.h"
61 #include "scanner.h"
62 #include "segments.h"
63 #include "tgtcfg.h"
64
65
66
67 /*****************************************************************************/
68 /*                                   Data                                    */
69 /*****************************************************************************/
70
71
72
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 */
77
78
79
80 /*****************************************************************************/
81 /*                                   Code                                    */
82 /*****************************************************************************/
83
84
85
86 static void Usage (void)
87 /* Print usage information and exit */
88 {
89     fprintf (stderr,
90              "Usage: %s [options] module ...\n"
91              "Short options:\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"
103              "\n"
104              "Long options:\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",
112              ProgName);
113 }
114
115
116
117 static unsigned long CvtNumber (const char* Arg, const char* Number)
118 /* Convert a number from a string. Allow '$' and '0x' prefixes for hex
119  * numbers.
120  */
121 {
122     unsigned long Val;
123     int           Converted;
124
125     /* Convert */
126     if (*Number == '$') {
127         ++Number;
128         Converted = sscanf (Number, "%lx", &Val);
129     } else {
130         Converted = sscanf (Number, "%li", (long*)&Val);
131     }
132
133     /* Check if we do really have a number */
134     if (Converted != 1) {
135         Error ("Invalid number given in argument: %s\n", Arg);
136     }
137
138     /* Return the result */
139     return Val;
140 }
141
142
143
144 static int HasPath (const char* Name)
145 /* Check if the given Name has a path component */
146 {
147     return strchr (Name, '/') != 0 || strchr (Name, '\\') != 0;
148 }
149
150
151
152 static void LinkFile (const char* Name)
153 /* Handle one file */
154 {
155     unsigned long Magic;
156     unsigned Len;
157     char* NewName = 0;
158
159     /* Try to open the file */
160     FILE* F = fopen (Name, "rb");
161     if (F == 0) {
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
164          * prepended.
165          */
166         if (LibPathLen > 0 && !HasPath (Name)) {
167             /* Allocate memory. Account for the trailing zero, and for a
168              * path separator character eventually needed.
169              */
170             Len = LibPathLen;
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++] = '/';
177             }
178             strcpy (NewName + Len, Name);
179
180             /* Now try to open the new file */
181             F = fopen (NewName, "rb");
182         }
183
184         if (F == 0) {
185             Error ("Cannot open `%s': %s", Name, strerror (errno));
186         }
187     }
188
189     /* Read the magic word */
190     Magic = Read32 (F);
191
192     /* Do we know this type of file? */
193     switch (Magic) {
194
195         case OBJ_MAGIC:
196             ObjAdd (F, Name);
197             ++ObjFiles;
198             break;
199
200         case LIB_MAGIC:
201             LibAdd (F, Name);
202             ++LibFiles;
203             break;
204
205         default:
206             fclose (F);
207             Error ("File `%s' has unknown type", Name);
208
209     }
210
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.
214      */
215     xfree (NewName);
216 }
217
218
219
220 static void OptConfig (const char* Opt attribute ((unused)), const char* Arg)
221 /* Define the config file */
222 {
223     if (CfgAvail ()) {
224         Error ("Cannot use -C/-t twice");
225     }
226     CfgSetName (Arg);
227 }
228
229
230
231 static void OptDbgFile (const char* Opt attribute ((unused)), const char* Arg)
232 /* Give the name of the debug file */
233 {
234     DbgFileName = Arg;
235 }
236
237
238
239 static void OptHelp (const char* Opt attribute ((unused)),
240                      const char* Arg attribute ((unused)))
241 /* Print usage information and exit */
242 {
243     Usage ();
244     exit (EXIT_SUCCESS);
245 }
246
247
248
249 static void OptMapFile (const char* Opt attribute ((unused)), const char* Arg)
250 /* Give the name of the map file */
251 {
252     MapFileName = Arg;
253 }
254
255
256
257 static void OptModuleId (const char* Opt, const char* Arg)
258 /* Specify a module id */
259 {
260     unsigned long Id = CvtNumber (Opt, Arg);
261     if (Id > 0xFFFFUL) {
262         Error ("Range error in module id");
263     }
264     ModuleId = (unsigned) Id;
265 }
266
267
268
269 static void OptStartAddr (const char* Opt, const char* Arg)
270 /* Set the default start address */
271 {
272     StartAddr = CvtNumber (Opt, Arg);
273 }
274
275
276
277 static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
278 /* Set the target system */
279 {
280     const TargetDesc* D;
281
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);
286     }
287
288     /* Get the target description record */
289     D = &Targets[Target];
290
291     /* Set the target data */
292     DefaultBinFmt = D->BinFmt;
293     CfgSetBuf (D->Cfg);
294 }
295
296
297
298 static void OptVersion (const char* Opt attribute ((unused)),
299                         const char* Arg attribute ((unused)))
300 /* Print the assembler version */
301 {
302     fprintf (stderr,
303              "ld65 V%u.%u.%u - (C) Copyright 1998-2002 Ullrich von Bassewitz\n",
304              VER_MAJOR, VER_MINOR, VER_PATCH);
305 }
306
307
308
309 int main (int argc, char* argv [])
310 /* Assembler main program */
311 {
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              },
322     };
323
324     unsigned I;
325
326     /* Initialize the cmdline module */
327     InitCmdLine (&argc, &argv, "ld65");
328
329     /* Evaluate the CC65_LIB environment variable */
330     LibPath = getenv ("CC65_LIB");
331     if (LibPath == 0) {
332         /* Use some default path */
333 #ifdef CC65_LIB
334         LibPath = CC65_LIB;
335 #else
336         LibPath = "/usr/lib/cc65/lib/";
337 #endif
338     }
339     LibPathLen = strlen (LibPath);
340
341     /* Check the parameters */
342     I = 1;
343     while (I < ArgCount) {
344
345         /* Get the argument */
346         const char* Arg = ArgVec[I];
347
348         /* Check for an option */
349         if (Arg [0] == '-') {
350
351             /* An option */
352             switch (Arg [1]) {
353
354                 case '-':
355                     LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
356                     break;
357
358                 case 'h':
359                 case '?':
360                     OptHelp (Arg, 0);
361                     break;
362
363                 case 'm':
364                     OptMapFile (Arg, GetArg (&I, 2));
365                     break;
366
367                 case 'o':
368                     OutputName = GetArg (&I, 2);
369                     break;
370
371                 case 't':
372                     if (CfgAvail ()) {
373                         Error ("Cannot use -C/-t twice");
374                     }
375                     OptTarget (Arg, GetArg (&I, 2));
376                     break;
377
378                 case 'v':
379                     switch (Arg [2]) {
380                         case 'm':   VerboseMap = 1;     break;
381                         case '\0':  ++Verbosity;        break;
382                         default:    UnknownOption (Arg);
383                     }
384                     break;
385
386                 case 'C':
387                     OptConfig (Arg, GetArg (&I, 2));
388                     break;
389
390                 case 'L':
391                     switch (Arg [2]) {
392                         case 'n': LabelFileName = GetArg (&I, 3); break;
393                         case 'p': WProtSegs = 1;                  break;
394                         default:  UnknownOption (Arg);            break;
395                     }
396                     break;
397
398                 case 'S':
399                     OptStartAddr (Arg, GetArg (&I, 2));
400                     break;
401
402                 case 'V':
403                     OptVersion (Arg, 0);
404                     break;
405
406                 default:
407                     UnknownOption (Arg);
408                     break;
409             }
410
411         } else {
412
413             /* A filename */
414             LinkFile (Arg);
415
416         }
417
418         /* Next argument */
419         ++I;
420     }
421
422     /* Check if we had any object files */
423     if (ObjFiles == 0) {
424         Error ("No object files to link");
425     }
426
427     /* Check if we have a valid configuration */
428     if (!CfgAvail ()) {
429         Error ("Memory configuration missing");
430     }
431
432     /* Read the config file */
433     CfgRead ();
434
435     /* Create the condes tables if requested */
436     ConDesCreate ();
437
438     /* Assign start addresses for the segments, define linker symbols */
439     CfgAssignSegments ();
440
441     /* Create the output file */
442     CfgWriteTarget ();
443
444     /* Check for segments not written to the output file */
445     CheckSegments ();
446
447     /* If requested, create a map file and a label file for VICE */
448     if (MapFileName) {
449         CreateMapFile ();
450     }
451     if (LabelFileName) {
452         CreateLabelFile ();
453     }
454     if (DbgFileName) {
455         CreateDbgFile ();
456     }
457
458     /* Dump the data for debugging */
459     if (Verbosity > 1) {
460         SegDump ();
461         ConDesDump ();
462     }
463
464     /* Return an apropriate exit code */
465     return EXIT_SUCCESS;
466 }
467
468
469
470