mirror of
https://github.com/gbdev/rgbds.git
synced 2026-09-18 03:37:06 +00:00
Use SectionTypeInfo struct member functions for section type info
This commit is contained in:
@@ -42,6 +42,8 @@ struct Section {
|
||||
std::deque<Patch> patches;
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
SectionTypeInfo const &typeInfo() const { return sectionTypeInfo[type]; }
|
||||
|
||||
uint32_t getID() const; // ID of the section in the object file (`UINT32_MAX` if none)
|
||||
bool isSizeKnown() const;
|
||||
};
|
||||
|
||||
@@ -51,6 +51,8 @@ struct Section {
|
||||
std::vector<Symbol *> symbols;
|
||||
std::unique_ptr<Section> nextPiece; // The next fragment or union "piece" of this section
|
||||
|
||||
SectionTypeInfo const &typeInfo() const { return sectionTypeInfo[type]; }
|
||||
|
||||
private:
|
||||
// Template class for both const and non-const iterators over the "pieces" of this section
|
||||
template<QualifiedEquivalent<Section> SectionT>
|
||||
|
||||
+17
-17
@@ -82,6 +82,13 @@ static constexpr uint8_t SECTTYPE_TYPE_MASK = 0b111;
|
||||
static constexpr uint8_t SECTTYPE_UNION_BIT = 7;
|
||||
static constexpr uint8_t SECTTYPE_FRAGMENT_BIT = 6;
|
||||
|
||||
// Tells whether a section has data in its object file definition,
|
||||
// depending on type.
|
||||
static inline bool sectTypeHasData(SectionType type) {
|
||||
assume(type != SECTTYPE_INVALID);
|
||||
return type == SECTTYPE_ROM0 || type == SECTTYPE_ROMX;
|
||||
}
|
||||
|
||||
enum FileStackNodeType {
|
||||
NODE_REPT,
|
||||
NODE_FILE,
|
||||
@@ -90,31 +97,24 @@ enum FileStackNodeType {
|
||||
|
||||
static constexpr uint8_t FSTACKNODE_QUIET_BIT = 7;
|
||||
|
||||
// Nont-`const` members may be patched in RGBLINK depending on CLI flags
|
||||
extern struct SectionTypeInfo {
|
||||
// Non-`const` members may be patched in RGBLINK depending on CLI flags
|
||||
struct SectionTypeInfo {
|
||||
std::string const name;
|
||||
uint16_t const startAddr;
|
||||
uint16_t size;
|
||||
uint32_t const firstBank;
|
||||
uint32_t lastBank;
|
||||
} sectionTypeInfo[SECTTYPE_INVALID];
|
||||
|
||||
// Tells whether a section has data in its object file definition,
|
||||
// depending on type.
|
||||
static inline bool sectTypeHasData(SectionType type) {
|
||||
assume(type != SECTTYPE_INVALID);
|
||||
return type == SECTTYPE_ROM0 || type == SECTTYPE_ROMX;
|
||||
}
|
||||
// Returns a memory region's end address (last byte), e.g. 0x7FFF
|
||||
uint16_t endAddr() const { return startAddr + size - 1; }
|
||||
|
||||
// Returns a memory region's end address (last byte), e.g. 0x7FFF
|
||||
static inline uint16_t sectTypeEndAddr(SectionType type) {
|
||||
return sectionTypeInfo[type].startAddr + sectionTypeInfo[type].size - 1;
|
||||
}
|
||||
// Returns a memory region's number of banks, or 1 for regions without banking
|
||||
uint32_t nbBanks() const { return lastBank - firstBank + 1; }
|
||||
|
||||
// Returns a memory region's number of banks, or 1 for regions without banking
|
||||
static inline uint32_t sectTypeBanks(SectionType type) {
|
||||
return sectionTypeInfo[type].lastBank - sectionTypeInfo[type].firstBank + 1;
|
||||
}
|
||||
bool isBanked() const { return nbBanks() != 1; }
|
||||
};
|
||||
|
||||
extern SectionTypeInfo sectionTypeInfo[SECTTYPE_INVALID];
|
||||
|
||||
enum SectionModifier { SECTION_NORMAL, SECTION_UNION, SECTION_FRAGMENT };
|
||||
|
||||
|
||||
+17
-17
@@ -100,7 +100,7 @@ void sect_ForEach(void (*callback)(Section &)) {
|
||||
|
||||
void sect_CheckSizes() {
|
||||
for (Section const § : sections) {
|
||||
if (uint32_t maxSize = sectionTypeInfo[sect.type].size; sect.size > maxSize) {
|
||||
if (uint32_t maxSize = sect.typeInfo().size; sect.size > maxSize) {
|
||||
error(
|
||||
"Section \"%s\" grew too big (max size = 0x%" PRIX32 " bytes, reached 0x%" PRIX32
|
||||
")",
|
||||
@@ -309,7 +309,7 @@ static void mergeSections(
|
||||
sectError(
|
||||
"Section \"%s\" already exists but with type `%s`",
|
||||
sect.name.c_str(),
|
||||
sectionTypeInfo[sect.type].name.c_str()
|
||||
sect.typeInfo().name.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -377,8 +377,8 @@ static Section *createSection(
|
||||
out_RegisterNode(sect.src);
|
||||
|
||||
// It is only needed to allocate memory for ROM sections.
|
||||
if (sectTypeHasData(type)) {
|
||||
sect.data.resize(sectionTypeInfo[type].size);
|
||||
if (sectTypeHasData(sect.type)) {
|
||||
sect.data.resize(sect.typeInfo().size);
|
||||
}
|
||||
|
||||
return §
|
||||
@@ -403,7 +403,7 @@ static Section *createSectionFragmentLiteral(Section const &parent) {
|
||||
|
||||
// Section fragment literals must be ROM sections.
|
||||
assume(sectTypeHasData(sect.type));
|
||||
sect.data.resize(sectionTypeInfo[sect.type].size);
|
||||
sect.data.resize(sect.typeInfo().size);
|
||||
|
||||
return §
|
||||
}
|
||||
@@ -424,24 +424,24 @@ static Section *getSection(
|
||||
uint32_t alignMask = alignSize - 1;
|
||||
|
||||
// First, validate parameters, and normalize them if applicable
|
||||
SectionTypeInfo const &typeInfo = sectionTypeInfo[type];
|
||||
|
||||
if (bank != UINT32_MAX) {
|
||||
if (type != SECTTYPE_ROMX && type != SECTTYPE_VRAM && type != SECTTYPE_SRAM
|
||||
&& type != SECTTYPE_WRAMX) {
|
||||
error("`BANK` only allowed for `ROMX`, `WRAMX`, `SRAM`, or `VRAM` sections");
|
||||
} else if (bank < sectionTypeInfo[type].firstBank
|
||||
|| bank > sectionTypeInfo[type].lastBank) {
|
||||
} else if (bank < typeInfo.firstBank || bank > typeInfo.lastBank) {
|
||||
error(
|
||||
"%s bank value $%04" PRIx32 " out of range ($%04" PRIx32 " to $%04" PRIx32 ")",
|
||||
sectionTypeInfo[type].name.c_str(),
|
||||
typeInfo.name.c_str(),
|
||||
bank,
|
||||
sectionTypeInfo[type].firstBank,
|
||||
sectionTypeInfo[type].lastBank
|
||||
typeInfo.firstBank,
|
||||
typeInfo.lastBank
|
||||
);
|
||||
}
|
||||
} else if (sectTypeBanks(type) == 1) {
|
||||
} else if (!typeInfo.isBanked()) {
|
||||
// If the section type only has a single bank, implicitly force it
|
||||
bank = sectionTypeInfo[type].firstBank;
|
||||
bank = typeInfo.firstBank;
|
||||
}
|
||||
|
||||
// This should be redundant, as the parser guarantees that `AlignmentSpec` will be valid.
|
||||
@@ -457,14 +457,14 @@ static Section *getSection(
|
||||
}
|
||||
|
||||
if (org != UINT32_MAX) {
|
||||
if (org < sectionTypeInfo[type].startAddr || org > sectTypeEndAddr(type)) {
|
||||
if (org < typeInfo.startAddr || org > typeInfo.endAddr()) {
|
||||
error(
|
||||
"Section \"%s\"'s fixed address $%04" PRIx32 " is outside of range [$%04" PRIx16
|
||||
"; $%04" PRIx16 "]",
|
||||
name.c_str(),
|
||||
org,
|
||||
sectionTypeInfo[type].startAddr,
|
||||
sectTypeEndAddr(type)
|
||||
typeInfo.startAddr,
|
||||
typeInfo.endAddr()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -476,11 +476,11 @@ static Section *getSection(
|
||||
error("Section \"%s\"'s fixed address does not match its alignment", name.c_str());
|
||||
}
|
||||
alignment = 0; // Ignore it if it's satisfied
|
||||
} else if (sectionTypeInfo[type].startAddr & alignMask) {
|
||||
} else if (typeInfo.startAddr & alignMask) {
|
||||
error(
|
||||
"Section \"%s\"'s alignment cannot be attained in %s",
|
||||
name.c_str(),
|
||||
sectionTypeInfo[type].name.c_str()
|
||||
typeInfo.name.c_str()
|
||||
);
|
||||
alignment = 0; // Ignore it if it's unattainable
|
||||
org = 0;
|
||||
|
||||
+17
-16
@@ -79,7 +79,7 @@ static MemoryLocation getStartLocation(Section const §ion) {
|
||||
if (section.isBankFixed) {
|
||||
location.bank = section.bank;
|
||||
} else {
|
||||
location.bank = sectionTypeInfo[section.type].firstBank;
|
||||
location.bank = section.typeInfo().firstBank;
|
||||
|
||||
// Scramble the bank if applicable
|
||||
if (options.scrambleROMX && section.type == SECTTYPE_ROMX) {
|
||||
@@ -106,14 +106,14 @@ static MemoryLocation getStartLocation(Section const §ion) {
|
||||
// Returns a suitable free space index into `memory[section->type]` at which to place the given
|
||||
// section, or `std::nullopt` if none was found.
|
||||
static std::optional<size_t> getPlacement(Section const §ion, MemoryLocation &location) {
|
||||
SectionTypeInfo const &typeInfo = sectionTypeInfo[section.type];
|
||||
SectionTypeInfo const &typeInfo = section.typeInfo();
|
||||
|
||||
for (;;) {
|
||||
if (location.bank < typeInfo.firstBank
|
||||
|| location.bank >= memory[section.type].size() + typeInfo.firstBank) {
|
||||
fatal(
|
||||
"Invalid bank for %s section \"%s\": %" PRIu32,
|
||||
sectionTypeInfo[section.type].name.c_str(),
|
||||
typeInfo.name.c_str(),
|
||||
section.name.c_str(),
|
||||
location.bank
|
||||
);
|
||||
@@ -217,9 +217,8 @@ static std::optional<size_t> getPlacement(Section const §ion, MemoryLocation
|
||||
}
|
||||
|
||||
static std::string getSectionDescription(Section const §ion) {
|
||||
std::string description =
|
||||
"\"" + section.name + "\" (" + sectionTypeInfo[section.type].name + " section) ";
|
||||
if (section.isBankFixed && sectTypeBanks(section.type) != 1) {
|
||||
std::string description = "\"" + section.name + "\" (" + section.typeInfo().name + " section) ";
|
||||
if (section.isBankFixed && section.typeInfo().isBanked()) {
|
||||
char bank[8];
|
||||
snprintf(bank, sizeof(bank), "%02" PRIx32, section.bank);
|
||||
if (section.isAddressFixed) {
|
||||
@@ -253,14 +252,15 @@ static std::string getSectionDescription(Section const §ion) {
|
||||
// Places a section in a suitable location, or error out if it fails to.
|
||||
// Due to the implemented algorithm, this should be called with sections of decreasing size!
|
||||
static void placeSection(Section §ion) {
|
||||
SectionTypeInfo const &typeInfo = section.typeInfo();
|
||||
|
||||
// Specially handle 0-byte SECTIONs, as they can't overlap anything
|
||||
if (section.size == 0) {
|
||||
// Unless the SECTION's address was fixed, the starting address
|
||||
// is fine for any alignment, as checked in sect_DoSanityChecks.
|
||||
MemoryLocation location = {
|
||||
.address =
|
||||
section.isAddressFixed ? section.org : sectionTypeInfo[section.type].startAddr,
|
||||
.bank = section.isBankFixed ? section.bank : sectionTypeInfo[section.type].firstBank,
|
||||
.address = section.isAddressFixed ? section.org : typeInfo.startAddr,
|
||||
.bank = section.isBankFixed ? section.bank : typeInfo.firstBank,
|
||||
};
|
||||
assignSection(section, location);
|
||||
return;
|
||||
@@ -270,8 +270,7 @@ static void placeSection(Section §ion) {
|
||||
// https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm
|
||||
MemoryLocation location = getStartLocation(section);
|
||||
if (std::optional<size_t> spaceIdx = getPlacement(section, location); spaceIdx) {
|
||||
std::deque<FreeSpace> &bankMem =
|
||||
memory[section.type][location.bank - sectionTypeInfo[section.type].firstBank];
|
||||
std::deque<FreeSpace> &bankMem = memory[section.type][location.bank - typeInfo.firstBank];
|
||||
FreeSpace &freeSpace = bankMem[*spaceIdx];
|
||||
|
||||
assignSection(section, location);
|
||||
@@ -308,13 +307,14 @@ static void placeSection(Section §ion) {
|
||||
if (!section.isBankFixed || !section.isAddressFixed) {
|
||||
// If a section failed to go to several places, nothing we can report
|
||||
fatal("Unable to place %s", getSectionDescription(section).c_str());
|
||||
} else if (section.org + section.size > sectTypeEndAddr(section.type) + 1) {
|
||||
} else if (uint16_t onePastEnd = typeInfo.endAddr() + 1;
|
||||
section.org + section.size > onePastEnd) {
|
||||
// If the section just can't fit the bank, report that
|
||||
fatal(
|
||||
"Unable to place %s: section runs past end of region ($%04x > $%04x)",
|
||||
getSectionDescription(section).c_str(),
|
||||
section.org + section.size,
|
||||
sectTypeEndAddr(section.type) + 1
|
||||
onePastEnd
|
||||
);
|
||||
} else {
|
||||
// Otherwise there is overlap with another section
|
||||
@@ -430,11 +430,12 @@ void assign_AssignSections() {
|
||||
|
||||
// Initialize the free space-modelling structs
|
||||
for (SectionType type : EnumSeq(SECTTYPE_INVALID)) {
|
||||
memory[type].resize(sectTypeBanks(type));
|
||||
SectionTypeInfo const &typeInfo = sectionTypeInfo[type];
|
||||
memory[type].resize(typeInfo.nbBanks());
|
||||
for (std::deque<FreeSpace> &bankMem : memory[type]) {
|
||||
bankMem.push_back({
|
||||
.address = sectionTypeInfo[type].startAddr,
|
||||
.size = sectionTypeInfo[type].size,
|
||||
.address = typeInfo.startAddr,
|
||||
.size = typeInfo.size,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -31,7 +31,7 @@ static void setActiveTypeAndIdx(SectionType type, uint32_t idx) {
|
||||
}
|
||||
|
||||
void layout_SetFloatingSectionType(SectionType type) {
|
||||
if (sectTypeBanks(type) == 1) {
|
||||
if (!sectionTypeInfo[type].isBanked()) {
|
||||
// There is only a single bank anyway, so just set the index to 0.
|
||||
setActiveTypeAndIdx(type, 0);
|
||||
} else {
|
||||
@@ -46,8 +46,8 @@ void layout_SetFloatingSectionType(SectionType type) {
|
||||
}
|
||||
|
||||
void layout_SetSectionType(SectionType type) {
|
||||
if (sectTypeBanks(type) != 1) {
|
||||
scriptError("A bank number must be specified for %s", sectionTypeInfo[type].name.c_str());
|
||||
if (SectionTypeInfo const &typeInfo = sectionTypeInfo[type]; typeInfo.isBanked()) {
|
||||
scriptError("A bank number must be specified for %s", typeInfo.name.c_str());
|
||||
// Keep going with a default value for the bank index.
|
||||
}
|
||||
|
||||
@@ -88,22 +88,22 @@ void layout_SetAddr(uint32_t addr) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t &pc = curAddr[activeType][activeBankIdx];
|
||||
SectionTypeInfo const &typeInfo = sectionTypeInfo[activeType];
|
||||
|
||||
if (addr < pc) {
|
||||
if (uint16_t &pc = curAddr[activeType][activeBankIdx]; addr < pc) {
|
||||
scriptError("Cannot decrease the current address (from $%04x to $%04x)", pc, addr);
|
||||
} else if (addr > sectTypeEndAddr(activeType)) { // Allow "one past the end" sections.
|
||||
} else if (addr > typeInfo.endAddr()) { // Allow "one past the end" sections.
|
||||
scriptError(
|
||||
"Cannot set the current address to $%04" PRIx32 ": %s ends at $%04" PRIx16,
|
||||
addr,
|
||||
typeInfo.name.c_str(),
|
||||
sectTypeEndAddr(activeType)
|
||||
typeInfo.endAddr()
|
||||
);
|
||||
pc = sectTypeEndAddr(activeType);
|
||||
pc = typeInfo.endAddr();
|
||||
} else {
|
||||
pc = addr;
|
||||
}
|
||||
|
||||
isPcFloating = false;
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ void layout_AlignTo(uint32_t alignment, uint32_t alignOfs) {
|
||||
", past $%04" PRIx16,
|
||||
pc,
|
||||
static_cast<uint16_t>(pc + length),
|
||||
static_cast<uint16_t>(sectTypeEndAddr(activeType) + 1)
|
||||
static_cast<uint16_t>(typeInfo.endAddr() + 1)
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -212,7 +212,7 @@ void layout_Pad(uint32_t length) {
|
||||
"Cannot increase the current address by %u bytes: only %u bytes to $%04" PRIx16,
|
||||
length,
|
||||
typeInfo.size - offset,
|
||||
static_cast<uint16_t>(sectTypeEndAddr(activeType) + 1)
|
||||
static_cast<uint16_t>(typeInfo.endAddr() + 1)
|
||||
);
|
||||
} else {
|
||||
pc += length;
|
||||
|
||||
+5
-8
@@ -71,7 +71,7 @@ void out_AddSection(Section const §ion) {
|
||||
1, // SECTTYPE_OAM
|
||||
};
|
||||
|
||||
uint32_t targetBank = section.bank - sectionTypeInfo[section.type].firstBank;
|
||||
uint32_t targetBank = section.bank - section.typeInfo().firstBank;
|
||||
if (targetBank >= maxNbBanks[section.type]) {
|
||||
fatal(
|
||||
"Section \"%s\" has an invalid bank range (%" PRIu32 " > %" PRIu32 ")",
|
||||
@@ -96,7 +96,7 @@ void out_AddSection(Section const §ion) {
|
||||
}
|
||||
|
||||
Section const *out_OverlappingSection(Section const §ion) {
|
||||
uint32_t bank = section.bank - sectionTypeInfo[section.type].firstBank;
|
||||
uint32_t bank = section.bank - section.typeInfo().firstBank;
|
||||
|
||||
for (Section const *ptr : sections[section.type][bank].sections) {
|
||||
if (ptr->org < section.org + section.size && section.org < ptr->org + ptr->size) {
|
||||
@@ -491,12 +491,10 @@ static void writeMapBank(SortedSections const §List, SectionType type, uint3
|
||||
if (used == 0) {
|
||||
fputs("\tEMPTY\n", mapFile);
|
||||
} else {
|
||||
uint16_t bankEndAddr = sectionTypeInfo[type].startAddr + sectionTypeInfo[type].size;
|
||||
|
||||
uint16_t bankEndAddr = sectionTypeInfo[type].endAddr() + 1;
|
||||
writeEmptySpace(prevEndAddr, bankEndAddr);
|
||||
|
||||
uint16_t slack = sectionTypeInfo[type].size - used;
|
||||
|
||||
fprintf(mapFile, "\tTOTAL EMPTY: $%04" PRIx16 " byte%s\n", slack, slack == 1 ? "" : "s");
|
||||
}
|
||||
}
|
||||
@@ -513,13 +511,12 @@ static void writeMapSummary() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not output unused section types
|
||||
// Skip types which haven't been used at all.
|
||||
if (nbBanks == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t usedTotal = 0;
|
||||
|
||||
for (uint32_t bank = 0; bank < nbBanks; ++bank) {
|
||||
usedTotal += forEachSection(sections[type][bank], [](Section const &) {});
|
||||
}
|
||||
@@ -532,7 +529,7 @@ static void writeMapSummary() {
|
||||
usedTotal == 1 ? "" : "s",
|
||||
static_cast<size_t>(nbBanks) * sectionTypeInfo[type].size - usedTotal
|
||||
);
|
||||
if (sectionTypeInfo[type].firstBank != sectionTypeInfo[type].lastBank) {
|
||||
if (sectionTypeInfo[type].isBanked()) {
|
||||
fprintf(mapFile, " in %u bank%s", nbBanks, nbBanks == 1 ? "" : "s");
|
||||
}
|
||||
putc('\n', mapFile);
|
||||
|
||||
+13
-12
@@ -254,18 +254,20 @@ static void doSanityChecks(Section §ion) {
|
||||
section.isAlignFixed = false;
|
||||
}
|
||||
|
||||
// The section's type is determined now, so we can get its type info
|
||||
SectionTypeInfo const &typeInfo = section.typeInfo();
|
||||
|
||||
// Too large an alignment may not be satisfiable
|
||||
if (section.isAlignFixed && (section.alignMask & sectionTypeInfo[section.type].startAddr)) {
|
||||
if (section.isAlignFixed && (section.alignMask & typeInfo.startAddr)) {
|
||||
error(
|
||||
"Section \"%s\" has type `%s`, which cannot be aligned to $%04x bytes",
|
||||
section.name.c_str(),
|
||||
sectionTypeInfo[section.type].name.c_str(),
|
||||
typeInfo.name.c_str(),
|
||||
section.alignMask + 1
|
||||
);
|
||||
}
|
||||
|
||||
uint32_t minbank = sectionTypeInfo[section.type].firstBank,
|
||||
maxbank = sectionTypeInfo[section.type].lastBank;
|
||||
uint32_t minbank = typeInfo.firstBank, maxbank = typeInfo.lastBank;
|
||||
|
||||
if (!bankModeError && section.isBankFixed
|
||||
&& (section.bank < minbank || section.bank > maxbank)) {
|
||||
@@ -282,12 +284,12 @@ static void doSanityChecks(Section §ion) {
|
||||
}
|
||||
|
||||
// Check if section has a chance to be placed
|
||||
if (section.size > sectionTypeInfo[section.type].size) {
|
||||
if (section.size > typeInfo.size) {
|
||||
error(
|
||||
"Section \"%s\" is bigger than the max size for that type: $%" PRIx16 " > $%" PRIx16,
|
||||
section.name.c_str(),
|
||||
section.size,
|
||||
sectionTypeInfo[section.type].size
|
||||
typeInfo.size
|
||||
);
|
||||
}
|
||||
|
||||
@@ -311,24 +313,23 @@ static void doSanityChecks(Section §ion) {
|
||||
}
|
||||
|
||||
// Ensure the target address is valid
|
||||
if (section.org < sectionTypeInfo[section.type].startAddr
|
||||
|| section.org > sectTypeEndAddr(section.type)) {
|
||||
if (section.org < typeInfo.startAddr || section.org > typeInfo.endAddr()) {
|
||||
error(
|
||||
"Section \"%s\"'s fixed address $%04" PRIx16 " is outside of range [$%04" PRIx16
|
||||
"; $%04" PRIx16 "]",
|
||||
section.name.c_str(),
|
||||
section.org,
|
||||
sectionTypeInfo[section.type].startAddr,
|
||||
sectTypeEndAddr(section.type)
|
||||
typeInfo.startAddr,
|
||||
typeInfo.endAddr()
|
||||
);
|
||||
}
|
||||
|
||||
if (section.org + section.size > sectTypeEndAddr(section.type) + 1) {
|
||||
if (section.org + section.size > typeInfo.endAddr() + 1) {
|
||||
error(
|
||||
"Section \"%s\"'s end address $%04x is greater than last address $%04x",
|
||||
section.name.c_str(),
|
||||
section.org + section.size,
|
||||
sectTypeEndAddr(section.type) + 1
|
||||
typeInfo.endAddr() + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user