Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement smart linking #654

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,3 @@ rgbshim.sh
CMakeCache.txt
CMakeFiles
cmake_install.cmake

test/pokecrystal
test/pokered
test/ucity
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)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);
section->isAlignFixed = byte != 0;
section->alignMask = (1 << byte) - 1;
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s alignment offset: %s",
Expand All @@ -365,35 +357,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 @@ -612,6 +601,11 @@ void obj_DoSanityChecks(void)
sect_DoSanityChecks();
}

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

void obj_CheckAssertions(void)
{
patch_CheckAssertions(assertions);
Expand All @@ -626,27 +620,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 @@ -658,16 +631,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