From 484569d7fb50fa051ad9a198c26fc6c0a9b45249 Mon Sep 17 00:00:00 2001 From: artart78 Date: Fri, 30 Dec 2011 18:48:23 +0000 Subject: [PATCH] Make the build system work EXACTLY the same way as for official kernel modules. Fixed alignment. Added our/my own version of psp-build-exports from the PSPSDK, so the library name is placed right before the library exports in .rodata. Added our/my own version of psp-prxgen from the PSPSDK (named psp-kprxgen for us), so the module uses only program headers and absolutely no sections. --- lib/build.mak | 4 +- lib/linkfile.prx | 5 +- src/global.h | 7 +- utils/build-exports/Makefile | 27 + utils/build-exports/psp-build-exports.c | 1050 +++++++++++++++++++++++ utils/build-exports/sha1.c | 282 ++++++ utils/build-exports/sha1.h | 84 ++ utils/kprxgen/Makefile | 27 + utils/kprxgen/elftypes.h | 246 ++++++ utils/kprxgen/prxtypes.h | 150 ++++ utils/kprxgen/psp-kprxgen.c | 815 ++++++++++++++++++ utils/kprxgen/types.h | 149 ++++ 12 files changed, 2838 insertions(+), 8 deletions(-) create mode 100644 utils/build-exports/Makefile create mode 100644 utils/build-exports/psp-build-exports.c create mode 100644 utils/build-exports/sha1.c create mode 100644 utils/build-exports/sha1.h create mode 100644 utils/kprxgen/Makefile create mode 100644 utils/kprxgen/elftypes.h create mode 100644 utils/kprxgen/prxtypes.h create mode 100644 utils/kprxgen/psp-kprxgen.c create mode 100644 utils/kprxgen/types.h diff --git a/lib/build.mak b/lib/build.mak index e757b07..2acc24e 100644 --- a/lib/build.mak +++ b/lib/build.mak @@ -23,10 +23,10 @@ $(TARGET).elf: $(OBJS) $(EXPORT_OBJ) -$(FIXUP) $@ %.prx: %.elf - psp-prxgen $< $@ + ../../utils/kprxgen/psp-kprxgen $< $@ %.c: %.exp - psp-build-exports -b $< > $@ + ../../utils/build-exports/psp-build-exports -b $< > $@ clean: -rm -f $(TARGET).prx $(TARGET).elf $(EXPORT_OBJ) $(OBJS) diff --git a/lib/linkfile.prx b/lib/linkfile.prx index 2743302..78ef23a 100644 --- a/lib/linkfile.prx +++ b/lib/linkfile.prx @@ -2,6 +2,7 @@ OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", "elf32-littlemips") OUTPUT_ARCH(mips:allegrex) +ENTRY(module_start) /* SEARCH_DIR("/usr/local/pspdev/psp/lib"); */ /* Do we need any of these for elf? __DYNAMIC = 0; */ @@ -72,6 +73,7 @@ SECTIONS *(.gnu.warning) *(.mips16.fn.*) *(.mips16.call.*) } =0 + . = ALIGN(16); .init : { KEEP (*(.init)) @@ -108,9 +110,6 @@ SECTIONS .eh_frame_hdr : { *(.eh_frame_hdr) } .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } .gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = ALIGN(256) + (. & (256 - 1)); /* Exception handling */ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } .gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } diff --git a/src/global.h b/src/global.h index 2aa39a6..92d85a3 100644 --- a/src/global.h +++ b/src/global.h @@ -77,15 +77,16 @@ enum PspModuleInfoAttr extern char __lib_stub_top[], __lib_stub_bottom[]; \ SceModuleInfo module_info \ __attribute__((section(".rodata.sceModuleInfo"), \ - aligned(16), unused)) = { \ + , unused)) = { \ attributes, { minor_version, major_version }, name, 0, _gp, \ __lib_ent_top, __lib_ent_bottom, \ __lib_stub_top, __lib_stub_bottom \ } -#define PSP_SDK_VERSION(ver) int syslib_11B97506 = ver +#define PSP_SDK_VERSION(ver) const int syslib_11B97506 = ver -#define PSP_MODULE_BOOTSTART(name) int module_bootstart(int arglen, void *argp) __attribute__((alias(name))) +#define PSP_MODULE_BOOTSTART(name) int module_start(int arglen, void *argp) __attribute__((alias(name))); \ +int module_bootstart(int arglen, void *argp) __attribute__((alias(name))) /********** TEMPORARY: it'll be in their corresponding module's header *********/ typedef int (*SceKernelCallbackFunction)(int arg1, int arg2, void *arg); diff --git a/utils/build-exports/Makefile b/utils/build-exports/Makefile new file mode 100644 index 0000000..d89d365 --- /dev/null +++ b/utils/build-exports/Makefile @@ -0,0 +1,27 @@ +# Copyright (C) 2011 The uOFW team +# See the file COPYING for copying permission. + +CPP=gcc +CFLAGS=-Wall -Wextra -Werror +LDFLAGS= +TARGET=psp-build-exports +OBJECTS=sha1.o psp-build-exports.o + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + @echo "Creating binary $(TARGET)" + @$(CPP) $(OBJECTS) -o $@ $(LDFLAGS) + +%.o: %.cpp + @echo "Compiling $^" + $(CPP) $(CFLAGS) -c $^ -o $@ + +clean: + @echo "Removing all the .o files" + @$(RM) $(OBJECTS) + +mrproper: clean + @echo "Removing binary" + @$(RM) $(TARGET) + diff --git a/utils/build-exports/psp-build-exports.c b/utils/build-exports/psp-build-exports.c new file mode 100644 index 0000000..2e5f09f --- /dev/null +++ b/utils/build-exports/psp-build-exports.c @@ -0,0 +1,1050 @@ +/* Copyright (C) 2011 The uOFW team + See the file COPYING for copying permission. + + Based on the original file from PSPSDK, written by tyranid; many thanks to him! +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "sha1.h" + +#define MAX_LIB_NAME 27 +#define MAX_LIB_FUNCS 65535 +#define MAX_LIB_VARS 255 +#define MAX_LIB_ENTRY_NAME 127 +#define MAX_ERROR 1024 +#define MAX_LINE 1024 +#define SYSTEM_LIB_NAME "syslib" + +enum PspConfigMode +{ + PSP_BUILD_UNKNOWN, + PSP_BUILD_EXPORTS, + PSP_BUILD_STUBS, + PSP_BUILD_STUBS_NEW, +}; + +struct psp_export +{ + struct psp_export *pNext; + unsigned int nid; + char name[MAX_LIB_ENTRY_NAME+1]; +}; + +struct psp_alias +{ + struct psp_alias *pNext; + char name[MAX_LIB_ENTRY_NAME+1]; + char alias[MAX_LIB_ENTRY_NAME+1]; +}; + +struct psp_lib +{ + struct psp_lib *pNext; + char name[MAX_LIB_NAME+1]; + unsigned short ver; + unsigned short attr; + int funcCount; + struct psp_export *pFuncHead; + int varCount; + struct psp_export *pVarHead; + struct psp_alias *pAliasHead; +}; + +struct export_cmd +{ + const char *name; + int params; + int (*handler)(char ** params); +}; + +/* Specifies that the current usage is to the print the pspsdk path */ +static enum PspConfigMode g_outputmode; +static int g_verbose = 0; +static const char *g_infile; +static char g_errstring[MAX_ERROR] = "No Error"; +static struct psp_lib *g_libhead = NULL; +static struct psp_lib *g_currlib = NULL; +static int g_libcount = 0; + +void free_export_chain(struct psp_export *pHead) +{ + struct psp_export *pNext; + + pNext = pHead; + + while(pNext != NULL) + { + struct psp_export *pTemp; + + pTemp = pNext->pNext; + free(pNext); + pNext = pTemp; + } +} + +void free_alias_chain(struct psp_alias *pHead) +{ + struct psp_alias *pNext; + + pNext = pHead; + + while(pNext != NULL) + { + struct psp_alias *pTemp; + + pTemp = pNext->pNext; + free(pNext); + pNext = pTemp; + } +} + +void free_lib_data(void) +{ + struct psp_lib *pNext; + + if(g_currlib != NULL) + { + free_export_chain(g_currlib->pFuncHead); + free_export_chain(g_currlib->pVarHead); + free_alias_chain(g_currlib->pAliasHead); + free(g_currlib); + g_currlib = NULL; + } + + pNext = g_libhead; + + while(pNext != NULL) + { + struct psp_lib *pTemp; + + pTemp = pNext->pNext; + free_export_chain(pNext->pFuncHead); + free_export_chain(pNext->pVarHead); + free_alias_chain(pNext->pAliasHead); + free(pNext); + pNext = pTemp; + } + + g_libhead = NULL; +} + +const char *find_alias(struct psp_alias *pHead, const char *name) +{ + struct psp_alias *pNext; + const char *szAlias = NULL; + + pNext = pHead; + while(pNext) + { + if(strcmp(name, pNext->name) == 0) + { + szAlias = pNext->alias; + break; + } + + pNext = pNext->pNext; + } + + return szAlias; +} + +static struct option arg_opts[] = +{ + {"build-exports", no_argument, NULL, 'b'}, + {"build-stubs", no_argument, NULL, 's'}, + {"build-stubs-new", no_argument, NULL, 'k'}, + {"verbose", no_argument, NULL, 'v'}, + { NULL, 0, NULL, 0 } +}; + +/* Process the arguments */ +int process_args(int argc, char **argv) +{ + int ret = 0; + int ch; + + g_outputmode = PSP_BUILD_UNKNOWN; + + ch = getopt_long(argc, argv, "bsvk", arg_opts, NULL); + while(ch != -1) + { + switch(ch) + { + case 'b' : g_outputmode = PSP_BUILD_EXPORTS; + ret = 1; + break; + case 's' : g_outputmode = PSP_BUILD_STUBS; + ret = 1; + break; + case 'v' : g_verbose = 1; + break; + case 'k' : g_outputmode = PSP_BUILD_STUBS_NEW; + ret = 1; + break; + default : //fprintf(stderr, "Invalid option '%c'\n", ch); + break; + }; + + ch = getopt_long(argc, argv, "bsvk", arg_opts, NULL); + } + + argc -= optind; + argv += optind; + + if(argc < 1) + { + return 0; + } + + g_infile = argv[0]; + + return ret; +} + +void print_help(void) +{ + fprintf(stderr, "Usage: psp-build-exports -b|-s|-k [-v] export.exp\n"); + fprintf(stderr, "Options:\n"); + fprintf(stderr, "-b, --build-exports : Build an export file to stdout\n"); + fprintf(stderr, "-s, --build-stubs : Build a batch of stub files for the exports\n"); + fprintf(stderr, "-k, --build-stubs-new : Build a batch of stub files (in new format)\n"); + fprintf(stderr, "-v, --verbose : Verbose output\n"); +} + +void strip_whitespace(char *dest, const char *src) +{ + assert(dest != NULL); + assert(src != NULL); + + while(*src != 0) + { + if(!isspace(*src)) + { + *dest = *src; + dest++; + } + + src++; + } + + *dest = 0; +} + +/* + Parse a string of the form FUNC(arg1,arg2,...) + Returns the number of parameters or -1 on error. + */ +int parse_string(char *line, char **params, int max_params) +{ + int pos; + int param_start; + char *next_param; + int param_count; + + assert(line != NULL); + assert(params != NULL); + + pos = 0; + + /* Parse off "function" name */ + while((isalnum(line[pos])) || (line[pos] == '_')) + { + pos++; + } + + /* If we don't have any thing else than this is just the function */ + if(line[pos] == 0) + { + return 0; + } + + if(line[pos] != '(') + { + snprintf(g_errstring, MAX_ERROR, "Invalid character %c, expected (", line[pos]); + return -1; + } + + /* Terminate */ + line[pos++] = 0; + param_start = pos; + + /* Scan parameters */ + while((isalnum(line[pos])) || (line[pos] == '_') || (line[pos] == ',')) + { + pos++; + } + + if(line[pos] == 0) + { + snprintf(g_errstring, MAX_ERROR, "Missing closing brace ')'"); + return -1; + } + + if(line[pos] != ')') + { + snprintf(g_errstring, MAX_ERROR, "Invalid character %c, expected ')'", line[pos]); + return -1; + } + + if(line[pos+1] != 0) + { + snprintf(g_errstring, MAX_ERROR, "Trailing characters after bracket close %d", line[pos+1]); + return -1; + } + + line[pos] = 0; + + param_count = 0; + next_param = strtok(&line[param_start], ","); + while(next_param != NULL) + { + if(param_count == max_params) + { + snprintf(g_errstring, MAX_ERROR, "Run out of space for parameters"); + return -1; + } + + params[param_count++] = next_param; + next_param = strtok(NULL, ","); + } + + return param_count; +} + +void build_exports_output_extern(struct psp_export *pHead) +{ + struct psp_export *pExp; + + pExp = pHead; + while(pExp != NULL) + { + fprintf(stdout, "extern void %s;\n", pExp->name); + pExp = pExp->pNext; + } +} + +void build_exports_output_nids(struct psp_export *pHead) +{ + struct psp_export *pExp; + + pExp = pHead; + while(pExp != NULL) + { + fprintf(stdout, "\t0x%08X,\n", pExp->nid); + pExp = pExp->pNext; + } +} + +void build_exports_output_names(struct psp_export *pHead) +{ + struct psp_export *pExp; + + pExp = pHead; + while(pExp != NULL) + { + fprintf(stdout, "\t(unsigned int) &%s,\n", pExp->name); + pExp = pExp->pNext; + } +} + +void build_exports(void) +{ + struct psp_lib *pLib; + + fprintf(stdout, "#include \n"); + fprintf(stdout, "#define NULL ((void *) 0)\n\n"); + + /* Write out the nid tables */ + pLib = g_libhead; + while(pLib != NULL) + { + if (strcmp(pLib->name, SYSTEM_LIB_NAME) != 0) + fprintf(stdout, "static const char __%s_name[] __attribute__((section(\".rodata.sceResident\"))) = \"%s\";\n", pLib->name, pLib->name); + /* Print extern */ + build_exports_output_extern(pLib->pFuncHead); + build_exports_output_extern(pLib->pVarHead); + + fprintf(stdout, "static const unsigned int __%s_exports[%d] __attribute__((section(\".rodata.sceResident\"))) = {\n", + pLib->name, (pLib->funcCount + pLib->varCount) * 2); + + /* Print nid */ + build_exports_output_nids(pLib->pFuncHead); + build_exports_output_nids(pLib->pVarHead); + /* Print names */ + build_exports_output_names(pLib->pFuncHead); + build_exports_output_names(pLib->pVarHead); + fprintf(stdout, "};\n\n"); + + pLib = pLib->pNext; + } + + fprintf(stdout, "const struct _PspLibraryEntry __library_exports[%d] __attribute__((section(\".lib.ent\"), used)) = {\n", g_libcount); + pLib = g_libhead; + while(pLib != NULL) + { + if(strcmp(pLib->name, SYSTEM_LIB_NAME) == 0) + { + fprintf(stdout, "\t{ NULL, "); + } + else + { + fprintf(stdout, "\t{ __%s_name, ", pLib->name); + } + + fprintf(stdout, "0x%04X, 0x%04X, 4, %d, %d, &__%s_exports },\n", pLib->ver, pLib->attr, + pLib->varCount, pLib->funcCount, pLib->name); + + pLib = pLib->pNext; + } + fprintf(stdout, "};\n"); +} + +void build_stubs_output_lib(struct psp_lib *pLib) +{ + FILE *fp; + char filename[256]; + + snprintf(filename, 256, "%s.S", pLib->name); + if(g_verbose) + { + fprintf(stderr, "Writing output file %s\n", filename); + } + fp = fopen(filename, "w"); + if(fp != NULL) + { + struct psp_export *pExp; + + fprintf(fp, "\t.set noreorder\n\n"); + fprintf(fp, "#include \"pspstub.s\"\n\n"); + fprintf(fp, "\tSTUB_START \"%s\",0x%08X,0x%08X\n", pLib->name, ((pLib->attr | 0x8) << 16) | pLib->ver, + (pLib->funcCount << 16) | 5); + + pExp = pLib->pFuncHead; + while(pExp != NULL) + { + const char *alias; + + alias = find_alias(pLib->pAliasHead, pExp->name); + if(alias) + { + fprintf(fp, "\tSTUB_FUNC_WITH_ALIAS 0x%08X,%s,%s\n", pExp->nid, pExp->name,alias); + } + else + { + fprintf(fp, "\tSTUB_FUNC 0x%08X,%s\n", pExp->nid, pExp->name); + } + pExp = pExp->pNext; + } + + fprintf(fp, "\tSTUB_END\n"); + + fclose(fp); + } + else + { + fprintf(stderr, "Error, couldn't open file %s for writing\n", filename); + } +} + +void build_stubs_output_lib_new(struct psp_lib *pLib) +{ + FILE *fp; + char filename[256]; + int i; + + snprintf(filename, 256, "%s.S", pLib->name); + if(g_verbose) + { + fprintf(stderr, "Writing output file %s\n", filename); + } + fp = fopen(filename, "w"); + if(fp != NULL) + { + struct psp_export *pExp; + + fprintf(fp, "\t.set noreorder\n\n"); + fprintf(fp, "#include \"pspimport.s\"\n\n"); + + fprintf(fp, "// Build files\n"); + fprintf(fp, "// %s_0000.o ", pLib->name); + pExp = pLib->pFuncHead; + i = 1; + while(pExp != NULL) + { + fprintf(fp, "%s_%04d.o ", pLib->name, i++); + pExp = pExp->pNext; + } + fprintf(fp, "\n\n"); + + fprintf(fp, "#ifdef F_%s_0000\n", pLib->name); + fprintf(fp, "\tIMPORT_START \"%s\",0x%08X\n", pLib->name, ((pLib->attr | 0x8) << 16) | pLib->ver); + fprintf(fp, "#endif\n"); + + pExp = pLib->pFuncHead; + i = 1; + while(pExp != NULL) + { + const char *alias; + fprintf(fp, "#ifdef F_%s_%04d\n", pLib->name, i++); + + alias = find_alias(pLib->pAliasHead, pExp->name); + if(alias) + { + fprintf(fp, "\tIMPORT_FUNC_WITH_ALIAS \"%s\",0x%08X,%s,%s\n", pLib->name, pExp->nid, pExp->name, alias); + } + else + { + fprintf(fp, "\tIMPORT_FUNC \"%s\",0x%08X,%s\n", pLib->name, pExp->nid, pExp->name); + } + + fprintf(fp, "#endif\n"); + pExp = pExp->pNext; + } + + fclose(fp); + } + else + { + fprintf(stderr, "Error, couldn't open file %s for writing\n", filename); + } +} + +void build_stubs(void) +{ + struct psp_lib *pLib; + + pLib = g_libhead; + + while(pLib != NULL) + { + if(strcmp(pLib->name, SYSTEM_LIB_NAME)) + { + if(g_outputmode == PSP_BUILD_STUBS) + { + build_stubs_output_lib(pLib); + } + else + { + build_stubs_output_lib_new(pLib); + } + } + + pLib = pLib->pNext; + } +} + +int validate_number(const char *str, unsigned int *num) +{ + char *endp; + + assert(str != NULL); + assert(num != NULL); + + if(!isxdigit(*str)) + { + snprintf(g_errstring, MAX_ERROR, "'%s' is an invalid number", str); + return 0; + } + + *num = strtoul(str, &endp, 0); + if(*endp != 0) + { + snprintf(g_errstring, MAX_ERROR, "'%s' has trailing non-numeric characters", str); + return 0; + } + + return 1; +} + +int psp_begin_exports(char **params __attribute__ ((unused))) +{ + /* Do nothing */ + return 1; +} + +int psp_end_exports(char **params __attribute__ ((unused))) +{ + if(g_currlib != NULL) + { + /* Error, missing end of exports */ + } + + return 1; +} + +int psp_export_start(char **params) +{ + unsigned int ver; + unsigned int attr; + + if(g_currlib != NULL) + { + snprintf(g_errstring, MAX_ERROR, "Previous library '%s' not ended", g_currlib->name); + return 0; + } + + if(validate_number(params[1], &ver) == 0) + { + return 0; + } + + if(validate_number(params[2], &attr) == 0) + { + return 0; + } + + g_currlib = (struct psp_lib *) malloc(sizeof(struct psp_lib)); + if(g_currlib == NULL) + { + snprintf(g_errstring, MAX_ERROR, "Could not allocate memory for library"); + return 0; + } + + memset(g_currlib, 0, sizeof(struct psp_lib)); + g_libcount++; + + strncpy(g_currlib->name, params[0], MAX_LIB_NAME); + g_currlib->ver = ver; + g_currlib->attr = attr; + + return 1; +} + +int psp_export_end(char **params __attribute__ ((unused))) +{ + struct psp_lib *pNext; + + if(g_currlib == NULL) + { + snprintf(g_errstring, MAX_ERROR, "No matching start command for library end"); + return 1; + } + + /* Add to the end of the chain */ + if(g_libhead == NULL) + { + g_libhead = g_currlib; + } + else + { + pNext = g_libhead; + while(pNext->pNext != NULL) + { + pNext = pNext->pNext; + } + + pNext->pNext = g_currlib; + } + + g_currlib = NULL; + + return 1; +} + +int internal_do_export(const char *name, unsigned int nid, struct psp_export **pHead) +{ + struct psp_export *pNew; + + assert(name != NULL); + assert(pHead != NULL); + + pNew = (struct psp_export *) malloc(sizeof(struct psp_export)); + + if(pNew != NULL) + { + struct psp_export *pNext; + + memset(pNew, 0, sizeof(struct psp_export)); + strncpy(pNew->name, name, MAX_LIB_ENTRY_NAME); + pNew->nid = nid; + + if(*pHead == NULL) + { + *pHead = pNew; + } + else + { + pNext = *pHead; + while(pNext->pNext != NULL) + { + pNext = pNext->pNext; + } + + pNext->pNext = pNew; + } + } + else + { + snprintf(g_errstring, MAX_ERROR, "Could not allocate memory for export %s", name); + return 0; + } + + return 1; +} + +int psp_export_func_nid(char **params) +{ + unsigned int nid; + + if(g_currlib == NULL) + { + snprintf(g_errstring, MAX_ERROR, "Cannot export function, not in a library definition"); + return 0; + } + + if(validate_number(params[1], &nid) == 0) + { + return 0; + } + + if(g_currlib->funcCount < MAX_LIB_FUNCS) + { + if(internal_do_export(params[0], nid, &g_currlib->pFuncHead)) + { + g_currlib->funcCount++; + return 1; + } + } + else + { + snprintf(g_errstring, MAX_ERROR, "Too many functions defined, cannot export another"); + } + + return 0; +} + +int psp_export_func_hash(char **params) +{ + unsigned int nid; + unsigned char hash[SHA1_DIGEST_SIZE]; + + if(g_currlib == NULL) + { + snprintf(g_errstring, MAX_ERROR, "Cannot export function, not in a library definition"); + return 0; + } + + sha1(hash, (unsigned char *) params[0], strlen(params[0])); + nid = hash[0] | (hash[1] << 8) | (hash[2] << 16) | (hash[3] << 24); + + if(g_currlib->funcCount < MAX_LIB_FUNCS) + { + if(internal_do_export(params[0], nid, &g_currlib->pFuncHead)) + { + g_currlib->funcCount++; + return 1; + } + } + else + { + snprintf(g_errstring, MAX_ERROR, "Too many functions defined, cannot export another"); + } + + return 0; +} + +int psp_export_var_nid(char **params) +{ + unsigned int nid; + + if(g_currlib == NULL) + { + snprintf(g_errstring, MAX_ERROR, "Cannot export variable, not in a library definition"); + return 0; + } + + if(validate_number(params[1], &nid) == 0) + { + return 0; + } + + if(g_currlib->varCount < MAX_LIB_VARS) + { + if(internal_do_export(params[0], nid, &g_currlib->pVarHead)) + { + g_currlib->varCount++; + return 1; + } + } + else + { + snprintf(g_errstring, MAX_ERROR, "Too many variables defined, cannot export another"); + } + + return 0; +} + +int psp_export_var_hash(char **params) +{ + unsigned int nid; + unsigned char hash[SHA1_DIGEST_SIZE]; + + if(g_currlib == NULL) + { + snprintf(g_errstring, MAX_ERROR, "Cannot export variable, not in a library definition"); + return 0; + } + + sha1(hash, (unsigned char *) params[0], strlen(params[0])); + nid = hash[0] | (hash[1] << 8) | (hash[2] << 16) | (hash[3] << 24); + + if(g_currlib->varCount < MAX_LIB_VARS) + { + if(internal_do_export(params[0], nid, &g_currlib->pVarHead)) + { + g_currlib->varCount++; + return 1; + } + } + else + { + snprintf(g_errstring, MAX_ERROR, "Too many variables defined, cannot export another"); + } + + return 0; +} + +int psp_export_alias(char **params) +{ + struct psp_alias *pAlias; + + if(g_currlib == NULL) + { + snprintf(g_errstring, MAX_ERROR, "Cannot alias name, not in a library definition"); + return 0; + } + + pAlias = (struct psp_alias *) malloc(sizeof(struct psp_alias)); + if(pAlias == NULL) + { + snprintf(g_errstring, MAX_ERROR, "Cannot allocate memory for alias"); + return 0; + } + + memset(pAlias, 0, sizeof(*pAlias)); + strncpy(pAlias->name, params[0], MAX_LIB_ENTRY_NAME); + strncpy(pAlias->alias, params[1], MAX_LIB_ENTRY_NAME); + + if(g_currlib->pAliasHead == NULL) + { + g_currlib->pAliasHead = pAlias; + } + else + { + struct psp_alias *pNext = g_currlib->pAliasHead; + + while(pNext->pNext) + { + pNext = pNext->pNext; + } + + pNext->pNext = pAlias; + } + + fprintf(stderr, "Alias %s->%s\n", params[0], params[1]); + + return 1; +} + +struct export_cmd commands[] = +{ + { "PSP_BEGIN_EXPORTS", 0, psp_begin_exports }, + { "PSP_END_EXPORTS", 0, psp_end_exports }, + { "PSP_EXPORT_START", 3, psp_export_start }, + { "PSP_EXPORT_END", 0, psp_export_end }, + { "PSP_EXPORT_FUNC_NID", 2, psp_export_func_nid }, + { "PSP_EXPORT_FUNC_HASH", 1, psp_export_func_hash }, + { "PSP_EXPORT_FUNC", 1, psp_export_func_hash }, + { "PSP_EXPORT_VAR_NID", 2, psp_export_var_nid }, + { "PSP_EXPORT_VAR", 1, psp_export_var_hash }, + { "PSP_EXPORT_VAR_HASH", 1, psp_export_var_hash }, + { "PSP_EXPORT_ALIAS", 2, psp_export_alias }, + { NULL, 0, NULL } +}; + +int process_command(const char *cmd, char ** params, int param_count) +{ + int i; + + i = 0; + + while(commands[i].name != NULL) + { + if(strcmp(cmd, commands[i].name) == 0) + { + assert(commands[i].handler != NULL); + if(param_count != commands[i].params) + { + snprintf(g_errstring, MAX_ERROR, "Incorrect number of parameters, have %d, expect %d\n", + param_count, commands[i].params); + break; + } + else + { + return commands[i].handler(params); + } + } + + i++; + } + + if(commands[i].name == NULL) + { + snprintf(g_errstring, MAX_ERROR, "Unknown command '%s'", cmd); + } + + return 0; +} + +int load_exports(void) +{ + FILE *fp; + int line_no = 1; + + fp = fopen(g_infile, "r"); + if(fp != NULL) + { + char curr_line[MAX_LINE]; + char strip_line[MAX_LINE]; + + while(fgets(curr_line, MAX_LINE, fp)) + { + strip_whitespace(strip_line, curr_line); + if((strip_line[0] != 0) && (strip_line[0] != '#')) + { + int ret; + char *params[16]; + + ret = parse_string(strip_line, params, 16); + if(ret >= 0) + { + if(g_verbose) + { + int i; + + fprintf(stderr, "Line %d, Name: %s ", line_no, strip_line); + for(i = 0; i < ret; i++) + { + fprintf(stderr, "Arg %d: %s ", i, params[i]); + } + fprintf(stderr, "\n"); + } + + if(process_command(strip_line, params, ret) == 0) + { + fprintf(stderr, "Error, line %d: %s\n", line_no, g_errstring); + return 0; + } + } + else + { + fprintf(stderr, "Error, line %d: %s\n", line_no, g_errstring); + return 0; + } + } + + line_no++; + } + + if(g_currlib) + { + fprintf(stderr, "Error, reached end of file while still exporting a library\n"); + return 0; + } + } + else + { + fprintf(stderr, "Could not open file %s\n", g_infile); + return 0; + } + + return 1; +} + +void dump_exports(void) +{ + struct psp_lib *pLib; + int count; + + pLib = g_libhead; + count = 1; + + while(pLib != NULL) + { + fprintf(stderr, "Export %d '%s', ver %04X, attr %04X\n", count, pLib->name, pLib->ver, pLib->attr); + fprintf(stderr, "Funcs %d-%p, Vars %d-%p\n", pLib->funcCount, pLib->pFuncHead, pLib->varCount, pLib->pVarHead); + + if(pLib->pFuncHead != NULL) + { + int func; + struct psp_export *pFunc; + + func = 0; + pFunc = pLib->pFuncHead; + while(pFunc != NULL) + { + fprintf(stderr, "Function %d - '%s', nid %08X\n", func++, pFunc->name, pFunc->nid); + pFunc = pFunc->pNext; + } + } + + if(pLib->pVarHead != NULL) + { + int var; + struct psp_export *pVar; + + var = 0; + pVar = pLib->pVarHead; + while(pVar != NULL) + { + fprintf(stderr, "Variable %d - '%s', nid %08X\n", var++, pVar->name, pVar->nid); + pVar = pVar->pNext; + } + } + + + + count++; + pLib = pLib->pNext; + } +} + +int main(int argc, char **argv) +{ + if(process_args(argc, argv)) + { + if(load_exports()) + { + if(g_verbose) + { + dump_exports(); + } + switch(g_outputmode) + { + case PSP_BUILD_EXPORTS: build_exports(); + break; + /* Do the same for both */ + case PSP_BUILD_STUBS_NEW: + case PSP_BUILD_STUBS : build_stubs(); + break; + default : /* Argh */ + break; + }; + } + + free_lib_data(); + } + else + { + print_help(); + } + + return 0; +} diff --git a/utils/build-exports/sha1.c b/utils/build-exports/sha1.c new file mode 100644 index 0000000..6e2fa21 --- /dev/null +++ b/utils/build-exports/sha1.c @@ -0,0 +1,282 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 18/06/2004 + + This is a byte oriented version of SHA1 that operates on arrays of bytes + stored in memory. +*/ + +#include /* for memcpy() etc. */ +#include /* for _lrotl with VC++ */ + +#include "sha1.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* + To obtain the highest speed on processors with 32-bit words, this code + needs to determine the order in which bytes are packed into such words. + The following block of code is an attempt to capture the most obvious + ways in which various environemnts specify their endian definitions. + It may well fail, in which case the definitions will need to be set by + editing at the points marked **** EDIT HERE IF NECESSARY **** below. +*/ + +/* PLATFORM SPECIFIC INCLUDES */ + +#define BRG_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ +#define BRG_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ + +#ifdef WORDS_BIGENDIAN +#define PLATFORM_BYTE_ORDER BRG_BIG_ENDIAN +#else +#define PLATFORM_BYTE_ORDER BRG_LITTLE_ENDIAN +#endif + +#ifdef _MSC_VER +#pragma intrinsic(memcpy) +#endif + +#if 0 && defined(_MSC_VER) +#define rotl32 _lrotl +#define rotr32 _lrotr +#else +#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n))) +#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n))) +#endif + +#if !defined(bswap_32) +#define bswap_32(x) ((rotr32((x), 24) & 0x00ff00ff) | (rotr32((x), 8) & 0xff00ff00)) +#endif + +#if (PLATFORM_BYTE_ORDER == BRG_LITTLE_ENDIAN) +#define SWAP_BYTES +#else +#undef SWAP_BYTES +#endif + +#if defined(SWAP_BYTES) +#define bsw_32(p,n) \ + { int _i = (n); while(_i--) ((sha1_32t*)p)[_i] = bswap_32(((sha1_32t*)p)[_i]); } +#else +#define bsw_32(p,n) +#endif + +#define SHA1_MASK (SHA1_BLOCK_SIZE - 1) + +#if 0 + +#define ch(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define parity(x,y,z) ((x) ^ (y) ^ (z)) +#define maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +#else /* Discovered by Rich Schroeppel and Colin Plumb */ + +#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define parity(x,y,z) ((x) ^ (y) ^ (z)) +#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y)))) + +#endif + +/* Compile 64 bytes of hash data into SHA1 context. Note */ +/* that this routine assumes that the byte order in the */ +/* ctx->wbuf[] at this point is in such an order that low */ +/* address bytes in the ORIGINAL byte stream will go in */ +/* this buffer to the high end of 32-bit words on BOTH big */ +/* and little endian systems */ + +#ifdef ARRAY +#define q(v,n) v[n] +#else +#define q(v,n) v##n +#endif + +#define one_cycle(v,a,b,c,d,e,f,k,h) \ + q(v,e) += rotr32(q(v,a),27) + \ + f(q(v,b),q(v,c),q(v,d)) + k + h; \ + q(v,b) = rotr32(q(v,b), 2) + +#define five_cycle(v,f,k,i) \ + one_cycle(v, 0,1,2,3,4, f,k,hf(i )); \ + one_cycle(v, 4,0,1,2,3, f,k,hf(i+1)); \ + one_cycle(v, 3,4,0,1,2, f,k,hf(i+2)); \ + one_cycle(v, 2,3,4,0,1, f,k,hf(i+3)); \ + one_cycle(v, 1,2,3,4,0, f,k,hf(i+4)) + +void sha1_compile(sha1_ctx ctx[1]) +{ sha1_32t *w = ctx->wbuf; + +#ifdef ARRAY + sha1_32t v[5]; + memcpy(v, ctx->hash, 5 * sizeof(sha1_32t)); +#else + sha1_32t v0, v1, v2, v3, v4; + v0 = ctx->hash[0]; v1 = ctx->hash[1]; + v2 = ctx->hash[2]; v3 = ctx->hash[3]; + v4 = ctx->hash[4]; +#endif + +#define hf(i) w[i] + + five_cycle(v, ch, 0x5a827999, 0); + five_cycle(v, ch, 0x5a827999, 5); + five_cycle(v, ch, 0x5a827999, 10); + one_cycle(v,0,1,2,3,4, ch, 0x5a827999, hf(15)); \ + +#undef hf +#define hf(i) (w[(i) & 15] = rotl32( \ + w[((i) + 13) & 15] ^ w[((i) + 8) & 15] \ + ^ w[((i) + 2) & 15] ^ w[(i) & 15], 1)) + + one_cycle(v,4,0,1,2,3, ch, 0x5a827999, hf(16)); + one_cycle(v,3,4,0,1,2, ch, 0x5a827999, hf(17)); + one_cycle(v,2,3,4,0,1, ch, 0x5a827999, hf(18)); + one_cycle(v,1,2,3,4,0, ch, 0x5a827999, hf(19)); + + five_cycle(v, parity, 0x6ed9eba1, 20); + five_cycle(v, parity, 0x6ed9eba1, 25); + five_cycle(v, parity, 0x6ed9eba1, 30); + five_cycle(v, parity, 0x6ed9eba1, 35); + + five_cycle(v, maj, 0x8f1bbcdc, 40); + five_cycle(v, maj, 0x8f1bbcdc, 45); + five_cycle(v, maj, 0x8f1bbcdc, 50); + five_cycle(v, maj, 0x8f1bbcdc, 55); + + five_cycle(v, parity, 0xca62c1d6, 60); + five_cycle(v, parity, 0xca62c1d6, 65); + five_cycle(v, parity, 0xca62c1d6, 70); + five_cycle(v, parity, 0xca62c1d6, 75); + +#ifdef ARRAY + ctx->hash[0] += v[0]; ctx->hash[1] += v[1]; + ctx->hash[2] += v[2]; ctx->hash[3] += v[3]; + ctx->hash[4] += v[4]; +#else + ctx->hash[0] += v0; ctx->hash[1] += v1; + ctx->hash[2] += v2; ctx->hash[3] += v3; + ctx->hash[4] += v4; +#endif +} + +void sha1_begin(sha1_ctx ctx[1]) +{ + ctx->count[0] = ctx->count[1] = 0; + ctx->hash[0] = 0x67452301; + ctx->hash[1] = 0xefcdab89; + ctx->hash[2] = 0x98badcfe; + ctx->hash[3] = 0x10325476; + ctx->hash[4] = 0xc3d2e1f0; +} + +/* SHA1 hash data in an array of bytes into hash buffer and */ +/* call the hash_compile function as required. */ + +void sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1]) +{ sha1_32t pos = (sha1_32t)(ctx->count[0] & SHA1_MASK), + space = SHA1_BLOCK_SIZE - pos; + const unsigned char *sp = data; + + if((ctx->count[0] += len) < len) + ++(ctx->count[1]); + + while(len >= space) /* tranfer whole blocks if possible */ + { + memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space); + sp += space; len -= space; space = SHA1_BLOCK_SIZE; pos = 0; + bsw_32(ctx->wbuf, SHA1_BLOCK_SIZE >> 2); + sha1_compile(ctx); + } + + memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len); +} + +/* SHA1 final padding and digest calculation */ + +void sha1_end(unsigned char hval[], sha1_ctx ctx[1]) +{ sha1_32t i = (sha1_32t)(ctx->count[0] & SHA1_MASK); + + /* put bytes in the buffer in an order in which references to */ + /* 32-bit words will put bytes with lower addresses into the */ + /* top of 32 bit words on BOTH big and little endian machines */ + bsw_32(ctx->wbuf, (i + 3) >> 2); + + /* we now need to mask valid bytes and add the padding which is */ + /* a single 1 bit and as many zero bits as necessary. Note that */ + /* we can always add the first padding byte here because the */ + /* buffer always has at least one empty slot */ + ctx->wbuf[i >> 2] &= 0xffffff80 << 8 * (~i & 3); + ctx->wbuf[i >> 2] |= 0x00000080 << 8 * (~i & 3); + + /* we need 9 or more empty positions, one for the padding byte */ + /* (above) and eight for the length count. If there is not */ + /* enough space, pad and empty the buffer */ + if(i > SHA1_BLOCK_SIZE - 9) + { + if(i < 60) ctx->wbuf[15] = 0; + sha1_compile(ctx); + i = 0; + } + else /* compute a word index for the empty buffer positions */ + i = (i >> 2) + 1; + + while(i < 14) /* and zero pad all but last two positions */ + ctx->wbuf[i++] = 0; + + /* the following 32-bit length fields are assembled in the */ + /* wrong byte order on little endian machines but this is */ + /* corrected later since they are only ever used as 32-bit */ + /* word values. */ + ctx->wbuf[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 29); + ctx->wbuf[15] = ctx->count[0] << 3; + sha1_compile(ctx); + + /* extract the hash value as bytes in case the hash buffer is */ + /* misaligned for 32-bit words */ + for(i = 0; i < SHA1_DIGEST_SIZE; ++i) + hval[i] = (unsigned char)(ctx->hash[i >> 2] >> (8 * (~i & 3))); +} + +void sha1(unsigned char hval[], const unsigned char data[], unsigned long len) +{ sha1_ctx cx[1]; + + sha1_begin(cx); sha1_hash(data, len, cx); sha1_end(hval, cx); +} + +#if defined(__cplusplus) +} +#endif diff --git a/utils/build-exports/sha1.h b/utils/build-exports/sha1.h new file mode 100644 index 0000000..0333b5c --- /dev/null +++ b/utils/build-exports/sha1.h @@ -0,0 +1,84 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 +*/ + +#ifndef _SHA1_H +#define _SHA1_H + +#include + +#define SHA1_BLOCK_SIZE 64 +#define SHA1_DIGEST_SIZE 20 + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* define an unsigned 32-bit type */ + +#if defined(_MSC_VER) + typedef unsigned long sha1_32t; +#elif defined(ULONG_MAX) && ULONG_MAX == 0xfffffffful + typedef unsigned long sha1_32t; +#elif defined(UINT_MAX) && UINT_MAX == 0xffffffff + typedef unsigned int sha1_32t; +#else +# error Please define sha1_32t as an unsigned 32 bit type in sha1.h +#endif + +/* type to hold the SHA256 context */ + +typedef struct +{ sha1_32t count[2]; + sha1_32t hash[5]; + sha1_32t wbuf[16]; +} sha1_ctx; + +/* Note that these prototypes are the same for both bit and */ +/* byte oriented implementations. However the length fields */ +/* are in bytes or bits as appropriate for the version used */ +/* and bit sequences are input as arrays of bytes in which */ +/* bit sequences run from the most to the least significant */ +/* end of each byte */ + +void sha1_compile(sha1_ctx ctx[1]); + +void sha1_begin(sha1_ctx ctx[1]); +void sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1]); +void sha1_end(unsigned char hval[], sha1_ctx ctx[1]); +void sha1(unsigned char hval[], const unsigned char data[], unsigned long len); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/utils/kprxgen/Makefile b/utils/kprxgen/Makefile new file mode 100644 index 0000000..302ac63 --- /dev/null +++ b/utils/kprxgen/Makefile @@ -0,0 +1,27 @@ +# Copyright (C) 2011 The uOFW team +# See the file COPYING for copying permission. + +CPP=gcc +CFLAGS=-Wall -Wextra -Werror +LDFLAGS= +TARGET=psp-kprxgen +OBJECTS=psp-kprxgen.o + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + @echo "Creating binary $(TARGET)" + @$(CPP) $(OBJECTS) -o $@ $(LDFLAGS) + +%.o: %.cpp + @echo "Compiling $^" + $(CPP) $(CFLAGS) -c $^ -o $@ + +clean: + @echo "Removing all the .o files" + @$(RM) $(OBJECTS) + +mrproper: clean + @echo "Removing binary" + @$(RM) $(TARGET) + diff --git a/utils/kprxgen/elftypes.h b/utils/kprxgen/elftypes.h new file mode 100644 index 0000000..c73ddc8 --- /dev/null +++ b/utils/kprxgen/elftypes.h @@ -0,0 +1,246 @@ +/* + * PSP Software Development Kit - http://www.pspdev.org + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * elftypes.h - Definitions for the different ELF types. + * + * Copyright (c) 2005 James Forshaw + * + * $Id: elftypes.h 1520 2005-12-04 20:09:36Z tyranid $ + */ + +#ifndef __ELF_TYPES_H__ +#define __ELF_TYPES_H__ + +#include "types.h" + +#define ELF_MACHINE_MIPS 0x0008 +#define ELF_SH_STRTAB ".shstrtab" + +#define ELF_SECT_MAX_NAME 128 + +/* Structure defining a single elf section */ +struct ElfSection +{ + /* Name index */ + u32 iName; + /* Type of section */ + u32 iType; + /* Section flags */ + u32 iFlags; + /* Addr of section when loaded */ + u32 iAddr; + /* Offset of the section in the elf */ + u32 iOffset; + /* Size of the sections data */ + u32 iSize; + /* Link info */ + u32 iLink; + /* Info */ + u32 iInfo; + /* Address alignment */ + u32 iAddralign; + /* Entry size */ + u32 iEntsize; + + /* Aliased pointer to the data (in the original Elf) */ + u8 *pData; + /* Name of the section */ + char szName[ELF_SECT_MAX_NAME]; + /* Index */ + int iIndex; + /* Section Ref. Used for relocations */ + struct ElfSection *pRef; + /* Indicates if this section is to be outputted */ + int blOutput; +}; + +struct ElfProgram +{ + u32 iType; + u32 iOffset; + u32 iVaddr; + u32 iPaddr; + u32 iFilesz; + u32 iMemsz; + u32 iFlags; + u32 iAlign; + + /* Aliased pointer to the data (in the original Elf)*/ + u8 *pData; +}; + +/* Structure to hold elf header data, in native format */ +struct ElfHeader +{ + u32 iMagic; + u32 iClass; + u32 iData; + u32 iIdver; + u32 iType; + u32 iMachine; + u32 iVersion; + u32 iEntry; + u32 iPhoff; + u32 iShoff; + u32 iFlags; + u32 iEhsize; + u32 iPhentsize; + u32 iPhnum; + u32 iShentsize; + u32 iShnum; + u32 iShstrndx; +}; + +struct ElfReloc +{ + /* Pointer to the section name */ + const char* secname; + /* Base address */ + u32 base; + /* Type */ + u32 type; + /* Symbol (if known) */ + u32 symbol; + /* Offset into the file */ + u32 offset; + /* New Address for the relocation (to do with what you will) */ + u32 addr; +}; + +/* Define ELF types */ +typedef u32 Elf32_Addr; +typedef u16 Elf32_Half; +typedef u32 Elf32_Off; +typedef s32 Elf32_Sword; +typedef u32 Elf32_Word; + +#define ELF_MAGIC 0x464C457F + +#define ELF_EXEC_TYPE 0x0002 +#define ELF_PRX_TYPE 0xFFA0 + +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +#define SHT_PRXRELOC (SHT_LOPROC | 0xA0) + +// MIPS Reloc Entry Types +#define R_MIPS_NONE 0 +#define R_MIPS_16 1 +#define R_MIPS_32 2 +#define R_MIPS_REL32 3 +#define R_MIPS_26 4 +#define R_MIPS_HI16 5 +#define R_MIPS_LO16 6 +#define R_MIPS_GPREL16 7 +#define R_MIPS_LITERAL 8 +#define R_MIPS_GOT16 9 +#define R_MIPS_PC16 10 +#define R_MIPS_CALL16 11 +#define R_MIPS_GPREL32 12 + +#define SHF_WRITE 1 +#define SHF_ALLOC 2 +#define SHF_EXECINSTR 4 + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +/* ELF file header */ +typedef struct { + Elf32_Word e_magic; + u8 e_class; + u8 e_data; + u8 e_idver; + u8 e_pad[9]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} __attribute__((packed)) Elf32_Ehdr; + +/* ELF section header */ +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} __attribute__((packed)) Elf32_Shdr; + +typedef struct { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +#define ELF32_R_SYM(i) ((i)>>8) +#define ELF32_R_TYPE(i) ((u8)(i&0xFF)) + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} __attribute__((packed)) Elf32_Sym; + +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +#define ELF32_ST_BIND(i) ((i)>>4) +#define ELF32_ST_TYPE(i) ((i)&0xf) +#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) + +#endif diff --git a/utils/kprxgen/prxtypes.h b/utils/kprxgen/prxtypes.h new file mode 100644 index 0000000..fd25154 --- /dev/null +++ b/utils/kprxgen/prxtypes.h @@ -0,0 +1,150 @@ +/* + * PSP Software Development Kit - http://www.pspdev.org + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * prxtypes.h - Definition of PRX specific types. + * + * Copyright (c) 2005 James Forshaw + * + * $Id: prxtypes.h 1095 2005-09-27 21:02:16Z jim $ + */ + +#ifndef __PRXTYPES_H__ +#define __PRXTYPES_H__ + +#include "types.h" + +#define PSP_MODULE_MAX_NAME 28 +#define PSP_LIB_MAX_NAME 128 +#define PSP_ENTRY_MAX_NAME 128 +/* Define the maximum number of permitted entries per lib */ +#define PSP_MAX_V_ENTRIES 255 +#define PSP_MAX_F_ENTRIES 65535 + +#define PSP_MODULE_INFO_NAME ".rodata.sceModuleInfo" + +/* Remove the .rel.sceStub.text section as it shouldn't have been there */ +#define PSP_MODULE_REMOVE_REL ".rel.sceStub.text" + +/* Define a name for the unnamed first export */ +#define PSP_SYSTEM_EXPORT "syslib" + +enum PspEntryType +{ + PSP_ENTRY_FUNC = 0, + PSP_ENTRY_VAR = 1 +}; + +/* Define the in-prx structure types */ + +/* Structure to hold the module export information */ +struct PspModuleExport +{ + u32 name; + u32 flags; + u32 counts; + u32 exports; +} __attribute__((packed)); + +/* Structure to hold the module import information */ +struct PspModuleImport +{ + u32 name; + u32 flags; + u8 entry_size; + u8 var_count; + u16 func_count; + u32 nids; + u32 funcs; +}; + +/* Structure to hold the module info */ +struct PspModuleInfo +{ + u32 flags; + char name[PSP_MODULE_MAX_NAME]; + u32 gp; + u32 exports; + u32 exp_end; + u32 imports; + u32 imp_end; +}; + +/* Define the loaded prx types */ +struct PspEntry +{ + /* Name of the entry */ + char name[PSP_ENTRY_MAX_NAME]; + /* Nid of the entry */ + u32 nid; + /* Type of the entry */ + enum PspEntryType type; + /* Virtual address of the entry in the loaded elf */ + u32 addr; + /* Virtual address of the nid dword */ + u32 nid_addr; +}; + +/* Holds a linking entry for an import library */ +struct PspLibImport +{ + /** Previous import */ + struct PspLibImport *prev; + /** Next import */ + struct PspLibImport *next; + /** Name of the library */ + char name[PSP_LIB_MAX_NAME]; + /* Virtual address of the lib import stub */ + u32 addr; + /* Copy of the import stub (in native byte order) */ + struct PspModuleImport stub; + /* List of function entries */ + struct PspEntry funcs[PSP_MAX_F_ENTRIES]; + /* Number of function entries */ + int f_count; + /* List of variable entried */ + struct PspEntry vars[PSP_MAX_V_ENTRIES]; + /* Number of variable entires */ + int v_count; +}; + +/* Holds a linking entry for an export library */ +struct PspLibExport +{ + /** Previous export in the chain */ + struct PspLibExport *prev; + /** Next export in the chain */ + struct PspLibExport *next; + /** Name of the library */ + char name[PSP_LIB_MAX_NAME]; + /** Virtual address of the lib import stub */ + u32 addr; + /** Copy of the import stub (in native byte order) */ + struct PspModuleExport stub; + /** List of function entries */ + struct PspEntry funcs[PSP_MAX_F_ENTRIES]; + /** Number of function entries */ + int f_count; + /** List of variable entried */ + struct PspEntry vars[PSP_MAX_V_ENTRIES]; + /** Number of variable entires */ + int v_count; +}; + +/** Structure to hold the loaded module information */ +struct PspModule +{ + /** Name of the module */ + char name[PSP_MODULE_MAX_NAME+1]; + /** Info structure, in native byte order */ + struct PspModuleInfo info; + /** Virtual address of the module info section */ + u32 addr; + /** Head of the export list */ + struct PspLibExport *exp_head; + /** Head of the import list */ + struct PspLibImport *imp_head; +}; + +#endif diff --git a/utils/kprxgen/psp-kprxgen.c b/utils/kprxgen/psp-kprxgen.c new file mode 100644 index 0000000..cf05a68 --- /dev/null +++ b/utils/kprxgen/psp-kprxgen.c @@ -0,0 +1,815 @@ +/* Copyright (C) 2011 The uOFW team + See the file COPYING for copying permission. + + Based on the original file from PSPSDK, written by tyranid; many thanks to him! +*/ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "types.h" +#include "elftypes.h" +#include "prxtypes.h" + +/* Arrangement of ELF file after stripping + * + * ELF Header - 52 bytes + * Program Headers + * .text data + * .data data + * Section Headers + * Relocation data + * Section Header String Table + * + * When stripping the sections remove anything which isn't an allocated section or a relocation section. + * The section string section we will rebuild. + */ + +static const char *g_outfile; +static const char *g_infile; +static unsigned char *g_elfdata = NULL; +static struct ElfHeader g_elfhead; +static struct ElfSection *g_elfsections = NULL; +static struct ElfSection *g_modinfo = NULL; +static int g_alloc_size = 0; +static int g_reloc_size = 0; + +/* Base addresses in the Elf */ +static int g_phbase = 0; +static int g_allocbase = 0; +static int g_shbase = 0; +static int g_relocbase = 0; + +/* Specifies that the current usage is to the print the pspsdk path */ +static int g_verbose = 0; + +static struct option arg_opts[] = +{ + {"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; + + ch = getopt_long(argc, argv, "v", arg_opts, NULL); + while(ch != -1) + { + switch(ch) + { + case 'v' : g_verbose = 1; + break; + default : break; + }; + + ch = getopt_long(argc, argv, "v", arg_opts, NULL); + } + + argc -= optind; + argv += optind; + + if(argc < 2) + { + return 0; + } + + g_infile = argv[0]; + g_outfile = argv[1]; + + 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-prxgen [-v] infile.elf outfile.prx\n"); + fprintf(stderr, "Options:\n"); + fprintf(stderr, "-v, --verbose : Verbose output\n"); +} + +unsigned char *load_file(const char *file) +{ + FILE *fp; + unsigned int size; + 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"); + break; + } + + data = (unsigned char *) malloc(size); + if(data == NULL) + { + fprintf(stderr, "Error, could not allocate memory for ELF\n"); + break; + } + + (void) fread(data, 1, size, fp); + 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() +{ + int ret = 0; + int found_rel = 0; + unsigned int load_addr = 0xFFFFFFFF; + + if(g_elfhead.iShnum > 0) + { + do + { + Elf32_Shdr *sect; + u32 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]; + found_rel = 1; + g_elfsections[i].blOutput = 1; + } + } + + /* 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, PSP_MODULE_REMOVE_REL) == 0) + { + /* Don't output .rel.lib.stub relocations */ + g_elfsections[i].blOutput = 0; + } + } + + 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(!found_rel) + { + fprintf(stderr, "Error, found no relocation sections\n"); + break; + } + + if(load_addr != 0) + { + fprintf(stderr, "Error, ELF not loaded to address 0 (%08X)\n", load_addr); + break; + } + + ret = 1; + } + while(0); + } + else + { + fprintf(stderr, "Error, no sections in the ELF\n"); + } + + return ret; +} + +int remove_weak_relocs(struct ElfSection *pReloc, struct ElfSection *pSymbol, struct ElfSection *pString) +{ + int iCount; + int iMaxSymbol; + void *pNewRel = NULL; + Elf32_Rel *pInRel; + Elf32_Rel *pOutRel; + Elf32_Sym *pSymData = (Elf32_Sym *) pSymbol->pData; + char *pStrData = NULL; + int iOutput; + int i; + + if(pString != NULL) + { + pStrData = (char *) pString->pData; + } + + iMaxSymbol = pSymbol->iSize / sizeof(Elf32_Sym); + iCount = pReloc->iSize / sizeof(Elf32_Rel); + + pNewRel = malloc(pReloc->iSize); + if(pNewRel == NULL) + { + return 0; + } + pOutRel = (Elf32_Rel *) pNewRel; + pInRel = (Elf32_Rel *) pReloc->pData; + iOutput = 0; + + if(g_verbose) + { + fprintf(stderr, "[%s] Processing %d relocations, %d symbols\n", pReloc->szName, iCount, iMaxSymbol); + } + + for(i = 0; i < iCount; i++) + { + int iSymbol; + + iSymbol = ELF32_R_SYM(LW(pInRel->r_info)); + if(g_verbose) + { + fprintf(stderr, "Relocation %d - Symbol %x\n", iOutput, iSymbol); + } + + if(iSymbol >= iMaxSymbol) + { + fprintf(stderr, "Warning: Ignoring relocation as cannot find matching symbol\n"); + } + else + { + if(g_verbose) + { + if(pStrData != NULL) + { + fprintf(stderr, "Symbol %d - Name %s info %x ndx %x\n", iSymbol, &pStrData[pSymData[iSymbol].st_name], + pSymData[iSymbol].st_info, pSymData[iSymbol].st_shndx); + } + else + { + fprintf(stderr, "Symbol %d - Name %d info %x ndx %x\n", iSymbol, pSymData[iSymbol].st_name, + pSymData[iSymbol].st_info, pSymData[iSymbol].st_shndx); + } + } + + if(LH(pSymData[iSymbol].st_shndx) == 0) + { + if(g_verbose) + { + fprintf(stderr, "Deleting relocation\n"); + } + } + else + { + /* We are keeping this relocation, copy it across */ + *pOutRel = *pInRel; + pOutRel++; + iOutput++; + } + } + + pInRel++; + } + + /* If we deleted some relocations */ + if(iOutput < iCount) + { + int iSize; + + iSize = iOutput * sizeof(Elf32_Rel); + if(g_verbose) + { + fprintf(stderr, "Old relocation size %d, new %d\n", pReloc->iSize, iSize); + } + pReloc->iSize = iSize; + /* If size is zero then delete this section */ + if(iSize == 0) + { + pReloc->blOutput = 0; + } + else + { + /* Copy across the new relocation data */ + memcpy(pReloc->pData, pNewRel, pReloc->iSize); + } + } + + free(pNewRel); + + return 1; +} + +/* Let's remove the weak relocations from the list */ +int process_relocs(void) +{ + u32 i; + + for(i = 0; i < g_elfhead.iShnum; i++) + { + if((g_elfsections[i].blOutput) && (g_elfsections[i].iType == SHT_REL)) + { + struct ElfSection *pReloc; + + pReloc = &g_elfsections[i]; + if((pReloc->iLink < g_elfhead.iShnum) && (g_elfsections[pReloc->iLink].iType == SHT_SYMTAB)) + { + struct ElfSection *pStrings = NULL; + struct ElfSection *pSymbols; + + pSymbols = &g_elfsections[pReloc->iLink]; + if((pSymbols->iLink < g_elfhead.iShnum) && (g_elfsections[pSymbols->iLink].iType == SHT_STRTAB)) + { + pStrings = &g_elfsections[pSymbols->iLink]; + } + + if(!remove_weak_relocs(pReloc, pSymbols, pStrings)) + { + return 0; + } + } + else + { + if(g_verbose) + { + fprintf(stderr, "Ignoring relocation section %d, invalid link number\n", i); + } + } + } + } + + return 1; +} + +/* Reindex the sections we are keeping */ +void reindex_sections(void) +{ + u32 i; + int sect = 1; + + for(i = 0; i < g_elfhead.iShnum; i++) + { + if(g_elfsections[i].blOutput) + { + g_elfsections[i].iIndex = sect++; + } + } +} + +/* Load an ELF file */ +int load_elf(const char *elf) +{ + int ret = 0; + + do + { + g_elfdata = load_file(elf); + if(g_elfdata == NULL) + { + break; + } + + if(!validate_header(g_elfdata)) + { + break; + } + + if(!load_sections()) + { + break; + } + + if(!process_relocs()) + { + break; + } + + reindex_sections(); + + ret = 1; + } + while(0); + + return ret; +} + +int calculate_outsize(void) +{ + u32 alloc_size = 0; + int reloc_size = 0; + u32 i; + + /* Calculate how big our output file needs to be */ + /* We have elf header + 3 PH + allocated data + section headers + relocation data */ + + /* Note that the ELF should be based from 0, we use this to calculate the alloc and mem sizes */ + + /* Skip null section */ + for(i = 1; i < g_elfhead.iShnum; i++) + { + if(g_elfsections[i].blOutput) + { + if(g_elfsections[i].iType == SHT_PROGBITS) + { + unsigned int top_addr = g_elfsections[i].iAddr + g_elfsections[i].iSize; + if(top_addr > alloc_size) + { + alloc_size = top_addr; + } + } + else if((g_elfsections[i].iType == SHT_REL) || (g_elfsections[i].iType == SHT_PRXRELOC)) + { + /* Check this is a reloc for an allocated section */ + if(g_elfsections[g_elfsections[i].iInfo].iFlags & SHF_ALLOC) + { + reloc_size += g_elfsections[i].iSize; + } + } + } + } + + alloc_size = (alloc_size + 3) & ~3; + + /* Save them for future use */ + g_alloc_size = alloc_size; + g_reloc_size = reloc_size; + + /* Lets build the offsets */ + g_phbase = sizeof(Elf32_Ehdr); + /* The allocated data needs to be 64 byte aligned (probably; seen in kernel .prx files) */ + g_allocbase = (g_phbase + 3 * sizeof(Elf32_Phdr) + 0x3F) & ~0x3F; + g_relocbase = g_allocbase + g_alloc_size; + + return g_relocbase + g_reloc_size; +} + +/* Output the ELF header */ +void output_header(unsigned char *data) +{ + Elf32_Ehdr *head; + + head = (Elf32_Ehdr*) data; + + SW(&head->e_magic, g_elfhead.iMagic); + head->e_class = g_elfhead.iClass; + head->e_data = g_elfhead.iData; + head->e_idver = g_elfhead.iIdver; + SH(&head->e_type, ELF_PRX_TYPE); + SH(&head->e_machine, g_elfhead.iMachine); + SW(&head->e_version, g_elfhead.iVersion); + SW(&head->e_entry, g_elfhead.iEntry); + SW(&head->e_phoff, g_phbase); + SW(&head->e_shoff, g_shbase); + SW(&head->e_flags, g_elfhead.iFlags); + SH(&head->e_ehsize, sizeof(Elf32_Ehdr)); + SH(&head->e_phentsize, sizeof(Elf32_Phdr)); + SH(&head->e_phnum, 3); + SH(&head->e_shentsize, 0); + SH(&head->e_shnum, 0); + SH(&head->e_shstrndx, 0); +} + +struct ElfSection *get_sh(const char *name) +{ + u32 i; + for(i = 0; i < g_elfhead.iShnum; i++) + if (strcmp(name, g_elfsections[i].szName) == 0) + return &g_elfsections[i]; + return NULL; +} + +/* Output the program header */ +void output_ph(unsigned char *data) +{ + Elf32_Phdr *phdr; + struct PspModuleInfo *pModinfo; + int mod_flags; + + phdr = (Elf32_Phdr*) data; + pModinfo = (struct PspModuleInfo *) (g_modinfo->pData); + mod_flags = LW(pModinfo->flags); + + SW(&phdr->p_type, 1); + /* Starts after the program header */ + SW(&phdr->p_offset, g_allocbase); + SW(&phdr->p_vaddr, 0); + + /* Check if this is a kernel module */ + if(mod_flags & 0x1000) + { + SW(&phdr->p_paddr, 0x80000000 | (g_modinfo->iAddr + g_allocbase)); + } + else + { + SW(&phdr->p_paddr, (g_modinfo->iAddr + g_allocbase)); + } + SW(&phdr->p_filesz, g_alloc_size); + SW(&phdr->p_memsz, g_alloc_size); + SW(&phdr->p_flags, 5); + SW(&phdr->p_align, 0x40); + + /* Second program header */ + phdr++; + + SW(&phdr->p_type, 1); + SW(&phdr->p_offset, get_sh(".data")->iAddr + g_allocbase); + SW(&phdr->p_vaddr, get_sh(".data")->iAddr); + SW(&phdr->p_paddr, 0); + SW(&phdr->p_filesz, get_sh(".data")->iSize); + SW(&phdr->p_memsz, get_sh(".data")->iSize + get_sh(".bss")->iSize); + SW(&phdr->p_flags, 6); + SW(&phdr->p_align, 0x40); + + /* Third program header */ + phdr++; + + SW(&phdr->p_type, 0x700000A1); + SW(&phdr->p_offset, g_relocbase); + SW(&phdr->p_vaddr, 0); + SW(&phdr->p_paddr, 0); + SW(&phdr->p_filesz, g_reloc_size); + SW(&phdr->p_memsz, 0); + SW(&phdr->p_flags, 0); + SW(&phdr->p_align, 0x10); +} + +/* Output the allocated sections */ +void output_alloc(unsigned char *data) +{ + u32 i; + + for(i = 0; i < g_elfhead.iShnum; i++) + { + if((g_elfsections[i].blOutput) && (g_elfsections[i].iType == SHT_PROGBITS)) + { + memcpy(&data[g_elfsections[i].iAddr], g_elfsections[i].pData, g_elfsections[i].iSize); + } + } +} + +/* Output relocations */ +void output_relocs(unsigned char *data) +{ + u32 i; + unsigned char *pReloc; + + pReloc = data; + + for(i = 0; i < g_elfhead.iShnum; i++) + { + if((g_elfsections[i].blOutput) && + ((g_elfsections[i].iType == SHT_REL) || (g_elfsections[i].iType == SHT_PRXRELOC))) + { + Elf32_Rel *rel; + int j, count; + + memcpy(pReloc, g_elfsections[i].pData, g_elfsections[i].iSize); + rel = (Elf32_Rel*) pReloc; + count = g_elfsections[i].iSize / sizeof(Elf32_Rel); + for(j = 0; j < count; j++) + { + unsigned int sym; + + /* Clear the top 24bits of the info */ + /* Kind of a dirty trick but hey :P */ + sym = LW(rel->r_info); + sym &= 0xFF; + SW(&rel->r_info, sym); + rel++; + } + pReloc += g_elfsections[i].iSize; + } + } +} + +/* Output a stripped prx file */ +int output_prx(const char *prxfile) +{ + int size; + unsigned char *data; + FILE *fp; + + do + { + size = calculate_outsize(); + data = malloc(size); + if(data == NULL) + { + fprintf(stderr, "Error, couldn't allocate output data\n"); + break; + } + + memset(data, 0, size); + + output_header(data); + output_ph(data + g_phbase); + output_alloc(data + g_allocbase); + output_relocs(data + g_relocbase); + + fp = fopen(prxfile, "wb"); + if(fp != NULL) + { + fwrite(data, 1, size, fp); + fclose(fp); + } + else + { + fprintf(stderr, "Error, could not open output file %s\n", prxfile); + } + + free(data); + } + while(0); + + return 0; +} + +/* 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; + } +} + +int main(int argc, char **argv) +{ + if(process_args(argc, argv)) + { + if(load_elf(g_infile)) + { + (void) output_prx(g_outfile); + free_data(); + } + } + else + { + print_help(); + } + + return 0; +} diff --git a/utils/kprxgen/types.h b/utils/kprxgen/types.h new file mode 100644 index 0000000..f083f94 --- /dev/null +++ b/utils/kprxgen/types.h @@ -0,0 +1,149 @@ +/* + * PSP Software Development Kit - http://www.pspdev.org + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * types.h - Definition of basic cross platform types. + * + * Copyright (c) 2005 James Forshaw + * + * $Id: types.h 2333 2007-10-31 19:37:40Z tyranid $ + */ + +#ifndef __TYPES_H__ +#define __TYPES_H__ + +#include + +/* Re-define some system types */ +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +#ifdef WORDS_BIGENDIAN +inline u32 lw_le(u32 data) +{ + u8 *ptr; + u32 val; + + ptr = (u8*) &data; + + val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); + + return val; +} + +inline u16 lh_le(u16 data) +{ + u8 *ptr; + u16 val; + + ptr = (u8*) &data; + + val = ptr[0] | (ptr[1] << 8); + + return val; +} + +#define LW_LE(x) (lw_le((x))) +#define LW_BE(x) (x) +#define LH_LE(x) (lh_le((x))) +#define LH_BE(x) (x) + +#else + +inline u32 lw_be(u32 data) +{ + u8 *ptr; + u32 val; + + ptr = (u8*) &data; + + val = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]; + + return val; +} + +inline u16 lh_be(u16 data) +{ + u8 *ptr; + u16 val; + + ptr = (u8*) &data; + + val = (ptr[0] << 16) | ptr[1]; + + return val; +} + +#define LW_LE(x) (x) +#define LW_BE(x) (lw_be((x))) +#define LH_LE(x) (x) +#define LH_BE(x) (lh_be((x))) + +#endif + +#define LW(x) (LW_LE(x)) +#define LH(x) (LH_LE(x)) + + +#ifdef WORDS_BIGENDIAN +inline void sw_le(u32 *data, u32 val) +{ + u8* ptr = (u8*) data; + + ptr[0] = (u8) (val & 0xFF); + ptr[1] = (u8) ((val >> 8) & 0xFF); + ptr[2] = (u8) ((val >> 16) & 0xFF); + ptr[3] = (u8) ((val >> 24) & 0xFF); +} + +inline void sh_le(u16 *data, u16 val) +{ + u8 *ptr = (u8*) data; + + ptr[0] = (u8) (val & 0xFF); + ptr[1] = (u8) ((val >> 8) & 0xFF); +} + +#define SW_LE(x, v) (sw_le((x), (v))) +#define SW_BE(x, v) (*(x) = (v)) +#define SH_LE(x, v) (sh_le((x), (v))) +#define SH_BE(x, v) (*(x) = (v)) + +#else + +inline void sw_be(u32 *data, u32 val) +{ + u8 *ptr = (u8*) data; + + ptr[0] = (u8) ((val >> 24) & 0xFF); + ptr[1] = (u8) ((val >> 16) & 0xFF); + ptr[2] = (u8) ((val >> 8) & 0xFF); + ptr[3] = (u8) (val & 0xFF); +} + +inline void sh_be(u16 *data, u16 val) +{ + u8* ptr = (u8*) data; + + ptr[0] = (u8) ((val >> 8) & 0xFF); + ptr[1] = (u8) (val & 0xFF); +} + +#define SW_LE(x, v) (*(x) = (v)) +#define SW_BE(x, v) (sw_be((x), (v))) +#define SH_LE(x, v) (*(x) = (v)) +#define SH_BE(x, v) (sh_be((x), (v))) + +#endif + +#define SW(x, v) (SW_LE(x, v)) +#define SH(x, v) (SH_LE(x, v)) + +#endif