Use std::string for symbol/section/node names and assertion messages

This commit is contained in:
Rangi42
2024-02-27 18:59:38 -05:00
committed by Sylvie
parent a24df27cd8
commit 48b2e94aa3
12 changed files with 172 additions and 201 deletions

View File

@@ -6,6 +6,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string>
#include <vector> #include <vector>
#include "helpers.hpp" #include "helpers.hpp"
@@ -35,7 +36,7 @@ struct FileStackNode {
enum FileStackNodeType type; enum FileStackNodeType type;
union { union {
char *name; // NODE_FILE, NODE_MACRO std::string *name; // NODE_FILE, NODE_MACRO
std::vector<uint32_t> *iters; // NODE_REPT std::vector<uint32_t> *iters; // NODE_REPT
}; };
}; };
@@ -50,7 +51,7 @@ struct FileStackNode {
* Dump a file stack to stderr * Dump a file stack to stderr
* @param node The leaf node to dump the context of * @param node The leaf node to dump the context of
*/ */
char const *dumpFileStack(struct FileStackNode const *node); std::string const *dumpFileStack(struct FileStackNode const *node);
void warning(struct FileStackNode const *where, uint32_t lineNo, void warning(struct FileStackNode const *where, uint32_t lineNo,
char const *fmt, ...) format_(printf, 3, 4); char const *fmt, ...) format_(printf, 3, 4);

View File

@@ -14,7 +14,7 @@
struct Assertion { struct Assertion {
struct Patch patch; // Also used for its `.type` struct Patch patch; // Also used for its `.type`
char *message; std::string *message;
// This would be redundant with `.section->fileSymbols`... but `section` is sometimes NULL! // This would be redundant with `.section->fileSymbols`... but `section` is sometimes NULL!
std::vector<struct Symbol> *fileSymbols; std::vector<struct Symbol> *fileSymbols;
}; };

View File

@@ -7,6 +7,7 @@
// GUIDELINE: external code MUST NOT BE AWARE of the data structure used! // GUIDELINE: external code MUST NOT BE AWARE of the data structure used!
#include <stdint.h> #include <stdint.h>
#include <string>
#include <vector> #include <vector>
#include "link/main.hpp" #include "link/main.hpp"
@@ -30,7 +31,7 @@ struct Patch {
struct Section { struct Section {
// Info contained in the object files // Info contained in the object files
char *name; std::string *name;
uint16_t size; uint16_t size;
uint16_t offset; uint16_t offset;
enum SectionType type; enum SectionType type;
@@ -70,7 +71,7 @@ void sect_AddSection(struct Section *section);
* @param name The name of the section to look for * @param name The name of the section to look for
* @return A pointer to the section, or NULL if it wasn't found * @return A pointer to the section, or NULL if it wasn't found
*/ */
struct Section *sect_GetSection(char const *name); struct Section *sect_GetSection(std::string const &name);
/* /*
* `free`s all section memory that was allocated. * `free`s all section memory that was allocated.

View File

@@ -7,6 +7,7 @@
// GUIDELINE: external code MUST NOT BE AWARE of the data structure used! // GUIDELINE: external code MUST NOT BE AWARE of the data structure used!
#include <stdint.h> #include <stdint.h>
#include <string>
#include "linkdefs.hpp" #include "linkdefs.hpp"
@@ -14,7 +15,7 @@ struct FileStackNode;
struct Symbol { struct Symbol {
// Info contained in the object files // Info contained in the object files
char *name; std::string *name;
enum ExportLevel type; enum ExportLevel type;
char const *objFileName; char const *objFileName;
struct FileStackNode const *src; struct FileStackNode const *src;
@@ -36,7 +37,7 @@ void sym_AddSymbol(struct Symbol *symbol);
* @param name The name of the symbol to look for * @param name The name of the symbol to look for
* @return A pointer to the symbol, or NULL if not found. * @return A pointer to the symbol, or NULL if not found.
*/ */
struct Symbol *sym_GetSymbol(char const *name); struct Symbol *sym_GetSymbol(std::string const &name);
/* /*
* `free`s all symbol memory that was allocated. * `free`s all symbol memory that was allocated.

View File

@@ -318,17 +318,17 @@ static void placeSection(struct Section *section)
// If a section failed to go to several places, nothing we can report // If a section failed to go to several places, nothing we can report
if (!section->isBankFixed || !section->isAddressFixed) if (!section->isBankFixed || !section->isAddressFixed)
errx("Unable to place \"%s\" (%s section) %s", errx("Unable to place \"%s\" (%s section) %s",
section->name, sectionTypeInfo[section->type].name.c_str(), where); section->name->c_str(), sectionTypeInfo[section->type].name.c_str(), where);
// If the section just can't fit the bank, report that // If the section just can't fit the bank, report that
else if (section->org + section->size > endaddr(section->type) + 1) else if (section->org + section->size > endaddr(section->type) + 1)
errx("Unable to place \"%s\" (%s section) %s: section runs past end of region ($%04x > $%04x)", errx("Unable to place \"%s\" (%s section) %s: section runs past end of region ($%04x > $%04x)",
section->name, sectionTypeInfo[section->type].name.c_str(), where, section->name->c_str(), sectionTypeInfo[section->type].name.c_str(), where,
section->org + section->size, endaddr(section->type) + 1); section->org + section->size, endaddr(section->type) + 1);
// Otherwise there is overlap with another section // Otherwise there is overlap with another section
else else
errx("Unable to place \"%s\" (%s section) %s: section overlaps with \"%s\"", errx("Unable to place \"%s\" (%s section) %s: section overlaps with \"%s\"",
section->name, sectionTypeInfo[section->type].name.c_str(), where, section->name->c_str(), sectionTypeInfo[section->type].name.c_str(), where,
out_OverlappingSection(section)->name); out_OverlappingSection(section)->name->c_str());
} }
#define BANK_CONSTRAINED (1 << 2) #define BANK_CONSTRAINED (1 << 2)
@@ -396,7 +396,7 @@ void assign_AssignSections(void)
constraints >= 0; constraints--) { constraints >= 0; constraints--) {
for (struct Section *section : unassignedSections[constraints]) { for (struct Section *section : unassignedSections[constraints]) {
fprintf(stderr, "%c \"%s\"", nbSections == 0 ? ';': ',', fprintf(stderr, "%c \"%s\"", nbSections == 0 ? ';': ',',
section->name); section->name->c_str());
nbSections++; nbSections++;
if (nbSections == 10) if (nbSections == 10)
goto max_out; goto max_out;

View File

@@ -49,16 +49,16 @@ FILE *linkerScript;
static uint32_t nbErrors = 0; static uint32_t nbErrors = 0;
// Helper function to dump a file stack to stderr // Helper function to dump a file stack to stderr
char const *dumpFileStack(struct FileStackNode const *node) std::string const *dumpFileStack(struct FileStackNode const *node)
{ {
char const *lastName; std::string const *lastName;
if (node->parent) { if (node->parent) {
lastName = dumpFileStack(node->parent); lastName = dumpFileStack(node->parent);
// REPT nodes use their parent's name // REPT nodes use their parent's name
if (node->type != NODE_REPT) if (node->type != NODE_REPT)
lastName = node->name; lastName = node->name;
fprintf(stderr, "(%" PRIu32 ") -> %s", node->lineNo, lastName); fprintf(stderr, "(%" PRIu32 ") -> %s", node->lineNo, lastName->c_str());
if (node->type == NODE_REPT) { if (node->type == NODE_REPT) {
for (uint32_t iter : *node->iters) for (uint32_t iter : *node->iters)
fprintf(stderr, "::REPT~%" PRIu32, iter); fprintf(stderr, "::REPT~%" PRIu32, iter);
@@ -66,7 +66,7 @@ char const *dumpFileStack(struct FileStackNode const *node)
} else { } else {
assert(node->type != NODE_REPT); assert(node->type != NODE_REPT);
lastName = node->name; lastName = node->name;
fputs(lastName, stderr); fputs(lastName->c_str(), stderr);
} }
return lastName; return lastName;

View File

@@ -102,37 +102,25 @@ static int64_t readlong(FILE *file)
* @return The string read, or NULL on failure. * @return The string read, or NULL on failure.
* If a non-NULL pointer is returned, make sure to `free` it when done! * If a non-NULL pointer is returned, make sure to `free` it when done!
*/ */
static char *readstr(FILE *file) static std::string *readstring(FILE *file)
{ {
// Default buffer size, have it close to the average string length std::string *str = new(std::nothrow) std::string();
size_t capacity = 32 / 2;
size_t index = -1;
// Force the first iteration to allocate
char *str = NULL;
do {
// Prepare going to next char
index++;
// If the buffer isn't suitable to write the next char...
if (index >= capacity || !str) {
capacity *= 2;
str = (char *)realloc(str, capacity);
// End now in case of error
if (!str) if (!str)
return NULL; return NULL;
} for (;;) {
// Read char // Read char
int byte = getc(file); int byte = getc(file);
if (byte == EOF) { if (byte == EOF) {
free(str); delete str;
return NULL; return NULL;
} } else if (byte == '\0') {
str[index] = byte;
} while (str[index]);
return str; return str;
} else {
str->push_back(byte);
}
};
} }
/* /*
@@ -143,8 +131,8 @@ static char *readstr(FILE *file)
* @param ... A format string and related arguments; note that an extra string * @param ... A format string and related arguments; note that an extra string
* argument is provided, the reason for failure * argument is provided, the reason for failure
*/ */
#define tryReadstr(var, file, ...) \ #define tryReadstring(var, file, ...) \
tryRead(readstr, char *, NULL, char *, var, file, __VA_ARGS__) tryRead(readstring, std::string *, NULL, std::string *, var, file, __VA_ARGS__)
// Functions to parse object files // Functions to parse object files
@@ -171,7 +159,7 @@ static void readFileStackNode(FILE *file, std::vector<struct FileStackNode> &fil
switch (node.type) { switch (node.type) {
case NODE_FILE: case NODE_FILE:
case NODE_MACRO: case NODE_MACRO:
tryReadstr(node.name, file, tryReadstring(node.name, file,
"%s: Cannot read node #%" PRIu32 "'s file name: %s", fileName, i); "%s: Cannot read node #%" PRIu32 "'s file name: %s", fileName, i);
break; break;
@@ -203,28 +191,23 @@ static void readFileStackNode(FILE *file, std::vector<struct FileStackNode> &fil
static void readSymbol(FILE *file, struct Symbol *symbol, char const *fileName, static void readSymbol(FILE *file, struct Symbol *symbol, char const *fileName,
std::vector<struct FileStackNode> const &fileNodes) std::vector<struct FileStackNode> const &fileNodes)
{ {
tryReadstr(symbol->name, file, "%s: Cannot read symbol name: %s", tryReadstring(symbol->name, file, "%s: Cannot read symbol name: %s", fileName);
fileName);
tryGetc(enum ExportLevel, symbol->type, file, "%s: Cannot read \"%s\"'s type: %s", tryGetc(enum ExportLevel, symbol->type, file, "%s: Cannot read \"%s\"'s type: %s",
fileName, symbol->name); fileName, symbol->name->c_str());
// If the symbol is defined in this file, read its definition // If the symbol is defined in this file, read its definition
if (symbol->type != SYMTYPE_IMPORT) { if (symbol->type != SYMTYPE_IMPORT) {
symbol->objFileName = fileName; symbol->objFileName = fileName;
uint32_t nodeID; uint32_t nodeID;
tryReadlong(nodeID, file, tryReadlong(nodeID, file, "%s: Cannot read \"%s\"'s node ID: %s",
"%s: Cannot read \"%s\"'s node ID: %s", fileName, symbol->name->c_str());
fileName, symbol->name);
symbol->src = &fileNodes[nodeID]; symbol->src = &fileNodes[nodeID];
tryReadlong(symbol->lineNo, file, tryReadlong(symbol->lineNo, file, "%s: Cannot read \"%s\"'s line number: %s",
"%s: Cannot read \"%s\"'s line number: %s", fileName, symbol->name->c_str());
fileName, symbol->name); tryReadlong(symbol->sectionID, file, "%s: Cannot read \"%s\"'s section ID: %s",
tryReadlong(symbol->sectionID, file, fileName, symbol->name->c_str());
"%s: Cannot read \"%s\"'s section ID: %s", tryReadlong(symbol->offset, file, "%s: Cannot read \"%s\"'s value: %s",
fileName, symbol->name); fileName, symbol->name->c_str());
tryReadlong(symbol->offset, file,
"%s: Cannot read \"%s\"'s value: %s",
fileName, symbol->name);
} else { } else {
symbol->sectionID = -1; symbol->sectionID = -1;
} }
@@ -298,17 +281,14 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
int32_t tmp; int32_t tmp;
uint8_t byte; uint8_t byte;
tryReadstr(section->name, file, "%s: Cannot read section name: %s", tryReadstring(section->name, file, "%s: Cannot read section name: %s", fileName);
fileName); tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s' size: %s", fileName, section->name->c_str());
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s' size: %s",
fileName, section->name);
if (tmp < 0 || tmp > UINT16_MAX) if (tmp < 0 || tmp > UINT16_MAX)
errx("\"%s\"'s section size (%" PRId32 ") is invalid", errx("\"%s\"'s section size (%" PRId32 ") is invalid", section->name->c_str(), tmp);
section->name, tmp);
section->size = tmp; section->size = tmp;
section->offset = 0; section->offset = 0;
tryGetc(uint8_t, byte, file, "%s: Cannot read \"%s\"'s type: %s", tryGetc(uint8_t, byte, file, "%s: Cannot read \"%s\"'s type: %s", fileName,
fileName, section->name); section->name->c_str());
section->type = (enum SectionType)(byte & 0x3F); section->type = (enum SectionType)(byte & 0x3F);
if (byte >> 7) if (byte >> 7)
section->modifier = SECTION_UNION; section->modifier = SECTION_UNION;
@@ -316,30 +296,27 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
section->modifier = SECTION_FRAGMENT; section->modifier = SECTION_FRAGMENT;
else else
section->modifier = SECTION_NORMAL; section->modifier = SECTION_NORMAL;
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s org: %s", tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s org: %s", fileName, section->name->c_str());
fileName, section->name);
section->isAddressFixed = tmp >= 0; section->isAddressFixed = tmp >= 0;
if (tmp > UINT16_MAX) { if (tmp > UINT16_MAX) {
error(NULL, 0, "\"%s\"'s org is too large (%" PRId32 ")", error(NULL, 0, "\"%s\"'s org is too large (%" PRId32 ")", section->name->c_str(), tmp);
section->name, tmp);
tmp = UINT16_MAX; tmp = UINT16_MAX;
} }
section->org = tmp; section->org = tmp;
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s bank: %s", tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s bank: %s", fileName, section->name->c_str());
fileName, section->name);
section->isBankFixed = tmp >= 0; section->isBankFixed = tmp >= 0;
section->bank = tmp; section->bank = tmp;
tryGetc(uint8_t, byte, file, "%s: Cannot read \"%s\"'s alignment: %s", tryGetc(uint8_t, byte, file, "%s: Cannot read \"%s\"'s alignment: %s", fileName,
fileName, section->name); section->name->c_str());
if (byte > 16) if (byte > 16)
byte = 16; byte = 16;
section->isAlignFixed = byte != 0; section->isAlignFixed = byte != 0;
section->alignMask = (1 << byte) - 1; section->alignMask = (1 << byte) - 1;
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s alignment offset: %s", tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s alignment offset: %s", fileName,
fileName, section->name); section->name->c_str());
if (tmp > UINT16_MAX) { if (tmp > UINT16_MAX) {
error(NULL, 0, "\"%s\"'s alignment offset is too large (%" PRId32 ")", error(NULL, 0, "\"%s\"'s alignment offset is too large (%" PRId32 ")",
section->name, tmp); section->name->c_str(), tmp);
tmp = UINT16_MAX; tmp = UINT16_MAX;
} }
section->alignOfs = tmp; section->alignOfs = tmp;
@@ -347,26 +324,27 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
if (sect_HasData(section->type)) { if (sect_HasData(section->type)) {
section->data = new(std::nothrow) std::vector<uint8_t>(section->size); section->data = new(std::nothrow) std::vector<uint8_t>(section->size);
if (!section->data) if (!section->data)
err("%s: Unable to read \"%s\"'s data", fileName, section->name); err("%s: Unable to read \"%s\"'s data", fileName, section->name->c_str());
if (section->size) { if (section->size) {
if (size_t nbRead = fread(&(*section->data)[0], 1, section->size, file); if (size_t nbRead = fread(&(*section->data)[0], 1, section->size, file);
nbRead != section->size) nbRead != section->size)
errx("%s: Cannot read \"%s\"'s data: %s", fileName, section->name, errx("%s: Cannot read \"%s\"'s data: %s", fileName, section->name->c_str(),
feof(file) ? "Unexpected end of file" : strerror(errno)); feof(file) ? "Unexpected end of file" : strerror(errno));
} }
uint32_t nbPatches; uint32_t nbPatches;
tryReadlong(nbPatches, file, tryReadlong(nbPatches, file,
"%s: Cannot read \"%s\"'s number of patches: %s", "%s: Cannot read \"%s\"'s number of patches: %s", fileName,
fileName, section->name); section->name->c_str());
section->patches = new(std::nothrow) std::vector<struct Patch>(); section->patches = new(std::nothrow) std::vector<struct Patch>();
if (!section->patches) if (!section->patches)
err("%s: Unable to read \"%s\"'s patches", fileName, section->name); err("%s: Unable to read \"%s\"'s patches", fileName, section->name->c_str());
section->patches->resize(nbPatches); section->patches->resize(nbPatches);
for (uint32_t i = 0; i < nbPatches; i++) for (uint32_t i = 0; i < nbPatches; i++)
readPatch(file, &(*section->patches)[i], fileName, section->name, i, fileNodes); readPatch(file, &(*section->patches)[i], fileName, section->name->c_str(),
i, fileNodes);
} else { } else {
section->data = NULL; // `mergeSections()` expects to be able to always read the ptr section->data = NULL; // `mergeSections()` expects to be able to always read the ptr
} }
@@ -399,8 +377,7 @@ static void linkSymToSect(struct Symbol &symbol, struct Section *section)
* @param assert The struct to fill * @param assert The struct to fill
* @param fileName The filename to report in errors * @param fileName The filename to report in errors
*/ */
static void readAssertion(FILE *file, struct Assertion *assert, static void readAssertion(FILE *file, struct Assertion *assert, char const *fileName, uint32_t i,
char const *fileName, uint32_t i,
std::vector<struct FileStackNode> const &fileNodes) std::vector<struct FileStackNode> const &fileNodes)
{ {
char assertName[sizeof("Assertion #4294967295")]; // UINT32_MAX char assertName[sizeof("Assertion #4294967295")]; // UINT32_MAX
@@ -408,14 +385,13 @@ static void readAssertion(FILE *file, struct Assertion *assert,
snprintf(assertName, sizeof(assertName), "Assertion #%" PRIu32, i); snprintf(assertName, sizeof(assertName), "Assertion #%" PRIu32, i);
readPatch(file, &assert->patch, fileName, assertName, 0, fileNodes); readPatch(file, &assert->patch, fileName, assertName, 0, fileNodes);
tryReadstr(assert->message, file, "%s: Cannot read assertion's message: %s", tryReadstring(assert->message, file, "%s: Cannot read assertion's message: %s", fileName);
fileName);
} }
static struct Section *getMainSection(struct Section *section) static struct Section *getMainSection(struct Section *section)
{ {
if (section->modifier != SECTION_NORMAL) if (section->modifier != SECTION_NORMAL)
section = sect_GetSection(section->name); section = sect_GetSection(*section->name);
return section; return section;
} }
@@ -453,7 +429,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
where.parent = NULL; where.parent = NULL;
where.type = NODE_FILE; where.type = NODE_FILE;
where.name = strdup(fileName); where.name = new(std::nothrow) std::string(fileName);
if (!where.name) if (!where.name)
fatal(NULL, 0, "Failed to duplicate \"%s\"'s name: %s", fileName, strerror(errno)); fatal(NULL, 0, "Failed to duplicate \"%s\"'s name: %s", fileName, strerror(errno));
@@ -599,7 +575,7 @@ static void freeNode(struct FileStackNode &node)
if (node.type == NODE_REPT) if (node.type == NODE_REPT)
delete node.iters; delete node.iters;
else else
free(node.name); delete node.name;
} }
static void freeSection(struct Section *section) static void freeSection(struct Section *section)
@@ -607,7 +583,7 @@ static void freeSection(struct Section *section)
do { do {
struct Section *next = section->nextu; struct Section *next = section->nextu;
free(section->name); delete section->name;
if (sect_HasData(section->type)) { if (sect_HasData(section->type)) {
delete section->data; delete section->data;
delete section->patches; delete section->patches;
@@ -633,9 +609,9 @@ void obj_Cleanup(void)
for (std::vector<struct Symbol> &fileSymbols : symbolLists) { for (std::vector<struct Symbol> &fileSymbols : symbolLists) {
for (struct Symbol &symbol : fileSymbols) for (struct Symbol &symbol : fileSymbols)
free(symbol.name); delete symbol.name;
} }
for (struct Assertion &assert : assertions) for (struct Assertion &assert : assertions)
free(assert.message); delete assert.message;
} }

View File

@@ -71,7 +71,7 @@ void out_AddSection(struct Section const *section)
if (minNbBanks > maxNbBanks[section->type]) if (minNbBanks > maxNbBanks[section->type])
errx("Section \"%s\" has an invalid bank range (%" PRIu32 " > %" PRIu32 ")", errx("Section \"%s\" has an invalid bank range (%" PRIu32 " > %" PRIu32 ")",
section->name, section->bank, section->name->c_str(), section->bank,
maxNbBanks[section->type] - 1); maxNbBanks[section->type] - 1);
for (uint32_t i = sections[section->type].size(); i < minNbBanks; i++) for (uint32_t i = sections[section->type].size(); i < minNbBanks; i++)
@@ -293,19 +293,19 @@ static int compareSymbols(struct SortedSymbol const &sym1, struct SortedSymbol c
if (sym1.addr != sym2.addr) if (sym1.addr != sym2.addr)
return sym1.addr < sym2.addr ? -1 : 1; return sym1.addr < sym2.addr ? -1 : 1;
char const *sym1_name = sym1.sym->name; std::string const *sym1_name = sym1.sym->name;
char const *sym2_name = sym2.sym->name; std::string const *sym2_name = sym2.sym->name;
bool sym1_local = strchr(sym1_name, '.'); bool sym1_local = sym1_name->find(".") != std::string::npos;
bool sym2_local = strchr(sym2_name, '.'); bool sym2_local = sym2_name->find(".") != std::string::npos;
if (sym1_local != sym2_local) { if (sym1_local != sym2_local) {
size_t sym1_len = strlen(sym1_name); size_t sym1_len = sym1_name->length();
size_t sym2_len = strlen(sym2_name); size_t sym2_len = sym2_name->length();
// Sort parent labels before their child local labels // Sort parent labels before their child local labels
if (!strncmp(sym1_name, sym2_name, sym1_len) && sym2_name[sym1_len] == '.') if (sym2_name->starts_with(*sym1_name) && (*sym2_name)[sym1_len] == '.')
return -1; return -1;
if (!strncmp(sym2_name, sym1_name, sym2_len) && sym1_name[sym2_len] == '.') if (sym1_name->starts_with(*sym2_name) && (*sym1_name)[sym2_len] == '.')
return 1; return 1;
// Sort local labels before unrelated global labels // Sort local labels before unrelated global labels
return sym1_local ? -1 : 1; return sym1_local ? -1 : 1;
@@ -348,7 +348,7 @@ static void writeSymBank(struct SortedSections const &bankSections,
forEachSortedSection(sect, { forEachSortedSection(sect, {
for (struct Symbol const *sym : *sect->symbols) { for (struct Symbol const *sym : *sect->symbols) {
// Don't output symbols that begin with an illegal character // Don't output symbols that begin with an illegal character
if (canStartSymName(sym->name[0])) if (!sym->name->empty() && canStartSymName((*sym->name)[0]))
symList.push_back({ .sym = sym, .addr = (uint16_t)(sym->offset + sect->org) }); symList.push_back({ .sym = sym, .addr = (uint16_t)(sym->offset + sect->org) });
} }
}); });
@@ -361,7 +361,7 @@ static void writeSymBank(struct SortedSections const &bankSections,
for (struct SortedSymbol &sym : symList) { for (struct SortedSymbol &sym : symList) {
fprintf(symFile, "%02" PRIx32 ":%04" PRIx16 " ", symBank, sym.addr); fprintf(symFile, "%02" PRIx32 ":%04" PRIx16 " ", symBank, sym.addr);
printSymName(sym.sym->name); printSymName(sym.sym->name->c_str());
putc('\n', symFile); putc('\n', symFile);
} }
} }
@@ -407,21 +407,19 @@ static void writeMapBank(struct SortedSections const &sectList, enum SectionType
if (sect->size != 0) if (sect->size != 0)
fprintf(mapFile, "\tSECTION: $%04" PRIx16 "-$%04x ($%04" PRIx16 fprintf(mapFile, "\tSECTION: $%04" PRIx16 "-$%04x ($%04" PRIx16
" byte%s) [\"%s\"]\n", " byte%s) [\"%s\"]\n",
sect->org, prevEndAddr - 1, sect->org, prevEndAddr - 1, sect->size, sect->size == 1 ? "" : "s",
sect->size, sect->size == 1 ? "" : "s", sect->name->c_str());
sect->name);
else else
fprintf(mapFile, "\tSECTION: $%04" PRIx16 " (0 bytes) [\"%s\"]\n", fprintf(mapFile, "\tSECTION: $%04" PRIx16 " (0 bytes) [\"%s\"]\n",
sect->org, sect->name); sect->org, sect->name->c_str());
if (!noSymInMap) { if (!noSymInMap) {
uint16_t org = sect->org; // Also print symbols in the following "pieces"
for (uint16_t org = sect->org; sect; sect = sect->nextu) {
while (sect) {
for (struct Symbol *sym : *sect->symbols) for (struct Symbol *sym : *sect->symbols)
// Space matches "\tSECTION: $xxxx ..." // Space matches "\tSECTION: $xxxx ..."
fprintf(mapFile, "\t $%04" PRIx32 " = %s\n", fprintf(mapFile, "\t $%04" PRIx32 " = %s\n",
sym->offset + org, sym->name); sym->offset + org, sym->name->c_str());
if (sect->nextu) { if (sect->nextu) {
// Announce the following "piece" // Announce the following "piece"
@@ -432,8 +430,6 @@ static void writeMapBank(struct SortedSections const &sectList, enum SectionType
fprintf(mapFile, fprintf(mapFile,
"\t ; Next fragment\n"); "\t ; Next fragment\n");
} }
sect = sect->nextu; // Also print symbols in the following "pieces"
} }
} }

View File

@@ -63,7 +63,7 @@ static struct Symbol const *getSymbol(std::vector<struct Symbol> const &symbolLi
// If the symbol is defined elsewhere... // If the symbol is defined elsewhere...
if (symbol.type == SYMTYPE_IMPORT) if (symbol.type == SYMTYPE_IMPORT)
return sym_GetSymbol(symbol.name); return sym_GetSymbol(*symbol.name);
return &symbol; return &symbol;
} }
@@ -224,13 +224,13 @@ static int32_t computeRPNExpr(struct Patch const *patch,
if (!symbol) { if (!symbol) {
error(patch->src, patch->lineNo, error(patch->src, patch->lineNo,
"Requested BANK() of symbol \"%s\", which was not found", "Requested BANK() of symbol \"%s\", which was not found",
fileSymbols[value].name); fileSymbols[value].name->c_str());
isError = true; isError = true;
value = 1; value = 1;
} else if (!symbol->section) { } else if (!symbol->section) {
error(patch->src, patch->lineNo, error(patch->src, patch->lineNo,
"Requested BANK() of non-label symbol \"%s\"", "Requested BANK() of non-label symbol \"%s\"",
fileSymbols[value].name); fileSymbols[value].name->c_str());
isError = true; isError = true;
value = 1; value = 1;
} else { } else {
@@ -385,7 +385,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
if (!symbol) { if (!symbol) {
error(patch->src, patch->lineNo, error(patch->src, patch->lineNo,
"Unknown symbol \"%s\"", fileSymbols[value].name); "Unknown symbol \"%s\"", fileSymbols[value].name->c_str());
isError = true; isError = true;
} else { } else {
value = symbol->value; value = symbol->value;
@@ -422,24 +422,24 @@ void patch_CheckAssertions(std::deque<struct Assertion> &assertions)
switch (type) { switch (type) {
case ASSERT_FATAL: case ASSERT_FATAL:
fatal(assert.patch.src, assert.patch.lineNo, "%s", fatal(assert.patch.src, assert.patch.lineNo, "%s",
assert.message[0] ? assert.message !assert.message->empty() ? assert.message->c_str()
: "assert failure"); : "assert failure");
case ASSERT_ERROR: case ASSERT_ERROR:
error(assert.patch.src, assert.patch.lineNo, "%s", error(assert.patch.src, assert.patch.lineNo, "%s",
assert.message[0] ? assert.message !assert.message->empty() ? assert.message->c_str()
: "assert failure"); : "assert failure");
break; break;
case ASSERT_WARN: case ASSERT_WARN:
warning(assert.patch.src, assert.patch.lineNo, "%s", warning(assert.patch.src, assert.patch.lineNo, "%s",
assert.message[0] ? assert.message !assert.message->empty() ? assert.message->c_str()
: "assert failure"); : "assert failure");
break; break;
} }
} else if (isError && type == ASSERT_FATAL) { } else if (isError && type == ASSERT_FATAL) {
fatal(assert.patch.src, assert.patch.lineNo, fatal(assert.patch.src, assert.patch.lineNo,
"Failed to evaluate assertion%s%s", "Failed to evaluate assertion%s%s",
assert.message[0] ? ": " : "", !assert.message->empty() ? ": " : "",
assert.message); assert.message->c_str());
} }
} }
} }
@@ -451,7 +451,7 @@ void patch_CheckAssertions(std::deque<struct Assertion> &assertions)
*/ */
static void applyFilePatches(struct Section *section, struct Section *dataSection) static void applyFilePatches(struct Section *section, struct Section *dataSection)
{ {
verbosePrint("Patching section \"%s\"...\n", section->name); verbosePrint("Patching section \"%s\"...\n", section->name->c_str());
for (struct Patch &patch : *section->patches) { for (struct Patch &patch : *section->patches) {
int32_t value = computeRPNExpr(&patch, *section->fileSymbols); int32_t value = computeRPNExpr(&patch, *section->fileSymbols);
uint16_t offset = patch.offset + section->offset; uint16_t offset = patch.offset + section->offset;

View File

@@ -268,7 +268,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
assert(strlen(token) != 0); // This should be impossible, tokens are non-empty assert(strlen(token) != 0); // This should be impossible, tokens are non-empty
// The following is required for fragment offsets to be reliably predicted // The following is required for fragment offsets to be reliably predicted
for (size_t i = 0; i < nbSections; ++i) { for (size_t i = 0; i < nbSections; ++i) {
if (!strcmp(token, fileSections[i].section->name)) if (!strcmp(token, fileSections[i].section->name->c_str()))
fatal(where, lineNo, "Area \"%s\" already defined earlier", fatal(where, lineNo, "Area \"%s\" already defined earlier",
token); token);
} }
@@ -282,7 +282,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
if (tmp > UINT16_MAX) if (tmp > UINT16_MAX)
fatal(where, lineNo, "Area \"%s\" is larger than the GB address space!?", fatal(where, lineNo, "Area \"%s\" is larger than the GB address space!?",
curSection->name); curSection->name->c_str());
curSection->size = tmp; curSection->size = tmp;
expectToken("flags", 'A'); expectToken("flags", 'A');
@@ -295,21 +295,16 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
curSection->isBankFixed = curSection->isAddressFixed; curSection->isBankFixed = curSection->isAddressFixed;
curSection->modifier = curSection->isAddressFixed || (tmp & (1 << AREA_TYPE)) curSection->modifier = curSection->isAddressFixed || (tmp & (1 << AREA_TYPE))
? SECTION_NORMAL : SECTION_FRAGMENT; ? SECTION_NORMAL : SECTION_FRAGMENT;
curSection->name = new(std::nothrow) std::string();
if (!curSection->name)
fatal(where, lineNo, "Failed to alloc new area's name: %s",
strerror(errno));
// If the section is absolute, its name might not be unique; thus, mangle the name // If the section is absolute, its name might not be unique; thus, mangle the name
if (curSection->modifier == SECTION_NORMAL) { if (curSection->modifier == SECTION_NORMAL) {
size_t len = strlen(where->name) + 1 + strlen(token); curSection->name->append(*where->name);
curSection->name->append(" ");
curSection->name = (char *)malloc(len + 1);
if (!curSection->name)
fatal(where, lineNo, "Failed to alloc new area's name: %s",
strerror(errno));
sprintf(curSection->name, "%s %s", where->name, sectionName);
} else {
curSection->name = strdup(sectionName); // We need a pointer that will live longer
if (!curSection->name)
fatal(where, lineNo, "Failed to alloc new area's name: %s",
strerror(errno));
} }
curSection->name->append(sectionName);
expectToken("addr", 'A'); expectToken("addr", 'A');
@@ -372,7 +367,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
struct Symbol &symbol = fileSymbols.emplace_back(); struct Symbol &symbol = fileSymbols.emplace_back();
// Init other members // Init other members
symbol.objFileName = where->name; symbol.objFileName = where->name->c_str();
symbol.src = where; symbol.src = where;
symbol.lineNo = lineNo; symbol.lineNo = lineNo;
@@ -380,7 +375,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
symbol.section = nbSections != 0 ? fileSections[nbSections - 1].section : NULL; symbol.section = nbSections != 0 ? fileSections[nbSections - 1].section : NULL;
getToken(line, "'S' line is too short"); getToken(line, "'S' line is too short");
symbol.name = strdup(token); symbol.name = new(std::nothrow) std::string(token);
if (!symbol.name) if (!symbol.name)
fatal(where, lineNo, "Failed to alloc symbol name: %s", strerror(errno)); fatal(where, lineNo, "Failed to alloc symbol name: %s", strerror(errno));
@@ -402,7 +397,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
} else { } else {
// All symbols are exported // All symbols are exported
symbol.type = SYMTYPE_EXPORT; symbol.type = SYMTYPE_EXPORT;
struct Symbol const *other = sym_GetSymbol(symbol.name); struct Symbol const *other = sym_GetSymbol(*symbol.name);
if (other) { if (other) {
// The same symbol can only be defined twice if neither // The same symbol can only be defined twice if neither
@@ -413,7 +408,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
} else if (other->value != symbol.value) { } else if (other->value != symbol.value) {
error(where, lineNo, error(where, lineNo,
"Definition of \"%s\" conflicts with definition in %s (%" PRId32 " != %" PRId32 ")", "Definition of \"%s\" conflicts with definition in %s (%" PRId32 " != %" PRId32 ")",
symbol.name, other->objFileName, symbol.value, other->value); symbol.name->c_str(), other->objFileName, symbol.value, other->value);
} }
} else { } else {
// Add a new definition // Add a new definition
@@ -485,7 +480,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
if (section->isAddressFixed) { if (section->isAddressFixed) {
if (addr < section->org) if (addr < section->org)
fatal(where, lineNo, "'T' line reports address $%04" PRIx16 " in \"%s\", which starts at $%04" PRIx16, fatal(where, lineNo, "'T' line reports address $%04" PRIx16 " in \"%s\", which starts at $%04" PRIx16,
addr, section->name, section->org); addr, section->name->c_str(), section->org);
addr -= section->org; addr -= section->org;
} }
// Lines are emitted that violate this check but contain no "payload"; // Lines are emitted that violate this check but contain no "payload";
@@ -499,7 +494,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
section->data = new(std::nothrow) std::vector<uint8_t>(section->size); section->data = new(std::nothrow) std::vector<uint8_t>(section->size);
if (!section->data) if (!section->data)
fatal(where, lineNo, "Failed to alloc data for \"%s\": %s", fatal(where, lineNo, "Failed to alloc data for \"%s\": %s",
section->name, strerror(errno)); section->name->c_str(), strerror(errno));
} }
} }
@@ -583,29 +578,30 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
// SDCC has a bunch of "magic symbols" that start with a // SDCC has a bunch of "magic symbols" that start with a
// letter and an underscore. These are not compatibility // letter and an underscore. These are not compatibility
// hacks, this is how SDLD actually works. // hacks, this is how SDLD actually works.
if (sym.name[0] == 'b' && sym.name[1] == '_') { if (sym.name->starts_with("b_")) {
// Look for the symbol being referenced, and use its index instead // Look for the symbol being referenced, and use its index instead
for (idx = 0; idx < nbSymbols; ++idx) { for (idx = 0; idx < nbSymbols; ++idx) {
if (strcmp(&sym.name[1], fileSymbols[idx].name) == 0) if (sym.name->ends_with(*fileSymbols[idx].name) &&
1 + sym.name->length() == fileSymbols[idx].name->length())
break; break;
} }
if (idx == nbSymbols) if (idx == nbSymbols)
fatal(where, lineNo, "\"%s\" is missing a reference to \"%s\"", fatal(where, lineNo, "\"%s\" is missing a reference to \"%s\"",
sym.name, &sym.name[1]); sym.name->c_str(), &sym.name->c_str()[1]);
patch.rpnExpression.resize(5); patch.rpnExpression.resize(5);
patch.rpnExpression[0] = RPN_BANK_SYM; patch.rpnExpression[0] = RPN_BANK_SYM;
patch.rpnExpression[1] = idx; patch.rpnExpression[1] = idx;
patch.rpnExpression[2] = idx >> 8; patch.rpnExpression[2] = idx >> 8;
patch.rpnExpression[3] = idx >> 16; patch.rpnExpression[3] = idx >> 16;
patch.rpnExpression[4] = idx >> 24; patch.rpnExpression[4] = idx >> 24;
} else if (sym.name[0] == 'l' && sym.name[1] == '_') { } else if (sym.name->starts_with("l_")) {
patch.rpnExpression.resize(1 + strlen(&sym.name[2]) + 1); patch.rpnExpression.resize(1 + sym.name->length() - 2 + 1);
patch.rpnExpression[0] = RPN_SIZEOF_SECT; patch.rpnExpression[0] = RPN_SIZEOF_SECT;
strcpy((char *)&patch.rpnExpression[1], &sym.name[2]); memcpy((char *)&patch.rpnExpression[1], &sym.name->c_str()[2], sym.name->length() - 2 + 1);
} else if (sym.name[0] == 's' && sym.name[1] == '_') { } else if (sym.name->starts_with("s_")) {
patch.rpnExpression.resize(1 + strlen(&sym.name[2]) + 1); patch.rpnExpression.resize(1 + sym.name->length() - 2 + 1);
patch.rpnExpression[0] = RPN_STARTOF_SECT; patch.rpnExpression[0] = RPN_STARTOF_SECT;
strcpy((char *)&patch.rpnExpression[1], &sym.name[2]); memcpy((char *)&patch.rpnExpression[1], &sym.name->c_str()[2], sym.name->length() - 2 + 1);
} else { } else {
patch.rpnExpression.resize(5); patch.rpnExpression.resize(5);
patch.rpnExpression[0] = RPN_SYM; patch.rpnExpression[0] = RPN_SYM;
@@ -627,8 +623,8 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
// the section gets moved for any reason. // the section gets moved for any reason.
if (fileSections[idx].section->isAddressFixed) if (fileSections[idx].section->isAddressFixed)
baseValue -= fileSections[idx].section->org; baseValue -= fileSections[idx].section->org;
char const *name = fileSections[idx].section->name; std::string const *name = fileSections[idx].section->name;
struct Section const *other = sect_GetSection(name); struct Section const *other = sect_GetSection(*name);
// Unlike with `s_<AREA>`, referencing an area in this way // Unlike with `s_<AREA>`, referencing an area in this way
// wants the beginning of this fragment, so we must add the // wants the beginning of this fragment, so we must add the
@@ -640,10 +636,10 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
// current size. // current size.
if (other) if (other)
baseValue += other->size; baseValue += other->size;
patch.rpnExpression.resize(1 + strlen(name) + 1); patch.rpnExpression.resize(1 + name->length() + 1);
patch.rpnExpression[0] = RPN_STARTOF_SECT; patch.rpnExpression[0] = RPN_STARTOF_SECT;
// The cast is fine, it's just different signedness // The cast is fine, it's just different signedness
strcpy((char *)&patch.rpnExpression[1], name); memcpy((char *)&patch.rpnExpression[1], name->c_str(), name->length() + 1);
} }
patch.rpnExpression.push_back(RPN_CONST); patch.rpnExpression.push_back(RPN_CONST);
@@ -659,7 +655,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
if (flags & 1 << RELOC_EXPR16) { if (flags & 1 << RELOC_EXPR16) {
if (*writeIndex + (offset - writtenOfs) > section->size) if (*writeIndex + (offset - writtenOfs) > section->size)
fatal(where, lineNo, "'T' line writes past \"%s\"'s end (%u > %" PRIu16 ")", fatal(where, lineNo, "'T' line writes past \"%s\"'s end (%u > %" PRIu16 ")",
section->name, *writeIndex + (offset - writtenOfs), section->size); section->name->c_str(), *writeIndex + (offset - writtenOfs), section->size);
// Copy all bytes up to those (plus the byte that we'll overwrite) // Copy all bytes up to those (plus the byte that we'll overwrite)
memcpy(&(*section->data)[*writeIndex], &data[writtenOfs], offset - writtenOfs + 1); memcpy(&(*section->data)[*writeIndex], &data[writtenOfs], offset - writtenOfs + 1);
*writeIndex += offset - writtenOfs + 1; *writeIndex += offset - writtenOfs + 1;
@@ -708,7 +704,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
assert(nbBytes > writtenOfs); assert(nbBytes > writtenOfs);
if (*writeIndex + (nbBytes - writtenOfs) > section->size) if (*writeIndex + (nbBytes - writtenOfs) > section->size)
fatal(where, lineNo, "'T' line writes past \"%s\"'s end (%zu > %" PRIu16 ")", fatal(where, lineNo, "'T' line writes past \"%s\"'s end (%zu > %" PRIu16 ")",
section->name, *writeIndex + (nbBytes - writtenOfs), section->size); section->name->c_str(), *writeIndex + (nbBytes - writtenOfs), section->size);
memcpy(&(*section->data)[*writeIndex], &data[writtenOfs], nbBytes - writtenOfs); memcpy(&(*section->data)[*writeIndex], &data[writtenOfs], nbBytes - writtenOfs);
*writeIndex += nbBytes - writtenOfs; *writeIndex += nbBytes - writtenOfs;
} }
@@ -739,7 +735,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
// RAM sections can have a size, but don't get any data (they shouldn't have any) // RAM sections can have a size, but don't get any data (they shouldn't have any)
if (fileSections[i].writeIndex != section->size && fileSections[i].writeIndex != 0) if (fileSections[i].writeIndex != section->size && fileSections[i].writeIndex != 0)
fatal(where, lineNo, "\"%s\" was not fully written (%" PRIu16 " < %" PRIu16 ")", fatal(where, lineNo, "\"%s\" was not fully written (%" PRIu16 " < %" PRIu16 ")",
section->name, fileSections[i].writeIndex, section->size); section->name->c_str(), fileSections[i].writeIndex, section->size);
// This must be done last, so that `->data` is not NULL anymore // This must be done last, so that `->data` is not NULL anymore
sect_AddSection(section); sect_AddSection(section);

View File

@@ -27,14 +27,13 @@ static void checkSectUnionCompat(struct Section *target, struct Section *other)
if (target->isAddressFixed) { if (target->isAddressFixed) {
if (target->org != other->org) if (target->org != other->org)
errx("Section \"%s\" is defined with conflicting addresses $%04" errx("Section \"%s\" is defined with conflicting addresses $%04"
PRIx16 " and $%04" PRIx16, PRIx16 " and $%04" PRIx16, other->name->c_str(), target->org,
other->name, target->org, other->org); other->org);
} else if (target->isAlignFixed) { } else if (target->isAlignFixed) {
if ((other->org - target->alignOfs) & target->alignMask) if ((other->org - target->alignOfs) & target->alignMask)
errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %" errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %"
PRIu16 ") and address $%04" PRIx16, PRIu16 ") and address $%04" PRIx16, other->name->c_str(),
other->name, target->alignMask + 1, target->alignMask + 1, target->alignOfs, other->org);
target->alignOfs, other->org);
} }
target->isAddressFixed = true; target->isAddressFixed = true;
target->org = other->org; target->org = other->org;
@@ -44,14 +43,14 @@ static void checkSectUnionCompat(struct Section *target, struct Section *other)
if ((target->org - other->alignOfs) & other->alignMask) if ((target->org - other->alignOfs) & other->alignMask)
errx("Section \"%s\" is defined with conflicting address $%04" errx("Section \"%s\" is defined with conflicting address $%04"
PRIx16 " and %d-byte alignment (offset %" PRIu16 ")", PRIx16 " and %d-byte alignment (offset %" PRIu16 ")",
other->name, target->org, other->name->c_str(), target->org, other->alignMask + 1,
other->alignMask + 1, other->alignOfs); other->alignOfs);
} else if (target->isAlignFixed } else if (target->isAlignFixed
&& (other->alignMask & target->alignOfs) && (other->alignMask & target->alignOfs)
!= (target->alignMask & other->alignOfs)) { != (target->alignMask & other->alignOfs)) {
errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %" errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %"
PRIu16 ") and %d-byte alignment (offset %" PRIu16 ")", PRIu16 ") and %d-byte alignment (offset %" PRIu16 ")",
other->name, target->alignMask + 1, target->alignOfs, other->name->c_str(), target->alignMask + 1, target->alignOfs,
other->alignMask + 1, other->alignOfs); other->alignMask + 1, other->alignOfs);
} else if (!target->isAlignFixed || (other->alignMask > target->alignMask)) { } else if (!target->isAlignFixed || (other->alignMask > target->alignMask)) {
target->isAlignFixed = true; target->isAlignFixed = true;
@@ -68,15 +67,14 @@ static void checkFragmentCompat(struct Section *target, struct Section *other)
if (target->isAddressFixed) { if (target->isAddressFixed) {
if (target->org != org) if (target->org != org)
errx("Section \"%s\" is defined with conflicting addresses $%04" errx("Section \"%s\" is defined with conflicting addresses $%04"
PRIx16 " and $%04" PRIx16, PRIx16 " and $%04" PRIx16, other->name->c_str(), target->org,
other->name, target->org, other->org); other->org);
} else if (target->isAlignFixed) { } else if (target->isAlignFixed) {
if ((org - target->alignOfs) & target->alignMask) if ((org - target->alignOfs) & target->alignMask)
errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %" errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %"
PRIu16 ") and address $%04" PRIx16, PRIu16 ") and address $%04" PRIx16, other->name->c_str(),
other->name, target->alignMask + 1, target->alignMask + 1, target->alignOfs, other->org);
target->alignOfs, other->org);
} }
target->isAddressFixed = true; target->isAddressFixed = true;
target->org = org; target->org = org;
@@ -91,14 +89,14 @@ static void checkFragmentCompat(struct Section *target, struct Section *other)
if ((target->org - ofs) & other->alignMask) if ((target->org - ofs) & other->alignMask)
errx("Section \"%s\" is defined with conflicting address $%04" errx("Section \"%s\" is defined with conflicting address $%04"
PRIx16 " and %d-byte alignment (offset %" PRIu16 ")", PRIx16 " and %d-byte alignment (offset %" PRIu16 ")",
other->name, target->org, other->name->c_str(), target->org, other->alignMask + 1,
other->alignMask + 1, other->alignOfs); other->alignOfs);
} else if (target->isAlignFixed } else if (target->isAlignFixed
&& (other->alignMask & target->alignOfs) != (target->alignMask & ofs)) { && (other->alignMask & target->alignOfs) != (target->alignMask & ofs)) {
errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %" errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %"
PRIu16 ") and %d-byte alignment (offset %" PRIu16 ")", PRIu16 ") and %d-byte alignment (offset %" PRIu16 ")",
other->name, target->alignMask + 1, target->alignOfs, other->name->c_str(), target->alignMask + 1, target->alignOfs,
other->alignMask + 1, other->alignOfs); other->alignMask + 1, other->alignOfs);
} else if (!target->isAlignFixed || (other->alignMask > target->alignMask)) { } else if (!target->isAlignFixed || (other->alignMask > target->alignMask)) {
@@ -115,7 +113,7 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se
if (target->type != other->type) if (target->type != other->type)
errx("Section \"%s\" is defined with conflicting types %s and %s", errx("Section \"%s\" is defined with conflicting types %s and %s",
other->name, sectionTypeInfo[target->type].name.c_str(), other->name->c_str(), sectionTypeInfo[target->type].name.c_str(),
sectionTypeInfo[other->type].name.c_str()); sectionTypeInfo[other->type].name.c_str());
if (other->isBankFixed) { if (other->isBankFixed) {
@@ -124,7 +122,7 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se
target->bank = other->bank; target->bank = other->bank;
} else if (target->bank != other->bank) { } else if (target->bank != other->bank) {
errx("Section \"%s\" is defined with conflicting banks %" PRIu32 " and %" errx("Section \"%s\" is defined with conflicting banks %" PRIu32 " and %"
PRIu32, other->name, target->bank, other->bank); PRIu32, other->name->c_str(), target->bank, other->bank);
} }
} }
@@ -173,24 +171,24 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se
void sect_AddSection(struct Section *section) void sect_AddSection(struct Section *section)
{ {
// Check if the section already exists // Check if the section already exists
if (struct Section *other = sect_GetSection(section->name); other) { if (struct Section *other = sect_GetSection(*section->name); other) {
if (section->modifier != other->modifier) if (section->modifier != other->modifier)
errx("Section \"%s\" defined as %s and %s", section->name, errx("Section \"%s\" defined as %s and %s", section->name->c_str(),
sectionModNames[section->modifier], sectionModNames[other->modifier]); sectionModNames[section->modifier], sectionModNames[other->modifier]);
else if (section->modifier == SECTION_NORMAL) else if (section->modifier == SECTION_NORMAL)
errx("Section name \"%s\" is already in use", section->name); errx("Section name \"%s\" is already in use", section->name->c_str());
else else
mergeSections(other, section, section->modifier); mergeSections(other, section, section->modifier);
} else if (section->modifier == SECTION_UNION && sect_HasData(section->type)) { } else if (section->modifier == SECTION_UNION && sect_HasData(section->type)) {
errx("Section \"%s\" is of type %s, which cannot be unionized", errx("Section \"%s\" is of type %s, which cannot be unionized",
section->name, sectionTypeInfo[section->type].name.c_str()); section->name->c_str(), sectionTypeInfo[section->type].name.c_str());
} else { } else {
// If not, add it // If not, add it
sections[section->name] = section; sections[*section->name] = section;
} }
} }
struct Section *sect_GetSection(char const *name) struct Section *sect_GetSection(std::string const &name)
{ {
auto search = sections.find(name); auto search = sections.find(name);
return search != sections.end() ? search->second : NULL; return search != sections.end() ? search->second : NULL;
@@ -205,27 +203,27 @@ static void doSanityChecks(struct Section *section)
{ {
// Sanity check the section's type // Sanity check the section's type
if (section->type < 0 || section->type >= SECTTYPE_INVALID) { if (section->type < 0 || section->type >= SECTTYPE_INVALID) {
error(NULL, 0, "Section \"%s\" has an invalid type", section->name); error(NULL, 0, "Section \"%s\" has an invalid type", section->name->c_str());
return; return;
} }
if (is32kMode && section->type == SECTTYPE_ROMX) { if (is32kMode && section->type == SECTTYPE_ROMX) {
if (section->isBankFixed && section->bank != 1) if (section->isBankFixed && section->bank != 1)
error(NULL, 0, "%s: ROMX sections must be in bank 1 (if any) with option -t", error(NULL, 0, "%s: ROMX sections must be in bank 1 (if any) with option -t",
section->name); section->name->c_str());
else else
section->type = SECTTYPE_ROM0; section->type = SECTTYPE_ROM0;
} }
if (isWRA0Mode && section->type == SECTTYPE_WRAMX) { if (isWRA0Mode && section->type == SECTTYPE_WRAMX) {
if (section->isBankFixed && section->bank != 1) if (section->isBankFixed && section->bank != 1)
error(NULL, 0, "%s: WRAMX sections must be in bank 1 with options -w or -d", error(NULL, 0, "%s: WRAMX sections must be in bank 1 with options -w or -d",
section->name); section->name->c_str());
else else
section->type = SECTTYPE_WRAM0; section->type = SECTTYPE_WRAM0;
} }
if (isDmgMode && section->type == SECTTYPE_VRAM && section->bank == 1) if (isDmgMode && section->type == SECTTYPE_VRAM && section->bank == 1)
error(NULL, 0, "%s: VRAM bank 1 can't be used with option -d", error(NULL, 0, "%s: VRAM bank 1 can't be used with option -d",
section->name); section->name->c_str());
// Check if alignment is reasonable, this is important to avoid UB // Check if alignment is reasonable, this is important to avoid UB
// An alignment of zero is equivalent to no alignment, basically // An alignment of zero is equivalent to no alignment, basically
@@ -235,7 +233,8 @@ static void doSanityChecks(struct Section *section)
// Too large an alignment may not be satisfiable // Too large an alignment may not be satisfiable
if (section->isAlignFixed && (section->alignMask & sectionTypeInfo[section->type].startAddr)) if (section->isAlignFixed && (section->alignMask & sectionTypeInfo[section->type].startAddr))
error(NULL, 0, "%s: %s sections cannot be aligned to $%04x bytes", error(NULL, 0, "%s: %s sections cannot be aligned to $%04x bytes",
section->name, sectionTypeInfo[section->type].name.c_str(), section->alignMask + 1); section->name->c_str(), sectionTypeInfo[section->type].name.c_str(),
section->alignMask + 1);
uint32_t minbank = sectionTypeInfo[section->type].firstBank, maxbank = sectionTypeInfo[section->type].lastBank; uint32_t minbank = sectionTypeInfo[section->type].firstBank, maxbank = sectionTypeInfo[section->type].lastBank;
@@ -243,13 +242,13 @@ static void doSanityChecks(struct Section *section)
error(NULL, 0, minbank == maxbank error(NULL, 0, minbank == maxbank
? "Cannot place section \"%s\" in bank %" PRIu32 ", it must be %" PRIu32 ? "Cannot place section \"%s\" in bank %" PRIu32 ", it must be %" PRIu32
: "Cannot place section \"%s\" in bank %" PRIu32 ", it must be between %" PRIu32 " and %" PRIu32, : "Cannot place section \"%s\" in bank %" PRIu32 ", it must be between %" PRIu32 " and %" PRIu32,
section->name, section->bank, minbank, maxbank); section->name->c_str(), section->bank, minbank, maxbank);
// Check if section has a chance to be placed // Check if section has a chance to be placed
if (section->size > sectionTypeInfo[section->type].size) if (section->size > sectionTypeInfo[section->type].size)
error(NULL, 0, "Section \"%s\" is bigger than the max size for that type: $%" error(NULL, 0, "Section \"%s\" is bigger than the max size for that type: $%"
PRIx16 " > $%" PRIx16, PRIx16 " > $%" PRIx16,
section->name, section->size, sectionTypeInfo[section->type].size); section->name->c_str(), section->size, sectionTypeInfo[section->type].size);
// Translate loose constraints to strong ones when they're equivalent // Translate loose constraints to strong ones when they're equivalent
@@ -263,7 +262,7 @@ static void doSanityChecks(struct Section *section)
if (section->isAlignFixed) { if (section->isAlignFixed) {
if ((section->org & section->alignMask) != section->alignOfs) if ((section->org & section->alignMask) != section->alignOfs)
error(NULL, 0, "Section \"%s\"'s fixed address doesn't match its alignment", error(NULL, 0, "Section \"%s\"'s fixed address doesn't match its alignment",
section->name); section->name->c_str());
section->isAlignFixed = false; section->isAlignFixed = false;
} }
@@ -271,12 +270,12 @@ static void doSanityChecks(struct Section *section)
if (section->org < sectionTypeInfo[section->type].startAddr if (section->org < sectionTypeInfo[section->type].startAddr
|| section->org > endaddr(section->type)) || section->org > endaddr(section->type))
error(NULL, 0, "Section \"%s\"'s fixed address $%04" PRIx16 " is outside of range [$%04" error(NULL, 0, "Section \"%s\"'s fixed address $%04" PRIx16 " is outside of range [$%04"
PRIx16 "; $%04" PRIx16 "]", section->name, section->org, PRIx16 "; $%04" PRIx16 "]", section->name->c_str(), section->org,
sectionTypeInfo[section->type].startAddr, endaddr(section->type)); sectionTypeInfo[section->type].startAddr, endaddr(section->type));
if (section->org + section->size > endaddr(section->type) + 1) if (section->org + section->size > endaddr(section->type) + 1)
error(NULL, 0, "Section \"%s\"'s end address $%04x is greater than last address $%04x", error(NULL, 0, "Section \"%s\"'s end address $%04x is greater than last address $%04x",
section->name, section->org + section->size, section->name->c_str(), section->org + section->size,
endaddr(section->type) + 1); endaddr(section->type) + 1);
} }
} }

