Skip to content

Commit fccb25b

Browse files
committed
Implement smart linking
1 parent cf85146 commit fccb25b

35 files changed

+542
-4
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_HPP
44
#define RGBDS_LINK_PATCH_HPP
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_HPP

include/link/section.hpp

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

5960
struct Assertion {
@@ -90,4 +91,11 @@ Section *sect_GetSection(std::string const &name);
9091
*/
9192
void sect_DoSanityChecks();
9293

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

include/link/symbol.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ void sym_AddSymbol(Symbol &symbol);
4848
*/
4949
Symbol *sym_GetSymbol(std::string const &name);
5050

51+
void sym_RemoveSymbol(std::string const &name);
5152
void sym_DumpLocalAliasedSymbols(std::string const &name);
5253

5354
#endif // RGBDS_LINK_SYMBOL_HPP

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

src/link/assign.cpp

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

368368
initFreeSpace();
369369

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

src/link/main.cpp

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

132132
// Short options
133-
static char const *optstring = "dl:m:Mn:O:o:p:S:tVvWwx";
133+
static char const *optstring = "dl:m:Mn:O:o:p:S:s:tVvWwx";
134134

135135
/*
136136
* Equivalent long options
@@ -152,6 +152,7 @@ static option const longopts[] = {
152152
{"output", required_argument, nullptr, 'o'},
153153
{"pad", required_argument, nullptr, 'p'},
154154
{"scramble", required_argument, nullptr, 'S'},
155+
{"smart", required_argument, nullptr, 's'},
155156
{"tiny", no_argument, nullptr, 't'},
156157
{"version", no_argument, nullptr, 'V'},
157158
{"verbose", no_argument, nullptr, 'v'},
@@ -164,7 +165,7 @@ static void printUsage() {
164165
fputs(
165166
"Usage: rgblink [-dMtVvwx] [-l script] [-m map_file] [-n sym_file]\n"
166167
" [-O overlay_file] [-o out_file] [-p pad_value]\n"
167-
" [-S spec] <file> ...\n"
168+
" [-S spec] [-s symbol] <file> ...\n"
168169
"Useful options:\n"
169170
" -l, --linkerscript <path> set the input linker script\n"
170171
" -m, --map <path> set the output map file\n"
@@ -374,6 +375,9 @@ int main(int argc, char *argv[]) {
374375
case 'S':
375376
parseScrambleSpec(musl_optarg);
376377
break;
378+
case 's':
379+
sect_AddSmartSection(musl_optarg);
380+
break;
377381
case 't':
378382
is32kMode = true;
379383
break;

0 commit comments

Comments
 (0)