ref: 0f488b67599c5d93423cf9ed830d829825eaf283
dir: /src/link/patch.c/
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "link/mylink.h" #include "link/symbol.h" #include "link/main.h" struct sSection *pCurrentSection; SLONG rpnstack[256]; SLONG rpnp; SLONG nPC; void rpnpush(SLONG i) { rpnstack[rpnp++] = i; } SLONG rpnpop(void) { return (rpnstack[--rpnp]); } SLONG getsymvalue(SLONG symid) { switch (pCurrentSection->tSymbols[symid]->Type) { case SYM_IMPORT: return (sym_GetValue(pCurrentSection->tSymbols[symid]->pzName)); break; case SYM_EXPORT: case SYM_LOCAL: { if (strcmp (pCurrentSection->tSymbols[symid]->pzName, "@") == 0) { return (nPC); } else return (pCurrentSection->tSymbols[symid]-> nOffset + pCurrentSection->tSymbols[symid]-> pSection->nOrg); } default: break; } fprintf(stderr, "*INTERNAL* UNKNOWN SYMBOL TYPE\n"); exit(1); } SLONG getsymbank(SLONG symid) { switch (pCurrentSection->tSymbols[symid]->Type) { case SYM_IMPORT: return (sym_GetBank(pCurrentSection->tSymbols[symid]->pzName)); break; case SYM_EXPORT: case SYM_LOCAL: return (pCurrentSection->tSymbols[symid]->pSection->nBank); //return (pCurrentSection->nBank); default: break; } fprintf(stderr, "*INTERNAL* UNKNOWN SYMBOL TYPE\n"); exit(1); } SLONG calcrpn(struct sPatch * pPatch) { SLONG t, size; UBYTE *rpn; rpnp = 0; size = pPatch->nRPNSize; rpn = pPatch->pRPN; pPatch->oRelocPatch = 0; while (size > 0) { size -= 1; switch (*rpn++) { case RPN_ADD: rpnpush(rpnpop() + rpnpop()); break; case RPN_SUB: t = rpnpop(); rpnpush(rpnpop() - t); break; case RPN_MUL: rpnpush(rpnpop() * rpnpop()); break; case RPN_DIV: t = rpnpop(); rpnpush(rpnpop() / t); break; case RPN_MOD: t = rpnpop(); rpnpush(rpnpop() % t); break; case RPN_UNSUB: rpnpush(-rpnpop()); break; case RPN_OR: rpnpush(rpnpop() | rpnpop()); break; case RPN_AND: rpnpush(rpnpop() & rpnpop()); break; case RPN_XOR: rpnpush(rpnpop() ^ rpnpop()); break; case RPN_UNNOT: rpnpush(rpnpop() ^ 0xFFFFFFFF); break; case RPN_LOGAND: rpnpush(rpnpop() && rpnpop()); break; case RPN_LOGOR: rpnpush(rpnpop() || rpnpop()); break; case RPN_LOGUNNOT: rpnpush(!rpnpop()); break; case RPN_LOGEQ: rpnpush(rpnpop() == rpnpop()); break; case RPN_LOGNE: rpnpush(rpnpop() != rpnpop()); break; case RPN_LOGGT: t = rpnpop(); rpnpush(rpnpop() > t); break; case RPN_LOGLT: t = rpnpop(); rpnpush(rpnpop() < t); break; case RPN_LOGGE: t = rpnpop(); rpnpush(rpnpop() >= t); break; case RPN_LOGLE: t = rpnpop(); rpnpush(rpnpop() <= t); break; case RPN_SHL: t = rpnpop(); rpnpush(rpnpop() << t); break; case RPN_SHR: t = rpnpop(); rpnpush(rpnpop() >> t); break; case RPN_HRAM: t = rpnpop(); rpnpush(t & 0xFF); if (t < 0 || (t > 0xFF && t < 0xFF00) || t > 0xFFFF) { fprintf(stderr, "%s(%ld) : Value must be in the HRAM area\n", pPatch->pzFilename, pPatch->nLineNo); exit(1); } break; case RPN_PCEZP: t = rpnpop(); rpnpush(t & 0xFF); if (t < 0x2000 || t > 0x20FF) { fprintf(stderr, "%s(%ld) : Value must be in the ZP area\n", pPatch->pzFilename, pPatch->nLineNo); exit(1); } break; case RPN_CONST: /* constant */ t = (*rpn++); t |= (*rpn++) << 8; t |= (*rpn++) << 16; t |= (*rpn++) << 24; rpnpush(t); size -= 4; break; case RPN_SYM: /* symbol */ t = (*rpn++); t |= (*rpn++) << 8; t |= (*rpn++) << 16; t |= (*rpn++) << 24; rpnpush(getsymvalue(t)); pPatch->oRelocPatch |= (getsymbank(t) != -1); size -= 4; break; case RPN_BANK: /* symbol */ t = (*rpn++); t |= (*rpn++) << 8; t |= (*rpn++) << 16; t |= (*rpn++) << 24; rpnpush(getsymbank(t)); size -= 4; break; case RPN_RANGECHECK: { SLONG low, high; low = (*rpn++); low |= (*rpn++) << 8; low |= (*rpn++) << 16; low |= (*rpn++) << 24; high = (*rpn++); high |= (*rpn++) << 8; high |= (*rpn++) << 16; high |= (*rpn++) << 24; t = rpnpop(); if (t < low || t > high) { fprintf(stderr, "%s(%ld) : Value must be in the range [%ld;%ld]\n", pPatch->pzFilename, pPatch->nLineNo, low, high); exit(1); } rpnpush(t); size -= 8; break; } } } return (rpnpop()); } void Patch(void) { struct sSection *pSect; pSect = pSections; while (pSect) { struct sPatch *pPatch; pCurrentSection = pSect; pPatch = pSect->pPatches; while (pPatch) { SLONG t; nPC = pSect->nOrg + pPatch->nOffset; t = calcrpn(pPatch); switch (pPatch->Type) { case PATCH_BYTE: if (t >= -128 && t <= 255) { t &= 0xFF; pSect->pData[pPatch->nOffset] = (UBYTE) t; } else { fprintf(stderr, "%s(%ld) : Value must be 8-bit\n", pPatch->pzFilename, pPatch->nLineNo); exit(1); } break; case PATCH_WORD_L: case PATCH_WORD_B: if (t >= -32768 && t <= 65535) { t &= 0xFFFF; if (pPatch->Type == PATCH_WORD_L) { pSect->pData[pPatch->nOffset] = t & 0xFF; pSect->pData[pPatch->nOffset + 1] = (t >> 8) & 0xFF; } else { //Assume big endian pSect->pData[pPatch->nOffset] = (t >> 8) & 0xFF; pSect->pData[pPatch->nOffset + 1] = t & 0xFF; } } else { fprintf(stderr, "%s(%ld) : Value must be 16-bit\n", pPatch->pzFilename, pPatch->nLineNo); exit(1); } break; case PATCH_LONG_L: pSect->pData[pPatch->nOffset + 0] = t & 0xFF; pSect->pData[pPatch->nOffset + 1] = (t >> 8) & 0xFF; pSect->pData[pPatch->nOffset + 2] = (t >> 16) & 0xFF; pSect->pData[pPatch->nOffset + 3] = (t >> 24) & 0xFF; break; case PATCH_LONG_B: pSect->pData[pPatch->nOffset + 0] = (t >> 24) & 0xFF; pSect->pData[pPatch->nOffset + 1] = (t >> 16) & 0xFF; pSect->pData[pPatch->nOffset + 2] = (t >> 8) & 0xFF; pSect->pData[pPatch->nOffset + 3] = t & 0xFF; break; } pPatch = pPatch->pNext; } pSect = pSect->pNext; } }