X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fld65%2Fmain.c;h=10fff402e6c05a0d484397405ca2996453822e1f;hb=0807da74bd7c3ebe3e6e75129a07a810b17174b2;hp=528c7c095d1ae5159acf87ea13cfc119e0ff0d0e;hpb=df5132d31c0e3b3cf49460d230870863c10d39d9;p=cc65 diff --git a/src/ld65/main.c b/src/ld65/main.c index 528c7c095..10fff402e 100644 --- a/src/ld65/main.c +++ b/src/ld65/main.c @@ -1,15 +1,15 @@ /*****************************************************************************/ -/* */ -/* main.c */ -/* */ +/* */ +/* main.c */ +/* */ /* Main program for the ld65 linker */ -/* */ -/* */ -/* */ -/* (C) 1998-2002 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* */ +/* (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,7 +39,10 @@ #include /* common */ +#include "addrsize.h" +#include "chartype.h" #include "cmdline.h" +#include "filetype.h" #include "libdefs.h" #include "objdefs.h" #include "print.h" @@ -48,18 +51,22 @@ #include "xmalloc.h" /* ld65 */ +#include "asserts.h" #include "binfmt.h" #include "condes.h" #include "config.h" +#include "dbgfile.h" #include "error.h" #include "exports.h" #include "fileio.h" +#include "filepath.h" #include "global.h" #include "library.h" #include "mapfile.h" #include "objfile.h" #include "scanner.h" #include "segments.h" +#include "spool.h" #include "tgtcfg.h" @@ -72,8 +79,6 @@ static unsigned ObjFiles = 0; /* Count of object files linked */ static unsigned LibFiles = 0; /* Count of library files linked */ -static const char* LibPath = 0; /* Search path for modules */ -static unsigned LibPathLen = 0; /* Length of LibPath */ @@ -86,30 +91,44 @@ static unsigned LibPathLen = 0; /* Length of LibPath */ 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" - " -Ln name\t\tCreate a VICE label file\n" - " -Lp\t\t\tMark write protected segments as such (VICE)\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" - " --config name\tUse linker config file\n" - " --help\t\tHelp (this text)\n" - " --mapfile name\tCreate a map file\n" - " --module-id id\tSpecify a module id\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); } @@ -141,78 +160,129 @@ static unsigned long CvtNumber (const char* Arg, const char* Number) -static int HasPath (const char* Name) -/* Check if the given Name has a path component */ +static void LinkFile (const char* Name, FILETYPE Type) +/* Handle one file */ { - return strchr (Name, '/') != 0 || strchr (Name, '\\') != 0; -} + char* PathName; + FILE* F; + unsigned long Magic; + /* If we don't know the file type, determine it from the extension */ + if (Type == FILETYPE_UNKNOWN) { + Type = GetFileType (Name); + } -static void LinkFile (const char* Name) -/* Handle one file */ -{ - unsigned long Magic; - unsigned Len; - char* NewName = 0; + /* For known file types, search the file in the directory list */ + switch (Type) { - /* Try to open the file */ - FILE* F = fopen (Name, "rb"); - if (F == 0) { - /* We couldn't open the file. If the name doesn't have a path, and we - * have a search path given, try the name with the search path - * prepended. - */ - if (LibPathLen > 0 && !HasPath (Name)) { - /* Allocate memory. Account for the trailing zero, and for a - * path separator character eventually needed. - */ - Len = LibPathLen; - NewName = xmalloc (strlen (Name) + Len + 2); - /* Build the new name */ - memcpy (NewName, LibPath, Len); - if (NewName [Len-1] != '/' && NewName [Len-1] != '\\') { - /* We need an additional path separator */ - NewName [Len++] = '/'; - } - strcpy (NewName + Len, Name); + case FILETYPE_LIB: + PathName = SearchFile (LibSearchPath, Name); + break; - /* Now try to open the new file */ - F = fopen (NewName, "rb"); - } + case FILETYPE_OBJ: + PathName = SearchFile (ObjSearchPath, Name); + break; - if (F == 0) { - Error ("Cannot open `%s': %s", Name, strerror (errno)); - } + default: + PathName = xstrdup (Name); /* Use the name as is */ + break; + } + + /* We must have a valid name now */ + if (PathName == 0) { + Error ("Input file `%s' not found", Name); + } + + /* Try to open the file */ + F = fopen (PathName, "rb"); + if (F == 0) { + Error ("Cannot open `%s': %s", PathName, strerror (errno)); } /* Read the magic word */ Magic = Read32 (F); - /* Do we know this type of file? */ + /* Check the magic for known file types. The handling is somewhat weird + * since we may have given a file with a ".lib" extension, which was + * searched and found in a directory for library files, but we now find + * out (by looking at the magic) that it's indeed an object file. We just + * ignore the problem and hope no one will notice... + */ switch (Magic) { - case OBJ_MAGIC: - ObjAdd (F, Name); - ++ObjFiles; - break; + case OBJ_MAGIC: + ObjAdd (F, PathName); + ++ObjFiles; + break; - case LIB_MAGIC: - LibAdd (F, Name); - ++LibFiles; - break; + case LIB_MAGIC: + LibAdd (F, PathName); + ++LibFiles; + break; - default: + default: fclose (F); - Error ("File `%s' has unknown type", Name); + Error ("File `%s' has unknown type", PathName); } - /* If we have allocated memory, free it here. Note: Memory will not always - * be freed if we run into an error, but that's no problem. Adding more - * code to work around it will use more memory than the chunk that's lost. - */ - xfree (NewName); + /* Free allocated memory. */ + xfree (PathName); +} + + + +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 (CfgSearchPath, Arg); } @@ -220,10 +290,18 @@ static void LinkFile (const char* Name) static void OptConfig (const char* Opt attribute ((unused)), const char* Arg) /* Define the config file */ { + char* PathName; + if (CfgAvail ()) { Error ("Cannot use -C/-t twice"); } - CfgSetName (Arg); + /* Search for the file */ + PathName = SearchFile (CfgSearchPath, Arg); + if (PathName == 0) { + Error ("Cannot find config file `%s'", Arg); + } else { + CfgSetName (PathName); + } } @@ -236,6 +314,76 @@ 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 */ +{ + /* Map the given target name to its id */ + target_t T = FindTarget (Arg); + if (T == TGT_UNKNOWN) { + Error ("Target system `%s' is unknown", Arg); + } + + /* Dump the builtin configuration */ + DumpBuiltinConfig (stdout, T); +} + + + +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 */ @@ -246,6 +394,22 @@ static void OptHelp (const char* Opt attribute ((unused)), +static void OptLib (const char* Opt attribute ((unused)), const char* Arg) +/* Link a library */ +{ + LinkFile (Arg, FILETYPE_LIB); +} + + + +static void OptLibPath (const char* Opt attribute ((unused)), const char* Arg) +/* Specify a library file search path */ +{ + AddSearchPath (LibSearchPath, Arg); +} + + + static void OptMapFile (const char* Opt attribute ((unused)), const char* Arg) /* Give the name of the map file */ { @@ -266,6 +430,22 @@ static void OptModuleId (const char* Opt, const char* Arg) +static void OptObj (const char* Opt attribute ((unused)), const char* Arg) +/* Link an object file */ +{ + LinkFile (Arg, FILETYPE_OBJ); +} + + + +static void OptObjPath (const char* Opt attribute ((unused)), const char* Arg) +/* Specify an object file search path */ +{ + AddSearchPath (ObjSearchPath, Arg); +} + + + static void OptStartAddr (const char* Opt, const char* Arg) /* Set the default start address */ { @@ -275,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 */ { @@ -301,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 ()); } @@ -312,32 +501,37 @@ int main (int argc, char* argv []) { /* Program long options */ static const LongOpt OptTab[] = { + { "--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 }, { "--mapfile", 1, OptMapFile }, { "--module-id", 1, OptModuleId }, + { "--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"); - /* Evaluate the CC65_LIB environment variable */ - LibPath = getenv ("CC65_LIB"); - if (LibPath == 0) { - /* Use some default path */ -#ifdef CC65_LIB - LibPath = CC65_LIB; -#else - LibPath = "/usr/lib/cc65/lib/"; -#endif - } - LibPathLen = strlen (LibPath); + /* Initialize the input file search paths */ + InitSearchPaths (); + + /* Initialize the string pool */ + InitStrPool (); /* Check the parameters */ I = 1; @@ -356,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); @@ -371,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; @@ -388,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]) { - case 'n': LabelFileName = GetArg (&I, 3); break; - case 'p': WProtSegs = 1; break; - default: UnknownOption (Arg); break; + /* ## The first one is obsolete and will go */ + case 'n': LabelFileName = GetArg (&I, 3); break; + default: OptLibPath (Arg, GetArg (&I, 2)); break; } break; @@ -412,7 +622,7 @@ int main (int argc, char* argv []) } else { /* A filename */ - LinkFile (Arg); + LinkFile (Arg, FILETYPE_UNKNOWN); } @@ -430,14 +640,38 @@ 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 (); + + /* 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 (); @@ -447,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 ();