X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rmac;a=blobdiff_plain;f=sect.c;h=ae4d750b98b84c8ed1726b4084ba39d8e6d85551;hp=c7580631faa89cf9534f206bdfd34847cab5b13f;hb=HEAD;hpb=7d0d2b9ecddea35722fd1d09c99735b98f6f0362 diff --git a/sect.c b/sect.c index c758063..12f9c89 100644 --- 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-2019 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 @@ -415,6 +461,21 @@ int ResolveFixups(int sno) // evexpr presumably issues the errors/warnings here if (evexpr(fup->expr, &eval, &eattr, &esym) != OK) continue; + + 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 when o30 is enabled"); + continue; + } } // Simple symbol else @@ -422,6 +483,12 @@ int ResolveFixups(int sno) 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 @@ -450,9 +517,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 +534,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) { @@ -493,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 { @@ -501,17 +568,9 @@ int ResolveFixups(int sno) } } - if (sbra_flag && (dw & FU_LBRA) && (eval + 0x80 < 0x100)) + if (optim_warn_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; @@ -536,11 +595,15 @@ int ResolveFixups(int sno) 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 @@ -670,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"); @@ -683,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"); @@ -895,8 +960,8 @@ int ResolveFixups(int sno) 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) { @@ -907,8 +972,8 @@ int ResolveFixups(int sno) 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) {