ref: a3d88366716a0c5115a54296d93fb6ee650fd08e
parent: db1eb8fbcbcd06bcbfa7f6244f06ae2807f1e94d
author: ISSOtm <[email protected]>
date: Sun Mar 29 08:18:24 EDT 2020
Prevent assertions outside sections from crashing
--- a/include/link/patch.h
+++ b/include/link/patch.h
@@ -22,6 +22,11 @@
// enum AssertionType type; The `patch`'s field is instead re-used
struct Section *section;
char *message;
+ /*
+ * This would be redundant with `.section->fileSymbols`... but
+ * `section` is sometimes NULL!
+ */
+ struct Symbol ** fileSymbols;
struct Assertion *next;
};
--- a/src/asm/output.c
+++ b/src/asm/output.c
@@ -362,7 +362,7 @@
static void writeassert(struct Assertion *assert, FILE *f)
{
writepatch(assert->patch, f);
- fputlong(getsectid(assert->section), f);
+ fputlong(assert->section ? getsectid(assert->section) : -1, f);
fputstring(assert->message, f);
}
--- a/src/link/object.c
+++ b/src/link/object.c
@@ -356,7 +356,7 @@
readPatch(file, &assert->patch, fileName, assertName, 0);
tryReadlong(sectionID, file, "%s: Cannot read assertion's section ID: %s",
fileName);
- assert->section = fileSections[sectionID];
+ assert->section = sectionID == -1 ? NULL : fileSections[sectionID];
tryReadstr(assert->message, file, "%s: Cannot read assertion's message: %s",
fileName);
}
@@ -502,6 +502,7 @@
if (!assertion)
err(1, "%s: Couldn't create new assertion", fileName);
readAssertion(file, assertion, fileName, fileSections, i);
+ assertion->fileSymbols = fileSymbols;
assertion->next = assertions;
assertions = assertion;
}
--- a/src/link/patch.c
+++ b/src/link/patch.c
@@ -117,7 +117,7 @@
return *(*expression)++;
}
-static struct Symbol const *getSymbol(struct Symbol ** const symbolList,
+static struct Symbol const *getSymbol(struct Symbol const * const *symbolList,
uint32_t index, char const *fileName)
{
struct Symbol const *symbol = symbolList[index];
@@ -142,7 +142,8 @@
* @return The patch's value
*/
static int32_t computeRPNExpr(struct Patch const *patch,
- struct Section const *section)
+ struct Section const *section,
+ struct Symbol const * const *fileSymbols)
{
/* Small shortcut to avoid a lot of repetition */
#define popRPN() popRPN(patch->fileName)
@@ -256,7 +257,7 @@
value |= getRPNByte(&expression, &size,
patch->fileName) << shift;
- value = getSymbol(section->fileSymbols, value,
+ value = getSymbol(fileSymbols, value,
patch->fileName)->section->bank;
break;
@@ -312,8 +313,7 @@
value |= getRPNByte(&expression, &size,
patch->fileName) << shift;
- symbol = getSymbol(section->fileSymbols, value,
- patch->fileName);
+ symbol = getSymbol(fileSymbols, value, patch->fileName);
if (!strcmp(symbol->name, "@")) {
value = section->org + patch->offset;
@@ -346,7 +346,9 @@
uint8_t failures = 0;
while (assert) {
- if (!computeRPNExpr(&assert->patch, assert->section)) {
+ if (!computeRPNExpr(&assert->patch, assert->section,
+ (struct Symbol const * const *)
+ assert->fileSymbols)) {
switch ((enum AssertionType)assert->patch.type) {
case ASSERT_FATAL:
errx(1, "%s: %s", assert->patch.fileName,
@@ -393,7 +395,9 @@
verbosePrint("Patching section \"%s\"...\n", section->name);
for (uint32_t patchID = 0; patchID < section->nbPatches; patchID++) {
struct Patch *patch = §ion->patches[patchID];
- int32_t value = computeRPNExpr(patch, section);
+ int32_t value = computeRPNExpr(patch, section,
+ (struct Symbol const * const *)
+ section->fileSymbols);
/* `jr` is quite unlike the others... */
if (patch->type == PATCHTYPE_JR) {
--- /dev/null
+++ b/test/asm/assert-nosect.asm
@@ -1,0 +1,5 @@
+assert Sym
+
+SECTION "test", ROM0
+ db 69
+Sym:
--- /dev/null
+++ b/test/asm/assert-nosect.out.bin
@@ -1,0 +1,1 @@
+E
\ No newline at end of file