Skip to content

Commit abb9a25

Browse files
ISSOtmdaid
authored andcommitted
Re-implement smart linking
Long-broken feature, fell into disrepair, got removed... Now it's back! Though, it needs testing. Fixes gbdev#82
1 parent 8864609 commit abb9a25

File tree

12 files changed

+444
-70
lines changed

12 files changed

+444
-70
lines changed

include/hashmap.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ bool hash_ReplaceElement(HashMap const map, char const *key, void *element);
4747
* Removes an element from a hashmap.
4848
* @param map The HashMap to remove the element from
4949
* @param key The key to search the element with
50-
* @return True if the element was found and removed
50+
* @return The element removed, or NULL if none was found
5151
*/
52-
bool hash_RemoveElement(HashMap map, char const *key);
52+
void *hash_RemoveElement(HashMap map, char const *key);
5353

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

7979
#endif /* RGBDS_LINK_HASHMAP_H */

include/link/object.h

+5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ void obj_ReadFile(char const *fileName, unsigned int i);
2323
*/
2424
void obj_DoSanityChecks(void);
2525

26+
/**
27+
* @return The first assertion in the linked list of all assertions
28+
*/
29+
struct Assertion const *obj_GetFirstAssertion(void);
30+
2631
/**
2732
* Evaluate all assertions
2833
*/

include/link/patch.h

+19
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
#include "linkdefs.h"
1919

20+
struct Symbol;
21+
2022
struct Assertion {
2123
struct Patch patch;
2224
// enum AssertionType type; The `patch`'s field is instead re-used
@@ -32,6 +34,7 @@ struct Assertion {
3234

3335
/**
3436
* Checks all assertions
37+
* @param assertion The first assertion to check (in a linked list)
3538
* @return true if assertion failed
3639
*/
3740
void patch_CheckAssertions(struct Assertion *assertion);
@@ -41,4 +44,20 @@ void patch_CheckAssertions(struct Assertion *assertion);
4144
*/
4245
void patch_ApplyPatches(void);
4346

47+
/**
48+
* Executes a callback on all sections referenced by a patch's expression
49+
* @param patch The patch to scan the expression of
50+
*/
51+
void patch_FindRefdSections(struct Patch const *patch, void (*callback)(struct Section *),
52+
struct Symbol const * const *fileSymbols);
53+
54+
/**
55+
* Properly deletes a patch object
56+
* @param patch The patch to be deleted
57+
*/
58+
static inline void patch_DeletePatch(struct Patch *patch)
59+
{
60+
free(patch->rpnExpression);
61+
}
62+
4463
#endif /* RGBDS_LINK_PATCH_H */

include/link/section.h

+8
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ struct Section {
6262
uint32_t nbSymbols;
6363
struct Symbol const **symbols;
6464
struct Section *nextu; /* The next "component" of this unionized sect */
65+
bool smartLinked; // Set to true if kept by smart linking
6566
};
6667

6768
/*
@@ -97,4 +98,11 @@ void sect_CleanupSections(void);
9798
*/
9899
void sect_DoSanityChecks(void);
99100

101+
/**
102+
* Adds a new function as "root" of the smart link graph
103+
*/
104+
void sect_AddSmartSection(char const *name);
105+
106+
void sect_PerformSmartLink(void);
107+
100108
#endif /* RGBDS_LINK_SECTION_H */

include/link/symbol.h

+18
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,24 @@ void sym_AddSymbol(struct Symbol *symbol);
5353
*/
5454
struct Symbol *sym_GetSymbol(char const *name);
5555

56+
/**
57+
* Cleanly deletes a symbol and associated data
58+
* @param arg The symbol to delete
59+
*/
60+
static inline void sym_FreeSymbol(void *arg)
61+
{
62+
struct Symbol *sym = arg;
63+
64+
free(sym->name);
65+
free(sym);
66+
}
67+
68+
/**
69+
* Cleanly deletes a symbol and associated data
70+
* @param name The name of the symbol to delete
71+
*/
72+
void sym_RemoveSymbol(char const *name);
73+
5674
/**
5775
* `free`s all symbol memory that was allocated.
5876
*/

src/hashmap.c

+7-4
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ bool hash_ReplaceElement(HashMap const map, char const *key, void *element)
8080
return false;
8181
}
8282

83-
bool hash_RemoveElement(HashMap map, char const *key)
83+
void *hash_RemoveElement(HashMap map, char const *key)
8484
{
8585
HashType hashedKey = hash(key);
8686
struct HashMapEntry **ptr = &map[(HalfHashType)hashedKey];
@@ -89,14 +89,15 @@ bool hash_RemoveElement(HashMap map, char const *key)
8989
if (hashedKey >> HALF_HASH_NB_BITS == (*ptr)->hash
9090
&& !strcmp((*ptr)->key, key)) {
9191
struct HashMapEntry *next = (*ptr)->next;
92+
void *elem = (*ptr)->content;
9293

9394
free(*ptr);
9495
*ptr = next;
95-
return true;
96+
return elem;
9697
}
9798
ptr = &(*ptr)->next;
9899
}
99-
return false;
100+
return NULL;
100101
}
101102

