diff --git a/src/link/section.cpp b/src/link/section.cpp index 101467146..7c711b76e 100644 --- a/src/link/section.cpp +++ b/src/link/section.cpp @@ -25,90 +25,71 @@ void sect_ForEach(void (*callback)(Section &)) { } } -static void checkAgainstFixedAddress(Section const &target, Section const &other, uint16_t org) { - if (target.isAddressFixed) { - if (target.org != org) { - fatalTwoAt( - target, - other, - "Section \"%s\" is defined with address $%04" PRIx16 - ", but also with address $%04" PRIx16, - target.name.c_str(), - target.org, - other.org - ); +static void checkPieceCompat(Section &target, Section const &other, size_t delta) { + assume(other.modifier != SECTION_UNION || delta == 0); + + if (other.isAddressFixed) { + uint16_t org = other.org - delta; + + if (target.isAddressFixed) { + if (target.org != org) { + fatalTwoAt( + target, + other, + "Section \"%s\" is defined with address $%04" PRIx16 + ", but also with address $%04" PRIx16, + target.name.c_str(), + target.org, + other.org + ); + } + } else if (target.isAlignFixed) { + if ((org - target.alignOfs) & target.alignMask) { + fatalTwoAt( + target, + other, + "Section \"%s\" is defined with %d-byte alignment (offset %" PRIu16 + "), but also with address $%04" PRIx16, + target.name.c_str(), + target.alignMask + 1, + target.alignOfs, + other.org + ); + } } - } else if (target.isAlignFixed) { - if ((org - target.alignOfs) & target.alignMask) { + + target.isAddressFixed = true; + target.org = org; + } else if (other.isAlignFixed) { + uint32_t ofs = (other.alignOfs - delta) & other.alignMask; + + if (target.isAddressFixed) { + if ((target.org - ofs) & other.alignMask) { + fatalTwoAt( + target, + other, + "Section \"%s\" is defined with address $%04" PRIx16 + ", but also with %d-byte alignment (offset %" PRIu16 ")", + target.name.c_str(), + target.org, + other.alignMask + 1, + other.alignOfs + ); + } + } else if (target.isAlignFixed + && (other.alignMask & target.alignOfs) != (target.alignMask & ofs)) { fatalTwoAt( target, other, "Section \"%s\" is defined with %d-byte alignment (offset %" PRIu16 - "), but also with address $%04" PRIx16, + "), but also with %d-byte alignment (offset %" PRIu16 ")", target.name.c_str(), target.alignMask + 1, target.alignOfs, - other.org - ); - } - } -} - -static bool checkAgainstFixedAlign(Section const &target, Section const &other, uint32_t ofs) { - if (target.isAddressFixed) { - if ((target.org - ofs) & other.alignMask) { - fatalTwoAt( - target, - other, - "Section \"%s\" is defined with address $%04" PRIx16 - ", but also with %d-byte alignment (offset %" PRIu16 ")", - target.name.c_str(), - target.org, other.alignMask + 1, other.alignOfs ); - } - return false; - } else if (target.isAlignFixed - && (other.alignMask & target.alignOfs) != (target.alignMask & ofs)) { - fatalTwoAt( - target, - other, - "Section \"%s\" is defined with %d-byte alignment (offset %" PRIu16 - "), but also with %d-byte alignment (offset %" PRIu16 ")", - target.name.c_str(), - target.alignMask + 1, - target.alignOfs, - other.alignMask + 1, - other.alignOfs - ); - } else { - return !target.isAlignFixed || (other.alignMask > target.alignMask); - } -} - -static void checkSectUnionCompat(Section &target, Section &other) { - if (other.isAddressFixed) { - checkAgainstFixedAddress(target, other, other.org); - target.isAddressFixed = true; - target.org = other.org; - } else if (other.isAlignFixed) { - if (checkAgainstFixedAlign(target, other, other.alignOfs)) { - target.isAlignFixed = true; - target.alignMask = other.alignMask; - } - } -} - -static void checkFragmentCompat(Section &target, Section &other) { - if (other.isAddressFixed) { - uint16_t org = other.org - target.size; - checkAgainstFixedAddress(target, other, org); - target.isAddressFixed = true; - target.org = org; - } else if (other.isAlignFixed) { - uint32_t ofs = (other.alignOfs - target.size) & other.alignMask; - if (checkAgainstFixedAlign(target, other, ofs)) { + } else if (!target.isAlignFixed || other.alignMask > target.alignMask) { target.isAlignFixed = true; target.alignMask = other.alignMask; target.alignOfs = ofs; @@ -157,14 +138,14 @@ static void mergeSections(Section &target, std::unique_ptr
&&other) { switch (other->modifier) { case SECTION_UNION: - checkSectUnionCompat(target, *other); + checkPieceCompat(target, *other, 0); if (other->size > target.size) { target.size = other->size; } break; case SECTION_FRAGMENT: - checkFragmentCompat(target, *other); + checkPieceCompat(target, *other, target.size); // Append `other` to `target` other->offset = target.size; target.size += other->size; diff --git a/test/link/section-union/compat/a.asm b/test/link/section-union/compat/a.asm new file mode 100644 index 000000000..d7b901a02 --- /dev/null +++ b/test/link/section-union/compat/a.asm @@ -0,0 +1,4 @@ +SECTION "ROM", ROM0 +LOAD UNION "U", WRAM0 + ds 1 +ENDL diff --git a/test/link/section-union/compat/b.asm b/test/link/section-union/compat/b.asm new file mode 100644 index 000000000..7428f1fb3 --- /dev/null +++ b/test/link/section-union/compat/b.asm @@ -0,0 +1,17 @@ +SECTION "R1", WRAM0 + ds $77 + +SECTION "R2", WRAM0 + ds $ef + +SECTION UNION "U", WRAM0 + ds $52e + +SECTION UNION "U", WRAM0 +wStart:: + ds $89 + assert @ & $FF == 0, "wContent must be 8-bit aligned" + align 8 +wContent:: + ds $111 +wEnd:: diff --git a/test/link/section-union/compat/ref.out.bin b/test/link/section-union/compat/ref.out.bin new file mode 100644 index 000000000..294f4016d Binary files /dev/null and b/test/link/section-union/compat/ref.out.bin differ diff --git a/test/link/section-union/compat/script.link b/test/link/section-union/compat/script.link new file mode 100644 index 000000000..bb3b77c78 --- /dev/null +++ b/test/link/section-union/compat/script.link @@ -0,0 +1,5 @@ +WRAM0 + align 8 + "R1" + "U" + "R2" diff --git a/test/link/test.sh b/test/link/test.sh index 78533e7f8..d098efa0b 100755 --- a/test/link/test.sh +++ b/test/link/test.sh @@ -390,6 +390,15 @@ rgblinkQuiet "$otemp" "$gbtemp" 2>"$outtemp" tryDiff "$test"/out.err "$outtemp" evaluateTest +test="section-union/compat" +startTest +"$RGBASM" -o "$otemp" "$test"/a.asm +"$RGBASM" -o "$gbtemp2" "$test"/b.asm +continueTest +rgblinkQuiet -o "$gbtemp" -l "$test"/script.link "$otemp" "$gbtemp2" +tryCmpRom "$test"/ref.out.bin +evaluateTest + test="section-union/good" startTest "$RGBASM" -o "$otemp" "$test"/a.asm