Use new hashmap implementation for symbols

This commit is contained in:
ISSOtm
2020-03-24 12:50:14 +01:00
parent 666b9f8f7b
commit 29629245a4
4 changed files with 115 additions and 219 deletions

View File

@@ -34,7 +34,6 @@ extern uint32_t unionStart[MAXUNIONS];
extern uint32_t unionSize[MAXUNIONS]; extern uint32_t unionSize[MAXUNIONS];
extern char tzCurrentFileName[_MAX_PATH + 1]; extern char tzCurrentFileName[_MAX_PATH + 1];
extern struct Section *pCurrentSection; extern struct Section *pCurrentSection;
extern struct sSymbol *tHashedSymbols[HASHSIZE];
extern struct sSymbol *pPCSymbol; extern struct sSymbol *pPCSymbol;
extern bool oDontExpandStrings; extern bool oDontExpandStrings;

View File

@@ -34,9 +34,7 @@ struct sSymbol {
enum SymbolType type; enum SymbolType type;
bool isExported; /* Whether the symbol is to be exported */ bool isExported; /* Whether the symbol is to be exported */
bool isBuiltin; /* Whether the symbol is a built-in */ bool isBuiltin; /* Whether the symbol is a built-in */
bool isReferenced; /* Whether the symbol is referenced in a RPN expr */
struct sSymbol *pScope; struct sSymbol *pScope;
struct sSymbol *pNext;
struct Section *pSection; struct Section *pSection;
int32_t nValue; int32_t nValue;
uint32_t ulMacroSize; uint32_t ulMacroSize;
@@ -44,6 +42,9 @@ struct sSymbol {
int32_t (*Callback)(struct sSymbol const *self); int32_t (*Callback)(struct sSymbol const *self);
char tzFileName[_MAX_PATH + 1]; /* File where the symbol was defined. */ char tzFileName[_MAX_PATH + 1]; /* File where the symbol was defined. */
uint32_t nFileLine; /* Line where the symbol was defined. */ uint32_t nFileLine; /* Line where the symbol was defined. */
uint32_t ID; /* ID of the symbol in the object file (-1 if none) */
struct sSymbol *next; /* Next object to output in the object file */
}; };
static inline bool sym_IsDefined(struct sSymbol const *sym) static inline bool sym_IsDefined(struct sSymbol const *sym)
@@ -87,8 +88,9 @@ static inline char *sym_GetStringValue(struct sSymbol const *sym)
return sym->pMacro; return sym->pMacro;
} }
void sym_ForEach(void (*func)(struct sSymbol *, void *), void *arg);
int32_t sym_GetValue(struct sSymbol const *sym); int32_t sym_GetValue(struct sSymbol const *sym);
uint32_t sym_CalcHash(const char *s);
void sym_SetExportAll(bool set); void sym_SetExportAll(bool set);
struct sSymbol *sym_AddLocalReloc(char const *tzSym); struct sSymbol *sym_AddLocalReloc(char const *tzSym);
struct sSymbol *sym_AddReloc(char const *tzSym); struct sSymbol *sym_AddReloc(char const *tzSym);

View File

