//
-// 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
//
#include "riscasm.h"
#include "symbol.h"
#include "token.h"
-
+#define DEF_REGRISC
+#include "riscregs.h"
// Function prototypes
void MakeSection(int, uint16_t);
}
// 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;
// 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
// evexpr presumably issues the errors/warnings here
if (evexpr(fup->expr, &eval, &eattr, &esym) != OK)
continue;
+
+ if ((CHECK_OPTS(OPT_PC_RELATIVE)) && (eattr & (DEFINED | REFERENCED | EQUATED)) == (DEFINED | REFERENCED))
+ {
+ error("relocation not allowed when o30 is enabled");
+ continue;
+ }
}
// Simple symbol
else
SYM * sy = fup->symbol;
eattr = sy->sattr;
+ if ((CHECK_OPTS(OPT_PC_RELATIVE)) && (eattr & (DEFINED | REFERENCED | EQUATED)) == (DEFINED | REFERENCED))
+ {
+ error("relocation not allowed when o30 is enabled");
+ continue;
+ }
+
if (eattr & DEFINED)
eval = sy->svalue;
else
}
}
- if (sbra_flag && (dw & FU_LBRA) && (eval + 0x80 < 0x100))
+ if (optim_warn_flag && (dw & FU_LBRA) && (eval + 0x80 < 0x100))
warn("unoptimized short branch");
}
if (eval == 0)
{
- if (CHECK_OPTS(OPT_NULL_BRA))
+ if (*locp) // optim_flags[OPT_NULL_BRA] is stored there, check the comment in mach.s under m_br
{
// Just output a NOP
*locp++ = 0x4E;
*locp = 0x71;
+
+ if (optim_warn_flag)
+ warn("o6: bra.s with zero offset converted to NOP");
+
continue;
}
else
}
else if ((dw & FUMASKRISC) == FU_REGONE)
{
+ eval -= REGRISC_R0;
if (eval > 31)
{
error("register one value out of range");
}
else if ((dw & FUMASKRISC) == FU_REGTWO)
{
+ eval -= REGRISC_R0;
if (eval > 31)
{
error("register two value out of range");
locp[1] = (uint8_t)eval;
break;
- // This is a 6 bit absoulte short address. It occupies
- // the low 6 bits of the middle byte of a DSP word.
+ // This is a 6 bit absoulte short address. It occupies the low 6
+ // bits of the middle byte of a DSP word.
case FU_DSPADR06:
if (eval > 63)
{
locp[1] |= eval;
break;
- // This is a 6 bit absoulte short address. It occupies
- // the low 6 bits of the middle byte of a DSP word.
+ // This is a 6 bit absoulte short address. It occupies the low 6
+ // bits of the middle byte of a DSP word.
case FU_DSPPP06:
if (eval < 0xFFFFFFC0)
{