//
// RLN - Reboot's Linker for the Atari Jaguar console system
-// Copyright (C) 199x, Allan K. Pratt, 2014-2015 Reboot & Friends
+// Copyright (C) 199x, Allan K. Pratt, 2014-2018 Reboot & Friends
//
#include "rln.h"
unsigned vflag = 0; // Verbose flag
unsigned wflag = 0; // Show warnings flag
unsigned zflag = 0; // Suppress banner flag
-unsigned pflag = 0, uflag = 0; // Unimplemented flags
+unsigned pflag = 0, uflag = 0; // Unimplemented flags (partial link, don't abort on unresolved symbols)
unsigned hd = 0; // Index of next file handle to fill
unsigned secalign = 7; // Section Alignment (8=phrase)
unsigned tbase = 0; // TEXT base address
char * PathTail(char *);
void ShowHelp(void);
void ShowVersion(void);
+int OSTLookup(char * sym);
+int OSTAdd(char * name, int type, long value);
+int ProcessFiles(void);
+int doargs(int argc, char * argv[]);
//
unsigned glblreloc; // Global relocation flag
unsigned absreloc; // Absolute relocation flag
unsigned relreloc; // Relative relocation flag
+ unsigned wordreloc; // Relocate word only flag
+ unsigned opreloc; // Relocate OP data address only flag
unsigned swcond; // Switch statement condition
unsigned relocsize; // Relocation record size
+ unsigned saveBits; // OP data leftover bits save
+ unsigned saveBits2;
// If there is no TEXT relocation data for the selected object file segment
// then update the COF TEXT segment offset allowing for the phrase padding
addr = GetLong(rptr);
rflg = GetLong(rptr + 4);
glblreloc = (rflg & 0x00000010 ? 1 : 0);// Set global relocation flag
- absreloc = (rflg & 0x00000040 ? 1 : 0); // Set absolute relocation flag
- relreloc = (rflg & 0x000000A0 ? 1 : 0); // Set relative relocation flag
+ absreloc = (rflg & 0x00000040 ? 1 : 0); // Set absolute relocation flag
+ relreloc = (rflg & 0x000000A0 ? 1 : 0); // Set relative relocation flag
+ wordreloc = (rflg & 0x00000002 ? 1 : 0); // Set word relocation flag
+ opreloc = (rflg & 0x00000004 ? 1 : 0); // Set OP relocation flag
// Additional processing required for global relocations
if (glblreloc)
newdata = GetLong(ost + ((ssidx - 1) * 12) + 8);
}
- // Obtain the existing long word segment data and flip words if the
- // relocation flags indicate it relates to a RISC MOVEI instruction
- olddata = GetLong(sptr + addr);
+ // Obtain the existing long word (or word) segment data and flip words
+ // if the relocation flags indicate it relates to a RISC MOVEI
+ // instruction
+ olddata = (wordreloc ? GetWord(sptr + addr) : GetLong(sptr + addr));
+
+ // If it's a OP QUAD relocation, get the data out of the DATA bits.
+ // Note that because we can't afford to lose the bottom 3 bits of the
+ // relocation record, we lose 3 off the top--which means the maximum
+ // this can store is $1FFFF8 (vs. $FFFFF8).
+ if (opreloc)
+ {
+ saveBits2 = (GetLong(sptr + addr + 8) & 0xE0000000) >> 8; // Upper 3 of data addr
+ saveBits = olddata & 0x7FF;
+ olddata = (olddata & 0xFFFFF800) >> 11;
+ olddata |= saveBits2; // Restore upper 3 bits of data addr
+ }
if (rflg & 0x01)
olddata = _SWAPWORD(olddata);
break;
case 0x00000400: // TEXT segment relocation record
// SCPCD : the symbol point to a text segment, we should use the textoffset
- newdata = tbase + textoffset + olddata;
+ newdata = tbase + textoffset + olddata;
break;
case 0x00000600: // DATA segment relocation record
if (rflg & 0x01)
newdata = _SWAPWORD(newdata);
- PutLong(sptr + addr, newdata);
+ if (wordreloc)
+ PutWord(sptr + addr, newdata);
+ else if (opreloc)
+ {
+ if (vflag > 1)
+ printf("OP reloc: oldata=$%X, newdata=$%X\n", olddata, newdata);
+
+ newdata = ((newdata & 0x00FFFFF8) << 8) | saveBits;
+ PutLong(sptr + addr, newdata);
+ // Strip out extraneous data hitchhikers from 2nd phrase...
+ newdata = GetLong(sptr + addr + 8) & 0x007FFFFF;
+ PutLong(sptr + addr + 8, newdata);
+ }
+ else
+ PutLong(sptr + addr, newdata);
}
else if (relreloc)
{
if (strchr(ofile, '.') == NULL)
{
if (aflag && cflag)
- strcat(ofile, ".cof"); // COF files
+ strcat(ofile, ".cof"); // COF files (a type of abs)
else if (aflag && !cflag)
strcat(ofile, ".abs"); // ABS files
else
- strcat(ofile, ".o"); // Object files (partial linking etc)
+ strcat(ofile, ".o"); // Object files (partial linking, etc)
}
FILE * fd = fopen(ofile, "wb"); // Attempt to open output file
}
// Write the header, but not if noheaderflag
- // Absolute (ABS) header
- if (!cflag)
+ if (!noheaderflag)
{
- if (!noheaderflag)
+ // Absolute (ABS) header
+ if (!cflag)
+ {
if (fwrite(himage, 36, 1, fd) != 1)
goto werror;
- }
- // Absolute (COF) header
- else
- {
- if (fwrite(himage, 168, 1, fd) != 1)
- goto werror;
+ }
+ // Absolute (COF) header
+ else
+ {
+ if (fwrite(himage, 168, 1, fd) != 1)
+ goto werror;
+ }
}
// Write the TEXT segment of each object file
}
}
- if (!noheaderflag)
+//wha? if (!noheaderflag)
+ // This isn't quite right, but it's closer...
+ // (the l and s flags tell the linker to output local & global symbols
+ // in the symbol table, so it seems there's some other thing that's a
+ // default set somewhere. Not 100% sure. Setting -s kills -l, BTW...)
+ if (lflag || sflag)
{
// Write the symbols table and string table
// Absolute (COF) symbol/string table
}
// Check to see if a long filename was requested
- if (objName[0] == 0x20)
+ // N.B.: " " is for GNU archives, and "/" is for BSD archives
+ if ((objName[0] == 0x20) || (objName[0] == '/'))
{
uint32_t fnSize = atoi(objName + 1);
wflag = 1;
break;
+ case 'y':
+ case 'Y':
+ if (i >= argc)
+ {
+ printf("No directory filename following -y switch\n");
+ return 1;
+ }
+
+ if (strlen(argv[i]) > FARGSIZE * 3)
+ {
+ printf("Directory file name too long (sorry!)\n");
+ return 1;
+ }
+
+ strcpy(libdir, argv[i++]);
+ break;
case 'z':
case 'Z': // Suppress banner flag
if (zflag)
"| | | | | | |\n"
"|_| |_|_| |_|\n"
"\nReboot's Linker for Atari Jaguar\n"
- "Copyright (c) 199x Allan K. Pratt, 2014-2015 Reboot\n"
+ "Copyright (c) 199x Allan K. Pratt, 2014-2018 Reboot\n"
"V%i.%i.%i %s (%s)\n\n", MAJOR, MINOR, PATCH, __DATE__, PLATFORM);
}
}
printf(" -d wait for key after link\n");
printf(" -e output COF absolute file\n");
printf(" -g output source-level debugging\n");
- printf(" -i <fname> <label> incbin <fname> and set <label>\n");
+ printf(" -i <fname> <label> incbin <fname> and set <label> (trunc to 8 chars)\n");
+ printf(" -ii <fname> <label> incbin <fname> and set <label> (no truncation)\n");
printf(" -l add local symbols\n");
printf(" -m produce load symbols map\n");
- printf(" -n output no file header to .abs file\n");
+ printf(" -n output no file header to absolute file\n");
printf(" -o <fname> set output name\n");
printf(" -r<size> section alignment size\n");
printf(" w: word (2 bytes)\n");
printf(" p: phrase (8 bytes, default alignment)\n");
printf(" d: double phrase (16 bytes)\n");
printf(" q: quad phrase (32 bytes)\n");
- printf(" -s output only global symbols\n");
+ printf(" -s output only global symbols (supresses -l)\n");
printf(" -u allow unresolved symbols (experimental)\n");
printf(" -v set verbose mode\n");
printf(" -w show linker warnings\n");
+ printf(" -y <fname> set include path (also set by RLNPATH)\n");
printf(" -z suppress banner\n");
printf("\n");
}
ExitLinker();
}
+ // Check to see if include paths actually exist
+ if (strlen(libdir) > 0)
+ {
+ DIR * test = opendir(libdir);
+
+ if (test == NULL)
+ {
+ printf("Invalid include path: %s\n", libdir);
+ errflag = 1;
+ ExitLinker();
+ }
+
+ closedir(test);
+ }
+
if (!zflag && !vflag)
{
ShowVersion(); // Display version information