mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Fix incorrect PC in LOAD blocks at link time
This commit is contained in:
@@ -20,7 +20,6 @@
|
|||||||
struct Assertion {
|
struct Assertion {
|
||||||
struct Patch patch;
|
struct Patch patch;
|
||||||
// enum AssertionType type; The `patch`'s field is instead re-used
|
// enum AssertionType type; The `patch`'s field is instead re-used
|
||||||
struct Section *section;
|
|
||||||
char *message;
|
char *message;
|
||||||
/*
|
/*
|
||||||
* This would be redundant with `.section->fileSymbols`... but
|
* This would be redundant with `.section->fileSymbols`... but
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include "linkdefs.h"
|
#include "linkdefs.h"
|
||||||
|
|
||||||
|
struct Section;
|
||||||
|
|
||||||
struct AttachedSymbol {
|
struct AttachedSymbol {
|
||||||
struct Symbol *symbol;
|
struct Symbol *symbol;
|
||||||
struct AttachedSymbol *next;
|
struct AttachedSymbol *next;
|
||||||
@@ -27,9 +29,13 @@ struct AttachedSymbol {
|
|||||||
struct Patch {
|
struct Patch {
|
||||||
char *fileName;
|
char *fileName;
|
||||||
int32_t offset;
|
int32_t offset;
|
||||||
|
uint32_t pcSectionID;
|
||||||
|
uint32_t pcOffset;
|
||||||
enum PatchType type;
|
enum PatchType type;
|
||||||
int32_t rpnSize;
|
int32_t rpnSize;
|
||||||
uint8_t *rpnExpression;
|
uint8_t *rpnExpression;
|
||||||
|
|
||||||
|
struct Section const *pcSection;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Section {
|
struct Section {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
#define RGBDS_OBJECT_VERSION_STRING "RGB%1hhu"
|
#define RGBDS_OBJECT_VERSION_STRING "RGB%1hhu"
|
||||||
#define RGBDS_OBJECT_VERSION_NUMBER (uint8_t)9
|
#define RGBDS_OBJECT_VERSION_NUMBER (uint8_t)9
|
||||||
#define RGBDS_OBJECT_REV 3
|
#define RGBDS_OBJECT_REV 4
|
||||||
|
|
||||||
enum AssertionType {
|
enum AssertionType {
|
||||||
ASSERT_WARN,
|
ASSERT_WARN,
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
struct Patch {
|
struct Patch {
|
||||||
char tzFilename[_MAX_PATH + 1];
|
char tzFilename[_MAX_PATH + 1];
|
||||||
uint32_t nOffset;
|
uint32_t nOffset;
|
||||||
|
struct Section *pcSection;
|
||||||
|
uint32_t pcOffset;
|
||||||
uint8_t nType;
|
uint8_t nType;
|
||||||
uint32_t nRPNSize;
|
uint32_t nRPNSize;
|
||||||
uint8_t *pRPN;
|
uint8_t *pRPN;
|
||||||
@@ -79,16 +81,13 @@ static uint32_t countsections(void)
|
|||||||
/*
|
/*
|
||||||
* Count the number of patches used in this object
|
* Count the number of patches used in this object
|
||||||
*/
|
*/
|
||||||
static uint32_t countpatches(struct Section *pSect)
|
static uint32_t countpatches(struct Section const *pSect)
|
||||||
{
|
{
|
||||||
struct Patch *pPatch;
|
|
||||||
uint32_t r = 0;
|
uint32_t r = 0;
|
||||||
|
|
||||||
pPatch = pSect->pPatches;
|
for (struct Patch const *patch = pSect->pPatches; patch != NULL;
|
||||||
while (pPatch) {
|
patch = patch->pNext)
|
||||||
r++;
|
r++;
|
||||||
pPatch = pPatch->pNext;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -132,9 +131,9 @@ static void fputstring(char const *s, FILE *f)
|
|||||||
/*
|
/*
|
||||||
* Return a section's ID
|
* Return a section's ID
|
||||||
*/
|
*/
|
||||||
static uint32_t getsectid(struct Section *pSect)
|
static uint32_t getsectid(struct Section const *pSect)
|
||||||
{
|
{
|
||||||
struct Section *sec;
|
struct Section const *sec;
|
||||||
uint32_t ID = 0;
|
uint32_t ID = 0;
|
||||||
|
|
||||||
sec = pSectionList;
|
sec = pSectionList;
|
||||||
@@ -149,13 +148,20 @@ static uint32_t getsectid(struct Section *pSect)
|
|||||||
fatalerror("Unknown section '%s'", pSect->pzName);
|
fatalerror("Unknown section '%s'", pSect->pzName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t getSectIDIfAny(struct Section const *sect)
|
||||||
|
{
|
||||||
|
return sect ? getsectid(sect) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write a patch to a file
|
* Write a patch to a file
|
||||||
*/
|
*/
|
||||||
static void writepatch(struct Patch *pPatch, FILE *f)
|
static void writepatch(struct Patch const *pPatch, FILE *f)
|
||||||
{
|
{
|
||||||
fputstring(pPatch->tzFilename, f);
|
fputstring(pPatch->tzFilename, f);
|
||||||
fputlong(pPatch->nOffset, f);
|
fputlong(pPatch->nOffset, f);
|
||||||
|
fputlong(getSectIDIfAny(pPatch->pcSection), f);
|
||||||
|
fputlong(pPatch->pcOffset, f);
|
||||||
fputc(pPatch->nType, f);
|
fputc(pPatch->nType, f);
|
||||||
fputlong(pPatch->nRPNSize, f);
|
fputlong(pPatch->nRPNSize, f);
|
||||||
fwrite(pPatch->pRPN, 1, pPatch->nRPNSize, f);
|
fwrite(pPatch->pRPN, 1, pPatch->nRPNSize, f);
|
||||||
@@ -164,7 +170,7 @@ static void writepatch(struct Patch *pPatch, FILE *f)
|
|||||||
/*
|
/*
|
||||||
* Write a section to a file
|
* Write a section to a file
|
||||||
*/
|
*/
|
||||||
static void writesection(struct Section *pSect, FILE *f)
|
static void writesection(struct Section const *pSect, FILE *f)
|
||||||
{
|
{
|
||||||
fputstring(pSect->pzName, f);
|
fputstring(pSect->pzName, f);
|
||||||
|
|
||||||
@@ -177,16 +183,12 @@ static void writesection(struct Section *pSect, FILE *f)
|
|||||||
fputlong(pSect->nAlign, f);
|
fputlong(pSect->nAlign, f);
|
||||||
|
|
||||||
if (sect_HasData(pSect->nType)) {
|
if (sect_HasData(pSect->nType)) {
|
||||||
struct Patch *pPatch;
|
|
||||||
|
|
||||||
fwrite(pSect->tData, 1, pSect->size, f);
|
fwrite(pSect->tData, 1, pSect->size, f);
|
||||||
fputlong(countpatches(pSect), f);
|
fputlong(countpatches(pSect), f);
|
||||||
|
|
||||||
pPatch = pSect->pPatches;
|
for (struct Patch const *patch = pSect->pPatches; patch != NULL;
|
||||||
while (pPatch) {
|
patch = patch->pNext)
|
||||||
writepatch(pPatch, f);
|
writepatch(patch, f);
|
||||||
pPatch = pPatch->pNext;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +204,7 @@ static void writesymbol(struct sSymbol const *pSym, FILE *f)
|
|||||||
fputc(pSym->isExported ? SYMTYPE_EXPORT : SYMTYPE_LOCAL, f);
|
fputc(pSym->isExported ? SYMTYPE_EXPORT : SYMTYPE_LOCAL, f);
|
||||||
fputstring(pSym->tzFileName, f);
|
fputstring(pSym->tzFileName, f);
|
||||||
fputlong(pSym->nFileLine, f);
|
fputlong(pSym->nFileLine, f);
|
||||||
fputlong(pSym->pSection ? getsectid(pSym->pSection) : -1, f);
|
fputlong(getSectIDIfAny(pSym->pSection), f);
|
||||||
fputlong(pSym->nValue, f);
|
fputlong(pSym->nValue, f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,9 +302,7 @@ static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn,
|
|||||||
static struct Patch *allocpatch(uint32_t type, struct Expression const *expr,
|
static struct Patch *allocpatch(uint32_t type, struct Expression const *expr,
|
||||||
uint32_t ofs)
|
uint32_t ofs)
|
||||||
{
|
{
|
||||||
struct Patch *pPatch;
|
struct Patch *pPatch = malloc(sizeof(struct Patch));
|
||||||
|
|
||||||
pPatch = malloc(sizeof(struct Patch));
|
|
||||||
|
|
||||||
if (!pPatch)
|
if (!pPatch)
|
||||||
fatalerror("No memory for patch: %s", strerror(errno));
|
fatalerror("No memory for patch: %s", strerror(errno));
|
||||||
@@ -316,6 +316,8 @@ static struct Patch *allocpatch(uint32_t type, struct Expression const *expr,
|
|||||||
pPatch->nType = type;
|
pPatch->nType = type;
|
||||||
fstk_DumpToStr(pPatch->tzFilename, sizeof(pPatch->tzFilename));
|
fstk_DumpToStr(pPatch->tzFilename, sizeof(pPatch->tzFilename));
|
||||||
pPatch->nOffset = ofs;
|
pPatch->nOffset = ofs;
|
||||||
|
pPatch->pcSection = sect_GetSymbolSection();
|
||||||
|
pPatch->pcOffset = curOffset;
|
||||||
|
|
||||||
writerpn(pPatch->pRPN, &pPatch->nRPNSize, expr->tRPN, expr->nRPNLength);
|
writerpn(pPatch->pRPN, &pPatch->nRPNSize, expr->tRPN, expr->nRPNLength);
|
||||||
assert(pPatch->nRPNSize == expr->nRPNPatchSize);
|
assert(pPatch->nRPNSize == expr->nRPNPatchSize);
|
||||||
@@ -346,7 +348,6 @@ bool out_CreateAssert(enum AssertionType type, struct Expression const *expr,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
assertion->patch = allocpatch(type, expr, ofs);
|
assertion->patch = allocpatch(type, expr, ofs);
|
||||||
assertion->section = pCurrentSection;
|
|
||||||
assertion->message = strdup(message);
|
assertion->message = strdup(message);
|
||||||
if (!assertion->message) {
|
if (!assertion->message) {
|
||||||
free(assertion);
|
free(assertion);
|
||||||
@@ -362,7 +363,6 @@ bool out_CreateAssert(enum AssertionType type, struct Expression const *expr,
|
|||||||
static void writeassert(struct Assertion *assert, FILE *f)
|
static void writeassert(struct Assertion *assert, FILE *f)
|
||||||
{
|
{
|
||||||
writepatch(assert->patch, f);
|
writepatch(assert->patch, f);
|
||||||
fputlong(assert->section ? getsectid(assert->section) : -1, f);
|
|
||||||
fputstring(assert->message, f);
|
fputstring(assert->message, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,11 +381,8 @@ static void registerExportedSymbol(struct sSymbol *symbol, void *arg)
|
|||||||
*/
|
*/
|
||||||
void out_WriteObject(void)
|
void out_WriteObject(void)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f = fopen(tzObjectname, "wb");
|
||||||
struct Section *pSect;
|
|
||||||
struct Assertion *assert = assertions;
|
|
||||||
|
|
||||||
f = fopen(tzObjectname, "wb");
|
|
||||||
if (!f)
|
if (!f)
|
||||||
err(1, "Couldn't write file '%s'", tzObjectname);
|
err(1, "Couldn't write file '%s'", tzObjectname);
|
||||||
|
|
||||||
@@ -398,21 +395,16 @@ void out_WriteObject(void)
|
|||||||
fputlong(nbSymbols, f);
|
fputlong(nbSymbols, f);
|
||||||
fputlong(countsections(), f);
|
fputlong(countsections(), f);
|
||||||
|
|
||||||
for (struct sSymbol const *sym = objectSymbols; sym; sym = sym->next) {
|
for (struct sSymbol const *sym = objectSymbols; sym; sym = sym->next)
|
||||||
writesymbol(sym, f);
|
writesymbol(sym, f);
|
||||||
}
|
|
||||||
|
|
||||||
pSect = pSectionList;
|
for (struct Section *sect = pSectionList; sect; sect = sect->pNext)
|
||||||
while (pSect) {
|
writesection(sect, f);
|
||||||
writesection(pSect, f);
|
|
||||||
pSect = pSect->pNext;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputlong(countasserts(), f);
|
fputlong(countasserts(), f);
|
||||||
while (assert) {
|
for (struct Assertion *assert = assertions; assert;
|
||||||
|
assert = assert->next)
|
||||||
writeassert(assert, f);
|
writeassert(assert, f);
|
||||||
assert = assert->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -207,8 +207,9 @@ static void readSymbol(FILE *file, struct Symbol *symbol, char const *fileName)
|
|||||||
* @param fileName The filename to report in errors
|
* @param fileName The filename to report in errors
|
||||||
* @param i The number of the patch to report in errors
|
* @param i The number of the patch to report in errors
|
||||||
*/
|
*/
|
||||||
static void readPatch(FILE *file, struct Patch *patch,
|
static void readPatch(FILE *file, struct Patch *patch, char const *fileName,
|
||||||
char const *fileName, char const *sectName, uint32_t i)
|
char const *sectName, uint32_t i,
|
||||||
|
struct Section *fileSections[])
|
||||||
{
|
{
|
||||||
tryReadstr(patch->fileName, file,
|
tryReadstr(patch->fileName, file,
|
||||||
"%s: Unable to read \"%s\"'s patch #%u's name: %s",
|
"%s: Unable to read \"%s\"'s patch #%u's name: %s",
|
||||||
@@ -216,6 +217,15 @@ static void readPatch(FILE *file, struct Patch *patch,
|
|||||||
tryReadlong(patch->offset, file,
|
tryReadlong(patch->offset, file,
|
||||||
"%s: Unable to read \"%s\"'s patch #%u's offset: %s",
|
"%s: Unable to read \"%s\"'s patch #%u's offset: %s",
|
||||||
fileName, sectName, i);
|
fileName, sectName, i);
|
||||||
|
tryReadlong(patch->pcSectionID, file,
|
||||||
|
"%s: Unable to read \"%s\"'s patch #%u's PC offset: %s",
|
||||||
|
fileName, sectName, i);
|
||||||
|
patch->pcSection = patch->pcSectionID == -1
|
||||||
|
? NULL
|
||||||
|
: fileSections[patch->pcSectionID];
|
||||||
|
tryReadlong(patch->pcOffset, file,
|
||||||
|
"%s: Unable to read \"%s\"'s patch #%u's PC offset: %s",
|
||||||
|
fileName, sectName, i);
|
||||||
tryGetc(patch->type, file,
|
tryGetc(patch->type, file,
|
||||||
"%s: Unable to read \"%s\"'s patch #%u's type: %s",
|
"%s: Unable to read \"%s\"'s patch #%u's type: %s",
|
||||||
fileName, sectName, i);
|
fileName, sectName, i);
|
||||||
@@ -242,7 +252,7 @@ static void readPatch(FILE *file, struct Patch *patch,
|
|||||||
* @param fileName The filename to report in errors
|
* @param fileName The filename to report in errors
|
||||||
*/
|
*/
|
||||||
static void readSection(FILE *file, struct Section *section,
|
static void readSection(FILE *file, struct Section *section,
|
||||||
char const *fileName)
|
char const *fileName, struct Section *fileSections[])
|
||||||
{
|
{
|
||||||
int32_t tmp;
|
int32_t tmp;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
@@ -302,9 +312,10 @@ static void readSection(FILE *file, struct Section *section,
|
|||||||
if (!patches)
|
if (!patches)
|
||||||
err(1, "%s: Unable to read \"%s\"'s patches", fileName,
|
err(1, "%s: Unable to read \"%s\"'s patches", fileName,
|
||||||
section->name);
|
section->name);
|
||||||
for (uint32_t i = 0; i < section->nbPatches; i++)
|
for (uint32_t i = 0; i < section->nbPatches; i++) {
|
||||||
readPatch(file, &patches[i], fileName, section->name,
|
readPatch(file, &patches[i], fileName, section->name,
|
||||||
i);
|
i, fileSections);
|
||||||
|
}
|
||||||
section->patches = patches;
|
section->patches = patches;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -345,18 +356,14 @@ static void linkSymToSect(struct Symbol const *symbol, struct Section *section)
|
|||||||
* @param fileName The filename to report in errors
|
* @param fileName The filename to report in errors
|
||||||
*/
|
*/
|
||||||
static void readAssertion(FILE *file, struct Assertion *assert,
|
static void readAssertion(FILE *file, struct Assertion *assert,
|
||||||
char const *fileName, struct Section *fileSections[],
|
char const *fileName, uint32_t i,
|
||||||
uint32_t i)
|
struct Section *fileSections[])
|
||||||
{
|
{
|
||||||
char assertName[sizeof("Assertion #" EXPAND_AND_STR(UINT32_MAX))];
|
char assertName[sizeof("Assertion #" EXPAND_AND_STR(UINT32_MAX))];
|
||||||
uint32_t sectionID;
|
|
||||||
|
|
||||||
snprintf(assertName, sizeof(assertName), "Assertion #%u", i);
|
snprintf(assertName, sizeof(assertName), "Assertion #%u", i);
|
||||||
|
|
||||||
readPatch(file, &assert->patch, fileName, assertName, 0);
|
readPatch(file, &assert->patch, fileName, assertName, 0, fileSections);
|
||||||
tryReadlong(sectionID, file, "%s: Cannot read assertion's section ID: %s",
|
|
||||||
fileName);
|
|
||||||
assert->section = sectionID == -1 ? NULL : fileSections[sectionID];
|
|
||||||
tryReadstr(assert->message, file, "%s: Cannot read assertion's message: %s",
|
tryReadstr(assert->message, file, "%s: Cannot read assertion's message: %s",
|
||||||
fileName);
|
fileName);
|
||||||
}
|
}
|
||||||
@@ -455,26 +462,25 @@ void obj_ReadFile(char const *fileName)
|
|||||||
verbosePrint("Reading %u sections...\n", nbSections);
|
verbosePrint("Reading %u sections...\n", nbSections);
|
||||||
for (uint32_t i = 0; i < nbSections; i++) {
|
for (uint32_t i = 0; i < nbSections; i++) {
|
||||||
/* Read section */
|
/* Read section */
|
||||||
struct Section *section = malloc(sizeof(*section));
|
fileSections[i] = malloc(sizeof(*fileSections[i]));
|
||||||
|
if (!fileSections[i])
|
||||||
if (!section)
|
|
||||||
err(1, "%s: Couldn't create new section", fileName);
|
err(1, "%s: Couldn't create new section", fileName);
|
||||||
section->nextu = NULL;
|
|
||||||
readSection(file, section, fileName);
|
|
||||||
section->fileSymbols = fileSymbols;
|
|
||||||
|
|
||||||
sect_AddSection(section);
|
fileSections[i]->nextu = NULL;
|
||||||
fileSections[i] = section;
|
readSection(file, fileSections[i], fileName, fileSections);
|
||||||
|
fileSections[i]->fileSymbols = fileSymbols;
|
||||||
if (nbSymPerSect[i]) {
|
if (nbSymPerSect[i]) {
|
||||||
section->symbols = malloc(sizeof(*section->symbols)
|
fileSections[i]->symbols = malloc(nbSymPerSect[i]
|
||||||
* nbSymPerSect[i]);
|
* sizeof(*fileSections[i]->symbols));
|
||||||
if (!section->symbols)
|
if (!fileSections[i]->symbols)
|
||||||
err(1, "%s: Couldn't link to symbols",
|
err(1, "%s: Couldn't link to symbols",
|
||||||
fileName);
|
fileName);
|
||||||
} else {
|
} else {
|
||||||
section->symbols = NULL;
|
fileSections[i]->symbols = NULL;
|
||||||
}
|
}
|
||||||
section->nbSymbols = 0;
|
fileSections[i]->nbSymbols = 0;
|
||||||
|
|
||||||
|
sect_AddSection(fileSections[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Give symbols pointers to their sections */
|
/* Give symbols pointers to their sections */
|
||||||
@@ -501,7 +507,7 @@ void obj_ReadFile(char const *fileName)
|
|||||||
|
|
||||||
if (!assertion)
|
if (!assertion)
|
||||||
err(1, "%s: Couldn't create new assertion", fileName);
|
err(1, "%s: Couldn't create new assertion", fileName);
|
||||||
readAssertion(file, assertion, fileName, fileSections, i);
|
readAssertion(file, assertion, fileName, i, fileSections);
|
||||||
assertion->fileSymbols = fileSymbols;
|
assertion->fileSymbols = fileSymbols;
|
||||||
assertion->next = assertions;
|
assertion->next = assertions;
|
||||||
assertions = assertion;
|
assertions = assertion;
|
||||||
|
|||||||
@@ -136,7 +136,6 @@ static struct Symbol const *getSymbol(struct Symbol const * const *symbolList,
|
|||||||
* @return The patch's value
|
* @return The patch's value
|
||||||
*/
|
*/
|
||||||
static int32_t computeRPNExpr(struct Patch const *patch,
|
static int32_t computeRPNExpr(struct Patch const *patch,
|
||||||
struct Section const *section,
|
|
||||||
struct Symbol const * const *fileSymbols)
|
struct Symbol const * const *fileSymbols)
|
||||||
{
|
{
|
||||||
/* Small shortcut to avoid a lot of repetition */
|
/* Small shortcut to avoid a lot of repetition */
|
||||||
@@ -283,7 +282,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RPN_BANK_SELF:
|
case RPN_BANK_SELF:
|
||||||
value = section->bank;
|
value = patch->pcSection->bank;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RPN_HRAM:
|
case RPN_HRAM:
|
||||||
@@ -322,13 +321,17 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
|||||||
|
|
||||||
symbol = getSymbol(fileSymbols, value);
|
symbol = getSymbol(fileSymbols, value);
|
||||||
|
|
||||||
if (!strcmp(symbol->name, "@")) {
|
if (strcmp(symbol->name, "@")) {
|
||||||
value = section->org + patch->offset;
|
|
||||||
} else {
|
|
||||||
value = symbol->value;
|
value = symbol->value;
|
||||||
/* Symbols attached to sections have offsets */
|
/* Symbols attached to sections have offsets */
|
||||||
if (symbol->section)
|
if (symbol->section)
|
||||||
value += symbol->section->org;
|
value += symbol->section->org;
|
||||||
|
} else if (!patch->pcSection) {
|
||||||
|
error("%s: PC has no value outside a section",
|
||||||
|
patch->fileName);
|
||||||
|
value = 0;
|
||||||
|
} else {
|
||||||
|
value = patch->pcOffset + patch->pcSection->org;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -351,7 +354,7 @@ void patch_CheckAssertions(struct Assertion *assert)
|
|||||||
initRPNStack();
|
initRPNStack();
|
||||||
|
|
||||||
while (assert) {
|
while (assert) {
|
||||||
if (!computeRPNExpr(&assert->patch, assert->section,
|
if (!computeRPNExpr(&assert->patch,
|
||||||
(struct Symbol const * const *)
|
(struct Symbol const * const *)
|
||||||
assert->fileSymbols)) {
|
assert->fileSymbols)) {
|
||||||
switch ((enum AssertionType)assert->patch.type) {
|
switch ((enum AssertionType)assert->patch.type) {
|
||||||
@@ -395,14 +398,15 @@ static void applyFilePatches(struct Section *section)
|
|||||||
verbosePrint("Patching section \"%s\"...\n", section->name);
|
verbosePrint("Patching section \"%s\"...\n", section->name);
|
||||||
for (uint32_t patchID = 0; patchID < section->nbPatches; patchID++) {
|
for (uint32_t patchID = 0; patchID < section->nbPatches; patchID++) {
|
||||||
struct Patch *patch = §ion->patches[patchID];
|
struct Patch *patch = §ion->patches[patchID];
|
||||||
int32_t value = computeRPNExpr(patch, section,
|
int32_t value = computeRPNExpr(patch,
|
||||||
(struct Symbol const * const *)
|
(struct Symbol const * const *)
|
||||||
section->fileSymbols);
|
section->fileSymbols);
|
||||||
|
|
||||||
/* `jr` is quite unlike the others... */
|
/* `jr` is quite unlike the others... */
|
||||||
if (patch->type == PATCHTYPE_JR) {
|
if (patch->type == PATCHTYPE_JR) {
|
||||||
/* Target is relative to the byte *after* the operand */
|
/* Target is relative to the byte *after* the operand */
|
||||||
uint16_t address = section->org + patch->offset + 1;
|
uint16_t address = patch->pcSection->org
|
||||||
|
+ patch->pcOffset + 1;
|
||||||
int16_t offset = value - address;
|
int16_t offset = value - address;
|
||||||
|
|
||||||
if (offset < -128 || offset > 127)
|
if (offset < -128 || offset > 127)
|
||||||
|
|||||||
23
src/rgbds.5
23
src/rgbds.5
@@ -101,8 +101,6 @@ REPT NumberOfSections
|
|||||||
|
|
||||||
LONG NumberOfPatches ; Number of patches to apply.
|
LONG NumberOfPatches ; Number of patches to apply.
|
||||||
|
|
||||||
; These types of sections may have patches
|
|
||||||
|
|
||||||
REPT NumberOfPatches
|
REPT NumberOfPatches
|
||||||
|
|
||||||
STRING SourceFile ; Name of the source file (for printing error
|
STRING SourceFile ; Name of the source file (for printing error
|
||||||
@@ -111,6 +109,16 @@ REPT NumberOfSections
|
|||||||
LONG Offset ; Offset into the section where patch should
|
LONG Offset ; Offset into the section where patch should
|
||||||
; be applied (in bytes).
|
; be applied (in bytes).
|
||||||
|
|
||||||
|
LONG PCSectionID ; Index within the file of the section in which
|
||||||
|
; PC is located.
|
||||||
|
; This is usually the same section that the
|
||||||
|
; patch should be applied into, except e.g.
|
||||||
|
; with LOAD blocks.
|
||||||
|
|
||||||
|
LONG PCOffset ; PC's offset into the above section.
|
||||||
|
; Used because the section may be floating, so
|
||||||
|
; PC's value is not known to RGBASM.
|
||||||
|
|
||||||
BYTE Type ; 0 = BYTE patch.
|
BYTE Type ; 0 = BYTE patch.
|
||||||
; 1 = little endian WORD patch.
|
; 1 = little endian WORD patch.
|
||||||
; 2 = little endian LONG patch.
|
; 2 = little endian LONG patch.
|
||||||
@@ -137,6 +145,13 @@ REPT NumberOfAssertions
|
|||||||
|
|
||||||
LONG Offset ; Offset into the section where the assertion is located.
|
LONG Offset ; Offset into the section where the assertion is located.
|
||||||
|
|
||||||
|
LONG SectionID ; Index within the file of the section in which PC is
|
||||||
|
; located, or -1 if defined outside a section.
|
||||||
|
|
||||||
|
LONG PCOffset ; PC's offset into the above section.
|
||||||
|
; Used because the section may be floating, so PC's value
|
||||||
|
; is not known to RGBASM.
|
||||||
|
|
||||||
BYTE Type ; 0 = Prints the message but allows linking to continue
|
BYTE Type ; 0 = Prints the message but allows linking to continue
|
||||||
; 1 = Prints the message and evaluates other assertions,
|
; 1 = Prints the message and evaluates other assertions,
|
||||||
; but linking fails afterwards
|
; but linking fails afterwards
|
||||||
@@ -146,10 +161,6 @@ REPT NumberOfAssertions
|
|||||||
|
|
||||||
BYTE RPN[RPNSize] ; RPN expression, same as patches. Assert fails if == 0.
|
BYTE RPN[RPNSize] ; RPN expression, same as patches. Assert fails if == 0.
|
||||||
|
|
||||||
LONG SectionID ; The section number (of this object file) in which this
|
|
||||||
; assert is defined. If it doesn't belong to any specific
|
|
||||||
; section (like a constant), this field has the value -1.
|
|
||||||
|
|
||||||
STRING Message ; A message displayed when the assert fails. If set to
|
STRING Message ; A message displayed when the assert fails. If set to
|
||||||
; the empty string, a generic message is printed instead.
|
; the empty string, a generic message is printed instead.
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
SECTION "test", ROM0[1]
|
SECTION "test", ROM0[1]
|
||||||
call Target
|
call Target
|
||||||
LOAD "new", WRAM0[$C001]
|
PRINTT "PC in ROM: {@}\n"
|
||||||
|
LOAD "new", WRAMX[$D001],BANK[1]
|
||||||
|
PRINTT "PC in WRAM: {@}\n"
|
||||||
|
assert @ == $D001
|
||||||
Target: dl DEAD << 16 | BEEF
|
Target: dl DEAD << 16 | BEEF
|
||||||
|
db BANK(@)
|
||||||
|
jr .end
|
||||||
.end
|
.end
|
||||||
|
jr .end
|
||||||
ds 2, $2A
|
ds 2, $2A
|
||||||
ENDL
|
ENDL
|
||||||
After:
|
After:
|
||||||
@@ -10,16 +16,16 @@ After:
|
|||||||
ld hl, Word
|
ld hl, Word
|
||||||
dw Byte, Target.end, After
|
dw Byte, Target.end, After
|
||||||
|
|
||||||
SECTION "dead", WRAMX[$DEAD]
|
SECTION "dead", WRAMX[$DEAD],BANK[2]
|
||||||
DEAD:
|
DEAD:
|
||||||
SECTION "beef", SRAM[$BEEF]
|
SECTION "beef", SRAM[$BEEF]
|
||||||
BEEF:
|
BEEF:
|
||||||
|
|
||||||
SECTION "ram test", WRAM0 ; Should end up at $C005
|
SECTION "ram test", WRAMX,BANK[1] ; Should end up at $D005
|
||||||
Word:
|
Word:
|
||||||
dw
|
dw
|
||||||
|
|
||||||
SECTION "small ram test", WRAM0 ; Should end up at $C000
|
SECTION "small ram test", WRAMX,BANK[1] ; Should end up at $D000
|
||||||
Byte:
|
Byte:
|
||||||
db
|
db
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
$C001
|
PC in ROM: $4
|
||||||
$C005
|
PC in WRAM: $D001
|
||||||
$A
|
$D001
|
||||||
|
$D008
|
||||||
|
$F
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user