From 52797b6f68bd470d538f5b12dff1c716eea4db09 Mon Sep 17 00:00:00 2001 From: Rangi <35663410+Rangi42@users.noreply.github.com> Date: Sat, 17 Apr 2021 18:36:26 -0400 Subject: [PATCH] Implement SIZEOF("Section") and STARTOF("Section") (#766) Updates the object file revision to 8 Fixes #765 --- include/asm/rpn.h | 2 + include/linkdefs.h | 76 ++++++++++++++-------------- src/asm/lexer.c | 5 +- src/asm/output.c | 16 ++++++ src/asm/parser.y | 3 ++ src/asm/rgbasm.5 | 6 +++ src/asm/rpn.c | 30 +++++++++++ src/link/patch.c | 43 ++++++++++++++++ src/rgbds.5 | 4 ++ test/asm/section-sizeof-startof.asm | 8 +++ test/asm/section-sizeof-startof.err | 5 ++ test/asm/section-sizeof-startof.out | 1 + test/link/sizeof-startof.asm | 7 +++ test/link/sizeof-startof.out.bin | Bin 0 -> 5 bytes 14 files changed, 168 insertions(+), 38 deletions(-) create mode 100644 test/asm/section-sizeof-startof.asm create mode 100644 test/asm/section-sizeof-startof.err create mode 100644 test/asm/section-sizeof-startof.out create mode 100644 test/link/sizeof-startof.asm create mode 100644 test/link/sizeof-startof.out.bin diff --git a/include/asm/rpn.h b/include/asm/rpn.h index d5a2eb8f6..e5af4e530 100644 --- a/include/asm/rpn.h +++ b/include/asm/rpn.h @@ -59,6 +59,8 @@ void rpn_UNNOT(struct Expression *expr, const struct Expression *src); void rpn_BankSymbol(struct Expression *expr, char const *tzSym); void rpn_BankSection(struct Expression *expr, char const *tzSectionName); void rpn_BankSelf(struct Expression *expr); +void rpn_SizeOfSection(struct Expression *expr, char const *tzSectionName); +void rpn_StartOfSection(struct Expression *expr, char const *tzSectionName); void rpn_Free(struct Expression *expr); void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src); void rpn_CheckRST(struct Expression *expr, const struct Expression *src); diff --git a/include/linkdefs.h b/include/linkdefs.h index d21f61f83..23c1fb42f 100644 --- a/include/linkdefs.h +++ b/include/linkdefs.h @@ -14,7 +14,7 @@ #define RGBDS_OBJECT_VERSION_STRING "RGB%1u" #define RGBDS_OBJECT_VERSION_NUMBER 9U -#define RGBDS_OBJECT_REV 7U +#define RGBDS_OBJECT_REV 8U enum AssertionType { ASSERT_WARN, @@ -23,42 +23,44 @@ enum AssertionType { }; enum RPNCommand { - RPN_ADD = 0x00, - RPN_SUB = 0x01, - RPN_MUL = 0x02, - RPN_DIV = 0x03, - RPN_MOD = 0x04, - RPN_UNSUB = 0x05, - RPN_EXP = 0x06, - - RPN_OR = 0x10, - RPN_AND = 0x11, - RPN_XOR = 0x12, - RPN_UNNOT = 0x13, - - RPN_LOGAND = 0x21, - RPN_LOGOR = 0x22, - RPN_LOGUNNOT = 0x23, - - RPN_LOGEQ = 0x30, - RPN_LOGNE = 0x31, - RPN_LOGGT = 0x32, - RPN_LOGLT = 0x33, - RPN_LOGGE = 0x34, - RPN_LOGLE = 0x35, - - RPN_SHL = 0x40, - RPN_SHR = 0x41, - - RPN_BANK_SYM = 0x50, - RPN_BANK_SECT = 0x51, - RPN_BANK_SELF = 0x52, - - RPN_HRAM = 0x60, - RPN_RST = 0x61, - - RPN_CONST = 0x80, - RPN_SYM = 0x81 + RPN_ADD = 0x00, + RPN_SUB = 0x01, + RPN_MUL = 0x02, + RPN_DIV = 0x03, + RPN_MOD = 0x04, + RPN_UNSUB = 0x05, + RPN_EXP = 0x06, + + RPN_OR = 0x10, + RPN_AND = 0x11, + RPN_XOR = 0x12, + RPN_UNNOT = 0x13, + + RPN_LOGAND = 0x21, + RPN_LOGOR = 0x22, + RPN_LOGUNNOT = 0x23, + + RPN_LOGEQ = 0x30, + RPN_LOGNE = 0x31, + RPN_LOGGT = 0x32, + RPN_LOGLT = 0x33, + RPN_LOGGE = 0x34, + RPN_LOGLE = 0x35, + + RPN_SHL = 0x40, + RPN_SHR = 0x41, + + RPN_BANK_SYM = 0x50, + RPN_BANK_SECT = 0x51, + RPN_BANK_SELF = 0x52, + RPN_SIZEOF_SECT = 0x53, + RPN_STARTOF_SECT = 0x54, + + RPN_HRAM = 0x60, + RPN_RST = 0x61, + + RPN_CONST = 0x80, + RPN_SYM = 0x81 }; enum SectionType { diff --git a/src/asm/lexer.c b/src/asm/lexer.c index 27d59229b..ecfadc42c 100644 --- a/src/asm/lexer.c +++ b/src/asm/lexer.c @@ -180,6 +180,9 @@ static struct KeywordMapping { {"BANK", T_OP_BANK}, {"ALIGN", T_OP_ALIGN}, + {"SIZEOF", T_OP_SIZEOF}, + {"STARTOF", T_OP_STARTOF}, + {"ROUND", T_OP_ROUND}, {"CEIL", T_OP_CEIL}, {"FLOOR", T_OP_FLOOR}, @@ -592,7 +595,7 @@ struct KeywordDictNode { uint16_t children[0x60 - ' ']; struct KeywordMapping const *keyword; /* Since the keyword structure is invariant, the min number of nodes is known at compile time */ -} keywordDict[357] = {0}; /* Make sure to keep this correct when adding keywords! */ +} keywordDict[365] = {0}; /* Make sure to keep this correct when adding keywords! */ /* Convert a char into its index into the dict */ static uint8_t dictIndex(char c) diff --git a/src/asm/output.c b/src/asm/output.c index d57c67687..305d8b8e2 100644 --- a/src/asm/output.c +++ b/src/asm/output.c @@ -354,6 +354,22 @@ static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn, } while (b != 0); break; + case RPN_SIZEOF_SECT: + writebyte(RPN_SIZEOF_SECT); + do { + b = popbyte(); + writebyte(b); + } while (b != 0); + break; + + case RPN_STARTOF_SECT: + writebyte(RPN_STARTOF_SECT); + do { + b = popbyte(); + writebyte(b); + } while (b != 0); + break; + default: writebyte(rpndata); break; diff --git a/src/asm/parser.y b/src/asm/parser.y index 1b156af68..b4ecdf095 100644 --- a/src/asm/parser.y +++ b/src/asm/parser.y @@ -514,6 +514,7 @@ enum { %token T_OP_DEF "DEF" %token T_OP_BANK "BANK" %token T_OP_ALIGN "ALIGN" +%token T_OP_SIZEOF "SIZEOF" T_OP_STARTOF "STARTOF" %token T_OP_SIN "SIN" T_OP_COS "COS" T_OP_TAN "TAN" %token T_OP_ASIN "ASIN" T_OP_ACOS "ACOS" T_OP_ATAN "ATAN" T_OP_ATAN2 "ATAN2" %token T_OP_FDIV "FDIV" @@ -1419,6 +1420,8 @@ relocexpr_no_str : scoped_anon_id { rpn_Symbol(&$$, $1); } rpn_BankSymbol(&$$, $3); } | T_OP_BANK T_LPAREN string T_RPAREN { rpn_BankSection(&$$, $3); } + | T_OP_SIZEOF T_LPAREN string T_RPAREN { rpn_SizeOfSection(&$$, $3); } + | T_OP_STARTOF T_LPAREN string T_RPAREN { rpn_StartOfSection(&$$, $3); } | T_OP_DEF { lexer_ToggleStringExpansion(false); } T_LPAREN scoped_anon_id T_RPAREN { diff --git a/src/asm/rgbasm.5 b/src/asm/rgbasm.5 index 178ce9ba2..cdc95989f 100644 --- a/src/asm/rgbasm.5 +++ b/src/asm/rgbasm.5 @@ -461,6 +461,12 @@ is a label, it returns the bank number the label is in. The result may be constant if .Nm is able to compute it. +.It Fn SIZEOF arg Ta Returns the size of the section named +.Ar arg . +The result is not constant, since only RGBLINK can compute its value. +.It Fn STARTOF arg Ta Returns the starting address of the section named +.Ar arg . +The result is not constant, since only RGBLINK can compute its value. .It Fn DEF symbol Ta Returns TRUE (1) if .Ar symbol has been defined, FALSE (0) otherwise. diff --git a/src/asm/rpn.c b/src/asm/rpn.c index bc363c171..1b1e63359 100644 --- a/src/asm/rpn.c +++ b/src/asm/rpn.c @@ -201,6 +201,34 @@ void rpn_BankSection(struct Expression *expr, char const *tzSectionName) } } +void rpn_SizeOfSection(struct Expression *expr, char const *tzSectionName) +{ + rpn_Init(expr); + + makeUnknown(expr, "Section \"%s\"'s size is not known", tzSectionName); + + size_t nameLen = strlen(tzSectionName) + 1; /* Room for NUL! */ + uint8_t *ptr = reserveSpace(expr, nameLen + 1); + + expr->nRPNPatchSize += nameLen + 1; + *ptr++ = RPN_SIZEOF_SECT; + memcpy(ptr, tzSectionName, nameLen); +} + +void rpn_StartOfSection(struct Expression *expr, char const *tzSectionName) +{ + rpn_Init(expr); + + makeUnknown(expr, "Section \"%s\"'s start is not known", tzSectionName); + + size_t nameLen = strlen(tzSectionName) + 1; /* Room for NUL! */ + uint8_t *ptr = reserveSpace(expr, nameLen + 1); + + expr->nRPNPatchSize += nameLen + 1; + *ptr++ = RPN_STARTOF_SECT; + memcpy(ptr, tzSectionName, nameLen); +} + void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src) { *expr = *src; @@ -396,6 +424,8 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, case RPN_BANK_SYM: case RPN_BANK_SECT: case RPN_BANK_SELF: + case RPN_SIZEOF_SECT: + case RPN_STARTOF_SECT: case RPN_HRAM: case RPN_RST: case RPN_CONST: diff --git a/src/link/patch.c b/src/link/patch.c index 1ff6d50b0..28ec412a8 100644 --- a/src/link/patch.c +++ b/src/link/patch.c @@ -292,6 +292,11 @@ static int32_t computeRPNExpr(struct Patch const *patch, break; case RPN_BANK_SECT: + /* + * `expression` is not guaranteed to be '\0'-terminated. If it is not, + * `getRPNByte` will have a fatal internal error. + * In either case, `getRPNByte` will not free `expression`. + */ name = (char const *)expression; while (getRPNByte(&expression, &size, patch->src, patch->lineNo)) ; @@ -320,6 +325,44 @@ static int32_t computeRPNExpr(struct Patch const *patch, } break; + case RPN_SIZEOF_SECT: + /* This has assumptions commented in the `RPN_BANK_SECT` case above. */ + name = (char const *)expression; + while (getRPNByte(&expression, &size, patch->src, patch->lineNo)) + ; + + sect = sect_GetSection(name); + + if (!sect) { + error(patch->src, patch->lineNo, + "Requested SIZEOF() of section \"%s\", which was not found", + name); + isError = true; + value = 1; + } else { + value = sect->size; + } + break; + + case RPN_STARTOF_SECT: + /* This has assumptions commented in the `RPN_BANK_SECT` case above. */ + name = (char const *)expression; + while (getRPNByte(&expression, &size, patch->src, patch->lineNo)) + ; + + sect = sect_GetSection(name); + + if (!sect) { + error(patch->src, patch->lineNo, + "Requested STARTOF() of section \"%s\", which was not found", + name); + isError = true; + value = 1; + } else { + value = sect->org; + } + break; + case RPN_HRAM: value = popRPN(); if (!isError && (value < 0 diff --git a/src/rgbds.5 b/src/rgbds.5 index f787ac79d..677bf7bd7 100644 --- a/src/rgbds.5 +++ b/src/rgbds.5 @@ -248,6 +248,10 @@ Symbol ID follows, where -1 means PC .It Li $51 Ta Li BANK(section_name) , a null-terminated string follows. .It Li $52 Ta Li Current BANK() +.It Li $53 Ta Li SIZEOF(section_name) , +a null-terminated string follows. +.It Li $54 Ta Li STARTOF(section_name) , +a null-terminated string follows. .It Li $60 Ta Li HRAMCheck . Checks if the value is in HRAM, ANDs it with 0xFF. .It Li $61 Ta Li RSTCheck . diff --git a/test/asm/section-sizeof-startof.asm b/test/asm/section-sizeof-startof.asm new file mode 100644 index 000000000..99e7c36ef --- /dev/null +++ b/test/asm/section-sizeof-startof.asm @@ -0,0 +1,8 @@ +SECTION "sect", ROMX[$4567], BANK[$23] + ds 42 + +W = BANK("sect") +X = SIZEOF("sect") +Y = STARTOF("sect") + + println "{W} {X} {Y}" diff --git a/test/asm/section-sizeof-startof.err b/test/asm/section-sizeof-startof.err new file mode 100644 index 000000000..8b8f95a9e --- /dev/null +++ b/test/asm/section-sizeof-startof.err @@ -0,0 +1,5 @@ +ERROR: section-sizeof-startof.asm(5): + Expected constant expression: Section "sect"'s size is not known +ERROR: section-sizeof-startof.asm(6): + Expected constant expression: Section "sect"'s start is not known +error: Assembly aborted (2 errors)! diff --git a/test/asm/section-sizeof-startof.out b/test/asm/section-sizeof-startof.out new file mode 100644 index 000000000..5872dbfac --- /dev/null +++ b/test/asm/section-sizeof-startof.out @@ -0,0 +1 @@ +$23 $0 $0 diff --git a/test/link/sizeof-startof.asm b/test/link/sizeof-startof.asm new file mode 100644 index 000000000..ae1a49f9c --- /dev/null +++ b/test/link/sizeof-startof.asm @@ -0,0 +1,7 @@ +SECTION "meta", ROM0[0] + db BANK("sect") + dw STARTOF("sect") + dw SIZEOF("sect") + +SECTION "sect", ROMX[$4567], BANK[$23] + ds 42 diff --git a/test/link/sizeof-startof.out.bin b/test/link/sizeof-startof.out.bin new file mode 100644 index 0000000000000000000000000000000000000000..b00e9df0062f749543fd357d2b3f0cb5fffeacd3 GIT binary patch literal 5 McmY#RchzD500VOX`Tzg` literal 0 HcmV?d00001