Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 56 additions & 75 deletions src/link/section.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -157,14 +138,14 @@ static void mergeSections(Section &target, std::unique_ptr<Section> &&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;
Expand Down
4 changes: 4 additions & 0 deletions test/link/section-union/compat/a.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
SECTION "ROM", ROM0
LOAD UNION "U", WRAM0
ds 1
ENDL
17 changes: 17 additions & 0 deletions test/link/section-union/compat/b.asm
Original file line number Diff line number Diff line change
@@ -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::
Binary file added test/link/section-union/compat/ref.out.bin
Binary file not shown.
5 changes: 5 additions & 0 deletions test/link/section-union/compat/script.link
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
WRAM0
align 8
"R1"
"U"
"R2"
9 changes: 9 additions & 0 deletions test/link/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down