Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/tools/patch_elf_32bit.c
7854 views
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
#include <stdint.h>
5
6
#define ARMAG "!<arch>\n"
7
#define SARMAG 8
8
9
/* from elf.h */
10
11
/* Type for a 16-bit quantity. */
12
typedef uint16_t Elf32_Half;
13
14
/* Types for signed and unsigned 32-bit quantities. */
15
typedef uint32_t Elf32_Word;
16
17
/* Type of addresses. */
18
typedef uint32_t Elf32_Addr;
19
20
/* Type of file offsets. */
21
typedef uint32_t Elf32_Off;
22
23
/* The ELF file header. This appears at the start of every ELF file. */
24
25
#define EI_NIDENT (16)
26
27
typedef struct
28
{
29
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
30
Elf32_Half e_type; /* Object file type */
31
Elf32_Half e_machine; /* Architecture */
32
Elf32_Word e_version; /* Object file version */
33
Elf32_Addr e_entry; /* Entry point virtual address */
34
Elf32_Off e_phoff; /* Program header table file offset */
35
Elf32_Off e_shoff; /* Section header table file offset */
36
Elf32_Word e_flags; /* Processor-specific flags */
37
Elf32_Half e_ehsize; /* ELF header size in bytes */
38
Elf32_Half e_phentsize; /* Program header table entry size */
39
Elf32_Half e_phnum; /* Program header table entry count */
40
Elf32_Half e_shentsize; /* Section header table entry size */
41
Elf32_Half e_shnum; /* Section header table entry count */
42
Elf32_Half e_shstrndx; /* Section header string table index */
43
} Elf32_Ehdr;
44
45
/* Conglomeration of the identification bytes, for easy testing as a word. */
46
#define ELFMAG "\177ELF"
47
#define SELFMAG 4
48
49
#define EI_CLASS 4 /* File class byte index */
50
#define ELFCLASS32 1 /* 32-bit objects */
51
52
#define EI_DATA 5 /* Data encoding byte index */
53
#define ELFDATA2MSB 2 /* 2's complement, big endian */
54
55
/* end from elf.h */
56
57
// This file will find all mips3 object files in an ar archive and set the ABI flags to O32
58
// this allows gcc to link them with the mips2 object files.
59
// Irix CC doesn't set the elf e_flags properly.
60
61
// the AR file is structured as followed
62
//"!<arch>" followed by 0x0A (linefeed) 8 characters
63
// then a file header that follows the following structure
64
// everything is represented using space padded characters
65
// the last two characters are alwos 0x60 0x0A
66
// then come the file contents
67
// you can find the location of the next header by adding file_size_in_bytes (after parsing)
68
// all file headers start at an even offset so if the file size in bytes is odd you have to add 1
69
// the first two "files" are special. One is a symbol table with a pointer to the header of the file
70
// contaning the symbol the other is an extended list of filenames
71
struct ar_header {
72
char identifier[16];
73
char file_modification_timestamp[12];
74
char owner_id[6];
75
char group_id[6];
76
char file_mode[8];
77
char file_size_in_bytes[10];
78
char ending[2];
79
};
80
81
//These constants found by inspecting output of objdump
82
#define FLAGS_MIPS3 0x20
83
#define FLAGS_O32ABI 0x100000
84
85
int fix_mips_elf(FILE *f, size_t filesize)
86
{
87
Elf32_Ehdr hdr;
88
if (filesize < sizeof(hdr) || (1 != fread(&hdr, sizeof(hdr), 1, f))) {
89
printf("Failed to read ELF header\n");
90
return -1;
91
}
92
93
if (strncmp((const char *) hdr.e_ident, ELFMAG, SELFMAG) == 0) {
94
// found an ELF file.
95
if (hdr.e_ident[EI_CLASS] != ELFCLASS32 || hdr.e_ident[EI_DATA] != ELFDATA2MSB) {
96
printf("Expected 32bit big endian object files\n");
97
return -1;
98
}
99
100
if ((hdr.e_flags & 0xFF) == FLAGS_MIPS3 && (hdr.e_flags & FLAGS_O32ABI) == 0) {
101
hdr.e_flags |= FLAGS_O32ABI;
102
fseek(f, -(long)sizeof(hdr), SEEK_CUR);
103
if (1 != fwrite(&hdr, sizeof(hdr), 1, f)) {
104
printf("Failed to write back ELF header after patching.\n");
105
return -1;
106
}
107
}
108
}
109
return 0;
110
}
111
112
int fix_mips_ar(FILE *f)
113
{
114
struct ar_header current_header;
115
fseek(f, 0x8, SEEK_SET); // skip header, this is safe enough given that we check to make sure the
116
// file header is valid
117
118
while (1 == fread(&current_header, sizeof(current_header), 1, f)) {
119
if (current_header.ending[0] != 0x60 && current_header.ending[1] != 0x0A) {
120
printf("Expected file header\n");
121
return -1;
122
}
123
size_t filesize = atoi(current_header.file_size_in_bytes);
124
if (fix_mips_elf(f, filesize)) {
125
return -1;
126
}
127
if (filesize % 2 == 1)
128
filesize++;
129
fseek(f, filesize - sizeof(Elf32_Ehdr), SEEK_CUR);
130
}
131
return 0;
132
}
133
134
int main(int argc, char **argv) {
135
FILE *f = fopen(argv[1], "r+b");
136
uint8_t magic[8];
137
int status = 0;
138
139
if (f == NULL) {
140
printf("Failed to open file! %s\n", argv[1]);
141
return -1;
142
}
143
if (1 != fread(&magic, sizeof(magic), 1, f)) {
144
printf("Failed to read file magic\n");
145
return -1;
146
}
147
rewind(f);
148
if (!memcmp(ARMAG, magic, SARMAG)) {
149
status = fix_mips_ar(f);
150
} else if (!memcmp(ELFMAG, magic, SELFMAG)) {
151
fseek(f, 0, SEEK_END);
152
size_t filesize = ftell(f);
153
rewind(f);
154
status = fix_mips_elf(f, filesize);
155
} else {
156
printf("Unknown file magic: %02x%02x%02X%02X\n", magic[0], magic[1], magic[2], magic[3]);
157
status = -1;
158
}
159
fclose(f);
160
return status;
161
}
162
163