diff --git a/src/link816/link816.cpp b/src/link816/link816.cpp index 954e754..11df0f1 100644 --- a/src/link816/link816.cpp +++ b/src/link816/link816.cpp @@ -431,6 +431,7 @@ struct Imm24Site { static std::vector gImm24Sites; static uint32_t gTextBaseForSites = 0; static bool gRecordSites = false; +static unsigned long gBank0DataSites = 0; // --report-self-mod: audit diagnostic. Reports every intra-.text-section // IMM16 reference made with a STORE opcode (absolute, DBR-relative) into the @@ -792,6 +793,32 @@ static void applyTextReloc(std::vector &buf, uint32_t off, // per-seg list for seg 1, since rodata is in seg 1's bank by // design). if (targetSeg == 0) { + // BANK-0 DATA/BSS target (inside SEG1's payload) referenced from an overflow segment: the + // GS/OS Loader honors at most PAGE alignment (it ignores OMF ALIGN=$10000), so seg1 loads + // at an arbitrary in-bank offset and every baked data operand from another segment misses + // by that offset (measured live on the RetroNet IIgs client: functions packed into seg1 + // worked, everything else read/wrote unowned memory - MAME memory-tap proven). Emit + // cINTERSEG records against seg 1 so the Loader writes the true placed address: 3 bytes + // for IMM24/DATA32, 2 for IMM16 (bank comes from DBR - BANKSIZE=$10000 keeps seg1 within + // one bank), 2+shift16 for BANK16. + if (gRecordSites && patchSeg >= 1 && !segments.empty() && + (rtype == R_W65816_IMM24 || rtype == R_W65816_DATA32 || + rtype == R_W65816_IMM16 || rtype == R_W65816_BANK16) && + (target & 0xFF0000u) == 0u && target != 0u) { + uint8_t cnt = (rtype == R_W65816_IMM24 || rtype == R_W65816_DATA32) ? 3 : 2; + for (uint8_t i = 0; i < cnt; ++i) + buf[off + i] = 0; + InterImm24Site s; + s.patchSeg = static_cast(patchSeg); + s.patchOff = static_cast(patchAddr - pseg.base); + s.targetSeg = 1; + s.targetOff = static_cast(target); + s.byteCnt = cnt; + s.bitShift = (rtype == R_W65816_BANK16) ? 16 : 0; + gInterImm24Sites.push_back(s); + gBank0DataSites++; + return; + } applyReloc(buf, off, patchAddr, target, rtype, symName); // Also push into the per-seg list with the same gates as // recordCRelocSite (target in same bank as textBase and @@ -2563,6 +2590,7 @@ int main(int argc, char **argv) { linker.writeMultiSegment(outPath, linker.manifestPath, "__start"); } + std::fprintf(stderr, "link816: %lu bank0-data cINTERSEG sites\n", gBank0DataSites); std::fprintf(stderr, "linked: text=[0x%04x+%u] rodata=[0x%04x+%u] bss=[0x%04x+%u] " "-> %s (%zu bytes)",