diff --git a/src/link/layout.cpp b/src/link/layout.cpp index 4ca65cc0..d2ded1c4 100644 --- a/src/link/layout.cpp +++ b/src/link/layout.cpp @@ -267,9 +267,8 @@ void layout_PlaceSection(std::string const &name, bool isOptional) { ); } - if (activeBankIdx == UINT32_MAX) { - section->isBankFixed = false; - } else { + // Enforce a bank if one is active, but leave any existing constraint alone. + if (activeBankIdx != UINT32_MAX) { uint32_t bank = activeBankIdx + typeInfo.firstBank; if (section->isBankFixed && bank != section->bank) { scriptError( @@ -296,11 +295,11 @@ void layout_PlaceSection(std::string const &name, bool isOptional) { section->org ); } else if (section->isAlignFixed && (org & section->alignMask) != section->alignOfs) { - uint8_t alignment = std::countr_one(section->alignMask); + int alignment = std::countr_one(section->alignMask); scriptError( "The linker script assigns section \"%s\" to address $%04" PRIx16 - ", but that would be ALIGN[%" PRIu8 ", %" PRIu16 - "] instead of the requested ALIGN[%" PRIu8 ", %" PRIu16 "]", + ", but that would be ALIGN[%d, %" PRIu16 + "] instead of the requested ALIGN[%d, %" PRIu16 "]", name.c_str(), org, alignment, @@ -331,10 +330,38 @@ void layout_PlaceSection(std::string const &name, bool isOptional) { org += section->size; } } else { - section->isAddressFixed = false; - section->isAlignFixed = floatingAlignMask != 0; - section->alignMask = floatingAlignMask; - section->alignOfs = floatingAlignOffset; + if (section->isAddressFixed) { + if ((section->org & floatingAlignMask) != floatingAlignOffset) { + int alignment = std::countr_one(floatingAlignMask); + scriptError( + "The linker script aligns floating section \"%s\" to ALIGN[%d, %" PRIu16 + "], but it was already at address $%04" PRIx16 " which has ALIGN[%d, %" PRIu16 + "]", + name.c_str(), + alignment, + floatingAlignOffset, + section->org, + alignment, + static_cast(section->org & floatingAlignMask) + ); + } + } else if (uint16_t commonMask = section->alignMask & floatingAlignMask; + section->isAlignFixed + && (section->alignOfs & commonMask) != (floatingAlignOffset & commonMask)) { + scriptError( + "The linker script aligns floating section \"%s\" to ALIGN[%d, %" PRIu16 + "], but it already has requested ALIGN[%d, %" PRIu16 "]", + name.c_str(), + std::countr_one(floatingAlignMask), + floatingAlignOffset, + std::countr_one(section->alignMask), + section->alignOfs + ); + } else if (!section->isAlignFixed || floatingAlignMask > section->alignMask) { + section->isAlignFixed = floatingAlignMask != 0; + section->alignMask = floatingAlignMask; + section->alignOfs = floatingAlignOffset; + } floatingAlignOffset = (floatingAlignOffset + section->size) & floatingAlignMask; } diff --git a/test/link/floating-constraints.asm b/test/link/floating-constraints.asm new file mode 100644 index 00000000..c7cc8b39 --- /dev/null +++ b/test/link/floating-constraints.asm @@ -0,0 +1,9 @@ +DEF address EQU $100 + +SECTION "code", ROM0[address] + +Start:: + jp Start + +assert STARTOF("code") == address +assert Start == address diff --git a/test/link/floating-constraints.link b/test/link/floating-constraints.link new file mode 100644 index 00000000..57e4e503 --- /dev/null +++ b/test/link/floating-constraints.link @@ -0,0 +1,3 @@ +ROM0 + FLOATING + "code" diff --git a/test/link/floating-constraints.out b/test/link/floating-constraints.out new file mode 100644 index 00000000..e69de29b diff --git a/test/link/linkerscript-floating-conflict.asm b/test/link/linkerscript-floating-conflict.asm new file mode 100644 index 00000000..2a385d94 --- /dev/null +++ b/test/link/linkerscript-floating-conflict.asm @@ -0,0 +1,11 @@ +SECTION "fixed", ROM0[$1234] + +SECTION "aligned", ROMX, ALIGN[8, 42] + +SECTION "less aligned", ROMX, ALIGN[4, 1] + +SECTION "more aligned", ROMX, ALIGN[8, 1] + +SECTION "address compatible", ROMX[$4463] + +SECTION "align compatible", ROMX, ALIGN[8, 99] diff --git a/test/link/linkerscript-floating-conflict.link b/test/link/linkerscript-floating-conflict.link new file mode 100644 index 00000000..38103511 --- /dev/null +++ b/test/link/linkerscript-floating-conflict.link @@ -0,0 +1,21 @@ +ROM0 + FLOATING + ALIGN 8, 42 + "fixed" +ROMX 1 + FLOATING + ALIGN 8, 23 + "aligned" +ROMX 2 + FLOATING + ALIGN 8, 2 + "less aligned" +ROMX 3 + FLOATING + ALIGN 4, 2 + "more aligned" +ROMX 4 + FLOATING + ALIGN 8, 99 + "address compatible" + "align compatible" diff --git a/test/link/linkerscript-floating-conflict.out b/test/link/linkerscript-floating-conflict.out new file mode 100644 index 00000000..18666f8f --- /dev/null +++ b/test/link/linkerscript-floating-conflict.out @@ -0,0 +1,9 @@ +error: The linker script aligns floating section "fixed" to ALIGN[8, 42], but it was already at address $1234 which has ALIGN[8, 52] + at linkerscript-floating-conflict.link(4) +error: The linker script aligns floating section "aligned" to ALIGN[8, 23], but it already has requested ALIGN[8, 42] + at linkerscript-floating-conflict.link(8) +error: The linker script aligns floating section "less aligned" to ALIGN[8, 2], but it already has requested ALIGN[4, 1] + at linkerscript-floating-conflict.link(12) +error: The linker script aligns floating section "more aligned" to ALIGN[4, 2], but it already has requested ALIGN[8, 1] + at linkerscript-floating-conflict.link(16) +Linking failed with 4 errors