Path: blob/master/dependencies/switch/libnx-dyn/dyn.c
774 views
#include <stdio.h>1#include <malloc.h>2#include <string.h>3#include <dyn.h>4#include <address_space.h>56static DynModule *g_ModuleList[MAX_MODULES];7static u32 g_ModuleCount = 0;89#define DBGFMT(fmt, ...) \10{ \11printf(fmt "\n", ##__VA_ARGS__); \12consoleUpdate(NULL); \13}1415Result dynElfFindValue(Elf64_Dyn *dynamic, s64 tag, u64 *value)16{17u64 *found = NULL;18*value = 0;19for (; dynamic->d_tag != DT_NULL; dynamic++) {20if (dynamic->d_tag == tag) {21if (found != NULL)22return MAKERESULT(Module_LibnxDyn, LibnxDynError_DuplicatedDtEntry);23else24found = &dynamic->d_un.d_val;25}26}27if (found == NULL)28return MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry);29*value = *found;30return 0;31}3233Result dynElfFindOffset(Elf64_Dyn *dynamic, s64 tag, void **value, void *aslr_base)34{35u64 intermediate;36Result r = dynElfFindValue(dynamic, tag, &intermediate);37*value = (u8 *)aslr_base + intermediate;38return r;39}4041u64 dynElfHashString(const char *name)42{43u64 h = 0;44u64 g;45while (*name) {46h = (h << 4) + *(const u8 *)name++;47if ((g = (h & 0xf0000000)) != 0)48h ^= g >> 24;49h &= ~g;50}51return h;52}5354static Handle ownHandle;5556static Result _dynLoad_elf(const char *path, DynModule *mod)57{58Result res = MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputElf);59FILE *f = fopen(path, "rb");60u64 appid = 0x010000000000100D;61svcGetInfo(&appid, InfoType_ProgramId, CUR_PROCESS_HANDLE, 0);6263if (f) {64fseek(f, 0, SEEK_END);65size_t filesz = ftell(f);6667rewind(f);68void *file = memalign(0x1000, filesz);69if (!file) {70fclose(f);71return res;72}7374size_t read = fread(file, 1, filesz, f);75if (read != filesz) {76free(file);77fclose(f);78return res;79}80fclose(f);8182Dyn_Elf64_Data *data = malloc(sizeof(*data));83if (data == NULL) {84return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);85}86data->num_segments = 0;8788Elf64_Ehdr *ehdr = (Elf64_Ehdr *)file;89Elf64_Phdr *phdrs = file + ehdr->e_phoff;90if (ehdr->e_phoff + sizeof(Elf64_Phdr) * ehdr->e_phnum > filesz) {91return res;92}93uint64_t total_as_size = 0;94for (int i = 0; i < ehdr->e_phnum; i++) {95Elf64_Phdr *phdr = &phdrs[i];96if (phdr->p_type == PT_LOAD && phdr->p_memsz > 0) {97data->num_segments++;98}99if (phdr->p_vaddr + phdr->p_memsz > total_as_size) {100total_as_size = phdr->p_vaddr + phdr->p_memsz;101}102}103104data->segments = malloc(sizeof(*data->segments) * data->num_segments);105if (data->segments == NULL) {106return res;107}108109// in theory this is safe :rapture:110void *slide = as_reserve(total_as_size);111data->as_base = slide;112data->as_size = total_as_size;113114for (int i = 0, j = 0; i < ehdr->e_phnum; i++) {115Elf64_Phdr *phdr = &phdrs[i];116if (phdr->p_type == PT_LOAD && phdr->p_memsz > 0) {117Dyn_Elf64_Seg *seg = &data->segments[j++];118seg->phdr = *phdr;119seg->size = phdr->p_memsz;120seg->dst = slide + phdr->p_vaddr;121seg->src = file + phdr->p_offset;122123if (phdr->p_offset + phdr->p_filesz > filesz) {124for (int k = 0; k < j - 1; k++) {125if (data->segments[k].clone) {126free(data->segments[k].clone);127}128}129return res;130}131132if (phdr->p_filesz == phdr->p_memsz && (phdr->p_memsz & 0xFFF) == 0 && (phdr->p_offset & 0xFFF) == 0) {133seg->clone = NULL;134}135else {136seg->size = (phdr->p_memsz + 0xFFF) & ~0xFFF;137seg->clone = memalign(0x1000, seg->size);138if (seg->clone == NULL) {139for (int k = 0; k < j - 1; k++) {140if (data->segments[k].clone) {141free(data->segments[k].clone);142}143}144res = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);145return res;146}147memset(seg->clone + phdr->p_filesz, 0, seg->size - phdr->p_filesz);148memcpy(seg->clone, seg->src, phdr->p_filesz);149seg->src = seg->clone;150}151}152}153154for (uint64_t i = 0; i < data->num_segments; i++) {155Dyn_Elf64_Seg *seg = &data->segments[i];156if (R_FAILED(res = svcMapProcessCodeMemory(ownHandle, (uint64_t)seg->dst, (uint64_t)seg->src, seg->size))) {157res = 0;158/*for (uint64_t j = 0; j < i; j++) {159svcUnmapProcessCodeMemory(ownHandle, seg->dst, seg->src, seg->size);160}161return res;//*/162}163164uint32_t permissions = 0;165if (seg->phdr.p_flags & PF_X) {166permissions |= 4;167}168if (seg->phdr.p_flags & PF_W) {169permissions |= 2;170}171if (seg->phdr.p_flags & PF_R) {172permissions |= 1;173}174175if (R_FAILED(res = svcSetProcessMemoryPermission(ownHandle, (uint64_t)seg->dst, seg->size, permissions))) {176res = 0;177/*for (uint64_t j = 0; j <= i; j++) {178svcUnmapProcessCodeMemory(ownHandle, seg->dst, seg->src, seg->size);179}180return res;//*/181}182}183mod->input.base = slide;184mod->input.loader_data = data;185}186return res;187}188189static Result _dynLoad_nrovsc(const char *path, DynModule *mod)190{191Result res = MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputNro);192FILE *f = fopen(path, "rb");193if (f) {194fseek(f, sizeof(NroStart), SEEK_SET);195NroHeader header;196fread(&header, 1, sizeof(NroHeader), f);197size_t filesz = header.size;198199rewind(f);200void *nro = memalign(0x1000, filesz);201if (!nro) {202fclose(f);203return res;204}205206size_t read = fread(nro, 1, filesz, f);207if (read != filesz) {208free(nro);209fclose(f);210return res;211}212fclose(f);213214u32 *nrr = (u32 *)memalign(0x1000, 0x1000);215if (!nrr) {216free(nro);217return res;218}219memset(nrr, 0, 0x1000);220221nrr[0] = NRR0_MAGIC;222nrr[(0x338 >> 2) + 0] = 0x1000;223nrr[(0x340 >> 2) + 0] = 0x350;224nrr[(0x340 >> 2) + 1] = 1; // NRO count225226u64 appid = 0x010000000000100D;227svcGetInfo(&appid, InfoType_ProgramId, CUR_PROCESS_HANDLE, 0);228229*(u64 *)&((u8 *)nrr)[0x330] = appid;230231sha256CalculateHash(&nrr[0x350 >> 2], nro, filesz);232233u32 bss_sz = *(u32 *)((u8 *)nro + 0x38);234void *bss = memalign(0x1000, bss_sz);235if (!bss) {236free(nro);237free(nrr);238return res;239}240241u64 nro_addr = 0;242243res = ldrRoLoadNrr((u64)nrr, 0x1000);244if (res == 0)245res = ldrRoLoadNro(&nro_addr, (u64)nro, filesz, (u64)bss, bss_sz);246247if ((res == 0)) {248mod->input.nro = (void*)nro;249mod->input.nrr = nrr;250mod->input.bss = bss;251mod->input.base = (void*)nro_addr;252}253}254return res;255}256257static Result _dynRelocate(DynModule *mod);258static Result _dynInitialize(DynModule *mod);259260static Result _dynLoad(const char *path, DynModule *mod)261{262if (R_FAILED(_dynLoad_nrovsc(path, mod))) {263return _dynLoad_elf(path, mod);264}265}266267static Result _dynScan(DynModule *mod)268{269u8 *module_base = (u8 *)mod->input.base;270u32 mod0_offset = *(u32 *)&(module_base)[4];271DynModuleHeader *mod_header = (DynModuleHeader *)&module_base[mod0_offset];272Elf64_Dyn *dynamic = (Elf64_Dyn *)((u8 *)mod_header + mod_header->dynamic);273mod->dynamic = dynamic;274275if (mod_header->magic != MOD0_MAGIC)276return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputNro);277278Result r = dynElfFindOffset(dynamic, DT_HASH, (void**)&mod->hash, module_base);279if ((r != 0) && (r != MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry)))280return r;281282r = dynElfFindOffset(dynamic, DT_STRTAB, (void**)&mod->strtab, module_base);283if ((r != 0) && (r != MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry)))284return r;285286r = dynElfFindOffset(mod->dynamic, DT_SYMTAB, (void**)&mod->symtab, module_base);287if ((r != 0) && (r != MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry)))288return r;289290u64 syment;291r = dynElfFindValue(mod->dynamic, DT_SYMENT, &syment);292if ((r == 0)) {293if (syment != sizeof(Elf64_Sym))294return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidSymEnt);295}296else if (r != MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry))297return r;298299for (Elf64_Dyn *walker = dynamic; walker->d_tag != DT_NULL; walker++) {300if (walker->d_tag == DT_NEEDED) {301DynModule *dep = malloc(sizeof(DynModule));302r = _dynLoad(mod->strtab + walker->d_un.d_val, dep);303if ((r == 0)) {304mod->dependencies[mod->dependency_count] = dep;305mod->dependency_count++;306}307}308}309310mod->state = DynModuleState_Scanned;311return 0;312}313314static Result _dynTryResolveSymbol(DynModule *try_mod, const char *find_name, u64 find_name_hash, Elf64_Sym **def, DynModule **defining_module,315bool require_global)316{317if (require_global && !try_mod->input.is_global)318return MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);319if (try_mod->symtab == NULL)320return MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);321if (try_mod->strtab == NULL)322return MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);323if (try_mod->hash != NULL) {324u32 nbucket = try_mod->hash[0];325u32 nchain = try_mod->hash[1];326(void)nchain;327u32 index = try_mod->hash[2 + (find_name_hash % nbucket)];328u32 *chains = try_mod->hash + 2 + nbucket;329while (index != 0 && strcmp(find_name, try_mod->strtab + try_mod->symtab[index].st_name) != 0) {330index = chains[index];331}332if (index == STN_UNDEF) {333return MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);334}335Elf64_Sym *sym = &try_mod->symtab[index];336if (sym->st_shndx == SHN_UNDEF) {337return 0x100;338MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);339}340*def = sym;341*defining_module = try_mod;342return 0;343}344return MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);345}346347Result _dynResolveLoadSymbol(DynModule *find_mod, const char *find_name, Elf64_Sym **def, DynModule **defining_module)348{349u64 hash = dynElfHashString(find_name);350351for (u32 i = 0; i < g_ModuleCount; i++) {352if (g_ModuleList[i] != find_mod) {353Result res = _dynTryResolveSymbol(g_ModuleList[i], find_name, hash, def, defining_module, true);354if (res == MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol)) {355continue;356}357else {358return res;359}360}361}362363if (find_mod != NULL) {364return _dynTryResolveSymbol(find_mod, find_name, hash, def, defining_module, false);365}366367return MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);368}369370Result _dynResolveDependencySymbol(DynModule *find_mod, const char *find_name, Elf64_Sym **def, DynModule **defining_module)371{372u64 find_name_hash = dynElfHashString(find_name);373Result r = _dynTryResolveSymbol(find_mod, find_name, find_name_hash, def, defining_module, false);374if (r != MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol))375return r;376377for (u32 i = 0; i < find_mod->dependency_count; i++) {378r = _dynTryResolveSymbol(find_mod->dependencies[i], find_name, find_name_hash, def, defining_module, false);379if (r == MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol)) {380continue;381}382else {383return r;384}385}386387for (u32 i = 0; i < find_mod->dependency_count; i++) {388r = _dynResolveDependencySymbol(find_mod->dependencies[i], find_name, def, defining_module);389if (r == MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol)) {390continue;391}392else {393return r;394}395}396397return MAKERESULT(Module_LibnxDyn, LibnxDynError_CouldNotResolveSymbol);398}399400Result _dynRelocateModuleBase(u8 *module_base)401{402DynModuleHeader *mod_header = (DynModuleHeader *)&module_base[*(u32 *)&module_base[4]];403Elf64_Dyn *dynamic = (Elf64_Dyn *)(((u8 *)mod_header) + mod_header->dynamic);404u64 rela_offset = 0;405u64 rela_size = 0;406u64 rela_ent = 0;407u64 rela_count = 0;408409if (mod_header->magic != MOD0_MAGIC) {410return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputNro);411}412413Result r = dynElfFindValue(dynamic, DT_RELA, &rela_offset);414if (R_FAILED(r)) {415return r;416}417418r = dynElfFindValue(dynamic, DT_RELASZ, &rela_size);419if (R_FAILED(r)) {420return r;421}422423r = dynElfFindValue(dynamic, DT_RELAENT, &rela_ent);424if (R_FAILED(r)) {425return r;426}427428r = dynElfFindValue(dynamic, DT_RELACOUNT, &rela_count);429if (R_FAILED(r)) {430return r;431}432433if (rela_ent != 0x18) {434return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidRelocEnt);435}436437if (rela_size != rela_count * rela_ent) {438return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidRelocTableSize);439}440441Dyn_Elf64_Rela *rela_base = (Dyn_Elf64_Rela *)(module_base + rela_offset);442for (u64 i = 0; i < rela_count; i++) {443Dyn_Elf64_Rela rela = rela_base[i];444445switch (rela.r_reloc_type) {446case 0x403:447if (rela.r_symbol != 0) {448return MAKERESULT(Module_LibnxDyn, LibnxDynError_RelaUnsupportedSymbol);449}450*(void **)(module_base + rela.r_offset) = module_base + rela.r_addend;451break;452default: return MAKERESULT(Module_LibnxDyn, LibnxDynError_UnrecognizedRelocType);453}454}455456return 0;457}458459static Result _dynRunRelocationTable(DynModule *mod, u32 offset_tag, u32 size_tag)460{461void *raw_table;462Elf64_Dyn *dynamic = mod->dynamic;463Result r = dynElfFindOffset(dynamic, offset_tag, &raw_table, mod->input.base);464if (r == MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry)) {465return 0;466}467if (R_FAILED(r)) {468return r;469}470471u64 table_size = 0;472u64 table_type = offset_tag;473r = dynElfFindValue(dynamic, size_tag, &table_size);474if (R_FAILED(r)) {475return r;476}477478if (offset_tag == DT_JMPREL) {479r = dynElfFindValue(dynamic, DT_PLTREL, &table_type);480if (R_FAILED(r)) {481return r;482}483}484485u64 ent_size = 0;486switch (table_type) {487case DT_RELA:488r = dynElfFindValue(dynamic, DT_RELAENT, &ent_size);489if (r == MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry)) {490ent_size = sizeof(Elf64_Rela);491}492else if (r == 0 && ent_size != sizeof(Elf64_Rela)) {493return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidRelocEnt);494}495else if (r != 0) {496return r;497}498break;499case DT_REL:500r = dynElfFindValue(dynamic, DT_RELENT, &ent_size);501if (r == MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry)) {502ent_size = sizeof(Elf64_Rel);503}504else if (r == 0 && ent_size != sizeof(Elf64_Rel)) {505return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidRelocEnt);506}507else if (r != 0) {508return r;509}510break;511default: return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidRelocTableType);512}513514if ((table_size % ent_size) != 0)515return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidRelocTableSize);516517for (size_t offset = 0; offset < table_size; offset += ent_size) {518Dyn_Elf64_Rela rela;519switch (table_type) {520case DT_RELA: rela = *(Dyn_Elf64_Rela *)((u8 *)raw_table + offset); break;521case DT_REL: {522Dyn_Elf64_Rel rel = *(Dyn_Elf64_Rel *)((u8 *)raw_table + offset);523rela.r_offset = rel.r_offset;524rela.r_reloc_type = rel.r_reloc_type;525rela.r_symbol = rel.r_symbol;526break;527}528}529530void *symbol = NULL;531DynModule *defining_module = mod;532if (rela.r_symbol != 0) {533if (mod->symtab == NULL)534return MAKERESULT(Module_LibnxDyn, LibnxDynError_NeedsSymTab);535if (mod->strtab == NULL)536return MAKERESULT(Module_LibnxDyn, LibnxDynError_NeedsStrTab);537Elf64_Sym *sym = &mod->symtab[rela.r_symbol];538539Elf64_Sym *def;540r = _dynResolveLoadSymbol(mod, mod->strtab + sym->st_name, &def, &defining_module);541if ((r != 0))542return r;543symbol = (u8 *)defining_module->input.base + def->st_value;544}545void *delta_symbol = defining_module->input.base;546547switch (rela.r_reloc_type) {548case 257:549case 1025:550case 1026: {551void **target = (void **)((u8 *)mod->input.base + rela.r_offset);552if (table_type == DT_REL)553rela.r_addend = (u64)*target;554*target = (u8 *)symbol + rela.r_addend;555break;556}557case 1027: {558if (!mod->input.has_run_basic_relocations) {559void **target = (void **)((u8 *)mod->input.base + rela.r_offset);560if (table_type == DT_REL)561rela.r_addend = (u64)*target;562*target = (u8 *)delta_symbol + rela.r_addend;563}564break;565}566default: return MAKERESULT(Module_LibnxDyn, LibnxDynError_UnrecognizedRelocType);567}568}569570return 0;571}572573static Result _dynRelocate(DynModule *mod)574{575Result r = _dynRunRelocationTable(mod, DT_RELA, DT_RELASZ);576if ((r != 0))577return r;578r = _dynRunRelocationTable(mod, DT_REL, DT_RELSZ);579if ((r != 0))580return r;581r = _dynRunRelocationTable(mod, DT_JMPREL, DT_PLTRELSZ);582mod->state = DynModuleState_Relocated;583return r;584}585586static Result _dynInitialize(DynModule *mod)587{588if (mod->state != DynModuleState_Relocated)589return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidModuleState);590591void (**init_array)(void);592size_t init_array_size;593594Result r = dynElfFindOffset(mod->dynamic, DT_INIT_ARRAY, (void **)&init_array, mod->input.base);595if ((r == 0)) {596r = dynElfFindValue(mod->dynamic, DT_INIT_ARRAYSZ, &init_array_size);597if ((r != 0))598return r;599for (size_t i = 0; i < (init_array_size / sizeof(init_array[0])); i++) init_array[i]();600}601else if (r != MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry))602return r;603mod->state = DynModuleState_Initialized;604return 0;605}606607static Result _dynFinalize(DynModule *mod)608{609if (mod->state != DynModuleState_Initialized)610return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidModuleState);611612void (**fini_array)(void);613size_t fini_array_size;614615Result r = dynElfFindOffset(mod->dynamic, DT_FINI_ARRAY, (void **)&fini_array, mod->input.base);616if ((r == 0)) {617r = dynElfFindValue(mod->dynamic, DT_FINI_ARRAYSZ, &fini_array_size);618if ((r != 0))619return r;620for (size_t i = 0; i < (fini_array_size / sizeof(fini_array[0])); i++) fini_array[i]();621}622else if (r != MAKERESULT(Module_LibnxDyn, LibnxDynError_MissingDtEntry))623return r;624625mod->state = DynModuleState_Finalized;626return 0;627}628629static Result _dynDestroy(DynModule *mod);630631static void _dynDecref(DynModule *mod)632{633mod->ref_count--;634if (mod->ref_count == 0)635_dynDestroy(mod);636}637638static Result _dynUnload(DynModule *mod)639{640Result res;641if (mod != NULL) {642if (mod->input.loader_data == NULL) {643free(mod->input.nrr);644free(mod->input.nro);645free(mod->input.bss);646res = ldrRoUnloadNro((u64)mod->input.base);647if ((res == 0))648res = ldrRoUnloadNrr((u64)mod->input.nrr);649}650else {651Dyn_Elf64_Data *data = mod->input.loader_data;652for (uint64_t i = 0; i < data->num_segments; i++) {653Dyn_Elf64_Seg *seg = &data->segments[i];654svcUnmapProcessCodeMemory(ownHandle, (uint64_t)seg->dst, (uint64_t)seg->src, seg->size);655if (seg->clone) {656free(seg->clone);657}658}659660as_release(data->as_base, data->as_size);661free(data->segments);662free(data);663}664}665return res;666}667668static Result _dynDestroy(DynModule *mod)669{670Result res;671if (mod->state == DynModuleState_Initialized) {672res = _dynFinalize(mod);673if ((res == 0))674res = _dynUnload(mod);675}676677for (u32 i = 0; i < mod->dependency_count; i++) _dynDecref(mod->dependencies[i]);678679return res;680}681682static void _dynDestroyModule(DynModule *mod) { _dynDecref(mod); }683684static void _dynEraseFromModules(u32 index)685{686if (index >= g_ModuleCount)687return;688u32 i;689for (i = index + 1; i < g_ModuleCount; i++) {690g_ModuleList[i - 1] = g_ModuleList[i];691g_ModuleList[i] = NULL;692}693g_ModuleCount--;694}695696Result dynInitialize()697{698ownHandle = envGetOwnProcessHandle();699if (!envIsSyscallHinted(0x77) || !envIsSyscallHinted(0x78))700return MAKERESULT(Module_LibnxDyn, LibnxDynError_InsufficientSysCalls);701return ldrRoInitialize();702}703704void dynExit() { ldrRoExit(); }705706Result dynLoadFromMemory(const char *name, void *base)707{708if (!name)709return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputNro);710if (!base)711return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputNro);712713DynModule *mod = malloc(sizeof(DynModule));714if (!mod)715return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputNro);716717memset(mod, 0, sizeof(DynModule));718strcpy(mod->input.name, name);719mod->input.has_run_basic_relocations = true;720mod->input.is_global = true;721mod->input.base = base;722mod->input.is_nro = false;723mod->dependency_count = 0;724725mod->ref_count = 1;726mod->state = DynModuleState_Queued;727728Result res = _dynScan(mod);729if (res != 0) {730free(mod);731return res;732}733734res = _dynRelocate(mod);735if (res != 0) {736free(mod);737return res;738}739740res = _dynInitialize(mod);741if (res != 0) {742free(mod);743return res;744}745746g_ModuleList[g_ModuleCount] = mod;747g_ModuleCount++;748749return res;750}751752Result dynLoadNroModule(DynModule *mod, const char *path, bool global)753{754if (path == NULL) {755return MAKERESULT(Module_LibnxDyn, LibnxDynError_InvalidInputNro);756}757758strcpy(mod->input.name, path);759mod->input.has_run_basic_relocations = false;760mod->input.is_global = global;761mod->dependency_count = 0;762763Result res = _dynLoad(path, mod);764765if (R_FAILED(res)) {766return res;767}768769mod->ref_count = 1;770mod->state = DynModuleState_Queued;771772res = _dynScan(mod);773if (R_FAILED(res)) {774return res;775}776777res = _dynRelocate(mod);778if (R_FAILED(res)) {779return res;780}781782res = _dynInitialize(mod);783if (R_FAILED(res)) {784return res;785}786787g_ModuleList[g_ModuleCount] = mod;788g_ModuleCount++;789790return res;791}792793void dynModuleUnload(DynModule *mod) { _dynDestroyModule(mod); }794795void dynUnloadMyName(const char *name)796{797for (u32 i = 0; i < g_ModuleCount; i++) {798if (strcmp(name, g_ModuleList[i]->input.name) == 0) {799_dynDestroyModule(g_ModuleList[i]);800_dynEraseFromModules(i);801break;802}803}804}805806void dynUnloadAll()807{808for (u32 i = 0; i < g_ModuleCount; i++) {809_dynDestroyModule(g_ModuleList[i]);810g_ModuleList[i] = NULL;811}812g_ModuleCount = 0;813}814815Result dynModuleLookupSymbol(DynModule *mod, const char *name, void **out_sym)816{817Elf64_Sym *def;818DynModule *def_mod;819820Result res = _dynResolveDependencySymbol(mod, name, &def, &def_mod);821if (R_SUCCEEDED(res)) {822*out_sym = (u8 *)mod->input.base + def->st_value;823}824return res;825}826827828