From 82e0e4ffaf93f9d577fc21a1d6502d3093b6dca5 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 6 Apr 2020 00:45:22 +0200 Subject: [PATCH] Make some RGBLINK errors non-fatal --- include/link/main.h | 6 ++ src/link/assign.c | 12 ++-- src/link/main.c | 53 ++++++++++++-- src/link/patch.c | 88 +++++++++++------------ test/link/assert.out | 5 +- test/link/rst-bad.out | 1 + test/link/section-attributes-mismatch.out | 1 + test/link/section-union/assert.out | 4 +- 8 files changed, 111 insertions(+), 59 deletions(-) diff --git a/include/link/main.h b/include/link/main.h index bef93513..fd6ec886 100644 --- a/include/link/main.h +++ b/include/link/main.h @@ -14,6 +14,8 @@ #include #include +#include "helpers.h" + /* Variables related to CLI options */ extern bool isDmgMode; extern char const *linkerScriptName; @@ -32,6 +34,10 @@ extern bool isWRA0Mode; fprintf(stderr, __VA_ARGS__); \ } while (0) +void error(char const *fmt, ...); + +noreturn_ void fatal(char const *fmt, ...); + /** * Opens a file if specified, and aborts on error. * @param fileName The name of the file to open; if NULL, no file will be opened diff --git a/src/link/assign.c b/src/link/assign.c index c63d5320..10d609ca 100644 --- a/src/link/assign.c +++ b/src/link/assign.c @@ -80,15 +80,15 @@ static void processLinkerScript(void) /* Check if this doesn't conflict with what the code says */ if (section->isBankFixed && placement->bank != section->bank) - errx(1, "Linker script contradicts \"%s\"'s bank placement", - section->name); + error("Linker script contradicts \"%s\"'s bank placement", + section->name); if (section->isAddressFixed && placement->org != section->org) - errx(1, "Linker script contradicts \"%s\"'s address placement", - section->name); + error("Linker script contradicts \"%s\"'s address placement", + section->name); if (section->isAlignFixed && (placement->org & section->alignMask) != 0) - errx(1, "Linker script contradicts \"%s\"'s alignment", - section->name); + error("Linker script contradicts \"%s\"'s alignment", + section->name); section->isAddressFixed = true; section->org = placement->org; diff --git a/src/link/main.c b/src/link/main.c index fd9ecd35..31993c70 100644 --- a/src/link/main.c +++ b/src/link/main.c @@ -35,6 +35,40 @@ bool is32kMode; /* -t */ bool beVerbose; /* -v */ bool isWRA0Mode; /* -w */ +static uint32_t nbErrors = 0; + +void error(char const *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "error: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + putc('\n', stderr); + + if (nbErrors != UINT32_MAX) + nbErrors++; +} + +noreturn_ void fatal(char const *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "fatal: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + putc('\n', stderr); + + if (nbErrors != UINT32_MAX) + nbErrors++; + + fprintf(stderr, "Linking aborted after %u error%s\n", nbErrors, + nbErrors != 1 ? "s" : ""); + exit(1); +} + FILE *openFile(char const *fileName, char const *mode) { if (!fileName) @@ -138,10 +172,14 @@ int main(int argc, char *argv[]) break; case 'p': value = strtoul(optarg, &endptr, 0); - if (optarg[0] == '\0' || *endptr != '\0') - errx(1, "Invalid argument for option 'p'"); - if (value > 0xFF) - errx(1, "Argument for 'p' must be a byte (between 0 and 0xFF)"); + if (optarg[0] == '\0' || *endptr != '\0') { + error("Invalid argument for option 'p'"); + value = 0xFF; + } + if (value > 0xFF) { + error("Argument for 'p' must be a byte (between 0 and 0xFF)"); + value = 0xFF; + } padValue = value; break; case 's': @@ -171,7 +209,7 @@ int main(int argc, char *argv[]) /* If no input files were specified, the user must have screwed up */ if (curArgIndex == argc) { - fputs("FATAL: no input files\n", stderr); + fputs("fatal: no input files\n", stderr); printUsage(); exit(1); } @@ -198,6 +236,11 @@ int main(int argc, char *argv[]) /* and finally output the result. */ patch_ApplyPatches(); + if (nbErrors) { + fprintf(stderr, "Linking failed with %u error%s\n", nbErrors, + nbErrors != 1 ? "s" : ""); + exit(1); + } out_WriteFiles(); /* Do cleanup before quitting, though. */ diff --git a/src/link/patch.c b/src/link/patch.c index 34d8222c..ef610d94 100644 --- a/src/link/patch.c +++ b/src/link/patch.c @@ -118,19 +118,13 @@ static uint32_t getRPNByte(uint8_t const **expression, int32_t *size, } static struct Symbol const *getSymbol(struct Symbol const * const *symbolList, - uint32_t index, char const *fileName) + uint32_t index) { struct Symbol const *symbol = symbolList[index]; /* If the symbol is defined elsewhere... */ - if (symbol->type == SYMTYPE_IMPORT) { - struct Symbol const *symbolDefinition = - sym_GetSymbol(symbol->name); - if (!symbolDefinition) - errx(1, "%s: Unknown symbol \"%s\"", fileName, - symbol->name); - symbol = symbolDefinition; - } + if (symbol->type == SYMTYPE_IMPORT) + return sym_GetSymbol(symbol->name); return symbol; } @@ -182,9 +176,13 @@ static int32_t computeRPNExpr(struct Patch const *patch, break; case RPN_DIV: value = popRPN(); - if (value == 0) - errx(1, "%s: Division by 0", patch->fileName); - value = popRPN() / value; + if (value == 0) { + error("%s: Division by 0", patch->fileName); + popRPN(); + value = INT32_MAX; + } else { + value = popRPN() / value; + } break; case RPN_MOD: value = popRPN(); @@ -256,9 +254,16 @@ static int32_t computeRPNExpr(struct Patch const *patch, for (uint8_t shift = 0; shift < 32; shift += 8) value |= getRPNByte(&expression, &size, patch->fileName) << shift; + symbol = getSymbol(fileSymbols, value); - value = getSymbol(fileSymbols, value, - patch->fileName)->section->bank; + if (!symbol) { + error("%s: Requested BANK() of symbol \"%s\", which was not found", + patch->fileName, + fileSymbols[value]->name); + value = 1; + } else { + value = symbol->section->bank; + } break; case RPN_BANK_SECT: @@ -268,11 +273,13 @@ static int32_t computeRPNExpr(struct Patch const *patch, sect = sect_GetSection(name); - if (!sect) - errx(1, "%s: Requested BANK() of section \"%s\", which was not found", - patch->fileName, name); - - value = sect->bank; + if (!sect) { + error("%s: Requested BANK() of section \"%s\", which was not found", + patch->fileName, name); + value = 1; + } else { + value = sect->bank; + } break; case RPN_BANK_SELF: @@ -284,8 +291,8 @@ static int32_t computeRPNExpr(struct Patch const *patch, if (value < 0 || (value > 0xFF && value < 0xFF00) || value > 0xFFFF) - errx(1, "%s: Value %d is not in HRAM range", - patch->fileName, value); + error("%s: Value %d is not in HRAM range", + patch->fileName, value); value &= 0xFF; break; @@ -295,8 +302,8 @@ static int32_t computeRPNExpr(struct Patch const *patch, * They can be easily checked with a bitmask */ if (value & ~0x38) - errx(1, "%s: Value %d is not a RST vector", - patch->fileName, value); + error("%s: Value %d is not a RST vector", + patch->fileName, value); value |= 0xC7; break; @@ -313,7 +320,7 @@ static int32_t computeRPNExpr(struct Patch const *patch, value |= getRPNByte(&expression, &size, patch->fileName) << shift; - symbol = getSymbol(fileSymbols, value, patch->fileName); + symbol = getSymbol(fileSymbols, value); if (!strcmp(symbol->name, "@")) { value = section->org + patch->offset; @@ -330,7 +337,7 @@ static int32_t computeRPNExpr(struct Patch const *patch, } if (stack.size > 1) - warnx("%s: RPN stack has %lu entries on exit, not 1", + error("%s: RPN stack has %lu entries on exit, not 1", patch->fileName, stack.size); return popRPN(); @@ -343,25 +350,21 @@ void patch_CheckAssertions(struct Assertion *assert) verbosePrint("Checking assertions..."); initRPNStack(); - uint8_t failures = 0; - while (assert) { 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, - assert->message[0] ? assert->message - : "assert failure"); + fatal("%s: %s", assert->patch.fileName, + assert->message[0] ? assert->message + : "assert failure"); /* Not reached */ break; /* Here so checkpatch doesn't complain */ case ASSERT_ERROR: - fprintf(stderr, "%s: %s\n", - assert->patch.fileName, - assert->message[0] ? assert->message - : "assert failure"); - failures++; + error("%s: %s", assert->patch.fileName, + assert->message[0] ? assert->message + : "assert failure"); break; case ASSERT_WARN: warnx("%s: %s", assert->patch.fileName, @@ -377,9 +380,6 @@ void patch_CheckAssertions(struct Assertion *assert) } freeRPNStack(); - - if (failures) - errx(1, "%u assertions failed!", failures); } /** @@ -406,8 +406,8 @@ static void applyFilePatches(struct Section *section) int16_t offset = value - address; if (offset < -128 || offset > 127) - errx(1, "%s: jr target out of reach (expected -129 < %d < 128)", - patch->fileName, offset); + error("%s: jr target out of reach (expected -129 < %d < 128)", + patch->fileName, offset); section->data[patch->offset] = offset & 0xFF; } else { /* Patch a certain number of bytes */ @@ -423,10 +423,10 @@ static void applyFilePatches(struct Section *section) if (value < types[patch->type].min || value > types[patch->type].max) - errx(1, "%s: Value %#x%s is not %u-bit", - patch->fileName, value, - value < 0 ? " (maybe negative?)" : "", - types[patch->type].size * 8); + error("%s: Value %#x%s is not %u-bit", + patch->fileName, value, + value < 0 ? " (maybe negative?)" : "", + types[patch->type].size * 8); for (uint8_t i = 0; i < types[patch->type].size; i++) { section->data[patch->offset + i] = value & 0xFF; value >>= 8; diff --git a/test/link/assert.out b/test/link/assert.out index f7d2cb63..e533a048 100644 --- a/test/link/assert.out +++ b/test/link/assert.out @@ -1,3 +1,4 @@ warning: assert.asm(7): Worry about me, but not too much. -assert.asm(8): Okay, this is getting serious! -error: assert.asm(9): It all ends now. +error: assert.asm(8): Okay, this is getting serious! +fatal: assert.asm(9): It all ends now. +Linking aborted after 2 errors diff --git a/test/link/rst-bad.out b/test/link/rst-bad.out index 6783e4d5..e315a01b 100644 --- a/test/link/rst-bad.out +++ b/test/link/rst-bad.out @@ -1 +1,2 @@ error: rst-bad.asm(2): Value 1 is not a RST vector +Linking failed with 1 error diff --git a/test/link/section-attributes-mismatch.out b/test/link/section-attributes-mismatch.out index 4512445d..e49983cc 100644 --- a/test/link/section-attributes-mismatch.out +++ b/test/link/section-attributes-mismatch.out @@ -1 +1,2 @@ error: Linker script contradicts "sec"'s alignment +Linking failed with 1 error diff --git a/test/link/section-union/assert.out b/test/link/section-union/assert.out index d0bce86e..c50272d9 100644 --- a/test/link/section-union/assert.out +++ b/test/link/section-union/assert.out @@ -1,5 +1,5 @@ -section-union/assert.asm(11): Force failing the build -error: 1 assertions failed! +error: section-union/assert.asm(11): Force failing the build +Linking failed with 1 error --- ERROR: -(30): Assertion failed: Force failing the build