mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-24 03:52:08 +00:00
Add section fragments
Fixes #517, and hopefully enables RGBDS as a SDCC back-end
This commit is contained in:
@@ -266,10 +266,16 @@ static void readSection(FILE *file, struct Section *section,
|
||||
errx(1, "\"%s\"'s section size (%" PRId32 ") is invalid",
|
||||
section->name, tmp);
|
||||
section->size = tmp;
|
||||
section->offset = 0;
|
||||
tryGetc(byte, file, "%s: Cannot read \"%s\"'s type: %s",
|
||||
fileName, section->name);
|
||||
section->type = byte & 0x7F;
|
||||
section->isUnion = byte >> 7;
|
||||
section->type = byte & 0x3F;
|
||||
if (byte >> 7)
|
||||
section->modifier = SECTION_UNION;
|
||||
else if (byte >> 6)
|
||||
section->modifier = SECTION_FRAGMENT;
|
||||
else
|
||||
section->modifier = SECTION_NORMAL;
|
||||
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s org: %s",
|
||||
fileName, section->name);
|
||||
section->isAddressFixed = tmp >= 0;
|
||||
@@ -382,7 +388,7 @@ static void readAssertion(FILE *file, struct Assertion *assert,
|
||||
|
||||
static inline struct Section *getMainSection(struct Section *section)
|
||||
{
|
||||
if (section->isUnion)
|
||||
if (section->modifier != SECTION_NORMAL)
|
||||
section = sect_GetSection(section->name);
|
||||
|
||||
return section;
|
||||
@@ -502,10 +508,18 @@ void obj_ReadFile(char const *fileName)
|
||||
if (sectionID == -1) {
|
||||
fileSymbols[i]->section = NULL;
|
||||
} else {
|
||||
struct Section *section = fileSections[sectionID];
|
||||
|
||||
/* Give the section a pointer to the symbol as well */
|
||||
linkSymToSect(fileSymbols[i], fileSections[sectionID]);
|
||||
fileSymbols[i]->section =
|
||||
getMainSection(fileSections[sectionID]);
|
||||
linkSymToSect(fileSymbols[i], section);
|
||||
|
||||
if (section->modifier != SECTION_NORMAL) {
|
||||
if (section->modifier == SECTION_FRAGMENT)
|
||||
/* Add the fragment's offset to the symbol's */
|
||||
fileSymbols[i]->offset += section->offset;
|
||||
section = getMainSection(section);
|
||||
}
|
||||
fileSymbols[i]->section = section;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -421,7 +421,7 @@ void patch_CheckAssertions(struct Assertion *assert)
|
||||
* @param section The section to patch
|
||||
* @param arg Ignored callback arg
|
||||
*/
|
||||
static void applyFilePatches(struct Section *section)
|
||||
static void applyFilePatches(struct Section *section, struct Section *dataSection)
|
||||
{
|
||||
if (!sect_HasData(section->type))
|
||||
return;
|
||||
@@ -432,6 +432,7 @@ static void applyFilePatches(struct Section *section)
|
||||
int32_t value = computeRPNExpr(patch,
|
||||
(struct Symbol const * const *)
|
||||
section->fileSymbols);
|
||||
uint16_t offset = patch->offset + section->offset;
|
||||
|
||||
/* `jr` is quite unlike the others... */
|
||||
if (patch->type == PATCHTYPE_JR) {
|
||||
@@ -443,7 +444,7 @@ static void applyFilePatches(struct Section *section)
|
||||
if (offset < -128 || offset > 127)
|
||||
error("%s: jr target out of reach (expected -129 < %" PRId16 " < 128)",
|
||||
patch->fileName, offset);
|
||||
section->data[patch->offset] = offset & 0xFF;
|
||||
dataSection->data[offset] = offset & 0xFF;
|
||||
} else {
|
||||
/* Patch a certain number of bytes */
|
||||
struct {
|
||||
@@ -463,7 +464,7 @@ static void applyFilePatches(struct Section *section)
|
||||
value < 0 ? " (maybe negative?)" : "",
|
||||
types[patch->type].size * 8U);
|
||||
for (uint8_t i = 0; i < types[patch->type].size; i++) {
|
||||
section->data[patch->offset + i] = value & 0xFF;
|
||||
dataSection->data[offset + i] = value & 0xFF;
|
||||
value >>= 8;
|
||||
}
|
||||
}
|
||||
@@ -479,9 +480,10 @@ static void applyFilePatches(struct Section *section)
|
||||
static void applyPatches(struct Section *section, void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
struct Section *dataSection = section;
|
||||
|
||||
do {
|
||||
applyFilePatches(section);
|
||||
applyFilePatches(section, dataSection);
|
||||
section = section->nextu;
|
||||
} while (section);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "link/main.h"
|
||||
#include "link/section.h"
|
||||
@@ -37,7 +39,7 @@ void sect_ForEach(void (*callback)(struct Section *, void *), void *arg)
|
||||
hash_ForEach(sections, forEach, &callbackArg);
|
||||
}
|
||||
|
||||
static void mergeSections(struct Section *target, struct Section *other)
|
||||
static void mergeSections(struct Section *target, struct Section *other, enum SectionModifier mod)
|
||||
{
|
||||
if (target->type != other->type)
|
||||
errx(1, "Section \"%s\" is defined with conflicting types %s and %s",
|
||||
@@ -86,9 +88,30 @@ static void mergeSections(struct Section *target, struct Section *other)
|
||||
}
|
||||
}
|
||||
|
||||
if (other->size > target->size)
|
||||
target->size = other->size;
|
||||
switch (mod) {
|
||||
case SECTION_UNION:
|
||||
if (other->size > target->size)
|
||||
target->size = other->size;
|
||||
break;
|
||||
|
||||
case SECTION_FRAGMENT:
|
||||
target->size += other->size;
|
||||
other->offset = target->size - other->size;
|
||||
if (sect_HasData(target->type)) {
|
||||
/* Ensure we're not allocating 0 bytes */
|
||||
target->data = realloc(target->data,
|
||||
sizeof(*target->data) * target->size + 1);
|
||||
if (!target->data)
|
||||
errx(1, "Failed to concatenate \"%s\"'s fragments", target->name);
|
||||
memcpy(target->data + target->size - other->size, other->data, other->size);
|
||||
}
|
||||
break;
|
||||
|
||||
case SECTION_NORMAL:
|
||||
trap_;
|
||||
}
|
||||
|
||||
other->nextu = target->nextu;
|
||||
target->nextu = other;
|
||||
}
|
||||
|
||||
@@ -98,16 +121,14 @@ void sect_AddSection(struct Section *section)
|
||||
struct Section *other = hash_GetElement(sections, section->name);
|
||||
|
||||
if (other) {
|
||||
if (other->isUnion && section->isUnion) {
|
||||
mergeSections(other, section);
|
||||
} else if (section->isUnion || other->isUnion) {
|
||||
errx(1, "Section \"%s\" defined as both unionized and not",
|
||||
section->name);
|
||||
} else {
|
||||
errx(1, "Section name \"%s\" is already in use",
|
||||
section->name);
|
||||
}
|
||||
} else if (section->isUnion && sect_HasData(section->type)) {
|
||||
if (section->modifier != other->modifier)
|
||||
errx(1, "Section \"%s\" defined as %s and %s", section->name,
|
||||
sectionModNames[section->modifier], sectionModNames[other->modifier]);
|
||||
else if (section->modifier == SECTION_NORMAL)
|
||||
errx(1, "Section name \"%s\" is already in use", section->name);
|
||||
else
|
||||
mergeSections(other, section, section->modifier);
|
||||
} else if (section->modifier == SECTION_UNION && sect_HasData(section->type)) {
|
||||
errx(1, "Section \"%s\" is of type %s, which cannot be unionized",
|
||||
section->name, typeNames[section->type]);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user