ref: cb52ae0f26462f3069f0fec0643dd98fd0929154
parent: 46a402f7d76dd90b668bc79c9d11b0f9f0c98e44
author: ISSOtm <[email protected]>
date: Fri Mar 20 17:02:32 EDT 2020
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.
--- 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;
--- a/include/asm/main.h
+++ b/include/asm/main.h
@@ -31,6 +31,8 @@
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;
--- a/include/asm/output.h
+++ b/include/asm/output.h
@@ -19,9 +19,10 @@
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 */
--- a/include/asm/section.h
+++ b/include/asm/section.h
@@ -18,7 +18,8 @@
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,18 +29,19 @@
};
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);
@@ -46,7 +48,7 @@
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);
--- a/include/asm/symbol.h
+++ b/include/asm/symbol.h
@@ -13,6 +13,8 @@
#include <stdint.h>
#include <string.h>
+#include "asm/section.h"
+
#include "types.h"
#define HASHSIZE (1 << 16)
@@ -30,7 +32,6 @@
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_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)
--- a/src/asm/asmy.y
+++ b/src/asm/asmy.y
@@ -393,7 +393,7 @@
if (nUnionDepth > MAXUNIONS)
fatalerror("Too many nested UNIONs");
- unionStart[unionIndex] = nPC;
+ unionStart[unionIndex] = curOffset;
unionSize[unionIndex] = 0;
}
@@ -400,13 +400,12 @@
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 @@
%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 <macroArg> macroargs;
+%type <nConstValue> sectunion
+%type <macroArg> macroargs
%token T_Z80_ADC T_Z80_ADD T_Z80_AND
%token T_Z80_BIT
@@ -815,7 +815,8 @@
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 @@
| 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 @@
updateUnion();
nUnionDepth--;
- nPC = unionStart[nUnionDepth] + unionSize[nUnionDepth];
- pCurrentSection->nPC = nPC;
+ curOffset = unionStart[nUnionDepth] + unionSize[nUnionDepth];
}
;
@@ -1418,10 +1419,13 @@
}
;
-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; }
--- a/src/asm/main.c
+++ b/src/asm/main.c
@@ -40,11 +40,13 @@
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 @@
nIFDepth = 0;
skipElif = true;
nUnionDepth = 0;
- nPC = 0;
sym_Init();
sym_SetExportAll(CurrentOptions.exportall);
fstk_Init(tzMainfile);
--- a/src/asm/output.c
+++ b/src/asm/output.c
@@ -187,7 +187,7 @@
{
fputstring(pSect->pzName, f);
- fputlong(pSect->nPC, f);
+ fputlong(pSect->size, f);
fputc(pSect->nType, f);
@@ -198,7 +198,7 @@
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 @@
/*
* 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 @@
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 @@
/*
* 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,7 +443,7 @@
* 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));
@@ -449,7 +450,7 @@
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) {
--- 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 @@
* 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 @@
/*
* 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 @@
* 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 @@
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 @@
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 @@
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,17 +273,17 @@
/*
* 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;
}
@@ -205,7 +290,7 @@
/*
* 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 @@
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 @@
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,17 +323,46 @@
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());
+}
+
/*
* Output an absolute byte
*/
@@ -253,16 +369,18 @@
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_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,21 +409,12 @@
void out_String(char const *s)
{
checkcodesection();
- checksectionoverflow(strlen(s));
+ reserveSpace(strlen(s));
+
while (*s)
- absByteBypassCheck(*s++);
+ writebyte(*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);
- }
-}
-
/*
* Output a relocatable byte. Checking will be done to see if it
* is an absolute value in disguise.
@@ -314,7 +421,15 @@
*/
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,69 +437,54 @@
* 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)
+void out_RelBytes(struct Expression *expr, uint32_t n)
{
- while (n--)
- outputExpression(expr);
+ checkcodesection();
+ reserveSpace(n);
+
+ while (n--) {
+ if (!rpn_isKnown(expr)) {
+ createPatch(PATCHTYPE_BYTE, expr);
+ writebyte(0);
+ } else {
+ writebyte(expr->nVal);
+ }
+ }
rpn_Free(expr);
}
/*
- * Output an absolute word
- */
-static void absWord(uint16_t b)
-{
- checkcodesection();
- checksectionoverflow(2);
- pCurrentSection->tData[pCurrentSection->nPC++] = b & 0xFF;
- pCurrentSection->tData[pCurrentSection->nPC++] = b >> 8;
- if (currentLoadSection)
- currentLoadSection->nPC += 2;
- nPC += 2;
-}
-
-/*
* Output a relocatable word. Checking will be done to see if
* it's an absolute value in disguise.
*/
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_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 @@
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 @@
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 @@
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 @@
}
checkcodesection();
- checksectionoverflow(length);
+ reserveSpace(length);
int32_t fsize;
@@ -524,10 +619,7 @@
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 @@
pSect->pSection = pCurrentSection;
pSect->pScope = sym_GetCurrentSymbolScope();
+ pSect->offset = curOffset;
pSect->pNext = pSectionStack;
pSectionStack = pSect;
}
@@ -571,6 +664,8 @@
setSection(pSect->pSection);
pCurrentSection = pSect->pSection;
sym_SetCurrentSymbolScope(pSect->pScope);
+ curOffset = pSect->offset;
+
pSectionStack = pSect->pNext;
free(pSect);
}
--- a/src/asm/symbol.c
+++ b/src/asm/symbol.c
@@ -62,7 +62,7 @@
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 @@
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 @@
nsym->nValue = value;
nsym->type = SYM_EQU;
- nsym->isConstant = true;
nsym->pScope = NULL;
updateSymbolFilename(nsym);
@@ -417,7 +415,6 @@
nsym->nValue = value;
nsym->type = SYM_SET;
- nsym->isConstant = true;
nsym->pScope = NULL;
updateSymbolFilename(nsym);
@@ -479,9 +476,8 @@
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;
--- /dev/null
+++ b/test/asm/section-union.asm
@@ -1,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!
--- /dev/null
+++ b/test/asm/section-union.err
@@ -1,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)
--- /dev/null
+++ b/test/asm/section-union.out
@@ -1,0 +1,3 @@
+Base is at $C000 (OK!)
+Plus42 is at $C02A (OK!)
+End is at $D000 (OK!)