Introducing new switch -fr which outputs binaries assembled at a given address.
authorggn <ggn.dbug@gmail.com>
Thu, 9 Jan 2020 09:40:02 +0000 (11:40 +0200)
committerShamus Hammons <jlhamm@acm.org>
Fri, 10 Jan 2020 15:04:35 +0000 (09:04 -0600)
direct.c
docs/rmac.rst
mark.c
mark.h
object.c
rmac.c
rmac.h
sect.c

index b3f51f3c3b73356c638a0dc9b087cc20f67ab58d..4e9cffd350cb1603bb01a34b58e2bf18cb55c676 100644 (file)
--- a/direct.c
+++ b/direct.c
@@ -154,7 +154,7 @@ int (*dirtab[])() = {
        d_nofpu,                        // 65 nofpu
        d_opt,                          // 66 .opt
        d_objproc,                      // 67 .objproc
-       d_dsm,                          // 68 .dsm
+       (void *)d_dsm,                  // 68 .dsm
 };
 
 
@@ -221,8 +221,8 @@ int d_org(void)
 {
        uint64_t address;
 
-       if (!rgpu && !rdsp && !robjproc && !m6502 && !dsp56001)
-               return error(".org permitted only in GPU/DSP/OP, 56001 and 6502 sections");
+       if (!rgpu && !rdsp && !robjproc && !m6502 && !dsp56001 && !(obj_format == RAW))
+               return error(".org permitted only in GPU/DSP/OP, 56001, 6502 and 68k (with -fr switch) sections");
 
        // M56K can leave the expression off the org for some reason :-/
        // (It's because the expression is non-standard, and so we have to look at
@@ -346,6 +346,17 @@ int d_org(void)
 // N.B.: It seems that by enabling this, even though it works elsewhere, will cause symbols to royally fuck up.  Will have to do some digging to figure out why.
 //             orgactive = 1;
        }
+       else
+       {
+               // If we get here we assume it's 68k with RAW output, so this is allowed
+               if (orgactive)
+               {
+                       return error("In 68k mode only one .org statement is allowed");
+               }
+
+               org68k_address = address;
+               org68k_active = 1;
+       }
 
        ErrorIfNotAtEOL();
        return 0;
index aeb1df423a68bf69439fe0811e3e4a75893a7564..0a2e73768365ac08d968fa36619caa83dfb71e7c 100644 (file)
@@ -4,7 +4,7 @@ RMAC
 =====================
 Reference Manual
 ================
-version 2.0.4
+version 2.0.8
 =============
 
 © and notes
@@ -123,6 +123,7 @@ Switch               Description
 -fa                  ALCYON output object file format (implied when **-ps** is enabled).
 -fb                  BSD COFF output object file format.
 -fe                  ELF output object file format.
+-fr                  Absolute address. Source code is required to have one .org statement.
 -fx                  Atari 800 com/exe/xex output object file format.
 -i\ *path*           Set include-file directory search path.
 -l\ *[file[prn]]*    Construct and direct assembly listing to the specified file.
@@ -153,8 +154,8 @@ Switch               Description
 
                       -o\ *file[.o]*       Direct object code output to the specified file.
 +/~oall              Turn all optimisations on/off
-+o\ *0-7*            Enable specific optimisation
-~o\ *0-7*            Disable specific optimisation
++o\ *0-9*            Enable specific optimisation
+~o\ *0-9*            Disable specific optimisation
 
                       `0: Absolute long adddresses to word`
                       
@@ -625,9 +626,15 @@ and may not be used as symbols (e.g. labels, equates, or the names of macros):
       r0 r1 r2 r3 r4 r5 r6 r7
       r8 r9 r10 r11 r12 rl3 r14 ri5
       6502:
-      **TODO**
+      x y a
       DSP56001:
-      **TODO**
+      x x0 x1 x2 y y0 y1 y2
+      a a0 a1 a2 b b0 b1 b2 ab ba
+      mr omr la lc ssh ssl ss
+      n0 n1 n2 n3 n4 n5 n6 n7
+      m0 m1 m2 m3 m4 m5 m6 m7
+      r0 r1 r2 r3 r4 r5 r6 r7
+      
 
 `Constants`_
 ''''''''''''
@@ -998,6 +1005,13 @@ described in the chapter on `6502 Support`_.
 
    Switch to Motorola DSP56001 mode.
 
