]> git.sur5r.net Git - cc65/blobdiff - src/ld65/main.c
Corrected indentation - no code change.
[cc65] / src / ld65 / main.c
index a424d37f1342d864a9e3b779f9f313da3d00f2d0..10fff402e6c05a0d484397405ca2996453822e1f 100644 (file)
@@ -1,15 +1,15 @@
 /*****************************************************************************/
-/*                                                                          */
-/*                                 main.c                                   */
-/*                                                                          */
+/*                                                                          */
+/*                                 main.c                                   */
+/*                                                                          */
 /*                    Main program for the ld65 linker                      */
-/*                                                                          */
-/*                                                                          */
-/*                                                                          */
-/* (C) 1998-2005 Ullrich von Bassewitz                                       */
-/*               Römerstrasse 52                                             */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/*                                                                          */
+/*                                                                          */
+/*                                                                          */
+/* (C) 1998-2010, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                          */
 /*                                                                          */
 /* This software is provided 'as-is', without any expressed or implied      */
@@ -39,6 +39,8 @@
 #include <errno.h>
 
 /* common */
+#include "addrsize.h"
+#include "chartype.h"
 #include "cmdline.h"
 #include "filetype.h"
 #include "libdefs.h"
@@ -89,37 +91,44 @@ static unsigned             LibFiles   = 0; /* Count of library files linked */
 static void Usage (void)
 /* Print usage information and exit */
 {
-    fprintf (stderr,
-            "Usage: %s [options] module ...\n"
-            "Short options:\n"
-                    "  -C name\t\tUse linker config file\n"
-             "  -L path\t\tSpecify a library search path\n"
-                    "  -Ln name\t\tCreate a VICE label file\n"
-                    "  -S addr\t\tSet the default start address\n"
-                    "  -V\t\t\tPrint the linker version\n"
-                    "  -h\t\t\tHelp (this text)\n"
-                    "  -m name\t\tCreate a map file\n"
-                    "  -o name\t\tName the default output file\n"
-                    "  -t sys\t\tSet the target system\n"
-                    "  -v\t\t\tVerbose mode\n"
-                    "  -vm\t\t\tVerbose map file\n"
-            "\n"
-            "Long options:\n"
-             "  --cfg-path path\tSpecify a config file search path\n"
-                    "  --config name\t\tUse linker config file\n"
-                    "  --dbgfile name\tGenerate debug information\n"
-             "  --dump-config name\tDump a builtin configuration\n"
-            "  --help\t\tHelp (this text)\n"
-             "  --lib file\t\tLink this library\n"
-             "  --lib-path path\tSpecify a library search path\n"
-            "  --mapfile name\tCreate a map file\n"
-             "  --module-id id\tSpecify a module id\n"
-             "  --obj file\t\tLink this object file\n"
-             "  --obj-path path\tSpecify an object file search path\n"
-                    "  --start-addr addr\tSet the default start address\n"
-                    "  --target sys\t\tSet the target system\n"
-                    "  --version\t\tPrint the linker version\n",
-            ProgName);
+    printf ("Usage: %s [options] module ...\n"
+            "Short options:\n"
+            "  -(\t\t\tStart a library group\n"
+            "  -)\t\t\tEnd a library group\n"
+            "  -C name\t\tUse linker config file\n"
+            "  -D sym=val\t\tDefine a symbol\n"
+            "  -L path\t\tSpecify a library search path\n"
+            "  -Ln name\t\tCreate a VICE label file\n"
+            "  -S addr\t\tSet the default start address\n"
+            "  -V\t\t\tPrint the linker version\n"
+            "  -h\t\t\tHelp (this text)\n"
+            "  -m name\t\tCreate a map file\n"
+            "  -o name\t\tName the default output file\n"
+            "  -t sys\t\tSet the target system\n"
+            "  -u sym\t\tForce an import of symbol `sym'\n"
+            "  -v\t\t\tVerbose mode\n"
+            "  -vm\t\t\tVerbose map file\n"
+            "\n"
+            "Long options:\n"
+            "  --cfg-path path\tSpecify a config file search path\n"
+            "  --config name\t\tUse linker config file\n"
+            "  --dbgfile name\tGenerate debug information\n"
+            "  --define sym=val\tDefine a symbol\n"
+            "  --dump-config name\tDump a builtin configuration\n"
+            "  --end-group\t\tEnd a library group\n"
+            "  --force-import sym\tForce an import of symbol `sym'\n"
+            "  --help\t\tHelp (this text)\n"
+            "  --lib file\t\tLink this library\n"
+            "  --lib-path path\tSpecify a library search path\n"
+            "  --mapfile name\tCreate a map file\n"
+            "  --module-id id\tSpecify a module id\n"
+            "  --obj file\t\tLink this object file\n"
+            "  --obj-path path\tSpecify an object file search path\n"
+            "  --start-addr addr\tSet the default start address\n"
+            "  --start-group\t\tStart a library group\n"
+            "  --target sys\t\tSet the target system\n"
+            "  --version\t\tPrint the linker version\n",
+            ProgName);
 }
 
 
