]> Shamusworld >> Repos - rmac/blobdiff - mark.c
Added in DSP fixups to sect.c, misc. fixes for 6502 assembler.
[rmac] / mark.c
diff --git a/mark.c b/mark.c
index 3b3bd3ada80dd969415089218b95f5b0b59e6e5d..1cb0f05131472f9d097dbdf5fe152ba58ef8c03e 100644 (file)
--- a/mark.c
+++ b/mark.c
 //
-// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// RMAC - Reboot's Macro Assembler for all Atari computers
 // MARK.C - A record of things that are defined relative to any of the sections
-// Copyright (C) 199x Landon Dyer, 2011-2012 Reboot and Friends
+// Copyright (C) 199x Landon Dyer, 2011-2019 Reboot and Friends
 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
-// Source Utilised with the Kind Permission of Landon Dyer
+// Source utilised with the kind permission of Landon Dyer
 //
 
 #include "mark.h"
 #include "error.h"
 #include "object.h"
 #include "riscasm.h"
+#include "sect.h"
 
 
+#define MARK_ALLOC_INCR 1024           // # bytes to alloc for more mark space
+#define MIN_MARK_MEM    (3 * sizeof(uint16_t) + 1 * sizeof(uint32_t) + sizeof(SYM *))
+
 MCHUNK * firstmch;             // First mark chunk
 MCHUNK * curmch;               // Current mark chunk
 PTR markptr;                   // Deposit point in current mark chunk
-LONG mcalloc;                  // #bytes alloc'd to current mark chunk
-LONG mcused;                   // #bytes used in current mark chunk
-uint16_t curfrom;                      // Current "from" section
-
+uint32_t mcalloc;              // # bytes alloc'd to current mark chunk
+uint32_t mcused;               // # bytes used in current mark chunk
+uint16_t curfrom;              // Current "from" section
+
+// Table to convert from TDB to fixup triad
+static uint8_t mark_tr[] = {
+       0,              // (N/A)
+       2,              // TEXT relocatable
+       1, 0,   // DATA relocatable
+       3               // BSS relocatable
+};
 
 //#define DEBUG_IMAGE_MARKING
 
 
 //
-// Initialize Marker
+// Initialize marker
 //
 void InitMark(void)
 {
        firstmch = curmch = NULL;
        mcalloc = mcused = 0;
        curfrom = 0;
+       sect[TEXT].relocs = sect[DATA].relocs = sect[BSS].relocs = 0;
 }
 
 
 //
 // Wrap up marker (called after final mark is made)
 //
-void stopmark(void)
+void StopMark(void)
 {
        if (curmch)
        {
                *markptr.wp = MCHEND;           // Mark end of block
-               curmch->mcused = mcused;        // Update #used in mark block
+               curmch->mcused = mcused;        // Update # used in mark block
        }
 }
 
 
 //
-// Mark a word or longword relocatable
+// Mark a word or longword as relocatable
+//
+// Record is either 2, 3, or 4 pieces of data long. A mark is of the form:
+// .W    <to+flags>    section mark is relative to, and flags in upper byte
+// .L    <loc>         location of mark in "from" section
+// .W    [from]                new from section (if different from current)
+// .L    [symbol]      symbol involved in external reference (if any)
 //
