mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-23 19:42:08 +00:00
Make comments more consistent
- Changes most `/* comments */` to `// comments` - Changes `/**` block comments consistently to `/*` - Adds consistent license comments to all files Also renames `T_POP_SET` to `T_Z80_SET`
This commit is contained in:
@@ -34,14 +34,12 @@ struct FreeSpace {
|
||||
struct FreeSpace *next, *prev;
|
||||
};
|
||||
|
||||
/* Table of free space for each bank */
|
||||
// Table of free space for each bank
|
||||
struct FreeSpace *memory[SECTTYPE_INVALID];
|
||||
|
||||
uint64_t nbSectionsToAssign;
|
||||
|
||||
/**
|
||||
* Init the free space-modelling structs
|
||||
*/
|
||||
// Init the free space-modelling structs
|
||||
static void initFreeSpace(void)
|
||||
{
|
||||
for (enum SectionType type = 0; type < SECTTYPE_INVALID; type++) {
|
||||
@@ -63,7 +61,7 @@ static void initFreeSpace(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Assigns a section to a given memory location
|
||||
* @param section The section to assign
|
||||
* @param location The location to assign the section to
|
||||
@@ -85,7 +83,7 @@ static void assignSection(struct Section *section, struct MemoryLocation const *
|
||||
out_AddSection(section);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Checks whether a given location is suitable for placing a given section
|
||||
* This checks not only that the location has enough room for the section, but
|
||||
* also that the constraints (alignment...) are respected.
|
||||
@@ -111,7 +109,7 @@ static bool isLocationSuitable(struct Section const *section,
|
||||
<= freeSpace->address + freeSpace->size;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Finds a suitable location to place a section at.
|
||||
* @param section The section to be placed
|
||||
* @param location A pointer to a location struct that will be filled
|
||||
@@ -146,61 +144,57 @@ static struct FreeSpace *getPlacement(struct Section const *section,
|
||||
struct FreeSpace *space;
|
||||
|
||||
for (;;) {
|
||||
/* Switch to the beginning of the next bank */
|
||||
// Switch to the beginning of the next bank
|
||||
#define BANK_INDEX (location->bank - sectionTypeInfo[section->type].firstBank)
|
||||
space = memory[section->type][BANK_INDEX].next;
|
||||
if (space)
|
||||
location->address = space->address;
|
||||
|
||||
/* Process locations in that bank */
|
||||
// Process locations in that bank
|
||||
while (space) {
|
||||
/* If that location is OK, return it */
|
||||
// If that location is OK, return it
|
||||
if (isLocationSuitable(section, space, location))
|
||||
return space;
|
||||
|
||||
/* Go to the next *possible* location */
|
||||
// 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 the address is fixed, there can be only
|
||||
// one candidate block per bank; if we already
|
||||
// reached it, give up.
|
||||
if (location->address < section->org)
|
||||
location->address = section->org;
|
||||
else
|
||||
/* Try again in next bank */
|
||||
// Try again in next bank
|
||||
space = NULL;
|
||||
} else if (section->isAlignFixed) {
|
||||
/* Move to next aligned location */
|
||||
/* Move back to alignment boundary */
|
||||
// Move to next aligned location
|
||||
// Move back to alignment boundary
|
||||
location->address -= section->alignOfs;
|
||||
/* Ensure we're there (e.g. on first check) */
|
||||
// Ensure we're there (e.g. on first check)
|
||||
location->address &= ~section->alignMask;
|
||||
/* Go to next align boundary and add offset */
|
||||
// Go to next align boundary and add offset
|
||||
location->address += section->alignMask + 1
|
||||
+ section->alignOfs;
|
||||
} else {
|
||||
/* Any location is fine, so, next free block */
|
||||
// Any location is fine, so, next free block
|
||||
space = space->next;
|
||||
if (space)
|
||||
location->address = space->address;
|
||||
}
|
||||
|
||||
/*
|
||||
* If that location is past the current block's end,
|
||||
* go forwards until that is no longer the case.
|
||||
*/
|
||||
// If that location is past the current block's end,
|
||||
// go forwards until that is no longer the case.
|
||||
while (space && location->address >=
|
||||
space->address + space->size)
|
||||
space = space->next;
|
||||
|
||||
/* Try again with the new location/free space combo */
|
||||
// Try again with the new location/free space combo
|
||||
}
|
||||
|
||||
if (section->isBankFixed)
|
||||
return NULL;
|
||||
|
||||
/* Try again in the next bank */
|
||||
// Try again in the next bank
|
||||
location->bank++;
|
||||
if (location->bank > sectionTypeInfo[section->type].lastBank)
|
||||
return NULL;
|
||||
@@ -208,7 +202,7 @@ static struct FreeSpace *getPlacement(struct Section const *section,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Places a section in a suitable location, or error out if it fails to.
|
||||
* @warning Due to the implemented algorithm, this should be called with
|
||||
* sections of decreasing size.
|
||||
@@ -218,12 +212,10 @@ static void placeSection(struct Section *section)
|
||||
{
|
||||
struct MemoryLocation location;
|
||||
|
||||
/* Specially handle 0-byte SECTIONs, as they can't overlap anything */
|
||||
// Specially handle 0-byte SECTIONs, as they can't overlap anything
|
||||
if (section->size == 0) {
|
||||
/*
|
||||
* Unless the SECTION's address was fixed, the starting address
|
||||
* is fine for any alignment, as checked in sect_DoSanityChecks.
|
||||
*/
|
||||
// Unless the SECTION's address was fixed, the starting address
|
||||
// is fine for any alignment, as checked in sect_DoSanityChecks.
|
||||
location.address = section->isAddressFixed
|
||||
? section->org
|
||||
: sectionTypeInfo[section->type].startAddr;
|
||||
@@ -234,60 +226,56 @@ static void placeSection(struct Section *section)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Place section using first-fit decreasing algorithm
|
||||
* https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm
|
||||
*/
|
||||
// Place section using first-fit decreasing algorithm
|
||||
// https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm
|
||||
struct FreeSpace *freeSpace = getPlacement(section, &location);
|
||||
|
||||
if (freeSpace) {
|
||||
assignSection(section, &location);
|
||||
|
||||
/* Split the free space */
|
||||
// Split the free space
|
||||
bool noLeftSpace = freeSpace->address == section->org;
|
||||
bool noRightSpace = freeSpace->address + freeSpace->size
|
||||
== section->org + section->size;
|
||||
if (noLeftSpace && noRightSpace) {
|
||||
/* The free space is entirely deleted */
|
||||
// The free space is entirely deleted
|
||||
freeSpace->prev->next = freeSpace->next;
|
||||
if (freeSpace->next)
|
||||
freeSpace->next->prev = freeSpace->prev;
|
||||
/*
|
||||
* If the space is the last one on the list, set its
|
||||
* size to 0 so it doesn't get picked, but don't free()
|
||||
* it as it will be freed when cleaning up
|
||||
*/
|
||||
// If the space is the last one on the list, set its
|
||||
// size to 0 so it doesn't get picked, but don't free()
|
||||
// it as it will be freed when cleaning up
|
||||
free(freeSpace);
|
||||
} else if (!noLeftSpace && !noRightSpace) {
|
||||
/* The free space is split in two */
|
||||
// The free space is split in two
|
||||
struct FreeSpace *newSpace = malloc(sizeof(*newSpace));
|
||||
|
||||
if (!newSpace)
|
||||
err("Failed to split new free space");
|
||||
/* Append the new space after the chosen one */
|
||||
// Append the new space after the chosen one
|
||||
newSpace->prev = freeSpace;
|
||||
newSpace->next = freeSpace->next;
|
||||
if (freeSpace->next)
|
||||
freeSpace->next->prev = newSpace;
|
||||
freeSpace->next = newSpace;
|
||||
/* Set its parameters */
|
||||
// Set its parameters
|
||||
newSpace->address = section->org + section->size;
|
||||
newSpace->size = freeSpace->address + freeSpace->size -
|
||||
newSpace->address;
|
||||
/* Set the original space's new parameters */
|
||||
// Set the original space's new parameters
|
||||
freeSpace->size = section->org - freeSpace->address;
|
||||
/* address is unmodified */
|
||||
// address is unmodified
|
||||
} else {
|
||||
/* The amount of free spaces doesn't change: resize! */
|
||||
// The amount of free spaces doesn't change: resize!
|
||||
freeSpace->size -= section->size;
|
||||
if (noLeftSpace)
|
||||
/* The free space is moved *and* resized */
|
||||
// The free space is moved *and* resized
|
||||
freeSpace->address += section->size;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Please adjust depending on longest message below */
|
||||
// Please adjust depending on longest message below
|
||||
char where[64];
|
||||
|
||||
if (section->isBankFixed && nbbanks(section->type) != 1) {
|
||||
@@ -312,16 +300,16 @@ static void placeSection(struct Section *section)
|
||||
strcpy(where, "anywhere");
|
||||
}
|
||||
|
||||
/* If a section failed to go to several places, nothing we can report */
|
||||
// If a section failed to go to several places, nothing we can report
|
||||
if (!section->isBankFixed || !section->isAddressFixed)
|
||||
errx("Unable to place \"%s\" (%s section) %s",
|
||||
section->name, sectionTypeInfo[section->type].name, where);
|
||||
/* If the section just can't fit the bank, report that */
|
||||
// If the section just can't fit the bank, report that
|
||||
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)",
|
||||
section->name, sectionTypeInfo[section->type].name, where,
|
||||
section->org + section->size, endaddr(section->type) + 1);
|
||||
/* Otherwise there is overlap with another section */
|
||||
// Otherwise there is overlap with another section
|
||||
else
|
||||
errx("Unable to place \"%s\" (%s section) %s: section overlaps with \"%s\"",
|
||||
section->name, sectionTypeInfo[section->type].name, where,
|
||||
@@ -339,7 +327,7 @@ struct UnassignedSection {
|
||||
static struct UnassignedSection *unassignedSections[1 << 3] = {0};
|
||||
static struct UnassignedSection *sections;
|
||||
|
||||
/**
|
||||
/*
|
||||
* Categorize a section depending on how constrained it is
|
||||
* This is so the most-constrained sections are placed first
|
||||
* @param section The section to categorize
|
||||
@@ -354,13 +342,13 @@ static void categorizeSection(struct Section *section, void *arg)
|
||||
constraints |= BANK_CONSTRAINED;
|
||||
if (section->isAddressFixed)
|
||||
constraints |= ORG_CONSTRAINED;
|
||||
/* Can't have both! */
|
||||
// Can't have both!
|
||||
else if (section->isAlignFixed)
|
||||
constraints |= ALIGN_CONSTRAINED;
|
||||
|
||||
struct UnassignedSection **ptr = &unassignedSections[constraints];
|
||||
|
||||
/* Insert section while keeping the list sorted by decreasing size */
|
||||
// Insert section while keeping the list sorted by decreasing size
|
||||
while (*ptr && (*ptr)->section->size > section->size)
|
||||
ptr = &(*ptr)->next;
|
||||
|
||||
@@ -375,9 +363,9 @@ void assign_AssignSections(void)
|
||||
{
|
||||
verbosePrint("Beginning assignment...\n");
|
||||
|
||||
/** Initialize assignment **/
|
||||
// Initialize assignment
|
||||
|
||||
/* Generate linked lists of sections to assign */
|
||||
// Generate linked lists of sections to assign
|
||||
sections = malloc(sizeof(*sections) * nbSectionsToAssign + 1);
|
||||
if (!sections)
|
||||
err("Failed to allocate memory for section assignment");
|
||||
@@ -387,9 +375,9 @@ void assign_AssignSections(void)
|
||||
nbSectionsToAssign = 0;
|
||||
sect_ForEach(categorizeSection, NULL);
|
||||
|
||||
/** Place sections, starting with the most constrained **/
|
||||
// Place sections, starting with the most constrained
|
||||
|
||||
/* Specially process fully-constrained sections because of overlaying */
|
||||
// Specially process fully-constrained sections because of overlaying
|
||||
struct UnassignedSection *sectionPtr =
|
||||
unassignedSections[BANK_CONSTRAINED | ORG_CONSTRAINED];
|
||||
|
||||
@@ -399,11 +387,11 @@ void assign_AssignSections(void)
|
||||
sectionPtr = sectionPtr->next;
|
||||
}
|
||||
|
||||
/* If all sections were fully constrained, we have nothing left to do */
|
||||
// If all sections were fully constrained, we have nothing left to do
|
||||
if (!nbSectionsToAssign)
|
||||
return;
|
||||
|
||||
/* Overlaying requires only fully-constrained sections */
|
||||
// Overlaying requires only fully-constrained sections
|
||||
verbosePrint("Assigning other sections...\n");
|
||||
if (overlayFileName) {
|
||||
fprintf(stderr, "FATAL: All sections must be fixed when using an overlay file");
|
||||
@@ -427,7 +415,7 @@ max_out:
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Assign all remaining sections by decreasing constraint order */
|
||||
// Assign all remaining sections by decreasing constraint order
|
||||
for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED;
|
||||
constraints >= 0; constraints--) {
|
||||
sectionPtr = unassignedSections[constraints];
|
||||
|
||||
@@ -33,34 +33,33 @@
|
||||
#include "platform.h"
|
||||
#include "version.h"
|
||||
|
||||
bool isDmgMode; /* -d */
|
||||
char *linkerScriptName; /* -l */
|
||||
char const *mapFileName; /* -m */
|
||||
bool noSymInMap; /* -M */
|
||||
char const *symFileName; /* -n */
|
||||
char const *overlayFileName; /* -O */
|
||||
char const *outputFileName; /* -o */
|
||||
uint8_t padValue; /* -p */
|
||||
bool isDmgMode; // -d
|
||||
char *linkerScriptName; // -l
|
||||
char const *mapFileName; // -m
|
||||
bool noSymInMap; // -M
|
||||
char const *symFileName; // -n
|
||||
char const *overlayFileName; // -O
|
||||
char const *outputFileName; // -o
|
||||
uint8_t padValue; // -p
|
||||
// Setting these three to 0 disables the functionality
|
||||
uint16_t scrambleROMX = 0; /* -S */
|
||||
uint16_t scrambleROMX = 0; // -S
|
||||
uint8_t scrambleWRAMX = 0;
|
||||
uint8_t scrambleSRAM = 0;
|
||||
bool is32kMode; /* -t */
|
||||
bool beVerbose; /* -v */
|
||||
bool isWRA0Mode; /* -w */
|
||||
bool disablePadding; /* -x */
|
||||
bool is32kMode; // -t
|
||||
bool beVerbose; // -v
|
||||
bool isWRA0Mode; // -w
|
||||
bool disablePadding; // -x
|
||||
|
||||
static uint32_t nbErrors = 0;
|
||||
|
||||
/***** Helper function to dump a file stack to stderr *****/
|
||||
|
||||
// Helper function to dump a file stack to stderr
|
||||
char const *dumpFileStack(struct FileStackNode const *node)
|
||||
{
|
||||
char const *lastName;
|
||||
|
||||
if (node->parent) {
|
||||
lastName = dumpFileStack(node->parent);
|
||||
/* REPT nodes use their parent's name */
|
||||
// REPT nodes use their parent's name
|
||||
if (node->type != NODE_REPT)
|
||||
lastName = node->name;
|
||||
fprintf(stderr, "(%" PRIu32 ") -> %s", node->lineNo, lastName);
|
||||
@@ -165,7 +164,7 @@ FILE *openFile(char const *fileName, char const *mode)
|
||||
return file;
|
||||
}
|
||||
|
||||
/* Short options */
|
||||
// Short options
|
||||
static const char *optstring = "dl:m:Mn:O:o:p:S:s:tVvWwx";
|
||||
|
||||
/*
|
||||
@@ -197,9 +196,7 @@ static struct option const longopts[] = {
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
|
||||
/**
|
||||
* Prints the program's usage to stdout.
|
||||
*/
|
||||
// Prints the program's usage to stdout.
|
||||
static void printUsage(void)
|
||||
{
|
||||
fputs(
|
||||
@@ -219,10 +216,8 @@ static void printUsage(void)
|
||||
stderr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up what has been done
|
||||
* Mostly here to please tools such as `valgrind` so actual errors can be seen
|
||||
*/
|
||||
// Cleans up what has been done
|
||||
// Mostly here to please tools such as `valgrind` so actual errors can be seen
|
||||
static void cleanup(void)
|
||||
{
|
||||
obj_Cleanup();
|
||||
@@ -362,10 +357,10 @@ _Noreturn void reportErrors(void) {
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int optionChar;
|
||||
char *endptr; /* For error checking with `strtoul` */
|
||||
unsigned long value; /* For storing `strtoul`'s return value */
|
||||
char *endptr; // For error checking with `strtoul`
|
||||
unsigned long value; // For storing `strtoul`'s return value
|
||||
|
||||
/* Parse options */
|
||||
// Parse options
|
||||
while ((optionChar = musl_getopt_long_only(argc, argv, optstring,
|
||||
longopts, NULL)) != -1) {
|
||||
switch (optionChar) {
|
||||
@@ -407,7 +402,7 @@ int main(int argc, char *argv[])
|
||||
parseScrambleSpec(musl_optarg);
|
||||
break;
|
||||
case 's':
|
||||
/* FIXME: nobody knows what this does, figure it out */
|
||||
// FIXME: nobody knows what this does, figure it out
|
||||
(void)musl_optarg;
|
||||
warning(NULL, 0, "Nobody has any idea what `-s` does");
|
||||
break;
|
||||
@@ -425,7 +420,7 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
case 'x':
|
||||
disablePadding = true;
|
||||
/* implies tiny mode */
|
||||
// implies tiny mode
|
||||
is32kMode = true;
|
||||
break;
|
||||
default:
|
||||
@@ -436,41 +431,41 @@ int main(int argc, char *argv[])
|
||||
|
||||
int curArgIndex = musl_optind;
|
||||
|
||||
/* If no input files were specified, the user must have screwed up */
|
||||
// If no input files were specified, the user must have screwed up
|
||||
if (curArgIndex == argc) {
|
||||
fputs("FATAL: no input files\n", stderr);
|
||||
printUsage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Patch the size array depending on command-line options */
|
||||
// Patch the size array depending on command-line options
|
||||
if (!is32kMode)
|
||||
sectionTypeInfo[SECTTYPE_ROM0].size = 0x4000;
|
||||
if (!isWRA0Mode)
|
||||
sectionTypeInfo[SECTTYPE_WRAM0].size = 0x1000;
|
||||
|
||||
/* Patch the bank ranges array depending on command-line options */
|
||||
// Patch the bank ranges array depending on command-line options
|
||||
if (isDmgMode)
|
||||
sectionTypeInfo[SECTTYPE_VRAM].lastBank = 0;
|
||||
|
||||
/* Read all object files first, */
|
||||
// Read all object files first,
|
||||
for (obj_Setup(argc - curArgIndex); curArgIndex < argc; curArgIndex++)
|
||||
obj_ReadFile(argv[curArgIndex], argc - curArgIndex - 1);
|
||||
|
||||
/* apply the linker script's modifications, */
|
||||
// apply the linker script's modifications,
|
||||
if (linkerScriptName) {
|
||||
verbosePrint("Reading linker script...\n");
|
||||
|
||||
linkerScript = openFile(linkerScriptName, "r");
|
||||
|
||||
/* Modify all sections according to the linker script */
|
||||
// Modify all sections according to the linker script
|
||||
struct SectionPlacement *placement;
|
||||
|
||||
while ((placement = script_NextSection())) {
|
||||
struct Section *section = placement->section;
|
||||
|
||||
assert(section->offset == 0);
|
||||
/* Check if this doesn't conflict with what the code says */
|
||||
// Check if this doesn't conflict with what the code says
|
||||
if (section->type == SECTTYPE_INVALID) {
|
||||
for (struct Section *sect = section; sect; sect = sect->nextu)
|
||||
sect->type = placement->type; // SDCC "unknown" sections
|
||||
@@ -493,7 +488,7 @@ int main(int argc, char *argv[])
|
||||
section->org = placement->org;
|
||||
section->isBankFixed = true;
|
||||
section->bank = placement->bank;
|
||||
section->isAlignFixed = false; /* The alignment is satisfied */
|
||||
section->isAlignFixed = false; // The alignment is satisfied
|
||||
}
|
||||
|
||||
fclose(linkerScript);
|
||||
@@ -506,7 +501,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
/* then process them, */
|
||||
// then process them,
|
||||
obj_DoSanityChecks();
|
||||
if (nbErrors != 0)
|
||||
reportErrors();
|
||||
@@ -514,12 +509,12 @@ int main(int argc, char *argv[])
|
||||
obj_CheckAssertions();
|
||||
assign_Cleanup();
|
||||
|
||||
/* and finally output the result. */
|
||||
// and finally output the result.
|
||||
patch_ApplyPatches();
|
||||
if (nbErrors != 0)
|
||||
reportErrors();
|
||||
out_WriteFiles();
|
||||
|
||||
/* Do cleanup before quitting, though. */
|
||||
// Do cleanup before quitting, though.
|
||||
cleanup();
|
||||
}
|
||||
|
||||
@@ -39,12 +39,10 @@ static struct {
|
||||
} *nodes;
|
||||
static struct Assertion *assertions;
|
||||
|
||||
/***** Helper functions for reading object files *****/
|
||||
// Helper functions for reading object files
|
||||
|
||||
/*
|
||||
* Internal, DO NOT USE.
|
||||
* For helper wrapper macros defined below, such as `tryReadlong`
|
||||
*/
|
||||
// Internal, DO NOT USE.
|
||||
// For helper wrapper macros defined below, such as `tryReadlong`
|
||||
#define tryRead(func, type, errval, var, file, ...) \
|
||||
do { \
|
||||
FILE *tmpFile = file; \
|
||||
@@ -58,7 +56,7 @@ static struct Assertion *assertions;
|
||||
var = tmpVal; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads an unsigned long (32-bit) value from a file.
|
||||
* @param file The file to read from. This will read 4 bytes from the file.
|
||||
* @return The value read, cast to a int64_t, or -1 on failure.
|
||||
@@ -67,25 +65,24 @@ static int64_t readlong(FILE *file)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
|
||||
/* Read the little-endian value byte by byte */
|
||||
// Read the little-endian value byte by byte
|
||||
for (uint8_t shift = 0; shift < sizeof(value) * CHAR_BIT; shift += 8) {
|
||||
int byte = getc(file);
|
||||
|
||||
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
|
||||
* `uint8_t`, because int is large enough to hold a byte. This
|
||||
* however causes values larger than 127 to be too large when
|
||||
* shifted, potentially triggering undefined behavior.
|
||||
*/
|
||||
// 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
|
||||
// `uint8_t`, because int is large enough to hold a byte. This
|
||||
// however causes values larger than 127 to be too large when
|
||||
// shifted, potentially triggering undefined behavior.
|
||||
value |= (unsigned int)byte << shift;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Helper macro for reading longs from a file, and errors out if it fails to.
|
||||
* Not as a function to avoid overhead in the general case.
|
||||
* @param var The variable to stash the number into
|
||||
@@ -96,9 +93,9 @@ static int64_t readlong(FILE *file)
|
||||
#define tryReadlong(var, file, ...) \
|
||||
tryRead(readlong, int64_t, INT64_MAX, var, file, __VA_ARGS__)
|
||||
|
||||
/* There is no `readbyte`, just use `fgetc` or `getc`. */
|
||||
// There is no `readbyte`, just use `fgetc` or `getc`.
|
||||
|
||||
/**
|
||||
/*
|
||||
* Helper macro for reading bytes from a file, and errors out if it fails to.
|
||||
* Differs from `tryGetc` in that the backing function is fgetc(1).
|
||||
* Not as a function to avoid overhead in the general case.
|
||||
@@ -110,7 +107,7 @@ static int64_t readlong(FILE *file)
|
||||
#define tryFgetc(var, file, ...) \
|
||||
tryRead(fgetc, int, EOF, var, file, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
/*
|
||||
* Helper macro for reading bytes from a file, and errors out if it fails to.
|
||||
* Differs from `tryGetc` in that the backing function is fgetc(1).
|
||||
* Not as a function to avoid overhead in the general case.
|
||||
@@ -122,7 +119,7 @@ static int64_t readlong(FILE *file)
|
||||
#define tryGetc(var, file, ...) \
|
||||
tryRead(getc, int, EOF, var, file, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads a '\0'-terminated string from a file.
|
||||
* @param file The file to read from. The file position will be advanced.
|
||||
* @return The string read, or NULL on failure.
|
||||
@@ -130,26 +127,26 @@ static int64_t readlong(FILE *file)
|
||||
*/
|
||||
static char *readstr(FILE *file)
|
||||
{
|
||||
/* Default buffer size, have it close to the average string length */
|
||||
// Default buffer size, have it close to the average string length
|
||||
size_t capacity = 32 / 2;
|
||||
size_t index = -1;
|
||||
/* Force the first iteration to allocate */
|
||||
// Force the first iteration to allocate
|
||||
char *str = NULL;
|
||||
|
||||
do {
|
||||
/* Prepare going to next char */
|
||||
// Prepare going to next char
|
||||
index++;
|
||||
|
||||
/* If the buffer isn't suitable to write the next char... */
|
||||
// If the buffer isn't suitable to write the next char...
|
||||
if (index >= capacity || !str) {
|
||||
capacity *= 2;
|
||||
str = realloc(str, capacity);
|
||||
/* End now in case of error */
|
||||
// End now in case of error
|
||||
if (!str)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read char */
|
||||
// Read char
|
||||
int byte = getc(file);
|
||||
|
||||
if (byte == EOF) {
|
||||
@@ -161,7 +158,7 @@ static char *readstr(FILE *file)
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Helper macro for reading bytes from a file, and errors out if it fails to.
|
||||
* Not as a function to avoid overhead in the general case.
|
||||
* @param var The variable to stash the string into
|
||||
@@ -172,9 +169,9 @@ static char *readstr(FILE *file)
|
||||
#define tryReadstr(var, file, ...) \
|
||||
tryRead(readstr, char*, NULL, var, file, __VA_ARGS__)
|
||||
|
||||
/***** Functions to parse object files *****/
|
||||
// Functions to parse object files
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads a file stack node form a file.
|
||||
* @param file The file to read from
|
||||
* @param nodes The file's array of nodes
|
||||
@@ -217,7 +214,7 @@ static void readFileStackNode(FILE *file, struct FileStackNode fileNodes[], uint
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads a symbol from a file.
|
||||
* @param file The file to read from
|
||||
* @param symbol The struct to fill
|
||||
@@ -230,7 +227,7 @@ static void readSymbol(FILE *file, struct Symbol *symbol,
|
||||
fileName);
|
||||
tryGetc(symbol->type, file, "%s: Cannot read \"%s\"'s type: %s",
|
||||
fileName, symbol->name);
|
||||
/* If the symbol is defined in this file, read its definition */
|
||||
// If the symbol is defined in this file, read its definition
|
||||
if (symbol->type != SYMTYPE_IMPORT) {
|
||||
symbol->objFileName = fileName;
|
||||
uint32_t nodeID;
|
||||
@@ -253,7 +250,7 @@ static void readSymbol(FILE *file, struct Symbol *symbol,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads a patch from a file.
|
||||
* @param file The file to read from
|
||||
* @param patch The struct to fill
|
||||
@@ -303,7 +300,7 @@ static void readPatch(FILE *file, struct Patch *patch, char const *fileName, cha
|
||||
feof(file) ? "Unexpected end of file" : strerror(errno));
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Sets a patch's pcSection from its pcSectionID.
|
||||
* @param patch The struct to fix
|
||||
*/
|
||||
@@ -313,7 +310,7 @@ static void linkPatchToPCSect(struct Patch *patch, struct Section *fileSections[
|
||||
: fileSections[patch->pcSectionID];
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads a section from a file.
|
||||
* @param file The file to read from
|
||||
* @param section The struct to fill
|
||||
@@ -372,7 +369,7 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
|
||||
section->alignOfs = tmp;
|
||||
|
||||
if (sect_HasData(section->type)) {
|
||||
/* Ensure we never allocate 0 bytes */
|
||||
// Ensure we never allocate 0 bytes
|
||||
uint8_t *data = malloc(sizeof(*data) * section->size + 1);
|
||||
|
||||
if (!data)
|
||||
@@ -404,7 +401,7 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Links a symbol to a section, keeping the section's symbol list sorted.
|
||||
* @param symbol The symbol to link
|
||||
* @param section The section to link
|
||||
@@ -433,7 +430,7 @@ static void linkSymToSect(struct Symbol *symbol, struct Section *section)
|
||||
section->nbSymbols++;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads an assertion from a file
|
||||
* @param file The file to read from
|
||||
* @param assert The struct to fill
|
||||
@@ -500,7 +497,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Begin by reading the magic bytes */
|
||||
// Begin by reading the magic bytes
|
||||
int matchedElems;
|
||||
|
||||
if (fscanf(file, RGBDS_OBJECT_VERSION_STRING "%n", &matchedElems) == 1
|
||||
@@ -536,7 +533,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||
for (uint32_t i = nodes[fileID].nbNodes; i--; )
|
||||
readFileStackNode(file, nodes[fileID].nodes, i, fileName);
|
||||
|
||||
/* This file's symbols, kept to link sections to them */
|
||||
// This file's symbols, kept to link sections to them
|
||||
struct Symbol **fileSymbols = malloc(sizeof(*fileSymbols) * nbSymbols + 1);
|
||||
|
||||
if (!fileSymbols)
|
||||
@@ -556,7 +553,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||
|
||||
verbosePrint("Reading %" PRIu32 " symbols...\n", nbSymbols);
|
||||
for (uint32_t i = 0; i < nbSymbols; i++) {
|
||||
/* Read symbol */
|
||||
// Read symbol
|
||||
struct Symbol *symbol = malloc(sizeof(*symbol));
|
||||
|
||||
if (!symbol)
|
||||
@@ -570,13 +567,13 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||
nbSymPerSect[symbol->sectionID]++;
|
||||
}
|
||||
|
||||
/* This file's sections, stored in a table to link symbols to them */
|
||||
// This file's sections, stored in a table to link symbols to them
|
||||
struct Section **fileSections = malloc(sizeof(*fileSections)
|
||||
* (nbSections ? nbSections : 1));
|
||||
|
||||
verbosePrint("Reading %" PRIu32 " sections...\n", nbSections);
|
||||
for (uint32_t i = 0; i < nbSections; i++) {
|
||||
/* Read section */
|
||||
// Read section
|
||||
fileSections[i] = malloc(sizeof(*fileSections[i]));
|
||||
if (!fileSections[i])
|
||||
err("%s: Couldn't create new section", fileName);
|
||||
@@ -600,7 +597,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||
|
||||
free(nbSymPerSect);
|
||||
|
||||
/* Give patches' PC section pointers to their sections */
|
||||
// Give patches' PC section pointers to their sections
|
||||
for (uint32_t i = 0; i < nbSections; i++) {
|
||||
if (sect_HasData(fileSections[i]->type)) {
|
||||
for (uint32_t j = 0; j < fileSections[i]->nbPatches; j++)
|
||||
@@ -608,7 +605,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||
}
|
||||
}
|
||||
|
||||
/* Give symbols' section pointers to their sections */
|
||||
// Give symbols' section pointers to their sections
|
||||
for (uint32_t i = 0; i < nbSymbols; i++) {
|
||||
int32_t sectionID = fileSymbols[i]->sectionID;
|
||||
|
||||
@@ -617,12 +614,12 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||
} else {
|
||||
struct Section *section = fileSections[sectionID];
|
||||
|
||||
/* Give the section a pointer to the symbol as well */
|
||||
// Give the section a pointer to the symbol as well
|
||||
linkSymToSect(fileSymbols[i], section);
|
||||
|
||||
if (section->modifier != SECTION_NORMAL) {
|
||||
if (section->modifier == SECTION_FRAGMENT)
|
||||
/* Add the fragment's offset to the symbol's */
|
||||
// Add the fragment's offset to the symbol's
|
||||
fileSymbols[i]->offset += section->offset;
|
||||
section = getMainSection(section);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ static struct {
|
||||
} *banks;
|
||||
} sections[SECTTYPE_INVALID];
|
||||
|
||||
/* Defines the order in which types are output to the sym and map files */
|
||||
// Defines the order in which types are output to the sym and map files
|
||||
static enum SectionType typeMap[SECTTYPE_INVALID] = {
|
||||
SECTTYPE_ROM0,
|
||||
SECTTYPE_ROMX,
|
||||
@@ -124,7 +124,7 @@ struct Section const *out_OverlappingSection(struct Section const *section)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Performs sanity checks on the overlay file.
|
||||
* @return The number of ROM banks in the overlay file
|
||||
*/
|
||||
@@ -140,7 +140,7 @@ static uint32_t checkOverlaySize(void)
|
||||
|
||||
long overlaySize = ftell(overlayFile);
|
||||
|
||||
/* Reset back to beginning */
|
||||
// Reset back to beginning
|
||||
fseek(overlayFile, 0, SEEK_SET);
|
||||
|
||||
if (overlaySize % BANK_SIZE)
|
||||
@@ -157,7 +157,7 @@ static uint32_t checkOverlaySize(void)
|
||||
return nbOverlayBanks;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Expand sections[SECTTYPE_ROMX].banks to cover all the overlay banks.
|
||||
* This ensures that writeROM will output each bank, even if some are not
|
||||
* covered by any sections.
|
||||
@@ -165,9 +165,9 @@ static uint32_t checkOverlaySize(void)
|
||||
*/
|
||||
static void coverOverlayBanks(uint32_t nbOverlayBanks)
|
||||
{
|
||||
/* 2 if is32kMode, 1 otherwise */
|
||||
// 2 if is32kMode, 1 otherwise
|
||||
uint32_t nbRom0Banks = sectionTypeInfo[SECTTYPE_ROM0].size / BANK_SIZE;
|
||||
/* Discount ROM0 banks to avoid outputting too much */
|
||||
// Discount ROM0 banks to avoid outputting too much
|
||||
uint32_t nbUncoveredBanks = nbOverlayBanks - nbRom0Banks > sections[SECTTYPE_ROMX].nbBanks
|
||||
? nbOverlayBanks - nbRom0Banks
|
||||
: 0;
|
||||
@@ -186,7 +186,7 @@ static void coverOverlayBanks(uint32_t nbOverlayBanks)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Write a ROM bank's sections to the output file.
|
||||
* @param bankSections The bank's sections, ordered by increasing address
|
||||
* @param baseOffset The address of the bank's first byte in GB address space
|
||||
@@ -201,18 +201,18 @@ static void writeBank(struct SortedSection *bankSections, uint16_t baseOffset,
|
||||
struct Section const *section = bankSections->section;
|
||||
|
||||
assert(section->offset == 0);
|
||||
/* Output padding up to the next SECTION */
|
||||
// Output padding up to the next SECTION
|
||||
while (offset + baseOffset < section->org) {
|
||||
putc(overlayFile ? getc(overlayFile) : padValue,
|
||||
outputFile);
|
||||
offset++;
|
||||
}
|
||||
|
||||
/* Output the section itself */
|
||||
// Output the section itself
|
||||
fwrite(section->data, sizeof(*section->data), section->size,
|
||||
outputFile);
|
||||
if (overlayFile) {
|
||||
/* Skip bytes even with pipes */
|
||||
// Skip bytes even with pipes
|
||||
for (uint16_t i = 0; i < section->size; i++)
|
||||
getc(overlayFile);
|
||||
}
|
||||
@@ -231,9 +231,7 @@ static void writeBank(struct SortedSection *bankSections, uint16_t baseOffset,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a ROM file to the output.
|
||||
*/
|
||||
// Writes a ROM file to the output.
|
||||
static void writeROM(void)
|
||||
{
|
||||
outputFile = openFile(outputFileName, "wb");
|
||||
@@ -258,7 +256,7 @@ static void writeROM(void)
|
||||
closeFile(overlayFile);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Get the lowest section by address out of the two
|
||||
* @param s1 One choice
|
||||
* @param s2 The other
|
||||
@@ -275,10 +273,8 @@ static struct SortedSection const **nextSection(struct SortedSection const **s1,
|
||||
return (*s1)->section->org < (*s2)->section->org ? s1 : s2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Comparator function for `qsort` to sort symbols
|
||||
* Symbols are ordered by address, or else by original index for a stable sort
|
||||
*/
|
||||
// Comparator function for `qsort` to sort symbols
|
||||
// Symbols are ordered by address, or else by original index for a stable sort
|
||||
static int compareSymbols(void const *a, void const *b)
|
||||
{
|
||||
struct SortedSymbol const *sym1 = (struct SortedSymbol const *)a;
|
||||
@@ -290,7 +286,7 @@ static int compareSymbols(void const *a, void const *b)
|
||||
return sym1->idx < sym2->idx ? -1 : sym1->idx > sym2->idx ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Write a bank's contents to the sym file
|
||||
* @param bankSections The bank's sections
|
||||
*/
|
||||
@@ -357,7 +353,7 @@ static void writeSymBank(struct SortedSections const *bankSections,
|
||||
free(symList);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Write a bank's contents to the map file
|
||||
* @param bankSections The bank's sections
|
||||
* @return The bank's used space
|
||||
@@ -445,7 +441,7 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
|
||||
return used;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Write the total used space by section type to the map file
|
||||
* @param usedMap The total used space by section type
|
||||
*/
|
||||
@@ -471,9 +467,7 @@ static void writeMapUsed(uint32_t usedMap[MIN_NB_ELMS(SECTTYPE_INVALID)])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the sym and/or map files, if applicable.
|
||||
*/
|
||||
// Writes the sym and/or map files, if applicable.
|
||||
static void writeSymAndMap(void)
|
||||
{
|
||||
if (!symFileName && !mapFileName)
|
||||
|
||||
@@ -63,11 +63,9 @@ static void pushRPN(int32_t value, bool comesFromError)
|
||||
realloc(stack.values, sizeof(*stack.values) * stack.capacity);
|
||||
stack.errorFlags =
|
||||
realloc(stack.errorFlags, sizeof(*stack.errorFlags) * stack.capacity);
|
||||
/*
|
||||
* Static analysis tools complain that the capacity might become
|
||||
* zero due to overflow, but fail to realize that it's caught by
|
||||
* the overflow check above. Hence the stringent check below.
|
||||
*/
|
||||
// Static analysis tools complain that the capacity might become
|
||||
// zero due to overflow, but fail to realize that it's caught by
|
||||
// the overflow check above. Hence the stringent check below.
|
||||
if (!stack.values || !stack.errorFlags || !stack.capacity)
|
||||
err("Failed to resize RPN stack");
|
||||
}
|
||||
@@ -97,7 +95,7 @@ static void freeRPNStack(void)
|
||||
free(stack.errorFlags);
|
||||
}
|
||||
|
||||
/* RPN operators */
|
||||
// RPN operators
|
||||
|
||||
static uint32_t getRPNByte(uint8_t const **expression, int32_t *size,
|
||||
struct FileStackNode const *node, uint32_t lineNo)
|
||||
@@ -111,17 +109,17 @@ static uint32_t getRPNByte(uint8_t const **expression, int32_t *size,
|
||||
static struct Symbol const *getSymbol(struct Symbol const * const *symbolList,
|
||||
uint32_t index)
|
||||
{
|
||||
assert(index != (uint32_t)-1); /* PC needs to be handled specially, not here */
|
||||
assert(index != (uint32_t)-1); // PC needs to be handled specially, not here
|
||||
struct Symbol const *symbol = symbolList[index];
|
||||
|
||||
/* If the symbol is defined elsewhere... */
|
||||
// If the symbol is defined elsewhere...
|
||||
if (symbol->type == SYMTYPE_IMPORT)
|
||||
return sym_GetSymbol(symbol->name);
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Compute a patch's value from its RPN string.
|
||||
* @param patch The patch to compute the value of
|
||||
* @param section The section the patch is contained in
|
||||
@@ -132,7 +130,7 @@ static struct Symbol const *getSymbol(struct Symbol const * const *symbolList,
|
||||
static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
struct Symbol const * const *fileSymbols)
|
||||
{
|
||||
/* Small shortcut to avoid a lot of repetition */
|
||||
// Small shortcut to avoid a lot of repetition
|
||||
#define popRPN() popRPN(patch->src, patch->lineNo)
|
||||
|
||||
uint8_t const *expression = patch->rpnExpression;
|
||||
@@ -147,13 +145,10 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
|
||||
isError = false;
|
||||
|
||||
/*
|
||||
* Friendly reminder:
|
||||
* Be VERY careful with two `popRPN` in the same expression.
|
||||
* C does not guarantee order of evaluation of operands!!
|
||||
* So, if there are two `popRPN` in the same expression, make
|
||||
* sure the operation is commutative.
|
||||
*/
|
||||
// Be VERY careful with two `popRPN` in the same expression.
|
||||
// C does not guarantee order of evaluation of operands!!
|
||||
// So, if there are two `popRPN` in the same expression, make
|
||||
// sure the operation is commutative.
|
||||
switch (command) {
|
||||
struct Symbol const *symbol;
|
||||
char const *name;
|
||||
@@ -295,11 +290,9 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
break;
|
||||
|
||||
case RPN_BANK_SECT:
|
||||
/*
|
||||
* `expression` is not guaranteed to be '\0'-terminated. If it is not,
|
||||
* `getRPNByte` will have a fatal internal error.
|
||||
* In either case, `getRPNByte` will not free `expression`.
|
||||
*/
|
||||
// `expression` is not guaranteed to be '\0'-terminated. If it is not,
|
||||
// `getRPNByte` will have a fatal internal error.
|
||||
// In either case, `getRPNByte` will not free `expression`.
|
||||
name = (char const *)expression;
|
||||
while (getRPNByte(&expression, &size, patch->src, patch->lineNo))
|
||||
;
|
||||
@@ -329,7 +322,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
break;
|
||||
|
||||
case RPN_SIZEOF_SECT:
|
||||
/* This has assumptions commented in the `RPN_BANK_SECT` case above. */
|
||||
// This has assumptions commented in the `RPN_BANK_SECT` case above.
|
||||
name = (char const *)expression;
|
||||
while (getRPNByte(&expression, &size, patch->src, patch->lineNo))
|
||||
;
|
||||
@@ -348,7 +341,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
break;
|
||||
|
||||
case RPN_STARTOF_SECT:
|
||||
/* This has assumptions commented in the `RPN_BANK_SECT` case above. */
|
||||
// This has assumptions commented in the `RPN_BANK_SECT` case above.
|
||||
name = (char const *)expression;
|
||||
while (getRPNByte(&expression, &size, patch->src, patch->lineNo))
|
||||
;
|
||||
@@ -381,9 +374,8 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
|
||||
case RPN_RST:
|
||||
value = popRPN();
|
||||
/* Acceptable values are 0x00, 0x08, 0x10, ..., 0x38
|
||||
* They can be easily checked with a bitmask
|
||||
*/
|
||||
// Acceptable values are 0x00, 0x08, 0x10, ..., 0x38
|
||||
// They can be easily checked with a bitmask
|
||||
if (value & ~0x38) {
|
||||
if (!isError)
|
||||
error(patch->src, patch->lineNo,
|
||||
@@ -406,7 +398,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
value |= getRPNByte(&expression, &size,
|
||||
patch->src, patch->lineNo) << shift;
|
||||
|
||||
if (value == -1) { /* PC */
|
||||
if (value == -1) { // PC
|
||||
if (!patch->pcSection) {
|
||||
error(patch->src, patch->lineNo,
|
||||
"PC has no value outside a section");
|
||||
@@ -424,7 +416,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
isError = true;
|
||||
} else {
|
||||
value = symbol->value;
|
||||
/* Symbols attached to sections have offsets */
|
||||
// Symbols attached to sections have offsets
|
||||
if (symbol->section)
|
||||
value += symbol->section->org;
|
||||
}
|
||||
@@ -461,8 +453,8 @@ void patch_CheckAssertions(struct Assertion *assert)
|
||||
fatal(assert->patch.src, assert->patch.lineNo, "%s",
|
||||
assert->message[0] ? assert->message
|
||||
: "assert failure");
|
||||
/* Not reached */
|
||||
break; /* Here so checkpatch doesn't complain */
|
||||
// Not reached
|
||||
break; // Here so checkpatch doesn't complain
|
||||
case ASSERT_ERROR:
|
||||
error(assert->patch.src, assert->patch.lineNo, "%s",
|
||||
assert->message[0] ? assert->message
|
||||
@@ -491,7 +483,7 @@ void patch_CheckAssertions(struct Assertion *assert)
|
||||
freeRPNStack();
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Applies all of a section's patches
|
||||
* @param section The section to patch
|
||||
* @param arg Ignored callback arg
|
||||
@@ -506,7 +498,7 @@ static void applyFilePatches(struct Section *section, struct Section *dataSectio
|
||||
section->fileSymbols);
|
||||
uint16_t offset = patch->offset + section->offset;
|
||||
|
||||
/* `jr` is quite unlike the others... */
|
||||
// `jr` is quite unlike the others...
|
||||
if (patch->type == PATCHTYPE_JR) {
|
||||
// Offset is relative to the byte *after* the operand
|
||||
// PC as operand to `jr` is lower than reference PC by 2
|
||||
@@ -519,7 +511,7 @@ static void applyFilePatches(struct Section *section, struct Section *dataSectio
|
||||
jumpOffset);
|
||||
dataSection->data[offset] = jumpOffset & 0xFF;
|
||||
} else {
|
||||
/* Patch a certain number of bytes */
|
||||
// Patch a certain number of bytes
|
||||
struct {
|
||||
uint8_t size;
|
||||
int32_t min;
|
||||
@@ -544,7 +536,7 @@ static void applyFilePatches(struct Section *section, struct Section *dataSectio
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Applies all of a section's patches, iterating over "components" of
|
||||
* unionized sections
|
||||
* @param section The section to patch
|
||||
|
||||
@@ -41,7 +41,7 @@ static void pushFile(char *newFileName)
|
||||
linkerScriptName, lineNo);
|
||||
|
||||
if (fileStackIndex == fileStackSize) {
|
||||
if (!fileStackSize) /* Init file stack */
|
||||
if (!fileStackSize) // Init file stack
|
||||
fileStackSize = 4;
|
||||
fileStackSize *= 2;
|
||||
fileStack = realloc(fileStack, sizeof(*fileStack) * fileStackSize);
|
||||
@@ -88,7 +88,7 @@ static bool isNewline(int c)
|
||||
return c == '\r' || c == '\n';
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Try parsing a number, in base 16 if it begins with a dollar,
|
||||
* in base 10 otherwise
|
||||
* @param str The number to parse
|
||||
@@ -108,7 +108,7 @@ static bool tryParseNumber(char const *str, uint32_t *number)
|
||||
base = 16;
|
||||
}
|
||||
|
||||
/* An empty string is not a number */
|
||||
// An empty string is not a number
|
||||
if (!*str)
|
||||
return false;
|
||||
|
||||
@@ -188,16 +188,16 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
static struct LinkerScriptToken token;
|
||||
int curchar;
|
||||
|
||||
/* If the token has a string, make sure to avoid leaking it */
|
||||
// If the token has a string, make sure to avoid leaking it
|
||||
if (token.type == TOKEN_STRING)
|
||||
free(token.attr.string);
|
||||
|
||||
/* Skip initial whitespace... */
|
||||
// Skip initial whitespace...
|
||||
do
|
||||
curchar = nextChar();
|
||||
while (isWhiteSpace(curchar));
|
||||
|
||||
/* If this is a comment, skip to the end of the line */
|
||||
// If this is a comment, skip to the end of the line
|
||||
if (curchar == ';') {
|
||||
do {
|
||||
curchar = nextChar();
|
||||
@@ -207,22 +207,22 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
if (curchar == EOF) {
|
||||
token.type = TOKEN_EOF;
|
||||
} else if (isNewline(curchar)) {
|
||||
/* If we have a newline char, this is a newline token */
|
||||
// If we have a newline char, this is a newline token
|
||||
token.type = TOKEN_NEWLINE;
|
||||
|
||||
if (curchar == '\r') {
|
||||
/* Handle CRLF */
|
||||
// Handle CRLF
|
||||
curchar = nextChar();
|
||||
if (curchar != '\n')
|
||||
ungetc(curchar, linkerScript);
|
||||
}
|
||||
} else if (curchar == '"') {
|
||||
/* If we have a string start, this is a string */
|
||||
// If we have a string start, this is a string
|
||||
token.type = TOKEN_STRING;
|
||||
token.attr.string = NULL; /* Force initial alloc */
|
||||
token.attr.string = NULL; // Force initial alloc
|
||||
|
||||
size_t size = 0;
|
||||
size_t capacity = 16; /* Half of the default capacity */
|
||||
size_t capacity = 16; // Half of the default capacity
|
||||
|
||||
do {
|
||||
curchar = nextChar();
|
||||
@@ -230,10 +230,10 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
errx("%s(%" PRIu32 "): Unterminated string",
|
||||
linkerScriptName, lineNo);
|
||||
} else if (curchar == '"') {
|
||||
/* Quotes force a string termination */
|
||||
// Quotes force a string termination
|
||||
curchar = '\0';
|
||||
} else if (curchar == '\\') {
|
||||
/* Backslashes are escape sequences */
|
||||
// Backslashes are escape sequences
|
||||
curchar = nextChar();
|
||||
if (curchar == EOF || isNewline(curchar))
|
||||
errx("%s(%" PRIu32 "): Unterminated string",
|
||||
@@ -259,10 +259,10 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
token.attr.string[size++] = curchar;
|
||||
} while (curchar);
|
||||
} else {
|
||||
/* This is either a number, command or bank, that is: a word */
|
||||
// This is either a number, command or bank, that is: a word
|
||||
char *str = NULL;
|
||||
size_t size = 0;
|
||||
size_t capacity = 8; /* Half of the default capacity */
|
||||
size_t capacity = 8; // Half of the default capacity
|
||||
|
||||
for (;;) {
|
||||
if (size >= capacity || str == NULL) {
|
||||
@@ -279,7 +279,7 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
break;
|
||||
|
||||
curchar = nextChar();
|
||||
/* Whitespace, a newline or a comment end the token */
|
||||
// Whitespace, a newline or a comment end the token
|
||||
if (isWhiteSpace(curchar) || isNewline(curchar) || curchar == ';') {
|
||||
ungetc(curchar, linkerScript);
|
||||
curchar = '\0';
|
||||
@@ -288,7 +288,7 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
|
||||
token.type = TOKEN_INVALID;
|
||||
|
||||
/* Try to match a command */
|
||||
// Try to match a command
|
||||
for (enum LinkerScriptCommand i = 0; i < COMMAND_INVALID; i++) {
|
||||
if (!strcmp(commands[i], str)) {
|
||||
token.type = TOKEN_COMMAND;
|
||||
@@ -298,7 +298,7 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
}
|
||||
|
||||
if (token.type == TOKEN_INVALID) {
|
||||
/* Try to match a bank specifier */
|
||||
// Try to match a bank specifier
|
||||
for (enum SectionType type = 0; type < SECTTYPE_INVALID; type++) {
|
||||
if (!strcmp(sectionTypeInfo[type].name, str)) {
|
||||
token.type = TOKEN_BANK;
|
||||
@@ -309,13 +309,13 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
}
|
||||
|
||||
if (token.type == TOKEN_INVALID) {
|
||||
/* Try to match an include token */
|
||||
// Try to match an include token
|
||||
if (!strcmp("INCLUDE", str))
|
||||
token.type = TOKEN_INCLUDE;
|
||||
}
|
||||
|
||||
if (token.type == TOKEN_INVALID) {
|
||||
/* None of the strings matched, do we have a number? */
|
||||
// None of the strings matched, do we have a number?
|
||||
if (tryParseNumber(str, &token.attr.number))
|
||||
token.type = TOKEN_NUMBER;
|
||||
else
|
||||
@@ -354,14 +354,14 @@ static void processCommand(enum LinkerScriptCommand command, uint16_t arg, uint1
|
||||
enum LinkerScriptParserState {
|
||||
PARSER_FIRSTTIME,
|
||||
PARSER_LINESTART,
|
||||
PARSER_INCLUDE, /* After an INCLUDE token */
|
||||
PARSER_INCLUDE, // After an INCLUDE token
|
||||
PARSER_LINEEND
|
||||
};
|
||||
|
||||
/* Part of internal state, but has data that needs to be freed */
|
||||
// Part of internal state, but has data that needs to be freed
|
||||
static uint16_t *curaddr[SECTTYPE_INVALID];
|
||||
|
||||
/* Put as global to ensure it's initialized only once */
|
||||
// Put as global to ensure it's initialized only once
|
||||
static enum LinkerScriptParserState parserState = PARSER_FIRSTTIME;
|
||||
|
||||
struct SectionPlacement *script_NextSection(void)
|
||||
@@ -373,7 +373,7 @@ struct SectionPlacement *script_NextSection(void)
|
||||
if (parserState == PARSER_FIRSTTIME) {
|
||||
lineNo = 1;
|
||||
|
||||
/* Init PC for all banks */
|
||||
// Init PC for all banks
|
||||
for (enum SectionType i = 0; i < SECTTYPE_INVALID; i++) {
|
||||
curaddr[i] = malloc(sizeof(*curaddr[i]) * nbbanks(i));
|
||||
for (uint32_t b = 0; b < nbbanks(i); b++)
|
||||
@@ -427,7 +427,7 @@ struct SectionPlacement *script_NextSection(void)
|
||||
lineNo++;
|
||||
break;
|
||||
|
||||
/* A stray string is a section name */
|
||||
// A stray string is a section name
|
||||
case TOKEN_STRING:
|
||||
parserState = PARSER_LINEEND;
|
||||
|
||||
@@ -454,15 +454,11 @@ struct SectionPlacement *script_NextSection(void)
|
||||
|
||||
token = nextToken();
|
||||
hasArg = token->type == TOKEN_NUMBER;
|
||||
/*
|
||||
* Leaving `arg` uninitialized when `!hasArg`
|
||||
* causes GCC to warn about its use as an
|
||||
* argument to `processCommand`. This cannot
|
||||
* happen because `hasArg` has to be true, but
|
||||
* silence the warning anyways.
|
||||
* I dislike doing this because it could swallow
|
||||
* actual errors, but I don't have a choice.
|
||||
*/
|
||||
// Leaving `arg` uninitialized when `!hasArg` causes GCC to warn
|
||||
// about its use as an argument to `processCommand`. This cannot
|
||||
// happen because `hasArg` has to be true, but silence the warning
|
||||
// anyways. I dislike doing this because it could swallow actual
|
||||
// errors, but I don't have a choice.
|
||||
arg = hasArg ? token->attr.number : 0;
|
||||
|
||||
if (tokType == TOKEN_COMMAND) {
|
||||
@@ -474,12 +470,10 @@ struct SectionPlacement *script_NextSection(void)
|
||||
linkerScriptName, lineNo);
|
||||
|
||||
processCommand(attr.command, arg, &curaddr[placement.type][bankID]);
|
||||
} else { /* TOKEN_BANK */
|
||||
} else { // TOKEN_BANK
|
||||
placement.type = attr.secttype;
|
||||
/*
|
||||
* If there's only one bank,
|
||||
* specifying the number is optional.
|
||||
*/
|
||||
// If there's only one bank,
|
||||
// specifying the number is optional.
|
||||
if (!hasArg && nbbanks(placement.type) != 1)
|
||||
errx("%s(%" PRIu32 "): Didn't specify a bank number",
|
||||
linkerScriptName, lineNo);
|
||||
@@ -497,7 +491,7 @@ struct SectionPlacement *script_NextSection(void)
|
||||
bankID = arg - sectionTypeInfo[placement.type].firstBank;
|
||||
}
|
||||
|
||||
/* If we read a token we shouldn't have... */
|
||||
// If we read a token we shouldn't have...
|
||||
if (token->type != TOKEN_NUMBER)
|
||||
goto lineend;
|
||||
break;
|
||||
@@ -513,9 +507,9 @@ struct SectionPlacement *script_NextSection(void)
|
||||
errx("%s(%" PRIu32 "): Expected a file name after INCLUDE",
|
||||
linkerScriptName, lineNo);
|
||||
|
||||
/* Switch to that file */
|
||||
// Switch to that file
|
||||
pushFile(token->attr.string);
|
||||
/* The file stack took ownership of the string */
|
||||
// The file stack took ownership of the string
|
||||
token->attr.string = NULL;
|
||||
|
||||
parserState = PARSER_LINESTART;
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 2022, Eldred Habert and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
@@ -166,7 +166,7 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se
|
||||
// `data` pointer, or a size of 0.
|
||||
if (other->data) {
|
||||
if (target->data) {
|
||||
/* Ensure we're not allocating 0 bytes */
|
||||
// Ensure we're not allocating 0 bytes
|
||||
target->data = realloc(target->data,
|
||||
sizeof(*target->data) * target->size + 1);
|
||||
if (!target->data)
|
||||
@@ -177,7 +177,7 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se
|
||||
target->data = other->data;
|
||||
other->data = NULL; // Prevent a double free()
|
||||
}
|
||||
/* Adjust patches' PC offsets */
|
||||
// Adjust patches' PC offsets
|
||||
for (uint32_t patchID = 0; patchID < other->nbPatches; patchID++)
|
||||
other->patches[patchID].pcOffset += other->offset;
|
||||
} else if (target->data) {
|
||||
@@ -195,7 +195,7 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se
|
||||
|
||||
void sect_AddSection(struct Section *section)
|
||||
{
|
||||
/* Check if the section already exists */
|
||||
// Check if the section already exists
|
||||
struct Section *other = hash_GetElement(sections, section->name);
|
||||
|
||||
if (other) {
|
||||
@@ -210,7 +210,7 @@ void sect_AddSection(struct Section *section)
|
||||
errx("Section \"%s\" is of type %s, which cannot be unionized",
|
||||
section->name, sectionTypeInfo[section->type].name);
|
||||
} else {
|
||||
/* If not, add it */
|
||||
// If not, add it
|
||||
hash_AddElement(sections, section->name, section);
|
||||
}
|
||||
}
|
||||
@@ -229,7 +229,7 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
||||
{
|
||||
(void)ptr;
|
||||
|
||||
/* Sanity check the section's type */
|
||||
// Sanity check the section's type
|
||||
|
||||
if (section->type < 0 || section->type >= SECTTYPE_INVALID) {
|
||||
error(NULL, 0, "Section \"%s\" has an invalid type", section->name);
|
||||
@@ -254,14 +254,12 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
||||
error(NULL, 0, "%s: VRAM bank 1 can't be used with option -d",
|
||||
section->name);
|
||||
|
||||
/*
|
||||
* Check if alignment is reasonable, this is important to avoid UB
|
||||
* An alignment of zero is equivalent to no alignment, basically
|
||||
*/
|
||||
// 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)
|
||||
section->isAlignFixed = false;
|
||||
|
||||
/* Too large an alignment may not be satisfiable */
|
||||
// Too large an alignment may not be satisfiable
|
||||
if (section->isAlignFixed && (section->alignMask & sectionTypeInfo[section->type].startAddr))
|
||||
error(NULL, 0, "%s: %s sections cannot be aligned to $%04x bytes",
|
||||
section->name, sectionTypeInfo[section->type].name, section->alignMask + 1);
|
||||
@@ -274,12 +272,12 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
||||
: "Cannot place section \"%s\" in bank %" PRIu32 ", it must be between %" PRIu32 " and %" PRIu32,
|
||||
section->name, section->bank, minbank, maxbank);
|
||||
|
||||
/* Check if section has a chance to be placed */
|
||||
// Check if section has a chance to be placed
|
||||
if (section->size > sectionTypeInfo[section->type].size)
|
||||
error(NULL, 0, "Section \"%s\" is bigger than the max size for that type: %#" PRIx16 " > %#" PRIx16,
|
||||
section->name, section->size, sectionTypeInfo[section->type].size);
|
||||
|
||||
/* Translate loose constraints to strong ones when they're equivalent */
|
||||
// Translate loose constraints to strong ones when they're equivalent
|
||||
|
||||
if (minbank == maxbank) {
|
||||
section->bank = minbank;
|
||||
@@ -287,7 +285,7 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
||||
}
|
||||
|
||||
if (section->isAddressFixed) {
|
||||
/* It doesn't make sense to have both org and alignment set */
|
||||
// It doesn't make sense to have both org and alignment set
|
||||
if (section->isAlignFixed) {
|
||||
if ((section->org & section->alignMask) != section->alignOfs)
|
||||
error(NULL, 0, "Section \"%s\"'s fixed address doesn't match its alignment",
|
||||
@@ -295,7 +293,7 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
||||
section->isAlignFixed = false;
|
||||
}
|
||||
|
||||
/* Ensure the target address is valid */
|
||||
// Ensure the target address is valid
|
||||
if (section->org < sectionTypeInfo[section->type].startAddr
|
||||
|| section->org > endaddr(section->type))
|
||||
error(NULL, 0, "Section \"%s\"'s fixed address %#" PRIx16 " is outside of range [%#"
|
||||
|
||||
@@ -40,7 +40,7 @@ void sym_ForEach(void (*callback)(struct Symbol *, void *), void *arg)
|
||||
|
||||
void sym_AddSymbol(struct Symbol *symbol)
|
||||
{
|
||||
/* Check if the symbol already exists */
|
||||
// Check if the symbol already exists
|
||||
struct Symbol *other = hash_GetElement(symbols, symbol->name);
|
||||
|
||||
if (other) {
|
||||
@@ -53,7 +53,7 @@ void sym_AddSymbol(struct Symbol *symbol)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* If not, add it */
|
||||
// If not, add it
|
||||
hash_AddElement(symbols, symbol->name, symbol);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user