NSMBW-Decomp
A decompilation of New Super Mario Bros. Wii
Loading...
Searching...
No Matches
c_dylink.cpp
1#include <cstdio>
2#include <game/cLib/c_dylink.hpp>
3#include <runtime/rel.h>
4
7
9 if (mpPrev != nullptr) {
10 mpPrev->mpNext = mpNext;
11 }
12 if (mpNext != nullptr) {
13 mpNext->mpPrev = mpPrev;
14 }
15 if (mFirst == this) {
16 mFirst = mpNext;
17 }
18 if (mLast == this) {
19 mLast = mpPrev;
20 }
21 mpNext = nullptr;
22 mpPrev = nullptr;
23}
24
26 if (mFirst == nullptr) {
27 mFirst = this;
28 }
29 mpPrev = mLast;
30 if (mpPrev != nullptr) {
31 mpPrev->mpNext = this;
32 }
33 mLast = this;
34}
35
37 if (mUsageCount == 0) {
38 // Only load and link if this module isn't already loaded
39 do_load();
40 if (!do_link()) {
41 return false;
42 }
43 if (mLinkCount < 0xffff) {
44 mLinkCount++;
45 }
46 }
47 if (mUsageCount < 0xffff) {
49 }
50 return true;
51}
52
53// [Deadstripped, but was presumably here because of the weak virtuals]
56 if (mUsageCount == 0) {
57 do_unlink();
58 mLinkCount--;
59 do_unload();
60 }
61 return true;
62}
63
65 if (mUsageCount == 0) {
66 return do_load_async();
67 }
68 return true;
69}
70
72
74 return 0;
75}
76
77const char *DynamicModuleControl::sModulesDir = "/rels";
78
81mDvd_toMainRam_c *sDvdCommand;
85
87 mpModule(nullptr),
88 mpBss(nullptr),
90 mModuleName(name),
92 mLoadCount(0),
93 mChecksum(0),
94 mModuleSize(0),
95 mpDvdCallback(nullptr),
96 mpHeap(heap),
98}
99
101
103 return mModuleName;
104}
105
106void DynamicModuleControl::initialize(EGG::ExpHeap *heap) {
107 sDylinkHeap = heap;
108
109 sDvdFile = (EGG::DvdFile *) heap->alloc(sizeof(EGG::DvdFile), 4);
110 new(sDvdFile) EGG::DvdFile();
111 sAllocBytes = sizeof(EGG::DvdFile);
112
113 sHeapMinAllocatableSize = heap->getAllocatableSize(4);
114 sHeapMinTotalFreeSize = heap->getTotalFreeSize();
115}
116
119 return (void *) dmc->do_load();
120}
121
123 if (mpHeap != sDylinkHeap) {
124 return;
125 }
126 size_t allocatableSize = mpHeap->getAllocatableSize(4);
127 if (sHeapMinAllocatableSize > allocatableSize) {
128 sHeapMinAllocatableSize = allocatableSize;
129 }
130 size_t totalFreeSize = mpHeap->getTotalFreeSize();
131 if (sHeapMinTotalFreeSize > totalFreeSize) {
132 sHeapMinTotalFreeSize = totalFreeSize;
133 }
134}
135
136u16 calcSum2(const u16 *data, size_t count) {
137 u16 sum = 0;
138 while (count > 0) {
139 sum += *data;
140 count -= 2;
141 data++;
142 }
143 return sum;
144}
145
147 // Check if already loaded
148 if (mpModule != nullptr) {
149 return true;
150 }
151
152 int attempts = 0;
153 if (mpHeap == nullptr) {
155 }
156
157 // On retry, free memory from the previous attempt
158retry_load:
159 if (mpModule != nullptr) {
160 mpHeap->free(mpModule);
161 mpModule = nullptr;
162 }
163
164 char buf[0x40];
165 snprintf(buf, ARRAY_SIZE(buf), "%s/%sNP.rel", sModulesDir, mModuleName);
166 if (mpModule == nullptr) {
167 sDvdCommand = mDvd_toMainRam_c::create(buf, 1, mpHeap);
168 if (sDvdCommand != nullptr) {
169 sDvdCommand->waitDone();
171 OSModuleHeader *module = (OSModuleHeader *) sDvdCommand->mpData;
172 sDvdCommand->mpData = nullptr;
173 mpModule = module;
174 sDvdCommand->destroy();
175 sDvdCommand = nullptr;
176
177 if (mpModule != nullptr) {
178 mModuleSize = 0;
180 }
181 }
182 }
183 if (mpModule == nullptr) {
184 return false;
185 }
186
187 // [The following seems to be a leftover debug check to ensure the data was correctly read]
188 if (mModuleSize > 0) {
189 u16 actualChecksum = calcSum2((u16 *) mpModule, mModuleSize);
190
191 // On first load, load the file again to verify
192 if (mLoadCount == 0) {
193 mChecksum = actualChecksum;
194 mLoadCount++;
195 goto retry_load;
196 }
197
198 // If the checksum fails, try to read the data 2 more times before quitting
199 if (actualChecksum != mChecksum) {
200 mLoadCount = 0;
201 if (attempts < 2) {
202 attempts++;
203 goto retry_load;
204 }
205 return false;
206 }
207 if (mLoadCount < 255) {
208 mLoadCount++;
209 }
210 } else {
211 if (mLoadCount < 255) {
212 mLoadCount++;
213 }
214 }
215
217 return true;
218}
219
221 if (mpDvdCallback == nullptr) {
222 if (mpModule != nullptr) {
223 return true;
224 }
225 mpDvdCallback = mDvd_callback_c::create(callback, this);
226 }
227
228 if (mpDvdCallback != nullptr && mpDvdCallback->mDone) {
229 mpDvdCallback->destroy();
230 mpDvdCallback = nullptr;
231 return true;
232 }
233
234 return false;
235}
236
238 if (mpModule != nullptr) {
239 mpHeap->free(mpModule);
240 mpModule = nullptr;
241 }
242 return true;
243}
244
246
248 size_t fixSize;
249 void *bssStart;
250 size_t blockSize;
251 if (mpModule == nullptr) {
252 goto fail;
253 }
254
255 fixSize = ROUND_UP(mpModule->fixSize, 0x20);
256 bssStart = (void *) ((u32) mpModule + fixSize);
257 blockSize = EGG::ExpHeap::getSizeForMBlock(mpModule);
258 if (blockSize == 0) {
259 void *bss = mpHeap->alloc(mpModule->bssSize, 0x20);
260 if (bss == nullptr) {
261 goto fail;
262 }
263 mpBss = bss;
264 if (!OSLink(&mpModule->info, bss)) {
265 goto fail;
266 }
267 } else if (fixSize + mpModule->bssSize < blockSize) {
268 if (!OSLinkFixed(&mpModule->info, bssStart)) {
269 goto fail;
270 }
271 mpHeap->resizeForMBlock(mpModule, fixSize + mpModule->bssSize);
272 } else if (mpHeap->resizeForMBlock(mpModule, fixSize + mpModule->bssSize) > 0) {
273 if (!OSLinkFixed(&mpModule->info, bssStart)) {
274 goto fail;
275 }
276 } else {
277 void *bss = mpHeap->alloc(mpModule->bssSize, 0x20);
278 if (bss == nullptr) {
279 goto fail;
280 }
281 mpBss = bss;
282 if (!OSLinkFixed(&mpModule->info, mpBss)) {
283 goto fail;
284 }
285 mpHeap->resizeForMBlock(mpModule, fixSize);
286 }
288
289 // Load map file
290 char mapFileBuf[0x40];
291 snprintf(mapFileBuf, ARRAY_SIZE(mapFileBuf), "%s/%sNP.map", "/maps", mModuleName);
292 mDebugMapFile.RegisterOnDvd(mapFileBuf, &mpModule->info);
293
294 // Run prolog
295 mPrologReturn = ((u32FctPtr) mpModule->prolog)();
296
298 return true;
299
300fail:
301 mLoadCount = 0;
302 if (mpBss != nullptr) {
303 mpHeap->free(mpBss);
304 mpBss = nullptr;
305 }
306 if (mpModule != nullptr) {
307 mpHeap->free(mpModule);
308 mpModule = nullptr;
309 }
310 return false;
311}
312
314 ((voidFctPtr) mpModule->epilog)();
315
316 mDebugMapFile.Unregister();
317 if (!OSUnlink(&mpModule->info)) {
318 return false;
319 }
320
322 if (mpBss != nullptr) {
323 mpHeap->free(mpBss);
324 mpBss = nullptr;
325 }
326 return true;
327}
328
330 if (mpModule != nullptr) {
331 size_t size = EGG::ExpHeap::getSizeForMBlock(mpModule);
332 if (mpBss) {
333 size += mpModule->bssSize;
334 }
335 return size;
336 }
337 return 0;
338}
339
341 static const char *c_ModuleTypeStrings[] = { "????", "MEM", "ARAM", "DVD" };
342 return c_ModuleTypeStrings[mType & 0b11];
343}
344
346 if (mpMapFile != nullptr) {
347 Unregister();
348 }
349}
350
351void DbMapFile::RegisterOnDvd(const char *path, const OSModuleInfo *moduleInfo) {
352 mpMapFile = nw4r::db::MapFile_RegistOnDvd(&mBuf, path, moduleInfo);
353}
354
356 nw4r::db::MapFile_Unregist(mpMapFile);
357 mpMapFile = nullptr;
358}
359
360extern "C" {
361
362void ModuleUnresolved() {}
363
364void ModuleConstructorsX(voidFctPtr *ctors) {
365 while (*ctors != nullptr) {
366 (*ctors)();
367 ctors++;
368 }
369}
370
371void ModuleDestructorsX(voidFctPtr *dtors) {
372 while (*dtors != nullptr) {
373 (*dtors)();
374 dtors++;
375 }
376}
377
378} // extern "C"
u8 mBuf[sizeof(nw4r::db::MapFile)]
The raw storage for the MapFile instance.
Definition c_dylink.hpp:31
void RegisterOnDvd(const char *path, const OSModuleInfo *moduleInfo)
Loads and registers a map file from disc.
Definition c_dylink.cpp:351
~DbMapFile()
Destroys the map file.
Definition c_dylink.cpp:345
nw4r::db::MapFile * mpMapFile
A pointer to the internal MapFile instance.
Definition c_dylink.hpp:30
void Unregister()
Unregisters the map file.
Definition c_dylink.cpp:355
Base class for managing a relocatable module.
Definition c_dylink.hpp:46
static DynamicModuleControlBase * mLast
The last module in the linked list.
Definition c_dylink.hpp:107
virtual void dump()
Outputs debug information about the module.
Definition c_dylink.cpp:71
DynamicModuleControlBase()
Constructs a new DynamicModuleControlBase and adds it to the linked list.
Definition c_dylink.cpp:25
virtual bool do_unload()
Module-specific implementation for unloading the module from memory.
Definition c_dylink.hpp:82
bool unlink()
Unlinks and unloads the module if needed.
Definition c_dylink.cpp:54
virtual ~DynamicModuleControlBase()
Destroys the DynamicModuleControlBase and removes it from the linked list.
Definition c_dylink.cpp:8
virtual bool do_unlink()
Module-specific implementation for unlinking the module.
Definition c_dylink.hpp:90
bool link()
Loads and links the module if needed.
Definition c_dylink.cpp:36
DynamicModuleControlBase * mpPrev
The previous module in the linked list.
Definition c_dylink.hpp:50
virtual bool do_load()
Module-specific implementation for loading the module into memory.
Definition c_dylink.hpp:74
virtual bool do_link()
Module-specific implementation for linking the module, making it ready for use.
Definition c_dylink.hpp:86
static DynamicModuleControlBase * mFirst
The first module in the linked list.
Definition c_dylink.hpp:106
bool load_async()
Loads the module asynchronously if needed.
Definition c_dylink.cpp:64
virtual bool do_load_async()
Module-specific implementation for loading the module into memory asynchronously.
Definition c_dylink.hpp:78
DynamicModuleControlBase * mpNext
The next module in the linked list.
Definition c_dylink.hpp:51
u16 mLinkCount
The number of times this module has been successfully linked.
Definition c_dylink.hpp:49
virtual size_t getModuleSize() const
Gets the module size in bytes.
Definition c_dylink.cpp:73
u16 mUsageCount
The number of active users of this module. When this reaches zero, the module may be unloaded.
Definition c_dylink.hpp:48
virtual bool do_link() override
Module-specific implementation for linking the module, making it ready for use.
Definition c_dylink.cpp:247
static EGG::DvdFile * sDvdFile
The DVD file handle used for loading the string table file.
Definition c_dylink.hpp:168
static const char * sModulesDir
The directory on the disk where the modules are located.
Definition c_dylink.hpp:172
@ MODULE_TYPE_UNKNOWN
The module type has not yet been determined.
Definition c_dylink.hpp:117
@ MODULE_TYPE_DVD
The module is loaded from the disc.
Definition c_dylink.hpp:120
u32 mPrologReturn
The return value of the module's prolog function.
Definition c_dylink.hpp:157
virtual ~DynamicModuleControl()
Destroys the DynamicModuleControl.
Definition c_dylink.cpp:100
virtual size_t getModuleSize() const override
Gets the module size in bytes.
Definition c_dylink.cpp:329
static size_t sAllocBytes
The total number of bytes allocated across all active modules.
Definition c_dylink.hpp:169
void * mpBss
The BSS section of the module.
Definition c_dylink.hpp:156
static void initialize(EGG::ExpHeap *heap)
Initializes the global dynamic linking system.
Definition c_dylink.cpp:106
virtual const char * getModuleTypeString() const override
Gets a human-readable module type string.
Definition c_dylink.cpp:340
EGG::ExpHeap * mpHeap
The heap used for module loading and BSS allocation.
Definition c_dylink.hpp:164
virtual bool do_load() override
Module-specific implementation for loading the module into memory.
Definition c_dylink.cpp:146
OSModuleHeader * mpModule
The data of the module, including the header.
Definition c_dylink.hpp:155
virtual const char * getModuleName() const override
Gets the module name.
Definition c_dylink.cpp:102
DbMapFile mDebugMapFile
The debug map file for this module.
Definition c_dylink.hpp:165
DynamicModuleControl(const char *name, EGG::ExpHeap *heap)
Constructs a new DynamicModuleControl.
Definition c_dylink.cpp:86
virtual bool do_load_async() override
Module-specific implementation for loading the module into memory asynchronously.
Definition c_dylink.cpp:220
mDvd_callback_c * mpDvdCallback
The DVD command used to load the module asynchronously.
Definition c_dylink.hpp:163
u16 mChecksum
The checksum of the module.
Definition c_dylink.hpp:161
int mModuleSize
The module size, in bytes.
Definition c_dylink.hpp:162
static EGG::ExpHeap * sDylinkHeap
The heap used for dynamic module loading and BSS allocation.
Definition c_dylink.hpp:167
static size_t sHeapMinAllocatableSize
The lowest observed allocatable space in sDylinkHeap during module loading.
Definition c_dylink.hpp:170
virtual bool do_unlink() override
Module-specific implementation for unlinking the module.
Definition c_dylink.cpp:313
virtual void dump() override
Outputs debug information about the module.
Definition c_dylink.cpp:245
void checkHeapStatus()
Updates the module linking heap statistics.
Definition c_dylink.cpp:122
u8 mLoadCount
The number of times this module has been loaded.
Definition c_dylink.hpp:160
static size_t sHeapMinTotalFreeSize
The lowest observed free space in sDylinkHeap during module loading.
Definition c_dylink.hpp:171
virtual bool do_unload() override
Module-specific implementation for unloading the module from memory.
Definition c_dylink.cpp:237
static void * callback(void *self)
Internal callback used for asynchronous loading operations.
Definition c_dylink.cpp:117
u8 mType
The module type. See ModuleType_e.
Definition c_dylink.hpp:159
const char * mModuleName
The module name.
Definition c_dylink.hpp:158