mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Replace RGBLINK non-null pointers with references
This commit is contained in:
@@ -12,11 +12,6 @@
|
|||||||
*/
|
*/
|
||||||
void obj_ReadFile(char const *fileName, unsigned int i);
|
void obj_ReadFile(char const *fileName, unsigned int i);
|
||||||
|
|
||||||
/*
|
|
||||||
* Perform validation on the object files' contents
|
|
||||||
*/
|
|
||||||
void obj_DoSanityChecks();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Evaluate all assertions
|
* Evaluate all assertions
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -12,14 +12,14 @@
|
|||||||
* Registers a section for output.
|
* Registers a section for output.
|
||||||
* @param section The section to add
|
* @param section The section to add
|
||||||
*/
|
*/
|
||||||
void out_AddSection(Section const *section);
|
void out_AddSection(Section const §ion);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finds an assigned section overlapping another one.
|
* Finds an assigned section overlapping another one.
|
||||||
* @param section The section that is being overlapped
|
* @param section The section that is being overlapped
|
||||||
* @return A section overlapping it
|
* @return A section overlapping it
|
||||||
*/
|
*/
|
||||||
Section const *out_OverlappingSection(Section const *section);
|
Section const *out_OverlappingSection(Section const §ion);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Writes all output (bin, sym, map) files.
|
* Writes all output (bin, sym, map) files.
|
||||||
|
|||||||
@@ -10,6 +10,6 @@
|
|||||||
struct FileStackNode;
|
struct FileStackNode;
|
||||||
struct Symbol;
|
struct Symbol;
|
||||||
|
|
||||||
void sdobj_ReadFile(FileStackNode const *fileName, FILE *file, std::vector<Symbol> &fileSymbols);
|
void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol> &fileSymbols);
|
||||||
|
|
||||||
#endif // RGBDS_LINK_SDAS_OBJ_H
|
#endif // RGBDS_LINK_SDAS_OBJ_H
|
||||||
|
|||||||
@@ -58,13 +58,13 @@ struct Section {
|
|||||||
* This is to avoid exposing the data structure in which sections are stored.
|
* This is to avoid exposing the data structure in which sections are stored.
|
||||||
* @param callback The function to call for each structure.
|
* @param callback The function to call for each structure.
|
||||||
*/
|
*/
|
||||||
void sect_ForEach(void (*callback)(Section *));
|
void sect_ForEach(void (*callback)(Section &));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Registers a section to be processed.
|
* Registers a section to be processed.
|
||||||
* @param section The section to register.
|
* @param section The section to register.
|
||||||
*/
|
*/
|
||||||
void sect_AddSection(Section *section);
|
void sect_AddSection(Section §ion);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finds a section by its name.
|
* Finds a section by its name.
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ struct Symbol {
|
|||||||
Section *section;
|
Section *section;
|
||||||
};
|
};
|
||||||
|
|
||||||
void sym_AddSymbol(Symbol *symbol);
|
void sym_AddSymbol(Symbol &symbol);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finds a symbol in all the defined symbols.
|
* Finds a symbol in all the defined symbols.
|
||||||
|
|||||||
@@ -54,16 +54,13 @@ static void initFreeSpace()
|
|||||||
* @param section The section to assign
|
* @param section The section to assign
|
||||||
* @param location The location to assign the section to
|
* @param location The location to assign the section to
|
||||||
*/
|
*/
|
||||||
static void assignSection(Section *section, MemoryLocation const *location)
|
static void assignSection(Section §ion, MemoryLocation const &location)
|
||||||
{
|
{
|
||||||
section->org = location->address;
|
|
||||||
section->bank = location->bank;
|
|
||||||
|
|
||||||
// Propagate the assigned location to all UNIONs/FRAGMENTs
|
// Propagate the assigned location to all UNIONs/FRAGMENTs
|
||||||
// so `jr` patches in them will have the correct offset
|
// so `jr` patches in them will have the correct offset
|
||||||
for (Section *next = section->nextu; next != nullptr; next = next->nextu) {
|
for (Section *next = §ion; next != nullptr; next = next->nextu) {
|
||||||
next->org = section->org;
|
next->org = location.address;
|
||||||
next->bank = section->bank;
|
next->bank = location.bank;
|
||||||
}
|
}
|
||||||
|
|
||||||
nbSectionsToAssign--;
|
nbSectionsToAssign--;
|
||||||
@@ -80,19 +77,19 @@ static void assignSection(Section *section, MemoryLocation const *location)
|
|||||||
* @param location The location to attempt placing the section at
|
* @param location The location to attempt placing the section at
|
||||||
* @return True if the location is suitable, false otherwise.
|
* @return True if the location is suitable, false otherwise.
|
||||||
*/
|
*/
|
||||||
static bool isLocationSuitable(Section const *section, FreeSpace const &freeSpace,
|
static bool isLocationSuitable(Section const §ion, FreeSpace const &freeSpace,
|
||||||
MemoryLocation const *location)
|
MemoryLocation const &location)
|
||||||
{
|
{
|
||||||
if (section->isAddressFixed && section->org != location->address)
|
if (section.isAddressFixed && section.org != location.address)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (section->isAlignFixed && ((location->address - section->alignOfs) & section->alignMask))
|
if (section.isAlignFixed && ((location.address - section.alignOfs) & section.alignMask))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (location->address < freeSpace.address)
|
if (location.address < freeSpace.address)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return location->address + section->size <= freeSpace.address + freeSpace.size;
|
return location.address + section.size <= freeSpace.address + freeSpace.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -102,40 +99,40 @@ static bool isLocationSuitable(Section const *section, FreeSpace const &freeSpac
|
|||||||
* @return The index into `memory[section->type]` of the free space encompassing the location,
|
* @return The index into `memory[section->type]` of the free space encompassing the location,
|
||||||
* or -1 if none was found
|
* or -1 if none was found
|
||||||
*/
|
*/
|
||||||
static ssize_t getPlacement(Section const *section, MemoryLocation *location)
|
static ssize_t getPlacement(Section const §ion, MemoryLocation &location)
|
||||||
{
|
{
|
||||||
SectionTypeInfo const &typeInfo = sectionTypeInfo[section->type];
|
SectionTypeInfo const &typeInfo = sectionTypeInfo[section.type];
|
||||||
|
|
||||||
static uint16_t curScrambleROM = 0;
|
static uint16_t curScrambleROM = 0;
|
||||||
static uint8_t curScrambleWRAM = 0;
|
static uint8_t curScrambleWRAM = 0;
|
||||||
static int8_t curScrambleSRAM = 0;
|
static int8_t curScrambleSRAM = 0;
|
||||||
|
|
||||||
// Determine which bank we should start searching in
|
// Determine which bank we should start searching in
|
||||||
if (section->isBankFixed) {
|
if (section.isBankFixed) {
|
||||||
location->bank = section->bank;
|
location.bank = section.bank;
|
||||||
} else if (scrambleROMX && section->type == SECTTYPE_ROMX) {
|
} else if (scrambleROMX && section.type == SECTTYPE_ROMX) {
|
||||||
if (curScrambleROM < 1)
|
if (curScrambleROM < 1)
|
||||||
curScrambleROM = scrambleROMX;
|
curScrambleROM = scrambleROMX;
|
||||||
location->bank = curScrambleROM--;
|
location.bank = curScrambleROM--;
|
||||||
} else if (scrambleWRAMX && section->type == SECTTYPE_WRAMX) {
|
} else if (scrambleWRAMX && section.type == SECTTYPE_WRAMX) {
|
||||||
if (curScrambleWRAM < 1)
|
if (curScrambleWRAM < 1)
|
||||||
curScrambleWRAM = scrambleWRAMX;
|
curScrambleWRAM = scrambleWRAMX;
|
||||||
location->bank = curScrambleWRAM--;
|
location.bank = curScrambleWRAM--;
|
||||||
} else if (scrambleSRAM && section->type == SECTTYPE_SRAM) {
|
} else if (scrambleSRAM && section.type == SECTTYPE_SRAM) {
|
||||||
if (curScrambleSRAM < 0)
|
if (curScrambleSRAM < 0)
|
||||||
curScrambleSRAM = scrambleSRAM;
|
curScrambleSRAM = scrambleSRAM;
|
||||||
location->bank = curScrambleSRAM--;
|
location.bank = curScrambleSRAM--;
|
||||||
} else {
|
} else {
|
||||||
location->bank = typeInfo.firstBank;
|
location.bank = typeInfo.firstBank;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Switch to the beginning of the next bank
|
// Switch to the beginning of the next bank
|
||||||
std::deque<FreeSpace> &bankMem = memory[section->type][location->bank - typeInfo.firstBank];
|
std::deque<FreeSpace> &bankMem = memory[section.type][location.bank - typeInfo.firstBank];
|
||||||
size_t spaceIdx = 0;
|
size_t spaceIdx = 0;
|
||||||
|
|
||||||
if (spaceIdx < bankMem.size())
|
if (spaceIdx < bankMem.size())
|
||||||
location->address = bankMem[spaceIdx].address;
|
location.address = bankMem[spaceIdx].address;
|
||||||
|
|
||||||
// Process locations in that bank
|
// Process locations in that bank
|
||||||
while (spaceIdx < bankMem.size()) {
|
while (spaceIdx < bankMem.size()) {
|
||||||
@@ -144,32 +141,32 @@ static ssize_t getPlacement(Section const *section, MemoryLocation *location)
|
|||||||
return spaceIdx;
|
return spaceIdx;
|
||||||
|
|
||||||
// Go to the next *possible* location
|
// Go to the next *possible* location
|
||||||
if (section->isAddressFixed) {
|
if (section.isAddressFixed) {
|
||||||
// If the address is fixed, there can be only
|
// If the address is fixed, there can be only
|
||||||
// one candidate block per bank; if we already
|
// one candidate block per bank; if we already
|
||||||
// reached it, give up.
|
// reached it, give up.
|
||||||
if (location->address < section->org)
|
if (location.address < section.org)
|
||||||
location->address = section->org;
|
location.address = section.org;
|
||||||
else
|
else
|
||||||
break; // Try again in next bank
|
break; // Try again in next bank
|
||||||
} else if (section->isAlignFixed) {
|
} else if (section.isAlignFixed) {
|
||||||
// Move to next aligned location
|
// Move to next aligned location
|
||||||
// Move back to alignment boundary
|
// Move back to alignment boundary
|
||||||
location->address -= section->alignOfs;
|
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;
|
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;
|
location.address += section.alignMask + 1 + section.alignOfs;
|
||||||
} else {
|
} else {
|
||||||
// Any location is fine, so, next free block
|
// Any location is fine, so, next free block
|
||||||
spaceIdx++;
|
spaceIdx++;
|
||||||
if (spaceIdx < bankMem.size())
|
if (spaceIdx < bankMem.size())
|
||||||
location->address = bankMem[spaceIdx].address;
|
location.address = bankMem[spaceIdx].address;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If that location is past the current block's end,
|
// If that location is past the current block's end,
|
||||||
// go forwards until that is no longer the case.
|
// go forwards until that is no longer the case.
|
||||||
while (spaceIdx < bankMem.size() && location->address >=
|
while (spaceIdx < bankMem.size() && location.address >=
|
||||||
bankMem[spaceIdx].address + bankMem[spaceIdx].size)
|
bankMem[spaceIdx].address + bankMem[spaceIdx].size)
|
||||||
spaceIdx++;
|
spaceIdx++;
|
||||||
|
|
||||||
@@ -179,31 +176,31 @@ static ssize_t getPlacement(Section const *section, MemoryLocation *location)
|
|||||||
// Try again in the next bank, if one is available.
|
// Try again in the next bank, if one is available.
|
||||||
// Try scrambled banks in descending order until no bank in the scrambled range is available.
|
// Try scrambled banks in descending order until no bank in the scrambled range is available.
|
||||||
// Otherwise, try in ascending order.
|
// Otherwise, try in ascending order.
|
||||||
if (section->isBankFixed) {
|
if (section.isBankFixed) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (scrambleROMX && section->type == SECTTYPE_ROMX && location->bank <= scrambleROMX) {
|
} else if (scrambleROMX && section.type == SECTTYPE_ROMX && location.bank <= scrambleROMX) {
|
||||||
if (location->bank > typeInfo.firstBank)
|
if (location.bank > typeInfo.firstBank)
|
||||||
location->bank--;
|
location.bank--;
|
||||||
else if (scrambleROMX < typeInfo.lastBank)
|
else if (scrambleROMX < typeInfo.lastBank)
|
||||||
location->bank = scrambleROMX + 1;
|
location.bank = scrambleROMX + 1;
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
} else if (scrambleWRAMX && section->type == SECTTYPE_WRAMX && location->bank <= scrambleWRAMX) {
|
} else if (scrambleWRAMX && section.type == SECTTYPE_WRAMX && location.bank <= scrambleWRAMX) {
|
||||||
if (location->bank > typeInfo.firstBank)
|
if (location.bank > typeInfo.firstBank)
|
||||||
location->bank--;
|
location.bank--;
|
||||||
else if (scrambleWRAMX < typeInfo.lastBank)
|
else if (scrambleWRAMX < typeInfo.lastBank)
|
||||||
location->bank = scrambleWRAMX + 1;
|
location.bank = scrambleWRAMX + 1;
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
} else if (scrambleSRAM && section->type == SECTTYPE_SRAM && location->bank <= scrambleSRAM) {
|
} else if (scrambleSRAM && section.type == SECTTYPE_SRAM && location.bank <= scrambleSRAM) {
|
||||||
if (location->bank > typeInfo.firstBank)
|
if (location.bank > typeInfo.firstBank)
|
||||||
location->bank--;
|
location.bank--;
|
||||||
else if (scrambleSRAM < typeInfo.lastBank)
|
else if (scrambleSRAM < typeInfo.lastBank)
|
||||||
location->bank = scrambleSRAM + 1;
|
location.bank = scrambleSRAM + 1;
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
} else if (location->bank < typeInfo.lastBank) {
|
} else if (location.bank < typeInfo.lastBank) {
|
||||||
location->bank++;
|
location.bank++;
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -216,36 +213,36 @@ static ssize_t getPlacement(Section const *section, MemoryLocation *location)
|
|||||||
* sections of decreasing size.
|
* sections of decreasing size.
|
||||||
* @param section The section to place
|
* @param section The section to place
|
||||||
*/
|
*/
|
||||||
static void placeSection(Section *section)
|
static void placeSection(Section §ion)
|
||||||
{
|
{
|
||||||
MemoryLocation location;
|
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) {
|
if (section.size == 0) {
|
||||||
// Unless the SECTION's address was fixed, the starting address
|
// Unless the SECTION's address was fixed, the starting address
|
||||||
// is fine for any alignment, as checked in sect_DoSanityChecks.
|
// is fine for any alignment, as checked in sect_DoSanityChecks.
|
||||||
location.address = section->isAddressFixed
|
location.address = section.isAddressFixed
|
||||||
? section->org
|
? section.org
|
||||||
: sectionTypeInfo[section->type].startAddr;
|
: sectionTypeInfo[section.type].startAddr;
|
||||||
location.bank = section->isBankFixed
|
location.bank = section.isBankFixed
|
||||||
? section->bank
|
? section.bank
|
||||||
: sectionTypeInfo[section->type].firstBank;
|
: sectionTypeInfo[section.type].firstBank;
|
||||||
assignSection(section, &location);
|
assignSection(section, location);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Place section using first-fit decreasing algorithm
|
// Place section using first-fit decreasing algorithm
|
||||||
// https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm
|
// https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm
|
||||||
if (ssize_t spaceIdx = getPlacement(section, &location); spaceIdx != -1) {
|
if (ssize_t spaceIdx = getPlacement(section, location); spaceIdx != -1) {
|
||||||
std::deque<FreeSpace> &bankMem = memory[section->type][location.bank -
|
std::deque<FreeSpace> &bankMem = memory[section.type][location.bank -
|
||||||
sectionTypeInfo[section->type].firstBank];
|
sectionTypeInfo[section.type].firstBank];
|
||||||
FreeSpace &freeSpace = bankMem[spaceIdx];
|
FreeSpace &freeSpace = bankMem[spaceIdx];
|
||||||
|
|
||||||
assignSection(section, &location);
|
assignSection(section, location);
|
||||||
|
|
||||||
// Update the free space
|
// Update the free space
|
||||||
bool noLeftSpace = freeSpace.address == section->org;
|
bool noLeftSpace = freeSpace.address == section.org;
|
||||||
bool noRightSpace = freeSpace.address + freeSpace.size == section->org + section->size;
|
bool noRightSpace = freeSpace.address + freeSpace.size == section.org + section.size;
|
||||||
if (noLeftSpace && noRightSpace) {
|
if (noLeftSpace && noRightSpace) {
|
||||||
// The free space is entirely deleted
|
// The free space is entirely deleted
|
||||||
bankMem.erase(bankMem.begin() + spaceIdx);
|
bankMem.erase(bankMem.begin() + spaceIdx);
|
||||||
@@ -253,18 +250,18 @@ static void placeSection(Section *section)
|
|||||||
// The free space is split in two
|
// The free space is split in two
|
||||||
// Append the new space after the original one
|
// Append the new space after the original one
|
||||||
bankMem.insert(bankMem.begin() + spaceIdx + 1, {
|
bankMem.insert(bankMem.begin() + spaceIdx + 1, {
|
||||||
.address = (uint16_t)(section->org + section->size),
|
.address = (uint16_t)(section.org + section.size),
|
||||||
.size = (uint16_t)(freeSpace.address + freeSpace.size -
|
.size = (uint16_t)(freeSpace.address + freeSpace.size -
|
||||||
section->org - section->size)
|
section.org - section.size)
|
||||||
});
|
});
|
||||||
// Resize the original space (address is unmodified)
|
// Resize the original space (address is unmodified)
|
||||||
freeSpace.size = section->org - freeSpace.address;
|
freeSpace.size = section.org - freeSpace.address;
|
||||||
} else {
|
} else {
|
||||||
// The amount of free spaces doesn't change: resize!
|
// The amount of free spaces doesn't change: resize!
|
||||||
freeSpace.size -= section->size;
|
freeSpace.size -= section.size;
|
||||||
if (noLeftSpace)
|
if (noLeftSpace)
|
||||||
// The free space is moved *and* resized
|
// The free space is moved *and* resized
|
||||||
freeSpace.address += section->size;
|
freeSpace.address += section.size;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -272,38 +269,38 @@ static void placeSection(Section *section)
|
|||||||
// Please adjust depending on longest message below
|
// Please adjust depending on longest message below
|
||||||
char where[64];
|
char where[64];
|
||||||
|
|
||||||
if (section->isBankFixed && nbbanks(section->type) != 1) {
|
if (section.isBankFixed && nbbanks(section.type) != 1) {
|
||||||
if (section->isAddressFixed)
|
if (section.isAddressFixed)
|
||||||
snprintf(where, sizeof(where), "at $%02" PRIx32 ":%04" PRIx16,
|
snprintf(where, sizeof(where), "at $%02" PRIx32 ":%04" PRIx16,
|
||||||
section->bank, section->org);
|
section.bank, section.org);
|
||||||
else if (section->isAlignFixed)
|
else if (section.isAlignFixed)
|
||||||
snprintf(where, sizeof(where), "in bank $%02" PRIx32 " with align mask %" PRIx16,
|
snprintf(where, sizeof(where), "in bank $%02" PRIx32 " with align mask %" PRIx16,
|
||||||
section->bank, (uint16_t)~section->alignMask);
|
section.bank, (uint16_t)~section.alignMask);
|
||||||
else
|
else
|
||||||
snprintf(where, sizeof(where), "in bank $%02" PRIx32, section->bank);
|
snprintf(where, sizeof(where), "in bank $%02" PRIx32, section.bank);
|
||||||
} else {
|
} else {
|
||||||
if (section->isAddressFixed)
|
if (section.isAddressFixed)
|
||||||
snprintf(where, sizeof(where), "at address $%04" PRIx16, section->org);
|
snprintf(where, sizeof(where), "at address $%04" PRIx16, section.org);
|
||||||
else if (section->isAlignFixed)
|
else if (section.isAlignFixed)
|
||||||
snprintf(where, sizeof(where), "with align mask %" PRIx16 " and offset %" PRIx16,
|
snprintf(where, sizeof(where), "with align mask %" PRIx16 " and offset %" PRIx16,
|
||||||
(uint16_t)~section->alignMask, section->alignOfs);
|
(uint16_t)~section.alignMask, section.alignOfs);
|
||||||
else
|
else
|
||||||
strcpy(where, "anywhere");
|
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)
|
if (!section.isBankFixed || !section.isAddressFixed)
|
||||||
errx("Unable to place \"%s\" (%s section) %s",
|
errx("Unable to place \"%s\" (%s section) %s",
|
||||||
section->name.c_str(), sectionTypeInfo[section->type].name.c_str(), where);
|
section.name.c_str(), sectionTypeInfo[section.type].name.c_str(), 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)
|
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)",
|
errx("Unable to place \"%s\" (%s section) %s: section runs past end of region ($%04x > $%04x)",
|
||||||
section->name.c_str(), sectionTypeInfo[section->type].name.c_str(), where,
|
section.name.c_str(), sectionTypeInfo[section.type].name.c_str(), where,
|
||||||
section->org + section->size, endaddr(section->type) + 1);
|
section.org + section.size, endaddr(section.type) + 1);
|
||||||
// Otherwise there is overlap with another section
|
// Otherwise there is overlap with another section
|
||||||
else
|
else
|
||||||
errx("Unable to place \"%s\" (%s section) %s: section overlaps with \"%s\"",
|
errx("Unable to place \"%s\" (%s section) %s: section overlaps with \"%s\"",
|
||||||
section->name.c_str(), sectionTypeInfo[section->type].name.c_str(), where,
|
section.name.c_str(), sectionTypeInfo[section.type].name.c_str(), where,
|
||||||
out_OverlappingSection(section)->name.c_str());
|
out_OverlappingSection(section)->name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,25 +314,25 @@ static std::deque<Section *> unassignedSections[1 << 3];
|
|||||||
* This is so the most-constrained sections are placed first
|
* This is so the most-constrained sections are placed first
|
||||||
* @param section The section to categorize
|
* @param section The section to categorize
|
||||||
*/
|
*/
|
||||||
static void categorizeSection(Section *section)
|
static void categorizeSection(Section §ion)
|
||||||
{
|
{
|
||||||
uint8_t constraints = 0;
|
uint8_t constraints = 0;
|
||||||
|
|
||||||
if (section->isBankFixed)
|
if (section.isBankFixed)
|
||||||
constraints |= BANK_CONSTRAINED;
|
constraints |= BANK_CONSTRAINED;
|
||||||
if (section->isAddressFixed)
|
if (section.isAddressFixed)
|
||||||
constraints |= ORG_CONSTRAINED;
|
constraints |= ORG_CONSTRAINED;
|
||||||
// Can't have both!
|
// Can't have both!
|
||||||
else if (section->isAlignFixed)
|
else if (section.isAlignFixed)
|
||||||
constraints |= ALIGN_CONSTRAINED;
|
constraints |= ALIGN_CONSTRAINED;
|
||||||
|
|
||||||
std::deque<Section *> §ions = unassignedSections[constraints];
|
std::deque<Section *> §ions = unassignedSections[constraints];
|
||||||
auto pos = sections.begin();
|
auto pos = sections.begin();
|
||||||
|
|
||||||
// Insert section while keeping the list sorted by decreasing size
|
// 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++;
|
pos++;
|
||||||
sections.insert(pos, section);
|
sections.insert(pos, §ion);
|
||||||
|
|
||||||
nbSectionsToAssign++;
|
nbSectionsToAssign++;
|
||||||
}
|
}
|
||||||
@@ -357,7 +354,7 @@ void assign_AssignSections()
|
|||||||
// Specially process fully-constrained sections because of overlaying
|
// Specially process fully-constrained sections because of overlaying
|
||||||
verbosePrint("Assigning bank+org-constrained...\n");
|
verbosePrint("Assigning bank+org-constrained...\n");
|
||||||
for (Section *section : unassignedSections[BANK_CONSTRAINED | ORG_CONSTRAINED])
|
for (Section *section : unassignedSections[BANK_CONSTRAINED | ORG_CONSTRAINED])
|
||||||
placeSection(section);
|
placeSection(*section);
|
||||||
|
|
||||||
// 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)
|
if (!nbSectionsToAssign)
|
||||||
@@ -389,7 +386,7 @@ max_out:
|
|||||||
// 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--) {
|
for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED; constraints >= 0; constraints--) {
|
||||||
for (Section *section : unassignedSections[constraints])
|
for (Section *section : unassignedSections[constraints])
|
||||||
placeSection(section);
|
placeSection(*section);
|
||||||
|
|
||||||
if (!nbSectionsToAssign)
|
if (!nbSectionsToAssign)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -342,11 +342,13 @@ next:
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeSection(Section *section)
|
static void freeSection(Section §ion)
|
||||||
{
|
{
|
||||||
for (Section *next; section; section = next) {
|
Section *next = §ion;
|
||||||
next = section->nextu;
|
|
||||||
delete section;
|
for (Section *nextu; next; next = nextu) {
|
||||||
|
nextu = next->nextu;
|
||||||
|
delete next;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,7 +480,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// then process them,
|
// then process them,
|
||||||
obj_DoSanityChecks();
|
sect_DoSanityChecks();
|
||||||
if (nbErrors != 0)
|
if (nbErrors != 0)
|
||||||
reportErrors();
|
reportErrors();
|
||||||
assign_AssignSections();
|
assign_AssignSections();
|
||||||
|
|||||||
@@ -33,8 +33,7 @@ static std::deque<Assertion> assertions;
|
|||||||
|
|
||||||
// Internal, DO NOT USE.
|
// Internal, DO NOT USE.
|
||||||
// For helper wrapper macros defined below, such as `tryReadlong`
|
// For helper wrapper macros defined below, such as `tryReadlong`
|
||||||
#define tryRead(func, type, errval, vartype, var, file, ...) \
|
#define tryRead(func, type, errval, vartype, var, file, ...) do { \
|
||||||
do { \
|
|
||||||
FILE *tmpFile = file; \
|
FILE *tmpFile = file; \
|
||||||
type tmpVal = func(tmpFile); \
|
type tmpVal = func(tmpFile); \
|
||||||
/* TODO: maybe mark the condition as `unlikely`; how to do that portably? */ \
|
/* TODO: maybe mark the condition as `unlikely`; how to do that portably? */ \
|
||||||
@@ -44,7 +43,7 @@ static std::deque<Assertion> assertions;
|
|||||||
: strerror(errno)); \
|
: strerror(errno)); \
|
||||||
} \
|
} \
|
||||||
var = (vartype)tmpVal; \
|
var = (vartype)tmpVal; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reads an unsigned long (32-bit) value from a file.
|
* Reads an unsigned long (32-bit) value from a file.
|
||||||
@@ -104,8 +103,7 @@ static int64_t readlong(FILE *file)
|
|||||||
* @param ... A format string and related arguments; note that an extra string
|
* @param ... A format string and related arguments; note that an extra string
|
||||||
* argument is provided, the reason for failure
|
* argument is provided, the reason for failure
|
||||||
*/
|
*/
|
||||||
#define tryReadstring(var, file, ...) \
|
#define tryReadstring(var, file, ...) do { \
|
||||||
do { \
|
|
||||||
FILE *tmpFile = file; \
|
FILE *tmpFile = file; \
|
||||||
std::string &tmpVal = var; \
|
std::string &tmpVal = var; \
|
||||||
for (int tmpByte = getc(tmpFile); tmpByte != '\0'; tmpByte = getc(tmpFile)) { \
|
for (int tmpByte = getc(tmpFile); tmpByte != '\0'; tmpByte = getc(tmpFile)) { \
|
||||||
@@ -117,7 +115,7 @@ static int64_t readlong(FILE *file)
|
|||||||
tmpVal.push_back(tmpByte); \
|
tmpVal.push_back(tmpByte); \
|
||||||
} \
|
} \
|
||||||
}; \
|
}; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
// Functions to parse object files
|
// Functions to parse object files
|
||||||
|
|
||||||
@@ -170,28 +168,28 @@ static void readFileStackNode(FILE *file, std::vector<FileStackNode> &fileNodes,
|
|||||||
* @param symbol The symbol to fill
|
* @param symbol The symbol to fill
|
||||||
* @param fileName The filename to report in errors
|
* @param fileName The filename to report in errors
|
||||||
*/
|
*/
|
||||||
static void readSymbol(FILE *file, Symbol *symbol, char const *fileName,
|
static void readSymbol(FILE *file, Symbol &symbol, char const *fileName,
|
||||||
std::vector<FileStackNode> const &fileNodes)
|
std::vector<FileStackNode> const &fileNodes)
|
||||||
{
|
{
|
||||||
tryReadstring(symbol->name, file, "%s: Cannot read symbol name: %s", fileName);
|
tryReadstring(symbol.name, file, "%s: Cannot read symbol name: %s", fileName);
|
||||||
tryGetc(enum ExportLevel, symbol->type, file, "%s: Cannot read \"%s\"'s type: %s",
|
tryGetc(enum ExportLevel, symbol.type, file, "%s: Cannot read \"%s\"'s type: %s",
|
||||||
fileName, symbol->name.c_str());
|
fileName, symbol.name.c_str());
|
||||||
// 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) {
|
if (symbol.type != SYMTYPE_IMPORT) {
|
||||||
symbol->objFileName = fileName;
|
symbol.objFileName = fileName;
|
||||||
uint32_t nodeID;
|
uint32_t nodeID;
|
||||||
|
|
||||||
tryReadlong(nodeID, file, "%s: Cannot read \"%s\"'s node ID: %s",
|
tryReadlong(nodeID, file, "%s: Cannot read \"%s\"'s node ID: %s",
|
||||||
fileName, symbol->name.c_str());
|
fileName, symbol.name.c_str());
|
||||||
symbol->src = &fileNodes[nodeID];
|
symbol.src = &fileNodes[nodeID];
|
||||||
tryReadlong(symbol->lineNo, file, "%s: Cannot read \"%s\"'s line number: %s",
|
tryReadlong(symbol.lineNo, file, "%s: Cannot read \"%s\"'s line number: %s",
|
||||||
fileName, symbol->name.c_str());
|
fileName, symbol.name.c_str());
|
||||||
tryReadlong(symbol->sectionID, file, "%s: Cannot read \"%s\"'s section ID: %s",
|
tryReadlong(symbol.sectionID, file, "%s: Cannot read \"%s\"'s section ID: %s",
|
||||||
fileName, symbol->name.c_str());
|
fileName, symbol.name.c_str());
|
||||||
tryReadlong(symbol->offset, file, "%s: Cannot read \"%s\"'s value: %s",
|
tryReadlong(symbol.offset, file, "%s: Cannot read \"%s\"'s value: %s",
|
||||||
fileName, symbol->name.c_str());
|
fileName, symbol.name.c_str());
|
||||||
} else {
|
} else {
|
||||||
symbol->sectionID = -1;
|
symbol.sectionID = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +200,7 @@ static void readSymbol(FILE *file, Symbol *symbol, char const *fileName,
|
|||||||
* @param fileName The filename to report in errors
|
* @param fileName The filename to report in errors
|
||||||
* @param i The number of the patch to report in errors
|
* @param i The number of the patch to report in errors
|
||||||
*/
|
*/
|
||||||
static void readPatch(FILE *file, Patch *patch, char const *fileName, std::string const §Name,
|
static void readPatch(FILE *file, Patch &patch, char const *fileName, std::string const §Name,
|
||||||
uint32_t i, std::vector<FileStackNode> const &fileNodes)
|
uint32_t i, std::vector<FileStackNode> const &fileNodes)
|
||||||
{
|
{
|
||||||
uint32_t nodeID, rpnSize;
|
uint32_t nodeID, rpnSize;
|
||||||
@@ -211,29 +209,29 @@ static void readPatch(FILE *file, Patch *patch, char const *fileName, std::strin
|
|||||||
tryReadlong(nodeID, file,
|
tryReadlong(nodeID, file,
|
||||||
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s node ID: %s",
|
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s node ID: %s",
|
||||||
fileName, sectName.c_str(), i);
|
fileName, sectName.c_str(), i);
|
||||||
patch->src = &fileNodes[nodeID];
|
patch.src = &fileNodes[nodeID];
|
||||||
tryReadlong(patch->lineNo, file,
|
tryReadlong(patch.lineNo, file,
|
||||||
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s line number: %s",
|
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s line number: %s",
|
||||||
fileName, sectName.c_str(), i);
|
fileName, sectName.c_str(), i);
|
||||||
tryReadlong(patch->offset, file,
|
tryReadlong(patch.offset, file,
|
||||||
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s offset: %s",
|
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s offset: %s",
|
||||||
fileName, sectName.c_str(), i);
|
fileName, sectName.c_str(), i);
|
||||||
tryReadlong(patch->pcSectionID, file,
|
tryReadlong(patch.pcSectionID, file,
|
||||||
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s",
|
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s",
|
||||||
fileName, sectName.c_str(), i);
|
fileName, sectName.c_str(), i);
|
||||||
tryReadlong(patch->pcOffset, file,
|
tryReadlong(patch.pcOffset, file,
|
||||||
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s",
|
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s",
|
||||||
fileName, sectName.c_str(), i);
|
fileName, sectName.c_str(), i);
|
||||||
tryGetc(enum PatchType, type, file,
|
tryGetc(enum PatchType, type, file,
|
||||||
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s type: %s",
|
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s type: %s",
|
||||||
fileName, sectName.c_str(), i);
|
fileName, sectName.c_str(), i);
|
||||||
patch->type = type;
|
patch.type = type;
|
||||||
tryReadlong(rpnSize, file,
|
tryReadlong(rpnSize, file,
|
||||||
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s RPN size: %s",
|
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s RPN size: %s",
|
||||||
fileName, sectName.c_str(), i);
|
fileName, sectName.c_str(), i);
|
||||||
|
|
||||||
patch->rpnExpression.resize(rpnSize);
|
patch.rpnExpression.resize(rpnSize);
|
||||||
size_t nbElementsRead = fread(patch->rpnExpression.data(), 1, rpnSize, file);
|
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",
|
errx("%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s RPN expression: %s",
|
||||||
@@ -245,9 +243,9 @@ static void readPatch(FILE *file, Patch *patch, char const *fileName, std::strin
|
|||||||
* Sets a patch's pcSection from its pcSectionID.
|
* Sets a patch's pcSection from its pcSectionID.
|
||||||
* @param patch The patch to fix
|
* @param patch The patch to fix
|
||||||
*/
|
*/
|
||||||
static void linkPatchToPCSect(Patch *patch, std::vector<Section *> const &fileSections)
|
static void linkPatchToPCSect(Patch &patch, std::vector<Section *> const &fileSections)
|
||||||
{
|
{
|
||||||
patch->pcSection = patch->pcSectionID != (uint32_t)-1 ? fileSections[patch->pcSectionID]
|
patch.pcSection = patch.pcSectionID != (uint32_t)-1 ? fileSections[patch.pcSectionID]
|
||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,58 +255,58 @@ static void linkPatchToPCSect(Patch *patch, std::vector<Section *> const &fileSe
|
|||||||
* @param section The section to fill
|
* @param section The section to fill
|
||||||
* @param fileName The filename to report in errors
|
* @param fileName The filename to report in errors
|
||||||
*/
|
*/
|
||||||
static void readSection(FILE *file, Section *section, char const *fileName,
|
static void readSection(FILE *file, Section §ion, char const *fileName,
|
||||||
std::vector<FileStackNode> const &fileNodes)
|
std::vector<FileStackNode> const &fileNodes)
|
||||||
{
|
{
|
||||||
int32_t tmp;
|
int32_t tmp;
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
|
|
||||||
tryReadstring(section->name, file, "%s: Cannot read section name: %s", fileName);
|
tryReadstring(section.name, file, "%s: Cannot read section name: %s", fileName);
|
||||||
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s' size: %s", fileName, 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 (%" PRId32 ") is invalid", section->name.c_str(), tmp);
|
errx("\"%s\"'s section size (%" PRId32 ") is invalid", section.name.c_str(), tmp);
|
||||||
section->size = tmp;
|
section.size = tmp;
|
||||||
section->offset = 0;
|
section.offset = 0;
|
||||||
tryGetc(uint8_t, byte, file, "%s: Cannot read \"%s\"'s type: %s", fileName,
|
tryGetc(uint8_t, byte, file, "%s: Cannot read \"%s\"'s type: %s", fileName,
|
||||||
section->name.c_str());
|
section.name.c_str());
|
||||||
section->type = (enum SectionType)(byte & 0x3F);
|
section.type = (enum SectionType)(byte & 0x3F);
|
||||||
if (byte >> 7)
|
if (byte >> 7)
|
||||||
section->modifier = SECTION_UNION;
|
section.modifier = SECTION_UNION;
|
||||||
else if (byte >> 6)
|
else if (byte >> 6)
|
||||||
section->modifier = SECTION_FRAGMENT;
|
section.modifier = SECTION_FRAGMENT;
|
||||||
else
|
else
|
||||||
section->modifier = SECTION_NORMAL;
|
section.modifier = SECTION_NORMAL;
|
||||||
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s org: %s", fileName, section->name.c_str());
|
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s org: %s", fileName, section.name.c_str());
|
||||||
section->isAddressFixed = tmp >= 0;
|
section.isAddressFixed = tmp >= 0;
|
||||||
if (tmp > UINT16_MAX) {
|
if (tmp > UINT16_MAX) {
|
||||||
error(nullptr, 0, "\"%s\"'s org is too large (%" PRId32 ")", section->name.c_str(), tmp);
|
error(nullptr, 0, "\"%s\"'s org is too large (%" PRId32 ")", section.name.c_str(), tmp);
|
||||||
tmp = UINT16_MAX;
|
tmp = UINT16_MAX;
|
||||||
}
|
}
|
||||||
section->org = tmp;
|
section.org = tmp;
|
||||||
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s bank: %s", fileName, section->name.c_str());
|
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s bank: %s", fileName, section.name.c_str());
|
||||||
section->isBankFixed = tmp >= 0;
|
section.isBankFixed = tmp >= 0;
|
||||||
section->bank = tmp;
|
section.bank = tmp;
|
||||||
tryGetc(uint8_t, byte, file, "%s: Cannot read \"%s\"'s alignment: %s", fileName,
|
tryGetc(uint8_t, byte, file, "%s: Cannot read \"%s\"'s alignment: %s", fileName,
|
||||||
section->name.c_str());
|
section.name.c_str());
|
||||||
if (byte > 16)
|
if (byte > 16)
|
||||||
byte = 16;
|
byte = 16;
|
||||||
section->isAlignFixed = byte != 0;
|
section.isAlignFixed = byte != 0;
|
||||||
section->alignMask = (1 << byte) - 1;
|
section.alignMask = (1 << byte) - 1;
|
||||||
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s alignment offset: %s", fileName,
|
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s alignment offset: %s", fileName,
|
||||||
section->name.c_str());
|
section.name.c_str());
|
||||||
if (tmp > UINT16_MAX) {
|
if (tmp > UINT16_MAX) {
|
||||||
error(nullptr, 0, "\"%s\"'s alignment offset is too large (%" PRId32 ")",
|
error(nullptr, 0, "\"%s\"'s alignment offset is too large (%" PRId32 ")",
|
||||||
section->name.c_str(), tmp);
|
section.name.c_str(), tmp);
|
||||||
tmp = UINT16_MAX;
|
tmp = UINT16_MAX;
|
||||||
}
|
}
|
||||||
section->alignOfs = tmp;
|
section.alignOfs = tmp;
|
||||||
|
|
||||||
if (sect_HasData(section->type)) {
|
if (sect_HasData(section.type)) {
|
||||||
if (section->size) {
|
if (section.size) {
|
||||||
section->data.resize(section->size);
|
section.data.resize(section.size);
|
||||||
if (size_t nbRead = fread(section->data.data(), 1, section->size, file);
|
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(),
|
errx("%s: Cannot read \"%s\"'s data: %s", fileName, section.name.c_str(),
|
||||||
feof(file) ? "Unexpected end of file" : strerror(errno));
|
feof(file) ? "Unexpected end of file" : strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,12 +314,11 @@ static void readSection(FILE *file, Section *section, char const *fileName,
|
|||||||
|
|
||||||
tryReadlong(nbPatches, file,
|
tryReadlong(nbPatches, file,
|
||||||
"%s: Cannot read \"%s\"'s number of patches: %s", fileName,
|
"%s: Cannot read \"%s\"'s number of patches: %s", fileName,
|
||||||
section->name.c_str());
|
section.name.c_str());
|
||||||
|
|
||||||
section->patches.resize(nbPatches);
|
section.patches.resize(nbPatches);
|
||||||
for (uint32_t i = 0; i < nbPatches; i++)
|
for (uint32_t i = 0; i < nbPatches; i++)
|
||||||
readPatch(file, §ion->patches[i], fileName, section->name, i,
|
readPatch(file, section.patches[i], fileName, section.name, i, fileNodes);
|
||||||
fileNodes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,20 +327,20 @@ static void readSection(FILE *file, Section *section, char const *fileName,
|
|||||||
* @param symbol The symbol to link
|
* @param symbol The symbol to link
|
||||||
* @param section The section to link
|
* @param section The section to link
|
||||||
*/
|
*/
|
||||||
static void linkSymToSect(Symbol &symbol, Section *section)
|
static void linkSymToSect(Symbol &symbol, Section §ion)
|
||||||
{
|
{
|
||||||
uint32_t a = 0, b = section->symbols.size();
|
uint32_t a = 0, b = section.symbols.size();
|
||||||
|
|
||||||
while (a != b) {
|
while (a != b) {
|
||||||
uint32_t c = (a + b) / 2;
|
uint32_t c = (a + b) / 2;
|
||||||
|
|
||||||
if (section->symbols[c]->offset > symbol.offset)
|
if (section.symbols[c]->offset > symbol.offset)
|
||||||
b = c;
|
b = c;
|
||||||
else
|
else
|
||||||
a = c + 1;
|
a = c + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
section->symbols.insert(section->symbols.begin() + a, &symbol);
|
section.symbols.insert(section.symbols.begin() + a, &symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -352,23 +349,20 @@ static void linkSymToSect(Symbol &symbol, Section *section)
|
|||||||
* @param assert The assertion to fill
|
* @param assert The assertion to fill
|
||||||
* @param fileName The filename to report in errors
|
* @param fileName The filename to report in errors
|
||||||
*/
|
*/
|
||||||
static void readAssertion(FILE *file, Assertion *assert, char const *fileName, uint32_t i,
|
static void readAssertion(FILE *file, Assertion &assert, char const *fileName, uint32_t i,
|
||||||
std::vector<FileStackNode> const &fileNodes)
|
std::vector<FileStackNode> const &fileNodes)
|
||||||
{
|
{
|
||||||
char assertName[sizeof("Assertion #4294967295")]; // UINT32_MAX
|
char assertName[sizeof("Assertion #4294967295")]; // UINT32_MAX
|
||||||
|
|
||||||
snprintf(assertName, sizeof(assertName), "Assertion #%" PRIu32, i);
|
snprintf(assertName, sizeof(assertName), "Assertion #%" PRIu32, i);
|
||||||
|
|
||||||
readPatch(file, &assert->patch, fileName, assertName, 0, fileNodes);
|
readPatch(file, assert.patch, fileName, assertName, 0, fileNodes);
|
||||||
tryReadstring(assert->message, file, "%s: Cannot read assertion's message: %s", fileName);
|
tryReadstring(assert.message, file, "%s: Cannot read assertion's message: %s", fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Section *getMainSection(Section *section)
|
static Section *getMainSection(Section §ion)
|
||||||
{
|
{
|
||||||
if (section->modifier != SECTION_NORMAL)
|
return section.modifier != SECTION_NORMAL ? sect_GetSection(section.name) : §ion;
|
||||||
section = sect_GetSection(section->name);
|
|
||||||
|
|
||||||
return section;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void obj_ReadFile(char const *fileName, unsigned int fileID)
|
void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||||
@@ -408,7 +402,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
|
|
||||||
std::vector<Symbol> &fileSymbols = symbolLists.emplace_front();
|
std::vector<Symbol> &fileSymbols = symbolLists.emplace_front();
|
||||||
|
|
||||||
sdobj_ReadFile(&nodes[fileID].back(), file, fileSymbols);
|
sdobj_ReadFile(nodes[fileID].back(), file, fileSymbols);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,10 +448,10 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
// Read symbol
|
// Read symbol
|
||||||
Symbol &symbol = fileSymbols[i];
|
Symbol &symbol = fileSymbols[i];
|
||||||
|
|
||||||
readSymbol(file, &symbol, fileName, nodes[fileID]);
|
readSymbol(file, symbol, fileName, nodes[fileID]);
|
||||||
|
|
||||||
if (symbol.type == SYMTYPE_EXPORT)
|
if (symbol.type == SYMTYPE_EXPORT)
|
||||||
sym_AddSymbol(&symbol);
|
sym_AddSymbol(symbol);
|
||||||
if (symbol.sectionID != -1)
|
if (symbol.sectionID != -1)
|
||||||
nbSymPerSect[symbol.sectionID]++;
|
nbSymPerSect[symbol.sectionID]++;
|
||||||
}
|
}
|
||||||
@@ -473,18 +467,18 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
err("%s: Failed to create new section", fileName);
|
err("%s: Failed to create new section", fileName);
|
||||||
|
|
||||||
fileSections[i]->nextu = nullptr;
|
fileSections[i]->nextu = nullptr;
|
||||||
readSection(file, fileSections[i], fileName, nodes[fileID]);
|
readSection(file, *fileSections[i], fileName, nodes[fileID]);
|
||||||
fileSections[i]->fileSymbols = &fileSymbols;
|
fileSections[i]->fileSymbols = &fileSymbols;
|
||||||
fileSections[i]->symbols.reserve(nbSymPerSect[i]);
|
fileSections[i]->symbols.reserve(nbSymPerSect[i]);
|
||||||
|
|
||||||
sect_AddSection(fileSections[i]);
|
sect_AddSection(*fileSections[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give patches' PC section pointers to their sections
|
// Give patches' PC section pointers to their sections
|
||||||
for (uint32_t i = 0; i < nbSections; i++) {
|
for (uint32_t i = 0; i < nbSections; i++) {
|
||||||
if (sect_HasData(fileSections[i]->type)) {
|
if (sect_HasData(fileSections[i]->type)) {
|
||||||
for (Patch &patch : fileSections[i]->patches)
|
for (Patch &patch : fileSections[i]->patches)
|
||||||
linkPatchToPCSect(&patch, fileSections);
|
linkPatchToPCSect(patch, fileSections);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,13 +492,13 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
Section *section = fileSections[sectionID];
|
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);
|
linkSymToSect(fileSymbols[i], *section);
|
||||||
|
|
||||||
if (section->modifier != SECTION_NORMAL) {
|
if (section->modifier != SECTION_NORMAL) {
|
||||||
if (section->modifier == SECTION_FRAGMENT)
|
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;
|
fileSymbols[i].offset += section->offset;
|
||||||
section = getMainSection(section);
|
section = getMainSection(*section);
|
||||||
}
|
}
|
||||||
fileSymbols[i].section = section;
|
fileSymbols[i].section = section;
|
||||||
}
|
}
|
||||||
@@ -517,19 +511,14 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
for (uint32_t i = 0; i < nbAsserts; i++) {
|
for (uint32_t i = 0; i < nbAsserts; i++) {
|
||||||
Assertion &assertion = assertions.emplace_front();
|
Assertion &assertion = assertions.emplace_front();
|
||||||
|
|
||||||
readAssertion(file, &assertion, fileName, i, nodes[fileID]);
|
readAssertion(file, assertion, fileName, i, nodes[fileID]);
|
||||||
linkPatchToPCSect(&assertion.patch, fileSections);
|
linkPatchToPCSect(assertion.patch, fileSections);
|
||||||
assertion.fileSymbols = &fileSymbols;
|
assertion.fileSymbols = &fileSymbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void obj_DoSanityChecks()
|
|
||||||
{
|
|
||||||
sect_DoSanityChecks();
|
|
||||||
}
|
|
||||||
|
|
||||||
void obj_CheckAssertions()
|
void obj_CheckAssertions()
|
||||||
{
|
{
|
||||||
patch_CheckAssertions(assertions);
|
patch_CheckAssertions(assertions);
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ static enum SectionType typeMap[SECTTYPE_INVALID] = {
|
|||||||
SECTTYPE_HRAM
|
SECTTYPE_HRAM
|
||||||
};
|
};
|
||||||
|
|
||||||
void out_AddSection(Section const *section)
|
void out_AddSection(Section const §ion)
|
||||||
{
|
{
|
||||||
static const uint32_t maxNbBanks[SECTTYPE_INVALID] = {
|
static const uint32_t maxNbBanks[SECTTYPE_INVALID] = {
|
||||||
1, // SECTTYPE_WRAM0
|
1, // SECTTYPE_WRAM0
|
||||||
@@ -65,34 +65,33 @@ void out_AddSection(Section const *section)
|
|||||||
1, // SECTTYPE_OAM
|
1, // SECTTYPE_OAM
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t targetBank = section->bank - sectionTypeInfo[section->type].firstBank;
|
uint32_t targetBank = section.bank - sectionTypeInfo[section.type].firstBank;
|
||||||
uint32_t minNbBanks = targetBank + 1;
|
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 ")",
|
errx("Section \"%s\" has an invalid bank range (%" PRIu32 " > %" PRIu32 ")",
|
||||||
section->name.c_str(), section->bank,
|
section.name.c_str(), section.bank, maxNbBanks[section.type] - 1);
|
||||||
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();
|
sections[section.type].emplace_back();
|
||||||
|
|
||||||
std::deque<Section const *> *ptr = section->size
|
std::deque<Section const *> &bankSections = section.size
|
||||||
? §ions[section->type][targetBank].sections
|
? sections[section.type][targetBank].sections
|
||||||
: §ions[section->type][targetBank].zeroLenSections;
|
: sections[section.type][targetBank].zeroLenSections;
|
||||||
auto pos = ptr->begin();
|
auto pos = bankSections.begin();
|
||||||
|
|
||||||
while (pos != ptr->end() && (*pos)->org < section->org)
|
while (pos != bankSections.end() && (*pos)->org < section.org)
|
||||||
pos++;
|
pos++;
|
||||||
|
|
||||||
ptr->insert(pos, section);
|
bankSections.insert(pos, §ion);
|
||||||
}
|
}
|
||||||
|
|
||||||
Section const *out_OverlappingSection(Section const *section)
|
Section const *out_OverlappingSection(Section const §ion)
|
||||||
{
|
{
|
||||||
uint32_t bank = section->bank - sectionTypeInfo[section->type].firstBank;
|
uint32_t bank = section.bank - sectionTypeInfo[section.type].firstBank;
|
||||||
|
|
||||||
for (Section const *ptr : sections[section->type][bank].sections) {
|
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 ptr;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|||||||
@@ -47,13 +47,13 @@ static int32_t popRPN(FileStackNode const *node, uint32_t lineNo)
|
|||||||
|
|
||||||
// RPN operators
|
// RPN operators
|
||||||
|
|
||||||
static uint32_t getRPNByte(uint8_t const **expression, int32_t *size,
|
static uint32_t getRPNByte(uint8_t const *&expression, int32_t &size,
|
||||||
FileStackNode const *node, uint32_t lineNo)
|
FileStackNode const *node, uint32_t lineNo)
|
||||||
{
|
{
|
||||||
if (!(*size)--)
|
if (!size--)
|
||||||
fatal(node, lineNo, "Internal error, RPN expression overread");
|
fatal(node, lineNo, "Internal error, RPN expression overread");
|
||||||
|
|
||||||
return *(*expression)++;
|
return *expression++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Symbol const *getSymbol(std::vector<Symbol> const &symbolList, uint32_t index)
|
static Symbol const *getSymbol(std::vector<Symbol> const &symbolList, uint32_t index)
|
||||||
@@ -76,19 +76,19 @@ static Symbol const *getSymbol(std::vector<Symbol> const &symbolList, uint32_t i
|
|||||||
* @return isError Set if an error occurred during evaluation, and further
|
* @return isError Set if an error occurred during evaluation, and further
|
||||||
* errors caused by the value should be suppressed.
|
* errors caused by the value should be suppressed.
|
||||||
*/
|
*/
|
||||||
static int32_t computeRPNExpr(Patch const *patch, std::vector<Symbol> const &fileSymbols)
|
static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> 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)
|
#define popRPN() popRPN(patch.src, patch.lineNo)
|
||||||
|
|
||||||
uint8_t const *expression = patch->rpnExpression.data();
|
uint8_t const *expression = patch.rpnExpression.data();
|
||||||
int32_t size = (int32_t)patch->rpnExpression.size();
|
int32_t size = (int32_t)patch.rpnExpression.size();
|
||||||
|
|
||||||
rpnStack.clear();
|
rpnStack.clear();
|
||||||
|
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
enum RPNCommand command = (enum RPNCommand)getRPNByte(&expression, &size,
|
enum RPNCommand command = (enum RPNCommand)getRPNByte(expression, size,
|
||||||
patch->src, patch->lineNo);
|
patch.src, patch.lineNo);
|
||||||
int32_t value;
|
int32_t value;
|
||||||
|
|
||||||
isError = false;
|
isError = false;
|
||||||
@@ -116,7 +116,7 @@ static int32_t computeRPNExpr(Patch const *patch, std::vector<Symbol> const &fil
|
|||||||
value = popRPN();
|
value = popRPN();
|
||||||
if (value == 0) {
|
if (value == 0) {
|
||||||
if (!isError)
|
if (!isError)
|
||||||
error(patch->src, patch->lineNo, "Division by 0");
|
error(patch.src, patch.lineNo, "Division by 0");
|
||||||
isError = true;
|
isError = true;
|
||||||
popRPN();
|
popRPN();
|
||||||
value = INT32_MAX;
|
value = INT32_MAX;
|
||||||
@@ -128,7 +128,7 @@ static int32_t computeRPNExpr(Patch const *patch, std::vector<Symbol> const &fil
|
|||||||
value = popRPN();
|
value = popRPN();
|
||||||
if (value == 0) {
|
if (value == 0) {
|
||||||
if (!isError)
|
if (!isError)
|
||||||
error(patch->src, patch->lineNo, "Modulo by 0");
|
error(patch.src, patch.lineNo, "Modulo by 0");
|
||||||
isError = true;
|
isError = true;
|
||||||
popRPN();
|
popRPN();
|
||||||
value = 0;
|
value = 0;
|
||||||
@@ -143,7 +143,7 @@ static int32_t computeRPNExpr(Patch const *patch, std::vector<Symbol> const &fil
|
|||||||
value = popRPN();
|
value = popRPN();
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
if (!isError)
|
if (!isError)
|
||||||
error(patch->src, patch->lineNo, "Exponent by negative");
|
error(patch.src, patch.lineNo, "Exponent by negative");
|
||||||
isError = true;
|
isError = true;
|
||||||
popRPN();
|
popRPN();
|
||||||
value = 0;
|
value = 0;
|
||||||
@@ -216,18 +216,18 @@ static int32_t computeRPNExpr(Patch const *patch, std::vector<Symbol> const &fil
|
|||||||
case RPN_BANK_SYM:
|
case RPN_BANK_SYM:
|
||||||
value = 0;
|
value = 0;
|
||||||
for (uint8_t shift = 0; shift < 32; shift += 8)
|
for (uint8_t shift = 0; shift < 32; shift += 8)
|
||||||
value |= getRPNByte(&expression, &size,
|
value |= getRPNByte(expression, size,
|
||||||
patch->src, patch->lineNo) << shift;
|
patch.src, patch.lineNo) << shift;
|
||||||
symbol = getSymbol(fileSymbols, value);
|
symbol = getSymbol(fileSymbols, value);
|
||||||
|
|
||||||
if (!symbol) {
|
if (!symbol) {
|
||||||
error(patch->src, patch->lineNo,
|
error(patch.src, patch.lineNo,
|
||||||
"Requested BANK() of symbol \"%s\", which was not found",
|
"Requested BANK() of symbol \"%s\", which was not found",
|
||||||
fileSymbols[value].name.c_str());
|
fileSymbols[value].name.c_str());
|
||||||
isError = true;
|
isError = true;
|
||||||
value = 1;
|
value = 1;
|
||||||
} else if (!symbol->section) {
|
} else if (!symbol->section) {
|
||||||
error(patch->src, patch->lineNo,
|
error(patch.src, patch.lineNo,
|
||||||
"Requested BANK() of non-label symbol \"%s\"",
|
"Requested BANK() of non-label symbol \"%s\"",
|
||||||
fileSymbols[value].name.c_str());
|
fileSymbols[value].name.c_str());
|
||||||
isError = true;
|
isError = true;
|
||||||
@@ -241,13 +241,13 @@ static int32_t computeRPNExpr(Patch const *patch, std::vector<Symbol> const &fil
|
|||||||
// `expression` is not guaranteed to be '\0'-terminated. If it is not,
|
// `expression` is not guaranteed to be '\0'-terminated. If it is not,
|
||||||
// `getRPNByte` will have a fatal internal error.
|
// `getRPNByte` will have a fatal internal error.
|
||||||
name = (char const *)expression;
|
name = (char const *)expression;
|
||||||
while (getRPNByte(&expression, &size, patch->src, patch->lineNo))
|
while (getRPNByte(expression, size, patch.src, patch.lineNo))
|
||||||
;
|
;
|
||||||
|
|
||||||
sect = sect_GetSection(name);
|
sect = sect_GetSection(name);
|
||||||
|
|
||||||
if (!sect) {
|
if (!sect) {
|
||||||
error(patch->src, patch->lineNo,
|
error(patch.src, patch.lineNo,
|
||||||
"Requested BANK() of section \"%s\", which was not found",
|
"Requested BANK() of section \"%s\", which was not found",
|
||||||
name);
|
name);
|
||||||
isError = true;
|
isError = true;
|
||||||
@@ -258,26 +258,26 @@ static int32_t computeRPNExpr(Patch const *patch, std::vector<Symbol> const &fil
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RPN_BANK_SELF:
|
case RPN_BANK_SELF:
|
||||||
if (!patch->pcSection) {
|
if (!patch.pcSection) {
|
||||||
error(patch->src, patch->lineNo,
|
error(patch.src, patch.lineNo,
|
||||||
"PC has no bank outside a section");
|
"PC has no bank outside a section");
|
||||||
isError = true;
|
isError = true;
|
||||||
value = 1;
|
value = 1;
|
||||||
} else {
|
} else {
|
||||||
value = patch->pcSection->bank;
|
value = patch.pcSection->bank;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RPN_SIZEOF_SECT:
|
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;
|
name = (char const *)expression;
|
||||||
while (getRPNByte(&expression, &size, patch->src, patch->lineNo))
|
while (getRPNByte(expression, size, patch.src, patch.lineNo))
|
||||||
;
|
;
|
||||||
|
|
||||||
sect = sect_GetSection(name);
|
sect = sect_GetSection(name);
|
||||||
|
|
||||||
if (!sect) {
|
if (!sect) {
|
||||||
error(patch->src, patch->lineNo,
|
error(patch.src, patch.lineNo,
|
||||||
"Requested SIZEOF() of section \"%s\", which was not found",
|
"Requested SIZEOF() of section \"%s\", which was not found",
|
||||||
name);
|
name);
|
||||||
isError = true;
|
isError = true;
|
||||||
@@ -290,14 +290,14 @@ static int32_t computeRPNExpr(Patch const *patch, std::vector<Symbol> const &fil
|
|||||||
case RPN_STARTOF_SECT:
|
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;
|
name = (char const *)expression;
|
||||||
while (getRPNByte(&expression, &size, patch->src, patch->lineNo))
|
while (getRPNByte(expression, size, patch.src, patch.lineNo))
|
||||||
;
|
;
|
||||||
|
|
||||||
sect = sect_GetSection(name);
|
sect = sect_GetSection(name);
|
||||||
assert(sect->offset == 0);
|
assert(sect->offset == 0);
|
||||||
|
|
||||||
if (!sect) {
|
if (!sect) {
|
||||||
error(patch->src, patch->lineNo,
|
error(patch.src, patch.lineNo,
|
||||||
"Requested STARTOF() of section \"%s\", which was not found",
|
"Requested STARTOF() of section \"%s\", which was not found",
|
||||||
name);
|
name);
|
||||||
isError = true;
|
isError = true;
|
||||||
@@ -308,9 +308,9 @@ static int32_t computeRPNExpr(Patch const *patch, std::vector<Symbol> const &fil
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RPN_SIZEOF_SECTTYPE:
|
case RPN_SIZEOF_SECTTYPE:
|
||||||
value = getRPNByte(&expression, &size, patch->src, patch->lineNo);
|
value = getRPNByte(expression, size, patch.src, patch.lineNo);
|
||||||
if (value < 0 || value >= SECTTYPE_INVALID) {
|
if (value < 0 || value >= SECTTYPE_INVALID) {
|
||||||
error(patch->src, patch->lineNo,
|
error(patch.src, patch.lineNo,
|
||||||
"Requested SIZEOF() an invalid section type");
|
"Requested SIZEOF() an invalid section type");
|
||||||
isError = true;
|
isError = true;
|
||||||
value = 0;
|
value = 0;
|
||||||
@@ -320,9 +320,9 @@ static int32_t computeRPNExpr(Patch const *patch, std::vector<Symbol> const &fil
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RPN_STARTOF_SECTTYPE:
|
case RPN_STARTOF_SECTTYPE:
|
||||||
value = getRPNByte(&expression, &size, patch->src, patch->lineNo);
|
value = getRPNByte(expression, size, patch.src, patch.lineNo);
|
||||||
if (value < 0 || value >= SECTTYPE_INVALID) {
|
if (value < 0 || value >= SECTTYPE_INVALID) {
|
||||||
error(patch->src, patch->lineNo,
|
error(patch.src, patch.lineNo,
|
||||||
"Requested STARTOF() an invalid section type");
|
"Requested STARTOF() an invalid section type");
|
||||||
isError = true;
|
isError = true;
|
||||||
value = 0;
|
value = 0;
|
||||||
@@ -336,7 +336,7 @@ static int32_t computeRPNExpr(Patch const *patch, std::vector<Symbol> const &fil
|
|||||||
if (!isError && (value < 0
|
if (!isError && (value < 0
|
||||||
|| (value > 0xFF && value < 0xFF00)
|
|| (value > 0xFF && value < 0xFF00)
|
||||||
|| value > 0xFFFF)) {
|
|| value > 0xFFFF)) {
|
||||||
error(patch->src, patch->lineNo,
|
error(patch.src, patch.lineNo,
|
||||||
"Value %" PRId32 " is not in HRAM range", value);
|
"Value %" PRId32 " is not in HRAM range", value);
|
||||||
isError = true;
|
isError = true;
|
||||||
}
|
}
|
||||||
@@ -349,7 +349,7 @@ static int32_t computeRPNExpr(Patch const *patch, std::vector<Symbol> const &fil
|
|||||||
// They can be easily checked with a bitmask
|
// They can be easily checked with a bitmask
|
||||||
if (value & ~0x38) {
|
if (value & ~0x38) {
|
||||||
if (!isError)
|
if (!isError)
|
||||||
error(patch->src, patch->lineNo,
|
error(patch.src, patch.lineNo,
|
||||||
"Value %" PRId32 " is not a RST vector", value);
|
"Value %" PRId32 " is not a RST vector", value);
|
||||||
isError = true;
|
isError = true;
|
||||||
}
|
}
|
||||||
@@ -359,30 +359,30 @@ static int32_t computeRPNExpr(Patch const *patch, std::vector<Symbol> const &fil
|
|||||||
case RPN_CONST:
|
case RPN_CONST:
|
||||||
value = 0;
|
value = 0;
|
||||||
for (uint8_t shift = 0; shift < 32; shift += 8)
|
for (uint8_t shift = 0; shift < 32; shift += 8)
|
||||||
value |= getRPNByte(&expression, &size,
|
value |= getRPNByte(expression, size,
|
||||||
patch->src, patch->lineNo) << shift;
|
patch.src, patch.lineNo) << shift;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RPN_SYM:
|
case RPN_SYM:
|
||||||
value = 0;
|
value = 0;
|
||||||
for (uint8_t shift = 0; shift < 32; shift += 8)
|
for (uint8_t shift = 0; shift < 32; shift += 8)
|
||||||
value |= getRPNByte(&expression, &size,
|
value |= getRPNByte(expression, size,
|
||||||
patch->src, patch->lineNo) << shift;
|
patch.src, patch.lineNo) << shift;
|
||||||
|
|
||||||
if (value == -1) { // PC
|
if (value == -1) { // PC
|
||||||
if (!patch->pcSection) {
|
if (!patch.pcSection) {
|
||||||
error(patch->src, patch->lineNo,
|
error(patch.src, patch.lineNo,
|
||||||
"PC has no value outside a section");
|
"PC has no value outside a section");
|
||||||
value = 0;
|
value = 0;
|
||||||
isError = true;
|
isError = true;
|
||||||
} else {
|
} else {
|
||||||
value = patch->pcOffset + patch->pcSection->org;
|
value = patch.pcOffset + patch.pcSection->org;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
symbol = getSymbol(fileSymbols, value);
|
symbol = getSymbol(fileSymbols, value);
|
||||||
|
|
||||||
if (!symbol) {
|
if (!symbol) {
|
||||||
error(patch->src, patch->lineNo,
|
error(patch.src, patch.lineNo,
|
||||||
"Unknown symbol \"%s\"", fileSymbols[value].name.c_str());
|
"Unknown symbol \"%s\"", fileSymbols[value].name.c_str());
|
||||||
isError = true;
|
isError = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -399,7 +399,7 @@ static int32_t computeRPNExpr(Patch const *patch, std::vector<Symbol> const &fil
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rpnStack.size() > 1)
|
if (rpnStack.size() > 1)
|
||||||
error(patch->src, patch->lineNo,
|
error(patch.src, patch.lineNo,
|
||||||
"RPN stack has %zu entries on exit, not 1", rpnStack.size());
|
"RPN stack has %zu entries on exit, not 1", rpnStack.size());
|
||||||
|
|
||||||
isError = false;
|
isError = false;
|
||||||
@@ -413,7 +413,7 @@ void patch_CheckAssertions(std::deque<Assertion> &assertions)
|
|||||||
verbosePrint("Checking assertions...\n");
|
verbosePrint("Checking assertions...\n");
|
||||||
|
|
||||||
for (Assertion &assert : assertions) {
|
for (Assertion &assert : assertions) {
|
||||||
int32_t value = computeRPNExpr(&assert.patch, *assert.fileSymbols);
|
int32_t value = computeRPNExpr(assert.patch, *assert.fileSymbols);
|
||||||
enum AssertionType type = (enum AssertionType)assert.patch.type;
|
enum AssertionType type = (enum AssertionType)assert.patch.type;
|
||||||
|
|
||||||
if (!isError && !value) {
|
if (!isError && !value) {
|
||||||
@@ -446,12 +446,12 @@ void patch_CheckAssertions(std::deque<Assertion> &assertions)
|
|||||||
* @param section The section component to patch
|
* @param section The section component to patch
|
||||||
* @param dataSection The section to patch
|
* @param dataSection The section to patch
|
||||||
*/
|
*/
|
||||||
static void applyFilePatches(Section *section, Section *dataSection)
|
static void applyFilePatches(Section §ion, Section &dataSection)
|
||||||
{
|
{
|
||||||
verbosePrint("Patching section \"%s\"...\n", section->name.c_str());
|
verbosePrint("Patching section \"%s\"...\n", section.name.c_str());
|
||||||
for (Patch &patch : section->patches) {
|
for (Patch &patch : section.patches) {
|
||||||
int32_t value = computeRPNExpr(&patch, *section->fileSymbols);
|
int32_t value = computeRPNExpr(patch, *section.fileSymbols);
|
||||||
uint16_t offset = patch.offset + section->offset;
|
uint16_t offset = patch.offset + section.offset;
|
||||||
|
|
||||||
// `jr` is quite unlike the others...
|
// `jr` is quite unlike the others...
|
||||||
if (patch.type == PATCHTYPE_JR) {
|
if (patch.type == PATCHTYPE_JR) {
|
||||||
@@ -464,7 +464,7 @@ static void applyFilePatches(Section *section, Section *dataSection)
|
|||||||
error(patch.src, patch.lineNo,
|
error(patch.src, patch.lineNo,
|
||||||
"jr target out of reach (expected -129 < %" PRId16 " < 128)",
|
"jr target out of reach (expected -129 < %" PRId16 " < 128)",
|
||||||
jumpOffset);
|
jumpOffset);
|
||||||
dataSection->data[offset] = jumpOffset & 0xFF;
|
dataSection.data[offset] = jumpOffset & 0xFF;
|
||||||
} else {
|
} else {
|
||||||
// Patch a certain number of bytes
|
// Patch a certain number of bytes
|
||||||
struct {
|
struct {
|
||||||
@@ -484,7 +484,7 @@ static void applyFilePatches(Section *section, Section *dataSection)
|
|||||||
value, value < 0 ? " (maybe negative?)" : "",
|
value, value < 0 ? " (maybe negative?)" : "",
|
||||||
types[patch.type].size * 8U);
|
types[patch.type].size * 8U);
|
||||||
for (uint8_t i = 0; i < types[patch.type].size; i++) {
|
for (uint8_t i = 0; i < types[patch.type].size; i++) {
|
||||||
dataSection->data[offset + i] = value & 0xFF;
|
dataSection.data[offset + i] = value & 0xFF;
|
||||||
value >>= 8;
|
value >>= 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -495,13 +495,13 @@ static void applyFilePatches(Section *section, Section *dataSection)
|
|||||||
* Applies all of a section's patches, iterating over "components" of unionized sections
|
* Applies all of a section's patches, iterating over "components" of unionized sections
|
||||||
* @param section The section to patch
|
* @param section The section to patch
|
||||||
*/
|
*/
|
||||||
static void applyPatches(Section *section)
|
static void applyPatches(Section §ion)
|
||||||
{
|
{
|
||||||
if (!sect_HasData(section->type))
|
if (!sect_HasData(section.type))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (Section *component = section; component; component = component->nextu)
|
for (Section *component = §ion; component; component = component->nextu)
|
||||||
applyFilePatches(component, section);
|
applyFilePatches(*component, section);
|
||||||
}
|
}
|
||||||
|
|
||||||
void patch_ApplyPatches()
|
void patch_ApplyPatches()
|
||||||
|
|||||||
@@ -25,15 +25,15 @@ enum NumberType {
|
|||||||
OCT = 8, // Q
|
OCT = 8, // Q
|
||||||
};
|
};
|
||||||
|
|
||||||
static void consumeLF(FileStackNode const *where, uint32_t lineNo, FILE *file) {
|
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)");
|
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
|
static char const *delim = " \f\n\r\t\v"; // Whitespace according to the C and POSIX locales
|
||||||
|
|
||||||
static int nextLine(std::vector<char> &lineBuf, uint32_t &lineNo,
|
static int nextLine(std::vector<char> &lineBuf, uint32_t &lineNo,
|
||||||
FileStackNode const *where, FILE *file) {
|
FileStackNode const &where, FILE *file) {
|
||||||
retry:
|
retry:
|
||||||
++lineNo;
|
++lineNo;
|
||||||
int firstChar = getc(file);
|
int firstChar = getc(file);
|
||||||
@@ -72,7 +72,7 @@ retry:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t readNumber(char const *str, char const **endptr, enum NumberType base) {
|
static uint32_t readNumber(char const *str, char const *&endptr, enum NumberType base) {
|
||||||
uint32_t res = 0;
|
uint32_t res = 0;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -80,7 +80,7 @@ static uint32_t readNumber(char const *str, char const **endptr, enum NumberType
|
|||||||
char const *ptr = strchr(digits, toupper(*str));
|
char const *ptr = strchr(digits, toupper(*str));
|
||||||
|
|
||||||
if (!ptr || ptr - digits >= base) {
|
if (!ptr || ptr - digits >= base) {
|
||||||
*endptr = str;
|
endptr = str;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
++str;
|
++str;
|
||||||
@@ -88,23 +88,23 @@ static uint32_t readNumber(char const *str, char const **endptr, enum NumberType
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t parseNumber(FileStackNode const *where, uint32_t lineNo, char const *str, enum NumberType base) {
|
static uint32_t parseNumber(FileStackNode const &where, uint32_t lineNo, char const *str, enum NumberType base) {
|
||||||
if (str[0] == '\0')
|
if (str[0] == '\0')
|
||||||
fatal(where, lineNo, "Expected number, got empty string");
|
fatal(&where, lineNo, "Expected number, got empty string");
|
||||||
|
|
||||||
char const *endptr;
|
char const *endptr;
|
||||||
uint32_t res = readNumber(str, &endptr, base);
|
uint32_t res = readNumber(str, endptr, base);
|
||||||
|
|
||||||
if (*endptr != '\0')
|
if (*endptr != '\0')
|
||||||
fatal(where, lineNo, "Expected number, got \"%s\"", str);
|
fatal(&where, lineNo, "Expected number, got \"%s\"", str);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t parseByte(FileStackNode const *where, uint32_t lineNo, char const *str, enum NumberType base) {
|
static uint8_t parseByte(FileStackNode const &where, uint32_t lineNo, char const *str, enum NumberType base) {
|
||||||
uint32_t num = parseNumber(where, lineNo, str, 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);
|
fatal(&where, lineNo, "\"%s\" is not a byte", str);
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,24 +133,24 @@ enum RelocFlags {
|
|||||||
| 1 << RELOC_EXPR24 | 1 << RELOC_BANKBYTE,
|
| 1 << RELOC_EXPR24 | 1 << RELOC_BANKBYTE,
|
||||||
};
|
};
|
||||||
|
|
||||||
void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol> &fileSymbols) {
|
void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol> &fileSymbols) {
|
||||||
std::vector<char> line(256);
|
std::vector<char> line(256);
|
||||||
char const *token;
|
char const *token;
|
||||||
|
|
||||||
#define getToken(ptr, ...) do { \
|
#define getToken(ptr, ...) do { \
|
||||||
token = strtok((ptr), delim); \
|
token = strtok((ptr), delim); \
|
||||||
if (!token) \
|
if (!token) \
|
||||||
fatal(where, lineNo, __VA_ARGS__); \
|
fatal(&where, lineNo, __VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#define expectEol(...) do { \
|
#define expectEol(...) do { \
|
||||||
token = strtok(nullptr, delim); \
|
token = strtok(nullptr, delim); \
|
||||||
if (token) \
|
if (token) \
|
||||||
fatal(where, lineNo, __VA_ARGS__); \
|
fatal(&where, lineNo, __VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#define expectToken(expected, lineType) do { \
|
#define expectToken(expected, lineType) do { \
|
||||||
getToken(nullptr, "'%c' line is too short", (lineType)); \
|
getToken(nullptr, "'%c' line is too short", (lineType)); \
|
||||||
if (strcasecmp(token, (expected)) != 0) \
|
if (strcasecmp(token, (expected)) != 0) \
|
||||||
fatal(where, lineNo, "Malformed '%c' line: expected \"%s\", got \"%s\"", \
|
fatal(&where, lineNo, "Malformed '%c' line: expected \"%s\", got \"%s\"", \
|
||||||
(lineType), (expected), token); \
|
(lineType), (expected), token); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
// The first letter (thus, the line type) identifies the integer type
|
// The first letter (thus, the line type) identifies the integer type
|
||||||
switch (lineType) {
|
switch (lineType) {
|
||||||
case EOF:
|
case EOF:
|
||||||
fatal(where, lineNo, "SDCC object only contains comments and empty lines");
|
fatal(&where, lineNo, "SDCC object only contains comments and empty lines");
|
||||||
case 'X':
|
case 'X':
|
||||||
numberType = HEX;
|
numberType = HEX;
|
||||||
break;
|
break;
|
||||||
@@ -172,7 +172,7 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
numberType = OCT;
|
numberType = OCT;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fatal(where, lineNo, "This does not look like a SDCC object file (unknown integer format '%c')",
|
fatal(&where, lineNo, "This does not look like a SDCC object file (unknown integer format '%c')",
|
||||||
lineType);
|
lineType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,23 +180,23 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
case 'L':
|
case 'L':
|
||||||
break;
|
break;
|
||||||
case 'H':
|
case 'H':
|
||||||
fatal(where, lineNo, "Big-endian SDCC object files are not supported");
|
fatal(&where, lineNo, "Big-endian SDCC object files are not supported");
|
||||||
default:
|
default:
|
||||||
fatal(where, lineNo, "Unknown endianness type '%c'", line[0]);
|
fatal(&where, lineNo, "Unknown endianness type '%c'", line[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ADDR_SIZE 3
|
#define 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]);
|
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]);
|
warning(&where, lineNo, "Ignoring unknown characters (\"%s\") in first line", &line[2]);
|
||||||
|
|
||||||
// Header line
|
// Header line
|
||||||
|
|
||||||
lineType = nextLine(line, lineNo, where, file);
|
lineType = nextLine(line, lineNo, where, file);
|
||||||
if (lineType != 'H')
|
if (lineType != 'H')
|
||||||
fatal(where, lineNo, "Expected header line, got '%c' line", lineType);
|
fatal(&where, lineNo, "Expected header line, got '%c' line", lineType);
|
||||||
// Expected format: "A areas S global symbols"
|
// Expected format: "A areas S global symbols"
|
||||||
|
|
||||||
getToken(line.data(), "Empty 'H' line");
|
getToken(line.data(), "Empty 'H' line");
|
||||||
@@ -234,19 +234,19 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
|
|
||||||
case 'A': {
|
case 'A': {
|
||||||
if (fileSections.size() == expectedNbAreas)
|
if (fileSections.size() == expectedNbAreas)
|
||||||
warning(where, lineNo, "Got more 'A' lines than the expected %" PRIu32,
|
warning(&where, lineNo, "Got more 'A' lines than the expected %" PRIu32,
|
||||||
expectedNbAreas);
|
expectedNbAreas);
|
||||||
Section *curSection = new(std::nothrow) Section();
|
Section *curSection = new(std::nothrow) Section();
|
||||||
|
|
||||||
if (!curSection)
|
if (!curSection)
|
||||||
fatal(where, lineNo, "Failed to alloc new area: %s", strerror(errno));
|
fatal(&where, lineNo, "Failed to alloc new area: %s", strerror(errno));
|
||||||
|
|
||||||
getToken(line.data(), "'A' line is too short");
|
getToken(line.data(), "'A' line is too short");
|
||||||
assert(strlen(token) != 0); // This should be impossible, tokens are non-empty
|
assert(strlen(token) != 0); // This should be impossible, tokens are non-empty
|
||||||
// The following is required for fragment offsets to be reliably predicted
|
// The following is required for fragment offsets to be reliably predicted
|
||||||
for (FileSection &entry : fileSections) {
|
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",
|
fatal(&where, lineNo, "Area \"%s\" already defined earlier",
|
||||||
token);
|
token);
|
||||||
}
|
}
|
||||||
char const *sectionName = token; // We'll deal with the section's name depending on type
|
char const *sectionName = token; // We'll deal with the section's name depending on type
|
||||||
@@ -260,7 +260,7 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
uint32_t tmp = parseNumber(where, lineNo, token, numberType);
|
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!?",
|
fatal(&where, lineNo, "Area \"%s\" is larger than the GB address space!?",
|
||||||
curSection->name.c_str());
|
curSection->name.c_str());
|
||||||
curSection->size = tmp;
|
curSection->size = tmp;
|
||||||
|
|
||||||
@@ -269,14 +269,14 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
getToken(nullptr, "'A' line is too short");
|
getToken(nullptr, "'A' line is too short");
|
||||||
tmp = parseNumber(where, lineNo, token, numberType);
|
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");
|
fatal(&where, lineNo, "Internal error: paging is not supported");
|
||||||
curSection->isAddressFixed = tmp & (1 << AREA_ISABS);
|
curSection->isAddressFixed = tmp & (1 << AREA_ISABS);
|
||||||
curSection->isBankFixed = curSection->isAddressFixed;
|
curSection->isBankFixed = curSection->isAddressFixed;
|
||||||
curSection->modifier = curSection->isAddressFixed || (tmp & (1 << AREA_TYPE))
|
curSection->modifier = curSection->isAddressFixed || (tmp & (1 << AREA_TYPE))
|
||||||
? SECTION_NORMAL : SECTION_FRAGMENT;
|
? SECTION_NORMAL : SECTION_FRAGMENT;
|
||||||
// If the section is absolute, its name might not be unique; thus, mangle the name
|
// If the section is absolute, its name might not be unique; thus, mangle the name
|
||||||
if (curSection->modifier == SECTION_NORMAL) {
|
if (curSection->modifier == SECTION_NORMAL) {
|
||||||
curSection->name.append(where->name());
|
curSection->name.append(where.name());
|
||||||
curSection->name.append(" ");
|
curSection->name.append(" ");
|
||||||
}
|
}
|
||||||
curSection->name.append(sectionName);
|
curSection->name.append(sectionName);
|
||||||
@@ -308,7 +308,7 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
} else if (high < 0xE0) {
|
} else if (high < 0xE0) {
|
||||||
curSection->type = SECTTYPE_WRAMX;
|
curSection->type = SECTTYPE_WRAMX;
|
||||||
} else if (high < 0xFE) {
|
} else if (high < 0xFE) {
|
||||||
fatal(where, lineNo, "Areas in echo RAM are not supported");
|
fatal(&where, lineNo, "Areas in echo RAM are not supported");
|
||||||
} else if (high < 0xFF) {
|
} else if (high < 0xFF) {
|
||||||
curSection->type = SECTTYPE_OAM;
|
curSection->type = SECTTYPE_OAM;
|
||||||
} else {
|
} else {
|
||||||
@@ -325,13 +325,13 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
|
|
||||||
case 'S': {
|
case 'S': {
|
||||||
if (fileSymbols.size() == expectedNbSymbols)
|
if (fileSymbols.size() == expectedNbSymbols)
|
||||||
warning(where, lineNo, "Got more 'S' lines than the expected %" PRIu32,
|
warning(&where, lineNo, "Got more 'S' lines than the expected %" PRIu32,
|
||||||
expectedNbSymbols);
|
expectedNbSymbols);
|
||||||
Symbol &symbol = fileSymbols.emplace_back();
|
Symbol &symbol = fileSymbols.emplace_back();
|
||||||
|
|
||||||
// Init other members
|
// Init other members
|
||||||
symbol.objFileName = where->name().c_str();
|
symbol.objFileName = where.name().c_str();
|
||||||
symbol.src = where;
|
symbol.src = &where;
|
||||||
symbol.lineNo = lineNo;
|
symbol.lineNo = lineNo;
|
||||||
|
|
||||||
// No need to set the `sectionID`, since we can directly set the pointer
|
// No need to set the `sectionID`, since we can directly set the pointer
|
||||||
@@ -354,7 +354,7 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
symbol.type = SYMTYPE_IMPORT;
|
symbol.type = SYMTYPE_IMPORT;
|
||||||
// TODO: hard error if the rest is not zero
|
// TODO: hard error if the rest is not zero
|
||||||
} else if (token[0] != 'D' && token[0] != 'd') {
|
} else if (token[0] != 'D' && token[0] != 'd') {
|
||||||
fatal(where, lineNo, "'S' line is neither \"Def\" nor \"Ref\"");
|
fatal(&where, lineNo, "'S' line is neither \"Def\" nor \"Ref\"");
|
||||||
} else {
|
} else {
|
||||||
// All symbols are exported
|
// All symbols are exported
|
||||||
symbol.type = SYMTYPE_EXPORT;
|
symbol.type = SYMTYPE_EXPORT;
|
||||||
@@ -365,21 +365,21 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
// definition is in a floating section
|
// definition is in a floating section
|
||||||
if ((other->section && !other->section->isAddressFixed)
|
if ((other->section && !other->section->isAddressFixed)
|
||||||
|| (symbol.section && !symbol.section->isAddressFixed)) {
|
|| (symbol.section && !symbol.section->isAddressFixed)) {
|
||||||
sym_AddSymbol(&symbol); // This will error out
|
sym_AddSymbol(symbol); // This will error out
|
||||||
} else if (other->value != symbol.value) {
|
} else if (other->value != symbol.value) {
|
||||||
error(where, lineNo,
|
error(&where, lineNo,
|
||||||
"Definition of \"%s\" conflicts with definition in %s (%" PRId32 " != %" PRId32 ")",
|
"Definition of \"%s\" conflicts with definition in %s (%" PRId32 " != %" PRId32 ")",
|
||||||
symbol.name.c_str(), other->objFileName, symbol.value, other->value);
|
symbol.name.c_str(), other->objFileName, symbol.value, other->value);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Add a new definition
|
// Add a new definition
|
||||||
sym_AddSymbol(&symbol);
|
sym_AddSymbol(symbol);
|
||||||
}
|
}
|
||||||
// It's fine to keep modifying the symbol after `AddSymbol`, only
|
// It's fine to keep modifying the symbol after `AddSymbol`, only
|
||||||
// the name must not be modified
|
// 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\"");
|
fatal(&where, lineNo, "'S' line is neither \"Def\" nor \"Ref\"");
|
||||||
|
|
||||||
if (!fileSections.empty())
|
if (!fileSections.empty())
|
||||||
fileSections.back().section->symbols.push_back(&symbol);
|
fileSections.back().section->symbols.push_back(&symbol);
|
||||||
@@ -391,21 +391,21 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
case 'T':
|
case 'T':
|
||||||
// Now, time to parse the data!
|
// Now, time to parse the data!
|
||||||
if (!data.empty())
|
if (!data.empty())
|
||||||
warning(where, lineNo, "Previous 'T' line had no 'R' line (ignored)");
|
warning(&where, lineNo, "Previous 'T' line had no 'R' line (ignored)");
|
||||||
|
|
||||||
data.clear();
|
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));
|
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");
|
fatal(&where, lineNo, "'T' line is too short");
|
||||||
// Importantly, now we know that there is "pending data" in `data`
|
// Importantly, now we know that there is "pending data" in `data`
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'R': {
|
case 'R': {
|
||||||
// Supposed to directly follow `T`
|
// Supposed to directly follow `T`
|
||||||
if (data.empty()) {
|
if (data.empty()) {
|
||||||
warning(where, lineNo, "'R' line with no 'T' line, ignoring");
|
warning(&where, lineNo, "'R' line with no 'T' line, ignoring");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,7 +419,7 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
getToken(nullptr, "'R' line is too short");
|
getToken(nullptr, "'R' line is too short");
|
||||||
areaIdx |= (uint16_t)parseByte(where, lineNo, token, numberType) << 8;
|
areaIdx |= (uint16_t)parseByte(where, lineNo, token, numberType) << 8;
|
||||||
if (areaIdx >= fileSections.size())
|
if (areaIdx >= fileSections.size())
|
||||||
fatal(where, lineNo, "'R' line references area #%" PRIu16 ", but there are only %zu (so far)",
|
fatal(&where, lineNo, "'R' line references area #%" PRIu16 ", but there are only %zu (so far)",
|
||||||
areaIdx, fileSections.size());
|
areaIdx, fileSections.size());
|
||||||
assert(!fileSections.empty()); // There should be at least one, from the above check
|
assert(!fileSections.empty()); // There should be at least one, from the above check
|
||||||
Section *section = fileSections[areaIdx].section;
|
Section *section = fileSections[areaIdx].section;
|
||||||
@@ -429,7 +429,7 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
|
|
||||||
if (section->isAddressFixed) {
|
if (section->isAddressFixed) {
|
||||||
if (addr < section->org)
|
if (addr < section->org)
|
||||||
fatal(where, lineNo, "'T' line reports address $%04" PRIx16 " in \"%s\", which starts at $%04" PRIx16,
|
fatal(&where, lineNo, "'T' line reports address $%04" PRIx16 " in \"%s\", which starts at $%04" PRIx16,
|
||||||
addr, section->name.c_str(), section->org);
|
addr, section->name.c_str(), section->org);
|
||||||
addr -= section->org;
|
addr -= section->org;
|
||||||
}
|
}
|
||||||
@@ -437,7 +437,7 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
// ignore those. "Empty" lines shouldn't trigger allocation, either.
|
// ignore those. "Empty" lines shouldn't trigger allocation, either.
|
||||||
if (data.size() != ADDR_SIZE) {
|
if (data.size() != ADDR_SIZE) {
|
||||||
if (addr != *writeIndex)
|
if (addr != *writeIndex)
|
||||||
fatal(where, lineNo, "'T' lines which don't append to their section are not supported (%" PRIu16 " != %" PRIu16 ")",
|
fatal(&where, lineNo, "'T' lines which don't append to their section are not supported (%" PRIu16 " != %" PRIu16 ")",
|
||||||
addr, *writeIndex);
|
addr, *writeIndex);
|
||||||
if (section->data.empty()) {
|
if (section->data.empty()) {
|
||||||
assert(section->size != 0);
|
assert(section->size != 0);
|
||||||
@@ -470,10 +470,10 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
uint8_t offset = parseByte(where, lineNo, token, numberType);
|
uint8_t offset = parseByte(where, lineNo, token, numberType);
|
||||||
|
|
||||||
if (offset < ADDR_SIZE)
|
if (offset < ADDR_SIZE)
|
||||||
fatal(where, lineNo, "Relocation index cannot point to header (%" PRIu16 " < %u)",
|
fatal(&where, lineNo, "Relocation index cannot point to header (%" PRIu16 " < %u)",
|
||||||
offset, ADDR_SIZE);
|
offset, ADDR_SIZE);
|
||||||
if (offset >= data.size())
|
if (offset >= data.size())
|
||||||
fatal(where, lineNo, "Relocation index is out of bounds (%" PRIu16 " >= %zu)",
|
fatal(&where, lineNo, "Relocation index is out of bounds (%" PRIu16 " >= %zu)",
|
||||||
offset, data.size());
|
offset, data.size());
|
||||||
|
|
||||||
getToken(nullptr, "Incomplete relocation");
|
getToken(nullptr, "Incomplete relocation");
|
||||||
@@ -484,20 +484,20 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
|
|
||||||
// Loudly fail on unknown flags
|
// 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");
|
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);
|
warning(&where, lineNo, "Unknown reloc flags 0x%x", flags & ~RELOC_ALL_FLAGS);
|
||||||
|
|
||||||
// Turn this into a Patch
|
// Turn this into a Patch
|
||||||
Patch &patch = section->patches.emplace_back();
|
Patch &patch = section->patches.emplace_back();
|
||||||
|
|
||||||
patch.lineNo = lineNo;
|
patch.lineNo = lineNo;
|
||||||
patch.src = where;
|
patch.src = &where;
|
||||||
patch.offset = offset - writtenOfs + *writeIndex;
|
patch.offset = offset - writtenOfs + *writeIndex;
|
||||||
if (section->patches.size() > 1) {
|
if (section->patches.size() > 1) {
|
||||||
uint32_t prevOffset = section->patches[section->patches.size() - 2].offset;
|
uint32_t prevOffset = section->patches[section->patches.size() - 2].offset;
|
||||||
if (prevOffset>= patch.offset)
|
if (prevOffset>= patch.offset)
|
||||||
fatal(where, lineNo, "Relocs not sorted by offset are not supported (%" PRIu32 " >= %" PRIu32 ")",
|
fatal(&where, lineNo, "Relocs not sorted by offset are not supported (%" PRIu32 " >= %" PRIu32 ")",
|
||||||
prevOffset, patch.offset);
|
prevOffset, patch.offset);
|
||||||
}
|
}
|
||||||
patch.pcSection = section; // No need to fill `pcSectionID`, then
|
patch.pcSection = section; // No need to fill `pcSectionID`, then
|
||||||
@@ -509,7 +509,7 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
|
|
||||||
assert(offset < data.size());
|
assert(offset < data.size());
|
||||||
if (data.size() - offset < nbBaseBytes)
|
if (data.size() - offset < nbBaseBytes)
|
||||||
fatal(where, lineNo, "Reloc would patch out of bounds (%" PRIu8 " > %zu)",
|
fatal(&where, lineNo, "Reloc would patch out of bounds (%" PRIu8 " > %zu)",
|
||||||
nbBaseBytes, data.size() - offset);
|
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);
|
baseValue = baseValue | data[offset + i] << (8 * i);
|
||||||
@@ -518,7 +518,7 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
// Generate a RPN expression from the info and flags
|
// Generate a RPN expression from the info and flags
|
||||||
if (flags & 1 << RELOC_ISSYM) {
|
if (flags & 1 << RELOC_ISSYM) {
|
||||||
if (idx >= fileSymbols.size())
|
if (idx >= fileSymbols.size())
|
||||||
fatal(where, lineNo, "Reloc refers to symbol #%" PRIu16 " out of %zu",
|
fatal(&where, lineNo, "Reloc refers to symbol #%" PRIu16 " out of %zu",
|
||||||
idx, fileSymbols.size());
|
idx, fileSymbols.size());
|
||||||
Symbol const &sym = fileSymbols[idx];
|
Symbol const &sym = fileSymbols[idx];
|
||||||
|
|
||||||
@@ -533,7 +533,7 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (idx == fileSymbols.size())
|
if (idx == fileSymbols.size())
|
||||||
fatal(where, lineNo, "\"%s\" is missing a reference to \"%s\"",
|
fatal(&where, lineNo, "\"%s\" is missing a reference to \"%s\"",
|
||||||
sym.name.c_str(), &sym.name.c_str()[1]);
|
sym.name.c_str(), &sym.name.c_str()[1]);
|
||||||
patch.rpnExpression.resize(5);
|
patch.rpnExpression.resize(5);
|
||||||
patch.rpnExpression[0] = RPN_BANK_SYM;
|
patch.rpnExpression[0] = RPN_BANK_SYM;
|
||||||
@@ -559,7 +559,7 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (idx >= fileSections.size())
|
if (idx >= fileSections.size())
|
||||||
fatal(where, lineNo, "Reloc refers to area #%" PRIu16 " out of %zu",
|
fatal(&where, lineNo, "Reloc refers to area #%" PRIu16 " out of %zu",
|
||||||
idx, fileSections.size());
|
idx, fileSections.size());
|
||||||
// It gets funky. If the area is absolute, *actually*, we
|
// It gets funky. If the area is absolute, *actually*, we
|
||||||
// must not add its base address, as the assembler will
|
// must not add its base address, as the assembler will
|
||||||
@@ -601,7 +601,7 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
// are present, so we must skip two of them
|
// are present, so we must skip two of them
|
||||||
if (flags & 1 << RELOC_EXPR16) {
|
if (flags & 1 << RELOC_EXPR16) {
|
||||||
if (*writeIndex + (offset - writtenOfs) > section->size)
|
if (*writeIndex + (offset - writtenOfs) > section->size)
|
||||||
fatal(where, lineNo, "'T' line writes past \"%s\"'s end (%u > %" PRIu16 ")",
|
fatal(&where, lineNo, "'T' line writes past \"%s\"'s end (%u > %" PRIu16 ")",
|
||||||
section->name.c_str(), *writeIndex + (offset - writtenOfs), section->size);
|
section->name.c_str(), *writeIndex + (offset - writtenOfs), section->size);
|
||||||
// Copy all bytes up to those (plus the byte that we'll overwrite)
|
// Copy all bytes up to those (plus the byte that we'll overwrite)
|
||||||
memcpy(§ion->data[*writeIndex], &data[writtenOfs], offset - writtenOfs + 1);
|
memcpy(§ion->data[*writeIndex], &data[writtenOfs], offset - writtenOfs + 1);
|
||||||
@@ -639,9 +639,9 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
}
|
}
|
||||||
} else if (flags & 1 << RELOC_ISPCREL) {
|
} else if (flags & 1 << RELOC_ISPCREL) {
|
||||||
assert(patch.type == PATCHTYPE_WORD);
|
assert(patch.type == PATCHTYPE_WORD);
|
||||||
fatal(where, lineNo, "16-bit PC-relative relocations are not supported");
|
fatal(&where, lineNo, "16-bit PC-relative relocations are not supported");
|
||||||
} else if (flags & (1 << RELOC_EXPR16 | 1 << RELOC_EXPR24)) {
|
} else if (flags & (1 << RELOC_EXPR16 | 1 << RELOC_EXPR24)) {
|
||||||
fatal(where, lineNo, "Flags 0x%x are not supported for 16-bit relocs",
|
fatal(&where, lineNo, "Flags 0x%x are not supported for 16-bit relocs",
|
||||||
flags & (1 << RELOC_EXPR16 | 1 << RELOC_EXPR24));
|
flags & (1 << RELOC_EXPR16 | 1 << RELOC_EXPR24));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -650,7 +650,7 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
if (writtenOfs != data.size()) {
|
if (writtenOfs != data.size()) {
|
||||||
assert(data.size() > writtenOfs);
|
assert(data.size() > writtenOfs);
|
||||||
if (*writeIndex + (data.size() - writtenOfs) > section->size)
|
if (*writeIndex + (data.size() - writtenOfs) > section->size)
|
||||||
fatal(where, lineNo, "'T' line writes past \"%s\"'s end (%zu > %" PRIu16 ")",
|
fatal(&where, lineNo, "'T' line writes past \"%s\"'s end (%zu > %" PRIu16 ")",
|
||||||
section->name.c_str(), *writeIndex + (data.size() - writtenOfs), section->size);
|
section->name.c_str(), *writeIndex + (data.size() - writtenOfs), section->size);
|
||||||
memcpy(§ion->data[*writeIndex], &data[writtenOfs], data.size() - writtenOfs);
|
memcpy(§ion->data[*writeIndex], &data[writtenOfs], data.size() - writtenOfs);
|
||||||
*writeIndex += data.size() - writtenOfs;
|
*writeIndex += data.size() - writtenOfs;
|
||||||
@@ -662,18 +662,18 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
|
|
||||||
case 'P':
|
case 'P':
|
||||||
default:
|
default:
|
||||||
warning(where, lineNo, "Unknown/unsupported line type '%c', ignoring", lineType);
|
warning(&where, lineNo, "Unknown/unsupported line type '%c', ignoring", lineType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.empty())
|
if (!data.empty())
|
||||||
warning(where, lineNo, "Last 'T' line had no 'R' line (ignored)");
|
warning(&where, lineNo, "Last 'T' line had no 'R' line (ignored)");
|
||||||
if (fileSections.size() < expectedNbAreas)
|
if (fileSections.size() < expectedNbAreas)
|
||||||
warning(where, lineNo, "Expected %" PRIu32 " 'A' lines, got only %zu", expectedNbAreas,
|
warning(&where, lineNo, "Expected %" PRIu32 " 'A' lines, got only %zu", expectedNbAreas,
|
||||||
fileSections.size());
|
fileSections.size());
|
||||||
if (fileSymbols.size() < expectedNbSymbols)
|
if (fileSymbols.size() < expectedNbSymbols)
|
||||||
warning(where, lineNo, "Expected %" PRIu32 " 'S' lines, got only %zu", expectedNbSymbols,
|
warning(&where, lineNo, "Expected %" PRIu32 " 'S' lines, got only %zu", expectedNbSymbols,
|
||||||
fileSymbols.size());
|
fileSymbols.size());
|
||||||
|
|
||||||
nbSectionsToAssign += fileSections.size();
|
nbSectionsToAssign += fileSections.size();
|
||||||
@@ -683,10 +683,10 @@ void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol>
|
|||||||
|
|
||||||
// RAM sections can have a size, but don't get any data (they shouldn't have any)
|
// RAM sections can have a size, but don't get any data (they shouldn't have any)
|
||||||
if (entry.writeIndex != section->size && entry.writeIndex != 0)
|
if (entry.writeIndex != section->size && entry.writeIndex != 0)
|
||||||
fatal(where, lineNo, "\"%s\" was not fully written (%" PRIu16 " < %" PRIu16 ")",
|
fatal(&where, lineNo, "\"%s\" was not fully written (%" PRIu16 " < %" PRIu16 ")",
|
||||||
section->name.c_str(), entry.writeIndex, section->size);
|
section->name.c_str(), entry.writeIndex, section->size);
|
||||||
|
|
||||||
sect_AddSection(section);
|
sect_AddSection(*section);
|
||||||
|
|
||||||
if (section->modifier == SECTION_FRAGMENT) {
|
if (section->modifier == SECTION_FRAGMENT) {
|
||||||
// Add the fragment's offset to all of its symbols
|
// Add the fragment's offset to all of its symbols
|
||||||
|
|||||||
@@ -15,122 +15,122 @@
|
|||||||
|
|
||||||
std::map<std::string, Section *> sections;
|
std::map<std::string, Section *> sections;
|
||||||
|
|
||||||
void sect_ForEach(void (*callback)(Section *))
|
void sect_ForEach(void (*callback)(Section &))
|
||||||
{
|
{
|
||||||
for (auto &it : sections)
|
for (auto &it : sections)
|
||||||
callback(it.second);
|
callback(*it.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkSectUnionCompat(Section *target, Section *other)
|
static void checkSectUnionCompat(Section &target, Section &other)
|
||||||
{
|
{
|
||||||
if (other->isAddressFixed) {
|
if (other.isAddressFixed) {
|
||||||
if (target->isAddressFixed) {
|
if (target.isAddressFixed) {
|
||||||
if (target->org != other->org)
|
if (target.org != other.org)
|
||||||
errx("Section \"%s\" is defined with conflicting addresses $%04"
|
errx("Section \"%s\" is defined with conflicting addresses $%04"
|
||||||
PRIx16 " and $%04" PRIx16, other->name.c_str(), target->org,
|
PRIx16 " and $%04" PRIx16, other.name.c_str(), target.org,
|
||||||
other->org);
|
other.org);
|
||||||
} else if (target->isAlignFixed) {
|
} else if (target.isAlignFixed) {
|
||||||
if ((other->org - target->alignOfs) & target->alignMask)
|
if ((other.org - target.alignOfs) & target.alignMask)
|
||||||
errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %"
|
errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %"
|
||||||
PRIu16 ") and address $%04" PRIx16, other->name.c_str(),
|
PRIu16 ") and address $%04" PRIx16, other.name.c_str(),
|
||||||
target->alignMask + 1, target->alignOfs, other->org);
|
target.alignMask + 1, target.alignOfs, other.org);
|
||||||
}
|
}
|
||||||
target->isAddressFixed = true;
|
target.isAddressFixed = true;
|
||||||
target->org = other->org;
|
target.org = other.org;
|
||||||
|
|
||||||
} else if (other->isAlignFixed) {
|
} else if (other.isAlignFixed) {
|
||||||
if (target->isAddressFixed) {
|
if (target.isAddressFixed) {
|
||||||
if ((target->org - other->alignOfs) & other->alignMask)
|
if ((target.org - other.alignOfs) & other.alignMask)
|
||||||
errx("Section \"%s\" is defined with conflicting address $%04"
|
errx("Section \"%s\" is defined with conflicting address $%04"
|
||||||
PRIx16 " and %d-byte alignment (offset %" PRIu16 ")",
|
PRIx16 " and %d-byte alignment (offset %" PRIu16 ")",
|
||||||
other->name.c_str(), target->org, other->alignMask + 1,
|
other.name.c_str(), target.org, other.alignMask + 1,
|
||||||
other->alignOfs);
|
other.alignOfs);
|
||||||
} else if (target->isAlignFixed
|
} else if (target.isAlignFixed
|
||||||
&& (other->alignMask & target->alignOfs)
|
&& (other.alignMask & target.alignOfs)
|
||||||
!= (target->alignMask & other->alignOfs)) {
|
!= (target.alignMask & other.alignOfs)) {
|
||||||
errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %"
|
errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %"
|
||||||
PRIu16 ") and %d-byte alignment (offset %" PRIu16 ")",
|
PRIu16 ") and %d-byte alignment (offset %" PRIu16 ")",
|
||||||
other->name.c_str(), target->alignMask + 1, target->alignOfs,
|
other.name.c_str(), target.alignMask + 1, target.alignOfs,
|
||||||
other->alignMask + 1, other->alignOfs);
|
other.alignMask + 1, other.alignOfs);
|
||||||
} else if (!target->isAlignFixed || (other->alignMask > target->alignMask)) {
|
} else if (!target.isAlignFixed || (other.alignMask > target.alignMask)) {
|
||||||
target->isAlignFixed = true;
|
target.isAlignFixed = true;
|
||||||
target->alignMask = other->alignMask;
|
target.alignMask = other.alignMask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkFragmentCompat(Section *target, Section *other)
|
static void checkFragmentCompat(Section &target, Section &other)
|
||||||
{
|
{
|
||||||
if (other->isAddressFixed) {
|
if (other.isAddressFixed) {
|
||||||
uint16_t org = other->org - target->size;
|
uint16_t org = other.org - target.size;
|
||||||
|
|
||||||
if (target->isAddressFixed) {
|
if (target.isAddressFixed) {
|
||||||
if (target->org != org)
|
if (target.org != org)
|
||||||
errx("Section \"%s\" is defined with conflicting addresses $%04"
|
errx("Section \"%s\" is defined with conflicting addresses $%04"
|
||||||
PRIx16 " and $%04" PRIx16, other->name.c_str(), target->org,
|
PRIx16 " and $%04" PRIx16, other.name.c_str(), target.org,
|
||||||
other->org);
|
other.org);
|
||||||
|
|
||||||
} else if (target->isAlignFixed) {
|
} else if (target.isAlignFixed) {
|
||||||
if ((org - target->alignOfs) & target->alignMask)
|
if ((org - target.alignOfs) & target.alignMask)
|
||||||
errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %"
|
errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %"
|
||||||
PRIu16 ") and address $%04" PRIx16, other->name.c_str(),
|
PRIu16 ") and address $%04" PRIx16, other.name.c_str(),
|
||||||
target->alignMask + 1, target->alignOfs, other->org);
|
target.alignMask + 1, target.alignOfs, other.org);
|
||||||
}
|
}
|
||||||
target->isAddressFixed = true;
|
target.isAddressFixed = true;
|
||||||
target->org = org;
|
target.org = org;
|
||||||
|
|
||||||
} else if (other->isAlignFixed) {
|
} else if (other.isAlignFixed) {
|
||||||
int32_t ofs = (other->alignOfs - target->size) % (other->alignMask + 1);
|
int32_t ofs = (other.alignOfs - target.size) % (other.alignMask + 1);
|
||||||
|
|
||||||
if (ofs < 0)
|
if (ofs < 0)
|
||||||
ofs += other->alignMask + 1;
|
ofs += other.alignMask + 1;
|
||||||
|
|
||||||
if (target->isAddressFixed) {
|
if (target.isAddressFixed) {
|
||||||
if ((target->org - ofs) & other->alignMask)
|
if ((target.org - ofs) & other.alignMask)
|
||||||
errx("Section \"%s\" is defined with conflicting address $%04"
|
errx("Section \"%s\" is defined with conflicting address $%04"
|
||||||
PRIx16 " and %d-byte alignment (offset %" PRIu16 ")",
|
PRIx16 " and %d-byte alignment (offset %" PRIu16 ")",
|
||||||
other->name.c_str(), target->org, other->alignMask + 1,
|
other.name.c_str(), target.org, other.alignMask + 1,
|
||||||
other->alignOfs);
|
other.alignOfs);
|
||||||
|
|
||||||
} else if (target->isAlignFixed
|
} else if (target.isAlignFixed
|
||||||
&& (other->alignMask & target->alignOfs) != (target->alignMask & ofs)) {
|
&& (other.alignMask & target.alignOfs) != (target.alignMask & ofs)) {
|
||||||
errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %"
|
errx("Section \"%s\" is defined with conflicting %d-byte alignment (offset %"
|
||||||
PRIu16 ") and %d-byte alignment (offset %" PRIu16 ")",
|
PRIu16 ") and %d-byte alignment (offset %" PRIu16 ")",
|
||||||
other->name.c_str(), target->alignMask + 1, target->alignOfs,
|
other.name.c_str(), target.alignMask + 1, target.alignOfs,
|
||||||
other->alignMask + 1, other->alignOfs);
|
other.alignMask + 1, other.alignOfs);
|
||||||
|
|
||||||
} else if (!target->isAlignFixed || (other->alignMask > target->alignMask)) {
|
} else if (!target.isAlignFixed || (other.alignMask > target.alignMask)) {
|
||||||
target->isAlignFixed = true;
|
target.isAlignFixed = true;
|
||||||
target->alignMask = other->alignMask;
|
target.alignMask = other.alignMask;
|
||||||
target->alignOfs = ofs;
|
target.alignOfs = ofs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mergeSections(Section *target, Section *other, enum SectionModifier mod)
|
static void mergeSections(Section &target, Section &other, enum SectionModifier mod)
|
||||||
{
|
{
|
||||||
// Common checks
|
// Common checks
|
||||||
|
|
||||||
if (target->type != other->type)
|
if (target.type != other.type)
|
||||||
errx("Section \"%s\" is defined with conflicting types %s and %s",
|
errx("Section \"%s\" is defined with conflicting types %s and %s",
|
||||||
other->name.c_str(), sectionTypeInfo[target->type].name.c_str(),
|
other.name.c_str(), sectionTypeInfo[target.type].name.c_str(),
|
||||||
sectionTypeInfo[other->type].name.c_str());
|
sectionTypeInfo[other.type].name.c_str());
|
||||||
|
|
||||||
if (other->isBankFixed) {
|
if (other.isBankFixed) {
|
||||||
if (!target->isBankFixed) {
|
if (!target.isBankFixed) {
|
||||||
target->isBankFixed = true;
|
target.isBankFixed = true;
|
||||||
target->bank = other->bank;
|
target.bank = other.bank;
|
||||||
} else if (target->bank != other->bank) {
|
} else if (target.bank != other.bank) {
|
||||||
errx("Section \"%s\" is defined with conflicting banks %" PRIu32 " and %"
|
errx("Section \"%s\" is defined with conflicting banks %" PRIu32 " and %"
|
||||||
PRIu32, other->name.c_str(), target->bank, other->bank);
|
PRIu32, other.name.c_str(), target.bank, other.bank);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (mod) {
|
switch (mod) {
|
||||||
case SECTION_UNION:
|
case SECTION_UNION:
|
||||||
checkSectUnionCompat(target, other);
|
checkSectUnionCompat(target, other);
|
||||||
if (other->size > target->size)
|
if (other.size > target.size)
|
||||||
target->size = other->size;
|
target.size = other.size;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SECTION_FRAGMENT:
|
case SECTION_FRAGMENT:
|
||||||
@@ -138,16 +138,16 @@ static void mergeSections(Section *target, Section *other, enum SectionModifier
|
|||||||
// Append `other` to `target`
|
// Append `other` to `target`
|
||||||
// Note that the order in which fragments are stored in the `nextu` list does not
|
// Note that the order in which fragments are stored in the `nextu` list does not
|
||||||
// really matter, only that offsets are properly computed
|
// really matter, only that offsets are properly computed
|
||||||
other->offset = target->size;
|
other.offset = target.size;
|
||||||
target->size += other->size;
|
target.size += other.size;
|
||||||
// Normally we'd check that `sect_HasData`, but SDCC areas may be `_INVALID` here
|
// Normally we'd check that `sect_HasData`, but SDCC areas may be `_INVALID` here
|
||||||
if (!other->data.empty()) {
|
if (!other.data.empty()) {
|
||||||
target->data.insert(target->data.end(), RANGE(other->data));
|
target.data.insert(target.data.end(), RANGE(other.data));
|
||||||
// Adjust patches' PC offsets
|
// Adjust patches' PC offsets
|
||||||
for (Patch &patch : other->patches)
|
for (Patch &patch : other.patches)
|
||||||
patch.pcOffset += other->offset;
|
patch.pcOffset += other.offset;
|
||||||
} else if (!target->data.empty()) {
|
} else if (!target.data.empty()) {
|
||||||
assert(other->size == 0);
|
assert(other.size == 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -155,27 +155,27 @@ static void mergeSections(Section *target, Section *other, enum SectionModifier
|
|||||||
unreachable_();
|
unreachable_();
|
||||||
}
|
}
|
||||||
|
|
||||||
other->nextu = target->nextu;
|
other.nextu = target.nextu;
|
||||||
target->nextu = other;
|
target.nextu = &other;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sect_AddSection(Section *section)
|
void sect_AddSection(Section §ion)
|
||||||
{
|
{
|
||||||
// Check if the section already exists
|
// Check if the section already exists
|
||||||
if (Section *other = sect_GetSection(section->name); other) {
|
if (Section *other = sect_GetSection(section.name); other) {
|
||||||
if (section->modifier != other->modifier)
|
if (section.modifier != other->modifier)
|
||||||
errx("Section \"%s\" defined as %s and %s", section->name.c_str(),
|
errx("Section \"%s\" defined as %s and %s", section.name.c_str(),
|
||||||
sectionModNames[section->modifier], sectionModNames[other->modifier]);
|
sectionModNames[section.modifier], sectionModNames[other->modifier]);
|
||||||
else if (section->modifier == SECTION_NORMAL)
|
else if (section.modifier == SECTION_NORMAL)
|
||||||
errx("Section name \"%s\" is already in use", section->name.c_str());
|
errx("Section name \"%s\" is already in use", section.name.c_str());
|
||||||
else
|
else
|
||||||
mergeSections(other, section, section->modifier);
|
mergeSections(*other, section, section.modifier);
|
||||||
} else if (section->modifier == SECTION_UNION && sect_HasData(section->type)) {
|
} else if (section.modifier == SECTION_UNION && sect_HasData(section.type)) {
|
||||||
errx("Section \"%s\" is of type %s, which cannot be unionized",
|
errx("Section \"%s\" is of type %s, which cannot be unionized",
|
||||||
section->name.c_str(), sectionTypeInfo[section->type].name.c_str());
|
section.name.c_str(), sectionTypeInfo[section.type].name.c_str());
|
||||||
} else {
|
} else {
|
||||||
// If not, add it
|
// If not, add it
|
||||||
sections[section->name] = section;
|
sections[section.name] = §ion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,84 +185,84 @@ Section *sect_GetSection(std::string const &name)
|
|||||||
return search != sections.end() ? search->second : nullptr;
|
return search != sections.end() ? search->second : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void doSanityChecks(Section *section)
|
static void doSanityChecks(Section §ion)
|
||||||
{
|
{
|
||||||
// Sanity check the section's type
|
// Sanity check the section's type
|
||||||
if (section->type < 0 || section->type >= SECTTYPE_INVALID) {
|
if (section.type < 0 || section.type >= SECTTYPE_INVALID) {
|
||||||
error(nullptr, 0, "Section \"%s\" has an invalid type", section->name.c_str());
|
error(nullptr, 0, "Section \"%s\" has an invalid type", section.name.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is32kMode && section->type == SECTTYPE_ROMX) {
|
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",
|
error(nullptr, 0, "%s: ROMX sections must be in bank 1 (if any) with option -t",
|
||||||
section->name.c_str());
|
section.name.c_str());
|
||||||
else
|
else
|
||||||
section->type = SECTTYPE_ROM0;
|
section.type = SECTTYPE_ROM0;
|
||||||
}
|
}
|
||||||
if (isWRAM0Mode && section->type == SECTTYPE_WRAMX) {
|
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",
|
error(nullptr, 0, "%s: WRAMX sections must be in bank 1 with options -w or -d",
|
||||||
section->name.c_str());
|
section.name.c_str());
|
||||||
else
|
else
|
||||||
section->type = SECTTYPE_WRAM0;
|
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",
|
error(nullptr, 0, "%s: VRAM bank 1 can't be used with option -d",
|
||||||
section->name.c_str());
|
section.name.c_str());
|
||||||
|
|
||||||
// Check if alignment is reasonable, this is important to avoid UB
|
// Check if alignment is reasonable, this is important to avoid UB
|
||||||
// An alignment of zero is equivalent to no alignment, basically
|
// 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;
|
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))
|
if (section.isAlignFixed && (section.alignMask & sectionTypeInfo[section.type].startAddr))
|
||||||
error(nullptr, 0, "%s: %s sections cannot be aligned to $%04x bytes",
|
error(nullptr, 0, "%s: %s sections cannot be aligned to $%04x bytes",
|
||||||
section->name.c_str(), sectionTypeInfo[section->type].name.c_str(),
|
section.name.c_str(), sectionTypeInfo[section.type].name.c_str(),
|
||||||
section->alignMask + 1);
|
section.alignMask + 1);
|
||||||
|
|
||||||
uint32_t minbank = sectionTypeInfo[section->type].firstBank, maxbank = sectionTypeInfo[section->type].lastBank;
|
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, minbank == maxbank
|
error(nullptr, 0, minbank == maxbank
|
||||||
? "Cannot place section \"%s\" in bank %" PRIu32 ", it must be %" PRIu32
|
? "Cannot place section \"%s\" in bank %" PRIu32 ", it must be %" PRIu32
|
||||||
: "Cannot place section \"%s\" in bank %" PRIu32 ", it must be between %" PRIu32 " and %" PRIu32,
|
: "Cannot place section \"%s\" in bank %" PRIu32 ", it must be between %" PRIu32 " and %" PRIu32,
|
||||||
section->name.c_str(), section->bank, minbank, maxbank);
|
section.name.c_str(), 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)
|
if (section.size > sectionTypeInfo[section.type].size)
|
||||||
error(nullptr, 0, "Section \"%s\" is bigger than the max size for that type: $%"
|
error(nullptr, 0, "Section \"%s\" is bigger than the max size for that type: $%"
|
||||||
PRIx16 " > $%" PRIx16,
|
PRIx16 " > $%" PRIx16,
|
||||||
section->name.c_str(), section->size, sectionTypeInfo[section->type].size);
|
section.name.c_str(), 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) {
|
if (minbank == maxbank) {
|
||||||
section->bank = minbank;
|
section.bank = minbank;
|
||||||
section->isBankFixed = true;
|
section.isBankFixed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (section->isAddressFixed) {
|
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.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",
|
error(nullptr, 0, "Section \"%s\"'s fixed address doesn't match its alignment",
|
||||||
section->name.c_str());
|
section.name.c_str());
|
||||||
section->isAlignFixed = false;
|
section.isAlignFixed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the target address is valid
|
// Ensure the target address is valid
|
||||||
if (section->org < sectionTypeInfo[section->type].startAddr
|
if (section.org < sectionTypeInfo[section.type].startAddr
|
||||||
|| section->org > endaddr(section->type))
|
|| section.org > endaddr(section.type))
|
||||||
error(nullptr, 0, "Section \"%s\"'s fixed address $%04" PRIx16 " is outside of range [$%04"
|
error(nullptr, 0, "Section \"%s\"'s fixed address $%04" PRIx16 " is outside of range [$%04"
|
||||||
PRIx16 "; $%04" PRIx16 "]", section->name.c_str(), section->org,
|
PRIx16 "; $%04" PRIx16 "]", section.name.c_str(), section.org,
|
||||||
sectionTypeInfo[section->type].startAddr, endaddr(section->type));
|
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, "Section \"%s\"'s end address $%04x is greater than last address $%04x",
|
error(nullptr, 0, "Section \"%s\"'s end address $%04x is greater than last address $%04x",
|
||||||
section->name.c_str(), section->org + section->size,
|
section.name.c_str(), section.org + section.size,
|
||||||
endaddr(section->type) + 1);
|
endaddr(section.type) + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,20 +13,20 @@
|
|||||||
|
|
||||||
std::map<std::string, Symbol *> symbols;
|
std::map<std::string, Symbol *> symbols;
|
||||||
|
|
||||||
void sym_AddSymbol(Symbol *symbol)
|
void sym_AddSymbol(Symbol &symbol)
|
||||||
{
|
{
|
||||||
// Check if the symbol already exists
|
// Check if the symbol already exists
|
||||||
if (Symbol *other = sym_GetSymbol(symbol->name); other) {
|
if (Symbol *other = sym_GetSymbol(symbol.name); other) {
|
||||||
fprintf(stderr, "error: \"%s\" both in %s from ", symbol->name.c_str(), symbol->objFileName);
|
fprintf(stderr, "error: \"%s\" both in %s from ", symbol.name.c_str(), symbol.objFileName);
|
||||||
symbol->src->dumpFileStack();
|
symbol.src->dumpFileStack();
|
||||||
fprintf(stderr, "(%" PRIu32 ") and in %s from ", symbol->lineNo, other->objFileName);
|
fprintf(stderr, "(%" PRIu32 ") and in %s from ", symbol.lineNo, other->objFileName);
|
||||||
other->src->dumpFileStack();
|
other->src->dumpFileStack();
|
||||||
fprintf(stderr, "(%" PRIu32 ")\n", other->lineNo);
|
fprintf(stderr, "(%" PRIu32 ")\n", other->lineNo);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not, add it
|
// If not, add it
|
||||||
symbols[symbol->name] = symbol;
|
symbols[symbol.name] = &symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol *sym_GetSymbol(std::string const &name)
|
Symbol *sym_GetSymbol(std::string const &name)
|
||||||
|
|||||||
Reference in New Issue
Block a user