Skip to content

Commit 656b87d

Browse files
committed
Implement smart linking
1 parent 9dac583 commit 656b87d

35 files changed

+539
-5
lines changed

contrib/bash_compl/_rgblink.bash

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ _rgblink_completions() {
2020
[O]="overlay:glob-*.gb *.gbc *.sgb"
2121
[o]="output:glob-*.gb *.gbc *.sgb"
2222
[p]="pad:unk"
23+
[s]="smart:unk"
2324
)
2425
# Parse command-line up to current word
2526
local opt_ena=true

contrib/zsh_compl/_rgblink

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ local args=(
1818
'(-o --output)'{-o,--output}"+[Write ROM image to this file]:rom file:_files -g '*.{gb,sgb,gbc}'"
1919
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:'
2020
'(-S --scramble)'{-s,--scramble}'+[Activate scrambling]:scramble spec'
21+
'(-s --smart)'{-s,--smart}'+[Perform smart linking from this section]:section name:'
2122

2223
'*'":object files:_files -g '*.o'"
2324
)

include/link/patch.hpp

+14
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
#ifndef RGBDS_LINK_PATCH_H
44
#define RGBDS_LINK_PATCH_H
55

6+
#include <vector>
7+
8+
struct Patch;
9+
struct Section;
10+
struct Symbol;
11+
612
/*
713
* Checks all assertions
814
* @return true if assertion failed
@@ -14,4 +20,12 @@ void patch_CheckAssertions();
1420
*/
1521
void patch_ApplyPatches();
1622

23+
/**
24+
* Executes a callback on all sections referenced by a patch's expression
25+
* @param patch The patch to scan the expression of
26+
*/
27+
void patch_FindReferencedSections(
28+
Patch const &patch, void (*callback)(Section &), std::vector<Symbol> const &fileSymbols
29+
);
30+
1731
#endif // RGBDS_LINK_PATCH_H

include/link/section.hpp

+8
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ struct Section {
5252
std::vector<Symbol> *fileSymbols;
5353
std::vector<Symbol *> symbols;
5454
std::unique_ptr<Section> nextu; // The next "component" of this unionized sect
55+
bool smartLinked = false; // Set to true if kept by smart linking
5556
};
5657

