]> Shamusworld >> Repos - rmac/blobdiff - sect.c
Version bump for last commit. :-)
[rmac] / sect.c
diff --git a/sect.c b/sect.c
index ae4d750b98b84c8ed1726b4084ba39d8e6d85551..12f9c89eae2f7eda973f63765816c21bb87f3c57 100644 (file)
--- a/sect.c
+++ b/sect.c
@@ -1,7 +1,7 @@
 //
-// RMAC - Reboot's Macro Assembler for all Atari computers
+// RMAC - Renamed Macro Assembler for all Atari computers
 // SECT.C - Code Generation, Fixups and Section Management
-// Copyright (C) 199x Landon Dyer, 2011-2020 Reboot and Friends
+// Copyright (C) 199x Landon Dyer, 2011-2021 Reboot and Friends
 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
 // Source utilised with the kind permission of Landon Dyer
 //
@@ -18,7 +18,8 @@
 #include "riscasm.h"
 #include "symbol.h"
 #include "token.h"
-
+#define DEF_REGRISC
+#include "riscregs.h"
 
 // Function prototypes
 void MakeSection(int, uint16_t);
@@ -294,7 +295,7 @@ int AddFixup(uint32_t attr, uint32_t loc, TOKEN * fexpr)
        }
 
        // Allocate space for the fixup + any expression
-       FIXUP * fixup = malloc(sizeof(FIXUP) + (sizeof(TOKEN) * exprlen));
+       FIXUP * fixup = malloc(sizeof(FIXUP) + (sizeof(TOKEN) * exprlen)*2);
 
        // Store the relevant fixup information in the FIXUP
        fixup->next = NULL;
@@ -309,8 +310,53 @@ int AddFixup(uint32_t attr, uint32_t loc, TOKEN * fexpr)
        // Copy the passed in expression to the FIXUP, if any
        if (exprlen > 0)
        {
+               // Here we used to to a plain memcpy and punt on trying to evaluate the expression by then.
+               // As discussed in bug #176, this can lead to robustness issues because some symbols might
+               // have changed by the time we perform the relocations (think of a symbol that's SET multiple
+               // times). So instead we perform a symbol-by-symbol copy and check to see if there are any
+               // resolved symbols that can be evaluated immediately. Those, we replace with constants.
+               // Also of note: because "fixup" can be larger than what ExpressionLength() returns
+               // (due to constants taking up more space than symbols), we allocate twice as RAM as we should
+               // without expansions just to be on the safe side. The "correct" thing to do would be to
+               // modify ExpressionLength() to cater for defined symbols and return the exact amount of items.
+
                fixup->expr = (TOKEN *)((uint8_t *)fixup + sizeof(FIXUP));
-               memcpy(fixup->expr, fexpr, sizeof(TOKEN) * exprlen);
+               int i;
+               PTR dstexpr;
+               dstexpr.u32 = fixup->expr;
+               SYM *sy;
+               for (i = 0; i < exprlen; i++)
+               {
+                       if (*fexpr == SYMBOL)
+                       {
+                               sy = symbolPtr[fexpr[1]];
+                               if (sy->sattr & DEFINED && !(sy->sattr & (TDB| M56KPXYL|M6502)))
+                               {
+                                       // Only convert symbols that are defined and are absolute
+                                       *dstexpr.u32++ = CONST;
+                                       *dstexpr.u64++ = sy->svalue;
+                                       fexpr += 2;
+                                       i++;
+                               }
+                               else
+                               {
+                                       // Just copy the symbol
+                                       *dstexpr.u32++ = *fexpr++;
+                                       *dstexpr.u32++ = *fexpr++;
+                                       i++;
+                               }
+                       }
+                       else if (*fexpr == CONST || *fexpr == FCONST)
+                       {
+                               // Copy constants
+                               *dstexpr.u32++ = *fexpr++;
+                               *dstexpr.u32++ = *fexpr++;
+                               *dstexpr.u32++ = *fexpr++;
+                               i += 2;
+                       }
+                       else
+                               *dstexpr.u32++ = *fexpr++;
+               }
        }
 
        // Finally, put the FIXUP in the current section's linked list
@@ -416,9 +462,18 @@ int ResolveFixups(int sno)
                        if (evexpr(fup->expr, &eval, &eattr, &esym) != OK)
                                continue;
 
-                       if ((CHECK_OPTS(OPT_PC_RELATIVE)) && (eattr & REFERENCED) && (eattr & DEFINED) && (!(eattr & EQUATED)))
+                       if (esym)
+                               if (!(esym->sattr & DEFINED) && eval==0)
+                               {
+                                       // If our expression still has an undefined symbol at this stage, it's bad news.
+                                       // The linker is never going to resolve the expression, so that's an error.
+                                       error("cannot export complex expression with unresloved symbol '%s'", esym->sname);
+                                       continue;
+                               }
+
+                       if ((CHECK_OPTS(OPT_PC_RELATIVE)) && (eattr & (DEFINED | REFERENCED | EQUATED)) == (DEFINED | REFERENCED))
                        {
-                               error("relocation not allowed");
+                               error("relocation not allowed when o30 is enabled");
                                continue;
                        }
                }
@@ -428,9 +483,9 @@ int ResolveFixups(int sno)
                        SYM * sy = fup->symbol;
                        eattr = sy->sattr;
 
-                       if ((CHECK_OPTS(OPT_PC_RELATIVE)) && (eattr & REFERENCED) && (eattr & DEFINED) && (!(eattr & EQUATED)))
+                       if ((CHECK_OPTS(OPT_PC_RELATIVE)) && (eattr & (DEFINED | REFERENCED | EQUATED)) == (DEFINED | REFERENCED))
                        {
-                               error("relocation not allowed");
+                               error("relocation not allowed when o30 is enabled");
                                continue;
                        }
 
@@ -502,6 +557,9 @@ int ResolveFixups(int sno)
                                                // In this instruction the PC is located a DWORD away
                                                if (dw & FU_PCRELX)
                                                        eval += 2;
+                                               
+                                               if ((int64_t)eval > 0x7fff || (int64_t)eval < -32768)
+                                                       error(range_error);
                                        }
                                        else
                                        {
@@ -544,7 +602,7 @@ int ResolveFixups(int sno)
                                        *locp = 0x71;
 
                                        if (optim_warn_flag)
-                                               warn("bra.s with zero offset converted to NOP");
+                                               warn("o6: bra.s with zero offset converted to NOP");
 
                                        continue;
                                }
@@ -675,6 +733,7 @@ int ResolveFixups(int sno)
                        }
                        else if ((dw & FUMASKRISC) == FU_REGONE)
                        {
+                               eval -= REGRISC_R0;
                                if (eval > 31)
                                {
                                        error("register one value out of range");
@@ -688,6 +747,7 @@ int ResolveFixups(int sno)
                        }
                        else if ((dw & FUMASKRISC) == FU_REGTWO)
                        {
+                               eval -= REGRISC_R0;
                                if (eval > 31)
                                {
                                        error("register two value out of range");