@@ -168,11 +177,11 @@ static void LinkFile (const char* Name, FILETYPE Type)
     switch (Type) {
 
         case FILETYPE_LIB:
-            PathName = SearchFile (Name, SEARCH_LIB);
+            PathName = SearchFile (LibSearchPath, Name);
             break;
 
         case FILETYPE_OBJ:
-            PathName = SearchFile (Name, SEARCH_OBJ);
+            PathName = SearchFile (ObjSearchPath, Name);
             break;
 
         default:
@@ -224,10 +233,56 @@ static void LinkFile (const char* Name, FILETYPE Type)
 
 
 
+static void DefineSymbol (const char* Def)
+/* Define a symbol from the command line */
+{
+    const char* P;
+    unsigned I;
+    long Val;
+    StrBuf SymName = AUTO_STRBUF_INITIALIZER;
+
+
+    /* The symbol must start with a character or underline */
+    if (Def [0] != '_' && !IsAlpha (Def [0])) {
+       InvDef (Def);
+    }
+    P = Def;
+
+    /* Copy the symbol, checking the remainder */
+    I = 0;
+    while (IsAlNum (*P) || *P == '_') {
+        SB_AppendChar (&SymName, *P++);
+    }
+    SB_Terminate (&SymName);
+
+    /* Do we have a value given? */
+    if (*P != '=') {
+        InvDef (Def);
+    } else {
+       /* We have a value */
+       ++P;
+       if (*P == '$') {
+           ++P;
+           if (sscanf (P, "%lx", &Val) != 1) {
+               InvDef (Def);
+           }
+       } else {
+           if (sscanf (P, "%li", &Val) != 1) {
+               InvDef (Def);
+           }
+               }
+    }
+
+    /* Define the new symbol */
+    CreateConstExport (GetStringId (SB_GetConstBuf (&SymName)), Val);
+}
+
+
+
 static void OptCfgPath (const char* Opt attribute ((unused)), const char* Arg)
 /* Specify a config file search path */
 {
-    AddSearchPath (Arg, SEARCH_CFG);
+    AddSearchPath (CfgSearchPath, Arg);
 }
 
 
@@ -241,7 +296,7 @@ static void OptConfig (const char* Opt attribute ((unused)), const char* Arg)
        Error ("Cannot use -C/-t twice");
     }
     /* Search for the file */
