diff --git a/man/rgblink.5 b/man/rgblink.5 index c839d0d5..0c41f810 100644 --- a/man/rgblink.5 +++ b/man/rgblink.5 @@ -68,15 +68,25 @@ and .Ic DS : .Bl -bullet .It -.Ic ORG -sets the address in which new sections will be placed. +.Ic ORG Ar addr +sets the address in which new sections will be placed to +.Ar addr . It can not be lower than the current address. .It -.Ic ALIGN +.Ic ALIGN Ar addr +or +.Ic ALIGN Ar addr , Ar offset will increase the address until it is aligned to the specified boundary -.Po it tries to set to 0 the number of bits specified after the directive: +.Po it tries to set to +.Ar offset +the number of bits specified by +.Ar align : +for example, .Ql ALIGN 8 -will align to $100 +will align to $100 , +and +.Ql ALIGN 8 , 10 +will align to $10A .Pc . .It .Ic DS diff --git a/src/link/script.y b/src/link/script.y index 5a015c87..945734fa 100644 --- a/src/link/script.y +++ b/src/link/script.y @@ -51,6 +51,7 @@ %token YYEOF 0 "end of file" %token newline +%token COMMA "," %token ORG "ORG" INCLUDE "INCLUDE" ALIGN "ALIGN" @@ -83,6 +84,7 @@ directive: section_type { setSectionType($1); } | section_type number { setSectionType($1, $2); } | ORG number { setAddr($2); } | ALIGN number { alignTo($2, 0); } + | ALIGN number COMMA number { alignTo($2, $4); } | DS number { pad($2); } | string { placeSection($1); } ; @@ -197,6 +199,8 @@ try_again: // Can't use a `do {} while(0)` loop, otherwise compilers (wrongly) t } else { return yy::parser::make_YYEOF(); } + } else if (c == ',') { + return yy::parser::make_COMMA(); } else if (isNewline(c)) { // Handle CRLF. if (c == '\r' && context.file.sgetc() == '\n') { @@ -372,18 +376,37 @@ static void alignTo(uint32_t alignment, uint32_t alignOfs) { auto const &typeInfo = sectionTypeInfo[activeType]; auto &pc = curAddr[activeType][activeBankIdx]; - // TODO: maybe warn if truncating? - alignOfs %= 1 << alignment; - - assert(pc >= typeInfo.startAddr); - uint16_t length = alignment < 16 ? (uint16_t)(alignOfs - pc) % (1u << alignment) - : alignOfs - pc; // Let it wrap around, this'll trip the check. - if (uint16_t offset = pc - typeInfo.startAddr; length > typeInfo.size - offset) { - scriptError(context, "Cannot align: the next suitable address after $%04" PRIx16 " is $%04" PRIx16 ", past $%04" PRIx16, - pc, (uint16_t)(pc + length), (uint16_t)(endaddr(activeType) + 1)); - } else { - pc += length; + if (alignment > 16) { + scriptError(context, "Cannot align: The alignment (%" PRIu32 ") must be less than 16\n", + alignment); + return; } + + // Let it wrap around, this'll trip the final check if alignment == 16. + uint16_t length = alignOfs - pc; + + if (alignment < 16) { + uint32_t alignSize = 1u << alignment; + + if (alignOfs >= alignSize) { + scriptError(context, "Cannot align: The alignment offset (%" PRIu32 + ") must be less than alignment size (%" PRIu32 ")\n", + alignOfs, 1 << alignment); + return; + } + + assert(pc >= typeInfo.startAddr); + length %= alignSize; + } + + if (uint16_t offset = pc - typeInfo.startAddr; length > typeInfo.size - offset) { + scriptError(context, "Cannot align: the next suitable address after $%04" + PRIx16 " is $%04" PRIx16 ", past $%04" PRIx16, + pc, (uint16_t)(pc + length), (uint16_t)(endaddr(activeType) + 1)); + return; + } + + pc += length; } static void pad(uint32_t length) { diff --git a/test/link/section-attributes-mismatch.out b/test/link/section-attributes-mismatch.out index 5c2f4fe8..6cde6d77 100644 --- a/test/link/section-attributes-mismatch.out +++ b/test/link/section-attributes-mismatch.out @@ -1,2 +1,2 @@ -error: ./section-attributes-mismatch.link(3): The linker script assigns section "sec" to address $0018, but that would be ALIGN[4, 8] instead of the requested ALIGN[4, 0] +error: ./section-attributes-mismatch.link(3): The linker script assigns section "sec" to address $0018, but that would be ALIGN[4, 8] instead of the requested ALIGN[4, 2] Linking failed with 1 error diff --git a/test/link/section-attributes.asm b/test/link/section-attributes.asm index 4ea51d14..34785e16 100644 --- a/test/link/section-attributes.asm +++ b/test/link/section-attributes.asm @@ -1,3 +1,3 @@ -SECTION "sec",ROM0,ALIGN[4] - ds 8, $42 +SECTION "sec",ROM0,ALIGN[4,2] + ds 6, $42 SECTION "secfix",ROM0[$20] diff --git a/test/link/section-attributes.link b/test/link/section-attributes.link index 2d93a7e6..8ca94f1d 100644 --- a/test/link/section-attributes.link +++ b/test/link/section-attributes.link @@ -1,6 +1,7 @@ ROM0 - align 4 + align 4, 2 "sec" ds $18 org $20 + align 5 "secfix"