mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-21 18:52:07 +00:00
Always use braces with InsertBraces: true in .clang-format
This commit is contained in:
@@ -74,14 +74,17 @@ static void assignSection(Section §ion, MemoryLocation const &location) {
|
||||
static bool isLocationSuitable(
|
||||
Section const §ion, FreeSpace const &freeSpace, MemoryLocation const &location
|
||||
) {
|
||||
if (section.isAddressFixed && section.org != location.address)
|
||||
if (section.isAddressFixed && section.org != location.address) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (section.isAlignFixed && ((location.address - section.alignOfs) & section.alignMask))
|
||||
if (section.isAlignFixed && ((location.address - section.alignOfs) & section.alignMask)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (location.address < freeSpace.address)
|
||||
if (location.address < freeSpace.address) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return location.address + section.size <= freeSpace.address + freeSpace.size;
|
||||
}
|
||||
@@ -102,16 +105,19 @@ static ssize_t getPlacement(Section const §ion, MemoryLocation &location) {
|
||||
if (section.isBankFixed) {
|
||||
location.bank = section.bank;
|
||||
} else if (scrambleROMX && section.type == SECTTYPE_ROMX) {
|
||||
if (curScrambleROM < 1)
|
||||
if (curScrambleROM < 1) {
|
||||
curScrambleROM = scrambleROMX;
|
||||
}
|
||||
location.bank = curScrambleROM--;
|
||||
} else if (scrambleWRAMX && section.type == SECTTYPE_WRAMX) {
|
||||
if (curScrambleWRAM < 1)
|
||||
if (curScrambleWRAM < 1) {
|
||||
curScrambleWRAM = scrambleWRAMX;
|
||||
}
|
||||
location.bank = curScrambleWRAM--;
|
||||
} else if (scrambleSRAM && section.type == SECTTYPE_SRAM) {
|
||||
if (curScrambleSRAM < 0)
|
||||
if (curScrambleSRAM < 0) {
|
||||
curScrambleSRAM = scrambleSRAM;
|
||||
}
|
||||
location.bank = curScrambleSRAM--;
|
||||
} else {
|
||||
location.bank = typeInfo.firstBank;
|
||||
@@ -128,18 +134,20 @@ static ssize_t getPlacement(Section const §ion, MemoryLocation &location) {
|
||||
// Process locations in that bank
|
||||
while (spaceIdx < bankMem.size()) {
|
||||
// If that location is OK, return it
|
||||
if (isLocationSuitable(section, bankMem[spaceIdx], location))
|
||||
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)
|
||||
if (location.address < section.org) {
|
||||
location.address = section.org;
|
||||
else
|
||||
} else {
|
||||
break; // Try again in next bank
|
||||
}
|
||||
} else if (section.isAlignFixed) {
|
||||
// Move to next aligned location
|
||||
// Move back to alignment boundary
|
||||
@@ -151,15 +159,17 @@ static ssize_t getPlacement(Section const §ion, MemoryLocation &location) {
|
||||
} else {
|
||||
// Any location is fine, so, next free block
|
||||
spaceIdx++;
|
||||
if (spaceIdx < bankMem.size())
|
||||
if (spaceIdx < bankMem.size()) {
|
||||
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)
|
||||
&& location.address >= bankMem[spaceIdx].address + bankMem[spaceIdx].size) {
|
||||
spaceIdx++;
|
||||
}
|
||||
|
||||
// Try again with the new location/free space combo
|
||||
}
|
||||
@@ -171,27 +181,30 @@ static ssize_t getPlacement(Section const §ion, MemoryLocation &location) {
|
||||
if (section.isBankFixed) {
|
||||
return -1;
|
||||
} else if (scrambleROMX && section.type == SECTTYPE_ROMX && location.bank <= scrambleROMX) {
|
||||
if (location.bank > typeInfo.firstBank)
|
||||
if (location.bank > typeInfo.firstBank) {
|
||||
location.bank--;
|
||||
else if (scrambleROMX < typeInfo.lastBank)
|
||||
} else if (scrambleROMX < typeInfo.lastBank) {
|
||||
location.bank = scrambleROMX + 1;
|
||||
else
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if (scrambleWRAMX && section.type == SECTTYPE_WRAMX
|
||||
&& location.bank <= scrambleWRAMX) {
|
||||
if (location.bank > typeInfo.firstBank)
|
||||
if (location.bank > typeInfo.firstBank) {
|
||||
location.bank--;
|
||||
else if (scrambleWRAMX < typeInfo.lastBank)
|
||||
} else if (scrambleWRAMX < typeInfo.lastBank) {
|
||||
location.bank = scrambleWRAMX + 1;
|
||||
else
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if (scrambleSRAM && section.type == SECTTYPE_SRAM && location.bank <= scrambleSRAM) {
|
||||
if (location.bank > typeInfo.firstBank)
|
||||
if (location.bank > typeInfo.firstBank) {
|
||||
location.bank--;
|
||||
else if (scrambleSRAM < typeInfo.lastBank)
|
||||
} else if (scrambleSRAM < typeInfo.lastBank) {
|
||||
location.bank = scrambleSRAM + 1;
|
||||
else
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if (location.bank < typeInfo.lastBank) {
|
||||
location.bank++;
|
||||
} else {
|
||||
@@ -251,9 +264,10 @@ static void placeSection(Section §ion) {
|
||||
} else {
|
||||
// The amount of free spaces doesn't change: resize!
|
||||
freeSpace.size -= section.size;
|
||||
if (noLeftSpace)
|
||||
if (noLeftSpace) {
|
||||
// The free space is moved *and* resized
|
||||
freeSpace.address += section.size;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -262,11 +276,11 @@ static void placeSection(Section §ion) {
|
||||
char where[64];
|
||||
|
||||
if (section.isBankFixed && nbbanks(section.type) != 1) {
|
||||
if (section.isAddressFixed)
|
||||
if (section.isAddressFixed) {
|
||||
snprintf(
|
||||
where, sizeof(where), "at $%02" PRIx32 ":%04" PRIx16, section.bank, section.org
|
||||
);
|
||||
else if (section.isAlignFixed)
|
||||
} else if (section.isAlignFixed) {
|
||||
snprintf(
|
||||
where,
|
||||
sizeof(where),
|
||||
@@ -274,12 +288,13 @@ static void placeSection(Section §ion) {
|
||||
section.bank,
|
||||
static_cast<uint16_t>(~section.alignMask)
|
||||
);
|
||||
else
|
||||
} else {
|
||||
snprintf(where, sizeof(where), "in bank $%02" PRIx32, section.bank);
|
||||
}
|
||||
} else {
|
||||
if (section.isAddressFixed)
|
||||
if (section.isAddressFixed) {
|
||||
snprintf(where, sizeof(where), "at address $%04" PRIx16, section.org);
|
||||
else if (section.isAlignFixed)
|
||||
} else if (section.isAlignFixed) {
|
||||
snprintf(
|
||||
where,
|
||||
sizeof(where),
|
||||
@@ -287,20 +302,22 @@ static void placeSection(Section §ion) {
|
||||
static_cast<uint16_t>(~section.alignMask),
|
||||
section.alignOfs
|
||||
);
|
||||
else
|
||||
} else {
|
||||
strcpy(where, "anywhere");
|
||||
}
|
||||
}
|
||||
|
||||
// If a section failed to go to several places, nothing we can report
|
||||
if (!section.isBankFixed || !section.isAddressFixed)
|
||||
if (!section.isBankFixed || !section.isAddressFixed) {
|
||||
errx(
|
||||
"Unable to place \"%s\" (%s section) %s",
|
||||
section.name.c_str(),
|
||||
sectionTypeInfo[section.type].name.c_str(),
|
||||
where
|
||||
);
|
||||
}
|
||||
// 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) {
|
||||
errx(
|
||||
"Unable to place \"%s\" (%s section) %s: section runs past end of region ($%04x > "
|
||||
"$%04x)",
|
||||
@@ -310,8 +327,9 @@ static void placeSection(Section §ion) {
|
||||
section.org + section.size,
|
||||
endaddr(section.type) + 1
|
||||
);
|
||||
}
|
||||
// Otherwise there is overlap with another section
|
||||
else
|
||||
else {
|
||||
errx(
|
||||
"Unable to place \"%s\" (%s section) %s: section overlaps with \"%s\"",
|
||||
section.name.c_str(),
|
||||
@@ -319,6 +337,7 @@ static void placeSection(Section §ion) {
|
||||
where,
|
||||
out_OverlappingSection(section)->name.c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off: vertically align values
|
||||
@@ -334,20 +353,24 @@ static std::deque<Section *> unassignedSections[1 << 3];
|
||||
static void categorizeSection(Section §ion) {
|
||||
uint8_t constraints = 0;
|
||||
|
||||
if (section.isBankFixed)
|
||||
if (section.isBankFixed) {
|
||||
constraints |= BANK_CONSTRAINED;
|
||||
if (section.isAddressFixed)
|
||||
}
|
||||
if (section.isAddressFixed) {
|
||||
constraints |= ORG_CONSTRAINED;
|
||||
}
|
||||
// Can't have both!
|
||||
else if (section.isAlignFixed)
|
||||
else if (section.isAlignFixed) {
|
||||
constraints |= ALIGN_CONSTRAINED;
|
||||
}
|
||||
|
||||
std::deque<Section *> §ions = unassignedSections[constraints];
|
||||
auto pos = sections.begin();
|
||||
|
||||
// Insert section while keeping the list sorted by decreasing size
|
||||
while (pos != sections.end() && (*pos)->size > section.size)
|
||||
while (pos != sections.end() && (*pos)->size > section.size) {
|
||||
pos++;
|
||||
}
|
||||
sections.insert(pos, §ion);
|
||||
|
||||
nbSectionsToAssign++;
|
||||
@@ -368,12 +391,14 @@ void assign_AssignSections() {
|
||||
|
||||
// Specially process fully-constrained sections because of overlaying
|
||||
verbosePrint("Assigning bank+org-constrained...\n");
|
||||
for (Section *section : unassignedSections[BANK_CONSTRAINED | ORG_CONSTRAINED])
|
||||
for (Section *section : unassignedSections[BANK_CONSTRAINED | ORG_CONSTRAINED]) {
|
||||
placeSection(*section);
|
||||
}
|
||||
|
||||
// If all sections were fully constrained, we have nothing left to do
|
||||
if (!nbSectionsToAssign)
|
||||
if (!nbSectionsToAssign) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Overlaying requires only fully-constrained sections
|
||||
verbosePrint("Assigning other sections...\n");
|
||||
@@ -385,14 +410,16 @@ void assign_AssignSections() {
|
||||
for (Section *section : unassignedSections[constraints]) {
|
||||
fprintf(stderr, "%c \"%s\"", nbSections == 0 ? ';' : ',', section->name.c_str());
|
||||
nbSections++;
|
||||
if (nbSections == 10)
|
||||
if (nbSections == 10) {
|
||||
goto max_out; // Can't `break` out of a nested loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
max_out:
|
||||
if (nbSectionsToAssign != nbSections)
|
||||
if (nbSectionsToAssign != nbSections) {
|
||||
fprintf(stderr, " and %" PRIu64 " more", nbSectionsToAssign - nbSections);
|
||||
}
|
||||
fprintf(stderr, " %sn't\n", nbSectionsToAssign == 1 ? "is" : "are");
|
||||
exit(1);
|
||||
}
|
||||
@@ -400,11 +427,13 @@ max_out:
|
||||
// Assign all remaining sections by decreasing constraint order
|
||||
for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED; constraints >= 0;
|
||||
constraints--) {
|
||||
for (Section *section : unassignedSections[constraints])
|
||||
for (Section *section : unassignedSections[constraints]) {
|
||||
placeSection(*section);
|
||||
}
|
||||
|
||||
if (!nbSectionsToAssign)
|
||||
if (!nbSectionsToAssign) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
unreachable_();
|
||||
|
||||
@@ -52,8 +52,9 @@ std::string const &FileStackNode::dump(uint32_t curLineNo) const {
|
||||
std::string const &lastName = parent->dump(lineNo);
|
||||
fputs(" -> ", stderr);
|
||||
fputs(lastName.c_str(), stderr);
|
||||
for (uint32_t iter : iters())
|
||||
for (uint32_t iter : iters()) {
|
||||
fprintf(stderr, "::REPT~%" PRIu32, iter);
|
||||
}
|
||||
fprintf(stderr, "(%" PRIu32 ")", curLineNo);
|
||||
return lastName;
|
||||
} else {
|
||||
@@ -96,8 +97,9 @@ void error(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) {
|
||||
printDiag(fmt, args, "error", where, lineNo);
|
||||
va_end(args);
|
||||
|
||||
if (nbErrors != UINT32_MAX)
|
||||
if (nbErrors != UINT32_MAX) {
|
||||
nbErrors++;
|
||||
}
|
||||
}
|
||||
|
||||
void argErr(char flag, char const *fmt, ...) {
|
||||
@@ -109,8 +111,9 @@ void argErr(char flag, char const *fmt, ...) {
|
||||
va_end(args);
|
||||
putc('\n', stderr);
|
||||
|
||||
if (nbErrors != UINT32_MAX)
|
||||
if (nbErrors != UINT32_MAX) {
|
||||
nbErrors++;
|
||||
}
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
@@ -121,8 +124,9 @@ void fatal(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) {
|
||||
printDiag(fmt, args, "FATAL", where, lineNo);
|
||||
va_end(args);
|
||||
|
||||
if (nbErrors != UINT32_MAX)
|
||||
if (nbErrors != UINT32_MAX) {
|
||||
nbErrors++;
|
||||
}
|
||||
|
||||
fprintf(
|
||||
stderr, "Linking aborted after %" PRIu32 " error%s\n", nbErrors, nbErrors == 1 ? "" : "s"
|
||||
@@ -216,10 +220,12 @@ static void parseScrambleSpec(char const *spec) {
|
||||
if (regionNameLen == 0) {
|
||||
argErr('S', "Missing region name");
|
||||
|
||||
if (*spec == '\0')
|
||||
if (*spec == '\0') {
|
||||
break;
|
||||
if (*spec == '=') // Skip the limit, too
|
||||
}
|
||||
if (*spec == '=') { // Skip the limit, too
|
||||
spec = strchr(&spec[1], ','); // Skip to next comma, if any
|
||||
}
|
||||
goto next;
|
||||
}
|
||||
|
||||
@@ -242,8 +248,9 @@ static void parseScrambleSpec(char const *spec) {
|
||||
}
|
||||
}
|
||||
|
||||
if (region == SCRAMBLE_UNK)
|
||||
if (region == SCRAMBLE_UNK) {
|
||||
argErr('S', "Unknown region \"%.*s\"", regionNameFmtLen, regionName);
|
||||
}
|
||||
|
||||
if (*spec == '=') {
|
||||
spec++; // `strtoul` will skip the whitespace on its own
|
||||
@@ -301,10 +308,12 @@ static void parseScrambleSpec(char const *spec) {
|
||||
next: // Can't `continue` a `for` loop with this nontrivial iteration logic
|
||||
if (spec) {
|
||||
assume(*spec == ',' || *spec == '\0');
|
||||
if (*spec == ',')
|
||||
if (*spec == ',') {
|
||||
spec += 1 + strspn(&spec[1], " \t");
|
||||
if (*spec == '\0')
|
||||
}
|
||||
if (*spec == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -329,31 +338,36 @@ int main(int argc, char *argv[]) {
|
||||
printUsage();
|
||||
exit(0);
|
||||
case 'l':
|
||||
if (linkerScriptName)
|
||||
if (linkerScriptName) {
|
||||
warnx("Overriding linker script %s", linkerScriptName);
|
||||
}
|
||||
linkerScriptName = musl_optarg;
|
||||
break;
|
||||
case 'M':
|
||||
noSymInMap = true;
|
||||
break;
|
||||
case 'm':
|
||||
if (mapFileName)
|
||||
if (mapFileName) {
|
||||
warnx("Overriding map file %s", mapFileName);
|
||||
}
|
||||
mapFileName = musl_optarg;
|
||||
break;
|
||||
case 'n':
|
||||
if (symFileName)
|
||||
if (symFileName) {
|
||||
warnx("Overriding sym file %s", symFileName);
|
||||
}
|
||||
symFileName = musl_optarg;
|
||||
break;
|
||||
case 'O':
|
||||
if (overlayFileName)
|
||||
if (overlayFileName) {
|
||||
warnx("Overriding overlay file %s", overlayFileName);
|
||||
}
|
||||
overlayFileName = musl_optarg;
|
||||
break;
|
||||
case 'o':
|
||||
if (outputFileName)
|
||||
if (outputFileName) {
|
||||
warnx("Overriding output file %s", outputFileName);
|
||||
}
|
||||
outputFileName = musl_optarg;
|
||||
break;
|
||||
case 'p': {
|
||||
@@ -410,18 +424,22 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
// Patch the size array depending on command-line options
|
||||
if (!is32kMode)
|
||||
if (!is32kMode) {
|
||||
sectionTypeInfo[SECTTYPE_ROM0].size = 0x4000;
|
||||
if (!isWRAM0Mode)
|
||||
}
|
||||
if (!isWRAM0Mode) {
|
||||
sectionTypeInfo[SECTTYPE_WRAM0].size = 0x1000;
|
||||
}
|
||||
|
||||
// Patch the bank ranges array depending on command-line options
|
||||
if (isDmgMode)
|
||||
if (isDmgMode) {
|
||||
sectionTypeInfo[SECTTYPE_VRAM].lastBank = 0;
|
||||
}
|
||||
|
||||
// Read all object files first,
|
||||
for (obj_Setup(argc - curArgIndex); curArgIndex < argc; curArgIndex++)
|
||||
for (obj_Setup(argc - curArgIndex); curArgIndex < argc; curArgIndex++) {
|
||||
obj_ReadFile(argv[curArgIndex], argc - curArgIndex - 1);
|
||||
}
|
||||
|
||||
// apply the linker script's modifications,
|
||||
if (linkerScriptName) {
|
||||
@@ -430,20 +448,23 @@ int main(int argc, char *argv[]) {
|
||||
script_ProcessScript(linkerScriptName);
|
||||
|
||||
// If the linker script produced any errors, some sections may be in an invalid state
|
||||
if (nbErrors != 0)
|
||||
if (nbErrors != 0) {
|
||||
reportErrors();
|
||||
}
|
||||
}
|
||||
|
||||
// then process them,
|
||||
sect_DoSanityChecks();
|
||||
if (nbErrors != 0)
|
||||
if (nbErrors != 0) {
|
||||
reportErrors();
|
||||
}
|
||||
assign_AssignSections();
|
||||
patch_CheckAssertions();
|
||||
|
||||
// and finally output the result.
|
||||
patch_ApplyPatches();
|
||||
if (nbErrors != 0)
|
||||
if (nbErrors != 0) {
|
||||
reportErrors();
|
||||
}
|
||||
out_WriteFiles();
|
||||
}
|
||||
|
||||
@@ -51,8 +51,9 @@ static int64_t readLong(FILE *file) {
|
||||
for (uint8_t shift = 0; shift < sizeof(value) * CHAR_BIT; shift += 8) {
|
||||
int byte = getc(file);
|
||||
|
||||
if (byte == EOF)
|
||||
if (byte == EOF) {
|
||||
return INT64_MAX;
|
||||
}
|
||||
// This must be casted to `unsigned`, not `uint8_t`. Rationale:
|
||||
// the type of the shift is the type of `byte` after undergoing
|
||||
// integer promotion, which would be `int` if this was casted to
|
||||
@@ -141,7 +142,7 @@ static void readFileStackNode(
|
||||
case NODE_REPT:
|
||||
tryReadLong(depth, file, "%s: Cannot read node #%" PRIu32 "'s rept depth: %s", fileName, i);
|
||||
node.data = std::vector<uint32_t>(depth);
|
||||
for (uint32_t k = 0; k < depth; k++)
|
||||
for (uint32_t k = 0; k < depth; k++) {
|
||||
tryReadLong(
|
||||
node.iters()[k],
|
||||
file,
|
||||
@@ -150,7 +151,8 @@ static void readFileStackNode(
|
||||
i,
|
||||
k
|
||||
);
|
||||
if (!node.parent)
|
||||
}
|
||||
if (!node.parent) {
|
||||
fatal(
|
||||
nullptr,
|
||||
0,
|
||||
@@ -158,6 +160,7 @@ static void readFileStackNode(
|
||||
fileName,
|
||||
i
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,7 +299,7 @@ static void readPatch(
|
||||
patch.rpnExpression.resize(rpnSize);
|
||||
size_t nbElementsRead = fread(patch.rpnExpression.data(), 1, rpnSize, file);
|
||||
|
||||
if (nbElementsRead != rpnSize)
|
||||
if (nbElementsRead != rpnSize) {
|
||||
errx(
|
||||
"%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s RPN expression: %s",
|
||||
fileName,
|
||||
@@ -304,6 +307,7 @@ static void readPatch(
|
||||
i,
|
||||
feof(file) ? "Unexpected end of file" : strerror(errno)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Sets a patch's pcSection from its pcSectionID.
|
||||
@@ -338,8 +342,9 @@ static void readSection(
|
||||
section.name.c_str()
|
||||
);
|
||||
tryReadLong(tmp, file, "%s: Cannot read \"%s\"'s' size: %s", fileName, section.name.c_str());
|
||||
if (tmp < 0 || tmp > UINT16_MAX)
|
||||
if (tmp < 0 || tmp > UINT16_MAX) {
|
||||
errx("\"%s\"'s section size ($%" PRIx32 ") is invalid", section.name.c_str(), tmp);
|
||||
}
|
||||
section.size = tmp;
|
||||
section.offset = 0;
|
||||
tryGetc(
|
||||
@@ -350,12 +355,13 @@ static void readSection(
|
||||
} else {
|
||||
section.type = SectionType(type);
|
||||
}
|
||||
if (byte >> 7)
|
||||
if (byte >> 7) {
|
||||
section.modifier = SECTION_UNION;
|
||||
else if (byte >> 6)
|
||||
} else if (byte >> 6) {
|
||||
section.modifier = SECTION_FRAGMENT;
|
||||
else
|
||||
} else {
|
||||
section.modifier = SECTION_NORMAL;
|
||||
}
|
||||
tryReadLong(tmp, file, "%s: Cannot read \"%s\"'s org: %s", fileName, section.name.c_str());
|
||||
section.isAddressFixed = tmp >= 0;
|
||||
if (tmp > UINT16_MAX) {
|
||||
@@ -374,8 +380,9 @@ static void readSection(
|
||||
fileName,
|
||||
section.name.c_str()
|
||||
);
|
||||
if (byte > 16)
|
||||
if (byte > 16) {
|
||||
byte = 16;
|
||||
}
|
||||
section.isAlignFixed = byte != 0;
|
||||
section.alignMask = (1 << byte) - 1;
|
||||
tryReadLong(
|
||||
@@ -397,13 +404,14 @@ static void readSection(
|
||||
if (section.size) {
|
||||
section.data.resize(section.size);
|
||||
if (size_t nbRead = fread(section.data.data(), 1, section.size, file);
|
||||
nbRead != section.size)
|
||||
nbRead != section.size) {
|
||||
errx(
|
||||
"%s: Cannot read \"%s\"'s data: %s",
|
||||
fileName,
|
||||
section.name.c_str(),
|
||||
feof(file) ? "Unexpected end of file" : strerror(errno)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t nbPatches;
|
||||
@@ -417,8 +425,9 @@ static void readSection(
|
||||
);
|
||||
|
||||
section.patches.resize(nbPatches);
|
||||
for (uint32_t i = 0; i < nbPatches; i++)
|
||||
for (uint32_t i = 0; i < nbPatches; i++) {
|
||||
readPatch(file, section.patches[i], fileName, section.name, i, fileNodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,10 +442,11 @@ static void linkSymToSect(Symbol &symbol, Section §ion) {
|
||||
uint32_t c = (a + b) / 2;
|
||||
int32_t otherOffset = section.symbols[c]->label().offset;
|
||||
|
||||
if (otherOffset > symbolOffset)
|
||||
if (otherOffset > symbolOffset) {
|
||||
b = c;
|
||||
else
|
||||
} else {
|
||||
a = c + 1;
|
||||
}
|
||||
}
|
||||
|
||||
section.symbols.insert(section.symbols.begin() + a, &symbol);
|
||||
@@ -469,8 +479,9 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) {
|
||||
(void)setmode(STDIN_FILENO, O_BINARY);
|
||||
file = stdin;
|
||||
}
|
||||
if (!file)
|
||||
if (!file) {
|
||||
err("Failed to open file \"%s\"", fileName);
|
||||
}
|
||||
Defer closeFile{[&] { fclose(file); }};
|
||||
|
||||
// First, check if the object is a RGBDS object or a SDCC one. If the first byte is 'R',
|
||||
@@ -506,15 +517,16 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) {
|
||||
int matchedElems;
|
||||
|
||||
if (fscanf(file, RGBDS_OBJECT_VERSION_STRING "%n", &matchedElems) == 1
|
||||
&& matchedElems != literal_strlen(RGBDS_OBJECT_VERSION_STRING))
|
||||
&& matchedElems != literal_strlen(RGBDS_OBJECT_VERSION_STRING)) {
|
||||
errx("%s: Not a RGBDS object file", fileName);
|
||||
}
|
||||
|
||||
verbosePrint("Reading object file %s\n", fileName);
|
||||
|
||||
uint32_t revNum;
|
||||
|
||||
tryReadLong(revNum, file, "%s: Cannot read revision number: %s", fileName);
|
||||
if (revNum != RGBDS_OBJECT_REV)
|
||||
if (revNum != RGBDS_OBJECT_REV) {
|
||||
errx(
|
||||
"%s: Unsupported object file for rgblink %s; try rebuilding \"%s\"%s"
|
||||
" (expected revision %d, got %d)",
|
||||
@@ -525,6 +537,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) {
|
||||
RGBDS_OBJECT_REV,
|
||||
revNum
|
||||
);
|
||||
}
|
||||
|
||||
uint32_t nbNodes;
|
||||
uint32_t nbSymbols;
|
||||
@@ -538,8 +551,9 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) {
|
||||
tryReadLong(nbNodes, file, "%s: Cannot read number of nodes: %s", fileName);
|
||||
nodes[fileID].resize(nbNodes);
|
||||
verbosePrint("Reading %u nodes...\n", nbNodes);
|
||||
for (uint32_t i = nbNodes; i--;)
|
||||
for (uint32_t i = nbNodes; i--;) {
|
||||
readFileStackNode(file, nodes[fileID], i, fileName);
|
||||
}
|
||||
|
||||
// This file's symbols, kept to link sections to them
|
||||
std::vector<Symbol> &fileSymbols = symbolLists.emplace_front(nbSymbols);
|
||||
@@ -553,8 +567,9 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) {
|
||||
readSymbol(file, symbol, fileName, nodes[fileID]);
|
||||
|
||||
sym_AddSymbol(symbol);
|
||||
if (symbol.data.holds<Label>())
|
||||
if (symbol.data.holds<Label>()) {
|
||||
nbSymPerSect[symbol.data.get<Label>().sectionID]++;
|
||||
}
|
||||
}
|
||||
|
||||
// This file's sections, stored in a table to link symbols to them
|
||||
@@ -585,8 +600,9 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) {
|
||||
// Give patches' PC section pointers to their sections
|
||||
for (uint32_t i = 0; i < nbSections; i++) {
|
||||
if (sect_HasData(fileSections[i]->type)) {
|
||||
for (Patch &patch : fileSections[i]->patches)
|
||||
for (Patch &patch : fileSections[i]->patches) {
|
||||
linkPatchToPCSect(patch, fileSections);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,8 +617,9 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) {
|
||||
}
|
||||
|
||||
// Calling `sect_AddSection` invalidates the contents of `fileSections`!
|
||||
for (uint32_t i = 0; i < nbSections; i++)
|
||||
for (uint32_t i = 0; i < nbSections; i++) {
|
||||
sect_AddSection(std::move(fileSections[i]));
|
||||
}
|
||||
|
||||
// Fix symbols' section pointers to component sections
|
||||
// This has to run **after** all the `sect_AddSection()` calls,
|
||||
|
||||
@@ -66,24 +66,27 @@ void out_AddSection(Section const §ion) {
|
||||
uint32_t targetBank = section.bank - sectionTypeInfo[section.type].firstBank;
|
||||
uint32_t minNbBanks = targetBank + 1;
|
||||
|
||||
if (minNbBanks > maxNbBanks[section.type])
|
||||
if (minNbBanks > maxNbBanks[section.type]) {
|
||||
errx(
|
||||
"Section \"%s\" has an invalid bank range (%" PRIu32 " > %" PRIu32 ")",
|
||||
section.name.c_str(),
|
||||
section.bank,
|
||||
maxNbBanks[section.type] - 1
|
||||
);
|
||||
}
|
||||
|
||||
for (uint32_t i = sections[section.type].size(); i < minNbBanks; i++)
|
||||
for (uint32_t i = sections[section.type].size(); i < minNbBanks; i++) {
|
||||
sections[section.type].emplace_back();
|
||||
}
|
||||
|
||||
std::deque<Section const *> &bankSections =
|
||||
section.size ? sections[section.type][targetBank].sections
|
||||
: sections[section.type][targetBank].zeroLenSections;
|
||||
auto pos = bankSections.begin();
|
||||
|
||||
while (pos != bankSections.end() && (*pos)->org < section.org)
|
||||
while (pos != bankSections.end() && (*pos)->org < section.org) {
|
||||
pos++;
|
||||
}
|
||||
|
||||
bankSections.insert(pos, §ion);
|
||||
}
|
||||
@@ -92,8 +95,9 @@ Section const *out_OverlappingSection(Section const §ion) {
|
||||
uint32_t bank = section.bank - sectionTypeInfo[section.type].firstBank;
|
||||
|
||||
for (Section const *ptr : sections[section.type][bank].sections) {
|
||||
if (ptr->org < section.org + section.size && section.org < ptr->org + ptr->size)
|
||||
if (ptr->org < section.org + section.size && section.org < ptr->org + ptr->size) {
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -101,8 +105,9 @@ Section const *out_OverlappingSection(Section const §ion) {
|
||||
// Performs sanity checks on the overlay file.
|
||||
// @return The number of ROM banks in the overlay file
|
||||
static uint32_t checkOverlaySize() {
|
||||
if (!overlayFile)
|
||||
if (!overlayFile) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fseek(overlayFile, 0, SEEK_END) != 0) {
|
||||
warnx("Overlay file is not seekable, cannot check if properly formed");
|
||||
@@ -114,12 +119,13 @@ static uint32_t checkOverlaySize() {
|
||||
// Reset back to beginning
|
||||
fseek(overlayFile, 0, SEEK_SET);
|
||||
|
||||
if (overlaySize % BANK_SIZE)
|
||||
if (overlaySize % BANK_SIZE) {
|
||||
warnx("Overlay file does not have a size multiple of 0x4000");
|
||||
else if (is32kMode && overlaySize != 0x8000)
|
||||
} else if (is32kMode && overlaySize != 0x8000) {
|
||||
warnx("Overlay is not exactly 0x8000 bytes large");
|
||||
else if (overlaySize < 0x8000)
|
||||
} else if (overlaySize < 0x8000) {
|
||||
warnx("Overlay is less than 0x8000 bytes large");
|
||||
}
|
||||
|
||||
return (overlaySize + BANK_SIZE - 1) / BANK_SIZE;
|
||||
}
|
||||
@@ -137,8 +143,9 @@ static void coverOverlayBanks(uint32_t nbOverlayBanks) {
|
||||
: 0;
|
||||
|
||||
if (nbUncoveredBanks > sections[SECTTYPE_ROMX].size()) {
|
||||
for (uint32_t i = sections[SECTTYPE_ROMX].size(); i < nbUncoveredBanks; i++)
|
||||
for (uint32_t i = sections[SECTTYPE_ROMX].size(); i < nbUncoveredBanks; i++) {
|
||||
sections[SECTTYPE_ROMX].emplace_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,8 +186,9 @@ static void
|
||||
fwrite(section->data.data(), 1, section->size, outputFile);
|
||||
if (overlayFile) {
|
||||
// Skip bytes even with pipes
|
||||
for (uint16_t i = 0; i < section->size; i++)
|
||||
for (uint16_t i = 0; i < section->size; i++) {
|
||||
getc(overlayFile);
|
||||
}
|
||||
}
|
||||
offset += section->size;
|
||||
}
|
||||
@@ -204,12 +212,14 @@ static void writeROM() {
|
||||
(void)setmode(STDOUT_FILENO, O_BINARY);
|
||||
outputFile = stdout;
|
||||
}
|
||||
if (!outputFile)
|
||||
if (!outputFile) {
|
||||
err("Failed to open output file \"%s\"", outputFileName);
|
||||
}
|
||||
}
|
||||
Defer closeOutputFile{[&] {
|
||||
if (outputFile)
|
||||
if (outputFile) {
|
||||
fclose(outputFile);
|
||||
}
|
||||
}};
|
||||
|
||||
if (overlayFileName) {
|
||||
@@ -220,18 +230,21 @@ static void writeROM() {
|
||||
(void)setmode(STDIN_FILENO, O_BINARY);
|
||||
overlayFile = stdin;
|
||||
}
|
||||
if (!overlayFile)
|
||||
if (!overlayFile) {
|
||||
err("Failed to open overlay file \"%s\"", overlayFileName);
|
||||
}
|
||||
}
|
||||
Defer closeOverlayFile{[&] {
|
||||
if (overlayFile)
|
||||
if (overlayFile) {
|
||||
fclose(overlayFile);
|
||||
}
|
||||
}};
|
||||
|
||||
uint32_t nbOverlayBanks = checkOverlaySize();
|
||||
|
||||
if (nbOverlayBanks > 0)
|
||||
if (nbOverlayBanks > 0) {
|
||||
coverOverlayBanks(nbOverlayBanks);
|
||||
}
|
||||
|
||||
if (outputFile) {
|
||||
writeBank(
|
||||
@@ -240,12 +253,13 @@ static void writeROM() {
|
||||
sectionTypeInfo[SECTTYPE_ROM0].size
|
||||
);
|
||||
|
||||
for (uint32_t i = 0; i < sections[SECTTYPE_ROMX].size(); i++)
|
||||
for (uint32_t i = 0; i < sections[SECTTYPE_ROMX].size(); i++) {
|
||||
writeBank(
|
||||
§ions[SECTTYPE_ROMX][i].sections,
|
||||
sectionTypeInfo[SECTTYPE_ROMX].startAddr,
|
||||
sectionTypeInfo[SECTTYPE_ROMX].size
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,8 +296,9 @@ static void printSymName(std::string const &name, FILE *file) {
|
||||
codepoint = 0xFFFD;
|
||||
// Skip continuation bytes
|
||||
// A NUL byte does not qualify, so we're good
|
||||
while ((*ptr & 0xC0) == 0x80)
|
||||
while ((*ptr & 0xC0) == 0x80) {
|
||||
++ptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
++ptr;
|
||||
@@ -297,8 +312,9 @@ static void printSymName(std::string const &name, FILE *file) {
|
||||
// Comparator function for `std::stable_sort` to sort symbols
|
||||
// Symbols are ordered by address, then by parentage
|
||||
static bool compareSymbols(SortedSymbol const &sym1, SortedSymbol const &sym2) {
|
||||
if (sym1.addr != sym2.addr)
|
||||
if (sym1.addr != sym2.addr) {
|
||||
return sym1.addr < sym2.addr;
|
||||
}
|
||||
|
||||
std::string const &sym1_name = sym1.sym->name;
|
||||
std::string const &sym2_name = sym2.sym->name;
|
||||
@@ -310,10 +326,12 @@ static bool compareSymbols(SortedSymbol const &sym1, SortedSymbol const &sym2) {
|
||||
size_t sym2_len = sym2_name.length();
|
||||
|
||||
// Sort parent labels before their child local labels
|
||||
if (sym2_name.starts_with(sym1_name) && sym2_name[sym1_len] == '.')
|
||||
if (sym2_name.starts_with(sym1_name) && sym2_name[sym1_len] == '.') {
|
||||
return true;
|
||||
if (sym1_name.starts_with(sym2_name) && sym1_name[sym2_len] == '.')
|
||||
}
|
||||
if (sym1_name.starts_with(sym2_name) && sym1_name[sym2_len] == '.') {
|
||||
return false;
|
||||
}
|
||||
// Sort local labels before unrelated global labels
|
||||
return sym1_local;
|
||||
}
|
||||
@@ -342,8 +360,9 @@ static void writeSymBank(SortedSections const &bankSections, SectionType type, u
|
||||
|
||||
forEachSortedSection(sect, { nbSymbols += sect->symbols.size(); });
|
||||
|
||||
if (!nbSymbols)
|
||||
if (!nbSymbols) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<SortedSymbol> symList;
|
||||
|
||||
@@ -352,11 +371,12 @@ static void writeSymBank(SortedSections const &bankSections, SectionType type, u
|
||||
forEachSortedSection(sect, {
|
||||
for (Symbol const *sym : sect->symbols) {
|
||||
// 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 = static_cast<uint16_t>(sym->label().offset + sect->org),
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -443,8 +463,9 @@ static void writeMapBank(SortedSections const §List, SectionType type, uint3
|
||||
prevEndAddr = sect->org + sect->size;
|
||||
|
||||
fprintf(mapFile, "\tSECTION: $%04" PRIx16, sect->org);
|
||||
if (sect->size != 0)
|
||||
if (sect->size != 0) {
|
||||
fprintf(mapFile, "-$%04x", prevEndAddr - 1);
|
||||
}
|
||||
fprintf(mapFile, " ($%04" PRIx16 " byte%s) [\"", sect->size, sect->size == 1 ? "" : "s");
|
||||
printSectionName(sect->name, mapFile);
|
||||
fputs("\"]\n", mapFile);
|
||||
@@ -461,10 +482,11 @@ static void writeMapBank(SortedSections const §List, SectionType type, uint3
|
||||
|
||||
if (sect->nextu) {
|
||||
// Announce the following "piece"
|
||||
if (sect->nextu->modifier == SECTION_UNION)
|
||||
if (sect->nextu->modifier == SECTION_UNION) {
|
||||
fprintf(mapFile, "\t ; Next union\n");
|
||||
else if (sect->nextu->modifier == SECTION_FRAGMENT)
|
||||
} else if (sect->nextu->modifier == SECTION_FRAGMENT) {
|
||||
fprintf(mapFile, "\t ; Next fragment\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -494,12 +516,14 @@ static void writeMapSummary() {
|
||||
uint32_t nbBanks = sections[type].size();
|
||||
|
||||
// Do not output used space for VRAM or OAM
|
||||
if (type == SECTTYPE_VRAM || type == SECTTYPE_OAM)
|
||||
if (type == SECTTYPE_VRAM || type == SECTTYPE_OAM) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not output unused section types
|
||||
if (nbBanks == 0)
|
||||
if (nbBanks == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t usedTotal = 0;
|
||||
|
||||
@@ -532,16 +556,18 @@ static void writeMapSummary() {
|
||||
usedTotal == 1 ? "" : "s",
|
||||
nbBanks * sectionTypeInfo[type].size - usedTotal
|
||||
);
|
||||
if (sectionTypeInfo[type].firstBank != sectionTypeInfo[type].lastBank || nbBanks > 1)
|
||||
if (sectionTypeInfo[type].firstBank != sectionTypeInfo[type].lastBank || nbBanks > 1) {
|
||||
fprintf(mapFile, " in %u bank%s", nbBanks, nbBanks == 1 ? "" : "s");
|
||||
}
|
||||
putc('\n', mapFile);
|
||||
}
|
||||
}
|
||||
|
||||
// Writes the sym file, if applicable.
|
||||
static void writeSym() {
|
||||
if (!symFileName)
|
||||
if (!symFileName) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(symFileName, "-")) {
|
||||
symFile = fopen(symFileName, "w");
|
||||
@@ -550,8 +576,9 @@ static void writeSym() {
|
||||
(void)setmode(STDOUT_FILENO, O_TEXT); // May have been set to O_BINARY previously
|
||||
symFile = stdout;
|
||||
}
|
||||
if (!symFile)
|
||||
if (!symFile) {
|
||||
err("Failed to open sym file \"%s\"", symFileName);
|
||||
}
|
||||
Defer closeSymFile{[&] { fclose(symFile); }};
|
||||
|
||||
fputs("; File generated by rgblink\n", symFile);
|
||||
@@ -559,8 +586,9 @@ static void writeSym() {
|
||||
for (uint8_t i = 0; i < SECTTYPE_INVALID; i++) {
|
||||
SectionType type = typeMap[i];
|
||||
|
||||
for (uint32_t bank = 0; bank < sections[type].size(); bank++)
|
||||
for (uint32_t bank = 0; bank < sections[type].size(); bank++) {
|
||||
writeSymBank(sections[type][bank], type, bank);
|
||||
}
|
||||
}
|
||||
|
||||
// Output the exported numeric constants
|
||||
@@ -568,8 +596,9 @@ static void writeSym() {
|
||||
constants.clear();
|
||||
sym_ForEach([](Symbol &sym) {
|
||||
// Symbols are already limited to the exported ones
|
||||
if (sym.data.holds<int32_t>())
|
||||
if (sym.data.holds<int32_t>()) {
|
||||
constants.push_back(&sym);
|
||||
}
|
||||
});
|
||||
// Numeric constants are ordered by value, then by name
|
||||
std::sort(RANGE(constants), [](Symbol *sym1, Symbol *sym2) -> bool {
|
||||
@@ -587,8 +616,9 @@ static void writeSym() {
|
||||
|
||||
// Writes the map file, if applicable.
|
||||
static void writeMap() {
|
||||
if (!mapFileName)
|
||||
if (!mapFileName) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(mapFileName, "-")) {
|
||||
mapFile = fopen(mapFileName, "w");
|
||||
@@ -597,8 +627,9 @@ static void writeMap() {
|
||||
(void)setmode(STDOUT_FILENO, O_TEXT); // May have been set to O_BINARY previously
|
||||
mapFile = stdout;
|
||||
}
|
||||
if (!mapFile)
|
||||
if (!mapFile) {
|
||||
err("Failed to open map file \"%s\"", mapFileName);
|
||||
}
|
||||
Defer closeMapFile{[&] { fclose(mapFile); }};
|
||||
|
||||
writeMapSummary();
|
||||
@@ -606,8 +637,9 @@ static void writeMap() {
|
||||
for (uint8_t i = 0; i < SECTTYPE_INVALID; i++) {
|
||||
SectionType type = typeMap[i];
|
||||
|
||||
for (uint32_t bank = 0; bank < sections[type].size(); bank++)
|
||||
for (uint32_t bank = 0; bank < sections[type].size(); bank++) {
|
||||
writeMapBank(sections[type][bank], type, bank);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +33,9 @@ static void pushRPN(int32_t value, bool comesFromError) {
|
||||
static bool isError = false;
|
||||
|
||||
static int32_t popRPN(Patch const &patch) {
|
||||
if (rpnStack.empty())
|
||||
if (rpnStack.empty()) {
|
||||
fatal(patch.src, patch.lineNo, "Internal error, RPN stack empty");
|
||||
}
|
||||
|
||||
RPNStackEntry entry = rpnStack.front();
|
||||
|
||||
@@ -46,8 +47,9 @@ static int32_t popRPN(Patch const &patch) {
|
||||
// RPN operators
|
||||
|
||||
static uint32_t getRPNByte(uint8_t const *&expression, int32_t &size, Patch const &patch) {
|
||||
if (!size--)
|
||||
if (!size--) {
|
||||
fatal(patch.src, patch.lineNo, "Internal error, RPN expression overread");
|
||||
}
|
||||
|
||||
return *expression++;
|
||||
}
|
||||
@@ -57,8 +59,9 @@ static Symbol const *getSymbol(std::vector<Symbol> const &symbolList, uint32_t i
|
||||
Symbol const &symbol = symbolList[index];
|
||||
|
||||
// If the symbol is defined elsewhere...
|
||||
if (symbol.type == SYMTYPE_IMPORT)
|
||||
if (symbol.type == SYMTYPE_IMPORT) {
|
||||
return sym_GetSymbol(symbol.name);
|
||||
}
|
||||
|
||||
return &symbol;
|
||||
}
|
||||
@@ -218,8 +221,9 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
|
||||
case RPN_BANK_SYM:
|
||||
value = 0;
|
||||
for (uint8_t shift = 0; shift < 32; shift += 8)
|
||||
for (uint8_t shift = 0; shift < 32; shift += 8) {
|
||||
value |= getRPNByte(expression, size, patch) << shift;
|
||||
}
|
||||
|
||||
if (Symbol const *symbol = getSymbol(fileSymbols, value); !symbol) {
|
||||
error(
|
||||
@@ -377,14 +381,16 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
|
||||
case RPN_CONST:
|
||||
value = 0;
|
||||
for (uint8_t shift = 0; shift < 32; shift += 8)
|
||||
for (uint8_t shift = 0; shift < 32; shift += 8) {
|
||||
value |= getRPNByte(expression, size, patch) << shift;
|
||||
}
|
||||
break;
|
||||
|
||||
case RPN_SYM:
|
||||
value = 0;
|
||||
for (uint8_t shift = 0; shift < 32; shift += 8)
|
||||
for (uint8_t shift = 0; shift < 32; shift += 8) {
|
||||
value |= getRPNByte(expression, size, patch) << shift;
|
||||
}
|
||||
|
||||
if (value == -1) { // PC
|
||||
if (!patch.pcSection) {
|
||||
@@ -417,8 +423,9 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
pushRPN(value, isError);
|
||||
}
|
||||
|
||||
if (rpnStack.size() > 1)
|
||||
if (rpnStack.size() > 1) {
|
||||
error(patch.src, patch.lineNo, "RPN stack has %zu entries on exit, not 1", rpnStack.size());
|
||||
}
|
||||
|
||||
isError = false;
|
||||
return popRPN(patch);
|
||||
@@ -505,7 +512,7 @@ static void applyFilePatches(Section §ion, Section &dataSection) {
|
||||
uint16_t address = patch.pcSection->org + patch.pcOffset + 2;
|
||||
int16_t jumpOffset = value - address;
|
||||
|
||||
if (!isError && (jumpOffset < -128 || jumpOffset > 127))
|
||||
if (!isError && (jumpOffset < -128 || jumpOffset > 127)) {
|
||||
error(
|
||||
patch.src,
|
||||
patch.lineNo,
|
||||
@@ -513,10 +520,11 @@ static void applyFilePatches(Section §ion, Section &dataSection) {
|
||||
"; use jp instead\n",
|
||||
jumpOffset
|
||||
);
|
||||
}
|
||||
dataSection.data[offset] = jumpOffset & 0xFF;
|
||||
} else {
|
||||
// Patch a certain number of bytes
|
||||
if (!isError && (value < type.min || value > type.max))
|
||||
if (!isError && (value < type.min || value > type.max)) {
|
||||
error(
|
||||
patch.src,
|
||||
patch.lineNo,
|
||||
@@ -525,6 +533,7 @@ static void applyFilePatches(Section §ion, Section &dataSection) {
|
||||
value < 0 ? " (maybe negative?)" : "",
|
||||
type.size * 8U
|
||||
);
|
||||
}
|
||||
for (uint8_t i = 0; i < type.size; i++) {
|
||||
dataSection.data[offset + i] = value & 0xFF;
|
||||
value >>= 8;
|
||||
@@ -536,11 +545,13 @@ static void applyFilePatches(Section §ion, Section &dataSection) {
|
||||
// Applies all of a section's patches, iterating over "components" of unionized sections
|
||||
// @param section The section to patch
|
||||
static void applyPatches(Section §ion) {
|
||||
if (!sect_HasData(section.type))
|
||||
if (!sect_HasData(section.type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Section *component = §ion; component; component = component->nextu.get())
|
||||
for (Section *component = §ion; component; component = component->nextu.get()) {
|
||||
applyFilePatches(*component, section);
|
||||
}
|
||||
}
|
||||
|
||||
void patch_ApplyPatches() {
|
||||
|
||||
@@ -25,8 +25,9 @@ enum NumberType {
|
||||
};
|
||||
|
||||
static void consumeLF(FileStackNode const &where, uint32_t lineNo, FILE *file) {
|
||||
if (getc(file) != '\n')
|
||||
if (getc(file) != '\n') {
|
||||
fatal(&where, lineNo, "Bad line ending (CR without LF)");
|
||||
}
|
||||
}
|
||||
|
||||
static char const *delim = " \f\n\r\t\v"; // Whitespace according to the C and POSIX locales
|
||||
@@ -49,8 +50,9 @@ retry:
|
||||
} while (firstChar != EOF && firstChar != '\r' && firstChar != '\n');
|
||||
[[fallthrough]];
|
||||
case '\r':
|
||||
if (firstChar == '\r' && getc(file) != '\n')
|
||||
if (firstChar == '\r' && getc(file) != '\n') {
|
||||
consumeLF(where, lineNo, file);
|
||||
}
|
||||
[[fallthrough]];
|
||||
case '\n':
|
||||
goto retry;
|
||||
@@ -90,14 +92,16 @@ static uint32_t readNumber(char const *str, char const *&endptr, NumberType base
|
||||
|
||||
static uint32_t
|
||||
parseNumber(FileStackNode const &where, uint32_t lineNo, char const *str, NumberType base) {
|
||||
if (str[0] == '\0')
|
||||
if (str[0] == '\0') {
|
||||
fatal(&where, lineNo, "Expected number, got empty string");
|
||||
}
|
||||
|
||||
char const *endptr;
|
||||
uint32_t res = readNumber(str, endptr, base);
|
||||
|
||||
if (*endptr != '\0')
|
||||
if (*endptr != '\0') {
|
||||
fatal(&where, lineNo, "Expected number, got \"%s\"", str);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -105,8 +109,9 @@ static uint8_t
|
||||
parseByte(FileStackNode const &where, uint32_t lineNo, char const *str, NumberType base) {
|
||||
uint32_t num = parseNumber(where, lineNo, str, base);
|
||||
|
||||
if (num > UINT8_MAX)
|
||||
if (num > UINT8_MAX) {
|
||||
fatal(&where, lineNo, "\"%s\" is not a byte", str);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
@@ -203,17 +208,20 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
|
||||
static constexpr uint8_t ADDR_SIZE = 3;
|
||||
|
||||
if (line[1] != '0' + ADDR_SIZE)
|
||||
if (line[1] != '0' + ADDR_SIZE) {
|
||||
fatal(&where, lineNo, "Unknown or unsupported address size '%c'", line[1]);
|
||||
}
|
||||
|
||||
if (line[2] != '\0')
|
||||
if (line[2] != '\0') {
|
||||
warning(&where, lineNo, "Ignoring unknown characters (\"%s\") in first line", &line[2]);
|
||||
}
|
||||
|
||||
// Header line
|
||||
|
||||
lineType = nextLine(line, lineNo, where, file);
|
||||
if (lineType != 'H')
|
||||
if (lineType != 'H') {
|
||||
fatal(&where, lineNo, "Expected header line, got '%c' line", lineType);
|
||||
}
|
||||
// Expected format: "A areas S global symbols"
|
||||
|
||||
getToken(line.data(), "Empty 'H' line");
|
||||
@@ -242,8 +250,9 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
|
||||
for (;;) {
|
||||
lineType = nextLine(line, lineNo, where, file);
|
||||
if (lineType == EOF)
|
||||
if (lineType == EOF) {
|
||||
break;
|
||||
}
|
||||
switch (lineType) {
|
||||
case 'M': // Module name
|
||||
case 'O': // Assembler flags
|
||||
@@ -251,10 +260,11 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
break;
|
||||
|
||||
case 'A': {
|
||||
if (fileSections.size() == expectedNbAreas)
|
||||
if (fileSections.size() == expectedNbAreas) {
|
||||
warning(
|
||||
&where, lineNo, "Got more 'A' lines than the expected %" PRIu32, expectedNbAreas
|
||||
);
|
||||
}
|
||||
std::unique_ptr<Section> curSection = std::make_unique<Section>();
|
||||
|
||||
curSection->src = &where;
|
||||
@@ -264,8 +274,9 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
assume(strlen(token) != 0); // This should be impossible, tokens are non-empty
|
||||
// The following is required for fragment offsets to be reliably predicted
|
||||
for (FileSection &entry : fileSections) {
|
||||
if (!strcmp(token, entry.section->name.c_str()))
|
||||
if (!strcmp(token, entry.section->name.c_str())) {
|
||||
fatal(&where, lineNo, "Area \"%s\" already defined earlier", token);
|
||||
}
|
||||
}
|
||||
char const *sectName = token; // We'll deal with the section's name depending on type
|
||||
|
||||
@@ -275,21 +286,23 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
|
||||
uint32_t tmp = parseNumber(where, lineNo, token, numberType);
|
||||
|
||||
if (tmp > UINT16_MAX)
|
||||
if (tmp > UINT16_MAX) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
"Area \"%s\" is larger than the GB address space!?",
|
||||
curSection->name.c_str()
|
||||
);
|
||||
}
|
||||
curSection->size = tmp;
|
||||
|
||||
expectToken("flags", 'A');
|
||||
|
||||
getToken(nullptr, "'A' line is too short");
|
||||
tmp = parseNumber(where, lineNo, token, numberType);
|
||||
if (tmp & (1 << AREA_PAGING))
|
||||
if (tmp & (1 << AREA_PAGING)) {
|
||||
fatal(&where, lineNo, "Internal error: paging is not supported");
|
||||
}
|
||||
curSection->isAddressFixed = tmp & (1 << AREA_ISABS);
|
||||
curSection->isBankFixed = curSection->isAddressFixed;
|
||||
curSection->modifier = curSection->isAddressFixed || (tmp & (1 << AREA_TYPE))
|
||||
@@ -430,11 +443,13 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
// It's fine to keep modifying the symbol after `AddSymbol`, only
|
||||
// the name must not be modified
|
||||
}
|
||||
if (strncasecmp(&token[1], "ef", 2) != 0)
|
||||
if (strncasecmp(&token[1], "ef", 2) != 0) {
|
||||
fatal(&where, lineNo, "'S' line is neither \"Def\" nor \"Ref\"");
|
||||
}
|
||||
|
||||
if (!fileSections.empty())
|
||||
if (!fileSections.empty()) {
|
||||
fileSections.back().section->symbols.push_back(&symbol);
|
||||
}
|
||||
|
||||
expectEol("'S' line is too long");
|
||||
break;
|
||||
@@ -442,15 +457,18 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
|
||||
case 'T':
|
||||
// Now, time to parse the data!
|
||||
if (!data.empty())
|
||||
if (!data.empty()) {
|
||||
warning(&where, lineNo, "Previous 'T' line had no 'R' line (ignored)");
|
||||
}
|
||||
|
||||
data.clear();
|
||||
for (token = strtok(line.data(), delim); token; token = strtok(nullptr, delim))
|
||||
for (token = strtok(line.data(), delim); token; token = strtok(nullptr, delim)) {
|
||||
data.push_back(parseByte(where, lineNo, token, numberType));
|
||||
}
|
||||
|
||||
if (data.size() < ADDR_SIZE)
|
||||
if (data.size() < ADDR_SIZE) {
|
||||
fatal(&where, lineNo, "'T' line is too short");
|
||||
}
|
||||
// Importantly, now we know that there is "pending data" in `data`
|
||||
break;
|
||||
|
||||
@@ -470,7 +488,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
areaIdx = parseByte(where, lineNo, token, numberType);
|
||||
getToken(nullptr, "'R' line is too short");
|
||||
areaIdx |= static_cast<uint16_t>(parseByte(where, lineNo, token, numberType)) << 8;
|
||||
if (areaIdx >= fileSections.size())
|
||||
if (areaIdx >= fileSections.size()) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
@@ -478,6 +496,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
areaIdx,
|
||||
fileSections.size()
|
||||
);
|
||||
}
|
||||
assume(!fileSections.empty()); // There should be at least one, from the above check
|
||||
Section *section = fileSections[areaIdx].section.get();
|
||||
uint16_t *writeIndex = &fileSections[areaIdx].writeIndex;
|
||||
@@ -485,7 +504,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
uint16_t addr = data[0] | data[1] << 8;
|
||||
|
||||
if (section->isAddressFixed) {
|
||||
if (addr < section->org)
|
||||
if (addr < section->org) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
@@ -495,12 +514,13 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
section->name.c_str(),
|
||||
section->org
|
||||
);
|
||||
}
|
||||
addr -= section->org;
|
||||
}
|
||||
// Lines are emitted that violate this check but contain no "payload";
|
||||
// ignore those. "Empty" lines shouldn't trigger allocation, either.
|
||||
if (data.size() != ADDR_SIZE) {
|
||||
if (addr != *writeIndex)
|
||||
if (addr != *writeIndex) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
@@ -509,6 +529,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
addr,
|
||||
*writeIndex
|
||||
);
|
||||
}
|
||||
if (section->data.empty()) {
|
||||
assume(section->size != 0);
|
||||
section->data.resize(section->size);
|
||||
@@ -541,7 +562,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
getToken(nullptr, "Incomplete relocation");
|
||||
uint8_t offset = parseByte(where, lineNo, token, numberType);
|
||||
|
||||
if (offset < ADDR_SIZE)
|
||||
if (offset < ADDR_SIZE) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
@@ -549,7 +570,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
offset,
|
||||
ADDR_SIZE
|
||||
);
|
||||
if (offset >= data.size())
|
||||
}
|
||||
if (offset >= data.size()) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
@@ -557,6 +579,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
offset,
|
||||
data.size()
|
||||
);
|
||||
}
|
||||
|
||||
getToken(nullptr, "Incomplete relocation");
|
||||
uint16_t idx = parseByte(where, lineNo, token, numberType);
|
||||
@@ -565,10 +588,12 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
idx |= static_cast<uint16_t>(parseByte(where, lineNo, token, numberType));
|
||||
|
||||
// Loudly fail on unknown flags
|
||||
if (flags & (1 << RELOC_ZPAGE | 1 << RELOC_NPAGE))
|
||||
if (flags & (1 << RELOC_ZPAGE | 1 << RELOC_NPAGE)) {
|
||||
fatal(&where, lineNo, "Paging flags are not supported");
|
||||
if (flags & ~RELOC_ALL_FLAGS)
|
||||
}
|
||||
if (flags & ~RELOC_ALL_FLAGS) {
|
||||
warning(&where, lineNo, "Unknown reloc flags 0x%x", flags & ~RELOC_ALL_FLAGS);
|
||||
}
|
||||
|
||||
// Turn this into a Patch
|
||||
Patch &patch = section->patches.emplace_back();
|
||||
@@ -578,7 +603,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
patch.offset = offset - writtenOfs + *writeIndex;
|
||||
if (section->patches.size() > 1) {
|
||||
uint32_t prevOffset = section->patches[section->patches.size() - 2].offset;
|
||||
if (prevOffset >= patch.offset)
|
||||
if (prevOffset >= patch.offset) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
@@ -587,6 +612,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
prevOffset,
|
||||
patch.offset
|
||||
);
|
||||
}
|
||||
}
|
||||
patch.pcSection = section; // No need to fill `pcSectionID`, then
|
||||
patch.pcOffset = patch.offset - 1; // For `jr`s
|
||||
@@ -596,7 +622,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
uint32_t baseValue = 0;
|
||||
|
||||
assume(offset < data.size());
|
||||
if (data.size() - offset < nbBaseBytes)
|
||||
if (data.size() - offset < nbBaseBytes) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
@@ -604,13 +630,15 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
nbBaseBytes,
|
||||
data.size() - offset
|
||||
);
|
||||
for (uint8_t i = 0; i < nbBaseBytes; ++i)
|
||||
}
|
||||
for (uint8_t i = 0; i < nbBaseBytes; ++i) {
|
||||
baseValue = baseValue | data[offset + i] << (8 * i);
|
||||
}
|
||||
|
||||
// Bit 4 specifies signedness, but I don't think that matters?
|
||||
// Generate a RPN expression from the info and flags
|
||||
if (flags & 1 << RELOC_ISSYM) {
|
||||
if (idx >= fileSymbols.size())
|
||||
if (idx >= fileSymbols.size()) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
@@ -618,6 +646,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
idx,
|
||||
fileSymbols.size()
|
||||
);
|
||||
}
|
||||
Symbol const &sym = fileSymbols[idx];
|
||||
|
||||
// SDCC has a bunch of "magic symbols" that start with a
|
||||
@@ -627,10 +656,11 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
// Look for the symbol being referenced, and use its index instead
|
||||
for (idx = 0; idx < fileSymbols.size(); ++idx) {
|
||||
if (sym.name.ends_with(fileSymbols[idx].name)
|
||||
&& 1 + sym.name.length() == fileSymbols[idx].name.length())
|
||||
&& 1 + sym.name.length() == fileSymbols[idx].name.length()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (idx == fileSymbols.size())
|
||||
if (idx == fileSymbols.size()) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
@@ -638,6 +668,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
sym.name.c_str(),
|
||||
&sym.name.c_str()[1]
|
||||
);
|
||||
}
|
||||
patch.rpnExpression.resize(5);
|
||||
patch.rpnExpression[0] = RPN_BANK_SYM;
|
||||
patch.rpnExpression[1] = idx;
|
||||
@@ -669,7 +700,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
patch.rpnExpression[4] = idx >> 24;
|
||||
}
|
||||
} else {
|
||||
if (idx >= fileSections.size())
|
||||
if (idx >= fileSections.size()) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
@@ -677,6 +708,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
idx,
|
||||
fileSections.size()
|
||||
);
|
||||
}
|
||||
// It gets funky. If the area is absolute, *actually*, we
|
||||
// must not add its base address, as the assembler will
|
||||
// already have added it in `baseValue`.
|
||||
@@ -684,8 +716,9 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
// address from `baseValue`, undoing what the assembler did;
|
||||
// this allows the relocation to still be correct, even if
|
||||
// the section gets moved for any reason.
|
||||
if (fileSections[idx].section->isAddressFixed)
|
||||
if (fileSections[idx].section->isAddressFixed) {
|
||||
baseValue -= fileSections[idx].section->org;
|
||||
}
|
||||
std::string const &name = fileSections[idx].section->name;
|
||||
Section const *other = sect_GetSection(name);
|
||||
|
||||
@@ -697,8 +730,9 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
// so this fragment will be appended to the existing section
|
||||
// *if any*, and thus its offset will be the section's
|
||||
// current size.
|
||||
if (other)
|
||||
if (other) {
|
||||
baseValue += other->size;
|
||||
}
|
||||
patch.rpnExpression.resize(1 + name.length() + 1);
|
||||
patch.rpnExpression[0] = RPN_STARTOF_SECT;
|
||||
// The cast is fine, it's just different signedness
|
||||
@@ -720,7 +754,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
// Despite the flag's name, as soon as it is set, 3 bytes
|
||||
// are present, so we must skip two of them
|
||||
if (flags & 1 << RELOC_EXPR16) {
|
||||
if (*writeIndex + (offset - writtenOfs) > section->size)
|
||||
if (*writeIndex + (offset - writtenOfs) > section->size) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
@@ -729,6 +763,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
*writeIndex + (offset - writtenOfs),
|
||||
section->size
|
||||
);
|
||||
}
|
||||
// Copy all bytes up to those (plus the byte that we'll overwrite)
|
||||
memcpy(
|
||||
§ion->data[*writeIndex], &data[writtenOfs], offset - writtenOfs + 1
|
||||
@@ -785,7 +820,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
// If there is some data left to append, do so
|
||||
if (writtenOfs != data.size()) {
|
||||
assume(data.size() > writtenOfs);
|
||||
if (*writeIndex + (data.size() - writtenOfs) > section->size)
|
||||
if (*writeIndex + (data.size() - writtenOfs) > section->size) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
@@ -794,6 +829,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
*writeIndex + (data.size() - writtenOfs),
|
||||
section->size
|
||||
);
|
||||
}
|
||||
memcpy(§ion->data[*writeIndex], &data[writtenOfs], data.size() - writtenOfs);
|
||||
*writeIndex += data.size() - writtenOfs;
|
||||
}
|
||||
@@ -813,9 +849,10 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
#undef expectToken
|
||||
#undef getToken
|
||||
|
||||
if (!data.empty())
|
||||
if (!data.empty()) {
|
||||
warning(&where, lineNo, "Last 'T' line had no 'R' line (ignored)");
|
||||
if (fileSections.size() < expectedNbAreas)
|
||||
}
|
||||
if (fileSections.size() < expectedNbAreas) {
|
||||
warning(
|
||||
&where,
|
||||
lineNo,
|
||||
@@ -823,7 +860,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
expectedNbAreas,
|
||||
fileSections.size()
|
||||
);
|
||||
if (fileSymbols.size() < expectedNbSymbols)
|
||||
}
|
||||
if (fileSymbols.size() < expectedNbSymbols) {
|
||||
warning(
|
||||
&where,
|
||||
lineNo,
|
||||
@@ -831,6 +869,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
expectedNbSymbols,
|
||||
fileSymbols.size()
|
||||
);
|
||||
}
|
||||
|
||||
nbSectionsToAssign += fileSections.size();
|
||||
|
||||
|
||||
@@ -14,8 +14,9 @@ std::vector<std::unique_ptr<Section>> sectionList;
|
||||
std::unordered_map<std::string, size_t> sectionMap; // Indexes into `sectionList`
|
||||
|
||||
void sect_ForEach(void (*callback)(Section &)) {
|
||||
for (auto &ptr : sectionList)
|
||||
for (auto &ptr : sectionList) {
|
||||
callback(*ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void checkAgainstFixedAddress(Section const &target, Section const &other, uint16_t org) {
|
||||
@@ -117,8 +118,9 @@ static void checkFragmentCompat(Section &target, Section &other) {
|
||||
target.org = org;
|
||||
} else if (other.isAlignFixed) {
|
||||
int32_t ofs = (other.alignOfs - target.size) % (other.alignMask + 1);
|
||||
if (ofs < 0)
|
||||
if (ofs < 0) {
|
||||
ofs += other.alignMask + 1;
|
||||
}
|
||||
if (checkAgainstFixedAlign(target, other, ofs)) {
|
||||
target.isAlignFixed = true;
|
||||
target.alignMask = other.alignMask;
|
||||
@@ -183,8 +185,9 @@ static void mergeSections(Section &target, std::unique_ptr<Section> &&other) {
|
||||
switch (other->modifier) {
|
||||
case SECTION_UNION:
|
||||
checkSectUnionCompat(target, *other);
|
||||
if (other->size > target.size)
|
||||
if (other->size > target.size) {
|
||||
target.size = other->size;
|
||||
}
|
||||
break;
|
||||
|
||||
case SECTION_FRAGMENT:
|
||||
@@ -196,8 +199,9 @@ static void mergeSections(Section &target, std::unique_ptr<Section> &&other) {
|
||||
if (!other->data.empty()) {
|
||||
target.data.insert(target.data.end(), RANGE(other->data));
|
||||
// Adjust patches' PC offsets
|
||||
for (Patch &patch : other->patches)
|
||||
for (Patch &patch : other->patches) {
|
||||
patch.pcOffset += other->offset;
|
||||
}
|
||||
} else if (!target.data.empty()) {
|
||||
assume(other->size == 0);
|
||||
}
|
||||
@@ -250,37 +254,41 @@ static void doSanityChecks(Section §ion) {
|
||||
}
|
||||
|
||||
if (is32kMode && section.type == SECTTYPE_ROMX) {
|
||||
if (section.isBankFixed && section.bank != 1)
|
||||
if (section.isBankFixed && section.bank != 1) {
|
||||
error(
|
||||
nullptr,
|
||||
0,
|
||||
"%s: ROMX sections must be in bank 1 (if any) with option -t",
|
||||
section.name.c_str()
|
||||
);
|
||||
else
|
||||
} else {
|
||||
section.type = SECTTYPE_ROM0;
|
||||
}
|
||||
}
|
||||
if (isWRAM0Mode && section.type == SECTTYPE_WRAMX) {
|
||||
if (section.isBankFixed && section.bank != 1)
|
||||
if (section.isBankFixed && section.bank != 1) {
|
||||
error(
|
||||
nullptr,
|
||||
0,
|
||||
"%s: WRAMX sections must be in bank 1 with options -w or -d",
|
||||
section.name.c_str()
|
||||
);
|
||||
else
|
||||
} else {
|
||||
section.type = SECTTYPE_WRAM0;
|
||||
}
|
||||
}
|
||||
if (isDmgMode && section.type == SECTTYPE_VRAM && section.bank == 1)
|
||||
if (isDmgMode && section.type == SECTTYPE_VRAM && section.bank == 1) {
|
||||
error(nullptr, 0, "%s: VRAM bank 1 can't be used with option -d", section.name.c_str());
|
||||
}
|
||||
|
||||
// Check if alignment is reasonable, this is important to avoid UB
|
||||
// An alignment of zero is equivalent to no alignment, basically
|
||||
if (section.isAlignFixed && section.alignMask == 0)
|
||||
if (section.isAlignFixed && section.alignMask == 0) {
|
||||
section.isAlignFixed = false;
|
||||
}
|
||||
|
||||
// Too large an alignment may not be satisfiable
|
||||
if (section.isAlignFixed && (section.alignMask & sectionTypeInfo[section.type].startAddr))
|
||||
if (section.isAlignFixed && (section.alignMask & sectionTypeInfo[section.type].startAddr)) {
|
||||
error(
|
||||
nullptr,
|
||||
0,
|
||||
@@ -289,11 +297,12 @@ static void doSanityChecks(Section §ion) {
|
||||
sectionTypeInfo[section.type].name.c_str(),
|
||||
section.alignMask + 1
|
||||
);
|
||||
}
|
||||
|
||||
uint32_t minbank = sectionTypeInfo[section.type].firstBank,
|
||||
maxbank = sectionTypeInfo[section.type].lastBank;
|
||||
|
||||
if (section.isBankFixed && section.bank < minbank && section.bank > maxbank)
|
||||
if (section.isBankFixed && section.bank < minbank && section.bank > maxbank) {
|
||||
error(
|
||||
nullptr,
|
||||
0,
|
||||
@@ -306,9 +315,10 @@ static void doSanityChecks(Section §ion) {
|
||||
minbank,
|
||||
maxbank
|
||||
);
|
||||
}
|
||||
|
||||
// Check if section has a chance to be placed
|
||||
if (section.size > sectionTypeInfo[section.type].size)
|
||||
if (section.size > sectionTypeInfo[section.type].size) {
|
||||
error(
|
||||
nullptr,
|
||||
0,
|
||||
@@ -317,6 +327,7 @@ static void doSanityChecks(Section §ion) {
|
||||
section.size,
|
||||
sectionTypeInfo[section.type].size
|
||||
);
|
||||
}
|
||||
|
||||
// Translate loose constraints to strong ones when they're equivalent
|
||||
|
||||
@@ -328,19 +339,20 @@ static void doSanityChecks(Section §ion) {
|
||||
if (section.isAddressFixed) {
|
||||
// It doesn't make sense to have both org and alignment set
|
||||
if (section.isAlignFixed) {
|
||||
if ((section.org & section.alignMask) != section.alignOfs)
|
||||
if ((section.org & section.alignMask) != section.alignOfs) {
|
||||
error(
|
||||
nullptr,
|
||||
0,
|
||||
"Section \"%s\"'s fixed address doesn't match its alignment",
|
||||
section.name.c_str()
|
||||
);
|
||||
}
|
||||
section.isAlignFixed = false;
|
||||
}
|
||||
|
||||
// Ensure the target address is valid
|
||||
if (section.org < sectionTypeInfo[section.type].startAddr
|
||||
|| section.org > endaddr(section.type))
|
||||
|| section.org > endaddr(section.type)) {
|
||||
error(
|
||||
nullptr,
|
||||
0,
|
||||
@@ -351,8 +363,9 @@ static void doSanityChecks(Section §ion) {
|
||||
sectionTypeInfo[section.type].startAddr,
|
||||
endaddr(section.type)
|
||||
);
|
||||
}
|
||||
|
||||
if (section.org + section.size > endaddr(section.type) + 1)
|
||||
if (section.org + section.size > endaddr(section.type) + 1) {
|
||||
error(
|
||||
nullptr,
|
||||
0,
|
||||
@@ -361,6 +374,7 @@ static void doSanityChecks(Section §ion) {
|
||||
section.org + section.size,
|
||||
endaddr(section.type) + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,14 +16,16 @@ std::unordered_map<std::string, Symbol *> symbols;
|
||||
std::unordered_map<std::string, std::vector<Symbol *>> localSymbols;
|
||||
|
||||
void sym_ForEach(void (*callback)(Symbol &)) {
|
||||
for (auto &it : symbols)
|
||||
for (auto &it : symbols) {
|
||||
callback(*it.second);
|
||||
}
|
||||
}
|
||||
|
||||
void sym_AddSymbol(Symbol &symbol) {
|
||||
if (symbol.type != SYMTYPE_EXPORT) {
|
||||
if (symbol.type != SYMTYPE_IMPORT)
|
||||
if (symbol.type != SYMTYPE_IMPORT) {
|
||||
localSymbols[symbol.name].push_back(&symbol);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -35,17 +37,19 @@ void sym_AddSymbol(Symbol &symbol) {
|
||||
// Check if the symbol already exists with a different value
|
||||
if (other && !(symValue && otherValue && *symValue == *otherValue)) {
|
||||
fprintf(stderr, "error: \"%s\" is defined as ", symbol.name.c_str());
|
||||
if (symValue)
|
||||
if (symValue) {
|
||||
fprintf(stderr, "%" PRId32, *symValue);
|
||||
else
|
||||
} else {
|
||||
fputs("a label", stderr);
|
||||
}
|
||||
fputs(" at ", stderr);
|
||||
symbol.src->dump(symbol.lineNo);
|
||||
fputs(", but as ", stderr);
|
||||
if (otherValue)
|
||||
if (otherValue) {
|
||||
fprintf(stderr, "%" PRId32, *otherValue);
|
||||
else
|
||||
} else {
|
||||
fputs("another label", stderr);
|
||||
}
|
||||
fputs(" at ", stderr);
|
||||
other->src->dump(other->lineNo);
|
||||
putc('\n', stderr);
|
||||
|
||||
Reference in New Issue
Block a user