#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define ARMAG "!<arch>\n"
#define SARMAG 8
typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Word;
typedef uint32_t Elf32_Addr;
typedef uint32_t Elf32_Off;
#define EI_NIDENT (16)
typedef struct
{
unsigned char e_ident[EI_NIDENT];
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;
} Elf32_Ehdr;
#define ELFMAG "\177ELF"
#define SELFMAG 4
#define EI_CLASS 4
#define ELFCLASS32 1
#define EI_DATA 5
#define ELFDATA2MSB 2
struct ar_header {
char identifier[16];
char file_modification_timestamp[12];
char owner_id[6];
char group_id[6];
char file_mode[8];
char file_size_in_bytes[10];
char ending[2];
};
#define FLAGS_MIPS3 0x20
#define FLAGS_O32ABI 0x100000
int fix_mips_elf(FILE *f, size_t filesize)
{
Elf32_Ehdr hdr;
if (filesize < sizeof(hdr) || (1 != fread(&hdr, sizeof(hdr), 1, f))) {
printf("Failed to read ELF header\n");
return -1;
}
if (strncmp((const char *) hdr.e_ident, ELFMAG, SELFMAG) == 0) {
if (hdr.e_ident[EI_CLASS] != ELFCLASS32 || hdr.e_ident[EI_DATA] != ELFDATA2MSB) {
printf("Expected 32bit big endian object files\n");
return -1;
}
if ((hdr.e_flags & 0xFF) == FLAGS_MIPS3 && (hdr.e_flags & FLAGS_O32ABI) == 0) {
hdr.e_flags |= FLAGS_O32ABI;
fseek(f, -(long)sizeof(hdr), SEEK_CUR);
if (1 != fwrite(&hdr, sizeof(hdr), 1, f)) {
printf("Failed to write back ELF header after patching.\n");
return -1;
}
}
}
return 0;
}
int fix_mips_ar(FILE *f)
{
struct ar_header current_header;
fseek(f, 0x8, SEEK_SET);
while (1 == fread(¤t_header, sizeof(current_header), 1, f)) {
if (current_header.ending[0] != 0x60 && current_header.ending[1] != 0x0A) {
printf("Expected file header\n");
return -1;
}
size_t filesize = atoi(current_header.file_size_in_bytes);
if (fix_mips_elf(f, filesize)) {
return -1;
}
if (filesize % 2 == 1)
filesize++;
fseek(f, filesize - sizeof(Elf32_Ehdr), SEEK_CUR);
}
return 0;
}
int main(int argc, char **argv) {
FILE *f = fopen(argv[1], "r+b");
uint8_t magic[8];
int status = 0;
if (f == NULL) {
printf("Failed to open file! %s\n", argv[1]);
return -1;
}
if (1 != fread(&magic, sizeof(magic), 1, f)) {
printf("Failed to read file magic\n");
return -1;
}
rewind(f);
if (!memcmp(ARMAG, magic, SARMAG)) {
status = fix_mips_ar(f);
} else if (!memcmp(ELFMAG, magic, SELFMAG)) {
fseek(f, 0, SEEK_END);
size_t filesize = ftell(f);
rewind(f);
status = fix_mips_elf(f, filesize);
} else {
printf("Unknown file magic: %02x%02x%02X%02X\n", magic[0], magic[1], magic[2], magic[3]);
status = -1;
}
fclose(f);
return status;
}