]> git.sur5r.net Git - cc65/blob - src/ld65/main.c
Added library groups
[cc65] / src / ld65 / main.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  main.c                                   */
4 /*                                                                           */
5 /*                     Main program for the ld65 linker                      */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2005 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 52                                             */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
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 "filetype.h"
44 #include "libdefs.h"
45 #include "objdefs.h"
46 #include "print.h"
47 #include "target.h"
48 #include "version.h"
49 #include "xmalloc.h"
50
51 /* ld65 */
52 #include "asserts.h"
53 #include "binfmt.h"
54 #include "condes.h"
55 #include "config.h"
56 #include "dbgfile.h"
57 #include "error.h"
58 #include "exports.h"
59 #include "fileio.h"
60 #include "filepath.h"
61 #include "global.h"
62 #include "library.h"
63 #include "mapfile.h"
64 #include "objfile.h"
65 #include "scanner.h"
66 #include "segments.h"
67 #include "spool.h"
68 #include "tgtcfg.h"
69
70
71
72 /*****************************************************************************/
73 /*                                   Data                                    */
74 /*****************************************************************************/
75
76
77
78 static unsigned         ObjFiles   = 0; /* Count of object files linked */
79 static unsigned         LibFiles   = 0; /* Count of library files linked */
80
81
82
83 /*****************************************************************************/
84 /*                                   Code                                    */
85 /*****************************************************************************/
86
87
88
89 static void Usage (void)
90 /* Print usage information and exit */
91 {
92     printf ("Usage: %s [options] module ...\n"
93             "Short options:\n"
94             "  -(\t\t\tStart a library group\n"
95             "  -)\t\t\tEnd a library group\n"
96             "  -C name\t\tUse linker config file\n"
97             "  -L path\t\tSpecify a library search path\n"
98             "  -Ln name\t\tCreate a VICE label file\n"
99             "  -S addr\t\tSet the default start address\n"
100             "  -V\t\t\tPrint the linker version\n"
101             "  -h\t\t\tHelp (this text)\n"
102             "  -m name\t\tCreate a map file\n"
103             "  -o name\t\tName the default output file\n"
104             "  -t sys\t\tSet the target system\n"
105             "  -v\t\t\tVerbose mode\n"
106             "  -vm\t\t\tVerbose map file\n"
107             "\n"
108             "Long options:\n"
109             "  --cfg-path path\tSpecify a config file search path\n"
110             "  --config name\t\tUse linker config file\n"
111             "  --dbgfile name\tGenerate debug information\n"
112             "  --dump-config name\tDump a builtin configuration\n"
113             "  --end-group\t\tEnd a library group\n"
114             "  --help\t\tHelp (this text)\n"
115             "  --lib file\t\tLink this library\n"
116             "  --lib-path path\tSpecify a library search path\n"
117             "  --mapfile name\tCreate a map file\n"
118             "  --module-id id\tSpecify a module id\n"
119             "  --obj file\t\tLink this object file\n"
120             "  --obj-path path\tSpecify an object file search path\n"
121             "  --start-addr addr\tSet the default start address\n"
122             "  --start-group\t\tStart a library group\n"
123             "  --target sys\t\tSet the target system\n"
124             "  --version\t\tPrint the linker version\n",
125             ProgName);
126 }
127
128
129
130 static unsigned long CvtNumber (const char* Arg, const char* Number)
131 /* Convert a number from a string. Allow '$' and '0x' prefixes for hex
132  * numbers.
133  */
134 {
135     unsigned long Val;
136     int           Converted;
137
138     /* Convert */
139     if (*Number == '$') {
140         ++Number;
141         Converted = sscanf (Number, "%lx", &Val);
142     } else {
143         Converted = sscanf (Number, "%li", (long*)&Val);
144     }
145
146     /* Check if we do really have a number */
147     if (Converted != 1) {
148         Error ("Invalid number given in argument: %s\n", Arg);
149     }
150
151     /* Return the result */
152     return Val;
153 }
154
155
156
157 static void LinkFile (const char* Name, FILETYPE Type)
158 /* Handle one file */
159 {
160     char*         PathName;
161     FILE*         F;
162     unsigned long Magic;
163
164
165     /* If we don't know the file type, determine it from the extension */
166     if (Type == FILETYPE_UNKNOWN) {
167         Type = GetFileType (Name);
168     }
169
170     /* For known file types, search the file in the directory list */
171     switch (Type) {
172
173         case FILETYPE_LIB:
174             PathName = SearchFile (Name, SEARCH_LIB);
175             break;
176
177         case FILETYPE_OBJ:
178             PathName = SearchFile (Name, SEARCH_OBJ);
179             break;
180
181         default:
182             PathName = xstrdup (Name);   /* Use the name as is */
183             break;
184     }
185
186     /* We must have a valid name now */
187     if (PathName == 0) {
188         Error ("Input file `%s' not found", Name);
189     }
190
191     /* Try to open the file */
192     F = fopen (PathName, "rb");
193     if (F == 0) {
194         Error ("Cannot open `%s': %s", PathName, strerror (errno));
195     }
196
197     /* Read the magic word */
198     Magic = Read32 (F);
199
200     /* Check the magic for known file types. The handling is somewhat weird
201      * since we may have given a file with a ".lib" extension, which was
202      * searched and found in a directory for library files, but we now find
203      * out (by looking at the magic) that it's indeed an object file. We just
204      * ignore the problem and hope no one will notice...
205      */
206     switch (Magic) {
207
208         case OBJ_MAGIC:
209             ObjAdd (F, PathName);
210             ++ObjFiles;
211             break;
212
213         case LIB_MAGIC:
214             LibAdd (F, PathName);
215             ++LibFiles;
216             break;
217
218         default:
219             fclose (F);
220             Error ("File `%s' has unknown type", PathName);
221
222     }
223
224     /* Free allocated memory. */
225     xfree (PathName);
226 }
227
228
229
230 static void OptCfgPath (const char* Opt attribute ((unused)), const char* Arg)
231 /* Specify a config file search path */
232 {
233     AddSearchPath (Arg, SEARCH_CFG);
234 }
235
236
237
238 static void OptConfig (const char* Opt attribute ((unused)), const char* Arg)
239 /* Define the config file */
240 {
241     char* PathName;
242
243     if (CfgAvail ()) {
244         Error ("Cannot use -C/-t twice");
245     }
246     /* Search for the file */
247     PathName = SearchFile (Arg, SEARCH_CFG);
248     if (PathName == 0) {
249         Error ("Cannot find config file `%s'", Arg);
250     } else {
251         CfgSetName (PathName);
252     }
253 }
254
255
256
257 static void OptDbgFile (const char* Opt attribute ((unused)), const char* Arg)
258 /* Give the name of the debug file */
259 {
260     DbgFileName = Arg;
261 }
262
263
264
265 static void OptDumpConfig (const char* Opt attribute ((unused)), const char* Arg)
266 /* Dump a builtin linker configuration */
267 {
268     /* Map the given target name to its id */
269     target_t T = FindTarget (Arg);
270     if (T == TGT_UNKNOWN) {
271         Error ("Target system `%s' is unknown", Arg);
272     }
273
274     /* Dump the builtin configuration */
275     DumpBuiltinConfig (stdout, T);
276 }
277
278
279
280 static void OptEndGroup (const char* Opt attribute ((unused)),
281                          const char* Arg attribute ((unused)))
282 /* End a library group */
283 {
284     LibEndGroup ();
285 }
286
287
288
289 static void OptHelp (const char* Opt attribute ((unused)),
290                      const char* Arg attribute ((unused)))
291 /* Print usage information and exit */
292 {
293     Usage ();
294     exit (EXIT_SUCCESS);
295 }
296
297
298
299 static void OptLib (const char* Opt attribute ((unused)), const char* Arg)
300 /* Link a library */
301 {
302     LinkFile (Arg, FILETYPE_LIB);
303 }
304
305
306
307 static void OptLibPath (const char* Opt attribute ((unused)), const char* Arg)
308 /* Specify a library file search path */
309 {
310     AddSearchPath (Arg, SEARCH_LIB);
311 }
312
313
314
315 static void OptMapFile (const char* Opt attribute ((unused)), const char* Arg)
316 /* Give the name of the map file */
317 {
318     MapFileName = Arg;
319 }
320
321
322
323 static void OptModuleId (const char* Opt, const char* Arg)
324 /* Specify a module id */
325 {
326     unsigned long Id = CvtNumber (Opt, Arg);
327     if (Id > 0xFFFFUL) {
328         Error ("Range error in module id");
329     }
330     ModuleId = (unsigned) Id;
331 }
332
333
334
335 static void OptObj (const char* Opt attribute ((unused)), const char* Arg)
336 /* Link an object file */
337 {
338     LinkFile (Arg, FILETYPE_OBJ);
339 }
340
341
342
343 static void OptObjPath (const char* Opt attribute ((unused)), const char* Arg)
344 /* Specify an object file search path */
345 {
346     AddSearchPath (Arg, SEARCH_OBJ);
347 }
348
349
350
351 static void OptStartAddr (const char* Opt, const char* Arg)
352 /* Set the default start address */
353 {
354     StartAddr = CvtNumber (Opt, Arg);
355     HaveStartAddr = 1;
356 }
357
358
359
360 static void OptStartGroup (const char* Opt attribute ((unused)),
361                            const char* Arg attribute ((unused)))
362 /* Start a library group */
363 {
364     LibStartGroup ();
365 }
366
367
368
369 static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
370 /* Set the target system */
371 {
372     const TargetDesc* D;
373
374     /* Map the target name to a target id */
375     Target = FindTarget (Arg);
376     if (Target == TGT_UNKNOWN) {
377         Error ("Invalid target name: `%s'", Arg);
378     }
379
380     /* Get the target description record */
381     D = &Targets[Target];
382
383     /* Set the target data */
384     DefaultBinFmt = D->BinFmt;
385     CfgSetBuf (D->Cfg);
386 }
387
388
389
390 static void OptVersion (const char* Opt attribute ((unused)),
391                         const char* Arg attribute ((unused)))
392 /* Print the assembler version */
393 {
394     fprintf (stderr,
395              "ld65 V%u.%u.%u - (C) Copyright 1998-2002 Ullrich von Bassewitz\n",
396              VER_MAJOR, VER_MINOR, VER_PATCH);
397 }
398
399
400
401 int main (int argc, char* argv [])
402 /* Assembler main program */
403 {
404     /* Program long options */
405     static const LongOpt OptTab[] = {
406         { "--cfg-path",         1,      OptCfgPath              },
407         { "--config",           1,      OptConfig               },
408         { "--dbgfile",          1,      OptDbgFile              },
409         { "--dump-config",      1,      OptDumpConfig           },
410         { "--end-group",        0,      OptEndGroup             },
411         { "--help",             0,      OptHelp                 },
412         { "--lib",              1,      OptLib                  },
413         { "--lib-path",         1,      OptLibPath              },
414         { "--mapfile",          1,      OptMapFile              },
415         { "--module-id",        1,      OptModuleId             },
416         { "--obj",              1,      OptObj                  },
417         { "--obj-path",         1,      OptObjPath              },
418         { "--start-addr",       1,      OptStartAddr            },
419         { "--start-group",      0,      OptStartGroup           },
420         { "--target",           1,      OptTarget               },
421         { "--version",          0,      OptVersion              },
422     };
423
424     unsigned I;
425     unsigned MemoryAreaOverflows;
426
427     /* Initialize the cmdline module */
428     InitCmdLine (&argc, &argv, "ld65");
429
430     /* Initialize the input file search paths */
431     InitSearchPaths ();
432
433     /* Initialize the string pool */
434     InitStrPool ();
435
436     /* Check the parameters */
437     I = 1;
438     while (I < ArgCount) {
439
440         /* Get the argument */
441         const char* Arg = ArgVec[I];
442
443         /* Check for an option */
444         if (Arg [0] == '-') {
445
446             /* An option */
447             switch (Arg [1]) {
448
449                 case '-':
450                     LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
451                     break;
452
453                 case '(':
454                     OptStartGroup (Arg, 0);
455                     break;
456
457                 case ')':
458                     OptEndGroup (Arg, 0);
459                     break;
460
461                 case 'h':
462                 case '?':
463                     OptHelp (Arg, 0);
464                     break;
465
466                 case 'm':
467                     OptMapFile (Arg, GetArg (&I, 2));
468                     break;
469
470                 case 'o':
471                     OutputName = GetArg (&I, 2);
472                     break;
473
474                 case 't':
475                     if (CfgAvail ()) {
476                         Error ("Cannot use -C/-t twice");
477                     }
478                     OptTarget (Arg, GetArg (&I, 2));
479                     break;
480
481                 case 'v':
482                     switch (Arg [2]) {
483                         case 'm':   VerboseMap = 1;     break;
484                         case '\0':  ++Verbosity;        break;
485                         default:    UnknownOption (Arg);
486                     }
487                     break;
488
489                 case 'C':
490                     OptConfig (Arg, GetArg (&I, 2));
491                     break;
492
493                 case 'L':
494                     switch (Arg [2]) {
495                         /* ## The first one is obsolete and will go */
496                         case 'n': LabelFileName = GetArg (&I, 3);   break;
497                         default:  OptLibPath (Arg, GetArg (&I, 2)); break;
498                     }
499                     break;
500
501                 case 'S':
502                     OptStartAddr (Arg, GetArg (&I, 2));
503                     break;
504
505                 case 'V':
506                     OptVersion (Arg, 0);
507                     break;
508
509                 default:
510                     UnknownOption (Arg);
511                     break;
512             }
513
514         } else {
515
516             /* A filename */
517             LinkFile (Arg, FILETYPE_UNKNOWN);
518
519         }
520
521         /* Next argument */
522         ++I;
523     }
524
525     /* Check if we had any object files */
526     if (ObjFiles == 0) {
527         Error ("No object files to link");
528     }
529
530     /* Check if we have a valid configuration */
531     if (!CfgAvail ()) {
532         Error ("Memory configuration missing");
533     }
534
535     /* Check if we have open library groups */
536     LibCheckGroup ();
537
538     /* Read the config file */
539     CfgRead ();
540
541     /* Create the condes tables if requested */
542     ConDesCreate ();
543
544     /* Assign start addresses for the segments, define linker symbols. The
545      * function will return the number of memory area overflows (zero on
546      * success).
547      */
548     MemoryAreaOverflows = CfgAssignSegments ();
549
550     /* Check module assertions */
551     CheckAssertions ();
552
553     /* Check for import/export mismatches */
554     CheckExports ();
555
556     /* If we had a memory area overflow before, we cannot generate the output
557      * file. However, we will generate a short map file if requested, since
558      * this will help the user to rearrange segments and fix the overflow.
559      */
560     if (MemoryAreaOverflows) {
561         if (MapFileName) {
562             CreateMapFile (SHORT_MAPFILE);
563         }
564         Error ("Cannot generate output due to memory area overflow%s",
565                (MemoryAreaOverflows > 1)? "s" : "");
566     }
567
568     /* Create the output file */
569     CfgWriteTarget ();
570
571     /* Check for segments not written to the output file */
572     CheckSegments ();
573
574     /* If requested, create a map file and a label file for VICE */
575     if (MapFileName) {
576         CreateMapFile (LONG_MAPFILE);
577     }
578     if (LabelFileName) {
579         CreateLabelFile ();
580     }
581     if (DbgFileName) {
582         CreateDbgFile ();
583     }
584
585     /* Dump the data for debugging */
586     if (Verbosity > 1) {
587         SegDump ();
588         ConDesDump ();
589     }
590
591     /* Return an apropriate exit code */
592     return EXIT_SUCCESS;
593 }
594
595
596
597