-    PathName = SearchFile (Arg, SEARCH_CFG);
+    PathName = SearchFile (CfgSearchPath, Arg);
     if (PathName == 0) {
         Error ("Cannot find config file `%s'", Arg);
     } else {
@@ -259,6 +314,14 @@ static void OptDbgFile (const char* Opt attribute ((unused)), const char* Arg)
 
 
 
+static void OptDefine (const char* Opt attribute ((unused)), const char* Arg)
+/* Define a symbol on the command line */
+{
+    DefineSymbol (Arg);
+}
+
+
+
 static void OptDumpConfig (const char* Opt attribute ((unused)), const char* Arg)
 /* Dump a builtin linker configuration */
 {
@@ -274,6 +337,53 @@ static void OptDumpConfig (const char* Opt attribute ((unused)), const char* Arg
 
 
 
+static void OptEndGroup (const char* Opt attribute ((unused)),
+                        const char* Arg attribute ((unused)))
+/* End a library group */
+{
+    LibEndGroup ();
+}
+
+
+
+static void OptForceImport (const char* Opt attribute ((unused)), const char* Arg)
+/* Force an import of a symbol */
+{
+    /* An optional address size may be specified */
+    const char* ColPos = strchr (Arg, ':');
+    if (ColPos == 0) {
+
+        /* Use default address size (which for now is always absolute
+         * addressing)
+         */
+        InsertImport (GenImport (Arg, ADDR_SIZE_ABS));
+
+    } else {
+
+        char* A;
+
+        /* Get the address size and check it */
+        unsigned char AddrSize = AddrSizeFromStr (ColPos+1);
+        if (AddrSize == ADDR_SIZE_INVALID) {
+            Error ("Invalid address size `%s'", ColPos+1);
+        }
+
+        /* Create a copy of the argument */
+        A = xstrdup (Arg);
+
+        /* We need just the symbol */
+        A[ColPos - Arg] = '\0';
+
+        /* Generate the import */
+        InsertImport (GenImport (A, AddrSize));
+
+        /* Delete the copy of the argument */
+        xfree (A);
+    }
+}
+
+
+
 static void OptHelp (const char* Opt attribute ((unused)),
                     const char* Arg attribute ((unused)))
 /* Print usage information and exit */
@@ -295,7 +405,7 @@ static void OptLib (const char* Opt attribute ((unused)), const char* Arg)
 static void OptLibPath (const char* Opt attribute ((unused)), const char* Arg)
 /* Specify a library file search path */
 {
-    AddSearchPath (Arg, SEARCH_LIB);
+    AddSearchPath (LibSearchPath, Arg);
 }
 
 
@@ -331,7 +441,7 @@ static void OptObj (const char* Opt attribute ((unused)), const char* Arg)
 static void OptObjPath (const char* Opt attribute ((unused)), const char* Arg)
 /* Specify an object file search path */
 {
-    AddSearchPath (Arg, SEARCH_OBJ);
+    AddSearchPath (ObjSearchPath, Arg);
 }
 
 
@@ -345,6 +455,15 @@ static void OptStartAddr (const char* Opt, const char* Arg)
 
 
 
+static void OptStartGroup (const char* Opt attribute ((unused)),
+                          const char* Arg attribute ((unused)))
+/* Start a library group */
+{
+    LibStartGroup ();
+}
+
+
+
 static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
 /* Set the target system */
 {
@@ -371,8 +490,8 @@ static void OptVersion (const char* Opt attribute ((unused)),
 /* Print the assembler version */
 {
     fprintf (stderr,
-                    "ld65 V%u.%u.%u - (C) Copyright 1998-2002 Ullrich von Bassewitz\n",
-            VER_MAJOR, VER_MINOR, VER_PATCH);
+                    "ld65 V%s - (C) Copyright 1998-2009, Ullrich von Bassewitz\n",
+            GetVersionAsString ());
 }
 
 
@@ -385,7 +504,10 @@ int main (int argc, char* argv [])
                { "--cfg-path",         1,      OptCfgPath              },
                { "--config",           1,      OptConfig               },
        { "--dbgfile",          1,      OptDbgFile              },
+        { "--define",           1,      OptDefine               },
                { "--dump-config",      1,      OptDumpConfig           },
+        { "--end-group",        0,      OptEndGroup             },
+        { "--force-import",     1,      OptForceImport          },
        { "--help",             0,      OptHelp                 },
         { "--lib",              1,      OptLib                  },
                { "--lib-path",         1,      OptLibPath              },
@@ -394,11 +516,13 @@ int main (int argc, char* argv [])
         { "--obj",              1,      OptObj                  },
                { "--obj-path",         1,      OptObjPath              },
        { "--start-addr",       1,      OptStartAddr            },
+        { "--start-group",      0,      OptStartGroup           },
        { "--target",           1,      OptTarget               },
        { "--version",          0,      OptVersion              },
     };
 
     unsigned I;
+    unsigned MemoryAreaOverflows;
 
     /* Initialize the cmdline module */
     InitCmdLine (&argc, &argv, "ld65");
@@ -426,6 +550,14 @@ int main (int argc, char* argv [])
                    LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
                    break;
 
+                case '(':
+                    OptStartGroup (Arg, 0);
+                    break;
+
+                case ')':
+                    OptEndGroup (Arg, 0);
+                    break;
+
                case 'h':
                case '?':
                    OptHelp (Arg, 0);
@@ -441,16 +573,20 @@ int main (int argc, char* argv [])
 
                case 't':
                    if (CfgAvail ()) {
-                       Error ("Cannot use -C/-t twice");
+                       Error ("Cannot use -C/-t twice");
                    }
                    OptTarget (Arg, GetArg (&I, 2));
                    break;
 
+                case 'u':
+                    OptForceImport (Arg, GetArg (&I, 2));
+                    break;
+
                case 'v':
                    switch (Arg [2]) {
-                       case 'm':   VerboseMap = 1;     break;
-                       case '\0':  ++Verbosity;        break;
-                       default:    UnknownOption (Arg);
+                       case 'm':   VerboseMap = 1;     break;
+                       case '\0':  ++Verbosity;        break;
+                       default:    UnknownOption (Arg);
                    }
                    break;
 
@@ -458,11 +594,15 @@ int main (int argc, char* argv [])
                    OptConfig (Arg, GetArg (&I, 2));
                    break;
 
-               case 'L':
+                case 'D':
+                    OptDefine (Arg, GetArg (&I, 2));
+                    break;
+
+               case 'L':
                    switch (Arg [2]) {
                         /* ## The first one is obsolete and will go */
-                       case 'n': LabelFileName = GetArg (&I, 3);   break;
-                       default:  OptLibPath (Arg, GetArg (&I, 2)); break;
+                       case 'n': LabelFileName = GetArg (&I, 3);   break;
+                       default:  OptLibPath (Arg, GetArg (&I, 2)); break;
                    }
                    break;
 
@@ -500,14 +640,20 @@ int main (int argc, char* argv [])
                Error ("Memory configuration missing");
     }
 
+    /* Check if we have open library groups */
+    LibCheckGroup ();
+
     /* Read the config file */
     CfgRead ();
 
     /* Create the condes tables if requested */
     ConDesCreate ();
 
-    /* Assign start addresses for the segments, define linker symbols */
-    CfgAssignSegments ();
+    /* Assign start addresses for the segments, define linker symbols. The
+     * function will return the number of memory area overflows (zero on
+     * success).
+     */
+    MemoryAreaOverflows = CfgAssignSegments ();
 
     /* Check module assertions */
     CheckAssertions ();
@@ -515,6 +661,18 @@ int main (int argc, char* argv [])
     /* Check for import/export mismatches */
     CheckExports ();
 
+    /* If we had a memory area overflow before, we cannot generate the output
+     * file. However, we will generate a short map file if requested, since
+     * this will help the user to rearrange segments and fix the overflow.
+     */
+    if (MemoryAreaOverflows) {
+        if (MapFileName) {
+            CreateMapFile (SHORT_MAPFILE);
+        }
+        Error ("Cannot generate output due to memory area overflow%s",
+               (MemoryAreaOverflows > 1)? "s" : "");
+    }
+
     /* Create the output file */
     CfgWriteTarget ();
 
@@ -523,7 +681,7 @@ int main (int argc, char* argv [])
 
     /* If requested, create a map file and a label file for VICE */
     if (MapFileName) {
-       CreateMapFile ();
+       CreateMapFile (LONG_MAPFILE);
     }
     if (LabelFileName) {
        CreateLabelFile ();