5758
struct Assertion {
@@ -88,4 +89,11 @@ Section *sect_GetSection(std::string const &name);
8889
*/
8990
void sect_DoSanityChecks();
9091

92+
/**
93+
* Adds a section as a new "root" of the smart link graph
94+
*/
95+
void sect_AddSmartSection(std::string const &name);
96+
97+
void sect_PerformSmartLink();
98+
9199
#endif // RGBDS_LINK_SECTION_H

include/link/symbol.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,6 @@ void sym_AddSymbol(Symbol &symbol);
4747
*/
4848
Symbol *sym_GetSymbol(std::string const &name);
4949

50+
void sym_RemoveSymbol(std::string const &name);
51+
5052
#endif // RGBDS_LINK_SYMBOL_H

man/rgblink.1

+108
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
.Op Fl o Ar out_file
1717
.Op Fl p Ar pad_value
1818
.Op Fl S Ar spec
19+
.Op Fl s Ar symbol
1920
.Ar
2021
.Sh DESCRIPTION
2122
The
@@ -105,6 +106,16 @@ See
105106
.Sx Scrambling algorithm
106107
below for an explanation and a description of
107108
.Ar spec .
109+
.It Fl s Ar sect_name , Fl Fl smart Ar sect_name
110+
This option specifies the name of a section that will be used as a starting point for smart linking; it may appear several times per
111+
.Nm
112+
invocation.
113+
See
114+
.Sx SMART LINKING
115+
below.
116+
If no section with that name is found,
117+
.Nm
118+
will error out.
108119
.It Fl t , Fl \-tiny
109120
Expand the ROM0 section size from 16 KiB to the full 32 KiB assigned to ROM.
110121
ROMX sections that are fixed to a bank other than 1 become errors, other ROMX sections are treated as ROM0.
@@ -192,6 +203,103 @@ to fix these so that the program will actually run in a Game Boy:
192203
Here is a more complete example:
193204
.Pp
194205
.Dl $ rgblink -o bin/game.gb -n bin/game.sym -p 0xFF obj/title.o obj/engine.o
206+
.Sh SMART LINKING
207+
Smart linking is a feature of
208+
.Nm
209+
that allows "trimming the fat" off of a ROM.
210+
It is enabled only if at least one
211+
.Fl s
212+
option is given on the command line.
213+
.Pp
214+
The smart linking process begins by finding all the
215+
.Ql referenced
216+
sections.
217+
A section is referenced if its name is specified using a
218+
.Fl s
219+
option, or if it is referred to by a referenced section.
220+
This definition applies recursively, so if section
221+
.Ql A
222+
is specified using
223+
.Fl s Va A ,
224+
section
225+
.Ql A
226+
references section
227+
.Ql B ,
228+
and section
229+
.Ql B
230+
references section
231+
.Ql C ,
232+
then all three sections
233+
.Ql A ,
234+
.Ql B ,
235+
and
236+
.Ql C
237+
are referenced.
238+
.Pp
239+
Sections refer to each other through expressions. For example:
240+
.Bd -literal -offset indent
241+
SECTION "A", ROM0
242+
db Someplace
243+
db BANK("C")
244+
SECTION "B", ROM0
245+
Someplace:
246+
SECTION "C", ROMX
247+
db 42
248+
.Ed
249+
Here, section
250+
.Ql A
251+
references section
252+
.Ql B
253+
via the label
254+
.Ql Someplace ,
255+
and references section
256+
.Ql C
257+
via its name in
258+
.Ql BANK("C") .
259+
.Pp
260+
After all the referenced sections are found, all sections that were not referenced are deleted, and the linking process continues as normal.
261+
.Sy This should not cause any symbols not to be found, please report a bug (see Sx BUGS Ns Sy ) if this occurs.
262+
.Pp
263+
This is useful to detect
264+
.Dq unused
265+
sections, i.e. sections that contain data not used by anything.
266+
Typically, the section containing the header, including the entry point at
267+
.Ad $00:0100
268+
will be one of the starting sections; more exotic use cases may require more starting sections.
269+
It may be a good idea to start with the header as the only root, and if needed, add more root sections.
270+
.Pp
271+
Be careful, as numeric expressions do
272+
.Sy not
273+
cause references:
274+
.Bd -literal -offset indent
275+
DEF BASE_ADDR EQU $4000
276+
SECTION "A", ROM0
277+
dw BASE_ADDR
278+
SECTION "B", ROMX[BASE_ADDR]
279+
db 42
280+
.Ed
281+
Section
282+
.Ql A
283+
does
284+
.Sy not
285+
reference section
286+
.Ql B ,
287+
since
288+
.Va BASE_ADDR
289+
is a constant, and thus does not belong to section
290+
.Ql B .
291+
.Pp
292+
Finally, be careful that
293+
.Xr rgbasm 1
294+
tries to fill in data by itself to speed up
295+
.Nm Ap s
296+
work, which may cause
297+
.Nm
298+
not to see references to sections whose bank and/or address are fixed.
299+
It may be advisable to avoid fixing those (notably, to enable
300+
.Nm
301+
to improve section placement), but they can still be manually referenced using
302+
.Fl s .
195303
.Sh BUGS
196304
Please report bugs on
197305
.Lk https://github.com/gbdev/rgbds/issues GitHub .

src/link/assign.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,9 @@ void assign_AssignSections() {
366366

367367
initFreeSpace();
368368

369+
// Check if we need to do smart linking and discard any sections
370+
sect_PerformSmartLink();
371+
369372
// Generate linked lists of sections to assign
370373
nbSectionsToAssign = 0;
371374
sect_ForEach(categorizeSection);

src/link/main.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ void argErr(char flag, char const *fmt, ...) {
149149
}
150150

151151
// Short options
152-
static char const *optstring = "dl:m:Mn:O:o:p:S:tVvWwx";
152+
static char const *optstring = "dl:m:Mn:O:o:p:S:s:tVvWwx";
153153

154154
/*
155155
* Equivalent long options
@@ -171,6 +171,7 @@ static option const longopts[] = {
171171
{"output", required_argument, nullptr, 'o'},
172172
{"pad", required_argument, nullptr, 'p'},
173173
{"scramble", required_argument, nullptr, 'S'},
174+
{"smart", required_argument, nullptr, 's'},
174175
{"tiny", no_argument, nullptr, 't'},
175176
{"version", no_argument, nullptr, 'V'},
176177
{"verbose", no_argument, nullptr, 'v'},
@@ -183,7 +184,7 @@ static void printUsage() {
183184
fputs(
184185
"Usage: rgblink [-dMtVvwx] [-l script] [-m map_file] [-n sym_file]\n"
185186
" [-O overlay_file] [-o out_file] [-p pad_value]\n"
186-
" [-S spec] <file> ...\n"
187+
" [-S spec] [-s symbol] <file> ...\n"
187188
"Useful options:\n"
188189
" -l, --linkerscript <path> set the input linker script\n"
189190
" -m, --map <path> set the output map file\n"
@@ -392,6 +393,9 @@ int main(int argc, char *argv[]) {
392393
case 'S':
393394
parseScrambleSpec(musl_optarg);
394395
break;
396+
case 's':
397+
sect_AddSmartSection(musl_optarg);
398+
break;
395399
case 't':
396400
is32kMode = true;
397401
break;

0 commit comments

Comments
 (0)