mirror of
https://github.com/pspdev/pspsdk.git
synced 2025-10-03 16:51:27 +00:00
391 lines
9.8 KiB
C
391 lines
9.8 KiB
C
/*
|
|
# _____ ___ ____ ___ ____
|
|
# ____| | ____| | | |____| https://github.com/pspdev
|
|
# | ___| | ___| ____| | \ PSPDEV Open Source Project.
|
|
#-----------------------------------------------------------------------
|
|
# Review pspsdk README & LICENSE files for further details.
|
|
#
|
|
# Converts 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 = NULL, * dest = NULL;
|
|
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");
|
|
fclose(source);
|
|
free(buffer);
|
|
return 1;
|
|
}
|
|
|
|
if (fread(buffer, 1, size, source) != size) {
|
|
printf("Failed to read file.\n");
|
|
fclose(source);
|
|
free(buffer);
|
|
return 1;
|
|
}
|
|
fclose(source);
|
|
|
|
if (!(dest = fopen(f_dest, "wb+"))) {
|
|
printf("Failed to open/create %s.\n", f_dest);
|
|
fclose(dest);
|
|
return 1;
|
|
}
|
|
|
|
create_elf(dest, buffer, size, f_label);
|
|
|
|
fclose(dest);
|
|
free(buffer);
|
|
|
|
return 0;
|
|
}
|