mirror of
https://github.com/pspdev/pspsdk.git
synced 2025-10-03 16:51:27 +00:00
885 lines
19 KiB
C
885 lines
19 KiB
C
/*
|
|
* PSP Software Development Kit - https://github.com/pspdev
|
|
* -----------------------------------------------------------------------
|
|
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
|
*
|
|
* psp-fixup-imports.c - Simple program to fixup an ELF's imports
|
|
*
|
|
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <getopt.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "types.h"
|
|
#include "elftypes.h"
|
|
#include "prxtypes.h"
|
|
#include "sha1.h"
|
|
|
|
#define PRX_LIBSTUB_SECT ".lib.stub"
|
|
#define PRX_STUBTEXT_SECT ".sceStub.text"
|
|
#define PRX_NID_SECT ".rodata.sceNid"
|
|
|
|
struct NidMap
|
|
{
|
|
unsigned int oldnid;
|
|
unsigned int newnid;
|
|
};
|
|
|
|
#define MAX_MAPNIDS 1024
|
|
|
|
struct ImportMap
|
|
{
|
|
struct ImportMap *next;
|
|
char name[32];
|
|
int count;
|
|
/* Could fail on things like PAF but who is going to want to remap 1000+ nids ? */
|
|
struct NidMap nids[MAX_MAPNIDS];
|
|
};
|
|
|
|
static const char *g_outfile;
|
|
static const char *g_infile;
|
|
static const char *g_mapfile;
|
|
static unsigned char *g_elfdata = NULL;
|
|
static unsigned int g_elfsize;
|
|
static struct ElfHeader g_elfhead = {0};
|
|
static struct ElfSection *g_elfsections = NULL;
|
|
static struct ElfSection *g_modinfo = NULL;
|
|
static struct ElfSection *g_libstub = NULL;
|
|
static struct ElfSection *g_stubtext = NULL;
|
|
static struct ElfSection *g_nid = NULL;
|
|
static struct ElfSection *g_symtab = NULL;
|
|
static struct ElfSection *g_strtab = NULL;
|
|
static struct ImportMap *g_map = NULL;
|
|
static int g_reversemap = 0;
|
|
|
|
/* Specifies that the current usage is to the print the pspsdk path */
|
|
static int g_verbose = 0;
|
|
|
|
static struct option arg_opts[] =
|
|
{
|
|
{"output", required_argument, NULL, 'o'},
|
|
{"reverse", no_argument, NULL, 'r' },
|
|
{"map", required_argument, NULL, 'm'},
|
|
{"verbose", no_argument, NULL, 'v'},
|
|
{ NULL, 0, NULL, 0 }
|
|
};
|
|
|
|
/* Process the arguments */
|
|
int process_args(int argc, char **argv)
|
|
{
|
|
int ch;
|
|
|
|
g_outfile = NULL;
|
|
g_infile = NULL;
|
|
g_mapfile = NULL;
|
|
|
|
ch = getopt_long(argc, argv, "vro:m:", arg_opts, NULL);
|
|
while(ch != -1)
|
|
{
|
|
switch(ch)
|
|
{
|
|
case 'v' : g_verbose = 1;
|
|
break;
|
|
case 'o' : g_outfile = optarg;
|
|
break;
|
|
case 'm' : g_mapfile = optarg;
|
|
break;
|
|
case 'r' : g_reversemap = 1;
|
|
break;
|
|
default : break;
|
|
};
|
|
|
|
ch = getopt_long(argc, argv, "vro:m:", arg_opts, NULL);
|
|
}
|
|
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
if(argc < 1)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
g_infile = argv[0];
|
|
|
|
if(g_outfile == NULL)
|
|
{
|
|
g_outfile = argv[0];
|
|
}
|
|
|
|
if(g_verbose)
|
|
{
|
|
fprintf(stderr, "Loading %s, outputting to %s\n", g_infile, g_outfile);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void print_help(void)
|
|
{
|
|
fprintf(stderr, "Usage: psp-fixup-imports [-v] [-o outfile.elf] infile.elf\n");
|
|
fprintf(stderr, "Options:\n");
|
|
fprintf(stderr, "-o, --output outfile : Output to a different file\n");
|
|
fprintf(stderr, "-m, --map mapfile : Specify a firmware NID mapfile\n");
|
|
fprintf(stderr, "-r, --reverse : Reverse the mapping\n");
|
|
fprintf(stderr, "-v, --verbose : Verbose output\n");
|
|
}
|
|
|
|
/* Scan through the sections trying to find this address */
|
|
const unsigned char *find_data(unsigned int iAddr)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < g_elfhead.iShnum; i++)
|
|
{
|
|
if((g_elfsections[i].iAddr <= iAddr) && ((g_elfsections[i].iAddr + g_elfsections[i].iSize) > iAddr))
|
|
{
|
|
return g_elfsections[i].pData + (iAddr - g_elfsections[i].iAddr);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* find symbol name. addr needs to be in host endianness */
|
|
static const char *getsymname(unsigned addr)
|
|
{
|
|
if(!g_symtab || !g_strtab) return 0;
|
|
if(g_symtab->iSize == 0 || g_symtab->pData == 0) return 0;
|
|
if(g_strtab->iSize == 0 || g_strtab->pData == 0) return 0;
|
|
Elf32_Sym *curr = (void*)g_symtab->pData;
|
|
Elf32_Sym *end = curr + (g_symtab->iSize / sizeof(Elf32_Sym));
|
|
addr = LW(addr);
|
|
while(curr < end) {
|
|
if(curr->st_value == addr) {
|
|
if(curr->st_name && curr->st_name < g_strtab->iSize)
|
|
return (char*)g_strtab->pData + curr->st_name;
|
|
else
|
|
return 0;
|
|
}
|
|
++curr;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
struct ImportMap *find_map_by_name(const char *name)
|
|
{
|
|
struct ImportMap *currmap = g_map;
|
|
|
|
while(currmap)
|
|
{
|
|
if(strcmp(name, currmap->name) == 0)
|
|
{
|
|
break;
|
|
}
|
|
currmap = currmap->next;
|
|
}
|
|
return currmap;
|
|
}
|
|
|
|
unsigned char *load_file(const char *file, unsigned int *size)
|
|
{
|
|
FILE *fp;
|
|
unsigned char *data = NULL;
|
|
|
|
do
|
|
{
|
|
fp = fopen(file, "rb");
|
|
if(fp != NULL)
|
|
{
|
|
(void) fseek(fp, 0, SEEK_END);
|
|
*size = ftell(fp);
|
|
rewind(fp);
|
|
|
|
if(*size < sizeof(Elf32_Ehdr))
|
|
{
|
|
fprintf(stderr, "Error, invalid file size\n");
|
|
fclose(fp);
|
|
break;
|
|
}
|
|
|
|
data = (unsigned char *) malloc(*size);
|
|
if(data == NULL)
|
|
{
|
|
fprintf(stderr, "Error, could not allocate memory for ELF\n");
|
|
fclose(fp);
|
|
break;
|
|
}
|
|
|
|
size_t result = fread(data, 1, *size, fp);
|
|
if (result < 0) {
|
|
fprintf(stderr, "Error, could not read the ELF\n");
|
|
fclose(fp);
|
|
break;
|
|
}
|
|
fclose(fp);
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Error, could not find file %s\n", file);
|
|
}
|
|
}
|
|
while(0);
|
|
|
|
return data;
|
|
}
|
|
|
|
/* Validate the ELF header */
|
|
int validate_header(unsigned char *data)
|
|
{
|
|
Elf32_Ehdr *head;
|
|
int ret = 0;
|
|
|
|
head = (Elf32_Ehdr*) data;
|
|
|
|
do
|
|
{
|
|
/* Read in the header structure */
|
|
g_elfhead.iMagic = LW(head->e_magic);
|
|
g_elfhead.iClass = head->e_class;
|
|
g_elfhead.iData = head->e_data;
|
|
g_elfhead.iIdver = head->e_idver;
|
|
g_elfhead.iType = LH(head->e_type);
|
|
g_elfhead.iMachine = LH(head->e_machine);
|
|
g_elfhead.iVersion = LW(head->e_version);
|
|
g_elfhead.iEntry = LW(head->e_entry);
|
|
g_elfhead.iPhoff = LW(head->e_phoff);
|
|
g_elfhead.iShoff = LW(head->e_shoff);
|
|
g_elfhead.iFlags = LW(head->e_flags);
|
|
g_elfhead.iEhsize = LH(head->e_ehsize);
|
|
g_elfhead.iPhentsize = LH(head->e_phentsize);
|
|
g_elfhead.iPhnum = LH(head->e_phnum);
|
|
g_elfhead.iShentsize = LH(head->e_shentsize);
|
|
g_elfhead.iShnum = LH(head->e_shnum);
|
|
g_elfhead.iShstrndx = LH(head->e_shstrndx);
|
|
|
|
if(g_verbose)
|
|
{
|
|
fprintf(stderr, "Magic %08x, Class %02x, Data %02x, Idver %02x\n", g_elfhead.iMagic,
|
|
g_elfhead.iClass, g_elfhead.iData, g_elfhead.iIdver);
|
|
fprintf(stderr, "Type %04x, Machine %04x, Version %08x, Entry %08x\n", g_elfhead.iType,
|
|
g_elfhead.iMachine, g_elfhead.iVersion, g_elfhead.iEntry);
|
|
fprintf(stderr, "Phoff %08x, Shoff %08x, Flags %08x, Ehsize %08x\n", g_elfhead.iPhoff,
|
|
g_elfhead.iShoff, g_elfhead.iFlags, g_elfhead.iEhsize);
|
|
fprintf(stderr, "Phentsize %04x, Phnum %04x\n", g_elfhead.iPhentsize, g_elfhead.iPhnum);
|
|
fprintf(stderr, "Shentsize %04x, Shnum %08x, Shstrndx %04x\n", g_elfhead.iShentsize,
|
|
g_elfhead.iShnum, g_elfhead.iShstrndx);
|
|
}
|
|
|
|
if(g_elfhead.iMagic != ELF_MAGIC)
|
|
{
|
|
fprintf(stderr, "Error, invalid magic in the header\n");
|
|
break;
|
|
}
|
|
|
|
if((g_elfhead.iType != ELF_EXEC_TYPE) && (g_elfhead.iType != ELF_PRX_TYPE))
|
|
{
|
|
fprintf(stderr, "Error, not EXEC type elf\n");
|
|
break;
|
|
}
|
|
|
|
if(g_elfhead.iMachine != ELF_MACHINE_MIPS)
|
|
{
|
|
fprintf(stderr, "Error, not MIPS type ELF\n");
|
|
break;
|
|
}
|
|
|
|
if(g_elfhead.iShnum < g_elfhead.iShstrndx)
|
|
{
|
|
fprintf(stderr, "Error, number of headers is less than section string index\n");
|
|
break;
|
|
}
|
|
|
|
ret = 1;
|
|
}
|
|
while(0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Load sections into ram */
|
|
int load_sections(unsigned char *data)
|
|
{
|
|
int ret = 0;
|
|
unsigned int load_addr = 0xFFFFFFFF;
|
|
|
|
if(g_elfhead.iShnum > 0)
|
|
{
|
|
do
|
|
{
|
|
Elf32_Shdr *sect;
|
|
int i;
|
|
|
|
g_elfsections = (struct ElfSection *) malloc(sizeof(struct ElfSection) * g_elfhead.iShnum);
|
|
if(g_elfsections == NULL)
|
|
{
|
|
fprintf(stderr, "Error, could not allocate memory for sections\n");
|
|
break;
|
|
}
|
|
|
|
memset(g_elfsections, 0, sizeof(struct ElfSection) * g_elfhead.iShnum);
|
|
|
|
for(i = 0; i < g_elfhead.iShnum; i++)
|
|
{
|
|
sect = (Elf32_Shdr *) (g_elfdata + g_elfhead.iShoff + (i * g_elfhead.iShentsize));
|
|
|
|
g_elfsections[i].iName = LW(sect->sh_name);
|
|
g_elfsections[i].iType = LW(sect->sh_type);
|
|
g_elfsections[i].iAddr = LW(sect->sh_addr);
|
|
g_elfsections[i].iFlags = LW(sect->sh_flags);
|
|
g_elfsections[i].iOffset = LW(sect->sh_offset);
|
|
g_elfsections[i].iSize = LW(sect->sh_size);
|
|
g_elfsections[i].iLink = LW(sect->sh_link);
|
|
g_elfsections[i].iInfo = LW(sect->sh_info);
|
|
g_elfsections[i].iAddralign = LW(sect->sh_addralign);
|
|
g_elfsections[i].iEntsize = LW(sect->sh_entsize);
|
|
g_elfsections[i].iIndex = i;
|
|
|
|
if(g_elfsections[i].iOffset != 0)
|
|
{
|
|
g_elfsections[i].pData = g_elfdata + g_elfsections[i].iOffset;
|
|
}
|
|
|
|
if(g_elfsections[i].iFlags & SHF_ALLOC)
|
|
{
|
|
g_elfsections[i].blOutput = 1;
|
|
if(g_elfsections[i].iAddr < load_addr)
|
|
{
|
|
load_addr = g_elfsections[i].iAddr;
|
|
}
|
|
}
|
|
|
|
if(((g_elfsections[i].iType == SHT_REL) || (g_elfsections[i].iType == SHT_PRXRELOC))
|
|
&& (g_elfsections[g_elfsections[i].iInfo].iFlags & SHF_ALLOC))
|
|
{
|
|
g_elfsections[i].pRef = &g_elfsections[g_elfsections[i].iInfo];
|
|
}
|
|
}
|
|
|
|
/* Okay so we have loaded all the sections, lets fix up the names */
|
|
for(i = 0; i < g_elfhead.iShnum; i++)
|
|
{
|
|
strcpy(g_elfsections[i].szName, (char *) (g_elfsections[g_elfhead.iShstrndx].pData + g_elfsections[i].iName));
|
|
if(strcmp(g_elfsections[i].szName, PSP_MODULE_INFO_NAME) == 0)
|
|
{
|
|
g_modinfo = &g_elfsections[i];
|
|
}
|
|
else if(strcmp(g_elfsections[i].szName, PRX_LIBSTUB_SECT) == 0)
|
|
{
|
|
g_libstub = &g_elfsections[i];
|
|
}
|
|
else if(strcmp(g_elfsections[i].szName, PRX_STUBTEXT_SECT) == 0)
|
|
{
|
|
g_stubtext = &g_elfsections[i];
|
|
}
|
|
else if(strcmp(g_elfsections[i].szName, PRX_NID_SECT) == 0)
|
|
{
|
|
g_nid = &g_elfsections[i];
|
|
}
|
|
else if(strcmp(g_elfsections[i].szName, ".symtab") == 0)
|
|
{
|
|
g_symtab = &g_elfsections[i];
|
|
}
|
|
else if(strcmp(g_elfsections[i].szName, ".strtab") == 0)
|
|
{
|
|
g_strtab = &g_elfsections[i];
|
|
}
|
|
}
|
|
|
|
if(g_verbose)
|
|
{
|
|
for(i = 0; i < g_elfhead.iShnum; i++)
|
|
{
|
|
fprintf(stderr, "\nSection %d: %s\n", i, g_elfsections[i].szName);
|
|
fprintf(stderr, "Name %08x, Type %08x, Flags %08x, Addr %08x\n",
|
|
g_elfsections[i].iName, g_elfsections[i].iType,
|
|
g_elfsections[i].iFlags, g_elfsections[i].iAddr);
|
|
fprintf(stderr, "Offset %08x, Size %08x, Link %08x, Info %08x\n",
|
|
g_elfsections[i].iOffset, g_elfsections[i].iSize,
|
|
g_elfsections[i].iLink, g_elfsections[i].iInfo);
|
|
fprintf(stderr, "Addralign %08x, Entsize %08x pData %p\n",
|
|
g_elfsections[i].iAddralign, g_elfsections[i].iEntsize,
|
|
g_elfsections[i].pData);
|
|
}
|
|
|
|
fprintf(stderr, "ELF Load Base address %08x\n", load_addr);
|
|
}
|
|
|
|
if(g_modinfo == NULL)
|
|
{
|
|
fprintf(stderr, "Error, no sceModuleInfo section found\n");
|
|
break;
|
|
}
|
|
|
|
if(g_libstub == NULL)
|
|
{
|
|
fprintf(stderr, "Error, no .lib.stub section found\n");
|
|
break;
|
|
}
|
|
|
|
if(g_stubtext == NULL)
|
|
{
|
|
fprintf(stderr, "Error, no stub text section found\n");
|
|
break;
|
|
}
|
|
|
|
if(g_nid == NULL)
|
|
{
|
|
fprintf(stderr, "Error, no nid section found\n");
|
|
break;
|
|
}
|
|
|
|
ret = 1;
|
|
}
|
|
while(0);
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Error, no sections in the ELF\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Load an ELF file */
|
|
int load_elf(const char *elf)
|
|
{
|
|
int ret = 0;
|
|
|
|
do
|
|
{
|
|
g_elfdata = load_file(elf, &g_elfsize);
|
|
if(g_elfdata == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(!validate_header(g_elfdata))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(!load_sections(g_elfdata))
|
|
{
|
|
break;
|
|
}
|
|
|
|
ret = 1;
|
|
}
|
|
while(0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Free allocated memory */
|
|
void free_data(void)
|
|
{
|
|
if(g_elfdata != NULL)
|
|
{
|
|
free(g_elfdata);
|
|
g_elfdata = NULL;
|
|
}
|
|
|
|
if(g_elfsections != NULL)
|
|
{
|
|
free(g_elfsections);
|
|
g_elfsections = NULL;
|
|
}
|
|
}
|
|
|
|
void strip_wsp(char *str)
|
|
{
|
|
int len;
|
|
char *p;
|
|
|
|
len = strlen(str);
|
|
while((len > 0) && (isspace(str[len-1])))
|
|
{
|
|
str[--len] = 0;
|
|
}
|
|
|
|
p = str;
|
|
while(isspace(*p))
|
|
{
|
|
p++;
|
|
len--;
|
|
}
|
|
|
|
memmove(str, p, len);
|
|
str[len] = 0;
|
|
}
|
|
|
|
/* Load map file in
|
|
* File format is :-
|
|
* @LibraryName followed by 0 or more
|
|
* OLDNID=NEWNID [ Comment ]
|
|
*
|
|
* Read in badly :P
|
|
*/
|
|
int load_mapfile(const char *mapfile)
|
|
{
|
|
int ret = 1;
|
|
char buf[1024];
|
|
struct ImportMap *currmap = NULL;
|
|
int line = 0;
|
|
|
|
if(mapfile == NULL) return ret;
|
|
do
|
|
{
|
|
FILE *fp;
|
|
|
|
fp = fopen(mapfile, "r");
|
|
if(fp == NULL) return ret;
|
|
while(fgets(buf, sizeof(buf), fp))
|
|
{
|
|
line++;
|
|
strip_wsp(buf);
|
|
if((buf[0]) && (buf[0] != '#'))
|
|
{
|
|
if(buf[0] == '@')
|
|
{
|
|
struct ImportMap *temp;
|
|
|
|
temp = (struct ImportMap *) malloc(sizeof(struct ImportMap));
|
|
if(temp == NULL)
|
|
{
|
|
printf("Error allocating memory for import map\n");
|
|
ret = 0;
|
|
break;
|
|
}
|
|
|
|
memset(temp, 0, sizeof(struct ImportMap));
|
|
if(currmap == NULL)
|
|
{
|
|
g_map = temp;
|
|
}
|
|
else
|
|
{
|
|
temp->next = currmap;
|
|
g_map = temp;
|
|
}
|
|
|
|
currmap = temp;
|
|
if(buf[1])
|
|
{
|
|
strncpy(currmap->name, &buf[1], 32);
|
|
currmap->name[31] = 0;
|
|
}
|
|
else
|
|
{
|
|
printf("Invalid library name at line %d\n", line);
|
|
break;
|
|
}
|
|
|
|
if(g_verbose)
|
|
{
|
|
printf("Mapping library %s\n", currmap->name);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned int oldnid;
|
|
unsigned int newnid;
|
|
char *endp;
|
|
|
|
if(currmap->count == MAX_MAPNIDS)
|
|
{
|
|
printf("Error, number of defined nids exceed maximum\n");
|
|
break;
|
|
}
|
|
|
|
/* Hex data should be prefixed with 0 */
|
|
if(buf[0] == '0')
|
|
{
|
|
errno = 0;
|
|
oldnid = strtoul(buf, &endp, 16);
|
|
if((errno != 0) || (*endp != ':'))
|
|
{
|
|
printf("Invalid NID entry on line %d\n", line);
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned char hash[SHA1_DIGEST_SIZE];
|
|
|
|
endp = strchr(buf, ':');
|
|
if(endp == NULL)
|
|
{
|
|
printf("Invalid NID entry on line %d\n", line);
|
|
continue;
|
|
}
|
|
|
|
sha1(hash, (unsigned char *) buf, endp-buf);
|
|
oldnid = hash[0] | (hash[1] << 8) | (hash[2] << 16) | (hash[3] << 24);
|
|
}
|
|
|
|
newnid = strtoul(endp+1, &endp, 16);
|
|
if(g_verbose)
|
|
{
|
|
fprintf(stderr, "NID Mapping 0x%08x to 0x%08x\n", oldnid, newnid);
|
|
}
|
|
|
|
currmap->nids[currmap->count].oldnid = oldnid;
|
|
currmap->nids[currmap->count].newnid = newnid;
|
|
currmap->count++;
|
|
}
|
|
}
|
|
}
|
|
fclose(fp);
|
|
}
|
|
while(0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#define MIPS_JR_31 0x03e00008
|
|
#define MIPS_NOP 0x0
|
|
|
|
int fixup_imports(void)
|
|
{
|
|
unsigned int *pText;
|
|
unsigned int *pNid;
|
|
struct PspModuleImport *pLastImport = NULL;
|
|
int count;
|
|
|
|
/* First let's check the sizes are correct */
|
|
if(g_stubtext->iSize != (g_nid->iSize * 2))
|
|
{
|
|
fprintf(stderr, "Error, size of text section and nid section do not match\n");
|
|
return 0;
|
|
}
|
|
|
|
count = g_nid->iSize / 4;
|
|
pText = (unsigned int *) g_stubtext->pData;
|
|
pNid = (unsigned int *) g_nid->pData;
|
|
|
|
if(g_verbose)
|
|
{
|
|
fprintf(stderr, "Import count %d\n", count);
|
|
}
|
|
|
|
while(count > 0)
|
|
{
|
|
unsigned int stub_addr;
|
|
unsigned int stub_nid;
|
|
unsigned int sect_nid;
|
|
|
|
stub_addr = LW(pText[0]);
|
|
stub_nid = LW(pText[1]);
|
|
sect_nid = LW(pNid[0]);
|
|
|
|
/* Check if this is an original format NID */
|
|
if((stub_addr != MIPS_JR_31) || (stub_nid != MIPS_NOP))
|
|
{
|
|
struct PspModuleImport *pImport;
|
|
u16 func_count;
|
|
|
|
if(g_verbose)
|
|
{
|
|
const char *tmp = getsymname(stub_addr);
|
|
fprintf(stderr, "Found import to fixup. pStub %08x (%s), Nid %08x, NidInSect %08x\n", stub_addr, tmp ? tmp : "", stub_nid, sect_nid);
|
|
}
|
|
|
|
if(stub_nid != sect_nid)
|
|
{
|
|
fprintf(stderr, "Error, unmatched NIDs\n");
|
|
return 0;
|
|
}
|
|
|
|
if((stub_addr < g_libstub->iAddr) || (stub_addr > (g_libstub->iAddr + g_libstub->iSize)) || (stub_addr & 3))
|
|
{
|
|
fprintf(stderr, "Error, invalid stub address\n");
|
|
return 0;
|
|
}
|
|
|
|
pImport = (struct PspModuleImport *) (g_libstub->pData + (stub_addr - g_libstub->iAddr));
|
|
if(g_verbose)
|
|
{
|
|
const char *tmp = getsymname(LW(pImport->name));
|
|
fprintf(stderr, "Import Stub %p, %08x (%s), %08x, %02x, %02x, %04x, %08x, %08x\n", pImport,
|
|
LW(pImport->name), tmp?tmp:"", LW(pImport->flags), pImport->entry_size, pImport->var_count,
|
|
LH(pImport->func_count), LW(pImport->nids), LW(pImport->funcs));
|
|
}
|
|
|
|
func_count = LH(pImport->func_count);
|
|
|
|
if(func_count == 0)
|
|
{
|
|
/* Setup the stub */
|
|
SW(&pImport->nids, ((unsigned char *) pNid - g_nid->pData) + g_nid->iAddr);
|
|
SW(&pImport->funcs, ((unsigned char *) pText - g_stubtext->pData) + g_stubtext->iAddr);
|
|
}
|
|
else
|
|
{
|
|
if((pLastImport) && (pImport != pLastImport))
|
|
{
|
|
fprintf(stderr, "Warning: could not fixup imports, stubs out of order.\n");
|
|
fprintf(stderr, "Ensure the SDK libraries are linked in last to correct this.\n");
|
|
fprintf(stderr, "Continuing, your binary may or not work.\n");
|
|
}
|
|
}
|
|
|
|
pLastImport = pImport;
|
|
func_count++;
|
|
SH(&pImport->func_count, func_count);
|
|
SW(&pText[0], MIPS_JR_31);
|
|
SW(&pText[1], MIPS_NOP);
|
|
}
|
|
else
|
|
{
|
|
/* Set last import to some value so we know if we have out of order stubs over a fixed stub table */
|
|
pLastImport = (struct PspModuleImport *) pText;
|
|
}
|
|
|
|
pText += 2;
|
|
pNid++;
|
|
count--;
|
|
}
|
|
|
|
/* Should indicate no error occurred */
|
|
if(count == 0)
|
|
{
|
|
if(g_verbose)
|
|
{
|
|
fprintf(stderr, "No libraries to fixup\n");
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int fixup_nidmap(void)
|
|
{
|
|
struct PspModuleImport *pImport;
|
|
int size;
|
|
|
|
pImport = (struct PspModuleImport *) g_libstub->pData;
|
|
size = g_libstub->iSize;
|
|
|
|
while(size >= sizeof(struct PspModuleImport))
|
|
{
|
|
const char *str;
|
|
|
|
str = (const char*) find_data(LW(pImport->name));
|
|
if(str)
|
|
{
|
|
struct ImportMap *pMap;
|
|
|
|
pMap = find_map_by_name(str);
|
|
if(pMap)
|
|
{
|
|
int count;
|
|
unsigned int *pNid;
|
|
|
|
pNid = (unsigned int*) find_data(LW(pImport->nids));
|
|
count = LH(pImport->func_count) + pImport->var_count;
|
|
|
|
if(pNid && (count > 0))
|
|
{
|
|
if(g_verbose)
|
|
{
|
|
fprintf(stderr, "Mapping library %s\n", str);
|
|
}
|
|
|
|
while(count > 0)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < pMap->count; i++)
|
|
{
|
|
unsigned oldnid, newnid;
|
|
|
|
if(g_reversemap)
|
|
{
|
|
oldnid = pMap->nids[i].newnid;
|
|
newnid = pMap->nids[i].oldnid;
|
|
}
|
|
else
|
|
{
|
|
newnid = pMap->nids[i].newnid;
|
|
oldnid = pMap->nids[i].oldnid;
|
|
}
|
|
|
|
if(oldnid == *pNid)
|
|
{
|
|
if(g_verbose)
|
|
{
|
|
fprintf(stderr, "Mapping 0x%08x to 0x%08x\n", oldnid, newnid);
|
|
}
|
|
|
|
*pNid = newnid;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pNid++;
|
|
count--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pImport++;
|
|
size -= sizeof(struct PspModuleImport);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int ret = 0;
|
|
|
|
if(process_args(argc, argv))
|
|
{
|
|
if(load_mapfile(g_mapfile) && load_elf(g_infile))
|
|
{
|
|
if(fixup_imports() && fixup_nidmap())
|
|
{
|
|
FILE *fp;
|
|
|
|
fp = fopen(g_outfile, "wb");
|
|
if(fp != NULL)
|
|
{
|
|
(void) fwrite(g_elfdata, 1, g_elfsize, fp);
|
|
fclose(fp);
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Error, couldn't open %s for writing\n", g_outfile);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ret = 1;
|
|
}
|
|
free_data();
|
|
}
|
|
else
|
|
{
|
|
ret = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
print_help();
|
|
ret = 1;
|
|
}
|
|
|
|
return ret;
|
|
}
|