Improve linker script align (#1271)

An offset is now supported, and invalid values are no longer silently
truncated, aligning behaviour with other instances of the directive.
This commit is contained in:
Rangi
2023-12-18 01:16:48 -05:00
committed by GitHub
parent 39018174c5
commit fdd45ab1dc
5 changed files with 54 additions and 20 deletions

View File

@@ -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

View File

@@ -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) {

View File

@@ -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

View File

@@ -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]

View File

@@ -1,6 +1,7 @@
ROM0
align 4
align 4, 2
"sec"
ds $18
org $20
align 5
"secfix"