]> git.sur5r.net Git - cc65/blob - src/ld65/main.c
This commit was generated by cvs2svn to compensate for changes in r2,
[cc65] / src / ld65 / main.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  main.c                                   */
4 /*                                                                           */
5 /*                     Main program for the ld65 linker                      */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998     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 #include "../common/libdefs.h"
42 #include "../common/objdefs.h"
43 #include "../common/version.h"
44
45 #include "global.h"
46 #include "error.h"
47 #include "mem.h"
48 #include "target.h"
49 #include "fileio.h"
50 #include "scanner.h"
51 #include "config.h"
52 #include "objfile.h"
53 #include "library.h"
54 #include "exports.h"
55 #include "segments.h"
56 #include "mapfile.h"
57
58
59
60 /*****************************************************************************/
61 /*                                   Data                                    */
62 /*****************************************************************************/
63
64
65
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 */
70
71
72
73 /*****************************************************************************/
74 /*                                   Code                                    */
75 /*****************************************************************************/
76
77
78
79 static void Usage (void)
80 /* Print usage information and exit */
81 {
82     fprintf (stderr,
83              "Usage: %s [options] module ...\n"
84              "Options are:\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",
95              ProgName);
96     exit (EXIT_FAILURE);
97 }
98
99
100
101 static void UnknownOption (const char* Arg)
102 /* Print an error about an unknown option. Print usage information and exit */
103 {
104     fprintf (stderr, "Unknown option: %s\n", Arg);
105     Usage ();
106 }
107
108
109
110 static void InvNumber (const char* Arg)
111 /* Print an error about an unknown option. Print usage information and exit */
112 {
113     fprintf (stderr, "Invalid number given in argument: %s\n", Arg);
114     Usage ();
115 }
116
117
118
119 static unsigned long CvtNumber (const char* Arg, const char* Number)
120 /* Convert a number from a string. Allow '$' and '0x' prefixes for hex
121  * numbers.
122  */
123 {
124     unsigned long Val;
125
126     /* Convert */
127     if (*Number == '$') {
128         ++Number;
129         if (sscanf (Number, "%lx", &Val) != 1) {
130             InvNumber (Arg);
131         }
132     } else {
133         if (sscanf (Number, "%li", (long*)&Val) != 1) {
134             InvNumber (Arg);
135         }
136     }
137
138     /* Return the result */
139     return Val;
140 }
141
142
143
144 static const char* GetArg (int* ArgNum, char* argv [], unsigned Len)
145 /* Get an option argument */
146 {
147     const char* Arg = argv [*ArgNum];
148     if (Arg [Len] != '\0') {
149         /* Argument appended */
150         return Arg + Len;
151     } else {
152         /* Separate argument */
153         Arg = argv [*ArgNum + 1];
154         if (Arg == 0) {
155             /* End of arguments */
156             fprintf (stderr, "Option requires an argument: %s\n", argv [*ArgNum]);
157             exit (EXIT_FAILURE);
158         }
159         ++(*ArgNum);
160         return Arg;
161     }
162 }
163
164
165
166 static void LongOption (int* Arg, char* argv [])
167 /* Handle a long command line option */
168 {
169     /* For now ... */
170     UnknownOption (argv [*Arg]);
171 }
172
173
174
175 static int HasPath (const char* Name)
176 /* Check if the given Name has a path component */
177 {
178     return strchr (Name, '/') != 0 || strchr (Name, '\\') != 0;
179 }
180
181
182
183 static void LinkFile (const char* Name)
184 /* Handle one file */
185 {
186     unsigned long Magic;
187     unsigned Len;
188     char* NewName = 0;
189
190     /* Try to open the file */
191     FILE* F = fopen (Name, "rb");
192     if (F == 0) {
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
195          * prepended.
196          */
197         if (LibPathLen > 0 && !HasPath (Name)) {
198             /* Allocate memory. Account for the trailing zero, and for a
199              * path separator character eventually needed.
200              */
201             Len = LibPathLen;
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++] = '/';
208             }
209             strcpy (NewName + Len, Name);
210
211             /* Now try to open the new file */
212             F = fopen (NewName, "rb");
213         }
214
215         if (F == 0) {
216             Error ("Cannot open `%s': %s", Name, strerror (errno));
217         }
218     }
219
220     /* Read the magic word */
221     Magic = Read32 (F);
222
223     /* Do we know this type of file? */
224     switch (Magic) {
225
226         case OBJ_MAGIC:
227             ObjAdd (F, Name);
228             ++ObjFiles;
229             break;
230
231         case LIB_MAGIC:
232             LibAdd (F, Name);
233             ++LibFiles;
234             break;
235
236         default:
237             fclose (F);
238             Error ("File `%s' has unknown type", Name);
239
240     }
241
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.
245      */
246     Xfree (NewName);
247 }
248
249
250
251 int main (int argc, char* argv [])
252 /* Assembler main program */
253 {
254     int I;
255
256     /* Evaluate the CC65_LIB environment variable */
257     LibPath = getenv ("CC65_LIB");
258     if (LibPath == 0) {
259         /* Use some default path */
260 #ifdef CC65_LIB
261         LibPath = CC65_LIB;
262 #else
263         LibPath = "/usr/lib/cc65/lib/";
264 #endif
265     }
266     LibPathLen = strlen (LibPath);
267
268     /* Check the parameters */
269     I = 1;
270     while (I < argc) {
271
272         /* Get the argument */
273         const char* Arg = argv [I];
274
275         /* Check for an option */
276         if (Arg [0] == '-') {
277
278             /* An option */
279             switch (Arg [1]) {
280
281                 case '-':
282                     LongOption (&I, argv);
283                     break;
284
285                 case 'm':
286                     MapFileName = GetArg (&I, argv, 2);
287                     break;
288
289                 case 'o':
290                     OutputName = GetArg (&I, argv, 2);
291                     break;
292
293                 case 't':
294                     if (CfgAvail ()) {
295                         Error ("Cannot use -C/-t twice");
296                     }
297                     TgtSet (GetArg (&I, argv, 2));
298                     break;
299
300                 case 'v':
301                     switch (Arg [2]) {
302                         case 'm':   VerboseMap = 1;     break;
303                         case '\0':  ++Verbose;          break;
304                         default:    UnknownOption (Arg);
305                     }
306                     break;
307
308                 case 'C':
309                     if (CfgAvail ()) {
310                         Error ("Cannot use -C/-t twice");
311                     }
312                     CfgSetName (GetArg (&I, argv, 2));
313                     break;
314
315                 case 'L':
316                     switch (Arg [2]) {
317                         case 'n': LabelFileName = GetArg (&I, argv, 3); break;
318                         case 'p': WProtSegs = 1;                        break;
319                         default:  UnknownOption (Arg);
320                     }
321                     break;
322
323                 case 'S':
324                     StartAddr = CvtNumber (Arg, GetArg (&I, argv, 2));
325                     break;
326
327                 case 'V':
328                     fprintf (stderr,
329                              "ld65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n",
330                              VER_MAJOR, VER_MINOR, VER_PATCH);
331                     break;
332
333                 default:
334                     UnknownOption (Arg);
335                     break;
336             }
337
338         } else {
339
340             /* A filename */
341             LinkFile (Arg);
342
343         }
344
345         /* Next argument */
346         ++I;
347     }
348
349     /* Check if we had any object files */
350     if (ObjFiles == 0) {
351         fprintf (stderr, "No object files to link\n");
352         Usage ();
353     }
354
355     /* Check if we have a valid configuration */
356     if (!CfgAvail ()) {
357         fprintf (stderr, "Memory configuration missing\n");
358         Usage ();
359     }
360
361     /* Read the config file */
362     CfgRead ();
363
364     /* Assign start addresses for the segments, define linker symbols */
365     CfgAssignSegments ();
366
367     /* Create the output file */
368     CfgWriteTarget ();
369
370     /* Check for segments not written to the output file */
371     CheckSegments ();
372
373     /* If requested, create a map file and a label file for VICE */
374     if (MapFileName) {
375         CreateMapFile ();
376     }
377     if (LabelFileName) {
378         CreateLabelFile ();
379     }
380
381     /* Dump the data for debugging */
382     if (Verbose > 1) {
383         SegDump ();
384     }
385
386     /* Return an apropriate exit code */
387     return EXIT_SUCCESS;
388 }
389
390
391