Skip to content

Instantly share code, notes, and snippets.

@murachue
Created December 3, 2016 15:37
Show Gist options
  • Save murachue/396283e7bb921c6e753f2f23fde6a49b to your computer and use it in GitHub Desktop.
Save murachue/396283e7bb921c6e753f2f23fde6a49b to your computer and use it in GitHub Desktop.
Binary to PlayStation1 executable converter.
// mkpsxexe.c
// Copyright 2016 Murachue
// License: CC-BY
#include <stdio.h>
#include <unistd.h>
#include <inttypes.h>
#include <stdlib.h>
size_t fwriteu32(uint32_t val, FILE *fp) {
char buf[4];
// little endian
buf[0] = (val >> 0) & 0xFF;
buf[1] = (val >> 8) & 0xFF;
buf[2] = (val >> 16) & 0xFF;
buf[3] = (val >> 24) & 0xFF;
return fwrite(buf, 4, 1, fp);
}
int main(int argc, char **argv) {
uint32_t load_addr = 0, entry_addr = 0, initial_sp = 0;
const char *outfile = NULL, *infile;
int opt;
while((opt = getopt(argc, argv, "l:e:s:o:")) != -1) {
switch(opt) {
case 'l': // load
load_addr = strtoul(optarg, NULL, 16);
break;
case 'e': // entry
entry_addr = strtoul(optarg, NULL, 16);
break;
case 's': // sp
initial_sp = strtoul(optarg, NULL, 16);
break;
case 'o': // output-file
outfile = optarg; // ah... is this ok?
break;
default:
fprintf(stderr, "Unknown option %c\n", opt);
return 1;
}
}
argc -= optind;
argv += optind;
infile = argv[0];
if(load_addr == 0) { fprintf(stderr, "Load address (-l) not specified.\n"); return 1; }
if(entry_addr == 0) { fprintf(stderr, "Entry address (-e) not specified.\n"); return 1; }
if(initial_sp == 0) { fprintf(stderr, "Initial stack pointer (-s) not specified.\n"); return 1; }
if(outfile == NULL) { fprintf(stderr, "Output file (-o) not specified.\n"); return 1; }
if(infile == NULL) { fprintf(stderr, "Input file not specified.\n"); return 1; }
if(1 < argc) { fprintf(stderr, "Extra arguments.\n"); return 1; }
{
FILE *wp, *fp;
uint32_t datasize, aligneddatasize;
if((wp = fopen(outfile, "wb")) == NULL) {
perror("Could not open the output file");
return 1;
}
if((fp = fopen(infile, "rb")) == NULL) {
perror("Could not open the input file");
return 1;
}
if(fseek(fp, 0, SEEK_END) != 0) {
perror("Could not seek to the end of the input file");
return 1;
}
datasize = ftell(fp); // must be <4GB
aligneddatasize = (datasize + (0x800 - 1)) & ~0x7FF; // round up to 0x800
if(fseek(fp, 0, SEEK_SET) != 0) {
perror("Could not seek to the begin of the input file");
return 1;
}
if(fwrite("PS-X EXE", 8, 1, wp) < 1) {
perror("Could not write magic");
return 1;
}
if(fwriteu32(0, wp) < 1) {
perror("Could not write zero8");
return 1;
}
if(fwriteu32(0, wp) < 1) {
perror("Could not write zeroC");
return 1;
}
if(fwriteu32(entry_addr, wp) < 1) {
perror("Could not write entry point");
return 1;
}
if(fwriteu32(0, wp) < 1) {
perror("Could not write initial gp = 0");
return 1;
}
if(fwriteu32(load_addr, wp) < 1) {
perror("Could not write load address");
return 1;
}
if(fwriteu32(aligneddatasize, wp) < 1) {
perror("Could not write size");
return 1;
}
if(fwriteu32(0, wp) < 1) {
perror("Could not write zero20");
return 1;
}
if(fwriteu32(0, wp) < 1) {
perror("Could not write zero24");
return 1;
}
if(fwriteu32(0, wp) < 1) {
perror("Could not write zero28");
return 1;
}
if(fwriteu32(0, wp) < 1) {
perror("Could not write zero2C");
return 1;
}
if(fwriteu32(initial_sp, wp) < 1) {
perror("Could not write initial sp");
return 1;
}
// should write the "SCEI. for * area" to 0x4C~?
{
int i;
for(i = 0x34; i < 0x4C; i += 4) {
if(fwriteu32(0, wp) < 1) {
perror("Could not write header padding before licensing");
return 1;
}
}
}
{
const char licensing[] = "Sony Computer Entertainment Inc. for Japan area";
const char nul[1] = {0};
int i;
if(fwrite(licensing, sizeof(licensing), 1, wp) < 1) {
perror("Could not write licensing");
return 1;
}
for(i = 0x4C + sizeof(licensing); i < 0x800; i++) {
if(fwrite(nul, 1, 1, wp) < 1) {
perror("Could not write header last padding");
return 1;
}
}
}
// copy the binary
{
char buf[2048];
uint32_t copied = 0;
while(copied < datasize) {
size_t shouldread, r;
shouldread = ((datasize - copied) < 2048) ? (datasize - copied) : 2048;
if(fread(buf, shouldread, 1, fp) < 1) {
perror("Could not read from the input file");
return 1;
}
if(fwrite(buf, shouldread, 1, wp) < 1) {
perror("Could not write to the output file");
return 1;
}
copied += shouldread;
}
}
if(fclose(fp) != 0) {
perror("Could not close the input file (ignored)");
}
// padding required?
if(datasize < aligneddatasize)
{
char buf[2048] = {0};
if(fwrite(buf, aligneddatasize - datasize, 1, wp) < 1) {
perror("Could not write the padding to the output file");
return 1;
}
}
if(fclose(wp) != 0) {
perror("Could not close the output file (ignored)");
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment