mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Use automatic allocation for patches
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
#ifndef RGBDS_ASM_OUTPUT_H
|
||||
#define RGBDS_ASM_OUTPUT_H
|
||||
|
||||
#include <deque>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "linkdefs.hpp"
|
||||
@@ -12,7 +11,6 @@ struct Expression;
|
||||
struct FileStackNode;
|
||||
|
||||
extern const char *objectName;
|
||||
extern std::deque<struct Section> sectionList;
|
||||
|
||||
void out_RegisterNode(struct FileStackNode *node);
|
||||
void out_ReplaceNode(struct FileStackNode *node);
|
||||
|
||||
@@ -12,6 +12,19 @@
|
||||
extern uint8_t fillByte;
|
||||
|
||||
struct Expression;
|
||||
struct FileStackNode;
|
||||
struct Section;
|
||||
|
||||
struct Patch {
|
||||
struct FileStackNode const *src;
|
||||
uint32_t lineNo;
|
||||
uint32_t offset;
|
||||
struct Section *pcSection;
|
||||
uint32_t pcOffset;
|
||||
uint8_t type;
|
||||
uint32_t rpnSize;
|
||||
uint8_t *rpn;
|
||||
};
|
||||
|
||||
struct Section {
|
||||
char *name;
|
||||
@@ -24,7 +37,7 @@ struct Section {
|
||||
uint32_t bank;
|
||||
uint8_t align; // Exactly as specified in `ALIGN[]`
|
||||
uint16_t alignOfs;
|
||||
std::deque<struct Patch *> *patches;
|
||||
std::deque<struct Patch> patches;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
@@ -34,6 +47,7 @@ struct SectionSpec {
|
||||
uint16_t alignOfs;
|
||||
};
|
||||
|
||||
extern std::deque<struct Section> sectionList;
|
||||
extern struct Section *currentSection;
|
||||
|
||||
struct Section *sect_FindSectionByName(char const *name);
|
||||
|
||||
@@ -27,27 +27,14 @@
|
||||
#include "linkdefs.hpp"
|
||||
#include "platform.hpp" // strdup
|
||||
|
||||
struct Patch {
|
||||
struct FileStackNode const *src;
|
||||
uint32_t lineNo;
|
||||
uint32_t offset;
|
||||
struct Section *pcSection;
|
||||
uint32_t pcOffset;
|
||||
uint8_t type;
|
||||
uint32_t rpnSize;
|
||||
uint8_t *rpn;
|
||||
};
|
||||
|
||||
struct Assertion {
|
||||
struct Patch *patch;
|
||||
struct Patch patch;
|
||||
struct Section *section;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
const char *objectName;
|
||||
|
||||
std::deque<struct Section> sectionList;
|
||||
|
||||
// List of symbols to put in the object file
|
||||
static std::vector<struct Symbol *> objectSymbols;
|
||||
|
||||
@@ -117,17 +104,17 @@ static uint32_t getSectIDIfAny(struct Section *sect)
|
||||
}
|
||||
|
||||
// Write a patch to a file
|
||||
static void writepatch(struct Patch const *patch, FILE *f)
|
||||
static void writepatch(struct Patch const &patch, FILE *f)
|
||||
{
|
||||
assert(patch->src->ID != (uint32_t)-1);
|
||||
putlong(patch->src->ID, f);
|
||||
putlong(patch->lineNo, f);
|
||||
putlong(patch->offset, f);
|
||||
putlong(getSectIDIfAny(patch->pcSection), f);
|
||||
putlong(patch->pcOffset, f);
|
||||
putc(patch->type, f);
|
||||
putlong(patch->rpnSize, f);
|
||||
fwrite(patch->rpn, 1, patch->rpnSize, f);
|
||||
assert(patch.src->ID != (uint32_t)-1);
|
||||
putlong(patch.src->ID, f);
|
||||
putlong(patch.lineNo, f);
|
||||
putlong(patch.offset, f);
|
||||
putlong(getSectIDIfAny(patch.pcSection), f);
|
||||
putlong(patch.pcOffset, f);
|
||||
putc(patch.type, f);
|
||||
putlong(patch.rpnSize, f);
|
||||
fwrite(patch.rpn, 1, patch.rpnSize, f);
|
||||
}
|
||||
|
||||
// Write a section to a file
|
||||
@@ -149,21 +136,18 @@ static void writesection(struct Section const §, FILE *f)
|
||||
|
||||
if (sect_HasData(sect.type)) {
|
||||
fwrite(sect.data, 1, sect.size, f);
|
||||
putlong(sect.patches->size(), f);
|
||||
putlong(sect.patches.size(), f);
|
||||
|
||||
for (struct Patch const *patch : *sect.patches)
|
||||
for (struct Patch const &patch : sect.patches)
|
||||
writepatch(patch, f);
|
||||
}
|
||||
}
|
||||
|
||||
static void freesection(struct Section const §)
|
||||
static void freesection(struct Section §)
|
||||
{
|
||||
if (sect_HasData(sect.type)) {
|
||||
for (struct Patch *patch : *sect.patches) {
|
||||
free(patch->rpn);
|
||||
free(patch);
|
||||
}
|
||||
delete sect.patches;
|
||||
for (struct Patch &patch : sect.patches)
|
||||
free(patch.rpn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,69 +280,62 @@ static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, const uint8_t *rpn,
|
||||
}
|
||||
}
|
||||
|
||||
static struct Patch *allocpatch(uint32_t type, struct Expression const *expr, uint32_t ofs)
|
||||
static void initpatch(struct Patch &patch, uint32_t type, struct Expression const *expr, uint32_t ofs)
|
||||
{
|
||||
struct Patch *patch = (struct Patch *)malloc(sizeof(*patch));
|
||||
uint32_t rpnSize = rpn_isKnown(expr) ? 5 : expr->rpnPatchSize;
|
||||
struct FileStackNode *node = fstk_GetFileStack();
|
||||
|
||||
if (!patch)
|
||||
fatalerror("No memory for patch: %s\n", strerror(errno));
|
||||
|
||||
patch->rpn = (uint8_t *)malloc(sizeof(*patch->rpn) * rpnSize);
|
||||
if (!patch->rpn)
|
||||
patch.rpn = (uint8_t *)malloc(sizeof(*patch.rpn) * rpnSize);
|
||||
if (!patch.rpn)
|
||||
fatalerror("No memory for patch's RPN rpnSize: %s\n", strerror(errno));
|
||||
|
||||
patch->type = type;
|
||||
patch->src = node;
|
||||
patch.type = type;
|
||||
patch.src = node;
|
||||
// All patches are assumed to eventually be written, so the file stack node is registered
|
||||
out_RegisterNode(node);
|
||||
patch->lineNo = lexer_GetLineNo();
|
||||
patch->offset = ofs;
|
||||
patch->pcSection = sect_GetSymbolSection();
|
||||
patch->pcOffset = sect_GetSymbolOffset();
|
||||
patch.lineNo = lexer_GetLineNo();
|
||||
patch.offset = ofs;
|
||||
patch.pcSection = sect_GetSymbolSection();
|
||||
patch.pcOffset = sect_GetSymbolOffset();
|
||||
|
||||
// If the rpnSize's value is known, output a constant RPN rpnSize directly
|
||||
if (rpn_isKnown(expr)) {
|
||||
patch->rpnSize = rpnSize;
|
||||
patch.rpnSize = rpnSize;
|
||||
// Make sure to update `rpnSize` above if modifying this!
|
||||
patch->rpn[0] = RPN_CONST;
|
||||
patch->rpn[1] = (uint32_t)(expr->val) & 0xFF;
|
||||
patch->rpn[2] = (uint32_t)(expr->val) >> 8;
|
||||
patch->rpn[3] = (uint32_t)(expr->val) >> 16;
|
||||
patch->rpn[4] = (uint32_t)(expr->val) >> 24;
|
||||
patch.rpn[0] = RPN_CONST;
|
||||
patch.rpn[1] = (uint32_t)(expr->val) & 0xFF;
|
||||
patch.rpn[2] = (uint32_t)(expr->val) >> 8;
|
||||
patch.rpn[3] = (uint32_t)(expr->val) >> 16;
|
||||
patch.rpn[4] = (uint32_t)(expr->val) >> 24;
|
||||
} else {
|
||||
patch->rpnSize = 0;
|
||||
writerpn(patch->rpn, &patch->rpnSize, expr->rpn, expr->rpnLength);
|
||||
patch.rpnSize = 0;
|
||||
writerpn(patch.rpn, &patch.rpnSize, expr->rpn, expr->rpnLength);
|
||||
}
|
||||
assert(patch->rpnSize == rpnSize);
|
||||
|
||||
return patch;
|
||||
assert(patch.rpnSize == rpnSize);
|
||||
}
|
||||
|
||||
// Create a new patch (includes the rpn expr)
|
||||
void out_CreatePatch(uint32_t type, struct Expression const *expr, uint32_t ofs, uint32_t pcShift)
|
||||
{
|
||||
struct Patch *patch = allocpatch(type, expr, ofs);
|
||||
// Add the patch to the list
|
||||
struct Patch &patch = currentSection->patches.emplace_front();
|
||||
|
||||
initpatch(patch, type, expr, ofs);
|
||||
|
||||
// If the patch had a quantity of bytes output before it,
|
||||
// PC is not at the patch's location, but at the location
|
||||
// before those bytes.
|
||||
patch->pcOffset -= pcShift;
|
||||
|
||||
// Add the patch to the list
|
||||
currentSection->patches->push_front(patch);
|
||||
patch.pcOffset -= pcShift;
|
||||
}
|
||||
|
||||
// Creates an assert that will be written to the object file
|
||||
void out_CreateAssert(enum AssertionType type, struct Expression const *expr,
|
||||
char const *message, uint32_t ofs)
|
||||
{
|
||||
assertions.push_front({
|
||||
.patch = allocpatch(type, expr, ofs),
|
||||
.section = NULL,
|
||||
.message = message,
|
||||
});
|
||||
struct Assertion &assertion = assertions.emplace_front();
|
||||
|
||||
initpatch(assertion.patch, type, expr, ofs);
|
||||
assertion.message = message;
|
||||
}
|
||||
|
||||
static void writeassert(struct Assertion &assert, FILE *f)
|
||||
@@ -369,8 +346,7 @@ static void writeassert(struct Assertion &assert, FILE *f)
|
||||
|
||||
static void freeassert(struct Assertion &assert)
|
||||
{
|
||||
free(assert.patch->rpn);
|
||||
free(assert.patch);
|
||||
free(assert.patch.rpn);
|
||||
}
|
||||
|
||||
static void writeFileStackNode(struct FileStackNode const *node, FILE *f)
|
||||
|
||||
@@ -42,6 +42,7 @@ struct SectionStackEntry {
|
||||
|
||||
std::stack<struct UnionStackEntry> *currentUnionStack = NULL;
|
||||
std::deque<struct SectionStackEntry> sectionStack;
|
||||
std::deque<struct Section> sectionList;
|
||||
uint32_t curOffset; // Offset into the current section (see sect_GetSymbolOffset)
|
||||
struct Section *currentSection = NULL;
|
||||
static struct Section *currentLoadSection = NULL;
|
||||
@@ -283,9 +284,6 @@ static struct Section *createSection(char const *name, enum SectionType type,
|
||||
sect.bank = bank;
|
||||
sect.align = alignment;
|
||||
sect.alignOfs = alignOffset;
|
||||
sect.patches = new(std::nothrow) std::deque<struct Patch *>();
|
||||
if (sect.patches == NULL)
|
||||
fatalerror("Not enough memory for section patches: %s\n", strerror(errno));
|
||||
|
||||
// It is only needed to allocate memory for ROM sections.
|
||||
if (sect_HasData(type)) {
|
||||
|
||||
Reference in New Issue
Block a user