diff --git a/include/asm/section.hpp b/include/asm/section.hpp index 9f3b61d5..28ea1dad 100644 --- a/include/asm/section.hpp +++ b/include/asm/section.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -40,6 +41,7 @@ struct Section { std::deque patches; std::vector data; + uint32_t getID() const; // ID of the section in the object file (`UINT32_MAX` if none) bool isSizeKnown() const; }; @@ -49,8 +51,8 @@ struct SectionSpec { uint16_t alignOfs; }; -extern std::deque
sectionList; -extern Section *currentSection; +size_t sect_CountSections(); +void sect_ForEach(void (*callback)(Section &)); Section *sect_FindSectionByName(std::string const &name); void sect_NewSection( @@ -73,6 +75,10 @@ void sect_CheckLoadClosed(); Section *sect_GetSymbolSection(); uint32_t sect_GetSymbolOffset(); uint32_t sect_GetOutputOffset(); +std::optional sect_GetOutputBank(); + +Patch *sect_AddOutputPatch(); + uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset); void sect_AlignPC(uint8_t alignment, uint16_t offset); diff --git a/src/asm/output.cpp b/src/asm/output.cpp index caf54c52..a993bc3d 100644 --- a/src/asm/output.cpp +++ b/src/asm/output.cpp @@ -60,29 +60,13 @@ void out_RegisterNode(std::shared_ptr node) { } } -// Return a section's ID, or UINT32_MAX if the section does not exist -static uint32_t getSectIDIfAny(Section *sect) { - if (!sect) { - return UINT32_MAX; - } - - // Section fragments share the same name but have different IDs, so search by identity - if (auto search = - std::find_if(RANGE(sectionList), [§](Section const &s) { return &s == sect; }); - search != sectionList.end()) { - return static_cast(std::distance(sectionList.begin(), search)); - } - - fatal("Unknown section '%s'", sect->name.c_str()); // LCOV_EXCL_LINE -} - static void writePatch(Patch const &patch, FILE *file) { assume(patch.src->ID != UINT32_MAX); putLong(patch.src->ID, file); putLong(patch.lineNo, file); putLong(patch.offset, file); - putLong(getSectIDIfAny(patch.pcSection), file); + putLong(patch.pcSection ? patch.pcSection->getID() : UINT32_MAX, file); putLong(patch.pcOffset, file); putc(patch.type, file); putLong(patch.rpn.size(), file); @@ -126,10 +110,12 @@ static void writeSymbol(Symbol const &sym, FILE *file) { } else { assume(sym.src->ID != UINT32_MAX); + Section *symSection = sym.getSection(); + putc(sym.isExported ? SYMTYPE_EXPORT : SYMTYPE_LOCAL, file); putLong(sym.src->ID, file); putLong(sym.fileLine, file); - putLong(getSectIDIfAny(sym.getSection()), file); + putLong(symSection ? symSection->getID() : UINT32_MAX, file); putLong(sym.getOutputValue(), file); } } @@ -259,7 +245,8 @@ static void initPatch(Patch &patch, uint32_t type, Expression const &expr, uint3 void out_CreatePatch(uint32_t type, Expression const &expr, uint32_t ofs, uint32_t pcShift) { // Add the patch to the list - Patch &patch = currentSection->patches.emplace_front(); + assume(sect_GetOutputBank().has_value()); + Patch &patch = *sect_AddOutputPatch(); initPatch(patch, type, expr, ofs); @@ -305,7 +292,7 @@ void out_WriteObject() { return; } - FILE *file; + static FILE *file; // `static` so `sect_ForEach` callback can see it if (options.objectFileName != "-") { file = fopen(options.objectFileName.c_str(), "wb"); } else { @@ -329,7 +316,7 @@ void out_WriteObject() { putLong(RGBDS_OBJECT_REV, file); putLong(objectSymbols.size(), file); - putLong(sectionList.size(), file); + putLong(sect_CountSections(), file); putLong(fileStackNodes.size(), file); for (auto it = fileStackNodes.begin(); it != fileStackNodes.end(); ++it) { @@ -345,9 +332,7 @@ void out_WriteObject() { writeSymbol(*sym, file); } - for (Section const § : sectionList) { - writeSection(sect, file); - } + sect_ForEach([](Section §) { writeSection(sect, file); }); putLong(assertions.size(), file); diff --git a/src/asm/rpn.cpp b/src/asm/rpn.cpp index f5670faa..74a0f782 100644 --- a/src/asm/rpn.cpp +++ b/src/asm/rpn.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -102,15 +103,15 @@ void Expression::makeBankSymbol(std::string const &symName) { clear(); if (Symbol const *sym = sym_FindScopedSymbol(symName); sym_IsPC(sym)) { // The @ symbol is treated differently. - if (!currentSection) { + if (std::optional outputBank = sect_GetOutputBank(); !outputBank) { error("PC has no bank outside of a section"); data = 1; - } else if (currentSection->bank == UINT32_MAX) { + } else if (*outputBank == UINT32_MAX) { data = "Current section's bank is not known"; *reserveSpace(1) = RPN_BANK_SELF; } else { - data = static_cast(currentSection->bank); + data = static_cast(*outputBank); } return; } else if (sym && !sym->isLabel()) { diff --git a/src/asm/section.cpp b/src/asm/section.cpp index 841f5f8d..ec0dd78a 100644 --- a/src/asm/section.cpp +++ b/src/asm/section.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -38,8 +37,8 @@ struct SectionStackEntry { std::stack unionStack; }; -Section *currentSection = nullptr; -std::deque
sectionList; +static Section *currentSection = nullptr; +static std::deque
sectionList; static std::unordered_map sectionMap; // Indexes into `sectionList` static uint32_t curOffset; // Offset into the current section (see `sect_GetSymbolOffset`) @@ -78,6 +77,16 @@ static bool requireCodeSection() { return false; } +size_t sect_CountSections() { + return sectionList.size(); +} + +void sect_ForEach(void (*callback)(Section &)) { + for (Section § : sectionList) { + callback(sect); + } +} + void sect_CheckSizes() { for (Section const § : sectionList) { if (uint32_t maxSize = sectionTypeInfo[sect.type].size; sect.size > maxSize) { @@ -440,6 +449,16 @@ static void changeSection() { sym_ResetCurrentLabelScopes(); } +uint32_t Section::getID() const { + // Section fragments share the same name but have different IDs, so search by identity + if (auto search = + std::find_if(RANGE(sectionList), [this](Section const &s) { return &s == this; }); + search != sectionList.end()) { + return static_cast(std::distance(sectionList.begin(), search)); + } + return UINT32_MAX; // LCOV_EXCL_LINE +} + bool Section::isSizeKnown() const { // SECTION UNION and SECTION FRAGMENT can still grow if (modifier != SECTION_NORMAL) { @@ -555,6 +574,14 @@ uint32_t sect_GetOutputOffset() { return curOffset + loadOffset; } +std::optional sect_GetOutputBank() { + return currentSection ? std::optional(currentSection->bank) : std::nullopt; +} + +Patch *sect_AddOutputPatch() { + return currentSection ? ¤tSection->patches.emplace_front() : nullptr; +} + // Returns how many bytes need outputting for the specified alignment and offset to succeed uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset) { Section *sect = sect_GetSymbolSection();