Skip to content

Commit

Permalink
Re-implement smart linking
Browse files Browse the repository at this point in the history
Long-broken feature, fell into disrepair, got removed...
Now it's back! Though, it needs testing.
Fixes gbdev#82
  • Loading branch information
ISSOtm authored and daid committed Mar 5, 2021
1 parent 8864609 commit abb9a25
Show file tree
Hide file tree
Showing 12 changed files with 444 additions and 70 deletions.
6 changes: 3 additions & 3 deletions include/hashmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ bool hash_ReplaceElement(HashMap const map, char const *key, void *element);
* Removes an element from a hashmap.
* @param map The HashMap to remove the element from
* @param key The key to search the element with
* @return True if the element was found and removed
* @return The element removed, or NULL if none was found
*/
bool hash_RemoveElement(HashMap map, char const *key);
void *hash_RemoveElement(HashMap map, char const *key);

/**
* Finds an element in a hashmap.
Expand All @@ -74,6 +74,6 @@ void hash_ForEach(HashMap const map, void (*func)(void *, void *), void *arg);
* This does not `free` the data structure itself!
* @param map The map to empty
*/
void hash_EmptyMap(HashMap map);
void hash_EmptyMap(HashMap map, void (*callback)(void *));

#endif /* RGBDS_LINK_HASHMAP_H */
5 changes: 5 additions & 0 deletions include/link/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ void obj_ReadFile(char const *fileName, unsigned int i);
*/
void obj_DoSanityChecks(void);

/**
* @return The first assertion in the linked list of all assertions
*/
struct Assertion const *obj_GetFirstAssertion(void);

/**
* Evaluate all assertions
*/
Expand Down
19 changes: 19 additions & 0 deletions include/link/patch.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

#include "linkdefs.h"

struct Symbol;

struct Assertion {
struct Patch patch;
// enum AssertionType type; The `patch`'s field is instead re-used
Expand All @@ -32,6 +34,7 @@ struct Assertion {

/**
* Checks all assertions
* @param assertion The first assertion to check (in a linked list)
* @return true if assertion failed
*/
void patch_CheckAssertions(struct Assertion *assertion);
Expand All @@ -41,4 +44,20 @@ void patch_CheckAssertions(struct Assertion *assertion);
*/
void patch_ApplyPatches(void);

/**
* Executes a callback on all sections referenced by a patch's expression
* @param patch The patch to scan the expression of
*/
void patch_FindRefdSections(struct Patch const *patch, void (*callback)(struct Section *),
struct Symbol const * const *fileSymbols);

/**
* Properly deletes a patch object
* @param patch The patch to be deleted
*/
static inline void patch_DeletePatch(struct Patch *patch)
{
free(patch->rpnExpression);
}

#endif /* RGBDS_LINK_PATCH_H */
8 changes: 8 additions & 0 deletions include/link/section.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ struct Section {
uint32_t nbSymbols;
struct Symbol const **symbols;
struct Section *nextu; /* The next "component" of this unionized sect */
bool smartLinked; // Set to true if kept by smart linking
};

/*
Expand Down Expand Up @@ -97,4 +98,11 @@ void sect_CleanupSections(void);
*/
void sect_DoSanityChecks(void);

/**
* Adds a new function as "root" of the smart link graph
*/
void sect_AddSmartSection(char const *name);

void sect_PerformSmartLink(void);

#endif /* RGBDS_LINK_SECTION_H */
18 changes: 18 additions & 0 deletions include/link/symbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,24 @@ void sym_AddSymbol(struct Symbol *symbol);
*/
struct Symbol *sym_GetSymbol(char const *name);

/**
* Cleanly deletes a symbol and associated data
* @param arg The symbol to delete
*/
static inline void sym_FreeSymbol(void *arg)
{
struct Symbol *sym = arg;

free(sym->name);
free(sym);
}

/**
* Cleanly deletes a symbol and associated data
* @param name The name of the symbol to delete
*/
void sym_RemoveSymbol(char const *name);

/**
* `free`s all symbol memory that was allocated.
*/
Expand Down
11 changes: 7 additions & 4 deletions src/hashmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ bool hash_ReplaceElement(HashMap const map, char const *key, void *element)
return false;
}

bool hash_RemoveElement(HashMap map, char const *key)
void *hash_RemoveElement(HashMap map, char const *key)
{
HashType hashedKey = hash(key);
struct HashMapEntry **ptr = &map[(HalfHashType)hashedKey];
Expand All @@ -89,14 +89,15 @@ bool hash_RemoveElement(HashMap map, char const *key)
if (hashedKey >> HALF_HASH_NB_BITS == (*ptr)->hash
&& !strcmp((*ptr)->key, key)) {
struct HashMapEntry *next = (*ptr)->next;
void *elem = (*ptr)->content;

free(*ptr);
*ptr = next;
return true;
return elem;
}
ptr = &(*ptr)->next;
}
return false;
return NULL;
}

