// fstubOffset and markOffset should be relative to segment static int addStub(Psp2_Rela *relaFstub, const scn_t *fstub, Elf32_Word *fnid, const scn_t *relMark, const scn_t *mark, Elf32_Addr fstubOffset, Elf32_Addr markOffset, const scn_t *scns, const seg_t *segs, const char *strtab, const Elf32_Sym *symtab) { const Elf32_Rel *rel; const Elf32_Sym *sym; Elf32_Word type; Elf32_Half symseg; Elf32_Addr addend; if (relaFstub == NULL || fstub == NULL || fnid == NULL || relMark == NULL || relMark->content == NULL || mark == NULL || mark->content == NULL || scns == NULL || symtab == NULL) { return EINVAL; } rel = findRelByOffset(relMark, markOffset + offsetof(sce_libgen_mark_stub, stub), 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(relaFstub, 0); PSP2_R_SET_SYMSEG(relaFstub, symseg); PSP2_R_SET_TYPE(relaFstub, type); PSP2_R_SET_DATSEG(relaFstub, fstub->phndx); PSP2_R_SET_OFFSET(relaFstub, fstubOffset); if (type == R_ARM_ABS32 || type == R_ARM_TARGET1) { if (mark->content == NULL) return EINVAL; addend = *(Elf32_Word *)((uintptr_t)mark->content + rel->r_offset - mark->shdr.sh_addr); } else addend = sym->st_value; addend -= segs[symseg].phdr.p_vaddr; PSP2_R_SET_ADDEND(relaFstub, addend); *fnid = *(Elf32_Word *)((uintptr_t)mark->content + markOffset - mark->shdr.sh_addr + offsetof(sce_libgen_mark_stub, nid)); 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; }