View File

@@ -16,8 +16,9 @@ std::map<std::string, struct Symbol *> symbols;
void sym_AddSymbol(struct Symbol *symbol) void sym_AddSymbol(struct Symbol *symbol)
{ {
// Check if the symbol already exists // Check if the symbol already exists
if (struct Symbol *other = sym_GetSymbol(symbol->name); other) { if (struct Symbol *other = sym_GetSymbol(*symbol->name); other) {
fprintf(stderr, "error: \"%s\" both in %s from ", symbol->name, symbol->objFileName); fprintf(stderr, "error: \"%s\" both in %s from ", symbol->name->c_str(),
symbol->objFileName);
dumpFileStack(symbol->src); dumpFileStack(symbol->src);
fprintf(stderr, "(%" PRIu32 ") and in %s from ", fprintf(stderr, "(%" PRIu32 ") and in %s from ",
symbol->lineNo, other->objFileName); symbol->lineNo, other->objFileName);
@@ -27,10 +28,10 @@ void sym_AddSymbol(struct Symbol *symbol)
} }
// If not, add it // If not, add it
symbols[symbol->name] = symbol; symbols[*symbol->name] = symbol;
} }
struct Symbol *sym_GetSymbol(char const *name) struct Symbol *sym_GetSymbol(std::string const &name)
{ {
auto search = symbols.find(name); auto search = symbols.find(name);
return search != symbols.end() ? search->second : NULL; return search != symbols.end() ? search->second : NULL;