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 : .Ic DS :
.Bl -bullet .Bl -bullet
.It .It
.Ic ORG .Ic ORG Ar addr
sets the address in which new sections will be placed. sets the address in which new sections will be placed to
.Ar addr .
It can not be lower than the current address. It can not be lower than the current address.
.It .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 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 .Ql ALIGN 8
will align to $100 will align to $100 ,
and
.Ql ALIGN 8 , 10
will align to $10A
.Pc . .Pc .
.It .It
.Ic DS .Ic DS

View File

@@ -51,6 +51,7 @@
%token YYEOF 0 "end of file" %token YYEOF 0 "end of file"
%token newline %token newline
%token COMMA ","
%token ORG "ORG" %token ORG "ORG"
INCLUDE "INCLUDE" INCLUDE "INCLUDE"
ALIGN "ALIGN" ALIGN "ALIGN"
@@ -83,6 +84,7 @@ directive: section_type { setSectionType($1); }
| section_type number { setSectionType($1, $2); } | section_type number { setSectionType($1, $2); }
| ORG number { setAddr($2); } | ORG number { setAddr($2); }
| ALIGN number { alignTo($2, 0); } | ALIGN number { alignTo($2, 0); }
| ALIGN number COMMA number { alignTo($2, $4); }
| DS number { pad($2); } | DS number { pad($2); }
| string { placeSection($1); } | string { placeSection($1); }
; ;
@@ -197,6 +199,8 @@ try_again: // Can't use a `do {} while(0)` loop, otherwise compilers (wrongly) t
} else { } else {
return yy::parser::make_YYEOF(); return yy::parser::make_YYEOF();
} }
} else if (c == ',') {
return yy::parser::make_COMMA();
} else if (isNewline(c)) { } else if (isNewline(c)) {
// Handle CRLF. // Handle CRLF.
if (c == '\r' && context.file.sgetc() == '\n') { 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 const &typeInfo = sectionTypeInfo[activeType];
auto &pc = curAddr[activeType][activeBankIdx]; auto &pc = curAddr[activeType][activeBankIdx];
// TODO: maybe warn if truncating? if (alignment > 16) {
alignOfs %= 1 << alignment; scriptError(context, "Cannot align: The alignment (%" PRIu32 ") must be less than 16\n",
alignment);
assert(pc >= typeInfo.startAddr); return;
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;
} }
// 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) { 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 Linking failed with 1 error

View File

@@ -1,3 +1,3 @@
SECTION "sec",ROM0,ALIGN[4] SECTION "sec",ROM0,ALIGN[4,2]
ds 8, $42 ds 6, $42
SECTION "secfix",ROM0[$20] SECTION "secfix",ROM0[$20]

View File

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