Linker fixes.
This commit is contained in:
parent
4a13f9df26
commit
26cc6eb96a
1 changed files with 42 additions and 0 deletions
|
|
@ -548,9 +548,16 @@ static uint32_t relocWidth(uint8_t rtype) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned long gDbgBareCalls = 0;
|
||||||
|
unsigned long gDbgTextCalls = 0;
|
||||||
static void applyReloc(std::vector<uint8_t> &buf, uint32_t off,
|
static void applyReloc(std::vector<uint8_t> &buf, uint32_t off,
|
||||||
uint32_t patchAddr, uint32_t target,
|
uint32_t patchAddr, uint32_t target,
|
||||||
uint8_t rtype, const std::string &symName) {
|
uint8_t rtype, const std::string &symName) {
|
||||||
|
extern unsigned long gDbgBareCalls;
|
||||||
|
gDbgBareCalls++;
|
||||||
|
if (symName.find("gRnInPack") != std::string::npos) {
|
||||||
|
std::fprintf(stderr, "TRACE-BARE %s rtype=%u target=0x%X off=0x%X\n", symName.c_str(), rtype, target, off);
|
||||||
|
}
|
||||||
int64_t pcrelDisp;
|
int64_t pcrelDisp;
|
||||||
switch (rtype) {
|
switch (rtype) {
|
||||||
case R_W65816_IMM8:
|
case R_W65816_IMM8:
|
||||||
|
|
@ -766,6 +773,12 @@ static void applyTextReloc(std::vector<uint8_t> &buf, uint32_t off,
|
||||||
}
|
}
|
||||||
const TextSeg &pseg = segments[patchSeg - 1];
|
const TextSeg &pseg = segments[patchSeg - 1];
|
||||||
uint32_t targetSeg = findSegContaining(target, segments);
|
uint32_t targetSeg = findSegContaining(target, segments);
|
||||||
|
gDbgTextCalls++;
|
||||||
|
// TEMP TRACE (RetroNet hunt): decisions for the mirror-pack refs.
|
||||||
|
if (symName.find("gRnInPack") != std::string::npos) {
|
||||||
|
std::fprintf(stderr, "TRACE %s rtype=%u patchSeg=%u targetSeg=%u target=0x%X rec=%d\n",
|
||||||
|
symName.c_str(), rtype, patchSeg, targetSeg, target, (int)gRecordSites);
|
||||||
|
}
|
||||||
// Cross-segment FUNCTION POINTER (IMM16 &func to a function in seg2+):
|
// Cross-segment FUNCTION POINTER (IMM16 &func to a function in seg2+):
|
||||||
// clang forms the pointer as func's 16-bit offset + the $00BE seg1 bank,
|
// clang forms the pointer as func's 16-bit offset + the $00BE seg1 bank,
|
||||||
// which is wrong for a function in another bank. Redirect the IMM16 to
|
// which is wrong for a function in another bank. Redirect the IMM16 to
|
||||||
|
|
@ -792,6 +805,34 @@ static void applyTextReloc(std::vector<uint8_t> &buf, uint32_t off,
|
||||||
// per-seg list for seg 1, since rodata is in seg 1's bank by
|
// per-seg list for seg 1, since rodata is in seg 1's bank by
|
||||||
// design).
|
// design).
|
||||||
if (targetSeg == 0) {
|
if (targetSeg == 0) {
|
||||||
|
// BANK-0 DATA/BSS target (inside SEG1's payload) referenced with a LONG form from an
|
||||||
|
// overflow segment: the baked bank byte would be the LINK-TIME bank (0), but the Loader
|
||||||
|
// places seg1 in an arbitrary bank - every such read/write silently hits the wrong bank
|
||||||
|
// (measured live on the RetroNet IIgs client: cross-TU constant-index accesses compile to
|
||||||
|
// LDA long and returned garbage while DBR-relative abs16 to the same symbols worked).
|
||||||
|
// Emit a 3-byte cINTERSEG against seg 1 so the Loader writes the true 24-bit address.
|
||||||
|
// ...and the SAME hole exists for 16-bit forms: seg1 is only PAGE-aligned by the real
|
||||||
|
// GS/OS Loader (it does not honor ALIGN=$10000), so abs16 operands and bank-byte
|
||||||
|
// materializations referencing seg1 data are wrong by seg1's placement offset unless the
|
||||||
|
// Loader patches them. Emit 2-byte cINTERSEG records for those too; BANKSIZE=$10000
|
||||||
|
// guarantees seg1 never straddles a bank, so offset16+DBR stays coherent.
|
||||||
|
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<uint16_t>(patchSeg);
|
||||||
|
s.patchOff = static_cast<uint16_t>(patchAddr - pseg.base);
|
||||||
|
s.targetSeg = 1;
|
||||||
|
s.targetOff = static_cast<uint16_t>(target);
|
||||||
|
s.byteCnt = cnt;
|
||||||
|
s.bitShift = (rtype == R_W65816_BANK16) ? 16 : 0;
|
||||||
|
gInterImm24Sites.push_back(s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
applyReloc(buf, off, patchAddr, target, rtype, symName);
|
applyReloc(buf, off, patchAddr, target, rtype, symName);
|
||||||
// Also push into the per-seg list with the same gates as
|
// Also push into the per-seg list with the same gates as
|
||||||
// recordCRelocSite (target in same bank as textBase and
|
// recordCRelocSite (target in same bank as textBase and
|
||||||
|
|
@ -2570,6 +2611,7 @@ int main(int argc, char **argv) {
|
||||||
L.bssBase, L.bssSize,
|
L.bssBase, L.bssSize,
|
||||||
outPath.c_str(), image.size());
|
outPath.c_str(), image.size());
|
||||||
if (L.segments.size() > 1) {
|
if (L.segments.size() > 1) {
|
||||||
|
std::fprintf(stderr, " [dbg: textReloc=%lu bare=%lu]", gDbgTextCalls, gDbgBareCalls);
|
||||||
std::fprintf(stderr, " + %zu extra segments",
|
std::fprintf(stderr, " + %zu extra segments",
|
||||||
L.segments.size() - 1);
|
L.segments.size() - 1);
|
||||||
for (size_t k = 1; k < L.segments.size(); ++k) {
|
for (size_t k = 1; k < L.segments.size(); ++k) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue