patch_elf_32bit.c (5282B)
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(¤t_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 }