Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Rubberduckycooly
GitHub Repository: Rubberduckycooly/RSDKv5-Decompilation
Path: blob/master/dependencies/switch/libnx-dyn/dyn.c
774 views
1
#include <stdio.h>
2
#include <malloc.h>
3
#include <string.h>
4
#include <dyn.h>
5
#include <address_space.h>
6
7
static DynModule *g_ModuleList[MAX_MODULES];
8
static u32 g_ModuleCount = 0;
9
10
#define DBGFMT(fmt, ...) \
11
{ \
12
printf(fmt "\n", ##__VA_ARGS__); \
13
consoleUpdate(NULL); \
14
}
15
16
Result dynElfFindValue(Elf64_Dyn *dynamic, s64 tag, u64 *value)
17
{
18
u64 *found = NULL;
19
*value = 0;
20
for (; dynamic->d_tag != DT_NULL; dynamic++) {
21
if (dynamic->d_tag == tag) {
22
if (found != NULL)
23
return MAKERESULT(Module_LibnxDyn, LibnxDynError_DuplicatedDtEntry);
24
else
25
found = &dynamic->d_un.d_val;
26
}
27
}
28
if (found == NULL)
29
return MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry);
30
*value = *found;
31
return 0;
32
}
33
34
Result dynElfFindOffset(Elf64_Dyn *dynamic, s64 tag, void **value, void *aslr_base)
35
{
36
u64 intermediate;
37
Result r = dynElfFindValue(dynamic, tag, &intermediate);
38
*value = (u8 *)aslr_base + intermediate;
39
return r;
40
}
41
42
u64 dynElfHashString(const char *name)
43
{
44
u64 h = 0;
45
u64 g;
46
while (*name) {
47
h = (h << 4) + *(const u8 *)name++;
48
if ((g = (h & 0xf0000000)) != 0)
49
h ^= g >> 24;
50
h &= ~g;
51
}
52
return h;
53
}
54
55
static Handle ownHandle;
56
57
static Result _dynLoad_elf(const char *path, DynModule *mod)
58
{
59
Result res = MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputElf);
60
FILE *f = fopen(path, "rb");
61
u64 appid = 0x010000000000100D;
62
svcGetInfo(&appid, InfoType_ProgramId, CUR_PROCESS_HANDLE, 0);
63
64
if (f) {
65
fseek(f, 0, SEEK_END);
66
size_t filesz = ftell(f);
67
68
rewind(f);
69
void *file = memalign(0x1000, filesz);
70
if (!file) {
71
fclose(f);
72
return res;
73
}
74
75
size_t read = fread(file, 1, filesz, f);
76
if (read != filesz) {
77
free(file);
78
fclose(f);
79
return res;
80
}
81
fclose(f);
82
83
Dyn_Elf64_Data *data = malloc(sizeof(*data));
84
if (data == NULL) {
85
return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
86
}
87
data->num_segments = 0;
88
89
Elf64_Ehdr *ehdr = (Elf64_Ehdr *)file;
90
Elf64_Phdr *phdrs = file + ehdr->e_phoff;
91
if (ehdr->e_phoff + sizeof(Elf64_Phdr) * ehdr->e_phnum > filesz) {
92
return res;
93
}
94
uint64_t total_as_size = 0;
95
for (int i = 0; i < ehdr->e_phnum; i++) {
96
Elf64_Phdr *phdr = &phdrs[i];
97
if (phdr->p_type == PT_LOAD && phdr->p_memsz > 0) {
98
data->num_segments++;
99
}
100
if (phdr->p_vaddr + phdr->p_memsz > total_as_size) {
101
total_as_size = phdr->p_vaddr + phdr->p_memsz;
102
}
103
}
104
105
data->segments = malloc(sizeof(*data->segments) * data->num_segments);
106
if (data->segments == NULL) {
107
return res;
108
}
109
110
// in theory this is safe :rapture:
111
void *slide = as_reserve(total_as_size);
112
data->as_base = slide;
113
data->as_size = total_as_size;
114
115
for (int i = 0, j = 0; i < ehdr->e_phnum; i++) {
116
Elf64_Phdr *phdr = &phdrs[i];
117
if (phdr->p_type == PT_LOAD && phdr->p_memsz > 0) {
118
Dyn_Elf64_Seg *seg = &data->segments[j++];
119
seg->phdr = *phdr;
120
seg->size = phdr->p_memsz;
121
seg->dst = slide + phdr->p_vaddr;
122
seg->src = file + phdr->p_offset;
123
124
if (phdr->p_offset + phdr->p_filesz > filesz) {
125
for (int k = 0; k < j - 1; k++) {
126
if (data->segments[k].clone) {
127
free(data->segments[k].clone);
128
}
129
}
130
return res;
131
}
132
133
if (phdr->p_filesz == phdr->p_memsz && (phdr->p_memsz & 0xFFF) == 0 && (phdr->p_offset & 0xFFF) == 0) {
134
seg->clone = NULL;
135
}
136
else {
137
seg->size = (phdr->p_memsz + 0xFFF) & ~0xFFF;
138
seg->clone = memalign(0x1000, seg->size);
139
if (seg->clone == NULL) {
140
for (int k = 0; k < j - 1; k++) {
141
if (data->segments[k].clone) {
142
free(data->segments[k].clone);
143
}
144
}
145
res = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
146
return res;
147
}
148
memset(seg->clone + phdr->p_filesz, 0, seg->size - phdr->p_filesz);
149
memcpy(seg->clone, seg->src, phdr->p_filesz);
150
seg->src = seg->clone;
151
}
152
}
153
}
154
155
for (uint64_t i = 0; i < data->num_segments; i++) {
156
Dyn_Elf64_Seg *seg = &data->segments[i];
157
if (R_FAILED(res = svcMapProcessCodeMemory(ownHandle, (uint64_t)seg->dst, (uint64_t)seg->src, seg->size))) {
158
res = 0;
159
/*for (uint64_t j = 0; j < i; j++) {
160
svcUnmapProcessCodeMemory(ownHandle, seg->dst, seg->src, seg->size);
161
}
162
return res;//*/
163
}
164
165
uint32_t permissions = 0;
166
if (seg->phdr.p_flags & PF_X) {
167
permissions |= 4;
168
}
169
if (seg->phdr.p_flags & PF_W) {
170
permissions |= 2;
171
}
172
if (seg->phdr.p_flags & PF_R) {
173
permissions |= 1;
174
}
175
176
if (R_FAILED(res = svcSetProcessMemoryPermission(ownHandle, (uint64_t)seg->dst, seg->size, permissions))) {
177
res = 0;
178
/*for (uint64_t j = 0; j <= i; j++) {
179
svcUnmapProcessCodeMemory(ownHandle, seg->dst, seg->src, seg->size);
180
}
181
return res;//*/
182
}
183
}
184
mod->input.base = slide;
185
mod->input.loader_data = data;
186
}
187
return res;
188
}
189
190
static Result _dynLoad_nrovsc(const char *path, DynModule *mod)
191
{
192
Result res = MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputNro);
193
FILE *f = fopen(path, "rb");
194
if (f) {
195
fseek(f, sizeof(NroStart), SEEK_SET);
196
NroHeader header;
197
fread(&header, 1, sizeof(NroHeader), f);
198
size_t filesz = header.size;
199
200
rewind(f);
201
void *nro = memalign(0x1000, filesz);
202
if (!nro) {
203
fclose(f);
204
return res;
205
}
206
207
size_t read = fread(nro, 1, filesz, f);
208
if (read != filesz) {
209
free(nro);
210
fclose(f);
211
return res;
212
}
213
fclose(f);
214
215
u32 *nrr = (u32 *)memalign(0x1000, 0x1000);
216
if (!nrr) {
217
free(nro);
218
return res;
219
}
220
memset(nrr, 0, 0x1000);
221
222
nrr[0] = NRR0_MAGIC;
223
nrr[(0x338 >> 2) + 0] = 0x1000;
224
nrr[(0x340 >> 2) + 0] = 0x350;
225
nrr[(0x340 >> 2) + 1] = 1; // NRO count
226
227
u64 appid = 0x010000000000100D;
228
svcGetInfo(&appid, InfoType_ProgramId, CUR_PROCESS_HANDLE, 0);
229
230
*(u64 *)&((u8 *)nrr)[0x330] = appid;
231
232
sha256CalculateHash(&nrr[0x350 >> 2], nro, filesz);
233
234
u32 bss_sz = *(u32 *)((u8 *)nro + 0x38);
235
void *bss = memalign(0x1000, bss_sz);
236
if (!bss) {
237
free(nro);
238
free(nrr);
239
return res;
240
}
241
242
u64 nro_addr = 0;
243
244
res = ldrRoLoadNrr((u64)nrr, 0x1000);
245
if (res == 0)
246
res = ldrRoLoadNro(&nro_addr, (u64)nro, filesz, (u64)bss, bss_sz);
247
248
if ((res == 0)) {
249
mod->input.nro = (void*)nro;
250
mod->input.nrr = nrr;
251
mod->input.bss = bss;
252
mod->input.base = (void*)nro_addr;
253
}
254
}
255
return res;
256
}
257
258
static Result _dynRelocate(DynModule *mod);
259
static Result _dynInitialize(DynModule *mod);
260
261
static Result _dynLoad(const char *path, DynModule *mod)
262
{
263
if (R_FAILED(_dynLoad_nrovsc(path, mod))) {
264
return _dynLoad_elf(path, mod);
265
}
266
}
267
268
static Result _dynScan(DynModule *mod)
269
{
270
u8 *module_base = (u8 *)mod->input.base;
271
u32 mod0_offset = *(u32 *)&(module_base)[4];
272
DynModuleHeader *mod_header = (DynModuleHeader *)&module_base[mod0_offset];
273
Elf64_Dyn *dynamic = (Elf64_Dyn *)((u8 *)mod_header + mod_header->dynamic);
274
mod->dynamic = dynamic;
275
276
if (mod_header->magic != MOD0_MAGIC)
277
return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputNro);
278
279
Result r = dynElfFindOffset(dynamic, DT_HASH, (void**)&mod->hash, module_base);
280
if ((r != 0) && (r != MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry)))
281
return r;
282
283
r = dynElfFindOffset(dynamic, DT_STRTAB, (void**)&mod->strtab, module_base);
284
if ((r != 0) && (r != MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry)))
285
return r;
286
287
r = dynElfFindOffset(mod->dynamic, DT_SYMTAB, (void**)&mod->symtab, module_base);
288
if ((r != 0) && (r != MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry)))
289
return r;
290
291
u64 syment;
292
r = dynElfFindValue(mod->dynamic, DT_SYMENT, &syment);
293
if ((r == 0)) {
294
if (syment != sizeof(Elf64_Sym))
295
return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidSymEnt);
296
}
297
else if (r != MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry))
298
return r;
299
300
for (Elf64_Dyn *walker = dynamic; walker->d_tag != DT_NULL; walker++) {
301
if (walker->d_tag == DT_NEEDED) {
302
DynModule *dep = malloc(sizeof(DynModule));
303
r = _dynLoad(mod->strtab + walker->d_un.d_val, dep);
304
if ((r == 0)) {
305
mod->dependencies[mod->dependency_count] = dep;
306
mod->dependency_count++;
307
}
308
}
309
}
310
311
mod->state = DynModuleState_Scanned;
312
return 0;
313
}
314
315
static Result _dynTryResolveSymbol(DynModule *try_mod, const char *find_name, u64 find_name_hash, Elf64_Sym **def, DynModule **defining_module,
316
bool require_global)
317
{
318
if (require_global && !try_mod->input.is_global)
319
return MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);
320
if (try_mod->symtab == NULL)
321
return MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);
322
if (try_mod->strtab == NULL)
323
return MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);
324
if (try_mod->hash != NULL) {
325
u32 nbucket = try_mod->hash[0];
326
u32 nchain = try_mod->hash[1];
327
(void)nchain;
328
u32 index = try_mod->hash[2 + (find_name_hash % nbucket)];
329
u32 *chains = try_mod->hash + 2 + nbucket;
330
while (index != 0 && strcmp(find_name, try_mod->strtab + try_mod->symtab[index].st_name) != 0) {
331
index = chains[index];
332
}
333
if (index == STN_UNDEF) {
334
return MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);
335
}
336
Elf64_Sym *sym = &try_mod->symtab[index];
337
if (sym->st_shndx == SHN_UNDEF) {
338
return 0x100;
339
MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);
340
}
341
*def = sym;
342
*defining_module = try_mod;
343
return 0;
344
}
345
return MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);
346
}
347
348
Result _dynResolveLoadSymbol(DynModule *find_mod, const char *find_name, Elf64_Sym **def, DynModule **defining_module)
349
{
350
u64 hash = dynElfHashString(find_name);
351
352
for (u32 i = 0; i < g_ModuleCount; i++) {
353
if (g_ModuleList[i] != find_mod) {
354
Result res = _dynTryResolveSymbol(g_ModuleList[i], find_name, hash, def, defining_module, true);
355
if (res == MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol)) {
356
continue;
357
}
358
else {
359
return res;
360
}
361
}
362
}
363
364
if (find_mod != NULL) {
365
return _dynTryResolveSymbol(find_mod, find_name, hash, def, defining_module, false);
366
}
367
368
return MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);
369
}
370
371
Result _dynResolveDependencySymbol(DynModule *find_mod, const char *find_name, Elf64_Sym **def, DynModule **defining_module)
372
{
373
u64 find_name_hash = dynElfHashString(find_name);
374
Result r = _dynTryResolveSymbol(find_mod, find_name, find_name_hash, def, defining_module, false);
375
if (r != MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol))
376
return r;
377
378
for (u32 i = 0; i < find_mod->dependency_count; i++) {
379
r = _dynTryResolveSymbol(find_mod->dependencies[i], find_name, find_name_hash, def, defining_module, false);
380
if (r == MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol)) {
381
continue;
382
}
383
else {
384
return r;
385
}
386
}
387
388
for (u32 i = 0; i < find_mod->dependency_count; i++) {
389
r = _dynResolveDependencySymbol(find_mod->dependencies[i], find_name, def, defining_module);
390
if (r == MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol)) {
391
continue;
392
}
393
else {
394
return r;
395
}
396
}
397
398
return MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);
399
}
400
401
Result _dynRelocateModuleBase(u8 *module_base)
402
{
403
DynModuleHeader *mod_header = (DynModuleHeader *)&module_base[*(u32 *)&module_base[4]];
404
Elf64_Dyn *dynamic = (Elf64_Dyn *)(((u8 *)mod_header) + mod_header->dynamic);
405
u64 rela_offset = 0;
406
u64 rela_size = 0;
407
u64 rela_ent = 0;
408
u64 rela_count = 0;
409
410
if (mod_header->magic != MOD0_MAGIC) {
411
return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputNro);
412
}
413
414
Result r = dynElfFindValue(dynamic, DT_RELA, &rela_offset);
415
if (R_FAILED(r)) {
416
return r;
417
}
418
419
r = dynElfFindValue(dynamic, DT_RELASZ, &rela_size);
420
if (R_FAILED(r)) {
421
return r;
422
}
423
424
r = dynElfFindValue(dynamic, DT_RELAENT, &rela_ent);
425
if (R_FAILED(r)) {
426
return r;
427
}
428
429
r = dynElfFindValue(dynamic, DT_RELACOUNT, &rela_count);
430
if (R_FAILED(r)) {
431
return r;
432
}
433
434
if (rela_ent != 0x18) {
435
return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidRelocEnt);
436
}
437
438
if (rela_size != rela_count * rela_ent) {
439
return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidRelocTableSize);
440
}
441
442
Dyn_Elf64_Rela *rela_base = (Dyn_Elf64_Rela *)(module_base + rela_offset);
443
for (u64 i = 0; i < rela_count; i++) {
444
Dyn_Elf64_Rela rela = rela_base[i];
445
446
switch (rela.r_reloc_type) {
447
case 0x403:
448
if (rela.r_symbol != 0) {
449
return MAKERESULT(Module_LibnxDyn, LibnxDynError_RelaUnsupportedSymbol);
450
}
451
*(void **)(module_base + rela.r_offset) = module_base + rela.r_addend;
452
break;
453
default: return MAKERESULT(Module_LibnxDyn, LibnxDynError_UnrecognizedRelocType);
454
}
455
}
456
457
return 0;
458
}
459
460
static Result _dynRunRelocationTable(DynModule *mod, u32 offset_tag, u32 size_tag)
461
{
462
void *raw_table;
463
Elf64_Dyn *dynamic = mod->dynamic;
464
Result r = dynElfFindOffset(dynamic, offset_tag, &raw_table, mod->input.base);
465
if (r == MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry)) {
466
return 0;
467
}
468
if (R_FAILED(r)) {
469
return r;
470
}
471
472
u64 table_size = 0;
473
u64 table_type = offset_tag;
474
r = dynElfFindValue(dynamic, size_tag, &table_size);
475
if (R_FAILED(r)) {
476
return r;
477
}
478
479
if (offset_tag == DT_JMPREL) {
480
r = dynElfFindValue(dynamic, DT_PLTREL, &table_type);
481
if (R_FAILED(r)) {
482
return r;
483
}
484
}
485
486
u64 ent_size = 0;
487
switch (table_type) {
488
case DT_RELA:
489
r = dynElfFindValue(dynamic, DT_RELAENT, &ent_size);
490
if (r == MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry)) {
491
ent_size = sizeof(Elf64_Rela);
492
}
493
else if (r == 0 && ent_size != sizeof(Elf64_Rela)) {
494
return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidRelocEnt);
495
}
496
else if (r != 0) {
497
return r;
498
}
499
break;
500
case DT_REL:
501
r = dynElfFindValue(dynamic, DT_RELENT, &ent_size);
502
if (r == MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry)) {
503
ent_size = sizeof(Elf64_Rel);
504
}
505
else if (r == 0 && ent_size != sizeof(Elf64_Rel)) {
506
return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidRelocEnt);
507
}
508
else if (r != 0) {
509
return r;
510
}
511
break;
512
default: return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidRelocTableType);
513
}
514
515
if ((table_size % ent_size) != 0)
516
return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidRelocTableSize);
517
518
for (size_t offset = 0; offset < table_size; offset += ent_size) {
519
Dyn_Elf64_Rela rela;
520
switch (table_type) {
521
case DT_RELA: rela = *(Dyn_Elf64_Rela *)((u8 *)raw_table + offset); break;
522
case DT_REL: {
523
Dyn_Elf64_Rel rel = *(Dyn_Elf64_Rel *)((u8 *)raw_table + offset);
524
rela.r_offset = rel.r_offset;
525
rela.r_reloc_type = rel.r_reloc_type;
526
rela.r_symbol = rel.r_symbol;
527
break;
528
}
529
}
530
531
void *symbol = NULL;
532
DynModule *defining_module = mod;
533
if (rela.r_symbol != 0) {
534
if (mod->symtab == NULL)
535
return MAKERESULT(Module_LibnxDyn, LibnxDynError_NeedsSymTab);
536
if (mod->strtab == NULL)
537
return MAKERESULT(Module_LibnxDyn, LibnxDynError_NeedsStrTab);
538
Elf64_Sym *sym = &mod->symtab[rela.r_symbol];
539
540
Elf64_Sym *def;
541
r = _dynResolveLoadSymbol(mod, mod->strtab + sym->st_name, &def, &defining_module);
542
if ((r != 0))
543
return r;
544
symbol = (u8 *)defining_module->input.base + def->st_value;
545
}
546
void *delta_symbol = defining_module->input.base;
547
548
switch (rela.r_reloc_type) {
549
case 257:
550
case 1025:
551
case 1026: {
552
void **target = (void **)((u8 *)mod->input.base + rela.r_offset);
553
if (table_type == DT_REL)
554
rela.r_addend = (u64)*target;
555
*target = (u8 *)symbol + rela.r_addend;
556
break;
557
}
558
case 1027: {
559
if (!mod->input.has_run_basic_relocations) {
560
void **target = (void **)((u8 *)mod->input.base + rela.r_offset);
561
if (table_type == DT_REL)
562
rela.r_addend = (u64)*target;
563
*target = (u8 *)delta_symbol + rela.r_addend;
564
}
565
break;
566
}
567
default: return MAKERESULT(Module_LibnxDyn, LibnxDynError_UnrecognizedRelocType);
568
}
569
}
570
571
return 0;
572
}
573
574
static Result _dynRelocate(DynModule *mod)
575
{
576
Result r = _dynRunRelocationTable(mod, DT_RELA, DT_RELASZ);
577
if ((r != 0))
578
return r;
579
r = _dynRunRelocationTable(mod, DT_REL, DT_RELSZ);
580
if ((r != 0))
581
return r;
582
r = _dynRunRelocationTable(mod, DT_JMPREL, DT_PLTRELSZ);
583
mod->state = DynModuleState_Relocated;
584
return r;
585
}
586
587
static Result _dynInitialize(DynModule *mod)
588
{
589
if (mod->state != DynModuleState_Relocated)
590
return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidModuleState);
591
592
void (**init_array)(void);
593
size_t init_array_size;
594
595
Result r = dynElfFindOffset(mod->dynamic, DT_INIT_ARRAY, (void **)&init_array, mod->input.base);
596
if ((r == 0)) {
597
r = dynElfFindValue(mod->dynamic, DT_INIT_ARRAYSZ, &init_array_size);
598
if ((r != 0))
599
return r;
600
for (size_t i = 0; i < (init_array_size / sizeof(init_array[0])); i++) init_array[i]();
601
}
602
else if (r != MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry))
603
return r;
604
mod->state = DynModuleState_Initialized;
605
return 0;
606
}
607
608
static Result _dynFinalize(DynModule *mod)
609
{
610
if (mod->state != DynModuleState_Initialized)
611
return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidModuleState);
612
613
void (**fini_array)(void);
614
size_t fini_array_size;
615
616
Result r = dynElfFindOffset(mod->dynamic, DT_FINI_ARRAY, (void **)&fini_array, mod->input.base);
617
if ((r == 0)) {
618
r = dynElfFindValue(mod->dynamic, DT_FINI_ARRAYSZ, &fini_array_size);
619
if ((r != 0))
620
return r;
621
for (size_t i = 0; i < (fini_array_size / sizeof(fini_array[0])); i++) fini_array[i]();
622
}
623
else if (r != MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry))
624
return r;
625
626
mod->state = DynModuleState_Finalized;
627
return 0;
628
}
629
630
static Result _dynDestroy(DynModule *mod);
631
632
static void _dynDecref(DynModule *mod)
633
{
634
mod->ref_count--;
635
if (mod->ref_count == 0)
636
_dynDestroy(mod);
637
}
638
639
static Result _dynUnload(DynModule *mod)
640
{
641
Result res;
642
if (mod != NULL) {
643
if (mod->input.loader_data == NULL) {
644
free(mod->input.nrr);
645
free(mod->input.nro);
646
free(mod->input.bss);
647
res = ldrRoUnloadNro((u64)mod->input.base);
648
if ((res == 0))
649
res = ldrRoUnloadNrr((u64)mod->input.nrr);
650
}
651
else {
652
Dyn_Elf64_Data *data = mod->input.loader_data;
653
for (uint64_t i = 0; i < data->num_segments; i++) {
654
Dyn_Elf64_Seg *seg = &data->segments[i];
655
svcUnmapProcessCodeMemory(ownHandle, (uint64_t)seg->dst, (uint64_t)seg->src, seg->size);
656
if (seg->clone) {
657
free(seg->clone);
658
}
659
}
660
661
as_release(data->as_base, data->as_size);
662
free(data->segments);
663
free(data);
664
}
665
}
666
return res;
667
}
668
669
static Result _dynDestroy(DynModule *mod)
670
{
671
Result res;
672
if (mod->state == DynModuleState_Initialized) {
673
res = _dynFinalize(mod);
674
if ((res == 0))
675
res = _dynUnload(mod);
676
}
677
678
for (u32 i = 0; i < mod->dependency_count; i++) _dynDecref(mod->dependencies[i]);
679
680
return res;
681
}
682
683
static void _dynDestroyModule(DynModule *mod) { _dynDecref(mod); }
684
685
static void _dynEraseFromModules(u32 index)
686
{
687
if (index >= g_ModuleCount)
688
return;
689
u32 i;
690
for (i = index + 1; i < g_ModuleCount; i++) {
691
g_ModuleList[i - 1] = g_ModuleList[i];
692
g_ModuleList[i] = NULL;
693
}
694
g_ModuleCount--;
695
}
696
697
Result dynInitialize()
698
{
699
ownHandle = envGetOwnProcessHandle();
700
if (!envIsSyscallHinted(0x77) || !envIsSyscallHinted(0x78))
701
return MAKERESULT(Module_LibnxDyn, LibnxDynError_InsufficientSysCalls);
702
return ldrRoInitialize();
703
}
704
705
void dynExit() { ldrRoExit(); }
706
707
Result dynLoadFromMemory(const char *name, void *base)
708
{
709
if (!name)
710
return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputNro);
711
if (!base)
712
return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputNro);
713
714
DynModule *mod = malloc(sizeof(DynModule));
715
if (!mod)
716
return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputNro);
717
718
memset(mod, 0, sizeof(DynModule));
719
strcpy(mod->input.name, name);
720
mod->input.has_run_basic_relocations = true;
721
mod->input.is_global = true;
722
mod->input.base = base;
723
mod->input.is_nro = false;
724
mod->dependency_count = 0;
725
726
mod->ref_count = 1;
727
mod->state = DynModuleState_Queued;
728
729
Result res = _dynScan(mod);
730
if (res != 0) {
731
free(mod);
732
return res;
733
}
734
735
res = _dynRelocate(mod);
736
if (res != 0) {
737
free(mod);
738
return res;
739
}
740
741
res = _dynInitialize(mod);
742
if (res != 0) {
743
free(mod);
744
return res;
745
}
746
747
g_ModuleList[g_ModuleCount] = mod;
748
g_ModuleCount++;
749
750
return res;
751
}
752
753
Result dynLoadNroModule(DynModule *mod, const char *path, bool global)
754
{
755
if (path == NULL) {
756
return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputNro);
757
}
758
759
strcpy(mod->input.name, path);
760
mod->input.has_run_basic_relocations = false;
761
mod->input.is_global = global;
762
mod->dependency_count = 0;
763
764
Result res = _dynLoad(path, mod);
765
766
if (R_FAILED(res)) {
767
return res;
768
}
769
770
mod->ref_count = 1;
771
mod->state = DynModuleState_Queued;
772
773
res = _dynScan(mod);
774
if (R_FAILED(res)) {
775
return res;
776
}
777
778
res = _dynRelocate(mod);
779
if (R_FAILED(res)) {
780
return res;
781
}
782
783
res = _dynInitialize(mod);
784
if (R_FAILED(res)) {
785
return res;
786
}
787
788
g_ModuleList[g_ModuleCount] = mod;
789
g_ModuleCount++;
790
791
return res;
792
}
793
794
void dynModuleUnload(DynModule *mod) { _dynDestroyModule(mod); }
795
796
void dynUnloadMyName(const char *name)
797
{
798
for (u32 i = 0; i < g_ModuleCount; i++) {
799
if (strcmp(name, g_ModuleList[i]->input.name) == 0) {
800
_dynDestroyModule(g_ModuleList[i]);
801
_dynEraseFromModules(i);
802
break;
803
}
804
}
805
}
806
807
void dynUnloadAll()
808
{
809
for (u32 i = 0; i < g_ModuleCount; i++) {
810
_dynDestroyModule(g_ModuleList[i]);
811
g_ModuleList[i] = NULL;
812
}
813
g_ModuleCount = 0;
814
}
815
816
Result dynModuleLookupSymbol(DynModule *mod, const char *name, void **out_sym)
817
{
818
Elf64_Sym *def;
819
DynModule *def_mod;
820
821
Result res = _dynResolveDependencySymbol(mod, name, &def, &def_mod);
822
if (R_SUCCEEDED(res)) {
823
*out_sym = (u8 *)mod->input.base + def->st_value;
824
}
825
return res;
826
}
827
828