@@ -40,13 +40,6 @@ struct Patch {
struct Patch *pNext; struct Patch *pNext;
}; };
struct PatchSymbol {
uint32_t ID;
struct sSymbol const *pSymbol;
struct PatchSymbol *pNext;
struct PatchSymbol *pBucketNext; /* next symbol in hash table bucket */
};
struct Assertion { struct Assertion {
struct Patch *patch; struct Patch *patch;
struct Section *section; struct Section *section;
@@ -54,29 +47,17 @@ struct Assertion {
struct Assertion *next; struct Assertion *next;
}; };
struct PatchSymbol *tHashedPatchSymbols[HASHSIZE];
struct Section *pSectionList, *pCurrentSection;
struct PatchSymbol *pPatchSymbols;
struct PatchSymbol **ppPatchSymbolsTail = &pPatchSymbols;
struct Assertion *assertions = NULL;
char *tzObjectname; char *tzObjectname;
/* /* TODO: shouldn't `pCurrentSection` be somewhere else? */
* Count the number of symbols used in this object struct Section *pSectionList, *pCurrentSection;
*/
static uint32_t countsymbols(void)
{
struct PatchSymbol *pSym;
uint32_t count = 0;
pSym = pPatchSymbols; /* Linked list of symbols to put in the object file */
while (pSym) { static struct sSymbol *objectSymbols = NULL;
count++; static struct sSymbol **objectSymbolsTail = &objectSymbols;
pSym = pSym->pNext; static uint32_t nbSymbols = 0; /* Length of the above list */
}
return count; static struct Assertion *assertions = NULL;
}
/* /*
* Count the number of sections used in this object * Count the number of sections used in this object
@@ -236,10 +217,8 @@ static void writesymbol(struct sSymbol const *pSym, FILE *f)
break; break;
case SYMTYPE_EXPORT: case SYMTYPE_EXPORT:
offset = pSym->nValue; offset = pSym->nValue;
if (pSym->type != SYM_LABEL) sectid = pSym->type == SYM_LABEL ? getsectid(pSym->pSection)
sectid = -1; : -1;
else
sectid = getsectid(pSym->pSection);
break; break;
} }
@@ -256,58 +235,18 @@ static void writesymbol(struct sSymbol const *pSym, FILE *f)
} }
/* /*
* Add a symbol to the object * Returns a symbol's ID within the object file
* If the symbol does not have one, one is assigned by registering the symbol
*/ */
static uint32_t nextID; static uint32_t getSymbolID(struct sSymbol *sym)
static uint32_t addsymbol(struct sSymbol const *pSym)
{ {
struct PatchSymbol *pPSym, **ppPSym; if (sym->ID == -1) {
uint32_t hash; sym->ID = nbSymbols++;
hash = sym_CalcHash(pSym->tzName); *objectSymbolsTail = sym;
ppPSym = &(tHashedPatchSymbols[hash]); objectSymbolsTail = &sym->next;
while ((*ppPSym) != NULL) {
if (pSym == (*ppPSym)->pSymbol)
return (*ppPSym)->ID;
ppPSym = &((*ppPSym)->pBucketNext);
}
pPSym = malloc(sizeof(struct PatchSymbol));
*ppPSym = pPSym;
if (pPSym == NULL)
fatalerror("No memory for patchsymbol");
pPSym->pNext = NULL;
pPSym->pBucketNext = NULL;
pPSym->pSymbol = pSym;
pPSym->ID = nextID++;
*ppPatchSymbolsTail = pPSym;
ppPatchSymbolsTail = &(pPSym->pNext);
return pPSym->ID;
}
/*
* Add all exported symbols to the object
*/
static void addexports(void)
{
int32_t i;
for (i = 0; i < HASHSIZE; i++) {
struct sSymbol *pSym;
pSym = tHashedSymbols[i];
while (pSym) {
if (pSym->isExported)
addsymbol(pSym);
pSym = pSym->pNext;
}
} }
return sym->ID;
} }
static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn, static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn,
@@ -330,63 +269,46 @@ static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn,
break; break;
case RPN_SYM: case RPN_SYM:
{ {
uint32_t symptr = 0; for (unsigned int i = -1; (tzSym[++i] = popbyte()); )
while ((tzSym[symptr++] = popbyte()) != 0)
; ;
struct sSymbol *sym = sym_FindSymbol(tzSym);
uint32_t value;
struct sSymbol const *sym = sym_FindSymbol(tzSym); if (sym_IsConstant(sym)) {
if (!sym) {
break; // TODO: wtf?
} else if (sym_IsConstant(sym)) {
uint32_t value;
value = sym_GetConstantValue(tzSym);
writebyte(RPN_CONST); writebyte(RPN_CONST);
writebyte(value & 0xFF); value = sym_GetConstantValue(tzSym);
writebyte(value >> 8);
writebyte(value >> 16);
writebyte(value >> 24);
} else { } else {
symptr = addsymbol(sym);
writebyte(RPN_SYM); writebyte(RPN_SYM);
writebyte(symptr & 0xFF); value = getSymbolID(sym);
writebyte(symptr >> 8);
writebyte(symptr >> 16);
writebyte(symptr >> 24);
} }
writebyte(value & 0xFF);
writebyte(value >> 8);
writebyte(value >> 16);
writebyte(value >> 24);
break; break;
} }
case RPN_BANK_SYM: case RPN_BANK_SYM:
{ {
struct sSymbol *sym; for (unsigned int i = -1; (tzSym[++i] = popbyte()); )
uint32_t symptr = 0;
while ((tzSym[symptr++] = popbyte()) != 0)
; ;
struct sSymbol *sym = sym_FindSymbol(tzSym);
uint32_t value = getSymbolID(sym);
sym = sym_FindSymbol(tzSym);
if (sym == NULL)
break;
symptr = addsymbol(sym);
writebyte(RPN_BANK_SYM); writebyte(RPN_BANK_SYM);
writebyte(symptr & 0xFF); writebyte(value & 0xFF);
writebyte(symptr >> 8); writebyte(value >> 8);
writebyte(symptr >> 16); writebyte(value >> 16);
writebyte(symptr >> 24); writebyte(value >> 24);
break; break;
} }
case RPN_BANK_SECT: case RPN_BANK_SECT:
{ {
uint16_t b; uint8_t b;
writebyte(RPN_BANK_SECT); writebyte(RPN_BANK_SECT);
do { do {
b = popbyte(); b = popbyte();
writebyte(b & 0xFF); writebyte(b);
} while (b != 0); } while (b != 0);
break; break;
} }
@@ -471,32 +393,40 @@ static void writeassert(struct Assertion *assert, FILE *f)
fputstring(assert->message, f); fputstring(assert->message, f);
} }
static void registerExportedSymbol(struct sSymbol *symbol, void *arg)
{
(void)arg;
if (symbol->isExported && symbol->ID == -1) {
*objectSymbolsTail = symbol;
objectSymbolsTail = &symbol->next;
nbSymbols++;
}
}
/* /*
* Write an objectfile * Write an objectfile
*/ */
void out_WriteObject(void) void out_WriteObject(void)
{ {
FILE *f; FILE *f;
struct PatchSymbol *pSym;
struct Section *pSect; struct Section *pSect;
struct Assertion *assert = assertions; struct Assertion *assert = assertions;
addexports();
f = fopen(tzObjectname, "wb"); f = fopen(tzObjectname, "wb");
if (!f) if (!f)
err(1, "Couldn't write file '%s'", tzObjectname); err(1, "Couldn't write file '%s'", tzObjectname);
/* Also write exported symbols that weren't written above */
sym_ForEach(registerExportedSymbol, NULL);
fprintf(f, RGBDS_OBJECT_VERSION_STRING, RGBDS_OBJECT_VERSION_NUMBER); fprintf(f, RGBDS_OBJECT_VERSION_STRING, RGBDS_OBJECT_VERSION_NUMBER);
fputlong(RGBDS_OBJECT_REV, f); fputlong(RGBDS_OBJECT_REV, f);
fputlong(countsymbols(), f); fputlong(nbSymbols, f);
fputlong(countsections(), f); fputlong(countsections(), f);
pSym = pPatchSymbols; for (struct sSymbol const *sym = objectSymbols; sym; sym = sym->next) {
while (pSym) { writesymbol(sym, f);
writesymbol(pSym->pSymbol, f);
pSym = pSym->pNext;
} }
pSect = pSectionList; pSect = pSectionList;

View File

@@ -11,6 +11,7 @@
*/ */
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -28,10 +29,12 @@
#include "extern/err.h" #include "extern/err.h"
#include "hashmap.h"
#include "helpers.h" #include "helpers.h"
#include "version.h" #include "version.h"
struct sSymbol *tHashedSymbols[HASHSIZE]; HashMap symbols;
static struct sSymbol *pScope; /* Current section symbol scope */ static struct sSymbol *pScope; /* Current section symbol scope */
struct sSymbol *pPCSymbol; struct sSymbol *pPCSymbol;
static struct sSymbol *p_NARGSymbol; static struct sSymbol *p_NARGSymbol;
@@ -48,6 +51,26 @@ static char SavedMINUTE[3];
static char SavedSECOND[3]; static char SavedSECOND[3];
static bool exportall; static bool exportall;
struct ForEachArgs {
void (*func)(struct sSymbol *, void *);
void *arg;
};
static void forEachWrapper(void *_symbol, void *_argWrapper)
{
struct ForEachArgs *argWrapper = _argWrapper;
struct sSymbol *symbol = _symbol;
argWrapper->func(symbol, argWrapper->arg);
}
void sym_ForEach(void (*func)(struct sSymbol *, void *), void *arg)
{
struct ForEachArgs argWrapper = { .func = func, .arg = arg };
hash_ForEach(symbols, forEachWrapper, &argWrapper);
}
static int32_t Callback_NARG(struct sSymbol const *self) static int32_t Callback_NARG(struct sSymbol const *self)
{ {
(void)self; (void)self;
@@ -79,14 +102,6 @@ int32_t sym_GetValue(struct sSymbol const *sym)
return sym->nValue; return sym->nValue;
} }
/*
* Calculate the hash value for a symbol name
*/
uint32_t sym_CalcHash(const char *s)
{
return calchash(s) % HASHSIZE;
}
/* /*
* Update a symbol's definition filename and line * Update a symbol's definition filename and line
*/ */
@@ -105,36 +120,28 @@ static void updateSymbolFilename(struct sSymbol *nsym)
*/ */
static struct sSymbol *createsymbol(char const *s) static struct sSymbol *createsymbol(char const *s)
{ {
struct sSymbol **ppsym; struct sSymbol *symbol = malloc(sizeof(*symbol));
uint32_t hash;
hash = sym_CalcHash(s); if (!symbol)
ppsym = &(tHashedSymbols[hash]); fatalerror("Failed to create symbol: %s", strerror(errno));
while ((*ppsym) != NULL) if (snprintf(symbol->tzName, MAXSYMLEN + 1, "%s", s) > MAXSYMLEN)
ppsym = &((*ppsym)->pNext);
(*ppsym) = malloc(sizeof(struct sSymbol));
if ((*ppsym) == NULL) {
fatalerror("No memory for symbol");
return NULL;
}
if (snprintf((*ppsym)->tzName, MAXSYMLEN + 1, "%s", s) > MAXSYMLEN)
warning(WARNING_LONG_STR, "Symbol name is too long: '%s'", s); warning(WARNING_LONG_STR, "Symbol name is too long: '%s'", s);
(*ppsym)->isExported = false; hash_AddElement(symbols, symbol->tzName, symbol);
(*ppsym)->isBuiltin = false;
(*ppsym)->isReferenced = false; symbol->isExported = false;
(*ppsym)->pScope = NULL; symbol->isBuiltin = false;
(*ppsym)->pNext = NULL; symbol->pScope = NULL;
(*ppsym)->pSection = NULL; symbol->pSection = NULL;
(*ppsym)->nValue = 0; symbol->nValue = 0; /* TODO: is this necessary? */
(*ppsym)->pMacro = NULL; symbol->pMacro = NULL;
(*ppsym)->Callback = NULL; symbol->Callback = NULL;
updateSymbolFilename(*ppsym);
return *ppsym; symbol->ID = -1;
symbol->next = NULL;
updateSymbolFilename(symbol);
return symbol;
} }
/* /*
@@ -153,12 +160,10 @@ static void fullSymbolName(char *output, size_t outputSize,
} }
/* /*
* Find the pointer to a symbol by name and scope * Find a symbol by name and scope
*/ */
static struct sSymbol **findpsymbol(char const *s, struct sSymbol const *scope) static struct sSymbol *findsymbol(char const *s, struct sSymbol const *scope)
{ {
struct sSymbol **ppsym;
int32_t hash;
char fullname[MAXSYMLEN + 1]; char fullname[MAXSYMLEN + 1];
if (s[0] == '.' && scope) { if (s[0] == '.' && scope) {
@@ -168,32 +173,11 @@ static struct sSymbol **findpsymbol(char const *s, struct sSymbol const *scope)
char const *separator = strchr(s, '.'); char const *separator = strchr(s, '.');
if (separator) { if (separator && strchr(separator + 1, '.'))
if (strchr(separator + 1, '.')) fatalerror("'%s' is a nonsensical reference to a nested local symbol",
fatalerror("'%s' is a nonsensical reference to a nested local symbol", s);
s);
}
hash = sym_CalcHash(s); return hash_GetElement(symbols, s);
ppsym = &(tHashedSymbols[hash]);
while ((*ppsym) != NULL) {
if ((strcmp(s, (*ppsym)->tzName) == 0))
return ppsym;
ppsym = &((*ppsym)->pNext);
}
return NULL;
}
/*
* Find a symbol by name and scope
*/
static struct sSymbol *findsymbol(char const *s, struct sSymbol const *scope)
{
struct sSymbol **ppsym = findpsymbol(s, scope);
return ppsym ? *ppsym : NULL;
} }
/* /*
@@ -213,7 +197,7 @@ struct sSymbol *sym_FindSymbol(char const *tzName)
static inline bool isReferenced(struct sSymbol const *sym) static inline bool isReferenced(struct sSymbol const *sym)
{ {
return sym->isReferenced; return sym->ID != -1;
} }
/* /*
@@ -221,33 +205,20 @@ static inline bool isReferenced(struct sSymbol const *sym)
*/ */
void sym_Purge(char const *tzName) void sym_Purge(char const *tzName)
{ {
struct sSymbol **ppSym; struct sSymbol *scope = tzName[0] == '.' ? pScope : NULL;
struct sSymbol *pscope; struct sSymbol *symbol = findsymbol(tzName, scope);
if (*tzName == '.') if (!symbol) {
pscope = pScope;
else
pscope = NULL;
ppSym = findpsymbol(tzName, pscope);
if (!ppSym) {
yyerror("'%s' not defined", tzName); yyerror("'%s' not defined", tzName);
} else if ((*ppSym)->isBuiltin) { } else if (symbol->isBuiltin) {
yyerror("Built-in symbol '%s' cannot be purged", tzName); yyerror("Built-in symbol '%s' cannot be purged", tzName);
} else if (isReferenced(*ppSym)) { } else if (isReferenced(symbol)) {
yyerror("Symbol \"%s\" is referenced and thus cannot be purged", yyerror("Symbol \"%s\" is referenced and thus cannot be purged",
tzName); tzName);
} else { } else {
struct sSymbol *pSym; hash_RemoveElement(symbols, tzName);
free(symbol->pMacro);
pSym = *ppSym; free(symbol);
*ppSym = pSym->pNext;
if (pSym->pMacro)
free(pSym->pMacro);
free(pSym);
} }
} }
@@ -503,10 +474,8 @@ void sym_Export(char const *tzSym)
struct sSymbol *nsym = sym_FindSymbol(tzSym); struct sSymbol *nsym = sym_FindSymbol(tzSym);
/* If the symbol doesn't exist, create a ref that can be purged */ /* If the symbol doesn't exist, create a ref that can be purged */
if (!nsym) { if (!nsym)
nsym = sym_Ref(tzSym); nsym = sym_Ref(tzSym);
nsym->isReferenced = false;
}
nsym->isExported = true; nsym->isExported = true;
} }
@@ -554,7 +523,6 @@ struct sSymbol *sym_Ref(char const *tzSym)
nsym = createsymbol(tzSym); nsym = createsymbol(tzSym);
nsym->type = SYM_REF; nsym->type = SYM_REF;
} }
nsym->isReferenced = true;
return nsym; return nsym;
} }
@@ -583,9 +551,6 @@ static inline char const *removeLeadingZeros(char const *ptr)
*/ */
void sym_Init(void) void sym_Init(void)
{ {
for (int32_t i = 0; i < HASHSIZE; i++)
tHashedSymbols[i] = NULL;
pPCSymbol = sym_AddReloc("@"); pPCSymbol = sym_AddReloc("@");
pPCSymbol->Callback = CallbackPC; pPCSymbol->Callback = CallbackPC;
pPCSymbol->isBuiltin = true; pPCSymbol->isBuiltin = true;