102103
void *hash_GetElement(HashMap const map, char const *key)
@@ -126,14 +127,16 @@ void hash_ForEach(HashMap const map, void (*func)(void *, void *), void *arg)
126127
}
127128
}
128129

129-
void hash_EmptyMap(HashMap map)
130+
void hash_EmptyMap(HashMap map, void (*callback)(void *))
130131
{
131132
for (size_t i = 0; i < HASHMAP_NB_BUCKETS; i++) {
132133
struct HashMapEntry *ptr = map[i];
133134

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

138+
if (callback)
139+
callback(ptr->content);
137140
free(ptr);
138141
ptr = next;
139142
}

src/link/main.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ static void printUsage(void)
200200
static void cleanup(void)
201201
{
202202
obj_Cleanup();
203+
sym_CleanupSymbols();
204+
sect_CleanupSections();
203205
}
204206

205207
int main(int argc, char *argv[])
@@ -244,9 +246,7 @@ int main(int argc, char *argv[])
244246
padValue = value;
245247
break;
246248
case 's':
247-
/* FIXME: nobody knows what this does, figure it out */
248-
(void)musl_optarg;
249-
warning(NULL, 0, "Nobody has any idea what `-s` does");
249+
sect_AddSmartSection(optarg);
250250
break;
251251
case 't':
252252
is32kMode = true;
@@ -296,6 +296,7 @@ int main(int argc, char *argv[])
296296

297297
/* then process them, */
298298
obj_DoSanityChecks();
299+
sect_PerformSmartLink();
299300
assign_AssignSections();
300301
obj_CheckAssertions();
301302
assign_Cleanup();

src/link/object.c

+21-53
Original file line numberDiff line numberDiff line change
@@ -316,39 +316,31 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
316316
int32_t tmp;
317317
uint8_t byte;
318318

319-
tryReadstr(section->name, file, "%s: Cannot read section name: %s",
320-
fileName);
321-
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s' size: %s",
322-
fileName, section->name);
319+
tryReadstr(section->name, file, "%s: Cannot read section name: %s", fileName);
320+
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s' size: %s", fileName, section->name);
323321
if (tmp < 0 || tmp > UINT16_MAX)
324-
errx(1, "\"%s\"'s section size (%" PRId32 ") is invalid",
325-
section->name, tmp);
322+
errx(1, "\"%s\"'s section size (%" PRId32 ") is invalid", section->name, tmp);
326323
section->size = tmp;
327324
section->offset = 0;
328-
tryGetc(byte, file, "%s: Cannot read \"%s\"'s type: %s",
329-
fileName, section->name);
325+
tryGetc(byte, file, "%s: Cannot read \"%s\"'s type: %s", fileName, section->name);
330326
section->type = byte & 0x3F;
331327
if (byte >> 7)
332328
section->modifier = SECTION_UNION;
333329
else if (byte >> 6)
334330
section->modifier = SECTION_FRAGMENT;
335331
else
336332
section->modifier = SECTION_NORMAL;
337-
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s org: %s",
338-
fileName, section->name);
333+
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s org: %s", fileName, section->name);
339334
section->isAddressFixed = tmp >= 0;
340335
if (tmp > UINT16_MAX) {
341-
error(NULL, 0, "\"%s\"'s org is too large (%" PRId32 ")",
342-
section->name, tmp);
336+
error(NULL, 0, "\"%s\"'s org is too large (%" PRId32 ")", section->name, tmp);
343337
tmp = UINT16_MAX;
344338
}
345339
section->org = tmp;
346-
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s bank: %s",
347-
fileName, section->name);
340+
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s bank: %s", fileName, section->name);
348341
section->isBankFixed = tmp >= 0;
349342
section->bank = tmp;
350-
tryGetc(byte, file, "%s: Cannot read \"%s\"'s alignment: %s",
351-
fileName, section->name);
343+
tryGetc(byte, file, "%s: Cannot read \"%s\"'s alignment: %s", fileName, section->name);
352344
if (byte > 16)
353345
byte = 16;
354346
section->isAlignFixed = byte != 0;
@@ -367,35 +359,32 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
367359
uint8_t *data = malloc(sizeof(*data) * section->size + 1);
368360

