mirror of
https://github.com/pspdev/pspsdk.git
synced 2026-01-03 14:12:21 +00:00
first commit
This commit is contained in:
23
tools/Makefile.am
Normal file
23
tools/Makefile.am
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
bin_PROGRAMS = bin2s bin2c bin2o pack-pbp unpack-pbp mksfo mksfoex psp-config psp-build-exports psp-prxgen psp-fixup-imports
|
||||
|
||||
bin2s_SOURCES = bin2s.c
|
||||
bin2c_SOURCES = bin2c.c
|
||||
bin2o_SOURCES = bin2o.c
|
||||
|
||||
pack_pbp_SOURCES = pack-pbp.c
|
||||
unpack_pbp_SOURCES = unpack-pbp.c
|
||||
|
||||
mksfo_SOURCES = mksfo.c
|
||||
|
||||
mksfoex_SOURCES = mksfoex.c
|
||||
|
||||
psp_config_SOURCES = psp-config.c getopt_long.c
|
||||
|
||||
psp_build_exports_SOURCES = psp-build-exports.c getopt_long.c sha1.c
|
||||
|
||||
psp_prxgen_SOURCES = psp-prxgen.c getopt_long.c
|
||||
|
||||
psp_fixup_imports_SOURCES = psp-fixup-imports.c getopt_long.c sha1.c
|
||||
|
||||
noinst_HEADERS = elftypes.h getopt.h prxtypes.h sha1.h types.h
|
||||
73
tools/bin2c.c
Normal file
73
tools/bin2c.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
# _____ ___ ____ ___ ____
|
||||
# ____| | ____| | | |____|
|
||||
# | ___| | ___| ____| | \ PSPDEV Open Source Project.
|
||||
#-----------------------------------------------------------------------
|
||||
# Review pspsdk README & LICENSE files for further details.
|
||||
#
|
||||
# $Id: bin2c.c 210 2005-06-18 17:52:59Z mrbrown $
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
unsigned char *buffer;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd_size;
|
||||
FILE *source,*dest;
|
||||
int i;
|
||||
|
||||
if(argc != 4) {
|
||||
printf("bin2c - from bin2s By Sjeep\n"
|
||||
"Usage: bin2c infile outfile label\n\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if((source=fopen( argv[1], "rb")) == NULL) {
|
||||
printf("Error opening %s for reading.\n",argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fseek(source,0,SEEK_END);
|
||||
fd_size = ftell(source);
|
||||
fseek(source,0,SEEK_SET);
|
||||
|
||||
buffer = malloc(fd_size);
|
||||
if(buffer == NULL) {
|
||||
printf("Failed to allocate memory.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(fread(buffer,1,fd_size,source) != fd_size) {
|
||||
printf("Failed to read file.\n");
|
||||
return 1;
|
||||
}
|
||||
fclose(source);
|
||||
|
||||
if((dest = fopen(argv[2],"w+")) == NULL) {
|
||||
printf("Failed to open/create %s.\n",argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(dest, "#ifndef __%s__\n", argv[3]);
|
||||
fprintf(dest, "#define __%s__\n\n", argv[3]);
|
||||
fprintf(dest, "static unsigned int size_%s = %d;\n", argv[3], fd_size);
|
||||
fprintf(dest, "static unsigned char %s[] __attribute__((aligned(16))) = {", argv[3]);
|
||||
|
||||
for(i=0;i<fd_size;i+=1) {
|
||||
if((i % 16) == 0) fprintf(dest, "\n\t");
|
||||
fprintf(dest, "0x%02x, ", buffer[i]);
|
||||
}
|
||||
|
||||
fprintf(dest, "\n};\n\n#endif\n");
|
||||
|
||||
fclose(dest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
385
tools/bin2o.c
Normal file
385
tools/bin2o.c
Normal file
@@ -0,0 +1,385 @@
|
||||
/*
|
||||
# _____ ___ ____ ___ ____
|
||||
# ____| | ____| | | |____|
|
||||
# | ___| | ___| ____| | \ PSPDEV Open Source Project.
|
||||
#-----------------------------------------------------------------------
|
||||
# Review pspsdk README & LICENSE files for further details.
|
||||
#
|
||||
# $Id: bin2o.c 1988 2006-08-06 12:06:54Z chip $
|
||||
# Convets any file into a PSP's .o file.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
int alignment = 16;
|
||||
int have_size = 1;
|
||||
int have_irx = 0;
|
||||
|
||||
u32 LE32(u32 b) {
|
||||
u32 t = 0x12345678;
|
||||
if (*((unsigned char*)(&t)) == 0x78) {
|
||||
return b;
|
||||
} else {
|
||||
return ((b & 0xff000000) >> 24) |
|
||||
((b & 0x00ff0000) >> 8 ) |
|
||||
((b & 0x0000ff00) << 8 ) |
|
||||
((b & 0x000000ff) << 24);
|
||||
}
|
||||
}
|
||||
|
||||
u16 LE16(u16 b) {
|
||||
u32 t = 0x12345678;
|
||||
if (*((unsigned char*)(&t)) == 0x78) {
|
||||
return b;
|
||||
} else {
|
||||
return ((b & 0xff00) >> 8) |
|
||||
((b & 0x00ff) << 8);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char elf_header[] = {
|
||||
0x7f, 'E', 'L', 'F', 0x01, 0x01, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // e_ident
|
||||
0x01, 0x00, // e_type (relocatable)
|
||||
0x08, 0x00, // e_machine (mips)
|
||||
0x01, 0x00, 0x00, 0x00, // e_version
|
||||
0x00, 0x00, 0x00, 0x00, // e_entry
|
||||
0x00, 0x00, 0x00, 0x00, // e_phoff
|
||||
0x34, 0x00, 0x00, 0x00, // e_shoff
|
||||
0x01, 0x40, 0x92, 0x20, // e_flags
|
||||
0x34, 0x00, // e_ehsize
|
||||
0x00, 0x00, // e_phentsize
|
||||
0x00, 0x00, // e_phnum
|
||||
0x28, 0x00, // e_shentsize
|
||||
0x05, 0x00, // e_shnum
|
||||
0x01, 0x00, // e_shstrndx
|
||||
};
|
||||
|
||||
// 0 = NULL
|
||||
// 1 = .shstrtab
|
||||
// 2 = .symtab
|
||||
// 3 = .strtab
|
||||
// 4 = .data
|
||||
|
||||
struct elf_section_t {
|
||||
u32 sh_name, sh_type, sh_flags, sh_addr, sh_offset, sh_size;
|
||||
u32 sh_link, sh_info, sh_addralign, sh_entsize;
|
||||
};
|
||||
|
||||
struct elf_symbol_t {
|
||||
u32 st_name, st_value, st_size;
|
||||
u8 st_info, st_other;
|
||||
u16 st_shndx;
|
||||
};
|
||||
|
||||
// 0 0000000001 11111111 12222222 22233
|
||||
// 0 1234567890 12345678 90123456 78901
|
||||
char shstrtab[] = "\0.shstrtab\0.symtab\0.strtab\0.data";
|
||||
|
||||
void create_elf(FILE * dest, const unsigned char * source, u32 size, const char * label) {
|
||||
int i, l_size;
|
||||
struct elf_section_t section;
|
||||
struct elf_symbol_t symbol;
|
||||
u32 strtab_size;
|
||||
char strtab[512];
|
||||
u32 data_size[4];
|
||||
|
||||
if (have_irx) {
|
||||
elf_header[36] = 1;
|
||||
elf_header[37] = 0;
|
||||
elf_header[38] = 0;
|
||||
elf_header[39] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(elf_header); i++) {
|
||||
fputc(elf_header[i], dest);
|
||||
}
|
||||
|
||||
l_size = strlen(label);
|
||||
|
||||
strtab[0] = 0;
|
||||
strcpy(strtab + 1, label);
|
||||
strcat(strtab + 1, "_start");
|
||||
strcpy(strtab + 1 + l_size + 7, label);
|
||||
strcat(strtab + 1 + l_size + 7, "_end");
|
||||
if (have_size) {
|
||||
strtab_size = (l_size * 3 + 1 + 7 + 5 + 6);
|
||||
strcpy(strtab + 1 + l_size + 7 + l_size + 5, label);
|
||||
strcat(strtab + 1 + l_size + 7 + l_size + 5, "_size");
|
||||
} else {
|
||||
strtab_size = (l_size * 2 + 1 + 7 + 5);
|
||||
}
|
||||
|
||||
// section 0 (NULL)
|
||||
section.sh_name = section.sh_type = section.sh_flags = section.sh_addr = section.sh_offset = section.sh_size =
|
||||
section.sh_link = section.sh_info = section.sh_addralign = section.sh_entsize = 0;
|
||||
|
||||
fwrite(§ion, 1, sizeof(section), dest);
|
||||
|
||||
|
||||
// section 1 (.shstrtab)
|
||||
section.sh_name = LE32(1);
|
||||
section.sh_type = LE32(3); // STRTAB
|
||||
section.sh_flags = 0;
|
||||
section.sh_addr = 0;
|
||||
section.sh_offset = LE32(40 * 5 + 0x34);
|
||||
section.sh_size = LE32(33);
|
||||
section.sh_link = 0;
|
||||
section.sh_info = 0;
|
||||
section.sh_addralign = LE32(1);
|
||||
section.sh_entsize = 0;
|
||||
|
||||
fwrite(§ion, 1, sizeof(section), dest);
|
||||
|
||||
|
||||
// section 2 (.symtab)
|
||||
section.sh_name = LE32(11);
|
||||
section.sh_type = LE32(2); // SYMTAB
|
||||
section.sh_flags = 0;
|
||||
section.sh_addr = 0;
|
||||
section.sh_offset = LE32(40 * 5 + 0x34 + 33);
|
||||
section.sh_size = LE32(have_size ? 0x30 : 0x20);
|
||||
section.sh_link = LE32(3);
|
||||
section.sh_info = 0;
|
||||
section.sh_addralign = LE32(4);
|
||||
section.sh_entsize = LE32(0x10);
|
||||
|
||||
fwrite(§ion, 1, sizeof(section), dest);
|
||||
|
||||
|
||||
// section 3 (.strtab)
|
||||
section.sh_name = LE32(19);
|
||||
section.sh_type = LE32(3); // STRTAB
|
||||
section.sh_flags = 0;
|
||||
section.sh_addr = 0;
|
||||
section.sh_offset = LE32(40 * 5 + 0x34 + 33 + (have_size ? 0x30 : 0x20));
|
||||
section.sh_size = LE32(strtab_size);
|
||||
section.sh_link = 0;
|
||||
section.sh_info = 0;
|
||||
section.sh_addralign = LE32(1);
|
||||
section.sh_entsize = 0;
|
||||
|
||||
fwrite(§ion, 1, sizeof(section), dest);
|
||||
|
||||
|
||||
// section 4 (.data)
|
||||
section.sh_name = LE32(27);
|
||||
section.sh_type = LE32(1); // PROGBITS
|
||||
section.sh_flags = LE32(3); // Write + Alloc
|
||||
section.sh_addr = 0;
|
||||
section.sh_offset = LE32(40 * 5 + 0x34 + 33 + (have_size ? 0x30 : 0x20) + strtab_size);
|
||||
section.sh_size = LE32(size + have_size * 16);
|
||||
section.sh_link = 0;
|
||||
section.sh_addralign = LE32(alignment);
|
||||
section.sh_entsize = 0;
|
||||
|
||||
fwrite(§ion, 1, sizeof(section), dest);
|
||||
|
||||
|
||||
|
||||
fwrite(shstrtab, 1, 33, dest);
|
||||
|
||||
symbol.st_name = LE32(1);
|
||||
symbol.st_value = LE32(have_size * 16);
|
||||
symbol.st_size = LE32(size);
|
||||
symbol.st_info = 0x11;
|
||||
symbol.st_other = 0;
|
||||
symbol.st_shndx = LE16(4);
|
||||
fwrite(&symbol, 1, sizeof(symbol), dest);
|
||||
|
||||
symbol.st_name = LE32(l_size + 1 + 7);
|
||||
symbol.st_value = LE32(size + have_size * 16);
|
||||
symbol.st_size = 0;
|
||||
symbol.st_info = 0x11;
|
||||
symbol.st_other = 0;
|
||||
symbol.st_shndx = LE16(4);
|
||||
fwrite(&symbol, 1, sizeof(symbol), dest);
|
||||
|
||||
if (have_size) {
|
||||
symbol.st_name = LE32(l_size * 2 + 1 + 7 + 5);
|
||||
symbol.st_value = 0;
|
||||
symbol.st_size = LE32(4);
|
||||
symbol.st_info = 0x11;
|
||||
symbol.st_other = 0;
|
||||
symbol.st_shndx = LE16(4);
|
||||
fwrite(&symbol, 1, sizeof(symbol), dest);
|
||||
}
|
||||
|
||||
fwrite(strtab, 1, strtab_size, dest);
|
||||
|
||||
if (have_size) {
|
||||
data_size[0] = LE32(size);
|
||||
data_size[1] = 0;
|
||||
data_size[2] = 0;
|
||||
data_size[3] = 0;
|
||||
fwrite(data_size, 4, 4, dest);
|
||||
}
|
||||
fwrite(source, 1, size, dest);
|
||||
}
|
||||
|
||||
void usage() {
|
||||
printf("bin2o - Converts a binary file into a .o file.\n"
|
||||
"Usage: bin2o [-a XX] [-n] [-i] [-b XX] [-e XX] [-s XX] infile outfile label\n"
|
||||
" -i - create an iop-compatible .o file.\n"
|
||||
" -n - don't add label_size symbol.\n"
|
||||
" -a XX - set .data section alignment to XX.\n"
|
||||
" (has to be a power of two).\n"
|
||||
" -b XX - start reading file at this offset.\n"
|
||||
" -e XX - stop reading file at this offset.\n"
|
||||
" -s XX - force output data to be of this size.\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
u32 fd_size, start = 0, end = 0xffffffff, size = 0xffffffff;
|
||||
unsigned char * buffer;
|
||||
FILE * source, * dest;
|
||||
char * f_source = 0, * f_dest = 0, * f_label = 0;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-') {
|
||||
switch (argv[i][1]) {
|
||||
case 'a':
|
||||
i++;
|
||||
if (!argv[i]) {
|
||||
usage();
|
||||
printf("-a requires an argument.\n");
|
||||
return 1;
|
||||
}
|
||||
if (argv[i][0] == '-') {
|
||||
usage();
|
||||
printf("-a requires an argument.\n");
|
||||
return 1;
|
||||
}
|
||||
alignment = atoi(argv[i]);
|
||||
if ((alignment - 1) & alignment) {
|
||||
printf("Error: alignment must be a power of 2.\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
have_size = 0;
|
||||
break;
|
||||
case 'i':
|
||||
have_irx = 1;
|
||||
break;
|
||||
case 'b':
|
||||
i++;
|
||||
if (!argv[i]) {
|
||||
usage();
|
||||
printf("-b requires an argument.\n");
|
||||
return 1;
|
||||
}
|
||||
if (argv[i][0] == '-') {
|
||||
usage();
|
||||
printf("-b requires an argument.\n");
|
||||
return 1;
|
||||
}
|
||||
start = atoi(argv[i]);
|
||||
break;
|
||||
case 'e':
|
||||
i++;
|
||||
if (!argv[i]) {
|
||||
usage();
|
||||
printf("-e requires an argument.\n");
|
||||
return 1;
|
||||
}
|
||||
if (argv[i][0] == '-') {
|
||||
usage();
|
||||
printf("-e requires an argument.\n");
|
||||
return 1;
|
||||
}
|
||||
end = atoi(argv[i]);
|
||||
break;
|
||||
case 's':
|
||||
i++;
|
||||
if (!argv[i]) {
|
||||
usage();
|
||||
printf("-s requires an argument.\n");
|
||||
return 1;
|
||||
}
|
||||
if (argv[i][0] == '-') {
|
||||
usage();
|
||||
printf("-s requires an argument.\n");
|
||||
return 1;
|
||||
}
|
||||
size = atoi(argv[i]);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
printf("Unknow option: %s.\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (!f_source) {
|
||||
f_source = argv[i];
|
||||
} else if (!f_dest) {
|
||||
f_dest = argv[i];
|
||||
} else if (!f_label) {
|
||||
f_label = argv[i];
|
||||
} else {
|
||||
usage();
|
||||
printf("Too many arguments.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!f_source || !f_dest || !f_label) {
|
||||
usage();
|
||||
printf("Not enough arguments.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(source = fopen(f_source, "rb"))) {
|
||||
printf("Error opening %s for reading.\n", f_source);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fseek(source, 0, SEEK_END);
|
||||
fd_size = ftell(source);
|
||||
fseek(source, start, SEEK_SET);
|
||||
|
||||
if (fd_size < end)
|
||||
end = fd_size;
|
||||
|
||||
if (end < (size - start))
|
||||
size = end - start;
|
||||
|
||||
buffer = malloc(size);
|
||||
if (buffer == NULL) {
|
||||
printf("Failed to allocate memory.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fread(buffer, 1, size, source) != size) {
|
||||
printf("Failed to read file.\n");
|
||||
return 1;
|
||||
}
|
||||
fclose(source);
|
||||
|
||||
if (!(dest = fopen(f_dest, "wb+"))) {
|
||||
printf("Failed to open/create %s.\n", f_dest);
|
||||
return 1;
|
||||
}
|
||||
|
||||
create_elf(dest, buffer, size, f_label);
|
||||
|
||||
fclose(dest);
|
||||
free(buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
75
tools/bin2s.c
Normal file
75
tools/bin2s.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
# _____ ___ ____ ___ ____
|
||||
# ____| | ____| | | |____|
|
||||
# | ___| | ___| ____| | \ PSPDEV Open Source Project.
|
||||
#-----------------------------------------------------------------------
|
||||
# Review pspsdk README & LICENSE files for further details.
|
||||
#
|
||||
# $Id: bin2s.c 210 2005-06-18 17:52:59Z mrbrown $
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
unsigned char *buffer;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd_size;
|
||||
FILE *source,*dest;
|
||||
int i;
|
||||
|
||||
if(argc != 4) {
|
||||
printf("bin2s - By Sjeep\n"
|
||||
"Usage: bin2s infile outfile label\n\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if((source=fopen( argv[1], "rb")) == NULL) {
|
||||
printf("Error opening %s for reading.\n",argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fseek(source,0,SEEK_END);
|
||||
fd_size = ftell(source);
|
||||
fseek(source,0,SEEK_SET);
|
||||
|
||||
buffer = malloc(fd_size);
|
||||
if(buffer == NULL) {
|
||||
printf("Failed to allocate memory.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(fread(buffer,1,fd_size,source) != fd_size) {
|
||||
printf("Failed to read file.\n");
|
||||
return 1;
|
||||
}
|
||||
fclose(source);
|
||||
|
||||
if((dest = fopen(argv[2],"w+")) == NULL) {
|
||||
printf("Failed to open/create %s.\n",argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(dest, ".sdata\n\n");
|
||||
fprintf(dest, ".globl size_%s\nsize_%s:\t.word %d\n\n", argv[3], argv[3], fd_size);
|
||||
fprintf(dest, ".data\n\n");
|
||||
fprintf(dest, ".balign 16\n\n");
|
||||
fprintf(dest, ".globl %s\n",argv[3]);
|
||||
fprintf(dest, "%s:\n\n",argv[3]);
|
||||
|
||||
for(i=0;i<fd_size;i++) {
|
||||
if((i % 16) == 0) fprintf(dest, "\n\t.byte 0x%02x", buffer[i]);
|
||||
else fprintf(dest, ", 0x%02x", buffer[i]);
|
||||
}
|
||||
|
||||
fprintf(dest, "\n");
|
||||
|
||||
fclose(dest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
246
tools/elftypes.h
Normal file
246
tools/elftypes.h
Normal file
@@ -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 <tyranid@gmail.com>
|
||||
*
|
||||
* $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
|
||||
68
tools/getopt.h
Normal file
68
tools/getopt.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* $NetBSD: getopt.h,v 1.7 2005/02/03 04:39:32 perry Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Dieter Baron and Thomas Klausner.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _GETOPT_H_
|
||||
#define _GETOPT_H_
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
|
||||
extern char *optarg;
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
struct option {
|
||||
/* name of long option */
|
||||
const char *name;
|
||||
/*
|
||||
* one of no_argument, required_argument, and optional_argument:
|
||||
* whether option takes an argument
|
||||
*/
|
||||
int has_arg;
|
||||
/* if not NULL, set *flag to val when option found */
|
||||
int *flag;
|
||||
/* if flag not NULL, value to set *flag to; else return value */
|
||||
int val;
|
||||
};
|
||||
|
||||
int getopt_long(int, char * const *, const char *,
|
||||
const struct option *, int *);
|
||||
|
||||
#endif /* !_GETOPT_H_ */
|
||||
405
tools/getopt_long.c
Normal file
405
tools/getopt_long.c
Normal file
@@ -0,0 +1,405 @@
|
||||
/* $NetBSD: getopt_long.c,v 1.19 2005/12/02 14:08:51 yamt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Dieter Baron and Thomas Klausner.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int opterr = 1; /* if error message should be printed */
|
||||
int optind = 1; /* index into parent argv vector */
|
||||
int optopt = '?'; /* character checked for validity */
|
||||
int optreset; /* reset getopt */
|
||||
char *optarg; /* argument associated with option */
|
||||
|
||||
#define IGNORE_FIRST (*options == '-' || *options == '+')
|
||||
#define PRINT_ERROR ((opterr) && ((*options != ':') \
|
||||
|| (IGNORE_FIRST && options[1] != ':')))
|
||||
#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
|
||||
#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
|
||||
/* XXX: GNU ignores PC if *options == '-' */
|
||||
#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
|
||||
|
||||
/* return values */
|
||||
#define BADCH (int)'?'
|
||||
#define BADARG ((IGNORE_FIRST && options[1] == ':') \
|
||||
|| (*options == ':') ? (int)':' : (int)'?')
|
||||
#define INORDER (int)1
|
||||
|
||||
#define EMSG ""
|
||||
|
||||
static int getopt_internal (int, char **, const char *);
|
||||
static int gcd (int, int);
|
||||
static void permute_args (int, int, int, char **);
|
||||
|
||||
static const char *place = EMSG; /* option letter processing */
|
||||
|
||||
/* XXX: set optreset to 1 rather than these two */
|
||||
static int nonopt_start = -1; /* first non option argument (for permute) */
|
||||
static int nonopt_end = -1; /* first option after non options (for permute) */
|
||||
|
||||
/* Error messages */
|
||||
static const char recargchar[] = "option requires an argument -- %c";
|
||||
static const char recargstring[] = "option requires an argument -- %s";
|
||||
static const char ambig[] = "ambiguous option -- %.*s";
|
||||
static const char noarg[] = "option doesn't take an argument -- %.*s";
|
||||
static const char illoptchar[] = "unknown option -- %c";
|
||||
static const char illoptstring[] = "unknown option -- %s";
|
||||
|
||||
|
||||
/*
|
||||
* Compute the greatest common divisor of a and b.
|
||||
*/
|
||||
static int
|
||||
gcd(a, b)
|
||||
int a;
|
||||
int b;
|
||||
{
|
||||
int c;
|
||||
|
||||
c = a % b;
|
||||
while (c != 0) {
|
||||
a = b;
|
||||
b = c;
|
||||
c = a % b;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exchange the block from nonopt_start to nonopt_end with the block
|
||||
* from nonopt_end to opt_end (keeping the same order of arguments
|
||||
* in each block).
|
||||
*/
|
||||
static void
|
||||
permute_args(int panonopt_start, int panonopt_end, int opt_end, char **nargv)
|
||||
{
|
||||
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
|
||||
char *swap;
|
||||
|
||||
/*
|
||||
* compute lengths of blocks and number and size of cycles
|
||||
*/
|
||||
nnonopts = panonopt_end - panonopt_start;
|
||||
nopts = opt_end - panonopt_end;
|
||||
ncycle = gcd(nnonopts, nopts);
|
||||
cyclelen = (opt_end - panonopt_start) / ncycle;
|
||||
|
||||
for (i = 0; i < ncycle; i++) {
|
||||
cstart = panonopt_end+i;
|
||||
pos = cstart;
|
||||
for (j = 0; j < cyclelen; j++) {
|
||||
if (pos >= panonopt_end)
|
||||
pos -= nnonopts;
|
||||
else
|
||||
pos += nopts;
|
||||
swap = nargv[pos];
|
||||
nargv[pos] = nargv[cstart];
|
||||
nargv[cstart] = swap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* getopt_internal --
|
||||
* Parse argc/argv argument vector. Called by user level routines.
|
||||
* Returns -2 if -- is found (can be long option or end of options marker).
|
||||
*/
|
||||
static int
|
||||
getopt_internal(int nargc, char **nargv, const char *options)
|
||||
{
|
||||
char *oli; /* option letter list index */
|
||||
int optchar;
|
||||
|
||||
optarg = NULL;
|
||||
|
||||
/*
|
||||
* XXX Some programs (like rsyncd) expect to be able to
|
||||
* XXX re-initialize optind to 0 and have getopt_long(3)
|
||||
* XXX properly function again. Work around this braindamage.
|
||||
*/
|
||||
if (optind == 0)
|
||||
optind = 1;
|
||||
|
||||
if (optreset)
|
||||
nonopt_start = nonopt_end = -1;
|
||||
start:
|
||||
if (optreset || !*place) { /* update scanning pointer */
|
||||
optreset = 0;
|
||||
if (optind >= nargc) { /* end of argument vector */
|
||||
place = EMSG;
|
||||
if (nonopt_end != -1) {
|
||||
/* do permutation, if we have to */
|
||||
permute_args(nonopt_start, nonopt_end,
|
||||
optind, nargv);
|
||||
optind -= nonopt_end - nonopt_start;
|
||||
}
|
||||
else if (nonopt_start != -1) {
|
||||
/*
|
||||
* If we skipped non-options, set optind
|
||||
* to the first of them.
|
||||
*/
|
||||
optind = nonopt_start;
|
||||
}
|
||||
nonopt_start = nonopt_end = -1;
|
||||
return -1;
|
||||
}
|
||||
if ((*(place = nargv[optind]) != '-')
|
||||
|| (place[1] == '\0')) { /* found non-option */
|
||||
place = EMSG;
|
||||
if (IN_ORDER) {
|
||||
/*
|
||||
* GNU extension:
|
||||
* return non-option as argument to option 1
|
||||
*/
|
||||
optarg = nargv[optind++];
|
||||
return INORDER;
|
||||
}
|
||||
if (!PERMUTE) {
|
||||
/*
|
||||
* if no permutation wanted, stop parsing
|
||||
* at first non-option
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
/* do permutation */
|
||||
if (nonopt_start == -1)
|
||||
nonopt_start = optind;
|
||||
else if (nonopt_end != -1) {
|
||||
permute_args(nonopt_start, nonopt_end,
|
||||
optind, nargv);
|
||||
nonopt_start = optind -
|
||||
(nonopt_end - nonopt_start);
|
||||
nonopt_end = -1;
|
||||
}
|
||||
optind++;
|
||||
/* process next argument */
|
||||
goto start;
|
||||
}
|
||||
if (nonopt_start != -1 && nonopt_end == -1)
|
||||
nonopt_end = optind;
|
||||
if (place[1] && *++place == '-') { /* found "--" */
|
||||
place++;
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
if ((optchar = (int)*place++) == (int)':' ||
|
||||
(oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
|
||||
/* option letter unknown or ':' */
|
||||
if (!*place)
|
||||
++optind;
|
||||
if (PRINT_ERROR)
|
||||
fprintf(stderr, illoptchar, optchar);
|
||||
optopt = optchar;
|
||||
return BADCH;
|
||||
}
|
||||
if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
|
||||
/* XXX: what if no long options provided (called by getopt)? */
|
||||
if (*place)
|
||||
return -2;
|
||||
|
||||
if (++optind >= nargc) { /* no arg */
|
||||
place = EMSG;
|
||||
if (PRINT_ERROR)
|
||||
fprintf(stderr, recargchar, optchar);
|
||||
optopt = optchar;
|
||||
return BADARG;
|
||||
} else /* white space */
|
||||
place = nargv[optind];
|
||||
/*
|
||||
* Handle -W arg the same as --arg (which causes getopt to
|
||||
* stop parsing).
|
||||
*/
|
||||
return -2;
|
||||
}
|
||||
if (*++oli != ':') { /* doesn't take argument */
|
||||
if (!*place)
|
||||
++optind;
|
||||
} else { /* takes (optional) argument */
|
||||
optarg = NULL;
|
||||
if (*place) /* no white space */
|
||||
optarg = (char *) place;
|
||||
/* XXX: disable test for :: if PC? (GNU doesn't) */
|
||||
else if (oli[1] != ':') { /* arg not optional */
|
||||
if (++optind >= nargc) { /* no arg */
|
||||
place = EMSG;
|
||||
if (PRINT_ERROR)
|
||||
fprintf(stderr, recargchar, optchar);
|
||||
optopt = optchar;
|
||||
return BADARG;
|
||||
} else
|
||||
optarg = nargv[optind];
|
||||
}
|
||||
place = EMSG;
|
||||
++optind;
|
||||
}
|
||||
/* dump back option letter */
|
||||
return optchar;
|
||||
}
|
||||
|
||||
/*
|
||||
* getopt_long --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int
|
||||
getopt_long(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = getopt_internal(nargc, (char **) (nargv), options);
|
||||
if (retval == -2) {
|
||||
char *current_argv, *has_equal;
|
||||
size_t current_argv_len;
|
||||
int i, match;
|
||||
|
||||
current_argv = (char *) (place);
|
||||
match = -1;
|
||||
|
||||
optind++;
|
||||
place = EMSG;
|
||||
|
||||
if (*current_argv == '\0') { /* found "--" */
|
||||
/*
|
||||
* We found an option (--), so if we skipped
|
||||
* non-options, we have to permute.
|
||||
*/
|
||||
if (nonopt_end != -1) {
|
||||
permute_args(nonopt_start, nonopt_end,
|
||||
optind, (char **) (nargv));
|
||||
optind -= nonopt_end - nonopt_start;
|
||||
}
|
||||
nonopt_start = nonopt_end = -1;
|
||||
return -1;
|
||||
}
|
||||
if ((has_equal = strchr(current_argv, '=')) != NULL) {
|
||||
/* argument found (--option=arg) */
|
||||
current_argv_len = has_equal - current_argv;
|
||||
has_equal++;
|
||||
} else
|
||||
current_argv_len = strlen(current_argv);
|
||||
|
||||
for (i = 0; long_options[i].name; i++) {
|
||||
/* find matching long option */
|
||||
if (strncmp(current_argv, long_options[i].name,
|
||||
current_argv_len))
|
||||
continue;
|
||||
|
||||
if (strlen(long_options[i].name) ==
|
||||
(unsigned)current_argv_len) {
|
||||
/* exact match */
|
||||
match = i;
|
||||
break;
|
||||
}
|
||||
if (match == -1) /* partial match */
|
||||
match = i;
|
||||
else {
|
||||
/* ambiguous abbreviation */
|
||||
if (PRINT_ERROR)
|
||||
fprintf(stderr, ambig, (int)current_argv_len,
|
||||
current_argv);
|
||||
optopt = 0;
|
||||
return BADCH;
|
||||
}
|
||||
}
|
||||
if (match != -1) { /* option found */
|
||||
if (long_options[match].has_arg == no_argument
|
||||
&& has_equal) {
|
||||
if (PRINT_ERROR)
|
||||
fprintf(stderr, noarg, (int)current_argv_len,
|
||||
current_argv);
|
||||
/*
|
||||
* XXX: GNU sets optopt to val regardless of
|
||||
* flag
|
||||
*/
|
||||
if (long_options[match].flag == NULL)
|
||||
optopt = long_options[match].val;
|
||||
else
|
||||
optopt = 0;
|
||||
return BADARG;
|
||||
}
|
||||
if (long_options[match].has_arg == required_argument ||
|
||||
long_options[match].has_arg == optional_argument) {
|
||||
if (has_equal)
|
||||
optarg = has_equal;
|
||||
else if (long_options[match].has_arg ==
|
||||
required_argument) {
|
||||
/*
|
||||
* optional argument doesn't use
|
||||
* next nargv
|
||||
*/
|
||||
optarg = nargv[optind++];
|
||||
}
|
||||
}
|
||||
if ((long_options[match].has_arg == required_argument)
|
||||
&& (optarg == NULL)) {
|
||||
/*
|
||||
* Missing argument; leading ':'
|
||||
* indicates no error should be generated
|
||||
*/
|
||||
if (PRINT_ERROR)
|
||||
fprintf(stderr, recargstring, current_argv);
|
||||
/*
|
||||
* XXX: GNU sets optopt to val regardless
|
||||
* of flag
|
||||
*/
|
||||
if (long_options[match].flag == NULL)
|
||||
optopt = long_options[match].val;
|
||||
else
|
||||
optopt = 0;
|
||||
--optind;
|
||||
return BADARG;
|
||||
}
|
||||
} else { /* unknown option */
|
||||
if (PRINT_ERROR)
|
||||
fprintf(stderr, illoptstring, current_argv);
|
||||
optopt = 0;
|
||||
return BADCH;
|
||||
}
|
||||
if (long_options[match].flag) {
|
||||
*long_options[match].flag = long_options[match].val;
|
||||
retval = 0;
|
||||
} else
|
||||
retval = long_options[match].val;
|
||||
if (idx)
|
||||
*idx = match;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
78
tools/mksfo.c
Normal file
78
tools/mksfo.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
# _____ ___ ____ ___ ____
|
||||
# ____| | ____| | | |____|
|
||||
# | ___| | ___| ____| | \ PSPDEV Open Source Project.
|
||||
#-----------------------------------------------------------------------
|
||||
# Review ps2sdk README & LICENSE files for further details.
|
||||
#
|
||||
# A simple tool to build an SFO file for use in the EBOOT.PBP
|
||||
# $Id: mksfo.c 1993 2006-08-23 21:40:16Z jim $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SIZE_POS 0x88
|
||||
#define TITLE_POS 0x118
|
||||
#define TITLE_SIZE 0x7F
|
||||
|
||||
/* A default, simple SFO file */
|
||||
unsigned char g_defaultSfo[] = {
|
||||
0x00, 0x50, 0x53, 0x46, 0x01, 0x01, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x04, 0x02, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x12, 0x00, 0x04, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x04, 0x02, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x18, 0x00, 0x00, 0x00, 0x27, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x36, 0x00, 0x04, 0x02, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x00, 0x00, 0x45, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x2c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x04, 0x02, 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
|
||||
0x30, 0x00, 0x00, 0x00, 0x42, 0x4f, 0x4f, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x00, 0x43, 0x41, 0x54,
|
||||
0x45, 0x47, 0x4f, 0x52, 0x59, 0x00, 0x44, 0x49, 0x53, 0x43, 0x5f, 0x49, 0x44, 0x00, 0x44, 0x49,
|
||||
0x53, 0x43, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x00, 0x50, 0x41, 0x52, 0x45, 0x4e,
|
||||
0x54, 0x41, 0x4c, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x00, 0x50, 0x53, 0x50, 0x5f, 0x53, 0x59,
|
||||
0x53, 0x54, 0x45, 0x4d, 0x5f, 0x56, 0x45, 0x52, 0x00, 0x52, 0x45, 0x47, 0x49, 0x4f, 0x4e, 0x00,
|
||||
0x54, 0x49, 0x54, 0x4c, 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4d, 0x47, 0x00, 0x00,
|
||||
0x55, 0x43, 0x4a, 0x53, 0x31, 0x30, 0x30, 0x34, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x31, 0x2e, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x2e, 0x30, 0x30,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *fp;
|
||||
int len;
|
||||
|
||||
if(argc < 3)
|
||||
{
|
||||
fprintf(stderr, "Usage: mksfo TITLE output.sfo\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
len = strlen(argv[1]);
|
||||
if(len > TITLE_SIZE) len = TITLE_SIZE;
|
||||
g_defaultSfo[SIZE_POS] = (unsigned char) len;
|
||||
strncpy((char *) &g_defaultSfo[TITLE_POS], argv[1], len);
|
||||
|
||||
fp = fopen(argv[2], "wb");
|
||||
if(fp != NULL)
|
||||
{
|
||||
fwrite(g_defaultSfo, 1, sizeof(g_defaultSfo), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Could not open %s\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
341
tools/mksfoex.c
Normal file
341
tools/mksfoex.c
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
# _____ ___ ____ ___ ____
|
||||
# ____| | ____| | | |____|
|
||||
# | ___| | ___| ____| | \ PSPDEV Open Source Project.
|
||||
#-----------------------------------------------------------------------
|
||||
# Review pspsdk README & LICENSE files for further details.
|
||||
#
|
||||
# New and improved mksfo
|
||||
# $Id$
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "types.h"
|
||||
|
||||
#define PSF_MAGIC 0x46535000
|
||||
#define PSF_VERSION 0x00000101
|
||||
|
||||
struct SfoHeader
|
||||
{
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t keyofs;
|
||||
uint32_t valofs;
|
||||
uint32_t count;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct SfoEntry
|
||||
{
|
||||
uint16_t nameofs;
|
||||
uint8_t alignment;
|
||||
uint8_t type;
|
||||
uint32_t valsize;
|
||||
uint32_t totalsize;
|
||||
uint32_t dataofs;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define PSF_TYPE_BIN 0
|
||||
#define PSF_TYPE_STR 2
|
||||
#define PSF_TYPE_VAL 4
|
||||
|
||||
struct EntryContainer
|
||||
{
|
||||
const char *name;
|
||||
int type;
|
||||
uint32_t value;
|
||||
const char *data;
|
||||
};
|
||||
|
||||
struct EntryContainer g_defaults[] = {
|
||||
{ "BOOTABLE", PSF_TYPE_VAL, 1, NULL },
|
||||
{ "CATEGORY", PSF_TYPE_STR, 0, "MG" },
|
||||
{ "DISC_ID", PSF_TYPE_STR, 0, "UCJS10041" },
|
||||
{ "DISC_VERSION", PSF_TYPE_STR, 0, "1.00" },
|
||||
{ "PARENTAL_LEVEL", PSF_TYPE_VAL, 1, NULL },
|
||||
{ "PSP_SYSTEM_VER", PSF_TYPE_STR, 0, "1.00" },
|
||||
{ "REGION", PSF_TYPE_VAL, 0x8000, NULL },
|
||||
};
|
||||
|
||||
#define MAX_OPTIONS (256)
|
||||
|
||||
static const char *g_title = NULL;
|
||||
static const char *g_filename = NULL;
|
||||
static int g_empty = 0;
|
||||
static struct EntryContainer g_vals[MAX_OPTIONS];
|
||||
|
||||
static struct option arg_opts[] =
|
||||
{
|
||||
{"dword", required_argument, NULL, 'd'},
|
||||
{"string", required_argument, NULL, 's'},
|
||||
{"empty", no_argument, NULL, 'e'},
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
struct EntryContainer *find_free()
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < MAX_OPTIONS; i++)
|
||||
{
|
||||
if(g_vals[i].name == NULL)
|
||||
{
|
||||
return &g_vals[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct EntryContainer *find_name(const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < MAX_OPTIONS; i++)
|
||||
{
|
||||
if((g_vals[i].name != NULL) && (strcmp(g_vals[i].name, name) == 0))
|
||||
{
|
||||
return &g_vals[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int add_string(char *str)
|
||||
{
|
||||
char *equals = NULL;
|
||||
struct EntryContainer *entry;
|
||||
|
||||
equals = strchr(str, '=');
|
||||
if(equals == NULL)
|
||||
{
|
||||
fprintf(stderr, "Invalid option (no =)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*equals++ = 0;
|
||||
|
||||
entry = find_free();
|
||||
if(entry == NULL)
|
||||
{
|
||||
fprintf(stderr, "Maximum options reached\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(entry, 0, sizeof(struct EntryContainer));
|
||||
entry->name = str;
|
||||
entry->type = PSF_TYPE_STR;
|
||||
entry->data = equals;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int add_dword(char *str)
|
||||
{
|
||||
char *equals = NULL;
|
||||
struct EntryContainer *entry;
|
||||
|
||||
equals = strchr(str, '=');
|
||||
if(equals == NULL)
|
||||
{
|
||||
fprintf(stderr, "Invalid option (no =)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*equals++ = 0;
|
||||
|
||||
entry = find_free();
|
||||
if(entry == NULL)
|
||||
{
|
||||
fprintf(stderr, "Maximum options reached\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(entry, 0, sizeof(struct EntryContainer));
|
||||
entry->name = str;
|
||||
entry->type = PSF_TYPE_VAL;
|
||||
entry->value = strtoul(equals, NULL, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Process the arguments */
|
||||
int process_args(int argc, char **argv)
|
||||
{
|
||||
int ch;
|
||||
|
||||
g_title = NULL;
|
||||
g_filename = NULL;
|
||||
g_empty = 0;
|
||||
|
||||
ch = getopt_long(argc, argv, "ed:s:", arg_opts, NULL);
|
||||
while(ch != -1)
|
||||
{
|
||||
switch(ch)
|
||||
{
|
||||
case 'd' : if(!add_dword(optarg))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 's' : if(!add_string(optarg))
|
||||
{
|
||||
}
|
||||
break;
|
||||
default : break;
|
||||
};
|
||||
|
||||
ch = getopt_long(argc, argv, "ed:s:", arg_opts, NULL);
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if(argc < 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!g_empty)
|
||||
{
|
||||
g_title = argv[0];
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if(argc < 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_filename = argv[0];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *fp;
|
||||
int i;
|
||||
char head[8192];
|
||||
char keys[8192];
|
||||
char data[8192];
|
||||
struct SfoHeader *h;
|
||||
struct SfoEntry *e;
|
||||
char *k;
|
||||
char *d;
|
||||
unsigned int align;
|
||||
unsigned int keyofs;
|
||||
unsigned int count;
|
||||
|
||||
if(!process_args(argc, argv))
|
||||
{
|
||||
fprintf(stderr, "Usage: mksfoex [options] TITLE output.sfo\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, "-d NAME=VALUE - Add a new DWORD value\n");
|
||||
fprintf(stderr, "-s NAME=STR - Add a new string value\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!g_empty)
|
||||
{
|
||||
struct EntryContainer *entry;
|
||||
|
||||
for(i = 0; i < (sizeof(g_defaults) / sizeof(struct EntryContainer)); i++)
|
||||
{
|
||||
if(!find_name(g_defaults[i].name))
|
||||
{
|
||||
entry = find_free();
|
||||
if(entry == NULL)
|
||||
{
|
||||
fprintf(stderr, "Maximum options reached\n");
|
||||
return 0;
|
||||
}
|
||||
*entry = g_defaults[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(!find_name("TITLE"))
|
||||
{
|
||||
entry = find_free();
|
||||
entry->name = "TITLE";
|
||||
entry->type = PSF_TYPE_STR;
|
||||
entry->value = 0;
|
||||
entry->data = g_title;
|
||||
}
|
||||
}
|
||||
|
||||
memset(head, 0, sizeof(head));
|
||||
memset(keys, 0, sizeof(keys));
|
||||
memset(data, 0, sizeof(data));
|
||||
h = (struct SfoHeader*) head;
|
||||
e = (struct SfoEntry*) (head+sizeof(struct SfoHeader));
|
||||
k = keys;
|
||||
d = data;
|
||||
SW(&h->magic, PSF_MAGIC);
|
||||
SW(&h->version, PSF_VERSION);
|
||||
count = 0;
|
||||
|
||||
for(i = 0; g_vals[i].name; i++)
|
||||
{
|
||||
SW(&h->count, ++count);
|
||||
SW(&e->nameofs, k-keys);
|
||||
SW(&e->dataofs, d-data);
|
||||
SW(&e->alignment, 4);
|
||||
SW(&e->type, g_vals[i].type);
|
||||
|
||||
strcpy(k, g_vals[i].name);
|
||||
k += strlen(k)+1;
|
||||
if(e->type == PSF_TYPE_VAL)
|
||||
{
|
||||
SW(&e->valsize, 4);
|
||||
SW(&e->totalsize, 4);
|
||||
SW((uint32_t*) d, g_vals[i].value);
|
||||
d += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
int totalsize;
|
||||
int valsize;
|
||||
|
||||
valsize = strlen(g_vals[i].data)+1;
|
||||
totalsize = (valsize + 3) & ~3;
|
||||
SW(&e->valsize, valsize);
|
||||
SW(&e->totalsize, totalsize);
|
||||
memset(d, 0, totalsize);
|
||||
memcpy(d, g_vals[i].data, valsize);
|
||||
d += totalsize;
|
||||
}
|
||||
e++;
|
||||
}
|
||||
|
||||
|
||||
keyofs = (char*)e - head;
|
||||
SW(&h->keyofs, keyofs);
|
||||
align = 3 - ((unsigned int) (k-keys) & 3);
|
||||
while(align < 3)
|
||||
{
|
||||
k++;
|
||||
align--;
|
||||
}
|
||||
|
||||
SW(&h->valofs, keyofs + (k-keys));
|
||||
|
||||
fp = fopen(g_filename, "wb");
|
||||
if(fp == NULL)
|
||||
{
|
||||
fprintf(stderr, "Cannot open filename %s\n", g_filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fwrite(head, 1, (char*)e-head, fp);
|
||||
fwrite(keys, 1, k-keys, fp);
|
||||
fwrite(data, 1, d-data, fp);
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
189
tools/pack-pbp.c
Normal file
189
tools/pack-pbp.c
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
# _____ ___ ____ ___ ____
|
||||
# ____| | ____| | | |____|
|
||||
# | ___| | ___| ____| | \ PSPDEV Open Source Project.
|
||||
#-----------------------------------------------------------------------
|
||||
# (c) 2005 Dan Peori <peori@oopo.net>
|
||||
# Licenced under Academic Free License version 2.0
|
||||
# Review pspsdk README & LICENSE files for further details.
|
||||
#
|
||||
# 2006-12-30 - Andrew Whatson <whatson@gmail.com>
|
||||
# - rewrote for easier reading
|
||||
# - gave "correct" names to UNKNOWN.* files
|
||||
# - improved memory efficiency with large PBPs
|
||||
# - output name of each file as it's added
|
||||
#
|
||||
# $Id: pack-pbp.c 2228 2007-05-01 05:22:03Z oopo $
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|
||||
// Swap the bytes of an int for big-endian machines
|
||||
static int swap_int(int n)
|
||||
{
|
||||
return ((n>>24)&0xff)|((n>>8)&0xff00)|((n<<8)&0xff0000)|((n<<24)&0xff000000);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_MALLOC_H
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
// Struct to describe the header of a PBP file
|
||||
struct {
|
||||
char signature[4];
|
||||
char version[4];
|
||||
int offset[8];
|
||||
} header = {
|
||||
{ 0x00, 0x50, 0x42, 0x50 },
|
||||
{ 0x00, 0x00, 0x01, 0x00 },
|
||||
{ 40, 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
// Maximum size of read buffer
|
||||
int maxbuffer = 16 * 1024 * 1024;
|
||||
|
||||
int main(int argc, char *argv[]) { int loop0, result;
|
||||
FILE *infile;
|
||||
FILE *outfile;
|
||||
int filesize[8];
|
||||
|
||||
// Check for the correct number of arguments
|
||||
if (argc != 10) {
|
||||
printf("USAGE: %s <output.pbp> <param.sfo> <icon0.png> <icon1.pmf> <pic0.png> <pic1.png> <snd0.at3> <data.psp> <data.psar>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// For each file in the PBP
|
||||
for (loop0 = 0; loop0 < 8; loop0++) {
|
||||
|
||||
// If the specificed filename is NULL or -, skip the file.
|
||||
if (strncmp(argv[2 + loop0], "NULL", 4) == 0 || strncmp(argv[2 + loop0], "-", 4) == 0) {
|
||||
filesize[loop0] = 0;
|
||||
} else {
|
||||
|
||||
// Open the file
|
||||
infile = fopen(argv[2 + loop0], "rb");
|
||||
if (infile == NULL) {
|
||||
printf("ERROR: Could not open the file. (%s)\n", argv[2 + loop0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read in the file size
|
||||
fseek(infile, 0, SEEK_END);
|
||||
filesize[loop0] = ftell(infile);
|
||||
fseek(infile, 0, SEEK_SET);
|
||||
if (filesize[loop0] < 0) {
|
||||
printf("ERROR: Could not read in the file size. (%s)\n", argv[2 + loop0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Close the file
|
||||
result = fclose(infile);
|
||||
if (result < 0) {
|
||||
printf("ERROR: Could not close the file. (%s)\n", argv[2 + loop0]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the header offset values for each file
|
||||
for (loop0 = 1; loop0 < 8; loop0++) {
|
||||
header.offset[loop0] = header.offset[loop0 - 1] + filesize[loop0 - 1];
|
||||
}
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|
||||
// Swap the bytes of the offsets for big-endian machines
|
||||
for (loop0 = 0; loop0 < 8; loop0++) {
|
||||
header.offset[loop0] = swap_int(header.offset[loop0]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Open the output file
|
||||
outfile = fopen(argv[1], "wb");
|
||||
if (outfile == NULL) {
|
||||
printf("ERROR: Could not open the output file. (%s)\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Write out the header
|
||||
result = fwrite(&header, sizeof(header), 1, outfile);
|
||||
if (result < 0) {
|
||||
printf("ERROR: Could not write out the file header. (%s)\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// For each file in the PBP
|
||||
for (loop0 = 0; loop0 < 8; loop0++) {
|
||||
void *buffer;
|
||||
int readsize;
|
||||
|
||||
// Print out the file details
|
||||
printf("[%d] %10d bytes | %s\n", loop0, filesize[loop0], argv[2 + loop0]);
|
||||
|
||||
// If this file is empty, skip it
|
||||
if (!filesize[loop0]) continue;
|
||||
|
||||
// Open the file
|
||||
infile = fopen(argv[2 + loop0], "rb");
|
||||
if (infile == NULL) {
|
||||
printf("ERROR: Could not open the file. (%s)\n", argv[2 + loop0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
do {
|
||||
// Make sure we don't exceed the maximum buffer size
|
||||
if (filesize[loop0] > maxbuffer) {
|
||||
readsize = maxbuffer;
|
||||
} else {
|
||||
readsize = filesize[loop0];
|
||||
}
|
||||
filesize[loop0] -= readsize;
|
||||
|
||||
// Create the read buffer
|
||||
buffer = malloc(readsize);
|
||||
if (buffer == NULL) {
|
||||
printf("ERROR: Could not allocate the file data space. (%s)\n", argv[2 + loop0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read in the data from the file
|
||||
if (fread(buffer, readsize, 1, infile) < 0) {
|
||||
printf("ERROR: Could not read in the file data. (%s)\n", argv[2 + loop0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Write the contents of the buffer to the PBP
|
||||
if (fwrite(buffer, readsize, 1, outfile) < 0) {
|
||||
printf("ERROR: Could not write out the file data. (%s)\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Clean up the buffer
|
||||
free(buffer);
|
||||
|
||||
// Repeat if we haven't finished writing the file
|
||||
} while (filesize[loop0]);
|
||||
}
|
||||
|
||||
// Close the output file.
|
||||
result = fclose(outfile);
|
||||
if (result < 0) {
|
||||
printf("ERROR: Could not close the output file. (%s)\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Exit successful
|
||||
return 0;
|
||||
}
|
||||
150
tools/prxtypes.h
Normal file
150
tools/prxtypes.h
Normal file
@@ -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 <tyranid@gmail.com>
|
||||
*
|
||||
* $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
|
||||
1058
tools/psp-build-exports.c
Normal file
1058
tools/psp-build-exports.c
Normal file
File diff suppressed because it is too large
Load Diff
290
tools/psp-config.c
Normal file
290
tools/psp-config.c
Normal file
@@ -0,0 +1,290 @@
|
||||
#if defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#define PSPDEV_ENV "PSPDEV"
|
||||
#define PATH_ENV "PATH"
|
||||
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH 256
|
||||
#endif
|
||||
|
||||
/***** Might need to change these for different platforms */
|
||||
#define PATH_SEP ":"
|
||||
#define DIR_SEP '/'
|
||||
#define DIR_SEP_STR "/"
|
||||
|
||||
/* The suffix to the path to strip off, if this is not there then we have an error */
|
||||
#ifdef __MINGW32__
|
||||
#define PSPDEV_PATH_SUFFIX "/bin/psp-config.exe"
|
||||
#else
|
||||
#define PSPDEV_PATH_SUFFIX "/bin/psp-config"
|
||||
#endif
|
||||
/************************/
|
||||
|
||||
enum PspConfigMode
|
||||
{
|
||||
PSP_CONFIG_UNKNOWN,
|
||||
PSP_CONFIG_PSPSDK_PATH,
|
||||
PSP_CONFIG_PSPDEV_PATH,
|
||||
PSP_CONFIG_PSP_PREFIX,
|
||||
};
|
||||
|
||||
/* Specifies that the current usage is to the print the pspsdk path */
|
||||
static enum PspConfigMode g_configmode;
|
||||
|
||||
static struct option arg_opts[] =
|
||||
{
|
||||
{"pspsdk-path", no_argument, NULL, 'p'},
|
||||
{"pspdev-path", no_argument, NULL, 'd'},
|
||||
{"psp-prefix", no_argument, NULL, 'P'},
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
/* Process the arguments */
|
||||
int process_args(int argc, char **argv)
|
||||
{
|
||||
int ret = 0;
|
||||
int ch;
|
||||
|
||||
g_configmode = PSP_CONFIG_UNKNOWN;
|
||||
|
||||
ch = getopt_long(argc, argv, "pdP", arg_opts, NULL);
|
||||
while(ch != -1)
|
||||
{
|
||||
switch(ch)
|
||||
{
|
||||
case 'p' : g_configmode = PSP_CONFIG_PSPSDK_PATH;
|
||||
ret = 1;
|
||||
break;
|
||||
case 'd' : g_configmode = PSP_CONFIG_PSPDEV_PATH;
|
||||
ret = 1;
|
||||
break;
|
||||
case 'P' : g_configmode = PSP_CONFIG_PSP_PREFIX;
|
||||
ret = 1;
|
||||
break;
|
||||
default : fprintf(stderr, "Invalid option '%c'\n", ch);
|
||||
break;
|
||||
};
|
||||
|
||||
ch = getopt_long(argc, argv, "p", arg_opts, NULL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void print_help(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: psp-config [opts]\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, "-p, --pspsdk-path : Print the base directory of PSPSDK\n");
|
||||
fprintf(stderr, "-d, --pspdev-path : Print the base install directory\n");
|
||||
fprintf(stderr, "-P, --psp-prefix : Print the prefix of PSP-hosted software\n");
|
||||
}
|
||||
|
||||
void normalize_path (char *out)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
/* Convert "//" to "/" */
|
||||
for (i = 0; out[i + 1]; i++) {
|
||||
if (out[i] == '/' && out[i + 1] == '/') {
|
||||
for (j = i + 1; out[j]; j++) {
|
||||
out[j] = out[j + 1];
|
||||
}
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the path to the pspdev dir (e.g. /usr/local/pspdev) */
|
||||
char *find_pspdev_path(char *name)
|
||||
{
|
||||
static char path[MAX_PATH];
|
||||
int found = 0;
|
||||
|
||||
/* Check if name is an absolute path, if so our job is done */
|
||||
|
||||
#ifdef __MINGW32__
|
||||
|
||||
char *writableName = malloc(strlen(name) + 2);
|
||||
char *ptr = writableName;
|
||||
char temp;
|
||||
|
||||
while (*(name)) {
|
||||
temp = *(name++);
|
||||
if (temp == '\\') temp = '/';
|
||||
*(ptr++) = temp;
|
||||
}
|
||||
|
||||
*(ptr) = '\0';
|
||||
name = writableName;
|
||||
#endif
|
||||
|
||||
if(name[0] == DIR_SEP
|
||||
#ifdef __MINGW32__
|
||||
|| name[1] == ':'
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* Absolute path */
|
||||
strncpy(path, name, MAX_PATH);
|
||||
/* Ensure NUL termination */
|
||||
path[MAX_PATH-1] = 0;
|
||||
found = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* relative path */
|
||||
if(strchr(name, DIR_SEP) != NULL)
|
||||
{
|
||||
if(getcwd(path, MAX_PATH) != NULL)
|
||||
{
|
||||
strncat(path, DIR_SEP_STR, MAX_PATH-1);
|
||||
strncat(path, name, MAX_PATH-1);
|
||||
found = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error getting current working directory\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char *path_env;
|
||||
/* Scan the PATH variable */
|
||||
path_env = getenv(PATH_ENV);
|
||||
if(path_env != NULL)
|
||||
{
|
||||
char *curr_tok;
|
||||
char new_path[MAX_PATH];
|
||||
|
||||
/* Should really use the path separator from the
|
||||
environment but who on earth changes it? */
|
||||
curr_tok = strtok(path_env, PATH_SEP);
|
||||
while(curr_tok != NULL)
|
||||
{
|
||||
strcpy(new_path, curr_tok);
|
||||
strcat(new_path, DIR_SEP_STR);
|
||||
strcat(new_path, name);
|
||||
|
||||
if(access(new_path, X_OK) == 0)
|
||||
{
|
||||
found = 1;
|
||||
strcpy(path, new_path);
|
||||
break;
|
||||
}
|
||||
|
||||
curr_tok = strtok(NULL, PATH_SEP);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error, couldn't get PATH environment variable\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
normalize_path(path);
|
||||
char *result = NULL;
|
||||
|
||||
if(found)
|
||||
{
|
||||
int suffix_len;
|
||||
int path_len;
|
||||
|
||||
suffix_len = strlen(PSPDEV_PATH_SUFFIX);
|
||||
path_len = strlen(path);
|
||||
|
||||
if(suffix_len <= path_len)
|
||||
{
|
||||
if(strcmp(PSPDEV_PATH_SUFFIX, &path[path_len - suffix_len]) == 0)
|
||||
{
|
||||
/* Oki valid path add a NUL */
|
||||
path[path_len - suffix_len] = 0;
|
||||
result = path;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error, invalid suffix on the end of the path. Should be %s\n", PSPDEV_PATH_SUFFIX);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error, path not large enough for creating the PSPSDK path\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef __MINGW32__
|
||||
free(writableName);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void print_path(char *name)
|
||||
{
|
||||
char *pspdev_env;
|
||||
|
||||
pspdev_env = getenv(PSPDEV_ENV);
|
||||
if(pspdev_env == NULL)
|
||||
{
|
||||
/* Could not find the PSPDEV environment variable */
|
||||
/* Let's try and find where psp-config is */
|
||||
pspdev_env = find_pspdev_path(name);
|
||||
}
|
||||
|
||||
if (pspdev_env != NULL) {
|
||||
switch(g_configmode)
|
||||
{
|
||||
case PSP_CONFIG_PSPSDK_PATH : printf("%s%c%s\n", pspdev_env, DIR_SEP, PSPSDK_TOPDIR);
|
||||
break;
|
||||
case PSP_CONFIG_PSPDEV_PATH : printf("%s\n", pspdev_env);
|
||||
break;
|
||||
case PSP_CONFIG_PSP_PREFIX : printf("%s%c%s\n", pspdev_env, DIR_SEP, "psp");
|
||||
break;
|
||||
default : fprintf(stderr, "Error, invalida configuration mode\n");
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#if defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||
// this will store the fully-qualified path
|
||||
char psp_config_path[MAX_PATH] = "";
|
||||
|
||||
// fetch the path of the executable
|
||||
if(GetModuleFileName(0, psp_config_path, sizeof(psp_config_path) - 1) == 0)
|
||||
{
|
||||
// fall back
|
||||
strcpy(psp_config_path, argv[0]);
|
||||
}
|
||||
#endif
|
||||
if(process_args(argc, argv))
|
||||
{
|
||||
#if defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||
print_path(psp_config_path);
|
||||
#else
|
||||
print_path(argv[0]);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
print_help();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
851
tools/psp-fixup-imports.c
Normal file
851
tools/psp-fixup-imports.c
Normal file
@@ -0,0 +1,851 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* 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>
|
||||
*
|
||||
* $Id: psp-fixup-imports.c 2324 2007-10-03 00:51:52Z tyranid $
|
||||
*/
|
||||
|
||||
#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 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;
|
||||
}
|
||||
|
||||
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");
|
||||
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(unsigned char *data)
|
||||
{
|
||||
int ret = 0;
|
||||
int found_rel = 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];
|
||||
found_rel = 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, 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];
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
do
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(mapfile, "r");
|
||||
if(fp != NULL)
|
||||
{
|
||||
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)
|
||||
{
|
||||
fprintf(stderr, "Found import to fixup. pStub %08X, Nid %08X, NidInSect %08X\n", stub_addr, 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)
|
||||
{
|
||||
fprintf(stderr, "Import Stub %p, %08X, %08X, %02X, %02X, %04X, %08X, %08X\n", pImport,
|
||||
LW(pImport->name), 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, "Error, could not fixup imports, stubs out of order.\n");
|
||||
fprintf(stderr, "Ensure the SDK libraries are linked in last to correct this error\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
941
tools/psp-prxgen.c
Normal file
941
tools/psp-prxgen.c
Normal file
@@ -0,0 +1,941 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* psp-prxgen.c - Simple program to build a PRX file (and strip at the same time)
|
||||
*
|
||||
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
||||
*
|
||||
* $Id: psp-prxgen.c 1520 2005-12-04 20:09:36Z tyranid $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#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 = {0};
|
||||
static struct ElfSection *g_elfsections = NULL;
|
||||
static struct ElfSection *g_modinfo = NULL;
|
||||
static int g_out_sects = 2;
|
||||
static int g_alloc_size = 0;
|
||||
static int g_mem_size = 0;
|
||||
static int g_reloc_size = 0;
|
||||
static int g_str_size = 1;
|
||||
|
||||
/* 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;
|
||||
static int g_shstrbase = 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(unsigned char *data)
|
||||
{
|
||||
int ret = 0;
|
||||
int found_rel = 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];
|
||||
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)
|
||||
{
|
||||
int 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)
|
||||
{
|
||||
int 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(g_elfdata))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(!process_relocs())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
reindex_sections();
|
||||
|
||||
ret = 1;
|
||||
}
|
||||
while(0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int calculate_outsize(void)
|
||||
{
|
||||
/* out_sects starts at two for the null section and the section string table */
|
||||
int out_sects = 2;
|
||||
int alloc_size = 0;
|
||||
int reloc_size = 0;
|
||||
int mem_size = 0;
|
||||
/* 1 for the NUL for the NULL section */
|
||||
int str_size = 1;
|
||||
int i;
|
||||
|
||||
/* Calculate how big our output file needs to be */
|
||||
/* We have elf header + 1 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;
|
||||
|
||||
top_addr = g_elfsections[i].iAddr + g_elfsections[i].iSize;
|
||||
|
||||
if(top_addr > alloc_size)
|
||||
{
|
||||
alloc_size = top_addr;
|
||||
}
|
||||
|
||||
if(top_addr > mem_size)
|
||||
{
|
||||
mem_size = top_addr;
|
||||
}
|
||||
|
||||
out_sects++;
|
||||
str_size += strlen(g_elfsections[i].szName) + 1;
|
||||
}
|
||||
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;
|
||||
out_sects++;
|
||||
str_size += strlen(g_elfsections[i].szName) + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int top_addr;
|
||||
|
||||
top_addr = g_elfsections[i].iAddr + g_elfsections[i].iSize;
|
||||
|
||||
if(top_addr > mem_size)
|
||||
{
|
||||
mem_size = top_addr;
|
||||
}
|
||||
|
||||
out_sects++;
|
||||
str_size += strlen(g_elfsections[i].szName) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alloc_size = (alloc_size + 3) & ~3;
|
||||
mem_size = (mem_size + 3) & ~3;
|
||||
str_size = (str_size + 3) & ~3;
|
||||
str_size += strlen(ELF_SH_STRTAB) + 1;
|
||||
|
||||
if(g_verbose)
|
||||
{
|
||||
fprintf(stderr, "Out_sects %d, alloc_size %d, reloc_size %d, str_size %d, mem_size %d\n",
|
||||
out_sects, alloc_size, reloc_size, str_size, mem_size);
|
||||
}
|
||||
|
||||
/* Save them for future use */
|
||||
g_out_sects = out_sects;
|
||||
g_alloc_size = alloc_size;
|
||||
g_reloc_size = reloc_size;
|
||||
g_mem_size = mem_size;
|
||||
g_str_size = str_size;
|
||||
|
||||
/* Lets build the offsets */
|
||||
g_phbase = sizeof(Elf32_Ehdr);
|
||||
/* The allocated data needs to be 16 byte aligned */
|
||||
g_allocbase = (g_phbase + sizeof(Elf32_Shdr) + 0xF) & ~0xF;
|
||||
g_shbase = g_allocbase + g_alloc_size;
|
||||
g_relocbase = g_shbase + (g_out_sects * sizeof(Elf32_Shdr));
|
||||
g_shstrbase = g_relocbase + g_reloc_size;
|
||||
|
||||
if(g_verbose)
|
||||
{
|
||||
fprintf(stderr, "PHBase %08X, AllocBase %08X, SHBase %08X\n", g_phbase, g_allocbase, g_shbase);
|
||||
fprintf(stderr, "Relocbase %08X, Shstrbase %08X\n", g_relocbase, g_shstrbase);
|
||||
fprintf(stderr, "Total size %d\n", g_shstrbase + g_str_size);
|
||||
}
|
||||
|
||||
return (g_shstrbase + g_str_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, 1);
|
||||
SH(&head->e_shentsize, sizeof(Elf32_Shdr));
|
||||
SH(&head->e_shnum, g_out_sects);
|
||||
SH(&head->e_shstrndx, g_out_sects-1);
|
||||
}
|
||||
|
||||
/* 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_mem_size);
|
||||
SW(&phdr->p_flags, 5);
|
||||
SW(&phdr->p_align, 0x10);
|
||||
}
|
||||
|
||||
/* Output the allocated sections */
|
||||
void output_alloc(unsigned char *data)
|
||||
{
|
||||
int 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 the section headers */
|
||||
void output_sh(unsigned char *data)
|
||||
{
|
||||
unsigned int reloc_ofs;
|
||||
unsigned int str_ofs;
|
||||
Elf32_Shdr *shdr;
|
||||
int i;
|
||||
|
||||
shdr = (Elf32_Shdr*) data;
|
||||
/* For the NULL section */
|
||||
shdr++;
|
||||
memset(data, 0, g_out_sects * sizeof(Elf32_Shdr));
|
||||
|
||||
reloc_ofs = g_relocbase;
|
||||
str_ofs = 1;
|
||||
|
||||
for(i = 1; i < g_elfhead.iShnum; i++)
|
||||
{
|
||||
if(g_elfsections[i].blOutput)
|
||||
{
|
||||
SW(&shdr->sh_name, str_ofs);
|
||||
str_ofs += strlen(g_elfsections[i].szName) + 1;
|
||||
SW(&shdr->sh_flags, g_elfsections[i].iFlags);
|
||||
SW(&shdr->sh_addr, g_elfsections[i].iAddr);
|
||||
SW(&shdr->sh_size, g_elfsections[i].iSize);
|
||||
SW(&shdr->sh_link, 0);
|
||||
SW(&shdr->sh_addralign, g_elfsections[i].iAddralign);
|
||||
SW(&shdr->sh_entsize, g_elfsections[i].iEntsize);
|
||||
|
||||
if((g_elfsections[i].iType == SHT_REL) || (g_elfsections[i].iType == SHT_PRXRELOC))
|
||||
{
|
||||
SW(&shdr->sh_type, SHT_PRXRELOC);
|
||||
SW(&shdr->sh_info, g_elfsections[i].pRef->iIndex);
|
||||
SW(&shdr->sh_offset, reloc_ofs);
|
||||
reloc_ofs += g_elfsections[i].iSize;
|
||||
}
|
||||
else if(g_elfsections[i].iType == SHT_PROGBITS)
|
||||
{
|
||||
SW(&shdr->sh_type, g_elfsections[i].iType);
|
||||
SW(&shdr->sh_info, 0);
|
||||
SW(&shdr->sh_offset, g_allocbase + g_elfsections[i].iAddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
SW(&shdr->sh_type, g_elfsections[i].iType);
|
||||
SW(&shdr->sh_info, 0);
|
||||
/* Point it to the end of the allocated section */
|
||||
SW(&shdr->sh_offset, g_allocbase + g_alloc_size);
|
||||
}
|
||||
|
||||
shdr++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill in the shstrtab section */
|
||||
SW(&shdr->sh_name, str_ofs);
|
||||
SW(&shdr->sh_flags, 0);
|
||||
SW(&shdr->sh_addr, 0);
|
||||
SW(&shdr->sh_size, g_str_size);
|
||||
SW(&shdr->sh_link, 0);
|
||||
SW(&shdr->sh_addralign, 1);
|
||||
SW(&shdr->sh_entsize, 0);
|
||||
SW(&shdr->sh_type, SHT_STRTAB);
|
||||
SW(&shdr->sh_info, 0);
|
||||
SW(&shdr->sh_offset, g_shstrbase);
|
||||
}
|
||||
|
||||
/* Output relocations */
|
||||
void output_relocs(unsigned char *data)
|
||||
{
|
||||
int 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 the section header string table */
|
||||
void output_shstrtab(unsigned char *data)
|
||||
{
|
||||
int i;
|
||||
char *pData;
|
||||
|
||||
/* For the NULL section, memory should be zeroed anyway */
|
||||
memset(data, 0, g_str_size);
|
||||
pData = (char *) (data + 1);
|
||||
|
||||
for(i = 1; i < g_elfhead.iShnum; i++)
|
||||
{
|
||||
if(g_elfsections[i].blOutput)
|
||||
{
|
||||
if(g_verbose)
|
||||
{
|
||||
fprintf(stderr, "String %d: %s\n", i, g_elfsections[i].szName);
|
||||
}
|
||||
|
||||
strcpy(pData, g_elfsections[i].szName);
|
||||
pData += strlen(g_elfsections[i].szName) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(pData, ELF_SH_STRTAB);
|
||||
}
|
||||
|
||||
/* Output a stripped prx file */
|
||||
int output_prx(const char *prxfile)
|
||||
{
|
||||
int size;
|
||||
unsigned char *data;
|
||||
FILE *fp;
|
||||
|
||||
do
|
||||
{
|
||||
size = calculate_outsize();
|
||||
data = (unsigned char *) 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_sh(data + g_shbase);
|
||||
output_relocs(data + g_relocbase);
|
||||
output_shstrtab(data + g_shstrbase);
|
||||
|
||||
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;
|
||||
}
|
||||
282
tools/sha1.c
Normal file
282
tools/sha1.c
Normal file
@@ -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 <string.h> /* for memcpy() etc. */
|
||||
#include <stdlib.h> /* 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
|
||||
84
tools/sha1.h
Normal file
84
tools/sha1.h
Normal file
@@ -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 <limits.h>
|
||||
|
||||
#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
|
||||
162
tools/types.h
Normal file
162
tools/types.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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 <tyranid@gmail.com>
|
||||
*
|
||||
* $Id: types.h 2333 2007-10-31 19:37:40Z tyranid $
|
||||
*/
|
||||
|
||||
#ifndef __TYPES_H__
|
||||
#define __TYPES_H__
|
||||
|
||||
#include "config.h"
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#define uint8_t u_int8_t
|
||||
#define uint16_t u_int16_t
|
||||
#define uint32_t u_int32_t
|
||||
#define uint64_t u_int64_t
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
205
tools/unpack-pbp.c
Normal file
205
tools/unpack-pbp.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
# _____ ___ ____ ___ ____
|
||||
# ____| | ____| | | |____|
|
||||
# | ___| | ___| ____| | \ PSPDEV Open Source Project.
|
||||
#-----------------------------------------------------------------------
|
||||
# (c) 2005 Dan Peori <peori@oopo.net>
|
||||
# Licenced under Academic Free License version 2.0
|
||||
# Review pspsdk README & LICENSE files for further details.
|
||||
#
|
||||
# 2006-12-26 - Andrew Whatson <whatson@gmail.com>
|
||||
# - rewrote for easier reading
|
||||
# - gave "correct" names to UNKNOWN.* files
|
||||
# - improved memory efficiency with large PBPs
|
||||
# - no longer outputs empty files
|
||||
#
|
||||
# $Id: unpack-pbp.c 2379 2008-04-08 21:18:58Z jim $
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_MALLOC_H
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|
||||
// Swap the bytes of an int for big-endian machines
|
||||
static int swap_int(int n)
|
||||
{
|
||||
return ((n >> 24) & 0xff) | ((n >> 8) & 0xff00) | ((n << 8) & 0xff0000) | ((n << 24) & 0xff000000);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Struct to describe the header of a PBP file
|
||||
typedef struct {
|
||||
char signature[4];
|
||||
int version;
|
||||
int offset[8];
|
||||
} HEADER;
|
||||
|
||||
// Correct PBP signature
|
||||
char correct_sig[4] = {
|
||||
0x00,
|
||||
0x50, // P
|
||||
0x42, // B
|
||||
0x50 // P
|
||||
};
|
||||
|
||||
// Names of files included in a PBP
|
||||
char *filename[8] = {
|
||||
"PARAM.SFO",
|
||||
"ICON0.PNG",
|
||||
"ICON1.PMF",
|
||||
"PIC0.PNG",
|
||||
"PIC1.PNG",
|
||||
"SND0.AT3",
|
||||
"DATA.PSP",
|
||||
"DATA.PSAR"
|
||||
};
|
||||
|
||||
// Maximum size of read buffer
|
||||
int maxbuffer = 16 * 1024 * 1024;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
FILE *infile;
|
||||
FILE *outfile;
|
||||
HEADER header;
|
||||
int loop0;
|
||||
int total_size;
|
||||
|
||||
// Check for the correct number of arguments
|
||||
if (argc != 2) {
|
||||
printf("USAGE: %s <filename>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Open the specified PBP
|
||||
infile = fopen(argv[1], "rb");
|
||||
if (infile == NULL) {
|
||||
printf("ERROR: Could not open the input file. (%s)\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the size of the PBP
|
||||
fseek(infile, 0, SEEK_END);
|
||||
total_size = ftell(infile);
|
||||
fseek(infile, 0, SEEK_SET);
|
||||
if (total_size < 0) {
|
||||
printf("ERROR: Could not get the input file size.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read in the header
|
||||
if (fread(&header, sizeof(HEADER), 1, infile) < 0) {
|
||||
printf("ERROR: Could not read the input file header.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check the signature
|
||||
for (loop0 = 0; loop0 < sizeof(correct_sig); loop0++) {
|
||||
if (header.signature[loop0] != correct_sig[loop0]) {
|
||||
printf("ERROR: Input file is not a PBP file.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|
||||
// Swap the bytes of the offsets for big-endian machines
|
||||
for (loop0 = 0; loop0 < 8; loop0++) {
|
||||
header.offset[loop0] = swap_int(header.offset[loop0]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// For each file in the PBP
|
||||
for (loop0 = 0; loop0 < 8; loop0++) {
|
||||
void *buffer;
|
||||
int size;
|
||||
|
||||
// Get the size of this file
|
||||
if (loop0 == 7) {
|
||||
size = total_size - header.offset[loop0];
|
||||
} else {
|
||||
size = header.offset[loop0 + 1] - header.offset[loop0];
|
||||
}
|
||||
|
||||
// Print out the file details
|
||||
printf("[%d] %10d bytes | %s\n", loop0, size, filename[loop0]);
|
||||
|
||||
// Skip the file if empty
|
||||
if (!size) continue;
|
||||
|
||||
// Seek to the proper position in the file
|
||||
if (fseek(infile, header.offset[loop0], SEEK_SET) != 0) {
|
||||
printf("ERROR: Could not seek in the input file.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Open the output file
|
||||
outfile = fopen(filename[loop0], "wb");
|
||||
if (outfile == NULL) {
|
||||
printf("ERROR: Could not open the output file. (%s)\n", filename[loop0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
do {
|
||||
int readsize;
|
||||
|
||||
// Make sure we don't exceed the maximum buffer size
|
||||
if (size > maxbuffer) {
|
||||
readsize = maxbuffer;
|
||||
} else {
|
||||
readsize = size;
|
||||
}
|
||||
size -= readsize;
|
||||
|
||||
// Create the read buffer
|
||||
buffer = malloc(readsize);
|
||||
if (buffer == NULL) {
|
||||
printf("ERROR: Could not allocate the section data buffer. (%d)\n", readsize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read in the data from the PBP
|
||||
if (fread(buffer, readsize, 1, infile) < 0) {
|
||||
printf("ERROR: Could not read in the section data.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Write the contents of the buffer to the output file
|
||||
if (fwrite(buffer, readsize, 1, outfile) < 0) {
|
||||
printf("ERROR: Could not write out the section data.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Clean up the buffer
|
||||
free(buffer);
|
||||
|
||||
// Repeat if we haven't finished writing the file
|
||||
} while (size);
|
||||
|
||||
// Close the output file
|
||||
if (fclose(outfile) < 0) {
|
||||
printf("ERROR: Could not close the output file.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Close the PBP
|
||||
if (fclose(infile) < 0) {
|
||||
printf("ERROR: Could not close the input file.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Exit successful
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user