Always use braces with InsertBraces: true in .clang-format

This commit is contained in:
Rangi42
2025-01-27 19:31:35 -05:00
committed by Rangi
parent 25c9f8f383
commit cae31005f8
29 changed files with 1350 additions and 717 deletions

View File

@@ -74,14 +74,17 @@ static void assignSection(Section &section, MemoryLocation const &location) {
static bool isLocationSuitable(
Section const &section, 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 &section, 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 &section, 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 &section, 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 &section, 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 &section) {
} 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 &section) {
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 &section) {
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 &section) {
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 &section) {
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 &section) {
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 &section) {
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 *> &sections = 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, &section);
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_();

View File

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

View File

@@ -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 &section) {
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,

View File

@@ -66,24 +66,27 @@ void out_AddSection(Section const &section) {
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, &section);
}
@@ -92,8 +95,9 @@ Section const *out_OverlappingSection(Section const &section) {
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 &section) {
// 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(
&sections[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 &sectList, 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 &sectList, 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);
}
}
}

View File

@@ -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 &section, 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 &section, 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 &section, 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 &section, 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 &section) {
if (!sect_HasData(section.type))
if (!sect_HasData(section.type)) {
return;
}
for (Section *component = &section; component; component = component->nextu.get())
for (Section *component = &section; component; component = component->nextu.get()) {
applyFilePatches(*component, section);
}
}
void patch_ApplyPatches() {

View File

@@ -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(
&section->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(&section->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();

View File

@@ -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 &section) {
}
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 &section) {
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 &section) {
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 &section) {
section.size,
sectionTypeInfo[section.type].size
);
}
// Translate loose constraints to strong ones when they're equivalent
@@ -328,19 +339,20 @@ static void doSanityChecks(Section &section) {
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 &section) {
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 &section) {
section.org + section.size,
endaddr(section.type) + 1
);
}
}
}

View File

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