void *hash_GetElement(HashMap const map, char const *key)
Expand Down Expand Up @@ -126,14 +127,16 @@ void hash_ForEach(HashMap const map, void (*func)(void *, void *), void *arg)
}
}

void hash_EmptyMap(HashMap map)
void hash_EmptyMap(HashMap map, void (*callback)(void *))
{
for (size_t i = 0; i < HASHMAP_NB_BUCKETS; i++) {
struct HashMapEntry *ptr = map[i];

while (ptr) {
struct HashMapEntry *next = ptr->next;

if (callback)
callback(ptr->content);
free(ptr);
ptr = next;
}
Expand Down
7 changes: 4 additions & 3 deletions src/link/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ static void printUsage(void)
static void cleanup(void)
{
obj_Cleanup();
sym_CleanupSymbols();
sect_CleanupSections();
}

int main(int argc, char *argv[])
Expand Down Expand Up @@ -244,9 +246,7 @@ int main(int argc, char *argv[])
padValue = value;
break;
case 's':
/* FIXME: nobody knows what this does, figure it out */
(void)musl_optarg;
warning(NULL, 0, "Nobody has any idea what `-s` does");
sect_AddSmartSection(optarg);
break;
case 't':
is32kMode = true;
Expand Down Expand Up @@ -296,6 +296,7 @@ int main(int argc, char *argv[])

/* then process them, */
obj_DoSanityChecks();
sect_PerformSmartLink();
assign_AssignSections();
obj_CheckAssertions();
assign_Cleanup();
Expand Down
74 changes: 21 additions & 53 deletions src/link/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,39 +316,31 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
int32_t tmp;
uint8_t byte;

tryReadstr(section->name, file, "%s: Cannot read section name: %s",
fileName);
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s' size: %s",
fileName, section->name);
tryReadstr(section->name, file, "%s: Cannot read section name: %s", fileName);
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s' size: %s", fileName, section->name);
if (tmp < 0 || tmp > UINT16_MAX)
errx(1, "\"%s\"'s section size (%" PRId32 ") is invalid",
section->name, tmp);
errx(1, "\"%s\"'s section size (%" PRId32 ") is invalid", section->name, tmp);
section->size = tmp;
section->offset = 0;
tryGetc(byte, file, "%s: Cannot read \"%s\"'s type: %s",
fileName, section->name);
tryGetc(byte, file, "%s: Cannot read \"%s\"'s type: %s", fileName, section->name);
section->type = byte & 0x3F;
if (byte >> 7)
section->modifier = SECTION_UNION;
else if (byte >> 6)
section->modifier = SECTION_FRAGMENT;
else
section->modifier = SECTION_NORMAL;
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s org: %s",
fileName, section->name);
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s org: %s", fileName, section->name);
section->isAddressFixed = tmp >= 0;
if (tmp > UINT16_MAX) {
error(NULL, 0, "\"%s\"'s org is too large (%" PRId32 ")",
section->name, tmp);
error(NULL, 0, "\"%s\"'s org is too large (%" PRId32 ")", section->name, tmp);
tmp = UINT16_MAX;
}
section->org = tmp;
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s bank: %s",
fileName, section->name);
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s bank: %s", fileName, section->name);
section->isBankFixed = tmp >= 0;
section->bank = tmp;
tryGetc(byte, file, "%s: Cannot read \"%s\"'s alignment: %s",
fileName, section->name);
tryGetc(byte, file, "%s: Cannot read \"%s\"'s alignment: %s", fileName, section->name);
if (byte > 16)
byte = 16;
section->isAlignFixed = byte != 0;
Expand All @@ -367,35 +359,32 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
uint8_t *data = malloc(sizeof(*data) * section->size + 1);