-int rmark(uint16_t from, uint32_t loc, uint16_t to, uint16_t size, SYM * symbol)
+uint32_t MarkRelocatable(uint16_t section, uint32_t loc, uint16_t to, uint16_t flags, SYM * symbol)
 {
 #ifdef DEBUG_IMAGE_MARKING
-printf("rmark: from=%i, loc=$%X, to=$%X, size=$%x, symbol=$%X\n", from, loc, to, size, symbol);
+printf("MarkRelocatable: section=%i, loc=$%X, to=$%X, flags=$%x, symbol=%p\n", section, loc, to, flags, symbol);
 if (symbol)
-       printf("      symbol->stype=$%02X, sattr=$%04X, sattre=$%08X, svalue=%i, sname=%s\n", symbol->stype, symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
+       printf("      symbol->stype=$%02X, sattr=$%04X, sattre=$%08X, svalue=%li, sname=%s\n", symbol->stype, symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
 #endif
 
        if ((mcalloc - mcused) < MIN_MARK_MEM)
-               amark();
+               AllocateMark();
 
-       uint16_t flags = (size | to);
+       // Set up flags
+       flags |= to;
 
-       if (from != curfrom)
+       if (section != curfrom)
                flags |= MCHFROM;
 
        if (symbol != NULL)
                flags |= MSYMBOL;
 
-       mcused += sizeof(WORD) + sizeof(LONG);
+       //
+       // Complain about some things are not allowed in '-p' (PRG) mode:
+       //  o  Marks that aren't to LONGs
+       //  o  External references
+       //
+       if (prg_flag)
+       {
+               if (symbol != NULL)
+                       error("illegal external reference (in .PRG mode) to '%s'",
+                               symbol->sname);
+       }
+
+       // Dump crap into the mark
        *markptr.wp++ = flags;
        *markptr.lp++ = loc;
+       mcused += sizeof(uint16_t) + sizeof(uint32_t);
 
        if (flags & MCHFROM)
        {
-               curfrom = from;
-               *markptr.wp++ = from;
-               mcused += sizeof(WORD);
+               curfrom = section;
+               *markptr.wp++ = section;
+               mcused += sizeof(uint16_t);
        }
 
        if (flags & MSYMBOL)
@@ -86,6 +118,11 @@ if (symbol)
                mcused += sizeof(SYM *);
        }
 
+       // Increment # of relocs in this section
+       sect[section].relocs++;
+
+       // Not sure what this is about (making sure the next mark is clear until
+       // it's marked as the end--I think)...
        *markptr.wp = 0x0000;
 
        return 0;
@@ -95,29 +132,28 @@ if (symbol)
 //
 // Allocate another chunk of mark space
 //
-int amark(void)
+uint32_t AllocateMark(void)
 {
-//     MCHUNK * p;
-
        // Alloc mark block header (and data) and set it up.
-//     p = (MCHUNK *)amem((long)(sizeof(MCHUNK)) + MARK_ALLOC_INCR);
-       MCHUNK * p = (MCHUNK *)malloc(sizeof(MCHUNK) + MARK_ALLOC_INCR);
+       MCHUNK * p = malloc(sizeof(MCHUNK) + MARK_ALLOC_INCR);
        p->mcnext = NULL;
        p->mcalloc = MARK_ALLOC_INCR;
-       p->mcptr.cp = (char *)(((char *)p) + sizeof(MCHUNK));
+       p->mcptr.cp = (uint8_t *)p + sizeof(MCHUNK);
+       p->mcused = 0;
+
+       if (firstmch == NULL)
+               firstmch = p;
 
        if (curmch)
        {
-               // Link onto previous chunk 
-               *markptr.wp++ = MCHEND;         // Mark end of block 
+               // Link onto previous chunk
+               *markptr.wp++ = MCHEND;         // Mark end of block
                curmch->mcused = mcused;
                curmch->mcnext = p;
        }
 
-       if (!firstmch)
-               firstmch = p;
-
-       curmch = p;                                             // Setup global vars 
+       // Setup global vars
+       curmch = p;
        markptr = p->mcptr;
        mcalloc = MARK_ALLOC_INCR;
        mcused = 0;
@@ -127,212 +163,435 @@ int amark(void)
 
 
 //
-// Make mark image for BSD .o file
+// Make mark image for Alcyon .o file
+// okflag: 1, ok to deposit reloc information
 //
-uint32_t bsdmarkimg(char * mp, LONG siz, LONG tsize, int reqseg)
+uint32_t MarkImage(register uint8_t * mp, uint32_t siz, uint32_t tsize, int okflag)
 {
-       MCHUNK * mch;                           // Mark chunk
-       PTR p;                                          // Source point from within mark chunk
-       uint16_t from;                          // Section fixups are currently FROM
-       uint16_t w;                                     // A word (temp)
-       uint32_t loc;                           // Location (temp) 
-       SYM * symbol;                           // Symbols (temp)
-       uint8_t * wp;                           // Pointer into raw relocation info
-       uint8_t * dp;                           // Deposit point for RELMOD info
-       uint32_t diff;                          // Difference to relocate (RELMOD)
-       uint32_t raddr, rflag = 0;      // BSD relocation address and flags
-       uint32_t rsize;                         // Relocation size
-       int validsegment = 0;           // Valid segment being processed
+       uint16_t from = 0;              // Section fixups are currently FROM
+       uint32_t loc;                   // Location (temp)
+       uint32_t lastloc;               // Last location fixed up (RELMOD)
+       uint8_t * wp;                   // Pointer into raw relocation information
+       register uint8_t * dp;  // Deposit point for RELMOD information
 
-#ifdef DEBUG_IMAGE_MARKING
-printf("bsdmarkimg():\n");
-#endif
-       // Initialise relocation size
-       rsize = 0;
-       chptr = mp;
-       from = 0;
+       if (okflag)
+               memset(mp, 0, siz);             // zero relocation buffer
 
-       for(mch=firstmch; mch!=NULL; mch=mch->mcnext)
+       for(MCHUNK * mch=firstmch; mch!=NULL; mch=mch->mcnext)
        {
-               for(p=mch->mcptr;;)
+               for(PTR p=mch->mcptr;;)
                {
-                       w = *p.wp++;                    // Next mark entry
+                       uint16_t w = *p.wp++;// w = next mark entry
 
-                       if (w & MCHEND)
-                               break;                          // End of mark chunk
+                       if (w & MCHEND)         // (end of mark chunk)
+                               break;
 
                        // Get mark record
-                       symbol = NULL;
-                       loc = *p.lp++;                  // Mark location
+                       SYM * symbol = NULL;
+                       loc = *p.lp++;          // mark location
 
-                       if (w & MCHFROM)
-                       {
-                               // Maybe change "from" section
+                       if (w & MCHFROM)        // maybe change "from" section
                                from = *p.wp++;
 
-                               if (obj_format == BSD)
+                       if (w & MSYMBOL)        // maybe includes a symbol
+                               symbol = *p.sy++;
+
+                       // Compute mark position in relocation information; in RELMOD mode,
+                       // get address of data to fix up.
+                       if (from == DATA)
+                               loc += tsize;
+
+                       wp = (uint8_t *)(mp + loc);
+
+                       if (okflag && (w & MLONG)) // indicate first word of long
+                       {
+                               wp[1] = 5;
+                               wp += 2;
+                       }
+
+                       if (symbol)
+                       {
+                               // Deposit external reference
+                               if (okflag)
                                {
-                                       if (reqseg == TEXT)
-                                       {
-                                               // Requested segment is TEXT
-                                               if (from == TEXT)
-                                                       validsegment = 1; 
-                                               else
-                                                       validsegment = 0;
-                                       }
+                                       if (w & MPCREL)
+                                               w = 6;          // PC-relative fixup
                                        else
-                                       {
-                                               // Requested segment is DATA
-                                               if (from == DATA)
-                                                       validsegment = 1; 
-                                               else
-                                                       validsegment = 0;
-                                       }
+                                               w = 4;          // Absolute fixup
+
+                                       w |= symbol->senv << 3;
+                                       *wp++ = w >> 8;
+                                       *wp = (uint8_t)w;
                                }
                        }
+                       else
+                       {
+                               // Deposit section-relative mark; in RELMOD mode, fix it up in
+                               // the chunk, kind of like a sleazoid linker.
+                               //
+                               // In RELMOD mode, marks to words (MWORDs) "cannot happen,"
+                               // checks are made when mark() is called, so we don't have to
+                               // check again here.
+                               w &= TDB;
+
+                               if (okflag)
+                                       wp[1] = mark_tr[w];
+                               else if (prg_flag && (w & (DATA | BSS)))
+                               {
+                                       uint32_t diff = GETBE32(wp, 0);
+#ifdef DO_DEBUG
+                                       DEBUG printf("diff=%lx ==> ", diff);
+#endif
+                                       diff += sect[TEXT].sloc;
 
-                       if (w & MSYMBOL)                        // Maybe includes a symbol
-                               symbol = *p.sy++;
+                                       if (w == BSS)
+                                               diff += sect[DATA].sloc;
 
-                       if (obj_format == BSD)
+                                       SETBE32(wp, 0, diff)
+#ifdef DO_DEBUG
+                                       DEBUG printf("%lx\n", diff);
+#endif
+                               }
+                       }
+               }
+       }
+
+       // Generate ".PRG" relocation information in place in the relocation words
+       // (the "RELMOD" operation).
+       if (okflag && prg_flag)
+       {
+               int firstp = 1;
+               wp = dp = mp;
+
+               for(loc=0; loc<siz;)
+               {
+                       if ((wp[1] & 7) == 5)
                        {
-                               raddr = loc;                    // Set relocation address
+                               if (firstp)
+                               {
+                                       SETBE32(dp, 0, loc);
+                                       dp += 4;
+                                       firstp = 0;
+                               }
+                               else
+                               {
+                                       uint32_t diff;
 
-                               if (validsegment)
-#ifdef DEBUG_IMAGE_MARKING
+                                       for(diff=loc-lastloc; diff>254; diff-=254)
+                                               *dp++ = 1;
+
+                                       *dp++ = (uint8_t)diff;
+                               }
+
+                               lastloc = loc;
+                               loc += 4;
+                               wp += 4;
+                       }
+                       else
+                       {
+                               loc += 2;
+                               wp += 2;
+                       }
+               }
+
+               // Terminate relocation list with 0L (if there was no relocation) or
+               // 0.B (if relocation information was written).
+               if (!firstp)
+                       *dp++ = 0;
+               else
+                       for(firstp=0; firstp<4; firstp++)
+                               *dp++ = 0;
+
+               // Return size of relocation information
+               loc = dp - mp;
+               return loc;
+       }
+
+       return siz;
+}
+
+
+//
+// Make mark image for BSD .o file
+//
+// Assumptions about mark records (for BSD): if there is a symbol, the mark is
+// for an undefined symbol, otherwise it's just a normal TDB relocation.
+// N.B.: tsize is only used if reqseg is DATA
+//
+uint32_t MarkBSDImage(uint8_t * mp, uint32_t siz, uint32_t tsize, int reqseg)
 {
-printf(" validsegment: raddr = $%08X\n", raddr);
-#endif
-                                       D_long(raddr);          // Write relocation address
+       uint16_t from = 0;                      // Section fixups are currently FROM
+       uint32_t rsize = 0;                     // Relocation table size (written to mp)
+       int validsegment = 0;           // We are not yet in a valid segment...
+
 #ifdef DEBUG_IMAGE_MARKING
-}
+printf("MarkBSDImage():\n");
 #endif
+       // Initialize relocation table point (for D_foo macros)
+       chptr = mp;
 
-                               if (w & MPCREL)
-                                       rflag = 0x000000A0;     // PC-relative fixup
+       // Run through all the relocation mark chunks
+       for(MCHUNK * mch=firstmch; mch!=NULL; mch=mch->mcnext)
+       {
+               for(PTR p=mch->mcptr;;)
+               {
+                       SYM * symbol = NULL;
+                       uint16_t w = *p.wp++;   // Next mark entry
+
+                       // If we hit the end of a chunk, go get the next one
+                       if (w & MCHEND)
+                               break;
+
+                       // Get the rest of the mark record
+                       uint32_t loc = *p.lp++; // Mark location
+
+                       // Maybe change "from" section
+                       if (w & MCHFROM)
+                       {
+                               from = *p.wp++;
+
+                               if (((reqseg == TEXT) && (from == TEXT))
+                                       || ((reqseg == DATA) && (from == DATA)))
+                                       validsegment = 1;
                                else
-                                       rflag = 0x00000040;     // Absolute fixup
-
-// This flag tells the linker to WORD swap the LONG when doing the fixup.
-                               if (w & MMOVEI)
-//{
-//printf("bsdmarkimg: ORing $01 to rflag (MMOVEI) [symbol=%s]...\n", symbol->sname);
-                                       rflag |= 0x00000001;
-//}
+                                       validsegment = 0;
                        }
 
-                       // Compute mark position in relocation information;
-                       // in RELMOD mode, get address of data to fix up.
-                       if (from == DATA)
-                               loc += tsize;
+                       // Maybe includes a symbol
+                       if (w & MSYMBOL)
+                               symbol = *p.sy++;
 
-                       wp = (uint8_t *)(mp + loc);
+                       if (!validsegment)
+                               continue;
 
-                       if (symbol)
+#ifdef DEBUG_IMAGE_MARKING
+printf(" validsegment: raddr = $%08X\n", loc);
+#endif
+                       uint32_t rflag = 0x00000040;    // Absolute relocation
+
+                       if (w & MPCREL)
+                               rflag = 0x000000A0;                     // PC-relative relocation
+
+                       // This flag tells the linker to WORD swap the LONG when doing the
+                       // relocation.
+                       if (w & MMOVEI)
+                               rflag |= 0x00000001;
+
+                       // This tells the linker to do a WORD relocation (otherwise it
+                       // defaults to doing a LONG, throwing things off for WORD sized
+                       // fixups)
+                       if (!(w & (MLONG | MQUAD)))
+                               rflag |= 0x00000002;
+
+                       // Tell the linker that the fixup is an OL QUAD data address
+                       if (w & MQUAD)
+                               rflag |= 0x00000004;
+
+                       if (symbol != NULL)
                        {
                                // Deposit external reference
-                               if (obj_format == BSD)
-                               {
-                                       rflag |= 0x00000010;                    // Set external reloc flag bit
-                                       rflag |= (symbol->senv << 8);   // Put symbol index in flags
+                               rflag |= 0x00000010;                    // Set external reloc flag bit
+                               rflag |= (symbol->senv << 8);   // Put symbol index in flags
 
-// Looks like this is completely unnecessary (considering it does the wrong thing!)
-#if 0
-                                       if (symbol->sattre & RISCSYM)
-{
-printf("bsdmarkimg: ORing $01 to rflag (RISCSYM) [symbol=%s]...\n", symbol->sname);
-                                               rflag |= 0x00000001;
-}
-#endif
-
-                                       if (validsegment)
-                                       {
 #ifdef DEBUG_IMAGE_MARKING
 printf("  validsegment(2): rflag = $%08X\n", rflag);
 #endif
-                                               D_long(rflag);                          // Write relocation flags
-                                               rsize += 8;                                     // Increment relocation size
-                                       }
-                               }
                        }
                        else
                        {
-                               if (obj_format == BSD)
-                               {
 #ifdef DEBUG_IMAGE_MARKING
 printf("  w = $%04X\n", w);
 #endif
-                                       w &= TDB;                                               // Set reloc flags to segment
+                               w &= TDB;                               // Set reloc flags to segment
 
-                                       switch (w)
-                                       {
-                                       case TEXT: rflag |= 0x00000400; break;
-                                       case DATA: rflag |= 0x00000600; break;
-                                       case BSS:  rflag |= 0x00000800; break;
-                                       }
+                               switch (w)
+                               {
+                               case TEXT: rflag |= 0x00000400; break;
+                               case DATA: rflag |= 0x00000600; break;
+                               case BSS:  rflag |= 0x00000800; break;
+                               }
 
-                                       if (validsegment)
-                                       {
 #ifdef DEBUG_IMAGE_MARKING
 printf("  validsegment(3): rflag = $%08X\n", rflag);
 #endif
-                                               D_long(rflag);                          // Write relocation flags
-                                               rsize += 8;                                     // Increment relocation size
-                                       }
+                               // Fix relocation by adding in start of TEXT segment, since it's
+                               // currently relative to the start of the DATA (or BSS) segment
+                               if (w & (DATA | BSS))
+                               {
+                                       uint8_t * dp = objImage + BSDHDRSIZE + loc;
+                                       uint32_t olBitsSave = 0;
+
+                                       // Bump the start of the section if it's DATA (& not TEXT)
+                                       if (from == DATA)
+                                               dp += tsize;
 
-                                       w &= TDB;
+                                       uint32_t diff = (rflag & 0x02 ? GETBE16(dp, 0) : GETBE32(dp, 0));
 
-                                       if (validsegment)
+                                       // Special handling for OP (data addr) relocation...
+                                       if (rflag & 0x04)
                                        {
-                                               if (w & (DATA|BSS))
-                                               {
-                                                       dp = objimage + BSDHDRSIZE + loc;
-                                                       diff = ((LONG)(*dp++ & 0xFF)) << 24;
-                                                       diff |= ((LONG)(*dp++ & 0xFF)) << 16;
-                                                       diff |= ((LONG)(*dp++ & 0xFF)) << 8;
-                                                       diff |= (LONG)(*dp & 0xFF);
-                                                       DEBUG printf("diff=%ux ==> ", diff);
+                                               olBitsSave = diff & 0x7FF;
+                                               diff = (diff & 0xFFFFF800) >> 8;
+                                       }
+
+                                       DEBUG printf("diff=%uX ==> ", diff);
+#ifdef DEBUG_IMAGE_MARKING
+printf("  validsegment(4): diff = $%08X ", diff);
+#endif
+                                       if (rflag & 0x01)
+                                               diff = WORDSWAP32(diff);
+
 #ifdef DEBUG_IMAGE_MARKING
-printf("  validsegment(4): diff = $%08X --> ", diff);
+printf("(sect[TEXT].sloc=$%X) --> ", sect[TEXT].sloc);
 #endif
-       
-                                                       if (rflag & 0x01)
-                                                               diff = ((diff >> 16) & 0x0000FFFF) | ((diff << 16) & 0xFFFF0000);
+                                       diff += sect[TEXT].sloc;
 
-                                                       diff += sect[TEXT].sloc;
+                                       if (w == BSS)
+                                               diff += sect[DATA].sloc;
 
-                                                       if (w == BSS)
-                                                               diff += sect[DATA].sloc;
+                                       if (rflag & 0x01)
+                                               diff = WORDSWAP32(diff);
 
-                                                       if (rflag & 0x01)
-                                                               diff = ((diff >> 16) & 0x0000FFFF) | ((diff << 16) & 0xFFFF0000);
+                                       // Make sure to deposit the correct size payload
+                                       // N.B.: The braces around the SETBExx macros are needed
+                                       //       because the macro supplies its own set of braces,
+                                       //       thus leaving a naked semicolon afterwards to
+                                       //       screw up the if/else structure. This is the price
+                                       //       you pay when using macros pretending to be code.
+                                       if (rflag & 0x02)               // WORD relocation
+                                       {
+                                               SETBE16(dp, 0, diff);
+                                       }
+                                       else if (rflag & 0x04)  // OP data address relocation
+                                       {
+                                               // We do it this way because we might have an offset
+                                               // that is not a multiple of 8 and thus we need this in
+                                               // place to prevent a bad address at link time. :-P As
+                                               // a consequence of this, the highest address we can
+                                               // have here is $1FFFF8.
+                                               uint32_t diffsave = diff;
+                                               diff = ((diff & 0x001FFFFF) << 11) | olBitsSave;
+                                               SETBE32(dp, 0, diff);
+                                               // But we need those 3 bits, otherwise we can get in
+                                               // trouble with things like OL data that is in the cart
+                                               // space, and BOOM! So the 2nd phrase of the fixup (it
+                                               // will *always* have a 2nd phrase) has a few spare
+                                               // bits, we chuck them in there.
+                                               uint32_t p2 = GETBE32(dp, 8);
+                                               p2 &= 0x1FFFFFFF;
+                                               p2 |= (diffsave & 0x00E00000) << 8;
+                                               SETBE32(dp, 8, p2);
+                                       }
+                                       else                                    // LONG relocation
+                                       {
+                                               SETBE32(dp, 0, diff);
+                                       }
 
-                                                       dp = objimage + BSDHDRSIZE + loc;
-                                                       *dp++ = (char)(diff >> 24);
-                                                       *dp++ = (char)(diff >> 16);
-                                                       *dp++ = (char)(diff >> 8);
-                                                       *dp = (char)diff;
-                                                       DEBUG printf("%ux\n", diff);
+                                       DEBUG printf("%uX\n", diff);
 #ifdef DEBUG_IMAGE_MARKING
 printf("$%08X\n", diff);
 #endif
-                                               }
-                                       }
                                }
                        }
+
+                       D_long(loc);            // Write relocation address
+                       D_long(rflag);          // Write relocation flags
+                       rsize += 0x08;          // Increment relocation size
                }
        }
 
-       // Return relocation size
-       if (obj_format == BSD)
+       // Return relocation table's size
 #ifdef DEBUG_IMAGE_MARKING
-{
 printf("  rsize = $%X\n", rsize);
 #endif
-               return rsize;                                        
-#ifdef DEBUG_IMAGE_MARKING
+       return rsize;
 }
-#endif
 
-       return siz;
+
+//
+// Make relocation record for ELF .o file.
+// Returns the size of the relocation record.
+//
+uint32_t CreateELFRelocationRecord(uint8_t * buf, uint8_t * secBuf, uint16_t section)
+{
+       uint16_t from = 0;              // Section fixups are currently FROM
+       uint32_t rsize = 0;             // Size of the relocation table
+
+       // Setup pointer for D_long/word/byte macros
+       chptr = buf;
+       ch_size = 0;
+
+       for(MCHUNK * mch=firstmch; mch!=NULL; mch=mch->mcnext)
+       {
+               for(register PTR p=mch->mcptr;;)
+               {
+                       register uint16_t w = *p.wp++;  // w = next mark entry
+
+                       if (w & MCHEND)         // (end of mark chunk)
+                               break;
+
+                       // Get mark record
+                       SYM * symbol = NULL;
+                       uint16_t symFlags = 0;
+                       uint32_t r_offset = *p.lp++;    // Mark's location
+
+                       if (w & MCHFROM)                // Maybe change "from" section
+                               from = *p.wp++;
+
+                       if (w & MSYMBOL)                // Maybe includes a symbol
+                       {
+                               symbol = *p.sy++;
+
+                               if (symbol)
+                                       symFlags = symbol->sattr;
+                       }
+
+                       // Create relocation record for ELF object, if the mark is in the
+                       // current section.
+                       if (from & section)
+                       {
+                               uint32_t r_sym = 0;
+                               uint32_t r_type = 0;
+                               uint32_t r_addend = 0;
+
+                               // Since we're chucking all symbols here for ELF objects by
+                               // default (cf. sect.c), we discriminate here (normally, if
+                               // there is a symbol in the mark record, it means an undefined
+                               // symbol) :-P
+                               if (symbol && !(symFlags & DEFINED) && (symFlags & GLOBAL))
+                                       r_sym = symbol->senv + extraSyms;
+                               else if (w & TEXT)
+                                       r_sym = elfHdrNum[ES_TEXT];     // Mark TEXT segment
+                               else if (w & DATA)
+                                       r_sym = elfHdrNum[ES_DATA];     // Mark DATA segment
+                               else if (w & BSS)
+                                       r_sym = elfHdrNum[ES_BSS];      // Mark BSS segment
+
+                               // Set the relocation type next
+                               if (w & MPCREL)
+                                       r_type = 5;  // R_68K_PC16
+                               // N.B.: Since we've established that (from & section) is non-
+                               //       zero, this condition will *never* be satisfied... :-P
+                               //       It might be better to check the symbol's senv; that is,
+                               //       if this is a real problem that needs addressing...
+                               else if ((from & section) == 0)
+                                       // In the case of a section referring to a label in another
+                                       // section (for example text->data) use a R_68K_PC32 mark.
+                                       r_type = 4;  // R_68K_PC32
+                               else
+                                       r_type = 1;  // R_68K_32
+
+                               r_addend = GETBE32(secBuf + r_offset, 0);
+
+                               // Deposit the relocation record
+                               D_long(r_offset);
+                               D_long(((r_sym << 8) | r_type));
+                               D_long(r_addend);
+                               rsize += 0x0C;
+                       }
+               }
+       }
+
+       return rsize;
 }
+