Files
pspsdk/tools/bin2o.c
2023-01-20 13:46:17 +08:00

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(&section, 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(&section, 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(&section, 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(&section, 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(&section, 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;
}