mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Comply with sym file spec (#1078)
Co-authored-by: Rangi <35663410+Rangi42@users.noreply.github.com>
This commit is contained in:
1
Makefile
1
Makefile
@@ -97,6 +97,7 @@ rgblink_obj := \
|
|||||||
src/link/section.o \
|
src/link/section.o \
|
||||||
src/link/symbol.o \
|
src/link/symbol.o \
|
||||||
src/extern/getopt.o \
|
src/extern/getopt.o \
|
||||||
|
src/extern/utf8decoder.o \
|
||||||
src/error.o \
|
src/error.o \
|
||||||
src/hashmap.o \
|
src/hashmap.o \
|
||||||
src/linkdefs.o \
|
src/linkdefs.o \
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ set(rgblink_src
|
|||||||
"link/sdas_obj.c"
|
"link/sdas_obj.c"
|
||||||
"link/section.c"
|
"link/section.c"
|
||||||
"link/symbol.c"
|
"link/symbol.c"
|
||||||
|
"extern/utf8decoder.c"
|
||||||
"hashmap.c"
|
"hashmap.c"
|
||||||
"linkdefs.c"
|
"linkdefs.c"
|
||||||
"opmath.c"
|
"opmath.c"
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
#include "link/section.h"
|
#include "link/section.h"
|
||||||
#include "link/symbol.h"
|
#include "link/symbol.h"
|
||||||
|
|
||||||
|
#include "extern/utf8decoder.h"
|
||||||
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "linkdefs.h"
|
#include "linkdefs.h"
|
||||||
#include "platform.h" // MIN_NB_ELMS
|
#include "platform.h" // MIN_NB_ELMS
|
||||||
@@ -273,6 +275,55 @@ static struct SortedSection const **nextSection(struct SortedSection const **s1,
|
|||||||
return (*s1)->section->org < (*s2)->section->org ? s1 : s2;
|
return (*s1)->section->org < (*s2)->section->org ? s1 : s2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checks whether this character is legal as the first character of a symbol's name in a sym file
|
||||||
|
static bool canStartSymName(char c)
|
||||||
|
{
|
||||||
|
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether this character is legal in a symbol's name in a sym file
|
||||||
|
static bool isLegalForSymName(char c)
|
||||||
|
{
|
||||||
|
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
|
||||||
|
c == '_' || c == '@' || c == '#' || c == '$' || c == '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints a symbol's name to `symFile`, assuming that the first character is legal.
|
||||||
|
// Illegal characters are UTF-8-decoded (errors are replaced by U+FFFD) and emitted as `\u`/`\U`.
|
||||||
|
static void printSymName(char const *name)
|
||||||
|
{
|
||||||
|
for (char const *ptr = name; *ptr != '\0'; ) {
|
||||||
|
char c = *ptr;
|
||||||
|
|
||||||
|
if (isLegalForSymName(c)) {
|
||||||
|
// Output legal ASCII characters as-is
|
||||||
|
fputc(c, symFile);
|
||||||
|
++ptr;
|
||||||
|
} else {
|
||||||
|
// Output illegal characters using Unicode escapes
|
||||||
|
// Decode the UTF-8 codepoint; or at least attempt to
|
||||||
|
uint32_t state = 0, codepoint;
|
||||||
|
|
||||||
|
do {
|
||||||
|
decode(&state, &codepoint, *ptr);
|
||||||
|
if (state == 1) {
|
||||||
|
// This sequence was invalid; emit a U+FFFD, and recover
|
||||||
|
codepoint = 0xFFFD;
|
||||||
|
// Skip continuation bytes
|
||||||
|
// A NUL byte does not qualify, so we're good
|
||||||
|
while ((*ptr & 0xC0) == 0x80)
|
||||||
|
++ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++ptr;
|
||||||
|
} while (state != 0);
|
||||||
|
|
||||||
|
fprintf(symFile, codepoint <= 0xFFFF ? "\\u%04" PRIx32 : "\\U%08" PRIx32,
|
||||||
|
codepoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Comparator function for `qsort` to sort symbols
|
// Comparator function for `qsort` to sort symbols
|
||||||
// Symbols are ordered by address, or else by original index for a stable sort
|
// Symbols are ordered by address, or else by original index for a stable sort
|
||||||
static int compareSymbols(void const *a, void const *b)
|
static int compareSymbols(void const *a, void const *b)
|
||||||
@@ -296,16 +347,22 @@ static void writeSymBank(struct SortedSections const *bankSections,
|
|||||||
if (!symFile)
|
if (!symFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#define forEachSortedSection(sect, ...) do { \
|
||||||
|
for (struct SortedSection const *ssp = bankSections->zeroLenSections; ssp; ssp = ssp->next) { \
|
||||||
|
for (struct Section const *sect = ssp->section; sect; sect = sect->nextu) \
|
||||||
|
__VA_ARGS__ \
|
||||||
|
} \
|
||||||
|
for (struct SortedSection const *ssp = bankSections->sections; ssp; ssp = ssp->next) { \
|
||||||
|
for (struct Section const *sect = ssp->section; sect; sect = sect->nextu) \
|
||||||
|
__VA_ARGS__ \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
uint32_t nbSymbols = 0;
|
uint32_t nbSymbols = 0;
|
||||||
|
|
||||||
for (struct SortedSection const *ptr = bankSections->zeroLenSections; ptr; ptr = ptr->next) {
|
forEachSortedSection(sect, {
|
||||||
for (struct Section const *sect = ptr->section; sect; sect = sect->nextu)
|
|
||||||
nbSymbols += sect->nbSymbols;
|
nbSymbols += sect->nbSymbols;
|
||||||
}
|
});
|
||||||
for (struct SortedSection const *ptr = bankSections->sections; ptr; ptr = ptr->next) {
|
|
||||||
for (struct Section const *sect = ptr->section; sect; sect = sect->nextu)
|
|
||||||
nbSymbols += sect->nbSymbols;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nbSymbols)
|
if (!nbSymbols)
|
||||||
return;
|
return;
|
||||||
@@ -315,29 +372,21 @@ static void writeSymBank(struct SortedSections const *bankSections,
|
|||||||
if (!symList)
|
if (!symList)
|
||||||
err("Failed to allocate symbol list");
|
err("Failed to allocate symbol list");
|
||||||
|
|
||||||
uint32_t idx = 0;
|
nbSymbols = 0;
|
||||||
|
|
||||||
for (struct SortedSection const *ptr = bankSections->zeroLenSections; ptr; ptr = ptr->next) {
|
forEachSortedSection(sect, {
|
||||||
for (struct Section const *sect = ptr->section; sect; sect = sect->nextu) {
|
|
||||||
for (uint32_t i = 0; i < sect->nbSymbols; i++) {
|
for (uint32_t i = 0; i < sect->nbSymbols; i++) {
|
||||||
symList[idx].idx = idx;
|
if (!canStartSymName(sect->symbols[i]->name[0]))
|
||||||
symList[idx].sym = sect->symbols[i];
|
// Don't output symbols that begin with an illegal character
|
||||||
symList[idx].addr = symList[idx].sym->offset + sect->org;
|
continue;
|
||||||
idx++;
|
symList[nbSymbols].idx = nbSymbols;
|
||||||
|
symList[nbSymbols].sym = sect->symbols[i];
|
||||||
|
symList[nbSymbols].addr = symList[nbSymbols].sym->offset + sect->org;
|
||||||
|
nbSymbols++;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
|
||||||
for (struct SortedSection const *ptr = bankSections->sections; ptr; ptr = ptr->next) {
|
#undef forEachSortedSection
|
||||||
for (struct Section const *sect = ptr->section; sect; sect = sect->nextu) {
|
|
||||||
for (uint32_t i = 0; i < sect->nbSymbols; i++) {
|
|
||||||
symList[idx].idx = idx;
|
|
||||||
symList[idx].sym = sect->symbols[i];
|
|
||||||
symList[idx].addr = symList[idx].sym->offset + sect->org;
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(idx == nbSymbols);
|
|
||||||
|
|
||||||
qsort(symList, nbSymbols, sizeof(*symList), compareSymbols);
|
qsort(symList, nbSymbols, sizeof(*symList), compareSymbols);
|
||||||
|
|
||||||
@@ -346,11 +395,13 @@ static void writeSymBank(struct SortedSections const *bankSections,
|
|||||||
for (uint32_t i = 0; i < nbSymbols; i++) {
|
for (uint32_t i = 0; i < nbSymbols; i++) {
|
||||||
struct SortedSymbol *sym = &symList[i];
|
struct SortedSymbol *sym = &symList[i];
|
||||||
|
|
||||||
fprintf(symFile, "%02" PRIx32 ":%04" PRIx16 " %s\n",
|
fprintf(symFile, "%02" PRIx32 ":%04" PRIx16 " ", symBank, sym->addr);
|
||||||
symBank, sym->addr, sym->sym->name);
|
printSymName(sym->sym->name);
|
||||||
|
fputc('\n', symFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(symList);
|
free(symList);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user