X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fld65%2Fmain.c;h=94a2101b33b61788b5bf382ca632198f3d8cbb63;hb=5a05acf9366e4c1eef73fd4387afc45f6a6cebef;hp=63ab842a493f7bff7e50dba80fcee314f00dd085;hpb=39b380b6e6f50f755b3c6d90de7269fa5b6662c8;p=cc65 diff --git a/src/ld65/main.c b/src/ld65/main.c index 63ab842a4..94a2101b3 100644 --- a/src/ld65/main.c +++ b/src/ld65/main.c @@ -1,34 +1,34 @@ /*****************************************************************************/ -/* */ -/* main.c */ -/* */ -/* Main program for the ld65 linker */ -/* */ -/* */ -/* */ -/* (C) 1998-2000 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ -/* */ -/* */ -/* This software is provided 'as-is', without any expressed or implied */ +/* */ +/* main.c */ +/* */ +/* Main program for the ld65 linker */ +/* */ +/* */ +/* */ +/* (C) 1998-2013, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ /* warranty. In no event will the authors be held liable for any damages */ -/* arising from the use of this software. */ -/* */ +/* arising from the use of this software. */ +/* */ /* Permission is granted to anyone to use this software for any purpose, */ /* including commercial applications, and to alter it and redistribute it */ -/* freely, subject to the following restrictions: */ -/* */ +/* freely, subject to the following restrictions: */ +/* */ /* 1. The origin of this software must not be misrepresented; you must not */ /* claim that you wrote the original software. If you use this software */ /* in a product, an acknowledgment in the product documentation would be */ -/* appreciated but is not required. */ +/* appreciated but is not required. */ /* 2. Altered source versions must be plainly marked as such, and must not */ -/* be misrepresented as being the original software. */ -/* 3. This notice may not be removed or altered from any source */ -/* distribution. */ -/* */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ /*****************************************************************************/ @@ -39,44 +39,69 @@ #include /* common */ +#include "addrsize.h" +#include "chartype.h" #include "cmdline.h" +#include "filetype.h" #include "libdefs.h" #include "objdefs.h" +#include "print.h" #include "target.h" #include "version.h" #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 "tgtcfg.h" +#include "spool.h" +#include "tpool.h" /*****************************************************************************/ -/* Data */ +/* Data */ /*****************************************************************************/ -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 */ +static unsigned ObjFiles = 0; /* Count of object files linked */ +static unsigned LibFiles = 0; /* Count of library files linked */ + +/* struct InputFile.Type definitions */ +#define INPUT_FILES_FILE 0 /* Entry is a file (unknown type) */ +#define INPUT_FILES_FILE_OBJ 1 /* Entry is a object file */ +#define INPUT_FILES_FILE_LIB 2 /* Entry is a library file */ +#define INPUT_FILES_SGROUP 3 /* Entry is 'StartGroup' */ +#define INPUT_FILES_EGROUP 4 /* Entry is 'EndGroup' */ + +#define MAX_INPUTFILES 256 + +/* Array of inputs (libraries and object files) */ +static struct InputFile { + const char *FileName; + unsigned Type; +} *InputFiles; +static unsigned InputFilesCount = 0; +static const char *CmdlineCfgFile = NULL, + *CmdlineTarget = NULL; /*****************************************************************************/ -/* Code */ +/* Code */ /*****************************************************************************/ @@ -84,51 +109,67 @@ 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" - " -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" - " -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" - "\n" - "Long options:\n" - " --help\t\tHelp (this text)\n" - " --mapfile name\tCreate a map file\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" + " --allow-multiple-definition\tAllow multiple definitions\n" + " --cfg-path path\t\tSpecify a config file search path\n" + " --config name\t\t\tUse linker config file\n" + " --dbgfile name\t\tGenerate debug information\n" + " --define sym=val\t\tDefine a symbol\n" + " --end-group\t\t\tEnd a library group\n" + " --force-import sym\t\tForce an import of symbol 'sym'\n" + " --help\t\t\tHelp (this text)\n" + " --lib file\t\t\tLink this library\n" + " --lib-path path\t\tSpecify a library search path\n" + " --mapfile name\t\tCreate a map file\n" + " --module-id id\t\tSpecify a module id\n" + " --obj file\t\t\tLink this object file\n" + " --obj-path path\t\tSpecify an object file search path\n" + " --start-addr addr\t\tSet the default start address\n" + " --start-group\t\t\tStart a library group\n" + " --target sys\t\t\tSet the target system\n" + " --version\t\t\tPrint the linker version\n", + ProgName); } static unsigned long CvtNumber (const char* Arg, const char* Number) /* Convert a number from a string. Allow '$' and '0x' prefixes for hex - * numbers. - */ +** numbers. +*/ { unsigned long Val; - int Converted; + int Converted; /* Convert */ if (*Number == '$') { - ++Number; - Converted = sscanf (Number, "%lx", &Val); + ++Number; + Converted = sscanf (Number, "%lx", &Val); } else { - Converted = sscanf (Number, "%li", (long*)&Val); + Converted = sscanf (Number, "%li", (long*)&Val); } /* Check if we do really have a number */ if (Converted != 1) { - Error ("Invalid number given in argument: %s\n", Arg); + Error ("Invalid number given in argument: %s\n", Arg); } /* Return the result */ @@ -137,94 +178,226 @@ 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) { + + case FILETYPE_LIB: + PathName = SearchFile (LibSearchPath, Name); + if (PathName == 0) { + PathName = SearchFile (LibDefaultPath, Name); + } + break; + + case FILETYPE_OBJ: + PathName = SearchFile (ObjSearchPath, Name); + if (PathName == 0) { + PathName = SearchFile (ObjDefaultPath, Name); + } + break; + + 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 */ - FILE* F = fopen (Name, "rb"); + F = fopen (PathName, "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); - - /* Now try to open the new file */ - F = fopen (NewName, "rb"); - } - - if (F == 0) { - Error ("Cannot open `%s': %s", Name, strerror (errno)); - } + 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, PathName); + ++LibFiles; + break; + + default: + fclose (F); + Error ("File '%s' has unknown type", PathName); + + } + + /* Free allocated memory. */ + xfree (PathName); +} + - case LIB_MAGIC: - LibAdd (F, Name); - ++LibFiles; - break; - default: - fclose (F); - Error ("File `%s' has unknown type", Name); +static void DefineSymbol (const char* Def) +/* Define a symbol from the command line */ +{ + const char* P; + 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 */ + 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); + } + } } - /* 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); + /* 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); } -static void OptConfig (const char* Opt, const char* Arg) +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"); + Error ("Cannot use -C/-t twice"); + } + /* Search for the file */ + PathName = SearchFile (CfgSearchPath, Arg); + if (PathName == 0) { + PathName = SearchFile (CfgDefaultPath, Arg); + } + if (PathName == 0) { + Error ("Cannot find config file '%s'", Arg); } - CfgSetName (Arg); + + /* Read the config */ + CfgSetName (PathName); + CfgRead (); } -static void OptHelp (const char* Opt, const char* Arg) +static void OptDbgFile (const char* Opt attribute ((unused)), const char* Arg) +/* Give the name of the debug file */ +{ + DbgFileName = Arg; +} + + + +static void OptDefine (const char* Opt attribute ((unused)), const char* Arg) +/* Define a symbol on the command line */ +{ + DefineSymbol (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 (GetStringId (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 (GetStringId (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 */ { Usage (); @@ -233,179 +406,434 @@ static void OptHelp (const char* Opt, const char* Arg) -static void OptMapFile (const char* Opt, const char* Arg) +static void OptLib (const char* Opt attribute ((unused)), const char* Arg) +/* Link a library */ +{ + InputFiles[InputFilesCount].Type = INPUT_FILES_FILE_LIB; + InputFiles[InputFilesCount].FileName = Arg; + if (++InputFilesCount >= MAX_INPUTFILES) + Error ("Too many input files"); +} + + + +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 */ { + if (MapFileName) { + Error ("Cannot use -m twice"); + } MapFileName = Arg; } +static void OptModuleId (const char* Opt, const char* Arg) +/* Specify a module id */ +{ + unsigned long Id = CvtNumber (Opt, Arg); + if (Id > 0xFFFFUL) { + Error ("Range error in module id"); + } + ModuleId = (unsigned) Id; +} + + + +static void OptObj (const char* Opt attribute ((unused)), const char* Arg) +/* Link an object file */ +{ + InputFiles[InputFilesCount].Type = INPUT_FILES_FILE_OBJ; + InputFiles[InputFilesCount].FileName = Arg; + if (++InputFilesCount >= MAX_INPUTFILES) + Error ("Too many input files"); +} + + + +static void OptObjPath (const char* Opt attribute ((unused)), const char* Arg) +/* Specify an object file search path */ +{ + AddSearchPath (ObjSearchPath, Arg); +} + + + +static void OptOutputName (const char* Opt attribute ((unused)), const char* Arg) +/* Give the name of the output file */ +{ + static int OutputNameSeen = 0; + if (OutputNameSeen) { + Error ("Cannot use -o twice"); + } + OutputNameSeen = 1; + OutputName = Arg; +} + + + static void OptStartAddr (const char* Opt, const char* Arg) /* Set the default start address */ { + if (HaveStartAddr) { + Error ("Cannot use -S twice"); + } StartAddr = CvtNumber (Opt, Arg); + HaveStartAddr = 1; +} + + + +static void OptStartGroup (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Start a library group */ +{ + LibStartGroup (); } -static void OptTarget (const char* Opt, const char* Arg) +static void OptTarget (const char* Opt attribute ((unused)), const char* Arg) /* Set the target system */ { - const TargetDesc* D; + StrBuf FileName = STATIC_STRBUF_INITIALIZER; + char* PathName; /* Map the target name to a target id */ Target = FindTarget (Arg); if (Target == TGT_UNKNOWN) { - Error ("Invalid target name: `%s'", Arg); + Error ("Invalid target name: '%s'", Arg); + } + + /* Set the target binary format */ + DefaultBinFmt = GetTargetProperties (Target)->BinFmt; + + /* Build config file name from target name */ + SB_CopyStr (&FileName, GetTargetName (Target)); + SB_AppendStr (&FileName, ".cfg"); + SB_Terminate (&FileName); + + /* Search for the file */ + PathName = SearchFile (CfgSearchPath, SB_GetBuf (&FileName)); + if (PathName == 0) { + PathName = SearchFile (CfgDefaultPath, SB_GetBuf (&FileName)); + } + if (PathName == 0) { + Error ("Cannot find config file '%s'", SB_GetBuf (&FileName)); } - /* Get the target description record */ - D = &Targets[Target]; + /* Free file name memory */ + SB_Done (&FileName); - /* Set the target data */ - DefaultBinFmt = D->BinFmt; - CfgSetBuf (D->Cfg); + /* Read the file */ + CfgSetName (PathName); + CfgRead (); } -static void OptVersion (const char* Opt, const char* Arg) +static void OptVersion (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) /* Print the assembler version */ { - fprintf (stderr, - "ld65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n", - VER_MAJOR, VER_MINOR, VER_PATCH); + fprintf (stderr, "%s V%s\n", ProgName, GetVersionAsString ()); + exit(EXIT_SUCCESS); } -int main (int argc, char* argv []) -/* Assembler main program */ +static void OptMultDef (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Print the assembler version */ { - /* Program long options */ - static const LongOpt OptTab[] = { - { "--config", 1, OptConfig }, - { "--help", 0, OptHelp }, - { "--mapfile", 1, OptMapFile }, - { "--start-addr", 1, OptStartAddr }, - { "--target", 1, OptTarget }, - { "--version", 0, OptVersion }, - }; + AllowMultDef = 1; +} - int I; - /* 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 +static void CmdlOptStartGroup (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Remember 'start group' occurrence in input files array */ +{ + InputFiles[InputFilesCount].Type = INPUT_FILES_SGROUP; + InputFiles[InputFilesCount].FileName = Arg; /* Unused */ + if (++InputFilesCount >= MAX_INPUTFILES) + Error ("Too many input files"); +} + + + +static void CmdlOptEndGroup (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Remember 'end group' occurrence in input files array */ +{ + InputFiles[InputFilesCount].Type = INPUT_FILES_EGROUP; + InputFiles[InputFilesCount].FileName = Arg; /* Unused */ + if (++InputFilesCount >= MAX_INPUTFILES) + Error ("Too many input files"); +} + + + +static void CmdlOptConfig (const char* Opt attribute ((unused)), const char* Arg) +/* Set 'config file' command line parameter */ +{ + if (CmdlineCfgFile || CmdlineTarget) { + Error ("Cannot use -C/-t twice"); } - LibPathLen = strlen (LibPath); + CmdlineCfgFile = Arg; +} - /* Check the parameters */ - I = 1; - while (I < argc) { - /* Get the argument */ - const char* Arg = argv [I]; - /* Check for an option */ - if (Arg [0] == '-') { +static void CmdlOptTarget (const char* Opt attribute ((unused)), const char* Arg) +/* Set 'target' command line parameter */ +{ + if (CmdlineCfgFile || CmdlineTarget) { + Error ("Cannot use -C/-t twice"); + } + CmdlineTarget = Arg; +} - /* An option */ - switch (Arg [1]) { - case '-': - LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0])); - break; - case 'h': - case '?': - OptHelp (Arg, 0); - break; +static void ParseCommandLine(void) +{ + /* Program long options */ + static const LongOpt OptTab[] = { + { "--allow-multiple-definition", 0, OptMultDef }, + { "--cfg-path", 1, OptCfgPath }, + { "--config", 1, CmdlOptConfig }, + { "--dbgfile", 1, OptDbgFile }, + { "--define", 1, OptDefine }, + { "--end-group", 0, CmdlOptEndGroup }, + { "--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, CmdlOptStartGroup }, + { "--target", 1, CmdlOptTarget }, + { "--version", 0, OptVersion }, + }; - case 'm': - OptMapFile (Arg, GetArg (&I, 2)); - break; + unsigned I; + unsigned LabelFileGiven = 0; - case 'o': - OutputName = GetArg (&I, 2); - break; + /* Allocate memory for input file array */ + InputFiles = xmalloc (MAX_INPUTFILES * sizeof (struct InputFile)); - case 't': - if (CfgAvail ()) { - Error ("Cannot use -C/-t twice"); - } - OptTarget (Arg, GetArg (&I, 2)); - break; + /* Defer setting of config/target and input files until all options are parsed */ + I = 1; + while (I < ArgCount) { + + /* Get the argument */ + const char* Arg = ArgVec[I]; + + /* Check for an option */ + if (Arg [0] == '-') { + + /* An option */ + switch (Arg [1]) { + + case '-': + LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0])); + break; + + case '(': + CmdlOptStartGroup (Arg, 0); + break; + + case ')': + CmdlOptEndGroup (Arg, 0); + break; + + case 'h': + case '?': + OptHelp (Arg, 0); + break; + + case 'm': + OptMapFile (Arg, GetArg (&I, 2)); + break; + + case 'o': + OptOutputName (NULL, GetArg (&I, 2)); + break; + + case 't': + CmdlOptTarget (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); + } + break; + + case 'C': + CmdlOptConfig (Arg, GetArg (&I, 2)); + break; + + case 'D': + OptDefine (Arg, GetArg (&I, 2)); + break; + + case 'L': + switch (Arg [2]) { + case 'n': + /* ## This one is obsolete and will go */ + if (LabelFileGiven) { + Error ("Cannot use -Ln twice"); + } + LabelFileGiven = 1; + LabelFileName = GetArg (&I, 3); + break; + default: + OptLibPath (Arg, GetArg (&I, 2)); + break; + } + break; + + case 'S': + OptStartAddr (Arg, GetArg (&I, 2)); + break; + + case 'V': + OptVersion (Arg, 0); + break; + + default: + UnknownOption (Arg); + break; + } + + } else { + + /* A filename */ + InputFiles[InputFilesCount].Type = INPUT_FILES_FILE; + InputFiles[InputFilesCount].FileName = Arg; + if (++InputFilesCount >= MAX_INPUTFILES) + Error ("Too many input files"); + + } + + /* Next argument */ + ++I; + } - case 'v': - switch (Arg [2]) { - case 'm': VerboseMap = 1; break; - case '\0': ++Verbose; break; - default: UnknownOption (Arg); - } - break; + if (CmdlineTarget) { + OptTarget (NULL, CmdlineTarget); + } else if (CmdlineCfgFile) { + OptConfig (NULL, CmdlineCfgFile); + } - case 'C': - OptConfig (Arg, GetArg (&I, 2)); - break; + /* Process input files */ + for (I = 0; I < InputFilesCount; ++I) { + switch (InputFiles[I].Type) { + case INPUT_FILES_FILE: + LinkFile (InputFiles[I].FileName, FILETYPE_UNKNOWN); + break; + case INPUT_FILES_FILE_LIB: + LinkFile (InputFiles[I].FileName, FILETYPE_LIB); + break; + case INPUT_FILES_FILE_OBJ: + LinkFile (InputFiles[I].FileName, FILETYPE_OBJ); + break; + case INPUT_FILES_SGROUP: + OptStartGroup (NULL, 0); + break; + case INPUT_FILES_EGROUP: + OptEndGroup (NULL, 0); + break; + default: + abort (); + } + } - case 'L': - switch (Arg [2]) { - case 'n': LabelFileName = GetArg (&I, 3); break; - case 'p': WProtSegs = 1; break; - default: UnknownOption (Arg); break; - } - break; + /* Free memory used for input file array */ + xfree (InputFiles); +} - case 'S': - OptStartAddr (Arg, GetArg (&I, 2)); - break; - case 'V': - OptVersion (Arg, 0); - break; - default: - UnknownOption (Arg); - break; - } +int main (int argc, char* argv []) +/* Linker main program */ +{ + unsigned MemoryAreaOverflows; - } else { + /* Initialize the cmdline module */ + InitCmdLine (&argc, &argv, "ld65"); - /* A filename */ - LinkFile (Arg); + /* Initialize the input file search paths */ + InitSearchPaths (); - } + /* Initialize the string pool */ + InitStrPool (); - /* Next argument */ - ++I; - } + /* Initialize the type pool */ + InitTypePool (); + + /* Parse the command line */ + ParseCommandLine (); /* Check if we had any object files */ if (ObjFiles == 0) { - Error ("No object files to link"); + Error ("No object files to link"); } /* Check if we have a valid configuration */ if (!CfgAvail ()) { - Error ("Memory configuration missing"); + Error ("Memory configuration missing"); } - /* Read the config file */ - CfgRead (); - - /* Assign start addresses for the segments, define linker symbols */ - CfgAssignSegments (); + /* Check if we have open library groups */ + LibCheckGroup (); + + /* Create the condes tables if requested */ + ConDesCreate (); + + /* Process data from the config file. Assign start addresses for the + ** segments, define linker symbols. The function will return the number + ** of memory area overflows (zero on success). + */ + MemoryAreaOverflows = CfgProcess (); + + /* 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 most of the files due to memory area overflow%c", + (MemoryAreaOverflows > 1) ? 's' : ' '); + } /* Create the output file */ CfgWriteTarget (); @@ -415,21 +843,21 @@ 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 (); + CreateLabelFile (); + } + if (DbgFileName) { + CreateDbgFile (); } /* Dump the data for debugging */ - if (Verbose > 1) { - SegDump (); + if (Verbosity > 1) { + SegDump (); + ConDesDump (); } /* Return an apropriate exit code */ return EXIT_SUCCESS; } - - - -