mirror of
				https://github.com/coop-deluxe/sm64coopdx.git
				synced 2025-10-30 08:01:01 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			126 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			126 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdint.h>
 | 
						|
 | 
						|
/* from elf.h */
 | 
						|
 | 
						|
/* Type for a 16-bit quantity.  */
 | 
						|
typedef uint16_t Elf32_Half;
 | 
						|
 | 
						|
/* Types for signed and unsigned 32-bit quantities.  */
 | 
						|
typedef uint32_t Elf32_Word;
 | 
						|
 | 
						|
/* Type of addresses.  */
 | 
						|
typedef uint32_t Elf32_Addr;
 | 
						|
 | 
						|
/* Type of file offsets.  */
 | 
						|
typedef uint32_t Elf32_Off;
 | 
						|
 | 
						|
/* The ELF file header.  This appears at the start of every ELF file.  */
 | 
						|
 | 
						|
#define EI_NIDENT (16)
 | 
						|
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
 | 
						|
  Elf32_Half	e_type;			/* Object file type */
 | 
						|
  Elf32_Half	e_machine;		/* Architecture */
 | 
						|
  Elf32_Word	e_version;		/* Object file version */
 | 
						|
  Elf32_Addr	e_entry;		/* Entry point virtual address */
 | 
						|
  Elf32_Off	e_phoff;		/* Program header table file offset */
 | 
						|
  Elf32_Off	e_shoff;		/* Section header table file offset */
 | 
						|
  Elf32_Word	e_flags;		/* Processor-specific flags */
 | 
						|
  Elf32_Half	e_ehsize;		/* ELF header size in bytes */
 | 
						|
  Elf32_Half	e_phentsize;		/* Program header table entry size */
 | 
						|
  Elf32_Half	e_phnum;		/* Program header table entry count */
 | 
						|
  Elf32_Half	e_shentsize;		/* Section header table entry size */
 | 
						|
  Elf32_Half	e_shnum;		/* Section header table entry count */
 | 
						|
  Elf32_Half	e_shstrndx;		/* Section header string table index */
 | 
						|
} Elf32_Ehdr;
 | 
						|
 | 
						|
/* Conglomeration of the identification bytes, for easy testing as a word.  */
 | 
						|
#define	ELFMAG		"\177ELF"
 | 
						|
#define	SELFMAG		4
 | 
						|
 | 
						|
#define EI_CLASS	4		/* File class byte index */
 | 
						|
#define ELFCLASS32	1		/* 32-bit objects */
 | 
						|
 | 
						|
#define EI_DATA		5		/* Data encoding byte index */
 | 
						|
#define ELFDATA2MSB	2		/* 2's complement, big endian */
 | 
						|
 | 
						|
/* end from elf.h */
 | 
						|
 | 
						|
// This file will find all mips3 object files in an ar archive and set the ABI flags to O32
 | 
						|
// this allows gcc to link them with the mips2 object files.
 | 
						|
// Irix CC doesn't set the elf e_flags properly.
 | 
						|
 | 
						|
// the AR file is structured as followed
 | 
						|
//"!<arch>" followed by 0x0A (linefeed) 8 characters
 | 
						|
// then a file header that follows the following structure
 | 
						|
// everything is represented using space padded characters
 | 
						|
// the last two characters are alwos 0x60 0x0A
 | 
						|
// then come the file contents
 | 
						|
// you can find the location of the next header by adding file_size_in_bytes (after parsing)
 | 
						|
// all file headers start at an even offset so if the file size in bytes is odd you have to add 1
 | 
						|
// the first two "files" are special.  One is a symbol table with a pointer to the header of the file
 | 
						|
// contaning the symbol the other is an extended list of filenames
 | 
						|
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];
 | 
						|
};
 | 
						|
 | 
						|
//These constants found by inspecting output of objdump
 | 
						|
#define FLAGS_MIPS3 0x20
 | 
						|
#define FLAGS_O32ABI 0x100000 
 | 
						|
int main(int argc, char **argv) {
 | 
						|
    FILE *f = fopen(argv[1], "r+");
 | 
						|
 | 
						|
    if (f == NULL) {
 | 
						|
        printf("Failed to open file! %s\n", argv[1]);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    struct ar_header current_header;
 | 
						|
    fseek(f, 0x8, SEEK_SET); // skip header, this is safe enough given that we check to make sure the
 | 
						|
                             // file header is valid
 | 
						|
 | 
						|
    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);
 | 
						|
        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) {
 | 
						|
            // found an ELF file.
 | 
						|
            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, -sizeof(hdr), SEEK_CUR);
 | 
						|
                if (1 != fwrite(&hdr, sizeof(hdr), 1, f)) {
 | 
						|
                    printf("Failed to write back ELF header after patching.\n");
 | 
						|
                    return -1;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (filesize % 2 == 1)
 | 
						|
            filesize++;
 | 
						|
        fseek(f, filesize - sizeof(hdr), SEEK_CUR);
 | 
						|
    }
 | 
						|
    fclose(f);
 | 
						|
    return 0;
 | 
						|
}
 |