Implement ds align[alignment, offset] (#1181)

This commit is contained in:
Rangi
2023-11-21 17:57:47 -05:00
committed by GitHub
parent 6f0ffcf3e1
commit 46e29de66f
17 changed files with 148 additions and 17 deletions

View File

@@ -503,6 +503,7 @@ enum {
struct SectionSpec sectSpec;
struct MacroArgs *macroArg;
enum AssertionType assertType;
struct DsAlignment dsAlign;
struct DsArgList dsArgs;
struct PurgeArgList purgeArgs;
struct {
@@ -660,6 +661,7 @@ enum {
%type <sectMod> sectmod
%type <macroArg> macroargs
%type <dsAlign> ds_align
%type <dsArgs> ds_args
%type <purgeArgs> purge_args
@@ -1194,6 +1196,40 @@ ds : T_POP_DS uconst { sect_Skip($2, true); }
sect_RelBytes($2, $4.args, $4.nbArgs);
freeDsArgList(&$4);
}
| T_POP_DS ds_align trailing_comma {
uint32_t n = sect_GetAlignBytes($2.alignment, $2.alignOfs);
sect_Skip(n, true);
sect_AlignPC($2.alignment, $2.alignOfs);
}
| T_POP_DS ds_align T_COMMA ds_args trailing_comma {
uint32_t n = sect_GetAlignBytes($2.alignment, $2.alignOfs);
sect_RelBytes(n, $4.args, $4.nbArgs);
sect_AlignPC($2.alignment, $2.alignOfs);
freeDsArgList(&$4);
}
;
ds_align : T_OP_ALIGN T_LBRACK uconst T_RBRACK {
if ($3 > 16) {
error("Alignment must be between 0 and 16, not %u\n", $3);
} else {
$$.alignment = $3;
$$.alignOfs = 0;
}
}
| T_OP_ALIGN T_LBRACK uconst T_COMMA uconst T_RBRACK {
if ($3 > 16) {
error("Alignment must be between 0 and 16, not %u\n", $3);
} else if ($5 >= 1 << $3) {
error("Offset must be between 0 and %u, not %u\n",
(1 << $3) - 1, $5);
} else {
$$.alignment = $3;
$$.alignOfs = $5;
}
}
;
ds_args : reloc_8bit {

View File

@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: MIT */
#include <algorithm>
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
@@ -471,6 +472,27 @@ uint32_t sect_GetOutputOffset(void)
return curOffset + loadOffset;
}
// Returns how many bytes need outputting for the specified alignment and offset to succeed
uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset)
{
struct Section *sect = sect_GetSymbolSection();
if (!sect)
return 0;
bool isFixed = sect->org != (uint32_t)-1;
// If the section is not aligned, no bytes are needed
// (fixed sections count as being maximally aligned for this purpose)
uint8_t curAlignment = isFixed ? 16 : sect->align;
if (curAlignment == 0)
return 0;
// We need `(pcValue + curOffset + return value) % (1 << alignment) == offset`
uint16_t pcValue = isFixed ? sect->org : sect->alignOfs;
return static_cast<uint16_t>(offset - curOffset - pcValue)
% (1u << std::min(alignment, curAlignment));
}
void sect_AlignPC(uint8_t alignment, uint16_t offset)
{
if (!checksection())
@@ -480,20 +502,16 @@ void sect_AlignPC(uint8_t alignment, uint16_t offset)
uint16_t alignSize = 1 << alignment; // Size of an aligned "block"
if (sect->org != (uint32_t)-1) {
if ((sym_GetPCValue() - offset) % alignSize)
if ((sect->org + curOffset - offset) % alignSize)
error("Section's fixed address fails required alignment (PC = $%04" PRIx32
")\n", sym_GetPCValue());
} else if (sect->align != 0) {
if ((((sect->alignOfs + curOffset) % (1 << sect->align)) - offset) % alignSize) {
error("Section's alignment fails required alignment (offset from section start = $%04"
PRIx32 ")\n", curOffset);
} else if (alignment > sect->align) {
sect->align = alignment;
sect->alignOfs = (offset - curOffset) % alignSize;
}
} else {
")\n", sect->org + curOffset);
} else if (sect->align != 0 && (((sect->alignOfs + curOffset) % (1u << sect->align))
- offset) % alignSize) {
error("Section's alignment fails required alignment (offset from section start = $%04"
PRIx32 ")\n", curOffset);
} else if (alignment > sect->align) {
sect->align = alignment;
// We need `(sect->alignOfs + curOffset) % alignSize == offset
// We need `(sect->alignOfs + curOffset) % alignSize == offset`
sect->alignOfs = (offset - curOffset) % alignSize;
}
}