Skip to content

Commit 6d6da0d

Browse files
committed
Implement smart linking
1 parent 0433714 commit 6d6da0d

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_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
@@ -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_HPP

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

152152
// Short options
153-
static char const *optstring = "dl:m:Mn:O:o:p:S:tVvWwx";
153+
static char const *optstring = "dl:m:Mn:O:o:p:S:s:tVvWwx";
154154

155155
/*
156156
* Equivalent long options
@@ -172,6 +172,7 @@ static option const longopts[] = {
172172
{"output", required_argument, nullptr, 'o'},
173173
{"pad", required_argument, nullptr, 'p'},
174174
{"scramble", required_argument, nullptr, 'S'},
175+
{"smart", required_argument, nullptr, 's'},
175176
{"tiny", no_argument, nullptr, 't'},
176177
{"version", no_argument, nullptr, 'V'},
177178
{"verbose", no_argument, nullptr, 'v'},
@@ -184,7 +185,7 @@ static void printUsage() {
184185
fputs(
185186
"Usage: rgblink [-dMtVvwx] [-l script] [-m map_file] [-n sym_file]\n"
186187
" [-O overlay_file] [-o out_file] [-p pad_value]\n"
187-
" [-S spec] <file> ...\n"
188+
" [-S spec] [-s symbol] <file> ...\n"
188189
"Useful options:\n"
189190
" -l, --linkerscript <path> set the input linker script\n"
190191
" -m, --map <path> set the output map file\n"
@@ -394,6 +395,9 @@ int main(int argc, char *argv[]) {
394395
case 'S':
395396
parseScrambleSpec(musl_optarg);
396397
break;
398+
case 's':
399+
sect_AddSmartSection(musl_optarg);
400+
break;
397401
case 't':
398402
is32kMode = true;
399403
break;

0 commit comments

Comments
 (0)