if (!data)
err(1, "%s: Unable to read \"%s\"'s data", fileName,
section->name);
err(1, "%s: Unable to read \"%s\"'s data", fileName, section->name);
if (section->size) {
size_t nbElementsRead = fread(data, sizeof(*data),
section->size, file);
size_t nbElementsRead = fread(data, sizeof(*data), section->size, file);
if (nbElementsRead != section->size)
errx(1, "%s: Cannot read \"%s\"'s data: %s",
fileName, section->name,
feof(file) ? "Unexpected end of file"
: strerror(errno));
feof(file) ? "Unexpected end of file" : strerror(errno));
}
section->data = data;

tryReadlong(section->nbPatches, file,
"%s: Cannot read \"%s\"'s number of patches: %s",
fileName, section->name);

struct Patch *patches =
malloc(sizeof(*patches) * section->nbPatches + 1);
struct Patch *patches = malloc(sizeof(*patches) * section->nbPatches + 1);

if (!patches)
err(1, "%s: Unable to read \"%s\"'s patches", fileName,
section->name);
err(1, "%s: Unable to read \"%s\"'s patches", fileName, section->name);
for (uint32_t i = 0; i < section->nbPatches; i++) {
readPatch(file, &patches[i], fileName, section->name,
i, fileSections, fileNodes);
}
section->patches = patches;
}

section->smartLinked = false;
}

/**
Expand Down Expand Up @@ -614,6 +603,11 @@ void obj_DoSanityChecks(void)
sect_DoSanityChecks();
}

struct Assertion const *obj_GetFirstAssertion(void)
{
return assertions;
}

void obj_CheckAssertions(void)
{
patch_CheckAssertions(assertions);
Expand All @@ -628,27 +622,6 @@ void obj_Setup(unsigned int nbFiles)
nodes = malloc(sizeof(*nodes) * nbFiles);
}

static void freeSection(struct Section *section, void *arg)
{
(void)arg;

free(section->name);
if (sect_HasData(section->type)) {
free(section->data);
for (int32_t i = 0; i < section->nbPatches; i++)
free(section->patches[i].rpnExpression);
free(section->patches);
}
free(section->symbols);
free(section);
}

static void freeSymbol(struct Symbol *symbol)
{
free(symbol->name);
free(symbol);
}

void obj_Cleanup(void)
{
for (unsigned int i = 0; i < nbObjFiles; i++) {
Expand All @@ -660,16 +633,11 @@ void obj_Cleanup(void)
}
free(nodes);

sym_CleanupSymbols();

sect_ForEach(freeSection, NULL);
sect_CleanupSections();

struct SymbolList *list = symbolLists;

while (list) {
for (size_t i = 0; i < list->nbSymbols; i++)
freeSymbol(list->symbolList[i]);
sym_FreeSymbol(list->symbolList[i]);
free(list->symbolList);

struct SymbolList *next = list->next;
Expand Down
Loading

0 comments on commit abb9a25

Please sign in to comment.