369361
if (!data)
370-
err(1, "%s: Unable to read \"%s\"'s data", fileName,
371-
section->name);
362+
err(1, "%s: Unable to read \"%s\"'s data", fileName, section->name);
372363
if (section->size) {
373-
size_t nbElementsRead = fread(data, sizeof(*data),
374-
section->size, file);
364+
size_t nbElementsRead = fread(data, sizeof(*data), section->size, file);
375365
if (nbElementsRead != section->size)
376366
errx(1, "%s: Cannot read \"%s\"'s data: %s",
377367
fileName, section->name,
378-
feof(file) ? "Unexpected end of file"
379-
: strerror(errno));
368+
feof(file) ? "Unexpected end of file" : strerror(errno));
380369
}
381370
section->data = data;
382371

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

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

390378
if (!patches)
391-
err(1, "%s: Unable to read \"%s\"'s patches", fileName,
392-
section->name);
379+
err(1, "%s: Unable to read \"%s\"'s patches", fileName, section->name);
393380
for (uint32_t i = 0; i < section->nbPatches; i++) {
394381
readPatch(file, &patches[i], fileName, section->name,
395382
i, fileSections, fileNodes);
396383
}
397384
section->patches = patches;
398385
}
386+
387+
section->smartLinked = false;
399388
}
400389

401390
/**
@@ -614,6 +603,11 @@ void obj_DoSanityChecks(void)
614603
sect_DoSanityChecks();
615604
}
616605

606+
struct Assertion const *obj_GetFirstAssertion(void)
607+
{
608+
return assertions;
609+
}
610+
617611
void obj_CheckAssertions(void)
618612
{
619613
patch_CheckAssertions(assertions);
@@ -628,27 +622,6 @@ void obj_Setup(unsigned int nbFiles)
628622
nodes = malloc(sizeof(*nodes) * nbFiles);
629623
}
630624

631-
static void freeSection(struct Section *section, void *arg)
632-
{
633-
(void)arg;
634-
635-
free(section->name);
636-
if (sect_HasData(section->type)) {
637-
free(section->data);
638-
for (int32_t i = 0; i < section->nbPatches; i++)
639-
free(section->patches[i].rpnExpression);
640-
free(section->patches);
641-
}
642-
free(section->symbols);
643-
free(section);
644-
}
645-
646-
static void freeSymbol(struct Symbol *symbol)
647-
{
648-
free(symbol->name);
649-
free(symbol);
650-
}
651-
652625
void obj_Cleanup(void)
653626
{
654627
for (unsigned int i = 0; i < nbObjFiles; i++) {
@@ -660,16 +633,11 @@ void obj_Cleanup(void)
660633
}
661634
free(nodes);
662635

663-
sym_CleanupSymbols();
664-
665-
sect_ForEach(freeSection, NULL);
666-
sect_CleanupSections();
667-
668636
struct SymbolList *list = symbolLists;
669637

670638
while (list) {
671639
for (size_t i = 0; i < list->nbSymbols; i++)
672-
freeSymbol(list->symbolList[i]);
640+
sym_FreeSymbol(list->symbolList[i]);
673641
free(list->symbolList);
674642

675643
struct SymbolList *next = list->next;

0 commit comments

Comments
 (0)