Skip to content

Instantly share code, notes, and snippets.

@psxdev
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save psxdev/6613c66bf9e8bbf52248 to your computer and use it in GitHub Desktop.
Save psxdev/6613c66bf9e8bbf52248 to your computer and use it in GitHub Desktop.
with osx mavericks and libelf installed elf.h is gelf.h and i include arm.h for extrs definition : gcc -I/opt/local/include -I./include psp2-fixup.c -o psp2-fixup
#include <errno.h>
#ifdef __APPLE__
//in osx mavericks with macport libelf elf.h is gelf.h
#include <libelf/gelf.h>
#elif __linux
#include <elf.h>
#endif
//we need some definition form include/elf/arm.h
#include <elf/arm.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
uint8_t size;
uint8_t unk0[3];
uint32_t nid;
uint32_t name;
uint32_t ver;
uint32_t unk[2];
} sce_libgen_mark_head;
typedef struct {
uint8_t size;
uint8_t unk0[3];
uint32_t head;
uint32_t stub;
uint32_t nid;
uint32_t nidSym;
} sce_libgen_mark_stub;
typedef struct {
uint16_t size;
uint16_t ver;
uint16_t flags;
uint16_t funcNum;
uint16_t varNum;
uint16_t unkNum;
uint32_t unused0;
uint32_t nid;
uint32_t name;
uint32_t unused1;
uint32_t funcNids;
uint32_t funcStubs;
uint32_t varNids;
uint32_t varStubs;
uint32_t unkNids;
uint32_t unkStubs;
} sceLib_stub;
typedef struct {
Elf32_Word r_short : 4;
Elf32_Word r_symseg : 4;
Elf32_Word r_code : 8;
Elf32_Word r_datseg : 4;
Elf32_Word r_offset : 32;
Elf32_Word r_addend : 12;
} Psp2_Rela_Short;
typedef struct {
Elf32_Addr addrDiff;
Elf32_Word orgOffset;
Elf32_Word orgSize;
Elf32_Half phndx;
Elf32_Word segOffset;
Elf32_Shdr shdr;
} scn_t;
typedef struct {
Elf32_Phdr phdr;
Elf32_Half shnum;
scn_t **scns;
} seg_t;
enum {
ET_SCE_RELEXEC = 0xFE04
};
enum {
SHT_SCE_RELA = 0x60000000
};
static void *loadScn(FILE *fp, const char *path, const scn_t *scn,
const char *strtab)
{
void *p;
if (fp == NULL || scn == NULL)
return NULL;
if (fseek(fp, scn->shdr.sh_offset, SEEK_SET)) {
if (strtab != NULL)
perror(strtab + scn->shdr.sh_name);
else if (path != NULL)
perror(path);
return NULL;
}
p = malloc(scn->shdr.sh_size);
if (p == NULL) {
if (strtab != NULL)
perror(strtab + scn->shdr.sh_name);
else if (path != NULL)
perror(path);
return NULL;
}
if (fread(p, scn->shdr.sh_size, 1, fp) <= 0) {
if (strtab != NULL)
perror(strtab + scn->shdr.sh_name);
else if (path != NULL)
perror(path);
free(p);
return NULL;
}
return p;
}
static scn_t *getScns(FILE *fp, const char *path, const Elf32_Ehdr *ehdr)
{
scn_t *scns;
Elf32_Half i;
if (fseek(fp, ehdr->e_shoff, SEEK_SET)) {
perror(path);
return NULL;
}
scns = malloc(ehdr->e_shnum * sizeof(scn_t));
if (scns == NULL) {
perror(NULL);
return NULL;
}
for (i = 0; i < ehdr->e_shnum; i++) {
if (fread(&scns[i].shdr, sizeof(scns[i].shdr), 1, fp) <= 0) {
perror(path);
free(scns);
return NULL;
}
scns[i].orgOffset = scns[i].shdr.sh_offset;
scns[i].orgSize = scns[i].shdr.sh_size;
}
return scns;
}
static void mapOverScnSeg(void (* f)(scn_t *, seg_t *, Elf32_Half),
scn_t *scns, seg_t *segs, const Elf32_Ehdr *ehdr)
{
Elf32_Half i, j;
Elf32_Phdr *phdr;
for (i = 0; i < ehdr->e_shnum; i++)
for (j = 0; j < ehdr->e_phnum; j++) {
phdr = &segs[j].phdr;
if (phdr->p_offset <= scns[i].shdr.sh_offset
&& scns[i].shdr.sh_offset + scns[i].shdr.sh_size
<= phdr->p_offset + phdr->p_filesz)
f(scns + i, segs + j, j);
}
}
static void segCntScns(scn_t *scn, seg_t *seg, Elf32_Half index)
{
seg->shnum++;
}
static void segCntMapScns(scn_t *scn, seg_t *seg, Elf32_Half index)
{
scn->phndx = index;
scn->segOffset = scn->shdr.sh_offset - seg->phdr.p_offset;
seg->scns[seg->shnum] = scn;
seg->shnum++;
}
/* Load phdrs and scns included in the sections. scns will be sorted. */
static seg_t *getSegs(FILE *fp, const char *path,
const Elf32_Ehdr *ehdr, const scn_t *scns)
{
Elf32_Half i, j, k;
scn_t *tmp;
seg_t *segs;
if (fp == NULL || path == NULL || ehdr == NULL || scns == NULL)
return NULL;
segs = malloc(ehdr->e_phnum * sizeof(seg_t));
if (segs == NULL) {
perror(path);
return NULL;
}
if (fseek(fp, ehdr->e_phoff, SEEK_SET)) {
perror(path);
return NULL;
}
for (i = 0; i < ehdr->e_phnum; i++) {
if (fread(&segs[i].phdr, sizeof(segs[i].phdr), 1, fp) <= 0) {
perror(path);
free(segs);
return NULL;
}
segs[i].shnum = 0;
}
mapOverScnSeg(segCntScns, (scn_t *)scns, segs, ehdr);
for (i = 0; i < ehdr->e_phnum; i++) {
segs[i].scns = malloc(segs[i].shnum * sizeof(scn_t));
if (segs[i].scns == NULL) {
perror(NULL);
while (i) {
i--;
free(segs[i].scns);
}
free(segs);
return NULL;
}
segs[i].shnum = 0;
}
mapOverScnSeg(segCntMapScns, (scn_t *)scns, segs, ehdr);
for (i = 0; i < ehdr->e_phnum; i++) {
for (j = 1; j < segs[i].shnum; j++) {
tmp = segs[i].scns[j];
if (segs[i].scns[j - 1]->shdr.sh_addr > tmp->shdr.sh_addr) {
k = j;
do {
segs[i].scns[k] = segs[i].scns[k - 1];
k--;
} while (k > 0 &&
segs[i].scns[k - 1]->shdr.sh_addr > tmp->shdr.sh_addr);
segs[i].scns[k] = tmp;
}
}
}
return segs;
}
static scn_t *getSymtabScn(const char *path, scn_t *scns, Elf32_Half shnum)
{
while (shnum) {
if (scns->shdr.sh_type == SHT_SYMTAB)
return scns;
scns++;
shnum--;
}
fprintf(stderr, "%s: Symbol Table is not found.\n", path);
return NULL;
}
static int freeSegs(seg_t *segs, Elf32_Half segnum)
{
seg_t *p;
if (segs == NULL)
return EINVAL;
p = segs;
while (segnum) {
free(p->scns);
p++;
segnum--;
}
free(segs);
return 0;
}
static scn_t *findScn(const scn_t *scns, Elf32_Half shnum,
const char *strtab, const char *name, const char *path)
{
if (scns == NULL || strtab == NULL || name == NULL || path == NULL)
return NULL;
while (shnum) {
if (!strcmp(strtab + scns->shdr.sh_name, name))
return (scn_t *)scns;
scns++;
shnum--;
}
fprintf(stderr, "%s: %s is not found\n", path, name);
errno = EILSEQ;
return NULL;
}
static int updateSegs(seg_t *segs, Elf32_Half segnum, const char *strtab)
{
scn_t *scn;
seg_t **sorts, *tmp;
Elf32_Addr addr, newAddr;
Elf32_Off offset;
Elf32_Half i, j;
Elf32_Word and, gap;
if (segs == NULL || strtab == NULL)
return EINVAL;
sorts = malloc(segnum * sizeof(seg_t *));
if (sorts == NULL) {
perror(NULL);
return errno;
}
for (i = 0; i < segnum; i++)
sorts[i] = segs + i;
for (i = 1; i < segnum; i++) {
tmp = sorts[i];
if (sorts[i - 1]->phdr.p_vaddr > tmp->phdr.p_vaddr) {
j = i;
do {
sorts[j] = sorts[j - 1];
j--;
} while (j > 0 && sorts[j - 1]->phdr.p_vaddr > tmp->phdr.p_vaddr);
sorts[j] = tmp;
}
}
addr = sorts[0]->phdr.p_vaddr;
for (i = 1; i < segnum; i++) {
and = sorts[i]->phdr.p_align - 1;
if (addr & and)
addr = (addr & ~and) + sorts[i]->phdr.p_align;
sorts[i]->phdr.p_vaddr = addr;
sorts[i]->phdr.p_memsz -= sorts[i]->phdr.p_filesz;
sorts[i]->phdr.p_filesz = 0;
for (j = 0; j < sorts[i]->shnum; j++) {
scn = sorts[i]->scns[j];
newAddr = addr;
gap = addr & (scn->shdr.sh_addralign - 1);
if (gap)
newAddr += scn->shdr.sh_addralign - gap;
gap = newAddr - addr;
if (gap)
sorts[i]->phdr.p_filesz += gap;
/* It doesn't back up sh_type, but it doesn't matter
because writeSegs assume sections whose sh_type were
SHT_REL */
if (scn->shdr.sh_type == SHT_REL)
scn->shdr.sh_type = SHT_SCE_RELA;
scn->addrDiff = addr - scn->shdr.sh_addr;
scn->segOffset = addr - sorts[i]->phdr.p_vaddr;
scn->shdr.sh_addr = addr;
if (scn->shdr.sh_type == SHT_SCE_RELA
&& scn->orgSize == scn->shdr.sh_size)
{
scn->shdr.sh_size /= sizeof(Elf32_Rel);
scn->shdr.sh_size *= sizeof(Psp2_Rela_Short);
}
sorts[i]->phdr.p_filesz += scn->shdr.sh_size;
addr += scn->shdr.sh_size;
}
sorts[i]->phdr.p_memsz += sorts[i]->phdr.p_filesz;
}
for (i = 1; i < segnum; i++) {
tmp = sorts[i];
if (sorts[i - 1]->phdr.p_offset > tmp->phdr.p_offset) {
j = i;
do {
sorts[j] = sorts[j - 1];
j--;
} while (j > 0 && sorts[j - 1]->phdr.p_offset > tmp->phdr.p_offset);
sorts[j] = tmp;
}
}
offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * segnum;
for (i = 0; i < segnum; i++) {
and = sorts[i]->phdr.p_align - 1;
if (offset & and)
offset = (offset & ~and) + sorts[i]->phdr.p_align;
sorts[i]->phdr.p_offset = offset;
for (j = 0; j < sorts[i]->shnum; j++) {
scn = sorts[i]->scns[j];
scn->shdr.sh_offset = offset + scn->segOffset;
}
offset += sorts[i]->phdr.p_filesz;
}
for (i = 1; i < segnum; i++) {
tmp = sorts[i];
if (sorts[i - 1]->phdr.p_paddr > tmp->phdr.p_paddr) {
j = i;
do {
sorts[j] = sorts[j - 1];
j--;
} while (j > 0 && sorts[j - 1]->phdr.p_paddr > tmp->phdr.p_paddr);
sorts[j] = tmp;
}
}
addr = sorts[0]->phdr.p_paddr;
for (i = 1; i < segnum; i++) {
and = sorts[i]->phdr.p_align - 1;
if (addr & and)
addr = (addr & ~and) + sorts[i]->phdr.p_align;
sorts[i]->phdr.p_paddr = addr;
addr += sorts[i]->phdr.p_memsz;
}
return 0;
}
static int updateSymtab(Elf32_Sym *symtab, Elf32_Word size, scn_t *scns)
{
if (symtab == NULL || scns == NULL)
return EINVAL;
while (size) {
symtab->st_value -= scns[symtab->st_shndx].addrDiff;
symtab++;
size -= sizeof(Elf32_Sym);
}
return 0;
}
static int updateEhdr(Elf32_Ehdr *ehdr, const char *path,
seg_t *segs, scn_t *modinfo)
{
Elf32_Off offset;
int i, j;
if (ehdr == NULL || segs == NULL)
return EINVAL;
ehdr->e_type = ET_SCE_RELEXEC;
for (i = 0; i < ehdr->e_phnum || i < 4; i++)
for (j = 0; j < segs[i].shnum; j++)
if (segs[i].scns[j] == modinfo)
goto found;
fprintf(stderr, "%s: .sceModuleInfo.rodata not found\n", path);
return EILSEQ;
found:
offset = modinfo->shdr.sh_offset - segs[i].phdr.p_offset;
if (offset >= 1 << 30) {
fprintf(stderr, "%s: .sceModuleInfo.rodata is invalid\n", path);
return EILSEQ;
}
ehdr->e_entry = (i << 30) | offset;
ehdr->e_phoff = sizeof(Elf32_Ehdr);
ehdr->e_shoff = 0;
ehdr->e_shentsize = 0;
ehdr->e_shnum = 0;
ehdr->e_shstrndx = 0;
return 0;
}
static int writeRel(FILE *dstFp, const char *dst,
FILE *srcFp, const char *src, const scn_t *scn, const seg_t *seg,
const scn_t *scns, const Elf32_Sym *symtab, const scn_t *modinfo)
{
Psp2_Rela_Short rela;
const scn_t *dstScn;
Elf32_Rel rel;
const Elf32_Sym *sym;
Elf32_Word i, j, type;
if (dstFp == NULL || dst == NULL || srcFp == NULL || src == NULL
|| scn == NULL || scns == NULL || symtab == NULL)
{
return EINVAL;
}
dstScn = scns + scn->shdr.sh_info;
for (i = 0; i < scn->orgSize; i += sizeof(rel)) {
if (fread(&rel, sizeof(rel), 1, srcFp) <= 0) {
perror(src);
return errno;
}
type = ELF32_R_TYPE(rel.r_info);
if (type == R_ARM_NONE || type == R_ARM_TARGET2)
continue;
sym = symtab + ELF32_R_SYM(rel.r_info);
rela.r_short = 1;
rela.r_symseg = scns[sym->st_shndx].phndx;
rela.r_code = type;
rela.r_datseg = dstScn->phndx;
if (dstScn == modinfo) {
rela.r_addend = scns[sym->st_shndx].shdr.sh_offset;
switch (rel.r_offset) {
case 40: // The bottom of the export table
case 48: // The bottom of the import table
rela.r_addend += scns[sym->st_shndx].shdr.sh_size;
case 36: // The top of the export table
case 44: // The top of the import table
break;
default:
goto usual;
}
} else {
usual:
rela.r_addend = sym->st_value;
if (type == R_ARM_ABS32 || type == R_ARM_TARGET1) {
if (fseek(srcFp, dstScn->orgOffset + rel.r_offset, SEEK_SET)) {
perror(src);
return errno;
}
if (fread(&j, sizeof(j), 1, srcFp) <= 0) {
perror(src);
return errno;
}
rela.r_addend += j;
}
}
rela.r_offset = dstScn->segOffset + rel.r_offset;
if (fwrite(&rela, sizeof(rela), 1, dstFp) != 1) {
perror(dst);
return errno;
}
}
return 0;
}
static int addStub(Psp2_Rela_Short *relaFstub, const scn_t *fstub,
uint32_t *fnid, const Elf32_Rel *relMark, Elf32_Word relMarkSize,
const void *mark, Elf32_Addr offset,
const scn_t *scns, const Elf32_Sym *symtab)
{
const Elf32_Sym *sym;
Elf32_Word i, type;
if (relaFstub == NULL || fnid == NULL
|| relMark == NULL || mark == NULL)
{
return EINVAL;
}
for (i = 0; i < relMarkSize / sizeof(Elf32_Rel); i++) {
if (relMark[i].r_offset == offset
+ offsetof(sce_libgen_mark_stub, stub))
{
type = ELF32_R_TYPE(relMark[i].r_info);
sym = symtab + ELF32_R_SYM(relMark[i].r_info);
relaFstub->r_short = 1;
relaFstub->r_symseg = scns[sym->st_shndx].phndx;
relaFstub->r_code = type;
relaFstub->r_datseg = fstub->phndx;
relaFstub->r_addend = sym->st_value;
if (type == R_ARM_ABS32 || type == R_ARM_TARGET1)
relaFstub->r_addend
+= *(uint32_t *)((uintptr_t)mark + relMark[i].r_offset);
relaFstub->r_offset = fstub->segOffset + relMark[i].r_offset;
}
}
*fnid = *(uint32_t *)((uintptr_t)mark + offset
+ offsetof(sce_libgen_mark_stub, nid));
return 0;
}
static int buildStubs(void **relaFstubContent, void **relaStubContent,
void **fnidContent, void **stubContent, Elf32_Half fstubPhndx,
scn_t *relaFstub, scn_t *relMark, scn_t *relStub,
scn_t *fnid, scn_t *fstub, scn_t *stub, scn_t *mark, FILE *srcFp,
const scn_t *scns, const char *strtab, Elf32_Sym *symtab)
{
union {
uint8_t size;
sce_libgen_mark_head head;
sce_libgen_mark_stub stub;
} *markContent, *p;
sceLib_stub *stubHeads;
Psp2_Rela_Short *relaFstubEnt, *relaStubEnt;
Elf32_Off offset, fnidOffset, fstubOffset;
Elf32_Rel *relMarkContent, *relMarkEnt;
Elf32_Sym *sym;
Elf32_Word i, *fnidEnt;
if (relaFstubContent == NULL || relaStubContent == NULL
|| fnidContent == NULL || stubContent == NULL
|| mark == NULL || relMark == NULL
|| relStub == NULL || fnid == NULL || fstub == NULL
|| stub == NULL || mark == NULL || srcFp == NULL
|| scns == NULL || strtab == NULL || symtab == NULL)
{
return EINVAL;
}
markContent = malloc(mark->shdr.sh_size);
if (markContent == NULL) {
perror(strtab + mark->shdr.sh_name);
return errno;
}
relMarkContent = malloc(relMark->shdr.sh_size);
if (relMarkContent == NULL) {
perror(strtab + relMark->shdr.sh_name);
return errno;
}
*relaFstubContent = malloc(relaFstub->shdr.sh_size);
if (*relaFstubContent == NULL) {
perror(strtab + relaFstub->shdr.sh_name);
return errno;
}
*relaStubContent = malloc(relStub->shdr.sh_size);
if (*relaStubContent == NULL) {
perror(strtab + relStub->shdr.sh_name);
return errno;
}
*fnidContent = malloc(fnid->shdr.sh_size);
if (*fnidContent == NULL) {
perror(strtab + fnid->shdr.sh_name);
return errno;
}
*stubContent = malloc(stub->shdr.sh_size);
if (*stubContent == NULL) {
perror(strtab + stub->shdr.sh_name);
return errno;
}
if (fseek(srcFp, mark->orgOffset, SEEK_SET)) {
perror(strtab + mark->shdr.sh_name);
return errno;
}
if (fread(markContent, mark->shdr.sh_size, 1, srcFp)) {
perror(strtab + mark->shdr.sh_name);
return errno;
}
if (fseek(srcFp, relMark->orgOffset, SEEK_SET)) {
perror(strtab + relMark->shdr.sh_name);
return errno;
}
if (fread(relMarkContent, relMark->shdr.sh_size, 1, srcFp)) {
perror(strtab + relMark->shdr.sh_name);
return errno;
}
relaFstubEnt = *relaFstubContent;
relaStubEnt = *relaStubContent;
fnidEnt = *fnidContent;
stubHeads = *stubContent;
relMarkEnt = relMarkContent;
p = markContent;
fnidOffset = 0;
fstubOffset = 0;
for (offset = 0; offset < mark->shdr.sh_size; offset += p->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;
relaStubEnt->r_short = 1;
relaStubEnt->r_symseg = fnid->phndx;
relaStubEnt->r_code = R_ARM_ABS32;
relaStubEnt->r_datseg = stub->phndx;
relaStubEnt->r_addend = fnidOffset;
relaStubEnt->r_offset = mark->segOffset
+ offset + offsetof(sceLib_stub, funcNids);
relaStubEnt->r_short = 1;
relaStubEnt->r_symseg = fstubPhndx;
relaStubEnt->r_code = R_ARM_ABS32;
relaStubEnt->r_datseg = stub->phndx;
relaStubEnt->r_addend = fstubOffset;
relaStubEnt->r_offset = mark->segOffset
+ offset + offsetof(sceLib_stub, funcStubs);
stubHeads->varNids = 0;
stubHeads->varStubs = 0;
stubHeads->unkNids = 0;
stubHeads->unkStubs = 0;
stubHeads->funcNum = 0;
stubHeads->varNum = 0;
stubHeads->unkNum = 0;
for (i = 0; i < relMark->shdr.sh_size / sizeof(Elf32_Rel); i++) {
sym = symtab + ELF32_R_SYM(relMarkEnt[i].r_info);
if (sym->st_value != stub->shdr.sh_offset + offset)
continue;
addStub(relaFstubEnt, fstub, fnidEnt,
relMarkContent, relMark->shdr.sh_size,
markContent,
relMarkEnt[i].r_offset
- offsetof(sce_libgen_mark_stub, head),
scns, symtab);
relaFstubEnt++;
fnidEnt++;
fstubOffset += sizeof(Psp2_Rela_Short);
fnidOffset += 4;
stubHeads->funcNum++;
}
stubHeads++;
}
p = (void *)((uintptr_t)p + p->size);
}
free(markContent);
free(relMarkContent);
return 0;
}
static int writeScn(FILE *dstFp, const char *dst,
FILE *srcFp, const char *src, const seg_t *seg, unsigned int index,
const char *strtab)
{
void *p;
if (dstFp == NULL || dst == NULL || srcFp == NULL || src == NULL
|| seg == NULL)
{
return EINVAL;
}
p = malloc(seg->scns[index]->orgSize);
if (p == NULL) {
perror(strtab + seg->scns[index]->shdr.sh_name);
return EINVAL;
}
if (fread(p, seg->scns[index]->orgSize, 1, srcFp) <= 0) {
perror(strtab + seg->scns[index]->shdr.sh_name);
free(p);
return errno;
}
free(p);
return 0;
}
static int writeSegs(FILE *dstFp, const char *dst,
FILE *srcFp, const char *src,
const char *strtab, const Elf32_Sym *symtab,
const Elf32_Ehdr *ehdr, const scn_t *scns, const seg_t *segs,
const scn_t *relaFstub, const scn_t *relaStub,
const scn_t *fnid, const scn_t *stub, const scn_t *modinfo,
const void *relaFstubContent, const void *relaStubContent,
const void *fnidContent, const void *stubContent)
{
Elf32_Half i, j;
int res;
if (dstFp == NULL || dst == NULL || srcFp == NULL || src == NULL
|| ehdr == NULL || scns == NULL || segs == NULL
|| relaFstub == NULL || relaStub == NULL || stub == NULL
|| relaFstubContent == NULL || relaStubContent == NULL
|| stubContent == NULL)
{
return EINVAL;
}
if (fseek(dstFp, ehdr->e_phoff, SEEK_SET)) {
perror(dst);
return errno;
}
for (i = 0; i < ehdr->e_phnum; i++)
if (fwrite(&segs[i].phdr, sizeof(segs[i].phdr), 1, dstFp) != 1) {
perror(dst);
return errno;
}
for (i = 0; i < ehdr->e_phnum; i++) {
for (j = 0; j < segs->shnum; j++) {
if (fseek(srcFp, segs->scns[j]->orgOffset, SEEK_SET)) {
perror(strtab + segs->scns[j]->shdr.sh_name);
return errno;
}
if (fseek(dstFp, segs->scns[j]->shdr.sh_offset, SEEK_SET)) {
perror(strtab + segs->scns[j]->shdr.sh_name);
return errno;
}
// Refer to updateSegs
if (segs->scns[j]->shdr.sh_type == SHT_SCE_RELA) {
if (segs->scns[j] == relaFstub) {
if (fwrite(relaFstubContent, relaFstub->shdr.sh_size, 1, dstFp) != 1) {
perror(strtab + relaFstub->shdr.sh_name);
res = errno;
}
} else if (segs->scns[j] == relaStub) {
if (fwrite(relaStubContent, relaStub->shdr.sh_size, 1, dstFp) != 1) {
perror(strtab + relaStub->shdr.sh_name);
res = errno;
}
} else
res = writeRel(dstFp, dst, srcFp, src,
segs->scns[j], segs,
scns, symtab, modinfo);
} else if (segs->scns[j] == fnid) {
if (fwrite(fnidContent, fnid->shdr.sh_size, 1, dstFp) != 1) {
perror(strtab + fnid->shdr.sh_name);
res = errno;
}
} else if (segs->scns[j] == stub) {
if (fwrite(stubContent, stub->shdr.sh_size, 1, dstFp) != 1) {
perror(strtab + stub->shdr.sh_name);
res = errno;
}
} else
res = writeScn(dstFp, dst, srcFp, src,
segs, j, strtab);
if (res)
return res;
}
segs++;
}
return 0;
}
int main(int argc, char *argv[])
{
scn_t *relMark, *relFstub, *relStub;
scn_t *fnid, *fstub, *stub, *mark, *symtabScn, *modinfo, *scns;
seg_t *segs;
FILE *srcFp, *dstFp;
Elf32_Ehdr ehdr;
Elf32_Sym *symtab;
Elf32_Word headNum;
void *relaFstubContent, *relaStubContent, *fnidContent, *stubContent;
char *src, *dst, *strtab;
int res;
if (argc != 3) {
fprintf(stderr, "%s: Usage <INPUT> <OUTPUT>\n", argv[0]);
return EINVAL;
}
src = argv[1];
dst = argv[2];
srcFp = fopen(src, "rb");
if (srcFp == NULL) {
perror(src);
return errno;
}
dstFp = fopen(dst, "wb");
if (dstFp == NULL) {
perror(dst);
fclose(srcFp);
return errno;
}
if (fread(&ehdr, sizeof(ehdr), 1, srcFp) <= 0) {
perror(src);
fclose(srcFp);
fclose(dstFp);
return errno;
}
scns = getScns(srcFp, src, &ehdr);
if (scns == NULL) {
fclose(srcFp);
fclose(dstFp);
return errno;
}
segs = getSegs(srcFp, src, &ehdr, scns);
if (segs == NULL) {
free(scns);
fclose(srcFp);
fclose(dstFp);
return errno;
}
strtab = loadScn(srcFp, src, scns + ehdr.e_shstrndx, NULL);
if (strtab == NULL) {
free(scns);
freeSegs(segs, ehdr.e_phnum);
fclose(srcFp);
fclose(dstFp);
return errno;
}
symtabScn = getSymtabScn(src, scns, ehdr.e_shnum);
if (symtabScn == NULL) {
free(scns);
freeSegs(segs, ehdr.e_phnum);
fclose(srcFp);
fclose(dstFp);
return errno;
}
symtab = loadScn(srcFp, src, symtabScn, strtab);
if (symtab == NULL) {
res = errno;
goto fail;
}
relMark = findScn(scns, ehdr.e_shnum, strtab, ".rel.sce_libgen_mark", src);
if (relMark == NULL) {
res = errno;
goto fail;
}
mark = scns + relMark->shdr.sh_info;
relFstub = findScn(scns, ehdr.e_shnum, strtab, ".rel.sceFStub.rodata", src);
if (relFstub == NULL) {
res = errno;
goto fail;
}
fstub = scns + relFstub->shdr.sh_info;
fnid = findScn(scns, ehdr.e_shnum, strtab, ".sceFNID.rodata", src);
if (fnid == NULL) {
res = errno;
goto fail;
}
relStub = findScn(scns, ehdr.e_shnum, strtab, ".rel.sceLib.stub", src);
if (relStub == NULL) {
res = errno;
goto fail;
}
stub = scns + relStub->shdr.sh_info;
modinfo = findScn(scns, ehdr.e_shnum, strtab, ".sceModuleInfo.rodata", src);
if (modinfo == NULL) {
res = errno;
goto fail;
}
/* mark->sh_size == (the number of the heads) * 24 + (the number of the stubs) * 20
fnid->sh_size == (the number of stubs) * 4 */
headNum = (mark->shdr.sh_size - fnid->shdr.sh_size / 4 * sizeof(sce_libgen_mark_stub))
/ sizeof(sce_libgen_mark_head);
relFstub->shdr.sh_size = fstub->shdr.sh_size / 4 * sizeof(Psp2_Rela_Short);
relStub->shdr.sh_size = headNum * 6 * sizeof(Psp2_Rela_Short);
stub->shdr.sh_size = headNum * sizeof(sceLib_stub);
res = updateSegs(segs, ehdr.e_phnum, strtab);
if (res)
goto fail;
res = updateEhdr(&ehdr, src, segs, modinfo);
if (res)
goto fail;
if (fwrite(&ehdr, sizeof(Elf32_Ehdr), 1, dstFp) != 1)
goto fail;
res = updateSymtab(symtab, symtabScn->orgSize, scns);
res = buildStubs(&relaFstubContent, &relaStubContent,
&fnidContent, &stubContent, fstub->phndx,
relFstub, relStub, fnid, fstub, stub, mark, relMark,
srcFp, scns, strtab, symtab);
res = writeSegs(dstFp, dst, srcFp, src, strtab, symtab,
&ehdr, scns, segs, relFstub, relStub, fnid, stub, modinfo,
relaFstubContent, relaStubContent, fnidContent, stubContent);
fail:
free(scns);
freeSegs(segs, ehdr.e_phnum);
free(strtab);
free(symtab);
fclose(dstFp);
fclose(srcFp);
return res;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment