From cb52ae0f26462f3069f0fec0643dd98fd0929154 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Fri, 20 Mar 2020 21:02:32 +0100 Subject: [PATCH] Implement unionized sections in RGBASM This touched a lot more code than initially expected, for two reasons. First, this broke a big RGBASM assumption: that sections are always being written to at their end. This plus other problems required touching basically the entirety of `section.c`. Second, I tried different solutions to solve the above problem, and along the way I cleaned up many things around. (I believe that keeping this to "cleanup" commits yields subpar results, and since it's boring they get postponed anyways.) RGBLINK support still needs to be added, but this will come next. --- include/asm/asm.h | 1 - include/asm/main.h | 2 + include/asm/output.h | 5 +- include/asm/section.h | 16 +- include/asm/symbol.h | 7 +- src/asm/asmy.y | 26 +-- src/asm/main.c | 7 +- src/asm/output.c | 17 +- src/asm/section.c | 339 ++++++++++++++++++++++++------------- src/asm/symbol.c | 8 +- test/asm/section-union.asm | 37 ++++ test/asm/section-union.err | 8 + test/asm/section-union.out | 3 + 13 files changed, 314 insertions(+), 162 deletions(-) create mode 100644 test/asm/section-union.asm create mode 100644 test/asm/section-union.err create mode 100644 test/asm/section-union.out diff --git a/include/asm/asm.h b/include/asm/asm.h index 5571a7a6..5f1bc4ef 100644 --- a/include/asm/asm.h +++ b/include/asm/asm.h @@ -27,7 +27,6 @@ extern int32_t nLineNo; extern uint32_t nTotalLines; -extern uint32_t nPC; extern uint32_t nIFDepth; extern bool skipElif; extern uint32_t nUnionDepth; diff --git a/include/asm/main.h b/include/asm/main.h index bc057906..bf396ddd 100644 --- a/include/asm/main.h +++ b/include/asm/main.h @@ -31,6 +31,8 @@ extern uint32_t ulNewMacroSize; extern int32_t nGBGfxID; extern int32_t nBinaryID; +extern uint32_t curOffset; /* Offset into the current section */ + extern struct sOptions DefaultOptions; extern struct sOptions CurrentOptions; diff --git a/include/asm/output.h b/include/asm/output.h index 7be1f43e..e6a45df7 100644 --- a/include/asm/output.h +++ b/include/asm/output.h @@ -19,9 +19,10 @@ extern char *tzObjectname; extern struct Section *pSectionList, *pCurrentSection; void out_SetFileName(char *s); -void out_CreatePatch(uint32_t type, struct Expression const *expr); +void out_CreatePatch(uint32_t type, struct Expression const *expr, + uint32_t ofs); bool out_CreateAssert(enum AssertionType type, struct Expression const *expr, - char const *message); + char const *message, uint32_t ofs); void out_WriteObject(void); #endif /* RGBDS_ASM_OUTPUT_H */ diff --git a/include/asm/section.h b/include/asm/section.h index 8fdefaa8..a0fd4ff6 100644 --- a/include/asm/section.h +++ b/include/asm/section.h @@ -18,7 +18,8 @@ struct Expression; struct Section { char *pzName; enum SectionType nType; - uint32_t nPC; + bool isUnion; + uint32_t size; uint32_t nOrg; uint32_t nBank; uint32_t nAlign; @@ -28,25 +29,26 @@ struct Section { }; struct SectionSpec { - int32_t bank; - int32_t alignment; + uint32_t bank; + uint32_t alignment; }; struct Section *out_FindSectionByName(const char *pzName); -void out_NewSection(char const *pzName, uint32_t secttype, int32_t org, - struct SectionSpec const *attributes); -void out_SetLoadSection(char const *name, uint32_t secttype, int32_t org, +void out_NewSection(char const *pzName, uint32_t secttype, uint32_t org, + struct SectionSpec const *attributes, bool isUnion); +void out_SetLoadSection(char const *name, uint32_t secttype, uint32_t org, struct SectionSpec const *attributes); void out_EndLoadSection(void); struct Section *sect_GetSymbolSection(void); +uint32_t sect_GetOutputOffset(void); void out_AbsByte(uint8_t b); void out_AbsByteGroup(uint8_t const *s, int32_t length); void out_Skip(int32_t skip); void out_String(char const *s); void out_RelByte(struct Expression *expr); -void out_RelBytes(struct Expression *expr, int32_t n); +void out_RelBytes(struct Expression *expr, uint32_t n); void out_RelWord(struct Expression *expr); void out_RelLong(struct Expression *expr); void out_PCRelByte(struct Expression *expr); diff --git a/include/asm/symbol.h b/include/asm/symbol.h index 16a37ecb..490786ce 100644 --- a/include/asm/symbol.h +++ b/include/asm/symbol.h @@ -13,6 +13,8 @@ #include #include +#include "asm/section.h" + #include "types.h" #define HASHSIZE (1 << 16) @@ -30,7 +32,6 @@ enum SymbolType { struct sSymbol { char tzName[MAXSYMLEN + 1]; enum SymbolType type; - bool isConstant; /* Whether the symbol's value is currently known */ bool isExported; /* Whether the symbol is to be exported */ bool isBuiltin; /* Whether the symbol is a built-in */ bool isReferenced; /* Whether the symbol is referenced in a RPN expr */ @@ -52,7 +53,9 @@ static inline bool sym_IsDefined(struct sSymbol const *sym) static inline bool sym_IsConstant(struct sSymbol const *sym) { - return sym->isConstant; + return sym->type == SYM_EQU || sym->type == SYM_SET + || (sym->type == SYM_LABEL && sym->pSection + && sym->pSection->nOrg != -1); } static inline bool sym_IsNumeric(struct sSymbol const *sym) diff --git a/src/asm/asmy.y b/src/asm/asmy.y index 3200ffd0..e0eaeae6 100644 --- a/src/asm/asmy.y +++ b/src/asm/asmy.y @@ -393,20 +393,19 @@ static void startUnion(void) if (nUnionDepth > MAXUNIONS) fatalerror("Too many nested UNIONs"); - unionStart[unionIndex] = nPC; + unionStart[unionIndex] = curOffset; unionSize[unionIndex] = 0; } static void updateUnion(void) { uint32_t unionIndex = nUnionDepth - 1; - uint32_t size = nPC - unionStart[unionIndex]; + uint32_t size = curOffset - unionStart[unionIndex]; if (size > unionSize[unionIndex]) unionSize[unionIndex] = size; - nPC = unionStart[unionIndex]; - pCurrentSection->nPC = unionStart[unionIndex]; + curOffset = unionStart[unionIndex]; } static size_t strlenUTF8(const char *s) @@ -601,7 +600,8 @@ static void strsubUTF8(char *dest, const char *src, uint32_t pos, uint32_t len) %token T_SECT_WRAM0 T_SECT_VRAM T_SECT_ROMX T_SECT_ROM0 T_SECT_HRAM %token T_SECT_WRAMX T_SECT_SRAM T_SECT_OAM -%type macroargs; +%type sectunion +%type macroargs %token T_Z80_ADC T_Z80_ADD T_Z80_AND %token T_Z80_BIT @@ -815,7 +815,8 @@ assert_type : /* empty */ { $$ = ASSERT_ERROR; } assert : T_POP_ASSERT assert_type relocexpr { if (!rpn_isKnown(&$3)) { - if (!out_CreateAssert($2, &$3, "")) + if (!out_CreateAssert($2, &$3, "", + sect_GetOutputOffset())) yyerror("Assertion creation failed: %s", strerror(errno)); } else if ($3.nVal == 0) { @@ -836,7 +837,8 @@ assert : T_POP_ASSERT assert_type relocexpr | T_POP_ASSERT assert_type relocexpr ',' string { if (!rpn_isKnown(&$3)) { - if (!out_CreateAssert($2, &$3, $5)) + if (!out_CreateAssert($2, &$3, $5, + sect_GetOutputOffset())) yyerror("Assertion creation failed: %s", strerror(errno)); } else if ($3.nVal == 0) { @@ -968,8 +970,7 @@ endu : T_POP_ENDU { updateUnion(); nUnionDepth--; - nPC = unionStart[nUnionDepth] + unionSize[nUnionDepth]; - pCurrentSection->nPC = nPC; + curOffset = unionStart[nUnionDepth] + unionSize[nUnionDepth]; } ; @@ -1418,11 +1419,14 @@ string : T_STRING { } ; -section : T_POP_SECTION string ',' sectiontype sectorg sectattrs { - out_NewSection($2, $4, $5, &$6); +section : T_POP_SECTION sectunion string ',' sectiontype sectorg sectattrs { + out_NewSection($3, $5, $6, &$7, $2); } ; +sectunion : /* empty */ { $$ = false; } + | T_POP_UNION { $$ = true; } + sectiontype : T_SECT_WRAM0 { $$ = SECTTYPE_WRAM0; } | T_SECT_VRAM { $$ = SECTTYPE_VRAM; } | T_SECT_ROMX { $$ = SECTTYPE_ROMX; } diff --git a/src/asm/main.c b/src/asm/main.c index 5426a1f4..4b94e5f2 100644 --- a/src/asm/main.c +++ b/src/asm/main.c @@ -40,11 +40,13 @@ const size_t cldefine_entrysize = 2 * sizeof(void *); char **cldefines; clock_t nStartClock, nEndClock; -int32_t nLineNo; -uint32_t nTotalLines, nPC, nIFDepth, nUnionDepth; +uint32_t nTotalLines, nIFDepth, nUnionDepth; bool skipElif; uint32_t unionStart[128], unionSize[128]; +int32_t nLineNo; +uint32_t curOffset; + #if defined(YYDEBUG) && YYDEBUG extern int yydebug; #endif @@ -525,7 +527,6 @@ int main(int argc, char *argv[]) nIFDepth = 0; skipElif = true; nUnionDepth = 0; - nPC = 0; sym_Init(); sym_SetExportAll(CurrentOptions.exportall); fstk_Init(tzMainfile); diff --git a/src/asm/output.c b/src/asm/output.c index 5faa849a..3c742aa0 100644 --- a/src/asm/output.c +++ b/src/asm/output.c @@ -187,7 +187,7 @@ static void writesection(struct Section *pSect, FILE *f) { fputstring(pSect->pzName, f); - fputlong(pSect->nPC, f); + fputlong(pSect->size, f); fputc(pSect->nType, f); @@ -198,7 +198,7 @@ static void writesection(struct Section *pSect, FILE *f) if (sect_HasData(pSect->nType)) { struct Patch *pPatch; - fwrite(pSect->tData, 1, pSect->nPC, f); + fwrite(pSect->tData, 1, pSect->size, f); fputlong(countpatches(pSect), f); pPatch = pSect->pPatches; @@ -402,7 +402,8 @@ static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn, /* * Allocate a new patch structure and link it into the list */ -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) { struct Patch *pPatch; @@ -418,8 +419,8 @@ static struct Patch *allocpatch(uint32_t type, struct Expression const *expr) pPatch->nRPNSize = 0; pPatch->nType = type; - pPatch->nOffset = pCurrentSection->nPC; fstk_DumpToStr(pPatch->tzFilename, sizeof(pPatch->tzFilename)); + pPatch->nOffset = ofs; writerpn(pPatch->pRPN, &pPatch->nRPNSize, expr->tRPN, expr->nRPNLength); assert(pPatch->nRPNSize == expr->nRPNPatchSize); @@ -430,9 +431,9 @@ static struct Patch *allocpatch(uint32_t type, struct Expression const *expr) /* * Create a new patch (includes the rpn expr) */ -void out_CreatePatch(uint32_t type, struct Expression const *expr) +void out_CreatePatch(uint32_t type, struct Expression const *expr, uint32_t ofs) { - struct Patch *pPatch = allocpatch(type, expr); + struct Patch *pPatch = allocpatch(type, expr, ofs); pPatch->pNext = pCurrentSection->pPatches; pCurrentSection->pPatches = pPatch; @@ -442,14 +443,14 @@ void out_CreatePatch(uint32_t type, struct Expression const *expr) * Creates an assert that will be written to the object file */ bool out_CreateAssert(enum AssertionType type, struct Expression const *expr, - char const *message) + char const *message, uint32_t ofs) { struct Assertion *assertion = malloc(sizeof(*assertion)); if (!assertion) return false; - assertion->patch = allocpatch(type, expr); + assertion->patch = allocpatch(type, expr, ofs); assertion->section = pCurrentSection; assertion->message = strdup(message); if (!assertion->message) { diff --git a/src/asm/section.c b/src/asm/section.c index 46536519..f2ac719d 100644 --- a/src/asm/section.c +++ b/src/asm/section.c @@ -16,16 +16,18 @@ struct SectionStackEntry { struct Section *pSection; struct sSymbol *pScope; /* Section's symbol scope */ + uint32_t offset; struct SectionStackEntry *pNext; }; struct SectionStackEntry *pSectionStack; static struct Section *currentLoadSection = NULL; +uint32_t loadOffset = 0; /* The offset of the LOAD section within its parent */ /* * A quick check to see if we have an initialized section */ -static void checksection(void) +static inline void checksection(void) { if (pCurrentSection == NULL) fatalerror("Code generation before SECTION directive"); @@ -35,7 +37,7 @@ static void checksection(void) * A quick check to see if we have an initialized section that can contain * this much initialized data */ -static void checkcodesection(void) +static inline void checkcodesection(void) { checksection(); @@ -49,22 +51,20 @@ static void checkcodesection(void) /* * Check if the section has grown too much. */ -static void checksectionoverflow(uint32_t delta_size) +static void reserveSpace(uint32_t delta_size) { uint32_t maxSize = maxsize[pCurrentSection->nType]; - uint32_t newSize = pCurrentSection->nPC + delta_size; + uint32_t newSize = curOffset + delta_size; - if (newSize > maxSize) { - /* - * This check is here to trap broken code that generates - * sections that are too big and to prevent the assembler from - * generating huge object files or trying to allocate too much - * memory. - * The real check must be done at the linking stage. - */ + /* + * This check is here to trap broken code that generates sections that + * are too big and to prevent the assembler from generating huge object + * files or trying to allocate too much memory. + * A check at the linking stage is still necessary. + */ + if (newSize > maxSize) fatalerror("Section '%s' is too big (max size = 0x%X bytes, reached 0x%X).", pCurrentSection->pzName, maxSize, newSize); - } } struct Section *out_FindSectionByName(const char *pzName) @@ -85,7 +85,8 @@ struct Section *out_FindSectionByName(const char *pzName) * Find a section by name and type. If it doesn't exist, create it */ static struct Section *getSection(char const *pzName, enum SectionType type, - int32_t org, int32_t bank, int32_t alignment) + uint32_t org, uint32_t bank, + uint32_t alignment, bool isUnion) { if (bank != -1) { if (type != SECTTYPE_ROMX && type != SECTTYPE_VRAM @@ -123,13 +124,99 @@ static struct Section *getSection(char const *pzName, enum SectionType type, struct Section *pSect = out_FindSectionByName(pzName); if (pSect) { - if (type == pSect->nType - && ((uint32_t)org) == pSect->nOrg - && ((uint32_t)bank) == pSect->nBank - && ((uint32_t)alignment == pSect->nAlign)) { - return pSect; + unsigned int nbSectErrors = 0; +#define fail(...) \ + do { \ + yyerror(__VA_ARGS__); \ + nbSectErrors++; \ + } while (0) + + if (type != pSect->nType) + fail("Section \"%s\" already exists but with type %s", + pSect->pzName, typeNames[pSect->nType]); + + /* + * Normal sections need to have exactly identical constraints; + * but unionized sections only need "compatible" constraints, + * and they end up with the strictest combination of both + */ + if (isUnion) { + if (!pSect->isUnion) + fail("Section \"%s\" already declared as non-union", + pSect->pzName); + /* + * WARNING: see comment abount assumption in + * `EndLoadSection` if modifying the following check! + */ + if (sect_HasData(type)) + fail("Cannot declare ROM sections as UNION"); + if (org != -1) { + /* If neither is fixed, they must be the same */ + if (pSect->nOrg != -1 && pSect->nOrg != org) + fail("Section \"%s\" already declared as fixed at different address $%x", + pSect->pzName, pSect->nOrg); + else + /* Otherwise, just override */ + pSect->nOrg = org; + } else if (alignment != 0) { + /* Make sure any fixed address is compatible */ + if (pSect->nOrg != -1) { + uint32_t mask = alignment - 1; + + if (pSect->nOrg & mask) + fail("Section \"%s\" already declared as fixed at incompatible address $%x", + pSect->pzName, + pSect->nOrg); + } else if (alignment > pSect->nAlign) { + /* + * If the section is not fixed, + * its alignment is the largest of both + */ + pSect->nAlign = alignment; + } + } + /* If the section's bank is unspecified, override it */ + if (pSect->nBank == -1) + pSect->nBank = bank; + /* If both specify a bank, it must be the same one */ + else if (bank != -1 && pSect->nBank != bank) + fail("Section \"%s\" already declared with different bank %u", + pSect->pzName, pSect->nBank); + } else { + if (pSect->isUnion) + fail("Section \"%s\" already declared as union", + pSect->pzName); + if (org != pSect->nOrg) { + if (pSect->nOrg == -1) + fail("Section \"%s\" already declared as floating", + pSect->pzName); + else + fail("Section \"%s\" already declared as fixed at $%x", + pSect->pzName, pSect->nOrg); + } + if (bank != pSect->nBank) { + if (pSect->nBank == -1) + fail("Section \"%s\" already declared as floating bank", + pSect->pzName); + else + fail("Section \"%s\" already declared as fixed at bank %u", + pSect->pzName, pSect->nBank); + } + if (alignment != pSect->nAlign) { + if (pSect->nAlign == 0) + fail("Section \"%s\" already declared as unaligned", + pSect->pzName); + else + fail("Section \"%s\" already declared as aligned to %u bits", + pSect->pzName, pSect->nAlign); + } } - fatalerror("Section already exists but with a different type"); + + if (nbSectErrors) + fatalerror("Cannot create section \"%s\" (%u errors)", + pSect->pzName, nbSectErrors); +#undef fail + return pSect; } pSect = malloc(sizeof(*pSect)); @@ -141,7 +228,8 @@ static struct Section *getSection(char const *pzName, enum SectionType type, fatalerror("Not enough memory for sectionname"); pSect->nType = type; - pSect->nPC = 0; + pSect->isUnion = isUnion; + pSect->size = 0; pSect->nOrg = org; pSect->nBank = bank; pSect->nAlign = alignment; @@ -177,10 +265,7 @@ static void setSection(struct Section *pSect) if (nUnionDepth > 0) fatalerror("Cannot change the section within a UNION"); - nPC = (pSect != NULL) ? pSect->nPC : 0; - pPCSymbol->pSection = pSect; - pPCSymbol->isConstant = pSect && pSect->nOrg != -1; sym_SetCurrentSymbolScope(NULL); } @@ -188,24 +273,24 @@ static void setSection(struct Section *pSect) /* * Set the current section by name and type */ -void out_NewSection(char const *pzName, uint32_t type, int32_t org, - struct SectionSpec const *attributes) +void out_NewSection(char const *pzName, uint32_t type, uint32_t org, + struct SectionSpec const *attributes, bool isUnion) { if (currentLoadSection) fatalerror("Cannot change the section within a `LOAD` block"); struct Section *pSect = getSection(pzName, type, org, attributes->bank, - 1 << attributes->alignment); + 1 << attributes->alignment, isUnion); - nPC = pSect->nPC; setSection(pSect); + curOffset = isUnion ? 0 : pSect->size; pCurrentSection = pSect; } /* * Set the current section by name and type */ -void out_SetLoadSection(char const *name, uint32_t type, int32_t org, +void out_SetLoadSection(char const *name, uint32_t type, uint32_t org, struct SectionSpec const *attributes) { checkcodesection(); @@ -214,9 +299,10 @@ void out_SetLoadSection(char const *name, uint32_t type, int32_t org, fatalerror("`LOAD` blocks cannot be nested"); struct Section *pSect = getSection(name, type, org, attributes->bank, - 1 << attributes->alignment); + 1 << attributes->alignment, false); - nPC = pSect->nPC; + loadOffset = curOffset; + curOffset = 0; /* curOffset -= loadOffset; */ setSection(pSect); currentLoadSection = pSect; } @@ -227,8 +313,9 @@ void out_EndLoadSection(void) yyerror("Found `ENDL` outside of a `LOAD` block"); currentLoadSection = NULL; - nPC = pCurrentSection->nPC; setSection(pCurrentSection); + curOffset += loadOffset; + loadOffset = 0; } struct Section *sect_GetSymbolSection(void) @@ -236,15 +323,44 @@ struct Section *sect_GetSymbolSection(void) return currentLoadSection ? currentLoadSection : pCurrentSection; } -/* - * Output an absolute byte (bypassing ROM/union checks) - */ -static void absByteBypassCheck(uint8_t b) +uint32_t sect_GetOutputOffset(void) { - pCurrentSection->tData[pCurrentSection->nPC++] = b; - if (currentLoadSection) - currentLoadSection->nPC++; - nPC++; + return curOffset + loadOffset; +} + +static inline void growSection(uint32_t growth) +{ + curOffset += growth; + if (curOffset > pCurrentSection->size) + pCurrentSection->size = curOffset; + if (currentLoadSection && curOffset > currentLoadSection->size) + currentLoadSection->size = curOffset; +} + +static inline void writebyte(uint8_t byte) +{ + pCurrentSection->tData[sect_GetOutputOffset()] = byte; + growSection(1); +} + +static inline void writeword(uint16_t b) +{ + writebyte(b & 0xFF); + writebyte(b >> 8); +} + +static inline void writelong(uint32_t b) +{ + writebyte(b & 0xFF); + writebyte(b >> 8); + writebyte(b >> 16); + writebyte(b >> 24); +} + +static inline void createPatch(enum PatchType type, + struct Expression const *expr) +{ + out_CreatePatch(type, expr, sect_GetOutputOffset()); } /* @@ -253,16 +369,18 @@ static void absByteBypassCheck(uint8_t b) void out_AbsByte(uint8_t b) { checkcodesection(); - checksectionoverflow(1); - absByteBypassCheck(b); + reserveSpace(1); + + writebyte(b); } void out_AbsByteGroup(uint8_t const *s, int32_t length) { checkcodesection(); - checksectionoverflow(length); + reserveSpace(length); + while (length--) - absByteBypassCheck(*s++); + writebyte(*s++); } /* @@ -271,19 +389,17 @@ void out_AbsByteGroup(uint8_t const *s, int32_t length) void out_Skip(int32_t skip) { checksection(); - checksectionoverflow(skip); + reserveSpace(skip); + if (!sect_HasData(pCurrentSection->nType)) { - pCurrentSection->nPC += skip; - if (currentLoadSection) - currentLoadSection->nPC += skip; - nPC += skip; + growSection(skip); } else if (nUnionDepth > 0) { while (skip--) - absByteBypassCheck(CurrentOptions.fillchar); + writebyte(CurrentOptions.fillchar); } else { checkcodesection(); while (skip--) - absByteBypassCheck(CurrentOptions.fillchar); + writebyte(CurrentOptions.fillchar); } } @@ -293,19 +409,10 @@ void out_Skip(int32_t skip) void out_String(char const *s) { checkcodesection(); - checksectionoverflow(strlen(s)); - while (*s) - absByteBypassCheck(*s++); -} + reserveSpace(strlen(s)); -static void outputExpression(struct Expression const *expr) -{ - if (!rpn_isKnown(expr)) { - out_CreatePatch(PATCHTYPE_BYTE, expr); - out_AbsByte(0); - } else { - out_AbsByte(expr->nVal); - } + while (*s) + writebyte(*s++); } /* @@ -314,7 +421,15 @@ static void outputExpression(struct Expression const *expr) */ void out_RelByte(struct Expression *expr) { - outputExpression(expr); + checkcodesection(); + reserveSpace(1); + + if (!rpn_isKnown(expr)) { + createPatch(PATCHTYPE_BYTE, expr); + writebyte(0); + } else { + writebyte(expr->nVal); + } rpn_Free(expr); } @@ -322,25 +437,20 @@ void out_RelByte(struct Expression *expr) * Output several copies of a relocatable byte. Checking will be done to see if * it is an absolute value in disguise. */ -void out_RelBytes(struct Expression *expr, int32_t n) -{ - while (n--) - outputExpression(expr); - rpn_Free(expr); -} - -/* - * Output an absolute word - */ -static void absWord(uint16_t b) +void out_RelBytes(struct Expression *expr, uint32_t n) { checkcodesection(); - checksectionoverflow(2); - pCurrentSection->tData[pCurrentSection->nPC++] = b & 0xFF; - pCurrentSection->tData[pCurrentSection->nPC++] = b >> 8; - if (currentLoadSection) - currentLoadSection->nPC += 2; - nPC += 2; + reserveSpace(n); + + while (n--) { + if (!rpn_isKnown(expr)) { + createPatch(PATCHTYPE_BYTE, expr); + writebyte(0); + } else { + writebyte(expr->nVal); + } + } + rpn_Free(expr); } /* @@ -349,42 +459,32 @@ static void absWord(uint16_t b) */ void out_RelWord(struct Expression *expr) { + checkcodesection(); + reserveSpace(2); + if (!rpn_isKnown(expr)) { - out_CreatePatch(PATCHTYPE_WORD, expr); - absWord(0); + createPatch(PATCHTYPE_WORD, expr); + writeword(0); } else { - absWord(expr->nVal); + writeword(expr->nVal); } rpn_Free(expr); } -/* - * Output an absolute longword - */ -static void absLong(uint32_t b) -{ - checkcodesection(); - checksectionoverflow(4); - pCurrentSection->tData[pCurrentSection->nPC++] = b & 0xFF; - pCurrentSection->tData[pCurrentSection->nPC++] = b >> 8; - pCurrentSection->tData[pCurrentSection->nPC++] = b >> 16; - pCurrentSection->tData[pCurrentSection->nPC++] = b >> 24; - if (currentLoadSection) - currentLoadSection->nPC += 4; - nPC += 4; -} - /* * Output a relocatable longword. Checking will be done to see if * is an absolute value in disguise. */ void out_RelLong(struct Expression *expr) { + checkcodesection(); + reserveSpace(2); + if (!rpn_isKnown(expr)) { - out_CreatePatch(PATCHTYPE_LONG, expr); - absLong(0); + createPatch(PATCHTYPE_LONG, expr); + writelong(0); } else { - absLong(expr->nVal); + writelong(expr->nVal); } rpn_Free(expr); } @@ -396,13 +496,11 @@ void out_RelLong(struct Expression *expr) void out_PCRelByte(struct Expression *expr) { checkcodesection(); - checksectionoverflow(1); + reserveSpace(1); + if (!rpn_isKnown(expr) || pCurrentSection->nOrg == -1) { - out_CreatePatch(PATCHTYPE_JR, expr); - pCurrentSection->tData[pCurrentSection->nPC++] = 0; - if (currentLoadSection) - currentLoadSection->nPC++; - nPC++; + createPatch(PATCHTYPE_JR, expr); + writebyte(0); } else { /* Target is relative to the byte *after* the operand */ uint16_t address = sym_GetValue(pPCSymbol) + 1; @@ -412,9 +510,9 @@ void out_PCRelByte(struct Expression *expr) if (offset < -128 || offset > 127) { yyerror("jr target out of reach (expected -129 < %d < 128)", offset); - out_AbsByte(0); + writebyte(0); } else { - out_AbsByte(offset); + writebyte(offset); } } rpn_Free(expr); @@ -444,7 +542,7 @@ void out_BinaryFile(char const *s) fsize = ftell(f); rewind(f); - checksectionoverflow(fsize); + reserveSpace(fsize); } else if (errno != ESPIPE) { yyerror("Error determining size of INCBIN file '%s': %s", s, strerror(errno)); @@ -452,11 +550,8 @@ void out_BinaryFile(char const *s) while ((byte = fgetc(f)) != EOF) { if (fsize == -1) - checksectionoverflow(1); - pCurrentSection->tData[pCurrentSection->nPC++] = byte; - if (currentLoadSection) - currentLoadSection->nPC++; - nPC++; + growSection(1); + writebyte(byte); } if (ferror(f)) @@ -493,7 +588,7 @@ void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length) } checkcodesection(); - checksectionoverflow(length); + reserveSpace(length); int32_t fsize; @@ -524,10 +619,7 @@ void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length) int byte = fgetc(f); if (byte != EOF) { - pCurrentSection->tData[pCurrentSection->nPC++] = byte; - if (currentLoadSection) - currentLoadSection->nPC++; - nPC++; + writebyte(byte); } else if (ferror(f)) { yyerror("Error reading INCBIN file '%s': %s", s, strerror(errno)); @@ -553,6 +645,7 @@ void out_PushSection(void) pSect->pSection = pCurrentSection; pSect->pScope = sym_GetCurrentSymbolScope(); + pSect->offset = curOffset; pSect->pNext = pSectionStack; pSectionStack = pSect; } @@ -571,6 +664,8 @@ void out_PopSection(void) setSection(pSect->pSection); pCurrentSection = pSect->pSection; sym_SetCurrentSymbolScope(pSect->pScope); + curOffset = pSect->offset; + pSectionStack = pSect->pNext; free(pSect); } diff --git a/src/asm/symbol.c b/src/asm/symbol.c index 79acb21c..9e204aad 100644 --- a/src/asm/symbol.c +++ b/src/asm/symbol.c @@ -62,7 +62,7 @@ static int32_t Callback__LINE__(struct sSymbol const *self) static int32_t CallbackPC(struct sSymbol const *self) { - return self->pSection ? self->pSection->nOrg + self->pSection->nPC : 0; + return self->pSection ? self->pSection->nOrg + curOffset : 0; } /* @@ -124,7 +124,6 @@ static struct sSymbol *createsymbol(char const *s) if (snprintf((*ppsym)->tzName, MAXSYMLEN + 1, "%s", s) > MAXSYMLEN) warning(WARNING_LONG_STR, "Symbol name is too long: '%s'", s); - (*ppsym)->isConstant = false; (*ppsym)->isExported = false; (*ppsym)->isBuiltin = false; (*ppsym)->isReferenced = false; @@ -349,7 +348,6 @@ struct sSymbol *sym_AddEqu(char const *tzSym, int32_t value) nsym->nValue = value; nsym->type = SYM_EQU; - nsym->isConstant = true; nsym->pScope = NULL; updateSymbolFilename(nsym); @@ -417,7 +415,6 @@ struct sSymbol *sym_AddSet(char const *tzSym, int32_t value) nsym->nValue = value; nsym->type = SYM_SET; - nsym->isConstant = true; nsym->pScope = NULL; updateSymbolFilename(nsym); @@ -479,9 +476,8 @@ struct sSymbol *sym_AddReloc(char const *tzSym) nsym->tzFileName, nsym->nFileLine); /* If the symbol already exists as a ref, just "take over" it */ - nsym->nValue = nPC; + nsym->nValue = curOffset; nsym->type = SYM_LABEL; - nsym->isConstant = pCurrentSection && pCurrentSection->nOrg != -1; if (exportall) nsym->isExported = true; diff --git a/test/asm/section-union.asm b/test/asm/section-union.asm new file mode 100644 index 00000000..cf7af0e8 --- /dev/null +++ b/test/asm/section-union.asm @@ -0,0 +1,37 @@ +SECTION UNION "test", WRAM0 +Base: + ds $1000 + +SECTION UNION "test", WRAM0,ALIGN[8] + ds 42 +Plus42: + +SECTION UNION "test", WRAM0,ALIGN[4] + +SECTION UNION "test", WRAM0[$C000] +; Since the section's base address is known, the labels are constant now + ds $1000 ; This shouldn't overflow +End: + +SECTION UNION "test", WRAM0,ALIGN[9] + + +check_label: MACRO +EXPECTED equ \2 + IF \1 == EXPECTED +RESULT equs "OK!" + ELSE +RESULT equs "expected {EXPECTED}" + ENDC + PURGE EXPECTED + + PRINTT "\1 is at {\1} ({RESULT})\n" + PURGE RESULT +ENDM + + check_label Base, $C000 + check_label Plus42, $C000 + 42 + check_label End, $D000 + + +SECTION "test", WRAM0 ; Don't allow creating a section that's not a union! diff --git a/test/asm/section-union.err b/test/asm/section-union.err new file mode 100644 index 00000000..533d56e5 --- /dev/null +++ b/test/asm/section-union.err @@ -0,0 +1,8 @@ +ERROR: section-union.asm(37): + Section "test" already declared as union +ERROR: section-union.asm(37): + Section "test" already declared as fixed at $c000 +ERROR: section-union.asm(37): + Section "test" already declared as aligned to 256 bits +ERROR: section-union.asm(37): + Cannot create section "test" (3 errors) diff --git a/test/asm/section-union.out b/test/asm/section-union.out new file mode 100644 index 00000000..52dd429a --- /dev/null +++ b/test/asm/section-union.out @@ -0,0 +1,3 @@ +Base is at $C000 (OK!) +Plus42 is at $C02A (OK!) +End is at $D000 (OK!)