mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Use std::variant for symbol values (#1330)
This commit is contained in:
@@ -8,12 +8,20 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
|
||||||
struct FileStackNode;
|
struct FileStackNode;
|
||||||
struct Section;
|
struct Section;
|
||||||
|
|
||||||
|
struct Label {
|
||||||
|
int32_t sectionID;
|
||||||
|
int32_t offset;
|
||||||
|
// Extra info computed during linking
|
||||||
|
Section *section;
|
||||||
|
};
|
||||||
|
|
||||||
struct Symbol {
|
struct Symbol {
|
||||||
// Info contained in the object files
|
// Info contained in the object files
|
||||||
std::string name;
|
std::string name;
|
||||||
@@ -21,14 +29,10 @@ struct Symbol {
|
|||||||
char const *objFileName;
|
char const *objFileName;
|
||||||
FileStackNode const *src;
|
FileStackNode const *src;
|
||||||
int32_t lineNo;
|
int32_t lineNo;
|
||||||
int32_t sectionID;
|
std::variant<
|
||||||
union {
|
int32_t, // Constants just have a numeric value
|
||||||
// Both types must be identical
|
Label // Label values refer to an offset within a specific section
|
||||||
int32_t offset;
|
> data;
|
||||||
int32_t value;
|
|
||||||
};
|
|
||||||
// Extra info computed during linking
|
|
||||||
Section *section;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void sym_AddSymbol(Symbol &symbol);
|
void sym_AddSymbol(Symbol &symbol);
|
||||||
|
|||||||
@@ -178,18 +178,28 @@ static void readSymbol(FILE *file, Symbol &symbol, char const *fileName,
|
|||||||
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, "%s: Cannot read \"%s\"'s node ID: %s",
|
tryReadlong(nodeID, file, "%s: Cannot read \"%s\"'s node ID: %s",
|
||||||
fileName, symbol.name.c_str());
|
fileName, symbol.name.c_str());
|
||||||
symbol.src = &fileNodes[nodeID];
|
symbol.src = &fileNodes[nodeID];
|
||||||
tryReadlong(symbol.lineNo, file, "%s: Cannot read \"%s\"'s line number: %s",
|
tryReadlong(symbol.lineNo, file, "%s: Cannot read \"%s\"'s line number: %s",
|
||||||
fileName, symbol.name.c_str());
|
fileName, symbol.name.c_str());
|
||||||
tryReadlong(symbol.sectionID, file, "%s: Cannot read \"%s\"'s section ID: %s",
|
int32_t sectionID, value;
|
||||||
|
tryReadlong(sectionID, file, "%s: Cannot read \"%s\"'s section ID: %s",
|
||||||
fileName, symbol.name.c_str());
|
fileName, symbol.name.c_str());
|
||||||
tryReadlong(symbol.offset, file, "%s: Cannot read \"%s\"'s value: %s",
|
tryReadlong(value, file, "%s: Cannot read \"%s\"'s value: %s",
|
||||||
fileName, symbol.name.c_str());
|
fileName, symbol.name.c_str());
|
||||||
|
if (sectionID == -1) {
|
||||||
|
symbol.data = value;
|
||||||
} else {
|
} else {
|
||||||
symbol.sectionID = -1;
|
symbol.data = Label{
|
||||||
|
.sectionID = sectionID,
|
||||||
|
.offset = value,
|
||||||
|
// Set the `.section` later based on the `.sectionID`
|
||||||
|
.section = nullptr,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
symbol.data = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,11 +340,13 @@ static void readSection(FILE *file, Section §ion, char const *fileName,
|
|||||||
static void linkSymToSect(Symbol &symbol, Section §ion)
|
static void linkSymToSect(Symbol &symbol, Section §ion)
|
||||||
{
|
{
|
||||||
uint32_t a = 0, b = section.symbols.size();
|
uint32_t a = 0, b = section.symbols.size();
|
||||||
|
int32_t symbolOffset = std::get<Label>(symbol.data).offset;
|
||||||
|
|
||||||
while (a != b) {
|
while (a != b) {
|
||||||
uint32_t c = (a + b) / 2;
|
uint32_t c = (a + b) / 2;
|
||||||
|
int32_t otherOffset = std::get<Label>(section.symbols[c]->data).offset;
|
||||||
|
|
||||||
if (section.symbols[c]->offset > symbol.offset)
|
if (otherOffset > symbolOffset)
|
||||||
b = c;
|
b = c;
|
||||||
else
|
else
|
||||||
a = c + 1;
|
a = c + 1;
|
||||||
@@ -452,8 +464,8 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
|
|
||||||
if (symbol.type == SYMTYPE_EXPORT)
|
if (symbol.type == SYMTYPE_EXPORT)
|
||||||
sym_AddSymbol(symbol);
|
sym_AddSymbol(symbol);
|
||||||
if (symbol.sectionID != -1)
|
if (Label *label = std::get_if<Label>(&symbol.data); label)
|
||||||
nbSymPerSect[symbol.sectionID]++;
|
nbSymPerSect[label->sectionID]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This file's sections, stored in a table to link symbols to them
|
// This file's sections, stored in a table to link symbols to them
|
||||||
@@ -484,12 +496,8 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
|
|
||||||
// Give symbols' section pointers to their sections
|
// Give symbols' section pointers to their sections
|
||||||
for (uint32_t i = 0; i < nbSymbols; i++) {
|
for (uint32_t i = 0; i < nbSymbols; i++) {
|
||||||
int32_t sectionID = fileSymbols[i].sectionID;
|
if (Label *label = std::get_if<Label>(&fileSymbols[i].data); label) {
|
||||||
|
Section *section = fileSections[label->sectionID];
|
||||||
if (sectionID == -1) {
|
|
||||||
fileSymbols[i].section = nullptr;
|
|
||||||
} else {
|
|
||||||
Section *section = fileSections[sectionID];
|
|
||||||
|
|
||||||
// Give the section a pointer to the symbol as well
|
// Give the section a pointer to the symbol as well
|
||||||
linkSymToSect(fileSymbols[i], *section);
|
linkSymToSect(fileSymbols[i], *section);
|
||||||
@@ -497,10 +505,10 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
if (section->modifier != SECTION_NORMAL) {
|
if (section->modifier != SECTION_NORMAL) {
|
||||||
if (section->modifier == SECTION_FRAGMENT)
|
if (section->modifier == SECTION_FRAGMENT)
|
||||||
// Add the fragment's offset to the symbol's
|
// Add the fragment's offset to the symbol's
|
||||||
fileSymbols[i].offset += section->offset;
|
label->offset += section->offset;
|
||||||
section = getMainSection(*section);
|
section = getMainSection(*section);
|
||||||
}
|
}
|
||||||
fileSymbols[i].section = section;
|
label->section = section;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -345,7 +345,10 @@ static void writeSymBank(SortedSections const &bankSections, enum SectionType ty
|
|||||||
for (Symbol const *sym : sect->symbols) {
|
for (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 (!sym->name.empty() && 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)(std::get<Label>(sym->data).offset + sect->org)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -414,7 +417,8 @@ static void writeMapBank(SortedSections const §List, enum SectionType type,
|
|||||||
for (Symbol *sym : sect->symbols)
|
for (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.c_str());
|
std::get<Label>(sym->data).offset + org,
|
||||||
|
sym->name.c_str());
|
||||||
|
|
||||||
if (sect->nextu) {
|
if (sect->nextu) {
|
||||||
// Announce the following "piece"
|
// Announce the following "piece"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#include "link/object.hpp"
|
#include "link/object.hpp"
|
||||||
#include "link/patch.hpp"
|
#include "link/patch.hpp"
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
#include "link/symbol.hpp"
|
#include "link/symbol.hpp"
|
||||||
|
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
|
#include "helpers.hpp"
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
#include "opmath.hpp"
|
#include "opmath.hpp"
|
||||||
#include "platform.hpp"
|
#include "platform.hpp"
|
||||||
@@ -226,14 +228,14 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
|||||||
fileSymbols[value].name.c_str());
|
fileSymbols[value].name.c_str());
|
||||||
isError = true;
|
isError = true;
|
||||||
value = 1;
|
value = 1;
|
||||||
} else if (!symbol->section) {
|
} else if (!std::holds_alternative<Label>(symbol->data)) {
|
||||||
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.c_str());
|
fileSymbols[value].name.c_str());
|
||||||
isError = true;
|
isError = true;
|
||||||
value = 1;
|
value = 1;
|
||||||
} else {
|
} else {
|
||||||
value = symbol->section->bank;
|
value = std::get<Label>(symbol->data).section->bank;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -386,10 +388,12 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
|||||||
"Unknown symbol \"%s\"", fileSymbols[value].name.c_str());
|
"Unknown symbol \"%s\"", fileSymbols[value].name.c_str());
|
||||||
isError = true;
|
isError = true;
|
||||||
} else {
|
} else {
|
||||||
value = symbol->value;
|
value = std::visit(Visitor{
|
||||||
// Symbols attached to sections have offsets
|
[](int32_t val) -> int32_t { return val; },
|
||||||
if (symbol->section)
|
[](Label label) -> int32_t {
|
||||||
value += symbol->section->org;
|
return label.section->org + label.offset;
|
||||||
|
}
|
||||||
|
}, symbol->data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -8,9 +8,12 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <tuple>
|
||||||
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
#include "helpers.hpp"
|
||||||
#include "platform.hpp"
|
#include "platform.hpp"
|
||||||
|
|
||||||
#include "link/assign.hpp"
|
#include "link/assign.hpp"
|
||||||
@@ -334,19 +337,29 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
|||||||
symbol.src = &where;
|
symbol.src = &where;
|
||||||
symbol.lineNo = lineNo;
|
symbol.lineNo = lineNo;
|
||||||
|
|
||||||
// No need to set the `sectionID`, since we can directly set the pointer
|
|
||||||
symbol.section = !fileSections.empty() ? fileSections.back().section : nullptr;
|
|
||||||
|
|
||||||
getToken(line.data(), "'S' line is too short");
|
getToken(line.data(), "'S' line is too short");
|
||||||
symbol.name = token;
|
symbol.name = token;
|
||||||
|
|
||||||
getToken(nullptr, "'S' line is too short");
|
getToken(nullptr, "'S' line is too short");
|
||||||
// It might be an `offset`, but both types are the same so type punning is fine
|
|
||||||
symbol.value = parseNumber(where, lineNo, &token[3], numberType);
|
if (int32_t value = parseNumber(where, lineNo, &token[3], numberType);
|
||||||
if (symbol.section && symbol.section->isAddressFixed) {
|
fileSections.empty()) {
|
||||||
assert(symbol.offset >= symbol.section->org);
|
// Symbols in sections are labels; their value is an offset
|
||||||
symbol.offset -= symbol.section->org;
|
Section *section = fileSections.back().section;
|
||||||
assert(symbol.offset <= symbol.section->size);
|
if (section->isAddressFixed) {
|
||||||
|
assert(value >= section->org &&
|
||||||
|
value <= section->org + section->size);
|
||||||
|
value -= section->org;
|
||||||
|
}
|
||||||
|
symbol.data = Label{
|
||||||
|
// No need to set the `sectionID`, since we set the pointer
|
||||||
|
.sectionID = 0,
|
||||||
|
.offset = value,
|
||||||
|
.section = section
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Symbols without sections are just constants
|
||||||
|
symbol.data = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expected format: /[DR]ef[0-9A-F]+/i
|
// Expected format: /[DR]ef[0-9A-F]+/i
|
||||||
@@ -363,13 +376,24 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
|||||||
if (other) {
|
if (other) {
|
||||||
// The same symbol can only be defined twice if neither
|
// The same symbol can only be defined twice if neither
|
||||||
// definition is in a floating section
|
// definition is in a floating section
|
||||||
if ((other->section && !other->section->isAddressFixed)
|
auto visitor = Visitor{
|
||||||
|| (symbol.section && !symbol.section->isAddressFixed)) {
|
[](int32_t value) -> std::tuple<Section *, int32_t> {
|
||||||
|
return {nullptr, value};
|
||||||
|
},
|
||||||
|
[](Label label) -> std::tuple<Section *, int32_t> {
|
||||||
|
return {label.section, label.offset};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto [symbolSection, symbolValue] = std::visit(visitor, symbol.data);
|
||||||
|
auto [otherSection, otherValue] = std::visit(visitor, other->data);
|
||||||
|
|
||||||
|
if ((otherSection && !otherSection->isAddressFixed)
|
||||||
|
|| (symbolSection && !symbolSection->isAddressFixed)) {
|
||||||
sym_AddSymbol(symbol); // This will error out
|
sym_AddSymbol(symbol); // This will error out
|
||||||
} else if (other->value != symbol.value) {
|
} else if (otherValue != symbolValue) {
|
||||||
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.c_str(), other->objFileName, symbol.value, other->value);
|
symbol.name.c_str(), other->objFileName, symbolValue, otherValue);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Add a new definition
|
// Add a new definition
|
||||||
@@ -691,7 +715,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
|||||||
if (section->modifier == SECTION_FRAGMENT) {
|
if (section->modifier == SECTION_FRAGMENT) {
|
||||||
// Add the fragment's offset to all of its symbols
|
// Add the fragment's offset to all of its symbols
|
||||||
for (Symbol *symbol : section->symbols)
|
for (Symbol *symbol : section->symbols)
|
||||||
symbol->offset += section->offset;
|
std::get<Label>(symbol->data).offset += section->offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,15 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#include "link/object.hpp"
|
#include "link/object.hpp"
|
||||||
|
#include "link/section.hpp"
|
||||||
#include "link/symbol.hpp"
|
#include "link/symbol.hpp"
|
||||||
#include "link/main.hpp"
|
#include "link/main.hpp"
|
||||||
|
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
|
#include "helpers.hpp"
|
||||||
|
|
||||||
std::map<std::string, Symbol *> symbols;
|
std::map<std::string, Symbol *> symbols;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user