From 52963cddfc29b2981d549ff785c1a24d814f7290 Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Sat, 30 May 2020 09:11:20 -0500 Subject: [PATCH 01/11] Added .gitignore. This should take care of bug #161. --- .gitignore | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ba6597 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +rln-* +rln +rln.exe +*.o +*~ +.*.swp +bugs*/ +parse* +versions/ +patches/ +ar.html -- 2.37.2 From a839b5e1b42ccc20bc7a0960c79c6916415adffb Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Sun, 7 Mar 2021 16:50:58 -0600 Subject: [PATCH 02/11] Update to the name (don't ask), and copyright dates. Now at v.1.7.0. --- makefile | 20 ++++++++++---------- rln.c | 8 ++++---- rln.h | 8 ++++---- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/makefile b/makefile index b70cc77..0c14fe6 100644 --- a/makefile +++ b/makefile @@ -1,5 +1,5 @@ # -# Makefile for Reboot's Linker for Jaguar +# Makefile for Renamed Linker for Jaguar # RM =/bin/rm -f CC = gcc @@ -21,18 +21,18 @@ endif endif CFLAGS = -g -I. -D$(SYSTYPE) -O2 -Wno-format -SRCS = rln.c +SRCS = rln.c OBJS = rln.o -.c.o: - $(RM) $@ - $(CROSS)$(CC) $(CFLAGS) -c $*.c +.c.o: + $(RM) $@ + $(CROSS)$(CC) $(CFLAGS) -c $*.c -all: $(PROGNAME) +all: $(PROGNAME) -$(PROGNAME) : $(OBJS) - $(CROSS)$(CC) $(CFLAGS) -o $(PROGNAME) $(OBJS) $(LIBS) +$(PROGNAME) : $(OBJS) + $(CROSS)$(CC) $(CFLAGS) -o $(PROGNAME) $(OBJS) $(LIBS) -clean: - $(RM) $(OBJS) $(PROGNAME) $(PROGNAME).exe *~ +clean: + $(RM) $(OBJS) $(PROGNAME) $(PROGNAME).exe *~ diff --git a/rln.c b/rln.c index a0b5ab0..e451f45 100644 --- a/rln.c +++ b/rln.c @@ -1,6 +1,6 @@ // -// RLN - Reboot's Linker for the Atari Jaguar console system -// Copyright (C) 199x, Allan K. Pratt, 2014-2018 Reboot & Friends +// RLN - Renamed Linker for the Atari Jaguar console system +// Copyright (C) 199x, Allan K. Pratt, 2014-2021 Reboot & Friends // #include "rln.h" @@ -3050,8 +3050,8 @@ void ShowVersion(void) "| '__| | '_ \\\n" "| | | | | | |\n" "|_| |_|_| |_|\n" - "\nReboot's Linker for Atari Jaguar\n" - "Copyright (c) 199x Allan K. Pratt, 2014-2018 Reboot\n" + "\nRenamed Linker for Atari Jaguar\n" + "Copyright (c) 199x Allan K. Pratt, 2014-2021 Reboot & Friends\n" "V%i.%i.%i %s (%s)\n\n", MAJOR, MINOR, PATCH, __DATE__, PLATFORM); } } diff --git a/rln.h b/rln.h index 75d6bb3..5b45bed 100644 --- a/rln.h +++ b/rln.h @@ -1,6 +1,6 @@ // -// RLN - Reboot's Linker for the Atari Jaguar console system -// Copyright (C) 199x Allan K. Pratt, 2011-2018 Reboot & Friends +// RLN - Renamed Linker for the Atari Jaguar console system +// Copyright (C) 199x Allan K. Pratt, 2011-2021 Reboot & Friends // #ifndef __RLN_H__ @@ -43,8 +43,8 @@ #endif #define MAJOR 1 // Major version number -#define MINOR 6 // Minor version number -#define PATCH 4 // Patch release number +#define MINOR 7 // Minor version number +#define PATCH 0 // Patch release number #ifdef WIN32 #define PLATFORM "Win32" // Release platform - Windows -- 2.37.2 From cc23da7a6e7fd332a0b4ec1e8be7b88cf2187ec1 Mon Sep 17 00:00:00 2001 From: ggn Date: Thu, 21 Jul 2022 19:57:03 +0300 Subject: [PATCH 03/11] Fix for #190, thanks to jagmod for the report --- rln.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rln.h b/rln.h index 5b45bed..1a448ce 100644 --- a/rln.h +++ b/rln.h @@ -68,7 +68,7 @@ #define OST_BLOCK 0x400000 // Output symbol table block (4MB) #define DSTSEG_D 1 // Include file destination seg (DATA) #define DSTSEG_T 2 // Include file destination seg (TEXT) -#define MAXARGS 256 // Max number of args in a command file +#define MAXARGS 4096 // Max number of args in a command file // Headers -- 2.37.2 From a0516e2c2a3377dadd28cdd3172b36d921550838 Mon Sep 17 00:00:00 2001 From: James Jones Date: Sat, 16 Apr 2022 21:11:21 -0700 Subject: [PATCH 04/11] Handle absolute BSS segment location of 'xt' When linking an absolute executable, the data segment and BSS segment can be assigned an absolute address, or the special value 'x' to indicate they are contiguous with the prior segment (text for data, data for BSS). However, RLN (like MAC) also accepts an optional segment specifier after the special value 'x' that allows explicitly specifying which segment the current one is contiguous with. For data, the only valid value is 'xt', meaning contiguous with text. However, when the data segment is specified to be at an explicit address rather than contiguous with the text segment, it is valid to specify that the BSS segment is contiguous with data ('xd') or with text ('xt'). RLN was accepting these additional 't' and 'd' values, but ignoring them. This change causes RLN to correctly place the BSS segment after the text segment when its location is specified as 'xt' as long as the data segment isn't also contiguous with the text segment. --- rln.c | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/rln.c b/rln.c index e451f45..78ed410 100644 --- a/rln.c +++ b/rln.c @@ -1572,11 +1572,19 @@ struct OHEADER * MakeOutputObject() dbase = dval; if (!bval) - // BSS follows DATA - bbase = dval + datasize; + { + if (btype == -2) + // BSS follows TEXT + bbase = tval + textsize; + else + // BSS follows DATA + bbase = dval + datasize; + } else + { // BSS is independent of DATA bbase = bval; + } } // Inject segment end labels, for C compilers that expect this shite @@ -2809,9 +2817,33 @@ int doargs(int argc, char * argv[]) } else if ((*argv[i] == 'x' || *argv[i] == 'X')) { - btype = -3; // BSS follows DATA + switch (argv[i][1]) + { + case 'd': case 'D': case '\0': + btype = -3; // BSS follows DATA + break; + + case 't': case 'T': + btype = -2; // BSS follows TEXT + if (btype == dtype) + { + printf("Error in bss-segment address: data-segment also follows text\n"); + return 1; + } + break; + + default: + btype = -4; // Error + break; + } } else if (GetHexValue(argv[i], &bval)) + { + btype = -4; + return 1; + } + + if (btype == -4) { printf("Error in bss-segment address: %s is not 'r', 'x[td]', or an address.", argv[i]); return 1; @@ -3070,7 +3102,10 @@ void ShowHelp(void) printf(" -a output absolute file (default: ABS)\n"); printf(" hex value: segment address\n"); printf(" r: relocatable segment\n"); - printf(" x: contiguous segment\n"); + printf(" x[dt]: contiguous segment\n"); + printf(" for contiguous bss:\n"); + printf(" d(default): follows data segment\n"); + printf(" t: follows text segment\n"); printf(" -b don't remove multiply defined local labels\n"); printf(" -c add contents of to command line\n"); printf(" -d wait for key after link\n"); -- 2.37.2 From f63e6b2da113c96ec385dce64bc306bb7f68b933 Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Mon, 15 Aug 2022 21:24:39 -0500 Subject: [PATCH 05/11] Version bump for latest patches. --- .gitignore | 1 + rln.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0ba6597..01b647c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ parse* versions/ patches/ ar.html +regression/ diff --git a/rln.h b/rln.h index 1a448ce..8409102 100644 --- a/rln.h +++ b/rln.h @@ -44,7 +44,7 @@ #define MAJOR 1 // Major version number #define MINOR 7 // Minor version number -#define PATCH 0 // Patch release number +#define PATCH 1 // Patch release number #ifdef WIN32 #define PLATFORM "Win32" // Release platform - Windows -- 2.37.2 From 304cdee3e0d3253c22eb380a76e30b32b720bb77 Mon Sep 17 00:00:00 2001 From: James Jones Date: Sat, 18 Apr 2020 02:45:06 -0700 Subject: [PATCH 06/11] Add Alcyon C object file support Support ingesting the DRI Alcyon C object file format in addition to a.out object files. The load file routine simply translates the Alcyon object file into an a.out file before passing it on to the existing processing workflow. The motivation here was to enable linking of the binary-only cinepak decompression GPU routines provided in the developer files. ALN can handle these files just fine, and now RLN can too. However, that is a very simple object files To fully exercise the relocation table translation code, contrived assembly files with all types of relocations were assembled as Alcyon C object files using MADMAC and BSD/a.out object files using RMAC (Note RMAC had to be used to generate the a.out files because MADMAC generates invalid a.out relocations for certain relocation types that it handles fine in Alcyon format), and then both object files were linked as COFF executables using RLN. The resulting COFF files were verified to be identical. --- rln.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- rln.h | 95 ++++++++++++++++++ 2 files changed, 389 insertions(+), 13 deletions(-) diff --git a/rln.c b/rln.c index 78ed410..4a83410 100644 --- a/rln.c +++ b/rln.c @@ -671,11 +671,11 @@ int RelocateSegment(struct OFILE * ofile, int flag) // object file image 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 - wordreloc = (rflg & 0x00000002 ? 1 : 0); // Set word relocation flag - opreloc = (rflg & 0x00000004 ? 1 : 0); // Set OP relocation flag + glblreloc = (rflg & BSDREL_GLOBAL ? 1 : 0); + absreloc = (rflg & BSDREL_ABS ? 1 : 0); + relreloc = (rflg & BSDREL_PCREL ? 1 : 0); + wordreloc = (rflg & BSDREL_WORD ? 1 : 0); + opreloc = (rflg & BSDREL_OP ? 1 : 0); // Additional processing required for global relocations if (glblreloc) @@ -684,7 +684,7 @@ int RelocateSegment(struct OFILE * ofile, int flag) // for it in the globals hash table to obtain information on that // symbol. For the hash calculation to work correctly it must be // placed in a 'clean' string before looking it up. - symidx = GetLong(symtab + ((rflg >> 8) * 12)); + symidx = GetLong(symtab + (BSDREL_SYMIDX(rflg) * 12)); memset(sym, 0, SYMLEN); strcpy(sym, symbols + symidx); olddata = newdata = 0; // Initialise old and new segment data @@ -709,32 +709,32 @@ int RelocateSegment(struct OFILE * ofile, int flag) olddata |= saveBits2; // Restore upper 3 bits of data addr } - if (rflg & 0x01) + if (rflg & BSDREL_MOVEI) olddata = _SWAPWORD(olddata); // Process record dependant on segment it relates to; TEXT, DATA or // BSS. Construct a new relocated segment long word based on the // required segment base address, the segment data offset in the // resulting COF file and the offsets from the incoming object file. - swcond = (rflg & 0xFFFFFF00); + swcond = (rflg & BSDREL_SEGMASK); if (!glblreloc) { switch (swcond) { - case 0x00000200: // Absolute Value + case BSDREL_SEG_ABS: break; - case 0x00000400: // TEXT segment relocation record + case BSDREL_SEG_TEXT: // SCPCD : the symbol point to a text segment, we should use the textoffset newdata = tbase + textoffset + olddata; break; - case 0x00000600: // DATA segment relocation record + case BSDREL_SEG_DATA: newdata = dbase + dataoffset + (olddata - ofile->o_header.tsize); break; - case 0x00000800: // BSS segment relocation record + case BSDREL_SEG_BSS: newdata = bbase + bssoffset + (olddata - (ofile->o_header.tsize + ofile->o_header.dsize)); @@ -754,7 +754,7 @@ int RelocateSegment(struct OFILE * ofile, int flag) // Flip the new long word segment data if the relocation record // indicated a RISC MOVEI instruction and place the resulting data // back in the COF segment - if (rflg & 0x01) + if (rflg & BSDREL_MOVEI) newdata = _SWAPWORD(newdata); if (wordreloc) @@ -2375,6 +2375,280 @@ int LoadObject(char * fname, int fd, char * ptr) return AddToProcessingList(ptr, fname, nullStr, 0, tSize, dSize, bSize); } +uint32_t SymTypeAlcToAout(uint32_t alcType) +{ + uint32_t type = T_UNDF; + + // Symbol type mappings here are derived from comparing Alcyon and BSD + // object files generated by MADMAC using the "size" utility from jag_utils + // (https://github.com/cubanismo/jag_utils) and the old PC/DOS Atari SDK. + // + // In BSD/a.out: + // + // 1) text | global text == text relocatable symbol in this file + // 2) data | global data == data relocatable symbol in this file + // 3) BSS | global BSS == bss relocatable symbol in this file + // 4) ABS | global ABS == non-relocatable symbol in this file + // 4) | global == undefined global symbol (extern) + // + // In DRI/Alcyon: + // + // 1) Everything seems to be marked defined. + // 2) There is an explicit "external" bit. It appears to be mutually + // exclusive with the "global" bit, at least in MADMAC's output. + // 3) There are separate "equated" and "equated reg" type bits that + // both represent ABS/non-relocatable values. + if ((alcType & ALCSYM_EQUATED) || + (alcType & ALCSYM_EQUATED_REG)) + type |= T_ABS; + else if (alcType & ALCSYM_TEXT) + type |= T_TEXT; + else if (alcType & ALCSYM_DATA) + type |= T_DATA; + else if (alcType & ALCSYM_BSS) + type |= T_BSS; + + if ((alcType & ALCSYM_GLOBAL) || + (alcType & ALCSYM_EXTERN)) + type |= T_GLBL; + + return type; +} + +int LoadAlcyon(char * fname, int fd) +{ + char *ptr, *sptr, *aout, *saout, *traout, *strPtr; + char *trelptr, *drelptr, *relend; + struct ALCHEADER hdr; + struct ALCSYM *alcSyms; + long size = FileSize(fd); + size_t symStrLen; + size_t strOff; + uint32_t numSyms, numTRel, numDRel, i, j; + + // Validate the file is at least large enough to contain a valid header + if (size < 0x1c) + { + printf("Alcyon object file %s too small to contain header\n", fname); + return 1; + } + + // Allocate memory for file data + ptr = malloc(size); + + if (ptr == NULL) + { + printf("Out of memory while processing %s\n", fname); + close(fd); + return 1; + } + + // Read in file data + if (read(fd, ptr, size) != size) + { + printf("File read error on %s\n", fname); + close(fd); + free(ptr); + return 1; + } + + close(fd); + + hdr.magic = GetWord(ptr); + hdr.tsize = GetLong(ptr + 2); + hdr.dsize = GetLong(ptr + 6); + hdr.bsize = GetLong(ptr + 10); + hdr.ssize = GetLong(ptr + 14); + + // Construct a BSD-style/aout object file in memory from the Alcyon data + numSyms = hdr.ssize / 14; + + alcSyms = calloc(numSyms, sizeof(*alcSyms)); + if (alcSyms == NULL) + { + printf("Out of memory while processing %s\n", fname); + free(ptr); + return 1; + } + + sptr = ptr + 0x1c + hdr.tsize + hdr.dsize; + trelptr = sptr + hdr.ssize; + drelptr = trelptr + hdr.tsize; + relend = drelptr + hdr.dsize; + + if (relend - ptr > size) + { + printf("Alcyon object file %s truncated: Header wants %ldB, file is %ldB\n", + fname, relend - ptr, size); + return 1; + } + + for (i = 0, symStrLen = 0; i < numSyms; i++) + { + memcpy(alcSyms[i].name, sptr, 8); + alcSyms[i].type = GetWord(sptr + 8); + alcSyms[i].value = GetLong(sptr + 10); + symStrLen += strnlen((char *)alcSyms[i].name, 8) + 1; + sptr += 14; + } + + for (i = 0, numTRel = 0; trelptr + i < drelptr; i += 2) + { + uint16_t rel = GetWord(trelptr + i); + if ((rel != ALCREL_ABS) && + (rel != ALCREL_LONG)) + numTRel++; + } + + for (i = 0, numDRel = 0; drelptr + i < relend; i += 2) + { + uint16_t rel = GetWord(drelptr + i); + if ((rel != ALCREL_ABS) && + (rel != ALCREL_LONG)) + numDRel++; + } + + aout = malloc(32 + /* header */ + hdr.tsize + + hdr.dsize + + numTRel * 8 + /* Text section relocations */ + numDRel * 8 + /* Data section relocations */ + numSyms * 12 + /* symbol table */ + 4 + symStrLen + /* string table size + strings */ + 4 /* NULL-terminator for file */); + if (aout == NULL) + { + printf("Out of memory while processing %s\n", fname); + free(alcSyms); + free(ptr); + return 1; + } + + // Construct the BSD/a.out header. + PutLong(aout, 0x00000107); // Magic number + + PutLong(aout+4, hdr.tsize); // Text size + PutLong(aout+8, hdr.dsize); // Data size + PutLong(aout+12, hdr.bsize); // BSS size + PutLong(aout+16, numSyms * 12); // Symbol table size + PutLong(aout+20, 0L); // Entry point + + PutLong(aout+24, numTRel * 8); // TEXT relocation size + PutLong(aout+28, numDRel * 8); // DATA relocation size + + // Copy the raw text and data segments + memcpy(aout + 32, ptr + 0x1c, hdr.tsize); + memcpy(aout + 32 + hdr.tsize, ptr + 0x1c + hdr.tsize, hdr.dsize); + + // Set traout to the start of the relocation tables + traout = aout + 32 + hdr.tsize + hdr.dsize; + + // Set saout to symbol table location + saout = traout + numTRel * 8 + numDRel * 8 ; + + // Convert the text and data relocations to a.out format + for (i = 0; trelptr + i < relend; i += 2) + { + uint16_t rel = GetWord(trelptr + i); + uint16_t relFlags = rel & 7; + uint32_t aoutflags = BSDREL_ABS; + uint32_t valoffset = 0; + char *const valaddr = aout + 32 + i; + const uint32_t reladdr = (trelptr + i >= drelptr) ? i - hdr.tsize : i; + + if (relFlags == ALCREL_LONG) + { + i += 2; + rel = GetWord(trelptr + i); + relFlags = rel & 7; + } + else + { + aoutflags |= BSDREL_WORD; + } + + if (relFlags == ALCREL_ABS) + continue; + + switch (relFlags) { + case ALCREL_EXTPCREL: + aoutflags &= ~BSDREL_ABS; + aoutflags |= BSDREL_PCREL; + /* Fall through */ + case ALCREL_EXTABS: + aoutflags |= BSDREL_GLOBAL; + aoutflags |= (ALCREL_SYMIDX(rel) << BSDREL_SYMIDX_SHIFT); + break; + case ALCREL_TEXT: + aoutflags |= BSDREL_SEG_TEXT; + break; + case ALCREL_DATA: + aoutflags |= BSDREL_SEG_DATA; + valoffset = hdr.tsize; + break; + case ALCREL_BSS: + aoutflags |= BSDREL_SEG_BSS; + valoffset = hdr.tsize + hdr.dsize; + break; + + default: + printf("Invalid Alcyon relocation flags: 0x%02x\n", relFlags); + free(alcSyms); + free(ptr); + free(aout); + return 1; + } + + if (valoffset != 0) + { + if (aoutflags & BSDREL_WORD) + { + valoffset += GetWord(valaddr); + PutWord(valaddr, (uint16_t)valoffset); + } + else + { + valoffset += GetLong(valaddr); + PutLong(valaddr, valoffset); + } + } + + PutLong(traout, reladdr); + PutLong(traout+4, aoutflags); + traout += 8; + } + + // Done with the Alcyon data. + free(ptr); + ptr = NULL; + sptr = NULL; + + // Set strPtr to string table location and write string table size + strPtr = saout + numSyms * 12; + PutLong(strPtr, 4 + symStrLen); + + for (i = 0, strOff = 4; i < numSyms; i++) + { + PutLong(saout, strOff); // String offset of symbol + PutLong(saout+4, SymTypeAlcToAout(alcSyms[i].type)); // Symbol type + PutLong(saout+8, alcSyms[i].value); // Symbol value + saout += 12; + + for (j = 0; j < 8 && alcSyms[i].name[j] != '\0'; j++) + *(strPtr + strOff + j) = alcSyms[i].name[j]; + strOff += j; // Step past string + *(strPtr + strOff) = '\0'; // Terminate symbol string + strOff++; // Step past termination + } + + PutLong(strPtr + strOff, 0L); // Terminating long for object file + + // Done with the Alcyon symbol table. + free(alcSyms); + + // Now add this image to the list of pending ofiles (plist) + return AddToProcessingList(aout, fname, nullStr, 0, hdr.tsize, hdr.dsize, hdr.bsize); +} // // What it says on the tin: check for a .o suffix on the passed in string @@ -2539,6 +2813,13 @@ int ProcessFiles(void) if (LoadObject(name[i], handle[i], 0L)) return 1; } + // Look for DRI Alcyon C (and old MAC) object files + else if (GetWord(magic) == 0x601A) + { + // Process Alcyon object file. + if (LoadAlcyon(name[i], handle[i])) + return 1; + } // Otherwise, look for an object archive file else if (strncmp(magic, "!\x0A", 8) == 0) { diff --git a/rln.h b/rln.h index 8409102..ebb575c 100644 --- a/rln.h +++ b/rln.h @@ -83,6 +83,86 @@ #include #include +// Alcyon object file header structures. +// +// Same as an Atari ST/GEMDOS/TOS executable file header. +// +// References: +// http://cd.textfiles.com/ataricompendium/BOOK/HTML/CHAP2.HTM#processes +// https://mikro.naprvyraz.sk/docs/GEM/GEMDOS.TXT +// MADMAC source from Landon Dyer (See below for URL) +// +// Note the above disagree on the last entry in the header layout: In practice +// the files MADMAC produces and that ALN consumes use the header layout from +// the Atari Compendium page. +struct ALCHEADER +{ + uint16_t magic; // $601A + uint32_t tsize; // text segment size + uint32_t dsize; // data segment size + uint32_t bsize; // BSS segment size + uint32_t ssize; // symbol table size + uint32_t reserved0; // unused + uint32_t reserved1; // unused + uint16_t absflag; // Always '0' (relocatable) for obj files +}; + +// Alcyon/DRI symbol type bits - From size.c:show_dri_symbol_type() in +// https://github.com/cubanismo/jag_utils, as well as +// the GEMDOS Reference Manual, 4/4/86, "Executable Files" section, in the +// table "Values For Symbol Types," available various places, e.g., +// https://mikro.naprvyraz.sk/docs/GEM/GEMDOS.TXT +#define ALCSYM_DEFINED 0x8000 +#define ALCSYM_EQUATED 0x4000 +#define ALCSYM_GLOBAL 0x2000 +#define ALCSYM_EQUATED_REG 0x1000 +#define ALCSYM_EXTERN 0x0800 +#define ALCSYM_DATA 0x0400 +#define ALCSYM_TEXT 0x0200 +#define ALCSYM_BSS 0x0100 + +// Alcyon/DRI symbol relocation flags - Derived from mark.c in the +// original MADMAC sources released by Landon Dyer on his blog: +// +// https://dadhacker-125488.ingress-alpha.ewp.live/ +// +// At this link from his September 2nd, 2008 post: +// +// http://www.dadhacker.com/Downloads/madmac.zip +// +// Downloaded from the Internet Archive Wayback Machine November 2015 +// snapshot of the above URL, here: +// +// https://web.archive.org/web/20151120225539/http://www.dadhacker.com/Downloads/madmac.zip +// +// Another valuable source of information on the Alcyon relocation data, +// and the Alcyon/DRI C object file format in general is the Sozobon 2.0 +// source code: +// +// https://sourceforge.net/projects/sozobon/files/ +// +// Sozobon is a reimplementation of the original Atari Alcyon C compiler +// suite that can generate and link Alcyon/DRI object files compatible +// with the original. Take a look at the jas/cpy.c file for an alternate +// implementation of Alcyon/DRI relocation section data generation than +// the one in MADMAC, as well as an alternate Alcyon/DRI relocation +// data processing implementation in ld/rel.c. +#define ALCREL_ABS 0x0000 // No relocation at this location +#define ALCREL_DATA 0x0001 // Local address from data segment +#define ALCREL_TEXT 0x0002 // Local address from text segment +#define ALCREL_BSS 0x0003 // Local address from BSS segment +#define ALCREL_EXTABS 0x0004 // External fixup: Absolute address +#define ALCREL_LONG 0x0005 // Relocation type is in next word +#define ALCREL_EXTPCREL 0x0006 // External fixup: PC relative address +#define ALCREL_SYMIDX(rval) ((rval) >> 3) // 0-based index of ext fixup symbol + +struct ALCSYM +{ + uint8_t name[8]; // fixed-size, padded with zeros. NOT NUL-terminated! + uint16_t type; // symbol type mask, from ALCSYM_* flags above. + uint32_t value; // value +}; + struct OHEADER { uint32_t magic; // $0107 for .o, $601B for .abs @@ -111,6 +191,21 @@ struct OHEADER #define new_oheader() (struct OHEADER *)malloc(sizeof(struct OHEADER)) +// BSD/a.out object relocation flags. +#define BSDREL_MOVEI 0x00000001 // Word-swapped (I.e., JRISC movei) long +#define BSDREL_WORD 0x00000002 +#define BSDREL_OP 0x00000004 // Object Processor relocation +#define BSDREL_GLOBAL 0x00000010 // AKA external reference +#define BSDREL_ABS 0x00000040 +#define BSDREL_PCREL 0x000000A0 // Note this implies BSDREL_GLOBAL +#define BSDREL_SYMIDX_SHIFT 8 // Bits to shift +#define BSDREL_SYMIDX(_rf) ((_rf) >> BSDREL_SYMIDX_SHIFT) +#define BSDREL_SEGMASK 0xFFFFFF00 +#define BSDREL_SEG_ABS 0x00000200 +#define BSDREL_SEG_TEXT 0x00000400 +#define BSDREL_SEG_DATA 0x00000600 +#define BSDREL_SEG_BSS 0x00000800 + struct ARHEADER { uint8_t a_fname[14]; -- 2.37.2 From a63bf6807773cdcf9d5660bab8e0bc97645cf8b1 Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Mon, 15 Aug 2022 21:28:33 -0500 Subject: [PATCH 07/11] Version bump for last commit. --- rln.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rln.h b/rln.h index ebb575c..7737f4d 100644 --- a/rln.h +++ b/rln.h @@ -44,7 +44,7 @@ #define MAJOR 1 // Major version number #define MINOR 7 // Minor version number -#define PATCH 1 // Patch release number +#define PATCH 2 // Patch release number #ifdef WIN32 #define PLATFORM "Win32" // Release platform - Windows -- 2.37.2 From 0d71dcf00270f75a7692c788e2834e47231780ef Mon Sep 17 00:00:00 2001 From: James Jones Date: Tue, 26 Jul 2022 03:36:50 -0700 Subject: [PATCH 08/11] Convert output symbol table back to a table It looks like at some point the output symbol was converted from an actual table of SYMREC structs to an in-memory copy of a COFF/a.out symbol table. This entailed relying on the assumption that all symbols had an entry in the string table when using OSTLookup()'s return value as anything other than a boolean value, as is done in the relocation procesing logic. In preparation for adding support for debug symbols, which often have no string table entry, revert to using an intermediate output symbol table representation and serializing it one symbol at a time when writing the output file. This simplifies various code paths, but potentially slows down writing COFF symbol tables to disk. Fortunately, this table is not written with default options, and is rather small unless using debug symbols, so this shouldn't significantly affect the runtime of most existing use cases. --- rln.c | 258 +++++++++++++++++++++++++--------------------------------- rln.h | 13 ++- 2 files changed, 116 insertions(+), 155 deletions(-) diff --git a/rln.c b/rln.c index 4a83410..4ae8d44 100644 --- a/rln.c +++ b/rln.c @@ -55,13 +55,12 @@ char * arPtr[512]; uint32_t arIndex = 0; struct HREC * htable[NBUCKETS]; // Hash table struct HREC * unresolved = NULL; // Pointer to unresolved hash list -char * ost; // Output symbol table -char * ost_ptr; // Output symbol table; current pointer -char * ost_end; // Output symbol table; end pointer -char * oststr; // Output string table -char * oststr_ptr; // Output string table; current pointer -char * oststr_end; // Output string table; end pointer -int ost_index = 0; // Index of next ost addition +struct SYMREC * ost; // Output symbol table +char * oststr = NULL; // Output string table +char * oststr_ptr = NULL; // Output string table; current pointer +char * oststr_end = NULL; // Output string table; end pointer +int ost_index = 0; // Index of next free ost entry +int ost_size = 0; // Size of ost uint8_t nullStr[1] = "\x00"; // Empty string struct HREC * arSymbol = NULL; // Pointer to AR symbol table @@ -139,6 +138,7 @@ int DoSymbols(struct OFILE * ofile) int type; long value; int index; + char *string; int j; struct HREC * hptr; uint32_t tsoSave, dsoSave, bsoSave; @@ -166,6 +166,7 @@ int DoSymbols(struct OFILE * ofile) index = GetLong(symptr + 0); // Obtain symbol string index type = GetLong(symptr + 4); // Obtain symbol type value = GetLong(symptr + 8); // Obtain symbol value + string = index ? symend + index : ""; // Global/External symbols have a pre-processing stage // N.B.: This destroys the t/d/bsegoffset discovered above. So if a @@ -176,21 +177,21 @@ int DoSymbols(struct OFILE * ofile) // Obtain the string table index for the relocation symbol, look // for it in the globals hash table to obtain information on that // symbol. - hptr = LookupHREC(symend + index); + hptr = LookupHREC(string); if (hptr == NULL) { // Try to find it in the OST - int ostIndex = OSTLookup(symend + index); + int ostIndex = OSTLookup(string); if (ostIndex == -1) { - printf("DoSymbols(): Symbol not found in hash table: '%s' (%s)\n", symend + index, ofile->o_name); + printf("DoSymbols(): Symbol not found in hash table: '%s' (%s)\n", string, ofile->o_name); return 1; } if (vflag > 1) - printf("DoSymbols(): Skipping symbol '%s' (%s) found in OST...\n", symend + index, ofile->o_name); + printf("DoSymbols(): Skipping symbol '%s' (%s) found in OST...\n", string, ofile->o_name); // If the symbol is not in any .a or .o units, it must be one // of the injected ones (_TEXT_E, _DATA_E, or _BSS_E), so skip @@ -230,7 +231,7 @@ int DoSymbols(struct OFILE * ofile) break; default: if (vflag > 1) - printf("DoSymbols: No adjustment made for symbol: %s (%s) = %X\n", symend + index, ofile->o_name, hptr->h_value); + printf("DoSymbols: No adjustment made for symbol: %s (%s) = %X\n", string, ofile->o_name, hptr->h_value); } } } @@ -311,13 +312,13 @@ int DoSymbols(struct OFILE * ofile) if (isglobal(type) || lflag) { if (vflag > 1) - printf("DoSymbols: Adding symbol: %s (%s) to OST...\n", symend + index, ofile->o_name); + printf("DoSymbols: Adding symbol: %s (%s) to OST...\n", string, ofile->o_name); - index = OSTAdd(symend + index, type, value); + index = OSTAdd(index ? string : NULL, type, value); if (index == -1) { - printf("DoSymbols(): Failed to add symbol '%s' to OST!\n", symend + index); + printf("DoSymbols(): Failed to add symbol '%s' to OST!\n", string); return 1; } } @@ -394,127 +395,102 @@ long DoCommon(void) // int OSTAdd(char * name, int type, long value) { - int ost_offset_p, ost_offset_e = 0; // OST table offsets for position calcs + int ost_offset_p = 0, ost_offset_e; // OST table offsets for position calcs int ostresult; // OST index result - int slen = strlen(name); + int slen; // String length, including terminator - // If the OST or OST string table has not been initialised then do so - if (ost_index == 0) + // If this is a debug symbol and the include debug symbol flag (-g) is not + // set then do nothing + if ((type & 0xF0000000) && !gflag) { - ost = malloc(OST_BLOCK); - oststr = malloc(OST_BLOCK); - - if (ost == NULL) - { - printf("OST memory allocation error.\n"); - return -1; - } + // Do nothing + return 0; + } - if (oststr == NULL) - { - printf("OSTSTR memory allocation error.\n"); - return -1; - } + if (!name || !name[0]) + slen = 0; + else + slen = strlen(name) + 1; - ost_ptr = ost; // Set OST start pointer - ost_end = ost + OST_BLOCK; // Set OST end pointer + // Get symbol index in OST, if any (-1 if not found) + ostresult = slen ? OSTLookup(name) : -1; - PutLong(oststr, 0x00000004); // Just null long for now - oststr_ptr = oststr + 4; // Skip size of str table long (incl null long) - PutLong(oststr_ptr, 0x00000000); // Null terminating long - oststr_end = oststr + OST_BLOCK; + // If the symbol is in the output symbol table and the bflag is set + // (don't remove multiply defined locals) and this is not an + // external/global symbol, or the gflag (output debug symbols) is + // set and this a debug symbol, *** OR *** the symbol is not in the + // output symbol table then add it. + if ((ostresult != -1) && !(bflag && !(type & 0x01000000)) + && !(gflag && (type & 0xF0000000))) + { + return ostresult; } - else + + // If the OST has not been initialised, or more space is needed, then + // allocate it. + if ((ost_index + 1) > ost_size) { - // If next symbol record exceeds current allocation then expand symbol - // table and/or symbol string table. - ost_offset_p = (ost_ptr - ost); - ost_offset_e = (ost_end - ost); + if (ost_size == 0) + ost_size = OST_SIZE_INIT; - // 3 x uint32_t (12 bytes) - if ((ost_ptr + 12) > ost_end) - { - // We want to allocate the current size of the OST + another block. - ost = realloc(ost, ost_offset_e + OST_BLOCK); + ost_size *= 2; - if (ost == NULL) - { - printf("OST memory reallocation error.\n"); - return -1; - } + ost = realloc(ost, ost_size * sizeof(ost[0])); - ost_ptr = ost + ost_offset_p; - ost_end = (ost + ost_offset_e) + OST_BLOCK; + if (ost == NULL) + { + printf("OST memory allocation error.\n"); + return -1; } + } + if (slen) + { ost_offset_p = (oststr_ptr - oststr); ost_offset_e = (oststr_end - oststr); - // string length + terminating NULL + uint32_t (terminal long) - if ((oststr_ptr + (slen + 1 + 4)) > oststr_end) + // If the OST data has been exhausted, allocate another chunk. + if (((oststr_ptr + slen + 4) > oststr_end)) { - oststr = realloc(oststr, ost_offset_e + OST_BLOCK); - - if (oststr == NULL) + // string length + terminating NULL + uint32_t (terminal long) + if ((oststr_ptr + (slen + 1 + 4)) > oststr_end) { - printf("OSTSTR memory reallocation error.\n"); - return -1; - } + oststr = realloc(oststr, ost_offset_e + OST_BLOCK); - oststr_ptr = oststr + ost_offset_p; - oststr_end = (oststr + ost_offset_e) + OST_BLOCK; - } - } - - // If this is a debug symbol and the include debug symbol flag (-g) is not - // set then do nothing - if ((type & 0xF0000000) && !gflag) - { - // Do nothing - return 0; - } + if (oststr == NULL) + { + printf("OSTSTR memory reallocation error.\n"); + return -1; + } - // Get symbol index in OST, if any (-1 if not found) - ostresult = OSTLookup(name); + oststr_ptr = oststr + ost_offset_p; + oststr_end = (oststr + ost_offset_e) + OST_BLOCK; - // If the symbol is in the output symbol table and the bflag is set - // (don't remove multiply defined locals) and this is not an - // external/global symbol *** OR *** the symbol is not in the output - // symbol table then add it. - if (((ostresult != -1) && bflag && !(type & 0x01000000)) - || ((ostresult != -1) && gflag && (type & 0xF0000000)) - || (ostresult == -1)) - { - if ((type & 0xF0000000) == 0x40000000) - PutLong(ost_ptr, 0x00000000); // Zero string table offset for dbg line - else - PutLong(ost_ptr, (oststr_ptr - oststr)); // String table offset of symbol string + // On the first alloc, reserve space for the string table + // size field. + if (ost_offset_e == 0) + oststr_ptr += 4; + } + } - PutLong(ost_ptr + 4, type); - PutLong(ost_ptr + 8, value); - ost_ptr += 12; + strcpy(oststr_ptr, name); // Put symbol name in string table + oststr_ptr += slen; + oststr_ptr[-1] = '\0'; // Add null terminating character + PutLong(oststr_ptr, 0x00000000); // Null terminating long + PutLong(oststr, (oststr_ptr - oststr)); // Update size of string table + } - // If the symbol type is anything but a debug line information - // symbol then write the symbol string to the string table - if ((type & 0xF0000000) != 0x40000000) - { - strcpy(oststr_ptr, name); // Put symbol name in string table - *(oststr_ptr + slen) = '\0'; // Add null terminating character - oststr_ptr += (slen + 1); - PutLong(oststr_ptr, 0x00000000); // Null terminating long - PutLong(oststr, (oststr_ptr - oststr)); // Update size of string table - } + ostresult = ost_index++; - if (vflag > 1) - printf("OSTAdd: (%s), type=$%08X, val=$%08lX\n", name, type, value); + ost[ostresult].s_idx = ost_offset_p; + ost[ostresult].s_type = type; + ost[ostresult].s_value = value; -// is ost_index pointing one past? -// does this return the same regardless of if its ++n or n++? -// no. it returns the value of ost_index *before* it's incremented. - return ++ost_index; - } + if (vflag > 1) + printf("OSTAdd: (%s), type=$%08X, val=$%08lX\n", + slen ? name : "", type, value); - return ostresult; + return ost_index; } @@ -525,14 +501,11 @@ int OSTAdd(char * name, int type, long value) int OSTLookup(char * sym) { int i; - int stro = 4; // Offset in string table for(i=0; issize) { - if (fwrite(ost, (ost_ptr - ost), 1, fd) != 1) - goto werror; + for (i = 0; i < ost_index; i++) + { + PutLong(symbol, ost[i].s_idx); + PutLong(symbol + 4, ost[i].s_type); + PutLong(symbol + 8, ost[i].s_value); + + if (fwrite(symbol, 12, 1, fd) != 1) + goto werror; + } if (fwrite(oststr, (oststr_ptr - oststr), 1, fd) != 1) goto werror; @@ -1288,32 +1266,16 @@ int WriteOutputFile(struct OHEADER * header) { memset(symbol, 0, 14); // Initialise symbol record abstype = 0; // Initialise ABS symbol type - slen = 0; // Initialise symbol string length - index = GetLong(ost + (i * 12)); // Get symbol index - type = GetLong((ost + (i * 12)) + 4); // Get symbol type // Skip debug symbols - if (type & 0xF0000000) + if (ost[i].s_type & 0xF0000000) continue; - // Get symbol value - value = GetLong((ost + (i * 12)) + 8); - slen = strlen(oststr + index); - // Get symbol string (maximum 8 chars) - if (slen > 8) - { - for(j=0; j<8; j++) - *(symbol + j) = *(oststr + index + j); - } - else - { - for(j=0; jtsize = textsize; // TEXT segment size header->dsize = datasize; // DATA segment size header->bsize = bsssize; // BSS segment size - header->ssize = (ost_ptr - ost); // Symbol table size - header->ostbase = ost; // Output symbol table base address + header->ssize = ost_index * 12; // Symbol table size + header->ostbase = NULL; // Output symbol table base address // For each object file, relocate its TEXT and DATA segments. OR the result // into ret so all files get moved (and errors reported) before returning diff --git a/rln.h b/rln.h index 7737f4d..9451dfb 100644 --- a/rln.h +++ b/rln.h @@ -250,18 +250,15 @@ struct OFILE // Symbol Record -// SYMREC: Used by builddir for the lists of exports and imports, and by the -// linker for the output symbol table (that's why there are type and value -// fields, unused in builddir) +// SYMREC: Used by the linker for the output symbol table -#define SYMLEN 100 // Symbol name size (incl. null) +#define OST_SIZE_INIT 8 // Half the initial output symbol table size struct SYMREC { - uint8_t s_name[SYMLEN]; // Including null terminator - uint16_t s_type; + uint32_t s_idx; + uint32_t s_type; uint32_t s_value; - struct SYMREC * s_next; }; #define new_symrec() (struct SYMREC *)malloc(sizeof(struct SYMREC)) @@ -272,6 +269,8 @@ struct SYMREC // and Globals share a hash table, but their value fields are interpreted // differently. +#define SYMLEN 100 // Symbol name size (incl. null) + struct HREC { uint8_t h_sym[SYMLEN]; -- 2.37.2 From 0fd021e7f8c8efa56c768945f71144f61b3ef2cf Mon Sep 17 00:00:00 2001 From: James Jones Date: Wed, 13 Jul 2022 15:22:46 -0700 Subject: [PATCH 09/11] Enable debug symbol propagation The existing code was sufficient to pass through and relocate most debug symbols as necessary. It was just disabled for some reason. The only bugs were in the handling of non-text line numbers, which aren't ever used as far as I can tell, and include files, which should be relocated like line numbers to match ALN's behavior. --- rln.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/rln.c b/rln.c index 4ae8d44..212a05c 100644 --- a/rln.c +++ b/rln.c @@ -33,7 +33,6 @@ unsigned dataoffset = 0; // COF DATA segment offset unsigned bssoffset = 0; // COF BSS segment offset unsigned displaybanner = 1; // Display version banner unsigned symoffset = 0; // Symbol table offset in output file -unsigned dbgsymbase = 0; // Debug symbol base address int noheaderflag = 0; // No header flag for ABS files int hflags; // Value of the arg to -h option int ttype, dtype, btype; // Type flag: 0, -1, -2, -3, -4 @@ -245,26 +244,21 @@ int DoSymbols(struct OFILE * ofile) if (type & 0xF0000000) { // DEBUG SYMBOL - // Set the correct debug symbol base address (TEXT segment) -#if 0 - dbgsymbase = 0; - - for(j=0; (unsigned)jsegBase[TEXT]; -#endif - switch (type & 0xFF000000) { - case 0x64000000: - value = tval + dbgsymbase; + case 0x64000000: // Primary source file path and/or name + case 0x84000000: // Included source file path and/or name + case 0x44000000: // Text line number + value = tbase + tsegoffset + value; + break; + case 0x46000000: // Data line number (Not used by GCC/rmac) + value = dbase + dsegoffset + value; break; - case 0x44000000: - case 0x46000000: - case 0x48000000: - value = tval + dbgsymbase + value; + case 0x48000000: // BSS line number (Not used by GCC/rmac) + value = bbase + bsegoffset + value; default: + // All other debug symbols don't need to be relocated + // XXX Not true, but matches ALN behavior. break; } @@ -3133,12 +3127,8 @@ int doargs(int argc, char * argv[]) break; case 'g': case 'G': // Output source level debugging - printf("\'g\' flag not currently implemented\n"); - gflag = 0; - /* if (gflag) warn('g', 1); gflag = 1; - */ break; case 'i': case 'I': // Include binary file -- 2.37.2 From ea99cb44afb302c05585de9139d1a28663686330 Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Mon, 15 Aug 2022 21:32:36 -0500 Subject: [PATCH 10/11] Version bump for latest commits. --- rln.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rln.h b/rln.h index 9451dfb..5625616 100644 --- a/rln.h +++ b/rln.h @@ -44,7 +44,7 @@ #define MAJOR 1 // Major version number #define MINOR 7 // Minor version number -#define PATCH 2 // Patch release number +#define PATCH 3 // Patch release number #ifdef WIN32 #define PLATFORM "Win32" // Release platform - Windows -- 2.37.2 From 8e049701be80210dd41a3b72a3b2daa875baf8ab Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Tue, 16 Aug 2022 12:30:52 -0500 Subject: [PATCH 11/11] Fix for bug #191, thanks to jagmod for the report. --- rln.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rln.h b/rln.h index 5625616..2a51fa9 100644 --- a/rln.h +++ b/rln.h @@ -44,7 +44,7 @@ #define MAJOR 1 // Major version number #define MINOR 7 // Minor version number -#define PATCH 3 // Patch release number +#define PATCH 4 // Patch release number #ifdef WIN32 #define PLATFORM "Win32" // Release platform - Windows @@ -269,7 +269,7 @@ struct SYMREC // and Globals share a hash table, but their value fields are interpreted // differently. -#define SYMLEN 100 // Symbol name size (incl. null) +#define SYMLEN 256 // Symbol name size (incl. null) struct HREC { -- 2.37.2