From: cuz Date: Sat, 8 Feb 2003 16:32:55 +0000 (+0000) Subject: First import X-Git-Tag: V2.12.0~1746 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=bbb70a2d474ade97e81374cf9efe2db9cb43ce32;p=cc65 First import git-svn-id: svn://svn.cc65.org/cc65/trunk@1942 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- diff --git a/src/co65/.cvsignore b/src/co65/.cvsignore new file mode 100644 index 000000000..bc9564328 --- /dev/null +++ b/src/co65/.cvsignore @@ -0,0 +1,2 @@ +.depend +co65 diff --git a/src/co65/error.c b/src/co65/error.c new file mode 100644 index 000000000..da0f8adad --- /dev/null +++ b/src/co65/error.c @@ -0,0 +1,94 @@ +/*****************************************************************************/ +/* */ +/* error.c */ +/* */ +/* Error handling for the co65 object file converter */ +/* */ +/* */ +/* */ +/* (C) 1998-2003 Ullrich von Bassewitz */ +/* Römerstrasse 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. */ +/* */ +/* 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: */ +/* */ +/* 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. */ +/* 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. */ +/* */ +/*****************************************************************************/ + + + +#include +#include +#include + +/* common */ +#include "cmdline.h" + +/* co65 */ +#include "error.h" + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +void Warning (const char* Format, ...) +/* Print a warning message */ +{ + va_list ap; + va_start (ap, Format); + fprintf (stderr, "%s: Warning: ", ProgName); + vfprintf (stderr, Format, ap); + putc ('\n', stderr); + va_end (ap); +} + + + +void Error (const char* Format, ...) +/* Print an error message and die */ +{ + va_list ap; + va_start (ap, Format); + fprintf (stderr, "%s: Error: ", ProgName); + vfprintf (stderr, Format, ap); + putc ('\n', stderr); + va_end (ap); + exit (EXIT_FAILURE); +} + + + +void Internal (const char* Format, ...) +/* Print an internal error message and die */ +{ + va_list ap; + va_start (ap, Format); + fprintf (stderr, "%s: Internal error: ", ProgName); + vfprintf (stderr, Format, ap); + putc ('\n', stderr); + va_end (ap); + exit (EXIT_FAILURE); +} + + + diff --git a/src/co65/error.h b/src/co65/error.h new file mode 100644 index 000000000..9eab1e7ba --- /dev/null +++ b/src/co65/error.h @@ -0,0 +1,68 @@ +/*****************************************************************************/ +/* */ +/* error.h */ +/* */ +/* Error handling for the co65 object file converter */ +/* */ +/* */ +/* */ +/* (C) 1998-2003 Ullrich von Bassewitz */ +/* Römerstrasse 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. */ +/* */ +/* 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: */ +/* */ +/* 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. */ +/* 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. */ +/* */ +/*****************************************************************************/ + + + +#ifndef ERROR_H +#define ERROR_H + + + +/* common */ +#include "attrib.h" + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +void Warning (const char* Format, ...) attribute((format(printf,1,2))); +/* Print a warning message */ + +void Error (const char* Format, ...) attribute((format(printf,1,2))); +/* Print an error message and die */ + +void Internal (const char* Format, ...) attribute((format(printf,1,2))); +/* Print an internal error message and die */ + + + +/* End of error.h */ + +#endif + + + diff --git a/src/co65/fileio.c b/src/co65/fileio.c new file mode 100644 index 000000000..1b0d58c46 --- /dev/null +++ b/src/co65/fileio.c @@ -0,0 +1,108 @@ +/*****************************************************************************/ +/* */ +/* fileio.c */ +/* */ +/* Binary file I/O for the co65 object file converter */ +/* */ +/* */ +/* */ +/* (C) 1998-2003 Ullrich von Bassewitz */ +/* Römerstrasse 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. */ +/* */ +/* 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: */ +/* */ +/* 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. */ +/* 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. */ +/* */ +/*****************************************************************************/ + + + +#include + +/* common */ +#include "xmalloc.h" + +/* ld65 */ +#include "error.h" +#include "fileio.h" + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +unsigned Read8 (FILE* F) +/* Read an 8 bit value from the file */ +{ + int C = getc (F); + if (C == EOF) { + Error ("Read error (file corrupt?)"); + } + return C; +} + + + +unsigned Read16 (FILE* F) +/* Read a 16 bit value from the file */ +{ + unsigned Lo = Read8 (F); + unsigned Hi = Read8 (F); + return (Hi << 8) | Lo; +} + + + +unsigned long Read24 (FILE* F) +/* Read a 24 bit value from the file */ +{ + unsigned long Lo = Read16 (F); + unsigned long Hi = Read8 (F); + return (Hi << 16) | Lo; +} + + + +unsigned long Read32 (FILE* F) +/* Read a 32 bit value from the file */ +{ + unsigned long Lo = Read16 (F); + unsigned long Hi = Read16 (F); + return (Hi << 16) | Lo; +} + + + +void* ReadData (FILE* F, void* Data, unsigned Size) +/* Read data from the file */ +{ + /* Explicitly allow reading zero bytes */ + if (Size > 0) { + if (fread (Data, 1, Size, F) != Size) { + Error ("Read error (file corrupt?)"); + } + } + return Data; +} + + + diff --git a/src/co65/fileio.h b/src/co65/fileio.h new file mode 100644 index 000000000..aedfddbc7 --- /dev/null +++ b/src/co65/fileio.h @@ -0,0 +1,76 @@ +/*****************************************************************************/ +/* */ +/* fileio.h */ +/* */ +/* Binary file I/O for the co65 object file converter */ +/* */ +/* */ +/* */ +/* (C) 1998-2003 Ullrich von Bassewitz */ +/* Römerstrasse 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. */ +/* */ +/* 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: */ +/* */ +/* 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. */ +/* 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. */ +/* */ +/*****************************************************************************/ + + + +#ifndef FILEIO_H +#define FILEIO_H + + + +#include + +/* common */ +#include "filepos.h" + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +unsigned Read8 (FILE* F); +/* Read an 8 bit value from the file */ + +unsigned Read16 (FILE* F); +/* Read a 16 bit value from the file */ + +unsigned long Read24 (FILE* F); +/* Read a 24 bit value from the file */ + +unsigned long Read32 (FILE* F); +/* Read a 32 bit value from the file */ + +void* ReadData (FILE* F, void* Data, unsigned Size); +/* Read data from the file */ + + + +/* End of fileio.h */ + +#endif + + + diff --git a/src/co65/global.c b/src/co65/global.c new file mode 100644 index 000000000..ed65c9c2b --- /dev/null +++ b/src/co65/global.c @@ -0,0 +1,67 @@ +/*****************************************************************************/ +/* */ +/* global.c */ +/* */ +/* Global variables for the co65 object file converter */ +/* */ +/* */ +/* */ +/* (C) 2003 Ullrich von Bassewitz */ +/* Römerstrasse 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. */ +/* */ +/* 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: */ +/* */ +/* 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. */ +/* 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. */ +/* */ +/*****************************************************************************/ + + + +/* common */ +#include "segnames.h" + +/* co65 */ +#include "global.h" + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* File names */ +const char* InFilename = 0; /* Name of input file */ +const char* OutFilename = 0; /* Name of output file */ + +/* Default extensions */ +const char AsmExt[] = ".s"; /* Default assembler extension */ + +/* Segment names */ +const char* CodeSeg = SEGNAME_CODE; /* Name of the code segment */ +const char* DataSeg = SEGNAME_DATA; /* Name of the data segment */ +const char* BssSeg = SEGNAME_BSS; /* Name of the bss segment */ +const char* ZeropageSeg = SEGNAME_ZEROPAGE; /* Name of the zeropage segment */ + +/* Flags */ +unsigned char DebugInfo = 0; /* Enable debug info */ + + + diff --git a/src/co65/global.h b/src/co65/global.h new file mode 100644 index 000000000..634537b7f --- /dev/null +++ b/src/co65/global.h @@ -0,0 +1,70 @@ +/*****************************************************************************/ +/* */ +/* global.h */ +/* */ +/* Global variables for the co65 object file converter */ +/* */ +/* */ +/* */ +/* (C) 2003 Ullrich von Bassewitz */ +/* Römerstrasse 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. */ +/* */ +/* 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: */ +/* */ +/* 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. */ +/* 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. */ +/* */ +/*****************************************************************************/ + + + +#ifndef GLOBAL_H +#define GLOBAL_H + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* File names */ +extern const char* InFilename; /* Name of input file */ +extern const char* OutFilename; /* Name of output file */ + +/* Default extensions */ +extern const char AsmExt[]; /* Default assembler extension */ + +/* Segment names */ +extern const char* CodeSeg; /* Name of the code segment */ +extern const char* DataSeg; /* Name of the data segment */ +extern const char* BssSeg; /* Name of the bss segment */ +extern const char* ZeropageSeg; /* Name of the zeropage segment */ + +/* Flags */ +extern unsigned char DebugInfo; /* Enable debug info */ + + + +/* End of global.h */ + +#endif + + + diff --git a/src/co65/main.c b/src/co65/main.c new file mode 100644 index 000000000..a206f56d5 --- /dev/null +++ b/src/co65/main.c @@ -0,0 +1,490 @@ +/*****************************************************************************/ +/* */ +/* main.c */ +/* */ +/* Main program for the co65 object file converter */ +/* */ +/* */ +/* */ +/* (C) 2003 Ullrich von Bassewitz */ +/* Römerstrasse 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. */ +/* */ +/* 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: */ +/* */ +/* 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. */ +/* 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. */ +/* */ +/*****************************************************************************/ + + + +#include +#include +#include +#include +#include + +/* common */ +#include "cmdline.h" +#include "fname.h" +#include "print.h" +#include "segnames.h" +#include "version.h" +#include "xmalloc.h" +#include "xsprintf.h" + +/* co65 */ +#include "error.h" +#include "global.h" +#include "o65.h" + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +static void Usage (void) +/* Print usage information and exit */ +{ + fprintf (stderr, + "Usage: %s [options] file\n" + "Short options:\n" + " -V\t\t\tPrint the version number\n" + " -g\t\t\tAdd debug info to object file\n" + " -h\t\t\tHelp (this text)\n" + " -o name\t\tName the output file\n" + " -v\t\t\tIncrease verbosity\n" + "\n" + "Long options:\n" + " --bss-name seg\tSet the name of the BSS segment\n" + " --code-name seg\tSet the name of the CODE segment\n" + " --data-name seg\tSet the name of the DATA segment\n" + " --debug-info\t\tAdd debug info to object file\n" + " --help\t\tHelp (this text)\n" + " --verbose\t\tIncrease verbosity\n" + " --version\t\tPrint the version number\n" + " --zeropage-name seg\tSet the name of the ZEROPAGE segment\n", + ProgName); +} + + + +static void CheckSegName (const char* Seg) +/* Abort if the given name is not a valid segment name */ +{ + /* Print an error and abort if the name is not ok */ + if (!ValidSegName (Seg)) { + Error ("Segment name `%s' is invalid", Seg); + } +} + + + +static void OptBssName (const char* Opt attribute ((unused)), const char* Arg) +/* Handle the --bss-name option */ +{ + /* Check for a valid name */ + CheckSegName (Arg); + + /* Set the name */ + BssSeg = xstrdup (Arg); +} + + + +static void OptCodeName (const char* Opt attribute ((unused)), const char* Arg) +/* Handle the --code-name option */ +{ + /* Check for a valid name */ + CheckSegName (Arg); + + /* Set the name */ + CodeSeg = xstrdup (Arg); +} + + + +static void OptDataName (const char* Opt attribute ((unused)), const char* Arg) +/* Handle the --data-name option */ +{ + /* Check for a valid name */ + CheckSegName (Arg); + + /* Set the name */ + DataSeg = xstrdup (Arg); +} + + + +static void OptDebugInfo (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Add debug info to the object file */ +{ + DebugInfo = 1; +} + + + +static void OptHelp (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Print usage information and exit */ +{ + Usage (); + exit (EXIT_SUCCESS); +} + + + +static void OptVerbose (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Increase verbosity */ +{ + ++Verbosity; +} + + + +static void OptVersion (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Print the assembler version */ +{ + fprintf (stderr, + "co65 V%u.%u.%u - (C) Copyright 1998-2003 Ullrich von Bassewitz\n", + VER_MAJOR, VER_MINOR, VER_PATCH); +} + + + +static void OptZeropageName (const char* Opt attribute ((unused)), const char* Arg) +/* Handle the --zeropage-name option */ +{ + /* Check for a valid name */ + CheckSegName (Arg); + + /* Set the name */ + ZeropageSeg = xstrdup (Arg); +} + + + +static const char* SegReloc (const O65Data* D, const O65Reloc* R, unsigned long Val) +{ + static char Buf[256]; + const O65Import* Import; + + switch (R->SegID) { + + case O65_SEGID_UNDEF: + if (R->SymIdx >= CollCount (&D->Imports)) { + Error ("Import index out of range (input file corrupt)"); + } + Import = CollConstAt (&D->Imports, R->SymIdx); + xsprintf (Buf, sizeof (Buf), "%s%+ld", Import->Name, (long) Val); + break; + + case O65_SEGID_TEXT: + xsprintf (Buf, sizeof (Buf), "%s%+ld", CodeSeg, (long) (Val - D->Header.tbase)); + break; + + case O65_SEGID_DATA: + xsprintf (Buf, sizeof (Buf), "%s%+ld", DataSeg, (long) (Val - D->Header.dbase)); + break; + + case O65_SEGID_BSS: + xsprintf (Buf, sizeof (Buf), "%s%+ld", BssSeg, (long) (Val - D->Header.bbase)); + break; + + case O65_SEGID_ZP: + xsprintf (Buf, sizeof (Buf), "%s%+ld", ZeropageSeg, (long) Val - D->Header.zbase); + break; + + case O65_SEGID_ABS: + Error ("Relocation entry contains O65_SEGID_ABS"); + break; + + default: + Internal ("Cannot handle this segment reference in reloc entry"); + } + + return Buf; +} + + + +static void ConvertSeg (FILE* F, const O65Data* D, const Collection* Relocs, + const unsigned char* Data, unsigned long Size) +/* Convert one segment */ +{ + const O65Reloc* R; + unsigned RIdx; + unsigned long Byte; + + /* Get the pointer to the first relocation entry if there are any */ + R = (CollCount (Relocs) > 0)? CollConstAt (Relocs, 0) : 0; + + /* Initialize for the loop */ + RIdx = 0; + Byte = 0; + + /* Walk over the segment data */ + while (Byte < Size) { + + if (R && R->Offs == Byte) { + /* We've reached an entry that must be relocated */ + unsigned long Val; + switch (R->Type) { + + case O65_RTYPE_WORD: + if (Byte >= Size - 1) { + Error ("Found WORD relocation, but not enough bytes left"); + } else { + Val = (Data[Byte+1] << 8) + Data[Byte]; + Byte += 2; + fprintf (F, "\t.word\t%s\n", SegReloc (D, R, Val)); + } + break; + + case O65_RTYPE_HIGH: + Val = (Data[Byte++] << 8) + R->Val; + fprintf (F, "\t.byte\t>(%s)\n", SegReloc (D, R, Val)); + break; + + case O65_RTYPE_LOW: + Val = Data[Byte++]; + fprintf (F, "\t.byte\t<(%s)\n", SegReloc (D, R, Val)); + break; + + case O65_RTYPE_SEGADDR: + if (Byte >= Size - 2) { + Error ("Found SEGADDR relocation, but not enough bytes left"); + } else { + Val = (((unsigned long) Data[Byte+2]) << 16) + + (((unsigned long) Data[Byte+1]) << 8) + + (((unsigned long) Data[Byte+0]) << 0) + + R->Val; + Byte += 3; + fprintf (F, "\t.faraddr\t%s\n", SegReloc (D, R, Val)); + } + break; + case O65_RTYPE_SEG: + default: + Internal ("Invalid relocation type at %lu", Byte); + } + + /* Get the next relocation entry */ + if (++RIdx < CollCount (Relocs)) { + R = CollConstAt (Relocs, RIdx); + } else { + R = 0; + } + + } else { + /* Just a constant value */ + fprintf (F, "\t.byte\t$%02X\n", Data[Byte++]); + } + } + + fprintf (F, "\n"); +} + + + +static void Convert (void) +/* Do file conversion */ +{ + FILE* F; + unsigned I; + + /* Read the o65 file into memory */ + O65Data* D = ReadO65File (InFilename); + + /* For now, we do only accept o65 files generated by the ld65 linker which + * have a specific format. + */ + if (D->Header.mode != O65_MODE_CC65) { + Error ("Cannot convert o65 files of this type"); + } + + printf ("Textsize: %lu\n", D->Header.tlen); + printf ("Datasize: %lu\n", D->Header.dlen); + printf ("Imports: %u\n", CollCount (&D->Imports)); + printf ("Exports: %u\n", CollCount (&D->Exports)); + printf ("Textrelocs: %u\n", CollCount (&D->TextReloc)); + printf ("Datarelocs: %u\n", CollCount (&D->DataReloc)); + + /* Open the output file */ + F = fopen (OutFilename, "wb"); + if (F == 0) { + Error ("Cannot open `%s': %s", OutFilename, strerror (errno)); + } + + /* Create a header */ + if ((D->Header.mode & O65_CPU_MASK) == O65_CPU_65816) { + fprintf (F, "\t.p816\n"); + } + fprintf (F, ";\n; File generated by co65 v %u.%u.%u\n;\n", + VER_MAJOR, VER_MINOR, VER_PATCH); + fprintf (F, "\t.fopt\t\tcompiler,\"co65 v %u.%u.%u\"\n", + VER_MAJOR, VER_MINOR, VER_PATCH); + fprintf (F, "\t.case\t\ton\n"); + fprintf (F, "\t.debuginfo\t%s\n", (DebugInfo != 0)? "on" : "off"); + fprintf (F, "\n"); + + /* Imported identifiers */ + if (CollCount (&D->Imports) > 0) { + for (I = 0; I < CollCount (&D->Imports); ++I) { + + /* Get the next import */ + O65Import* Import = CollAtUnchecked (&D->Imports, I); + + /* Import it by name */ + fprintf (F, "\t.import\t%s\n", Import->Name); + } + fprintf (F, "\n"); + } + + /* Exported identifiers */ + if (CollCount (&D->Exports) > 0) { + for (I = 0; I < CollCount (&D->Exports); ++I) { + + /* Get the next import */ + O65Export* Export = CollAtUnchecked (&D->Exports, I); + + /* Import it by name */ + fprintf (F, "\t.export\t%s\n", Export->Name); + } + fprintf (F, "\n"); + } + + /* Code segment */ + fprintf (F, ".segment\t\"%s\"\n", CodeSeg); + fprintf (F, "%s:\n", CodeSeg); + ConvertSeg (F, D, &D->TextReloc, D->Text, D->Header.tlen); + + /* Data segment */ + fprintf (F, ".segment\t\"%s\"\n", DataSeg); + fprintf (F, "%s:\n", DataSeg); + ConvertSeg (F, D, &D->DataReloc, D->Data, D->Header.dlen); + + /* BSS segment */ + fprintf (F, ".segment\t\"%s\"\n", BssSeg); + fprintf (F, "%s:\n", BssSeg); + fprintf (F, "\t.res\t%lu\n", D->Header.blen); + fprintf (F, "\n"); + + fprintf (F, "\t.end\n"); + fclose (F); +} + + + +int main (int argc, char* argv []) +/* Converter main program */ +{ + /* Program long options */ + static const LongOpt OptTab[] = { + { "--bss-name", 1, OptBssName }, + { "--code-name", 1, OptCodeName }, + { "--data-name", 1, OptDataName }, + { "--debug-info", 0, OptDebugInfo }, + { "--help", 0, OptHelp }, + { "--verbose", 0, OptVerbose }, + { "--version", 0, OptVersion }, + { "--zeropage-name", 1, OptZeropageName }, + }; + + unsigned I; + + /* Initialize the cmdline module */ + InitCmdLine (&argc, &argv, "co65"); + + /* Check the parameters */ + I = 1; + while (I < ArgCount) { + + /* Get the argument */ + const char* Arg = ArgVec [I]; + + /* Check for an option */ + if (Arg [0] == '-') { + switch (Arg [1]) { + + case '-': + LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0])); + break; + + case 'g': + OptDebugInfo (Arg, 0); + break; + + case 'h': + OptHelp (Arg, 0); + break; + + case 'o': + OutFilename = GetArg (&I, 2); + break; + + case 'v': + OptVerbose (Arg, 0); + break; + + case 'V': + OptVersion (Arg, 0); + break; + + default: + UnknownOption (Arg); + break; + + } + } else { + /* Filename. Check if we already had one */ + if (InFilename) { + Error ("Don't know what to do with `%s'\n", Arg); + } else { + InFilename = Arg; + } + } + + /* Next argument */ + ++I; + } + + /* Do we have an input file? */ + if (InFilename == 0) { + Error ("No input file\n"); + } + + /* Generate the name of the output file if none was specified */ + if (OutFilename == 0) { + OutFilename = MakeFilename (InFilename, AsmExt); + } + + /* Do the conversion */ + Convert (); + + /* Return an apropriate exit code */ + return EXIT_SUCCESS; +} + + + diff --git a/src/co65/make/gcc.mak b/src/co65/make/gcc.mak new file mode 100644 index 000000000..7b0cb3930 --- /dev/null +++ b/src/co65/make/gcc.mak @@ -0,0 +1,52 @@ +# +# gcc Makefile for co65 +# + +# Library dir +COMMON = ../common + +CFLAGS = -g -O2 -Wall -W -I$(COMMON) +CC = gcc +EBIND = emxbind +LDFLAGS = + +OBJS = error.o \ + fileio.o \ + global.o \ + main.o \ + o65.o + +LIBS = $(COMMON)/common.a + +EXECS = co65 + +.PHONY: all +ifeq (.depend,$(wildcard .depend)) +all : $(EXECS) +include .depend +else +all: depend + @$(MAKE) -f make/gcc.mak all +endif + + + +co65: $(OBJS) $(LIBS) + $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) + @if [ $(OS2_SHELL) ] ; then $(EBIND) $@ ; fi + +clean: + rm -f *~ core *.lst + +zap: clean + rm -f *.o $(EXECS) .depend + +# ------------------------------------------------------------------------------ +# Make the dependencies + +.PHONY: depend dep +depend dep: $(OBJS:.o=.c) + @echo "Creating dependency information" + $(CC) -I$(COMMON) -MM $^ > .depend + + diff --git a/src/co65/make/watcom.mak b/src/co65/make/watcom.mak new file mode 100644 index 000000000..42f99183a --- /dev/null +++ b/src/co65/make/watcom.mak @@ -0,0 +1,82 @@ +# +# CO65 Makefile for the Watcom compiler (using GNU make) +# + +# ------------------------------------------------------------------------------ +# Generic stuff + +AR = WLIB +LD = WLINK +LNKCFG = ld.tmp + +# --------------------- OS2 --------------------- +ifeq ($(TARGET),OS2) +SYSTEM = os2v2 +CC = WCC386 +CFLAGS = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2 +endif + +# -------------------- DOS4G -------------------- +ifeq ($(TARGET),DOS32) +SYSTEM = dos4g +CC = WCC386 +CFLAGS = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2 +endif + +# --------------------- NT ---------------------- +ifeq ($(TARGET),NT) +SYSTEM = nt +CC = WCC386 +CFLAGS = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2 +endif + +# Add the include dir +CFLAGS += -i=..\common + +# ------------------------------------------------------------------------------ +# Implicit rules + +%.obj: %.c + $(CC) $(CFLAGS) $^ + + +# ------------------------------------------------------------------------------ +# All library OBJ files + +OBJS = error.obj \ + fileio.obj \ + global.obj \ + main.obj \ + o65.obj + +LIBS = ..\common\common.lib + + +# ------------------------------------------------------------------------------ +# Main targets + +all: co65 + +co65: co65.exe + + +# ------------------------------------------------------------------------------ +# Other targets + + +co65.exe: $(OBJS) $(LIBS) + @echo DEBUG ALL > $(LNKCFG) + @echo OPTION QUIET >> $(LNKCFG) + @echo NAME $@ >> $(LNKCFG) + @for %%i in ($(OBJS)) do echo FILE %%i >> $(LNKCFG) + @for %%i in ($(LIBS)) do echo LIBRARY %%i >> $(LNKCFG) + $(LD) system $(SYSTEM) @$(LNKCFG) + @rm $(LNKCFG) + +clean: + @if exist *.obj del *.obj + @if exist co65.exe del co65.exe + +strip: + @-wstrip co65.exe + diff --git a/src/co65/o65.c b/src/co65/o65.c new file mode 100644 index 000000000..aa000f307 --- /dev/null +++ b/src/co65/o65.c @@ -0,0 +1,369 @@ +/*****************************************************************************/ +/* */ +/* o65.h */ +/* */ +/* Definitions and code for the o65 file format */ +/* */ +/* */ +/* */ +/* (C) 2002-2003 Ullrich von Bassewitz */ +/* Römerstrasse 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. */ +/* */ +/* 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: */ +/* */ +/* 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. */ +/* 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. */ +/* */ +/*****************************************************************************/ + + + +#include +#include +#include + +/* common */ +#include "xmalloc.h" + +/* co65 */ +#include "error.h" +#include "fileio.h" +#include "o65.h" + + + +/*****************************************************************************/ +/* struct O65Data */ +/*****************************************************************************/ + + + +static O65Data* NewO65Data (void) +/* Create, initialize and return a new O65Data struct */ +{ + /* Allocate memory */ + O65Data* D = xmalloc (sizeof (O65Data)); + + /* Initialize the fields as needed */ + D->Options = AUTO_COLLECTION_INITIALIZER; + D->Text = 0; + D->Data = 0; + D->TextReloc = AUTO_COLLECTION_INITIALIZER; + D->DataReloc = AUTO_COLLECTION_INITIALIZER; + D->Imports = AUTO_COLLECTION_INITIALIZER; + D->Exports = AUTO_COLLECTION_INITIALIZER; + + /* Return the new struct */ + return D; +} + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +static unsigned long ReadO65Size (FILE* F, const O65Header* H) +/* Read a size variable (16 or 32 bit, depending on the mode word in the + * header) from the o65 file. + */ +{ + switch (H->mode & O65_SIZE_MASK) { + case O65_SIZE_32BIT: return Read32 (F); + case O65_SIZE_16BIT: return Read16 (F); + default: Internal ("Invalid size field value in o65 header"); + } +} + + + +static void ReadO65Header (FILE* F, O65Header* H) +/* Read an o65 header from the given file. The function will call Error if + * something is wrong. + */ +{ + static const char Magic[3] = { + O65_MAGIC_0, O65_MAGIC_1, O65_MAGIC_2 /* "o65" */ + }; + + /* Read the marker and check it */ + ReadData (F, H->marker, sizeof (H->marker)); + if (H->marker[0] != O65_MARKER_0 || H->marker[1] != O65_MARKER_1) { + Error ("Not an o65 object file: Invalid marker %02X %02X", + H->marker[0], H->marker[1]); + } + + /* Read the magic and check it */ + ReadData (F, H->magic, sizeof (H->magic)); + if (memcmp (H->magic, Magic, sizeof (H->magic)) != 0) { + Error ("Not an o65 object file: Invalid magic %02X %02X %02X", + H->magic[0], H->magic[1], H->magic[2]); + } + + /* Read the version number and check it */ + H->version = Read8 (F); + if (H->version != O65_VERSION) { + Error ("Invalid o65 version number: %02X", H->version); + } + + /* Read the mode word */ + H->mode = Read16 (F); + + /* Read the remainder of the header */ + H->tbase = ReadO65Size (F, H); + H->tlen = ReadO65Size (F, H); + H->dbase = ReadO65Size (F, H); + H->dlen = ReadO65Size (F, H); + H->bbase = ReadO65Size (F, H); + H->blen = ReadO65Size (F, H); + H->zbase = ReadO65Size (F, H); + H->zlen = ReadO65Size (F, H); + H->stack = ReadO65Size (F, H); +} + + + +static O65Option* ReadO65Option (FILE* F) +/* Read the next O65 option from the given file. The option is stored into a + * dynamically allocated O65Option struct which is returned. On end of options, + * NULL is returned. On error, Error is called which terminates the program. + */ +{ + O65Option* O; + + /* Read the length of the option and bail out on end of options */ + unsigned char Len = Read8 (F); + if (Len == 0) { + return 0; + } + + /* Allocate a new O65Option structure of the needed size */ + O = xmalloc (sizeof (*O) - sizeof (O->Data) + Len - 2); + + /* Assign the length and read the remaining option data */ + O->Len = Len; + O->Type = Read8 (F); + ReadData (F, O->Data, Len - 2); + + /* Return the new struct */ + return O; +} + + + +static O65Import* ReadO65Import (FILE* F) +/* Read an o65 import from the file */ +{ + O65Import* I; + + /* Allow identifiers up to 511 bytes */ + char Buf[512]; + + /* Read the identifier */ + unsigned Len = 0; + char C; + do { + C = Read8 (F); + if (Len >= sizeof (Buf)) { + Error ("Imported identifier exceeds maximum size (%u)", sizeof (Buf)); + } + Buf[Len++] = C; + } while (C != '\0'); + + /* Allocate an import structure and initialize it */ + I = xmalloc (sizeof (*I) - sizeof (I->Name) + Len); + memcpy (I->Name, Buf, Len); + + /* Return the new struct */ + return I; +} + + + +static void ReadO65RelocInfo (FILE* F, const O65Data* D, Collection* Reloc) +/* Read relocation data for one segment */ +{ + /* Relocation starts at (start address - 1) */ + unsigned long Offs = (unsigned long) -1L; + + while (1) { + + O65Reloc* R; + + /* Read the next relocation offset */ + unsigned char C = Read8 (F); + if (C == 0) { + /* End of relocation table */ + break; + } + + /* Create a new relocation entry */ + R = xmalloc (sizeof (*R)); + + /* Handle overflow bytes */ + while (C == 0xFF) { + Offs += 0xFE; + C = Read8 (F); + } + + /* Calculate the final offset */ + R->Offs = (Offs += C); + + /* Read typebyte and segment id */ + C = Read8 (F); + R->Type = (C & O65_RTYPE_MASK); + R->SegID = (C & O65_SEGID_MASK); + + /* Read an additional relocation value if there is one */ + R->SymIdx = (R->SegID == O65_SEGID_UNDEF)? ReadO65Size (F, &D->Header) : 0; + switch (R->Type) { + + case O65_RTYPE_HIGH: + if ((D->Header.mode & O65_RELOC_MASK) == O65_RELOC_BYTE) { + /* Low byte follows */ + R->Val = Read8 (F); + } else { + /* Low byte is zero */ + R->Val = 0; + } + break; + + case O65_RTYPE_SEG: + /* Low 16 byte of the segment address follow */ + R->Val = Read16 (F); + break; + + default: + R->Val = 0; + break; + } + + /* Insert this relocation entry into the collection */ + CollAppend (Reloc, R); + } +} + + + +static O65Export* ReadO65Export (FILE* F, const O65Header* H) +/* Read an o65 export from the file */ +{ + O65Export* E; + + /* Allow identifiers up to 511 bytes */ + char Buf[512]; + + /* Read the identifier */ + unsigned Len = 0; + char C; + do { + C = Read8 (F); + if (Len >= sizeof (Buf)) { + Error ("Exported identifier exceeds maximum size (%u)", sizeof (Buf)); + } + Buf[Len++] = C; + } while (C != '\0'); + + /* Allocate an export structure and initialize it */ + E = xmalloc (sizeof (*E) - sizeof (E->Name) + Len); + memcpy (E->Name, Buf, Len); + E->SegID = Read8 (F); + E->Val = ReadO65Size (F, H); + + /* Return the new struct */ + return E; +} + + + +static O65Data* ReadO65Data (FILE* F) +/* Read a complete o65 file into dynamically allocated memory and return the + * created O65Data struct. + */ +{ + unsigned long Count; + O65Option* O; + + /* Create the struct we're going to return */ + O65Data* D = NewO65Data (); + + /* Read the header */ + ReadO65Header (F, &D->Header); + + /* Read the options */ + while ((O = ReadO65Option (F)) != 0) { + CollAppend (&D->Options, O); + } + + /* Allocate space for the text segment and read it */ + D->Text = xmalloc (D->Header.tlen); + ReadData (F, D->Text, D->Header.tlen); + + /* Allocate space for the data segment and read it */ + D->Data = xmalloc (D->Header.dlen); + ReadData (F, D->Data, D->Header.dlen); + + /* Read the undefined references list */ + Count = ReadO65Size (F, &D->Header); + while (Count--) { + CollAppend (&D->Imports, ReadO65Import (F)); + } + + /* Read the relocation tables for text and data segment */ + ReadO65RelocInfo (F, D, &D->TextReloc); + ReadO65RelocInfo (F, D, &D->DataReloc); + + /* Read the exported globals list */ + Count = ReadO65Size (F, &D->Header); + while (Count--) { + CollAppend (&D->Exports, ReadO65Export (F, &D->Header)); + } + + /* Return the o65 data read from the file */ + return D; +} + + + +O65Data* ReadO65File (const char* Name) +/* Read a complete o65 file into dynamically allocated memory and return the + * created O65Data struct. + */ +{ + O65Data* D; + + /* Open the o65 input file */ + FILE* F = fopen (Name, "rb"); + if (F == 0) { + Error ("Cannot open `%s': %s", Name, strerror (errno)); + } + + /* Read the file data */ + D = ReadO65Data (F); + + /* Close the input file. Ignore errors since we were only reading */ + fclose (F); + + /* Return the data read */ + return D; +} + + + diff --git a/src/co65/o65.h b/src/co65/o65.h new file mode 100644 index 000000000..4cb395fa6 --- /dev/null +++ b/src/co65/o65.h @@ -0,0 +1,222 @@ +/*****************************************************************************/ +/* */ +/* o65.h */ +/* */ +/* Definitions and code for the o65 file format */ +/* */ +/* */ +/* */ +/* (C) 2002-2003 Ullrich von Bassewitz */ +/* Römerstrasse 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. */ +/* */ +/* 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: */ +/* */ +/* 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. */ +/* 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. */ +/* */ +/*****************************************************************************/ + + + +/* This files exports structures and constants to handle the o65 relocatable + * file format as defined by Andre Fachat. See the original document under + * + * http://www.6502.org/users/andre/o65/fileformat.html + * + * for more information. + */ + + + +#ifndef _O65_H +#define _O65_H + + + +/* common */ +#include "coll.h" + + + +/*****************************************************************************/ +/* Defines */ +/*****************************************************************************/ + + + +/* Define a structure for the o65 file header */ +typedef struct { + char marker[2]; /* Non-C64 marker */ + char magic[3]; /* o65 magic */ + char version; /* Version number */ + unsigned mode; /* Mode word */ + unsigned long tbase; /* Original text (code) segment address */ + unsigned long tlen; /* Size of text (code) segment */ + unsigned long dbase; /* Original data segment address */ + unsigned long dlen; /* Size of data segment */ + unsigned long bbase; /* Original bss segment address */ + unsigned long blen; /* Size of bss segment */ + unsigned long zbase; /* Original zp segment address */ + unsigned long zlen; /* Size of zp segment */ + unsigned long stack; /* Stacksize needed */ +} O65Header; + +/* o65 option */ +typedef struct { + unsigned char Len; /* Option length */ + unsigned char Type; /* Option type */ + unsigned char Data[1]; /* Option data (dynamically allocated) */ +} O65Option; + +/* o65 relocation entry */ +typedef struct { + unsigned long Offs; /* Offset in segment */ + unsigned char Type; /* Relocation type */ + unsigned char SegID; /* Segment ID */ + unsigned Val; /* Any offset value needed for relocation */ + unsigned long SymIdx; /* Index into list of imported symbols */ +} O65Reloc; + +/* o65 import */ +typedef struct { + char Name[1]; /* Name of the import (dynamically allocated) */ +} O65Import; + +/* o65 export */ +typedef struct { + unsigned char SegID; /* Segment ID */ + unsigned long Val; /* Relocation value */ + char Name[1]; /* Name of the export (dynamically allocated) */ +} O65Export; + +/* Complete o65 file data */ +typedef struct { + O65Header Header; /* File header */ + Collection Options; /* O65 options */ + unsigned char* Text; /* Text segment data (unrelocated) */ + unsigned char* Data; /* Data segment data (unrelocated) */ + Collection TextReloc; /* Relocation entries for the text segment */ + Collection DataReloc; /* Relocation entries for the data segment */ + Collection Imports; /* Imported symbols */ + Collection Exports; /* Exported symbols */ +} O65Data; + + + +/* Marker, magic and version number */ +#define O65_MARKER_0 0x01 +#define O65_MARKER_1 0x00 +#define O65_MAGIC_0 0x6F /* 'o' */ +#define O65_MAGIC_1 0x36 /* '6' */ +#define O65_MAGIC_2 0x35 /* '5' */ +#define O65_VERSION 0x00 + +/* Defines for the mode word */ +#define O65_CPU_65816 0x8000 /* Executable is for 65816 */ +#define O65_CPU_6502 0x0000 /* Executable is for the 6502 */ +#define O65_CPU_MASK 0x8000 /* Mask to extract CPU type */ + +#define O65_RELOC_PAGE 0x4000 /* Page wise relocation */ +#define O65_RELOC_BYTE 0x0000 /* Byte wise relocation */ +#define O65_RELOC_MASK 0x4000 /* Mask to extract relocation type */ + +#define O65_SIZE_32BIT 0x2000 /* All size words are 32bit */ +#define O65_SIZE_16BIT 0x0000 /* All size words are 16bit */ +#define O65_SIZE_MASK 0x2000 /* Mask to extract size */ + +#define O65_FTYPE_OBJ 0x1000 /* Object file */ +#define O65_FTYPE_EXE 0x0000 /* Executable file */ +#define O65_FTYPE_MASK 0x1000 /* Mask to extract type */ + +#define O65_ADDR_SIMPLE 0x0800 /* Simple addressing */ +#define O65_ADDR_DEFAULT 0x0000 /* Default addressing */ +#define O65_ADDR_MASK 0x0800 /* Mask to extract addressing */ + +#define O65_ALIGN_1 0x0000 /* Bytewise alignment */ +#define O65_ALIGN_2 0x0001 /* Align words */ +#define O65_ALIGN_4 0x0002 /* Align longwords */ +#define O65_ALIGN_256 0x0003 /* Align pages (256 bytes) */ +#define O65_ALIGN_MASK 0x0003 /* Mask to extract alignment */ + +/* The mode word as generated by the ld65 linker */ +#define O65_MODE_CC65 (O65_CPU_6502 | \ + O65_RELOC_BYTE | \ + O65_SIZE_16BIT | \ + O65_FTYPE_EXE | \ + O65_ADDR_SIMPLE | \ + O65_ALIGN_1) + +/* The four o65 segment types. */ +#define O65_SEGID_UNDEF 0x00 +#define O65_SEGID_ABS 0x01 +#define O65_SEGID_TEXT 0x02 +#define O65_SEGID_DATA 0x03 +#define O65_SEGID_BSS 0x04 +#define O65_SEGID_ZP 0x05 +#define O65_SEGID_MASK 0x07 + +/* Relocation type codes */ +#define O65_RTYPE_WORD 0x80 +#define O65_RTYPE_HIGH 0x40 +#define O65_RTYPE_LOW 0x20 +#define O65_RTYPE_SEGADDR 0xC0 +#define O65_RTYPE_SEG 0xA0 +#define O65_RTYPE_MASK 0xE0 + +/* Segment IDs */ +#define O65_SEGID_UNDEF 0x00 +#define O65_SEGID_ABS 0x01 +#define O65_SEGID_TEXT 0x02 +#define O65_SEGID_DATA 0x03 +#define O65_SEGID_BSS 0x04 +#define O65_SEGID_ZP 0x05 +#define O65_SEGID_MASK 0x07 + +/* Option tags */ +#define O65_OPT_FILENAME 0 +#define O65_OPT_OS 1 +#define O65_OPT_ASM 2 +#define O65_OPT_AUTHOR 3 +#define O65_OPT_TIMESTAMP 4 + +/* Operating system codes for O65_OPT_OS */ +#define O65_OS_OSA65 1 +#define O65_OS_LUNIX 2 +#define O65_OS_CC65_MODULE 3 + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +O65Data* ReadO65File (const char* Name); +/* Read a complete o65 file into dynamically allocated memory and return the + * created O65Data struct. + */ + + + +/* End of o65.h */ +#endif + + + +