int updateModinfo(FILE *fp, const scn_t *scns, Elf32_Half shnum, const sceScns_t *sceScns, Elf32_Addr base, const syslib_t *syslib, const char *strtab, const char *str) { unsigned char md[SHA_DIGEST_LENGTH]; _sceModuleInfo *info; const scn_t *sp; int res; if (fp == NULL || scns == NULL || sceScns == NULL || sceScns->relEnt->content == NULL || strtab == NULL || str == NULL) { return EINVAL; } if (sceScns->modinfo->orgSize != sizeof(_sceModuleInfo)) return EILSEQ; res = loadScn(fp, sceScns->modinfo, str); if (res) return res; info = sceScns->modinfo->content; info->expTop = sceScns->ent->shdr.sh_addr - base; info->expBtm = info->expTop + sceScns->ent->shdr.sh_size; info->impTop = sceScns->stub->shdr.sh_addr - base; info->impBtm = info->impTop + sceScns->stub->shdr.sh_size; info->start = syslib->start - base; info->stop = syslib->stop - base; sp = findScnByType(scns, shnum, SHT_ARM_EXIDX, NULL); if (sp != NULL) { info->exidxTop = sp->segOffset; info->exidxBtm = info->exidxTop + sp->shdr.sh_size; } sp = findScnByName(scns, shnum, strtab, ".ARM.extab", NULL); if (sp != NULL) { info->extabTop = sp->segOffset; info->extabBtm = info->extabTop + sp->shdr.sh_size; } if (info->nid == 0) { SHA1((unsigned char *)info->name, strlen(info->name), md); ((unsigned char *)&info->nid)[0] = md[3]; ((unsigned char *)&info->nid)[1] = md[2]; ((unsigned char *)&info->nid)[2] = md[1]; ((unsigned char *)&info->nid)[3] = md[0]; } return 0; }
int updateStubs(sceScns_t *sceScns, FILE *fp, const scn_t *scns, const seg_t *segs, const char *strtab, Elf32_Sym *symtab) { union { uint8_t size; sce_libgen_mark_head head; sce_libgen_mark_stub stub; } *p; sceLib_stub *stubHeads; Psp2_Rela *relaFstubEnt, *relaStubEnt; Elf32_Off offset, fnidOffset, fstubOffset, stubOffset; Elf32_Rel *rel, *relMarkEnt; Elf32_Sym *sym; Elf32_Word i, type, *fnidEnt; Elf32_Half symseg; Elf32_Addr addend; int res; if (sceScns == NULL || fp == NULL || scns == NULL || segs == NULL || strtab == NULL || symtab == NULL) { return EINVAL; } sceScns->relFstub->content = malloc(sceScns->relFstub->shdr.sh_size); if (sceScns->relFstub->content == NULL) { perror(strtab + sceScns->relFstub->shdr.sh_name); return errno; } sceScns->relStub->content = malloc(sceScns->relStub->shdr.sh_size); if (sceScns->relFstub->content == NULL) { perror(strtab + sceScns->relStub->shdr.sh_name); return errno; } sceScns->fnid->content = malloc(sceScns->fnid->shdr.sh_size); if (sceScns->fnid->content == NULL) { perror(strtab + sceScns->fnid->shdr.sh_name); return errno; } sceScns->stub->content = malloc(sceScns->stub->shdr.sh_size); if (sceScns->stub->content == NULL) { perror(strtab + sceScns->stub->shdr.sh_name); return errno; } res = loadScn(fp, sceScns->mark, strtab + sceScns->mark->shdr.sh_name); if (res) return res; res = loadScn(fp, sceScns->relMark, strtab + sceScns->relMark->shdr.sh_name); if (res) return res; relaFstubEnt = sceScns->relFstub->content; relaStubEnt = sceScns->relStub->content; fnidEnt = sceScns->fnid->content; stubHeads = sceScns->stub->content; p = sceScns->mark->content; fnidOffset = sceScns->fnid->segOffset; fstubOffset = sceScns->fstub->segOffset; stubOffset = sceScns->stub->segOffset; offset = 0; while (offset < sceScns->mark->shdr.sh_size) { if (p->size == sizeof(sce_libgen_mark_head)) { stubHeads->size = sizeof(sceLib_stub); stubHeads->ver = 1; stubHeads->flags = 0; stubHeads->nid = p->head.nid; // Resolve name rel = findRelByOffset(sceScns->relMark, sceScns->mark->shdr.sh_addr + offset + offsetof(sce_libgen_mark_head, name), strtab); if (rel == NULL) return errno; type = ELF32_R_TYPE(rel->r_info); sym = symtab + ELF32_R_SYM(rel->r_info); symseg = scns[sym->st_shndx].phndx; PSP2_R_SET_SHORT(relaStubEnt, 0); PSP2_R_SET_SYMSEG(relaStubEnt, symseg); PSP2_R_SET_TYPE(relaStubEnt, type); PSP2_R_SET_DATSEG(relaStubEnt, sceScns->stub->phndx); PSP2_R_SET_OFFSET(relaStubEnt, stubOffset + offsetof(sceLib_stub, name)); PSP2_R_SET_ADDEND(relaStubEnt, (type == R_ARM_ABS32 || type == R_ARM_TARGET1 ? sym->st_value : p->head.name) - segs[symseg].phdr.p_vaddr); relaStubEnt++; // Resolve function NID table PSP2_R_SET_SHORT(relaStubEnt, 0); PSP2_R_SET_SYMSEG(relaStubEnt, sceScns->fnid->phndx); PSP2_R_SET_TYPE(relaStubEnt, R_ARM_ABS32); PSP2_R_SET_DATSEG(relaStubEnt, sceScns->stub->phndx); PSP2_R_SET_OFFSET(relaStubEnt, stubOffset + offsetof(sceLib_stub, funcNids)); PSP2_R_SET_ADDEND(relaStubEnt, fnidOffset); relaStubEnt++; // Resolve function stub table PSP2_R_SET_SHORT(relaStubEnt, 0); PSP2_R_SET_SYMSEG(relaStubEnt, sceScns->fstub->phndx); PSP2_R_SET_TYPE(relaStubEnt, R_ARM_ABS32); PSP2_R_SET_DATSEG(relaStubEnt, sceScns->stub->phndx); PSP2_R_SET_OFFSET(relaStubEnt, stubOffset + offsetof(sceLib_stub, funcStubs)); PSP2_R_SET_ADDEND(relaStubEnt, fstubOffset); relaStubEnt++; // TODO: Support other types stubHeads->varNids = 0; stubHeads->varStubs = 0; stubHeads->unkNids = 0; stubHeads->unkStubs = 0; // Resolve nids and stubs stubHeads->funcNum = 0; stubHeads->varNum = 0; stubHeads->unkNum = 0; relMarkEnt = sceScns->relMark->content; for (i = 0; i < sceScns->relMark->orgSize / sizeof(Elf32_Rel); i++) { sym = symtab + ELF32_R_SYM(relMarkEnt->r_info); type = ELF32_R_TYPE(relMarkEnt->r_info); if (type == R_ARM_ABS32 || type == R_ARM_TARGET1) { if (scns + sym->st_shndx != sceScns->mark) goto cont; addend = *(Elf32_Word *)((uintptr_t)sceScns->mark->content + relMarkEnt->r_offset - sceScns->mark->shdr.sh_addr); } else addend = sym->st_value; if (addend != sceScns->mark->shdr.sh_addr + offset) goto cont; res = addStub(relaFstubEnt, sceScns->fstub, fnidEnt, sceScns->relMark, sceScns->mark, fstubOffset, relMarkEnt->r_offset - offsetof(sce_libgen_mark_stub, head), scns, segs, strtab, symtab); if (res) return res; relaFstubEnt++; fnidEnt++; fstubOffset += sizeof(Elf32_Addr); fnidOffset += sizeof(Elf32_Word); stubHeads->funcNum++; cont: relMarkEnt++; } stubOffset += sizeof(sceLib_stub); stubHeads++; } else if (p->size == 0) { printf("%s: Invalid mark\n", strtab + sceScns->mark->shdr.sh_name); return EILSEQ; } offset += p->size; p = (void *)((uintptr_t)p + p->size); } sceScns->relFstub->shdr.sh_type = SHT_PSP2_RELA; sceScns->relStub->shdr.sh_type = SHT_PSP2_RELA; return 0; }
int findSyslib(syslib_t *syslib, FILE *fp, scn_t *scns, Elf32_Half shnum, const seg_t *segs, const seg_t *rela, const char *strtab, const Elf32_Sym *symtab, scn_t *ent, const scn_t *relEnt) { const Elf32_Rel *rel; const Elf32_Sym *sym; const Elf32_Word *nids; Elf32_Word i, stubOffset, type, *p; const scn_t *stubRel; scn_t *scn; int res; if (syslib == NULL || fp == NULL || scns == NULL || segs == NULL || rela == NULL || strtab == NULL || symtab == NULL || ent == NULL || relEnt == NULL || relEnt->content == NULL) { return EINVAL; } if (ent->content == NULL) { res = loadScn(fp, ent, strtab + ent->shdr.sh_name); if (res) return res; } // Stub Table rel = findRelByOffset(relEnt, ent->shdr.sh_addr + 28, strtab); if (rel == NULL) return errno; sym = symtab + ELF32_R_SYM(rel->r_info); scn = scns + sym->st_shndx; type = ELF32_R_TYPE(rel->r_info); stubOffset = (type == R_ARM_ABS32 || type == R_ARM_TARGET1 ? *(Elf32_Word *)((uintptr_t)ent->content + 28) : sym->st_value) - segs[scn->phndx].phdr.p_vaddr; i = 0; do { if (i >= rela->shnum) { fprintf(stderr, "%s: Relocation table not found\n", strtab + scn->shdr.sh_name); return EILSEQ; } stubRel = rela->scns[i]; i++; } while (stubRel->shdr.sh_info != sym->st_shndx); // NID Table rel = findRelByOffset(relEnt, ent->segOffset + 24, strtab); if (rel == NULL) return errno; sym = symtab + ELF32_R_SYM(rel->r_info); scn = scns + sym->st_shndx; if (scn->content == NULL) { res = loadScn(fp, scn, strtab + scn->shdr.sh_name); if (res) return res; } type = ELF32_R_TYPE(rel->r_info); nids = (void *)((uintptr_t)scn->content + (type == R_ARM_ABS32 || type == R_ARM_TARGET1 ? *(Elf32_Word *)((uintptr_t)ent->content + 24) : sym->st_value) - scn->shdr.sh_addr); // Resolve for (i = 0; i < ((Elf32_Half *)ent->content)[3]; i++) { if (nids[i] == 0x935CD196) p = &syslib->start; else if (nids[i] == 0x79F8E492) p = &syslib->stop; else continue; rel = findRelByOffset(stubRel, stubOffset + i * 4, strtab); if (rel == NULL) return errno; *p = symtab[ELF32_R_SYM(rel->r_info)].st_value; } return 0; }
int openElf(elf_t *dst, const char *path) { int res; if (dst == NULL || path == NULL) return EINVAL; dst->path = path; dst->fp = fopen(path, "rb"); if (dst->fp == NULL) { perror(path); return errno; } if (fread(&dst->ehdr, sizeof(dst->ehdr), 1, dst->fp) <= 0) { if (feof(dst->fp)) { fprintf(stderr, "%s: Unexpected EOF\n", path); errno = EILSEQ; } else perror(path); fclose(dst->fp); return errno; } dst->orgShnum = dst->ehdr.e_shnum; dst->scns = getScns(dst->fp, path, &dst->ehdr); if (dst->scns == NULL) { fclose(dst->fp); return errno; } dst->strtab = dst->scns + dst->ehdr.e_shstrndx; res = loadScn(dst->fp, dst->strtab, path); if (res) { free(dst->scns); fclose(dst->fp); return res; } dst->symtab = findScnByType(dst->scns, dst->ehdr.e_shnum, SHT_SYMTAB, path); if (dst->symtab == NULL) { free(dst->scns); free(dst->strtab->content); fclose(dst->fp); return errno; } res = loadScn(dst->fp, dst->symtab, (void *)((uintptr_t)dst->strtab->content + dst->symtab->shdr.sh_name)); if (res) { free(dst->scns); free(dst->strtab->content); fclose(dst->fp); return res; } res = getSceScns(&dst->sceScns, dst->scns, dst->ehdr.e_shnum, dst->strtab->content, path); if (res) { free(dst->scns); free(dst->strtab->content); free(dst->symtab->content); fclose(dst->fp); return res; } dst->segs = getSegs(dst->fp, path, &dst->ehdr, dst->scns, &dst->rela, dst->sceScns.relMark); if (dst->segs == NULL) { free(dst->scns); free(dst->strtab->content); free(dst->symtab->content); fclose(dst->fp); return errno; } return 0; }