Update README.md
[sm64pc.git] / tools / patch_libultra_math.c
blobe6bdcc0cfd2373c725e4a96524fe0c52f43a0143
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdint.h>
6 /* from elf.h */
8 /* Type for a 16-bit quantity. */
9 typedef uint16_t Elf32_Half;
11 /* Types for signed and unsigned 32-bit quantities. */
12 typedef uint32_t Elf32_Word;
14 /* Type of addresses. */
15 typedef uint32_t Elf32_Addr;
17 /* Type of file offsets. */
18 typedef uint32_t Elf32_Off;
20 /* The ELF file header. This appears at the start of every ELF file. */
22 #define EI_NIDENT (16)
24 typedef struct
26 unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
27 Elf32_Half e_type; /* Object file type */
28 Elf32_Half e_machine; /* Architecture */
29 Elf32_Word e_version; /* Object file version */
30 Elf32_Addr e_entry; /* Entry point virtual address */
31 Elf32_Off e_phoff; /* Program header table file offset */
32 Elf32_Off e_shoff; /* Section header table file offset */
33 Elf32_Word e_flags; /* Processor-specific flags */
34 Elf32_Half e_ehsize; /* ELF header size in bytes */
35 Elf32_Half e_phentsize; /* Program header table entry size */
36 Elf32_Half e_phnum; /* Program header table entry count */
37 Elf32_Half e_shentsize; /* Section header table entry size */
38 Elf32_Half e_shnum; /* Section header table entry count */
39 Elf32_Half e_shstrndx; /* Section header string table index */
40 } Elf32_Ehdr;
42 /* Conglomeration of the identification bytes, for easy testing as a word. */
43 #define ELFMAG "\177ELF"
44 #define SELFMAG 4
46 #define EI_CLASS 4 /* File class byte index */
47 #define ELFCLASS32 1 /* 32-bit objects */
49 #define EI_DATA 5 /* Data encoding byte index */
50 #define ELFDATA2MSB 2 /* 2's complement, big endian */
52 /* end from elf.h */
54 // This file will find all mips3 object files in an ar archive and set the ABI flags to O32
55 // this allows gcc to link them with the mips2 object files.
56 // Irix CC doesn't set the elf e_flags properly.
58 // the AR file is structured as followed
59 //"!<arch>" followed by 0x0A (linefeed) 8 characters
60 // then a file header that follows the following structure
61 // everything is represented using space padded characters
62 // the last two characters are alwos 0x60 0x0A
63 // then come the file contents
64 // you can find the location of the next header by adding file_size_in_bytes (after parsing)
65 // all file headers start at an even offset so if the file size in bytes is odd you have to add 1
66 // the first two "files" are special. One is a symbol table with a pointer to the header of the file
67 // contaning the symbol the other is an extended list of filenames
68 struct ar_header {
69 char identifier[16];
70 char file_modification_timestamp[12];
71 char owner_id[6];
72 char group_id[6];
73 char file_mode[8];
74 char file_size_in_bytes[10];
75 char ending[2];
78 //These constants found by inspecting output of objdump
79 #define FLAGS_MIPS3 0x20
80 #define FLAGS_O32ABI 0x100000
81 int main(int argc, char **argv) {
82 FILE *f = fopen(argv[1], "r+");
84 if (f == NULL) {
85 printf("Failed to open file! %s\n", argv[1]);
86 return -1;
88 struct ar_header current_header;
89 fseek(f, 0x8, SEEK_SET); // skip header, this is safe enough given that we check to make sure the
90 // file header is valid
92 while (1 == fread(&current_header, sizeof(current_header), 1, f)) {
93 if (current_header.ending[0] != 0x60 && current_header.ending[1] != 0x0A) {
94 printf("Expected file header\n");
95 return -1;
97 size_t filesize = atoi(current_header.file_size_in_bytes);
98 Elf32_Ehdr hdr;
99 if (filesize < sizeof(hdr) || (1 != fread(&hdr, sizeof(hdr), 1, f))) {
100 printf("Failed to read ELF header\n");
101 return -1;
104 if (strncmp((const char *) hdr.e_ident, ELFMAG, SELFMAG) == 0) {
105 // found an ELF file.
106 if (hdr.e_ident[EI_CLASS] != ELFCLASS32 || hdr.e_ident[EI_DATA] != ELFDATA2MSB) {
107 printf("Expected 32bit big endian object files\n");
108 return -1;
111 if ((hdr.e_flags & 0xFF) == FLAGS_MIPS3 && (hdr.e_flags & FLAGS_O32ABI) == 0) {
112 hdr.e_flags |= FLAGS_O32ABI;
113 fseek(f, -sizeof(hdr), SEEK_CUR);
114 if (1 != fwrite(&hdr, sizeof(hdr), 1, f)) {
115 printf("Failed to write back ELF header after patching.\n");
116 return -1;
120 if (filesize % 2 == 1)
121 filesize++;
122 fseek(f, filesize - sizeof(hdr), SEEK_CUR);
124 fclose(f);
125 return 0;