diff --git a/src/asm/charmap.cpp b/src/asm/charmap.cpp index d4920f63..01ce2862 100644 --- a/src/asm/charmap.cpp +++ b/src/asm/charmap.cpp @@ -31,28 +31,28 @@ struct CharmapNode { struct Charmap { std::string name; std::vector nodes; // first node is reserved for the root node +}; - // Traverse the trie depth-first to derive the character mappings in definition order - template - bool forEachChar(F callback) const { - // clang-format off: nested initializers - for (std::stack> prefixes({{0, ""}}); !prefixes.empty();) { - // clang-format on - auto [nodeIdx, mapping] = std::move(prefixes.top()); - prefixes.pop(); - CharmapNode const &node = nodes[nodeIdx]; - if (node.isTerminal() && !callback(nodeIdx, mapping)) { - return false; - } - for (unsigned c = 0; c < std::size(node.next); c++) { - if (size_t nextIdx = node.next[c]; nextIdx) { - prefixes.push({nextIdx, mapping + static_cast(c)}); - } +// Traverse the trie depth-first to derive the character mappings in definition order +template +bool forEachChar(Charmap const &charmap, F callback) { + // clang-format off: nested initializers + for (std::stack> prefixes({{0, ""}}); !prefixes.empty();) { + // clang-format on + auto [nodeIdx, mapping] = std::move(prefixes.top()); + prefixes.pop(); + CharmapNode const &node = charmap.nodes[nodeIdx]; + if (node.isTerminal() && !callback(nodeIdx, mapping)) { + return false; + } + for (unsigned c = 0; c < std::size(node.next); c++) { + if (size_t nextIdx = node.next[c]; nextIdx) { + prefixes.push({nextIdx, mapping + static_cast(c)}); } } - return true; } -}; + return true; +} static std::deque charmapList; static std::unordered_map charmapMap; // Indexes into `charmapList` @@ -66,7 +66,7 @@ bool charmap_ForEach( ) { for (Charmap const &charmap : charmapList) { std::map mappings; - charmap.forEachChar([&mappings](size_t nodeIdx, std::string const &mapping) { + forEachChar(charmap, [&mappings](size_t nodeIdx, std::string const &mapping) { mappings[nodeIdx] = mapping; return true; }); @@ -305,7 +305,7 @@ size_t charmap_ConvertNext(std::string_view &input, std::vector *output std::string charmap_Reverse(std::vector const &value, bool &unique) { Charmap const &charmap = *currentCharmap; std::string revMapping; - unique = charmap.forEachChar([&](size_t nodeIdx, std::string const &mapping) { + unique = forEachChar(charmap, [&](size_t nodeIdx, std::string const &mapping) { if (charmap.nodes[nodeIdx].value == value) { if (revMapping.empty()) { revMapping = mapping; diff --git a/src/asm/output.cpp b/src/asm/output.cpp index ef9fdcb9..754c0f2a 100644 --- a/src/asm/output.cpp +++ b/src/asm/output.cpp @@ -144,12 +144,19 @@ static void registerUnregisteredSymbol(Symbol &sym) { } static void writeRpn(std::vector &rpnexpr, std::vector const &rpn) { - std::string symName; size_t rpnptr = 0; for (size_t offset = 0; offset < rpn.size();) { uint8_t rpndata = rpn[offset++]; + auto getSymName = [&](){ + std::string symName; + for (uint8_t c; (c = rpn[offset++]) != 0;) { + symName += c; + } + return symName; + }; + switch (rpndata) { Symbol *sym; uint32_t value; @@ -164,17 +171,8 @@ static void writeRpn(std::vector &rpnexpr, std::vector const & break; case RPN_SYM: - symName.clear(); - for (;;) { - uint8_t c = rpn[offset++]; - if (c == 0) { - break; - } - symName += c; - } - // The symbol name is always written expanded - sym = sym_FindExactSymbol(symName); + sym = sym_FindExactSymbol(getSymName()); if (sym->isConstant()) { rpnexpr[rpnptr++] = RPN_CONST; value = sym->getConstantValue(); @@ -191,17 +189,8 @@ static void writeRpn(std::vector &rpnexpr, std::vector const & break; case RPN_BANK_SYM: - symName.clear(); - for (;;) { - uint8_t c = rpn[offset++]; - if (c == 0) { - break; - } - symName += c; - } - // The symbol name is always written expanded - sym = sym_FindExactSymbol(symName); + sym = sym_FindExactSymbol(getSymName()); registerUnregisteredSymbol(*sym); // Ensure that `sym->ID` is set value = sym->ID; diff --git a/src/gfx/process.cpp b/src/gfx/process.cpp index 4e2aca7a..6afd1a8a 100644 --- a/src/gfx/process.cpp +++ b/src/gfx/process.cpp @@ -364,51 +364,50 @@ public: std::vector indeterminates; // Assign a color to the given position, and register it in the image palette as well - auto assignColor = - [this, &conflicts, &indeterminates](png_uint_32 x, png_uint_32 y, Rgba &&color) { - if (!color.isTransparent() && !color.isOpaque()) { - uint32_t css = color.toCSS(); - if (std::find(RANGE(indeterminates), css) == indeterminates.end()) { - error( - "Color #%08x is neither transparent (alpha < %u) nor opaque (alpha >= " - "%u) [first seen at x: %" PRIu32 ", y: %" PRIu32 "]", - css, - Rgba::transparency_threshold, - Rgba::opacity_threshold, - x, - y - ); - indeterminates.push_back(css); - } - } else if (Rgba const *other = colors.registerColor(color); other) { - std::tuple conflicting{color.toCSS(), other->toCSS()}; - // Do not report combinations twice - if (std::find(RANGE(conflicts), conflicting) == conflicts.end()) { - warnx( - "Fusing colors #%08x and #%08x into Game Boy color $%04x [first seen " - "at x: %" PRIu32 ", y: %" PRIu32 "]", - std::get<0>(conflicting), - std::get<1>(conflicting), - color.cgbColor(), - x, - y - ); - // Do not report this combination again - conflicts.emplace_back(conflicting); - } - } + auto assignColor = [&](png_uint_32 x, png_uint_32 y, Rgba &&color) { + if (!color.isTransparent() && !color.isOpaque()) { + uint32_t css = color.toCSS(); + if (std::find(RANGE(indeterminates), css) == indeterminates.end()) { + error( + "Color #%08x is neither transparent (alpha < %u) nor opaque (alpha >= " + "%u) [first seen at x: %" PRIu32 ", y: %" PRIu32 "]", + css, + Rgba::transparency_threshold, + Rgba::opacity_threshold, + x, + y + ); + indeterminates.push_back(css); + } + } else if (Rgba const *other = colors.registerColor(color); other) { + std::tuple conflicting{color.toCSS(), other->toCSS()}; + // Do not report combinations twice + if (std::find(RANGE(conflicts), conflicting) == conflicts.end()) { + warnx( + "Fusing colors #%08x and #%08x into Game Boy color $%04x [first seen " + "at x: %" PRIu32 ", y: %" PRIu32 "]", + std::get<0>(conflicting), + std::get<1>(conflicting), + color.cgbColor(), + x, + y + ); + // Do not report this combination again + conflicts.emplace_back(conflicting); + } + } - pixel(x, y) = color; - }; + pixel(x, y) = color; + }; if (interlaceType == PNG_INTERLACE_NONE) { for (png_uint_32 y = 0; y < height; ++y) { - png_read_row(png, row.data(), nullptr); + png_bytep ptr = row.data(); + png_read_row(png, ptr, nullptr); for (png_uint_32 x = 0; x < width; ++x) { - assignColor( - x, y, Rgba(row[x * 4], row[x * 4 + 1], row[x * 4 + 2], row[x * 4 + 3]) - ); + assignColor(x, y, Rgba(ptr[0], ptr[1], ptr[2], ptr[3])); + ptr += 4; } } } else { diff --git a/src/gfx/reverse.cpp b/src/gfx/reverse.cpp index ceebc6e7..a8daa2db 100644 --- a/src/gfx/reverse.cpp +++ b/src/gfx/reverse.cpp @@ -211,28 +211,28 @@ void reverse() { palettes.clear(); std::array buf; // 4 colors - size_t nbRead; - do { - nbRead = file->sgetn(reinterpret_cast(buf.data()), buf.size()); - if (nbRead == buf.size()) { - // Expand the colors - auto &palette = palettes.emplace_back(); - std::generate( - palette.begin(), - palette.begin() + options.nbColorsPerPal, - [&buf, i = 0]() mutable { - i += 2; - return Rgba::fromCGBColor(buf[i - 2] + (buf[i - 1] << 8)); - } - ); - } else if (nbRead != 0) { + for (;;) { + if (size_t nbRead = file->sgetn(reinterpret_cast(buf.data()), buf.size()); + nbRead == 0) { + break; + } else if (nbRead != buf.size()) { fatal( "Palette data size (%zu) is not a multiple of %zu bytes!\n", palettes.size() * buf.size() + nbRead, buf.size() ); } - } while (nbRead != 0); + // Expand the colors + auto &palette = palettes.emplace_back(); + std::generate( + palette.begin(), + palette.begin() + options.nbColorsPerPal, + [&buf, i = 0]() mutable { + i += 2; + return Rgba::fromCGBColor(buf[i - 2] + (buf[i - 1] << 8)); + } + ); + } if (palettes.size() > options.nbPalettes) { warnx( diff --git a/src/link/assign.cpp b/src/link/assign.cpp index 3728fc35..5c0b6b15 100644 --- a/src/link/assign.cpp +++ b/src/link/assign.cpp @@ -34,8 +34,6 @@ struct FreeSpace { // Table of free space for each bank static std::vector> memory[SECTTYPE_INVALID]; -static uint64_t nbSectionsToAssign; - // Init the free space-modelling structs static void initFreeSpace() { for (SectionType type : EnumSeq(SECTTYPE_INVALID)) { @@ -58,8 +56,6 @@ static void assignSection(Section §ion, MemoryLocation const &location) { next->bank = location.bank; } - --nbSectionsToAssign; - out_AddSection(section); } @@ -84,15 +80,13 @@ static bool isLocationSuitable( return location.address + section.size <= freeSpace.address + freeSpace.size; } -// Returns a suitable free space index into `memory[section->type]` at which to place the given -// section, or -1 if none was found. -static ssize_t getPlacement(Section const §ion, MemoryLocation &location) { - SectionTypeInfo const &typeInfo = sectionTypeInfo[section.type]; - +static MemoryLocation getStartLocation(Section const §ion) { static uint16_t curScrambleROM = 0; static uint8_t curScrambleWRAM = 0; static int8_t curScrambleSRAM = 0; + MemoryLocation location; + // Determine which bank we should start searching in if (section.isBankFixed) { location.bank = section.bank; @@ -112,96 +106,150 @@ static ssize_t getPlacement(Section const §ion, MemoryLocation &location) { } location.bank = curScrambleSRAM--; } else { - location.bank = typeInfo.firstBank; + location.bank = sectionTypeInfo[section.type].firstBank; } - for (;;) { - // Switch to the beginning of the next bank - std::deque &bankMem = memory[section.type][location.bank - typeInfo.firstBank]; - size_t spaceIdx = 0; + return location; +} - if (spaceIdx < bankMem.size()) { +// Returns a suitable free space index into `memory[section->type]` at which to place the given +// section, or -1 if none was found. +static ssize_t getPlacement(Section const §ion, MemoryLocation &location) { + SectionTypeInfo const &typeInfo = sectionTypeInfo[section.type]; + + // Switch to the beginning of the next bank + std::deque &bankMem = memory[section.type][location.bank - typeInfo.firstBank]; + size_t spaceIdx = 0; + + if (spaceIdx < bankMem.size()) { + location.address = bankMem[spaceIdx].address; + } + + // Process locations in that bank + while (spaceIdx < bankMem.size()) { + // If that location is OK, return it + if (isLocationSuitable(section, bankMem[spaceIdx], location)) { + return spaceIdx; + } + + // Go to the next *possible* location + if (section.isAddressFixed) { + // If the address is fixed, there can be only one candidate block per bank; + // if we already reached it, give up. + if (location.address < section.org) { + location.address = section.org; + } else { + break; // Try again in next bank + } + } else if (section.isAlignFixed) { + // Move to next aligned location + // Move back to alignment boundary + location.address -= section.alignOfs; + // Ensure we're there (e.g. on first check) + location.address &= ~section.alignMask; + // Go to next align boundary and add offset + location.address += section.alignMask + 1 + section.alignOfs; + } else if (++spaceIdx < bankMem.size()) { + // Any location is fine, so, next free block location.address = bankMem[spaceIdx].address; } - // Process locations in that bank - while (spaceIdx < bankMem.size()) { - // If that location is OK, return it - if (isLocationSuitable(section, bankMem[spaceIdx], location)) { - return spaceIdx; - } - - // Go to the next *possible* location - if (section.isAddressFixed) { - // If the address is fixed, there can be only - // one candidate block per bank; if we already - // reached it, give up. - if (location.address < section.org) { - location.address = section.org; - } else { - break; // Try again in next bank - } - } else if (section.isAlignFixed) { - // Move to next aligned location - // Move back to alignment boundary - location.address -= section.alignOfs; - // Ensure we're there (e.g. on first check) - location.address &= ~section.alignMask; - // Go to next align boundary and add offset - location.address += section.alignMask + 1 + section.alignOfs; - } else if (++spaceIdx < bankMem.size()) { - // Any location is fine, so, next free block - location.address = bankMem[spaceIdx].address; - } - - // If that location is past the current block's end, - // go forwards until that is no longer the case. - while (spaceIdx < bankMem.size() - && location.address >= bankMem[spaceIdx].address + bankMem[spaceIdx].size) { - ++spaceIdx; - } - - // Try again with the new location/free space combo + // If that location is past the current block's end, + // go forwards until that is no longer the case. + while (spaceIdx < bankMem.size() + && location.address >= bankMem[spaceIdx].address + bankMem[spaceIdx].size) { + ++spaceIdx; } - // Try again in the next bank, if one is available. - // Try scrambled banks in descending order until no bank in the scrambled range is - // available. Otherwise, try in ascending order. - if (section.isBankFixed) { - return -1; - } else if (options.scrambleROMX && section.type == SECTTYPE_ROMX - && location.bank <= options.scrambleROMX) { - if (location.bank > typeInfo.firstBank) { - --location.bank; - } else if (options.scrambleROMX < typeInfo.lastBank) { - location.bank = options.scrambleROMX + 1; - } else { - return -1; - } - } else if (options.scrambleWRAMX && section.type == SECTTYPE_WRAMX - && location.bank <= options.scrambleWRAMX) { - if (location.bank > typeInfo.firstBank) { - --location.bank; - } else if (options.scrambleWRAMX < typeInfo.lastBank) { - location.bank = options.scrambleWRAMX + 1; - } else { - return -1; - } - } else if (options.scrambleSRAM && section.type == SECTTYPE_SRAM - && location.bank <= options.scrambleSRAM) { - if (location.bank > typeInfo.firstBank) { - --location.bank; - } else if (options.scrambleSRAM < typeInfo.lastBank) { - location.bank = options.scrambleSRAM + 1; - } else { - return -1; - } - } else if (location.bank < typeInfo.lastBank) { - ++location.bank; + // Try again with the new location/free space combo + } + + // Try again in the next bank, if one is available. + // Try scrambled banks in descending order until no bank in the scrambled range is + // available. Otherwise, try in ascending order. + if (section.isBankFixed) { + return -1; + } else if (options.scrambleROMX && section.type == SECTTYPE_ROMX + && location.bank <= options.scrambleROMX) { + if (location.bank > typeInfo.firstBank) { + --location.bank; + } else if (options.scrambleROMX < typeInfo.lastBank) { + location.bank = options.scrambleROMX + 1; } else { return -1; } + } else if (options.scrambleWRAMX && section.type == SECTTYPE_WRAMX + && location.bank <= options.scrambleWRAMX) { + if (location.bank > typeInfo.firstBank) { + --location.bank; + } else if (options.scrambleWRAMX < typeInfo.lastBank) { + location.bank = options.scrambleWRAMX + 1; + } else { + return -1; + } + } else if (options.scrambleSRAM && section.type == SECTTYPE_SRAM + && location.bank <= options.scrambleSRAM) { + if (location.bank > typeInfo.firstBank) { + --location.bank; + } else if (options.scrambleSRAM < typeInfo.lastBank) { + location.bank = options.scrambleSRAM + 1; + } else { + return -1; + } + } else if (location.bank < typeInfo.lastBank) { + ++location.bank; + } else { + return -1; } + + return getPlacement(section, location); // Tail recursion +} + +static std::string getSectionDescription(Section const §ion) { + std::string where; + + char bank[8], addr[8], mask[8], offset[8]; + if (section.isBankFixed && nbbanks(section.type) != 1) { + snprintf(bank, sizeof(bank), "%02" PRIx32, section.bank); + } + if (section.isAddressFixed) { + snprintf(addr, sizeof(addr), "%04" PRIx16, section.org); + } + if (section.isAlignFixed) { + snprintf(mask, sizeof(mask), "%" PRIx16, static_cast(~section.alignMask)); + snprintf(offset, sizeof(offset), "%" PRIx16, section.alignOfs); + } + + if (section.isBankFixed && nbbanks(section.type) != 1) { + if (section.isAddressFixed) { + where = "at $"; + where += bank; + where += ":"; + where += addr; + } else if (section.isAlignFixed) { + where = "in bank $"; + where += bank; + where += " with align mask $"; + where += mask; + } else { + where = "in bank $"; + where += bank; + } + } else { + if (section.isAddressFixed) { + where = "at address $"; + where += addr; + } else if (section.isAlignFixed) { + where = "with align mask $"; + where += mask; + where += " and offset $"; + where += offset; + } else { + where = "anywhere"; + } + } + + return where; } // Places a section in a suitable location, or error out if it fails to. @@ -222,7 +270,7 @@ static void placeSection(Section §ion) { // Place section using first-fit decreasing algorithm // https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm - MemoryLocation location; + MemoryLocation location = getStartLocation(section); if (ssize_t spaceIdx = getPlacement(section, location); spaceIdx != -1) { std::deque &bankMem = memory[section.type][location.bank - sectionTypeInfo[section.type].firstBank]; @@ -258,80 +306,53 @@ static void placeSection(Section §ion) { return; } - // Please adjust depending on longest message below - char where[64]; - - if (section.isBankFixed && nbbanks(section.type) != 1) { - if (section.isAddressFixed) { - snprintf( - where, sizeof(where), "at $%02" PRIx32 ":%04" PRIx16, section.bank, section.org - ); - } else if (section.isAlignFixed) { - snprintf( - where, - sizeof(where), - "in bank $%02" PRIx32 " with align mask $%" PRIx16, - section.bank, - static_cast(~section.alignMask) - ); - } else { - snprintf(where, sizeof(where), "in bank $%02" PRIx32, section.bank); - } - } else { - if (section.isAddressFixed) { - snprintf(where, sizeof(where), "at address $%04" PRIx16, section.org); - } else if (section.isAlignFixed) { - snprintf( - where, - sizeof(where), - "with align mask $%" PRIx16 " and offset $%" PRIx16, - static_cast(~section.alignMask), - section.alignOfs - ); - } else { - strcpy(where, "anywhere"); - } - } - - // If a section failed to go to several places, nothing we can report if (!section.isBankFixed || !section.isAddressFixed) { + // If a section failed to go to several places, nothing we can report fatal( "Unable to place \"%s\" (%s section) %s", section.name.c_str(), sectionTypeInfo[section.type].name.c_str(), - where + getSectionDescription(section).c_str() ); - } - // 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) { + // If the section just can't fit the bank, report that fatal( "Unable to place \"%s\" (%s section) %s: section runs past end of region ($%04x > " "$%04x)", section.name.c_str(), sectionTypeInfo[section.type].name.c_str(), - where, + getSectionDescription(section).c_str(), section.org + section.size, endaddr(section.type) + 1 ); - } - // Otherwise there is overlap with another section - else { + } else { + // Otherwise there is overlap with another section fatal( "Unable to place \"%s\" (%s section) %s: section overlaps with \"%s\"", section.name.c_str(), sectionTypeInfo[section.type].name.c_str(), - where, + getSectionDescription(section).c_str(), out_OverlappingSection(section)->name.c_str() ); } } +static std::deque
unassignedSections[1 << 3]; // clang-format off: vertically align values static constexpr uint8_t BANK_CONSTRAINED = 1 << 2; static constexpr uint8_t ORG_CONSTRAINED = 1 << 1; static constexpr uint8_t ALIGN_CONSTRAINED = 1 << 0; // clang-format on -static std::deque
unassignedSections[1 << 3]; +static char const * const constraintNames[] = { + "un", + "align-", + "org-", + nullptr, // align+org (impossible) + "bank-", + "bank+align-", + "bank+org-", + nullptr, // bank+align+org (impossible) +}; // Categorize a section depending on how constrained it is. // This is so the most-constrained sections are placed first. @@ -341,11 +362,10 @@ static void categorizeSection(Section §ion) { if (section.isBankFixed) { constraints |= BANK_CONSTRAINED; } + // Can't have both! if (section.isAddressFixed) { constraints |= ORG_CONSTRAINED; - } - // Can't have both! - else if (section.isAlignFixed) { + } else if (section.isAlignFixed) { constraints |= ALIGN_CONSTRAINED; } @@ -357,68 +377,77 @@ static void categorizeSection(Section §ion) { ++pos; } sections.insert(pos, §ion); +} - ++nbSectionsToAssign; +static std::vector
checkOverlayCompat() { + std::vector
unfixedSections; + + if (!options.overlayFileName) { + return unfixedSections; + } + + for (uint8_t constraints = std::size(unassignedSections); constraints--;) { + if ((constraints & (BANK_CONSTRAINED | ORG_CONSTRAINED)) + || unassignedSections[constraints].empty()) { + continue; + } + + for (Section *section : unassignedSections[constraints]) { + unfixedSections.push_back(section); + + if (unfixedSections.size() == 10) { + return unfixedSections; + } + } + } + + return unfixedSections; } void assign_AssignSections() { verbosePrint("Beginning assignment...\n"); // Initialize assignment - initFreeSpace(); // Generate linked lists of sections to assign - nbSectionsToAssign = 0; - sect_ForEach(categorizeSection); - - // Place sections, starting with the most constrained - - // Specially process fully-constrained sections because of overlaying - verbosePrint("Assigning bank+org-constrained...\n"); - for (Section *section : unassignedSections[BANK_CONSTRAINED | ORG_CONSTRAINED]) { - placeSection(*section); - } - - // If all sections were fully constrained, we have nothing left to do - if (!nbSectionsToAssign) { - return; - } + static uint64_t nbSectionsToAssign = 0; // `static` so `sect_ForEach` callback can see it + sect_ForEach([](Section §ion) { + categorizeSection(section); + ++nbSectionsToAssign; + }); // Overlaying requires only fully-constrained sections - verbosePrint("Assigning other sections...\n"); - if (options.overlayFileName) { + if (std::vector
unfixedSections = checkOverlayCompat(); !unfixedSections.empty()) { + size_t nbUnfixedSections = unfixedSections.size(); fputs("FATAL: All sections must be fixed when using an overlay file", stderr); - uint8_t nbSections = 0; - for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED; constraints >= 0; - constraints--) { - for (Section *section : unassignedSections[constraints]) { - fprintf(stderr, "%c \"%s\"", nbSections == 0 ? ';' : ',', section->name.c_str()); - if (++nbSections == 10) { - goto max_out; // Can't `break` out of a nested loop - } - } + for (size_t i = 0; i < nbUnfixedSections; ++i) { + fprintf(stderr, "%c \"%s\"", i == 0 ? ';' : ',', unfixedSections[i]->name.c_str()); } - -max_out: - if (nbSectionsToAssign != nbSections) { - fprintf(stderr, " and %" PRIu64 " more", nbSectionsToAssign - nbSections); + if (nbSectionsToAssign != nbUnfixedSections) { + fprintf(stderr, " and %" PRIu64 " more", nbSectionsToAssign - nbUnfixedSections); } - fprintf(stderr, " %sn't\n", nbSectionsToAssign == 1 ? "is" : "are"); + fprintf(stderr, " %s not\n", nbSectionsToAssign == 1 ? "is" : "are"); exit(1); } - // Assign all remaining sections by decreasing constraint order - for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED; constraints >= 0; - constraints--) { - for (Section *section : unassignedSections[constraints]) { - placeSection(*section); + // Assign sections in decreasing constraint order + for (uint8_t constraints = std::size(unassignedSections); constraints--;) { + if (char const *constraintName = constraintNames[constraints]; constraintName) { + verbosePrint("Assigning %sconstrained sections...\n", constraintName); + } else { + assume(unassignedSections[constraints].empty()); } - if (!nbSectionsToAssign) { - return; + for (Section *section : unassignedSections[constraints]) { + placeSection(*section); + + // If all sections were fully constrained, we have nothing left to do + if (!--nbSectionsToAssign) { + return; + } } } - unreachable_(); // LCOV_EXCL_LINE + assume(nbSectionsToAssign == 0); } diff --git a/src/link/object.cpp b/src/link/object.cpp index 4c76edc1..a5ad37f3 100644 --- a/src/link/object.cpp +++ b/src/link/object.cpp @@ -77,7 +77,7 @@ static int64_t readLong(FILE *file) { do { \ FILE *tmpFile = file; \ std::string &tmpVal = var; \ - for (int tmpByte = getc(tmpFile); tmpByte != '\0'; tmpByte = getc(tmpFile)) { \ + for (int tmpByte; (tmpByte = getc(tmpFile)) != '\0';) { \ if (tmpByte == EOF) { \ fatal(__VA_ARGS__, feof(tmpFile) ? "Unexpected end of file" : strerror(errno)); \ } else { \ @@ -582,15 +582,16 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) { for (uint32_t i = 0; i < nbSymbols; i++) { if (std::holds_alternative