+**.org** *location* [*X:*/*Y:*/*P:*/*L:*]
+   This directive sets the value of the location counter (or **pc**) to location, an
+   expression that must be defined and absolute. It is legal to use the directive in
+   the following modes: 6502, Tom, Jerry, OP, 56001 and 680x0 (only with -fr switch).
+   Especially for the 56001 mode the *location* field **must** be prefixed with the
+   intended section (*X:*, *Y:*, *P:* or *L:*).
+   
 **.abs** [*location*]
 
    Start an absolute section, beginning with the specified location (or zero, if
@@ -1913,7 +1927,7 @@ Atari Falcon XBIOS) and *.p56* (binary equivalent of *.lod*)
 - Motorola's assembler allows reordering of addressing modes **x:**, **x:r**,
   **r:y**, **x:y**. rmac will only accept syntax as is defined on the reference
   manual.
-- In **l:** section a dc value cannot be 12 hex digits like Motorola's assmebler.
+- In **L:** section a dc value cannot be 12 hex digits like Motorola's assmebler.
   Instead, the value needs to be split into two parts separated by **:**.
 
 `6502 Support`_
@@ -1966,7 +1980,7 @@ y,\ *expr*     indexed Y
    This directive leaves the 6502 segment and returns to the 68000's text segment.
    68000 instructions may be assembled as normal.
 **.org** *location*
-   This directive is only legal in the 6502 section. It sets the value of the location
+   This directive sets the value of the location
    counter (or **pc**) to location, an expression that must be defined, absolute, and
    less than $10000.
 
@@ -2084,10 +2098,6 @@ order, along with a short description of what may have caused the problem.
 
     You tried to use ``.init`` in the BSS or ABS section.
 
-**.org permitted only in .6502 section**
-
-    You tried to use ``.org`` in a 68000 section.
-
 **Cannot create:** *filename*
 
     The assembler could not create the indicated filename.
diff --git a/mark.c b/mark.c
index 6d69c6a2a7d1b1b1812a2b774b1c6315f6ac235f..ebd798353017e057b4f32e3bbfe25b973e4a8afe 100644 (file)
--- a/mark.c
+++ b/mark.c
@@ -508,6 +508,161 @@ printf("  rsize = $%X\n", rsize);
 }
 
 
+//
+// Make mark image for RAW file
+//
+uint32_t MarkABSImage(uint8_t * mp, uint32_t siz, uint32_t tsize, int reqseg)
+{
+       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...
+
+       // Initialize relocation table point (for D_foo macros)
+       chptr = mp;
+
+       // 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
+                                       validsegment = 0;
+                       }
+
+                       // Maybe includes a symbol
+                       if (w & MSYMBOL)
+                               symbol = *p.sy++;
+
+                       if (!validsegment)
+                               continue;
+
+                       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)
+                       {
+                               return error("Unresolved symbol when outputting raw image");
+                       }
+                       else
+                       {
+                               w &= TDB;                               // Set reloc flags to segment
+
+                               switch (w)
+                               {
+                               case TEXT: rflag |= 0x00000400; break;
+                               case DATA: rflag |= 0x00000600; break;
+                               case BSS:  rflag |= 0x00000800; break;
+                               }
+
+                               // Fix relocation by adding in start of TEXT segment, since it's
+                               // currently relative to the start of the DATA (or BSS) segment
+                               uint8_t * dp = objImage + loc;
+                               uint32_t olBitsSave = 0;
+
+                               // Bump the start of the section if it's DATA (& not TEXT)
+                               if (from == DATA)
+                                       dp += tsize;
+
+                               uint32_t diff = (rflag & 0x02 ? GETBE16(dp, 0) : GETBE32(dp, 0));
+
+                               if (w & (DATA | BSS))
+                               {
+                                       // Special handling for OP (data addr) relocation...
+                                       if (rflag & 0x04)
+                                       {
+                                               olBitsSave = diff & 0x7FF;
+                                               diff = (diff & 0xFFFFF800) >> 8;
+                                       }
+
+                                       if (rflag & 0x01)
+                                               diff = WORDSWAP32(diff);
+
+                                       diff += sect[TEXT].sloc;
+
+                                       if (w == BSS)
+                                               diff += sect[DATA].sloc;
+                               }
+                               if ((rflag & 0x02) == 0)
+                               {
+                                       diff += org68k_address;
+                               }
+
+                               if (rflag & 0x01)
+                                       diff = WORDSWAP32(diff);
+                
+                               // Make sure to deposit the correct size payload
+                               // Check comments in MarkBSDImage for more candid moments
+                               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);
+                               }
+                       }
+               }
+       }
+
+       return OK;
+}
+
+
 //
 // Make relocation record for ELF .o file.
 // Returns the size of the relocation record.
diff --git a/mark.h b/mark.h
index c408b14c0307103d8da010cd54403435147129e6..e185c2489297fffdb91520d9431fbef1372f9e77 100644 (file)
--- a/mark.h
+++ b/mark.h
@@ -52,6 +52,7 @@ uint32_t AllocateMark(void);
 uint32_t MarkImage(register uint8_t * mp, uint32_t siz, uint32_t tsize, int okflag);
 uint32_t MarkBSDImage(uint8_t *, uint32_t, uint32_t, int);
 uint32_t CreateELFRelocationRecord(uint8_t *, uint8_t *, uint16_t section);
+uint32_t MarkABSImage(uint8_t * mp, uint32_t siz, uint32_t tsize, int reqseg);
 
 #endif // __MARK_H__
 
index 0828eff69dad2c5dad86d5702268dafb42e356d8..7545866fd8a9f10106aad0adf726715fb0f951d4 100644 (file)
--- a/object.c
+++ b/object.c
@@ -327,7 +327,9 @@ int WriteObject(int fd)
 
        // Write requested object file...
        if ((obj_format == BSD) || ((obj_format == ALCYON) && (prg_flag == 0)))
-    {
+       {
+               ch_size = 0;
+
                // Force BSD format (if it was ALCYON format)
                obj_format = BSD;
 
@@ -425,6 +427,8 @@ int WriteObject(int fd)
        }
        else if (obj_format == ALCYON)
        {
+               ch_size = 0;
+
                if (verb_flag)
                {
                        if (prg_flag)
@@ -435,6 +439,7 @@ int WriteObject(int fd)
 
                // Assign index numbers to the symbols, get # of symbols (we assume
                // that all symbols can potentially be extended, hence the x28)
+               // (To clarify: 28 bytes is the size of an extended symbol)
                uint32_t symbolMaxSize = sy_assign(NULL, NULL) * 28;
 
                // Alloc memory for header + text + data, symbol and relocation
@@ -807,13 +812,52 @@ for(int j=0; j<i; j++)
                else
                        WriteP56();
 
-               // Write all the things |o/
+               // Write all the things \o/
                unused = write(fd, buf, chptr - buf);
 
                if (buf)
                        free(buf);
        }
+       else if (obj_format == RAW)
+       {
+               if (!org68k_active)
+               {
+                       return error("cannot output absolute binary without a starting address (.org or command line)");
+               }
+
+               // Alloc memory for text + data construction.
+               tds = sect[TEXT].sloc + sect[DATA].sloc;
+               buf = malloc(tds);
+               chptr = buf;
+
+               // Construct text and data segments; fixup relocatable longs;
+               // finally write the text + data
+
+               p = buf;
+               objImage = buf;                                 // Set global object image pointer
+
+               for (i = TEXT; i <= DATA; i++)
+               {
+                       for (cp = sect[i].sfcode; cp != NULL; cp = cp->chnext)
+                       {
+                               memcpy(p, cp->chptr, cp->ch_size);
+                               p += cp->ch_size;
+                       }
+               }
+
+               if (MarkABSImage(buf, tds, sect[TEXT].sloc, TEXT) != OK)  // Do TEXT relocation table
+               {
+                       return ERROR;
+               }
+               if (MarkABSImage(buf, tds, sect[TEXT].sloc, DATA) != OK) // Do DATA relocation table
+               {
+                       return ERROR;
+               }
 
+               // Write out the header + text & data + symbol table (if any)
+               unused = write(fd, buf, tds);
+
+       }
        return 0;
 }
 
diff --git a/rmac.c b/rmac.c
index 1111d6d64053ac5901cea5b35e0991db71372538..087225eec049263c548aba1dd0cac2654f412c58 100644 (file)
--- a/rmac.c
+++ b/rmac.c
@@ -55,7 +55,8 @@ char defname[] = "noname.o";  // Default output filename
 int optim_flags[OPT_COUNT];            // Specific optimisations on/off matrix
 int activecpu = CPU_68000;             // Active 68k CPU (68000 by default)
 int activefpu = FPU_NONE;              // Active FPU (none by default)
-
+int org68k_active = 0;                 // .org switch for 68k (only with RAW output format)
+uint32_t org68k_address;               // .org for 68k
 
 //
 // Convert a string to uppercase
@@ -152,6 +153,7 @@ void DisplayHelp(void)
                "                    p: P56 (use this for DSP56001 only)\n"
                "                    l: LOD (use this for DSP56001 only)\n"
                "                    x: com/exe/xex (Atari 800)\n"
+               "                    r: absolute address"
                "  -i[path]          Directory to search for include files\n"
                "  -l[filename]      Create an output listing file\n"
                "  -l*[filename]     Create an output listing file without pagination\n"
@@ -174,10 +176,9 @@ void DisplayHelp(void)
                "  ~o[value]         Turn a specific optimisation off\n"
                "  +oall             Turn all optimisations on\n"
                "  ~oall             Turn all optimisations off\n"
-               "  -p                Create an ST .prg (without symbols)\n"
-               "  -ps               Create an ST .prg (with symbols)\n"
-               "  -px               Create an ST .prg (with exsymbols)\n"
-               "                    Forces -fa\n"
+               "  -p                Create an ST .prg (without symbols). Forces -fa\n"
+               "  -ps               Create an ST .prg (with symbols). Forces -fa\n"
+               "  -px               Create an ST .prg (with exsymbols). Forces -fa\n"
                "  -r[size]          Pad segments to boundary size specified\n"
                "                    w: word (2 bytes, default alignment)\n"
                "                    l: long (4 bytes)\n"
@@ -368,6 +369,10 @@ int Process(int argc, char ** argv)
                                case 'X':
                                        obj_format = XEX;
                                        break;
+                case 'r':           // -fr = Absolute address
+                case 'R':
+                    obj_format = RAW;
+                    break;
                                default:
                                        printf("-f: unknown object format specified\n");
                                        errcnt++;
diff --git a/rmac.h b/rmac.h
index 52fb92ddd355621645fe812b9f60a6839d74baa2..5ae6d13f76f15a9ced6144513909c4dd204a7101 100644 (file)
--- a/rmac.h
+++ b/rmac.h
 enum
 {
 ALCYON,                                // Alcyon/DRI C object format
-MWC,                           // Mark Williams object format
 BSD,                           // BSD object format
 ELF,                           // ELF object format
 LOD,                           // DSP 56001 object format
 P56,                           // DSP 56001 object format
 XEX,                           // COM/EXE/XEX/whatever a8 object format
+RAW,                           // Output at absolute address
 };
 
 // Assembler token
@@ -318,6 +318,8 @@ extern LONG PRGFLAGS;
 extern int optim_flags[OPT_COUNT];
 extern int activecpu;
 extern int activefpu;
+extern uint32_t org68k_address;
+extern int org68k_active;
 
 // Exported functions
 void strtoupper(char * s);
diff --git a/sect.c b/sect.c
index 4dc7032c4c34a7834626589daf4f9eefa6c0df82..0ea53a843f1c4568dec445fcab7c7f3a179ed014 100644 (file)
--- a/sect.c
+++ b/sect.c
@@ -450,9 +450,6 @@ int ResolveFixups(int sno)
                // from the location (that will happen in the linker when the external
                // reference is resolved).
                //
-               // MWC expects PC-relative things to have the LOC subtracted from the
-               // value, if the value is external (that is, undefined at this point).
-               //
                // PC-relative fixups must be DEFINED and either in the same section
                // (whereupon the subtraction takes place) or ABS (with no subtract).
                if ((dw & FU_PCREL) || (dw & FU_PCRELX))
@@ -470,7 +467,7 @@ int ResolveFixups(int sno)
                                else if (tdb)
                                {
                                        // Allow cross-section PCREL fixups in Alcyon mode
-                                       if (prg_flag)
+                                       if (prg_flag || (obj_format == RAW))
                                        {
                                                switch (tdb)
                                                {
@@ -504,14 +501,6 @@ int ResolveFixups(int sno)
                                if (sbra_flag && (dw & FU_LBRA) && (eval + 0x80 < 0x100))
                                        warn("unoptimized short branch");
                        }
-                       else if (obj_format == MWC)
-                       {
-                               eval -= loc;
-
-                               // In this instruction the PC is located a DWORD away
-                               if (dw & FU_PCRELX)
-                                       eval += 2;
-                       }
 
                        // Be sure to clear any TDB flags, since we handled it just now
                        tdb = 0;