Use std::variant for symbol values (#1330)

This commit is contained in:
Sylvie
2024-03-03 21:16:36 -05:00
committed by GitHub
parent f8dab23e8f
commit 447c561aaa
6 changed files with 92 additions and 45 deletions

View File

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

View File

@@ -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 &section, char const *fileName,
static void linkSymToSect(Symbol &symbol, Section &section) static void linkSymToSect(Symbol &symbol, Section &section)
{ {
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;
} }
} }

View File

@@ -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 &sectList, 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"

View File

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

View File

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

View File

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