Add section fragments

Fixes #517, and hopefully enables RGBDS as a SDCC back-end
This commit is contained in:
ISSOtm
2020-07-21 19:53:40 +02:00
parent aca00e4fce
commit 1f2f797cb9
17 changed files with 174 additions and 50 deletions

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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 {