Skip to content

Commit b0771cb

Browse files
committed
Implement smart linking
1 parent 817dcfd commit b0771cb

35 files changed

+541
-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
@@ -49,4 +49,6 @@ void sym_AddSymbol(Symbol &symbol);
4949
*/
5050
Symbol *sym_GetSymbol(std::string const &name);
5151

52+
void sym_RemoveSymbol(std::string const &name);
53+
5254
#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
@@ -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)