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