You've already forked ultrasm64-2
mirror of
https://github.com/HackerN64/ultrasm64-2.git
synced 2026-01-21 10:38:08 -08:00
Very close to GCC building
This commit is contained in:
4
Makefile
4
Makefile
@@ -23,7 +23,7 @@ TARGET_N64 ?= 1
|
||||
# ido - uses the SGI IRIS Development Option compiler, which is used to build
|
||||
# an original matching N64 ROM
|
||||
# gcc - uses the GNU C Compiler
|
||||
COMPILER ?= ido
|
||||
COMPILER ?= gcc
|
||||
$(eval $(call validate-option,COMPILER,ido gcc))
|
||||
|
||||
|
||||
@@ -327,7 +327,7 @@ else
|
||||
endif
|
||||
endif
|
||||
ifeq ($(COMPILER),gcc)
|
||||
LD := $(CROSS)ld
|
||||
LD := LD_LIBRARY_PATH=$(LD_PATH) $(LD_PATH)/mips64-elf-ld
|
||||
else
|
||||
LD := LD_LIBRARY_PATH=$(LD_PATH) $(LD_PATH)/mips64-elf-ld
|
||||
endif
|
||||
|
||||
@@ -31,21 +31,4 @@ ABS(__osBbPakBindings, 0x80000394)
|
||||
ABS(__osBbStateName, 0x800003a4)
|
||||
ABS(__osBbStateDirty, 0x800003b4)
|
||||
ABS(__osBbAuxDataLimit, 0x800003b8)
|
||||
|
||||
/* padding */
|
||||
.fill 0x64
|
||||
#else
|
||||
/* padding */
|
||||
/* JP is the only version without padding even though 2.0D has it (US) */
|
||||
#if (LIBULTRA_VERSION > OS_VER_D) || (LIBULTRA_VERSION == OS_VER_D && LIBULTRA_REVISION >= 1)
|
||||
.repeat 0x34
|
||||
.byte 0
|
||||
.endr
|
||||
#endif
|
||||
#if LIBULTRA_VERSION >= OS_VER_H
|
||||
.repeat 0x20
|
||||
.byte 0
|
||||
.endr
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -49,7 +49,7 @@ endif
|
||||
# LIBGULTRA - whenever to compile libultra using IDO or GNU
|
||||
# 1 - uses egcs to match iQue (uses gcc if COMPILER is gcc)
|
||||
# 0 - uses ido, used to match JP, US, EU and Shindou
|
||||
LIBGULTRA ?= 0
|
||||
LIBGULTRA ?= 1
|
||||
$(eval $(call validate-option,LIBGULTRA,0 1))
|
||||
|
||||
ULTRA_C_FILES := $(foreach dir,$(ULTRA_SRC_DIRS),$(wildcard $(dir)/*.c))
|
||||
@@ -83,7 +83,7 @@ ULTRA_CFLAGS = -non_shared -Wab,-r4300_mul -Xcpluscomm -Xfullwarn -G 0 -signed
|
||||
ULTRA_ASFLAGS = -non_shared -Wab,-r4300_mul -Xcpluscomm -Xfullwarn -G 0 -nostdinc -o32 -c
|
||||
|
||||
GULTRA_CC := COMPILER_PATH=$(EGCS_PATH) $(EGCS_PATH)/gcc
|
||||
GULTRA_CFLAGS = -mcpu=r4300 -fno-pic -Wa,--strip-local-absolute -G 0
|
||||
GULTRA_CFLAGS = -mcpu=r4300 -fno-pic -Wa,--strip-local-absolute -G 0 -fno-common
|
||||
GULTRA_ASFLAGS = -mcpu=r4300 -fno-pic -x assembler-with-cpp -c -DEGCS_GCC
|
||||
|
||||
ifeq ($(LIBGULTRA),1)
|
||||
|
||||
4
sm64.ld
4
sm64.ld
@@ -230,7 +230,7 @@ SECTIONS
|
||||
#undef JP_PADDING_TEXT
|
||||
#endif
|
||||
|
||||
#ifdef VERSION_CN
|
||||
#ifndef __sgi
|
||||
BUILD_DIR/libgcc.a:_divdi3.o(.text);
|
||||
BUILD_DIR/libgcc.a:_moddi3.o(.text);
|
||||
BUILD_DIR/libgcc.a:_udivdi3.o(.text);
|
||||
@@ -390,7 +390,7 @@ SECTIONS
|
||||
#include "lib/ultra/ld.inc"
|
||||
#undef SECTION
|
||||
|
||||
#ifdef VERSION_CN
|
||||
#ifndef __sgi
|
||||
BUILD_DIR/libgcc.a:_divdi3.o(.rodata*);
|
||||
BUILD_DIR/libgcc.a:_moddi3.o(.rodata*);
|
||||
BUILD_DIR/libgcc.a:_udivdi3.o(.rodata*);
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
// 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.
|
||||
//
|
||||
// In addition, it sorts symbol tables to put local symbols before global ones,
|
||||
// which is required by modern ld.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -13,6 +20,7 @@ typedef uint16_t Elf32_Half;
|
||||
|
||||
/* Types for signed and unsigned 32-bit quantities. */
|
||||
typedef uint32_t Elf32_Word;
|
||||
typedef int32_t Elf32_Sword;
|
||||
|
||||
/* Type of addresses. */
|
||||
typedef uint32_t Elf32_Addr;
|
||||
@@ -26,37 +34,82 @@ typedef uint32_t Elf32_Off;
|
||||
|
||||
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 */
|
||||
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;
|
||||
|
||||
typedef struct {
|
||||
Elf32_Word sh_name;
|
||||
Elf32_Word sh_type;
|
||||
Elf32_Word sh_flags;
|
||||
Elf32_Addr sh_addr;
|
||||
Elf32_Off sh_offset;
|
||||
Elf32_Word sh_size;
|
||||
Elf32_Word sh_link;
|
||||
Elf32_Word sh_info;
|
||||
Elf32_Word sh_addralign;
|
||||
Elf32_Word sh_entsize;
|
||||
} Elf32_Shdr;
|
||||
|
||||
typedef struct {
|
||||
Elf32_Word st_name;
|
||||
Elf32_Addr st_value;
|
||||
Elf32_Word st_size;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
Elf32_Half st_shndx;
|
||||
} Elf32_Sym;
|
||||
|
||||
typedef struct {
|
||||
Elf32_Addr r_offset;
|
||||
Elf32_Word r_info;
|
||||
} Elf32_Rel;
|
||||
|
||||
typedef struct {
|
||||
Elf32_Addr r_offset;
|
||||
Elf32_Word r_info;
|
||||
Elf32_Sword r_addend;
|
||||
} Elf32_Rela;
|
||||
|
||||
|
||||
/* Conglomeration of the identification bytes, for easy testing as a word. */
|
||||
#define ELFMAG "\177ELF"
|
||||
#define SELFMAG 4
|
||||
#define ELFMAG "\177ELF"
|
||||
#define SELFMAG 4
|
||||
|
||||
#define EI_CLASS 4 /* File class byte index */
|
||||
#define ELFCLASS32 1 /* 32-bit objects */
|
||||
#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 */
|
||||
#define EI_DATA 5 /* Data encoding byte index */
|
||||
#define ELFDATA2MSB 2 /* 2's complement, big endian */
|
||||
|
||||
#define ELF32_ST_BIND(i) ((i)>>4)
|
||||
#define ELF32_R_SYM(i) ((i)>>8)
|
||||
#define ELF32_R_TYPE(i) ((unsigned char)(i))
|
||||
#define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t))
|
||||
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_RELA 4
|
||||
#define SHT_NOBITS 8
|
||||
#define SHT_REL 9
|
||||
|
||||
#define STB_LOCAL 0
|
||||
|
||||
/* 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.
|
||||
#define BSWAP16(x) ((uint16_t)(((x) & 0xff00) >> 8) | (uint16_t)(((x) & 0x00ff) << 8))
|
||||
#define BSWAP32(x) (uint32_t)(BSWAP16((x) >> 16) | (uint32_t)(BSWAP16(x) << 16))
|
||||
|
||||
// the AR file is structured as followed
|
||||
//"!<arch>" followed by 0x0A (linefeed) 8 characters
|
||||
@@ -67,7 +120,7 @@ typedef struct
|
||||
// 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
|
||||
// containing the symbol the other is an extended list of filenames
|
||||
struct ar_header {
|
||||
char identifier[16];
|
||||
char file_modification_timestamp[12];
|
||||
@@ -78,34 +131,180 @@ struct ar_header {
|
||||
char ending[2];
|
||||
};
|
||||
|
||||
//These constants found by inspecting output of objdump
|
||||
// These constants found by inspecting output of objdump
|
||||
#define FLAGS_MIPS3 0x20
|
||||
#define FLAGS_O32ABI 0x100000
|
||||
|
||||
void *malloc_checked(size_t size)
|
||||
{
|
||||
void *ret = calloc(size, 1);
|
||||
if (!ret) {
|
||||
printf("Failed to allocate memory\n");
|
||||
exit(-1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Elf32_Sym *syms;
|
||||
|
||||
int cmpsym(const void *lhs, const void *rhs)
|
||||
{
|
||||
size_t ind1 = *(size_t *)lhs;
|
||||
size_t ind2 = *(size_t *)rhs;
|
||||
int local1 = ELF32_ST_BIND(syms[ind1].st_info) == STB_LOCAL;
|
||||
int local2 = ELF32_ST_BIND(syms[ind2].st_info) == STB_LOCAL;
|
||||
if (local1 != local2) {
|
||||
return local1 ? -1 : 1;
|
||||
}
|
||||
if (ind1 != ind2) {
|
||||
return ind1 < ind2 ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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");
|
||||
int changed = 0;
|
||||
uint8_t *buf = malloc_checked(filesize);
|
||||
if (1 != fread(buf, filesize, 1, f)) {
|
||||
printf("Failed to read ELF\n");
|
||||
return -1;
|
||||
}
|
||||
fseek(f, -(long)filesize, SEEK_CUR);
|
||||
|
||||
if (filesize < sizeof(Elf32_Ehdr)) {
|
||||
printf("truncated 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");
|
||||
Elf32_Ehdr *hdr = (Elf32_Ehdr *)buf;
|
||||
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;
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
size_t e_shoff = BSWAP32(hdr->e_shoff);
|
||||
size_t num_sections = BSWAP16(hdr->e_shnum);
|
||||
if (BSWAP16(hdr->e_shentsize) != sizeof(Elf32_Shdr) ||
|
||||
e_shoff > filesize ||
|
||||
filesize - e_shoff < num_sections * sizeof(Elf32_Shdr)) {
|
||||
printf("bad e_shentsize/e_shoff\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Elf32_Shdr *sections = (Elf32_Shdr *)(buf + e_shoff);
|
||||
Elf32_Shdr *symtab = NULL;
|
||||
for (size_t i = 0; i < num_sections; i++) {
|
||||
Elf32_Shdr *s = §ions[i];
|
||||
Elf32_Off sh_offset = BSWAP32(s->sh_offset);
|
||||
if (BSWAP32(s->sh_type) != SHT_NOBITS &&
|
||||
(sh_offset > filesize || filesize - sh_offset < BSWAP32(s->sh_size))) {
|
||||
printf("bad section data\n");
|
||||
return -1;
|
||||
}
|
||||
if (BSWAP32(sections[i].sh_type) == SHT_SYMTAB) {
|
||||
symtab = §ions[i];
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
if (symtab == NULL) {
|
||||
printf("missing symtab\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Elf32_Word symtab_size = BSWAP32(symtab->sh_size);
|
||||
if (BSWAP32(symtab->sh_entsize) != sizeof(Elf32_Sym) ||
|
||||
symtab_size % sizeof(Elf32_Sym) != 0) {
|
||||
printf("bad symtab sh_size/sh_entsize\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
syms = (Elf32_Sym *)(buf + BSWAP32(symtab->sh_offset));
|
||||
size_t num_syms = symtab_size / sizeof(Elf32_Sym);
|
||||
size_t num_locals = 0;
|
||||
size_t *new_sym_order = malloc_checked(num_syms * sizeof(*new_sym_order));
|
||||
for (size_t i = 0; i < num_syms; i++) {
|
||||
new_sym_order[i] = i;
|
||||
if (ELF32_ST_BIND(syms[i].st_info) == STB_LOCAL) {
|
||||
num_locals++;
|
||||
}
|
||||
}
|
||||
qsort(new_sym_order, num_syms, sizeof(*new_sym_order), cmpsym);
|
||||
|
||||
Elf32_Sym *new_syms = malloc_checked(symtab_size);
|
||||
for (size_t i = 0; i < num_syms; i++) {
|
||||
new_syms[i] = syms[new_sym_order[i]];
|
||||
}
|
||||
if (memcmp(syms, new_syms, symtab_size)) {
|
||||
changed = 1;
|
||||
}
|
||||
memcpy(syms, new_syms, symtab_size);
|
||||
|
||||
if (symtab->sh_info != BSWAP32(num_locals)) {
|
||||
changed = 1;
|
||||
}
|
||||
symtab->sh_info = BSWAP32(num_locals);
|
||||
|
||||
size_t *new_sym_order_inv = malloc_checked(num_syms * sizeof(*new_sym_order));
|
||||
for (size_t i = 0; i < num_syms; i++) {
|
||||
new_sym_order_inv[new_sym_order[i]] = i;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_sections; i++) {
|
||||
Elf32_Shdr *s = §ions[i];
|
||||
if (BSWAP32(s->sh_type) == SHT_REL) {
|
||||
if (BSWAP32(s->sh_entsize) != sizeof(Elf32_Rel) ||
|
||||
BSWAP32(s->sh_size) % sizeof(Elf32_Rel) != 0) {
|
||||
printf("bad rel section\n");
|
||||
return -1;
|
||||
}
|
||||
Elf32_Rel *rels = (Elf32_Rel *)(buf + BSWAP32(s->sh_offset));
|
||||
size_t num_rels = BSWAP32(s->sh_size) / sizeof(Elf32_Rel);
|
||||
for (size_t j = 0; j < num_rels; j++) {
|
||||
Elf32_Word r_info = BSWAP32(rels[j].r_info);
|
||||
Elf32_Word sym = ELF32_R_SYM(r_info);
|
||||
Elf32_Word type = ELF32_R_TYPE(r_info);
|
||||
sym = (Elf32_Word)new_sym_order_inv[sym];
|
||||
r_info = ELF32_R_INFO(sym, type);
|
||||
rels[j].r_info = BSWAP32(r_info);
|
||||
}
|
||||
}
|
||||
|
||||
if (BSWAP32(s->sh_type) == SHT_RELA) {
|
||||
if (BSWAP32(s->sh_entsize) != sizeof(Elf32_Rela) ||
|
||||
BSWAP32(s->sh_size) % sizeof(Elf32_Rela) != 0) {
|
||||
printf("bad rela section\n");
|
||||
return -1;
|
||||
}
|
||||
Elf32_Rela *rels = (Elf32_Rela *)(buf + BSWAP32(s->sh_offset));
|
||||
size_t num_rels = BSWAP32(s->sh_size) / sizeof(Elf32_Rela);
|
||||
for (size_t j = 0; j < num_rels; j++) {
|
||||
Elf32_Word r_info = BSWAP32(rels[j].r_info);
|
||||
Elf32_Word sym = ELF32_R_SYM(r_info);
|
||||
Elf32_Word type = ELF32_R_TYPE(r_info);
|
||||
sym = (Elf32_Word)new_sym_order_inv[sym];
|
||||
r_info = ELF32_R_INFO(sym, type);
|
||||
rels[j].r_info = BSWAP32(r_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
if (1 != fwrite(buf, filesize, 1, f)) {
|
||||
printf("Failed to write back ELF after patching.\n");
|
||||
return -1;
|
||||
}
|
||||
fseek(f, -(long)filesize, SEEK_CUR);
|
||||
}
|
||||
free(buf);
|
||||
free(new_syms);
|
||||
free(new_sym_order);
|
||||
free(new_sym_order_inv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -121,12 +320,26 @@ int fix_mips_ar(FILE *f)
|
||||
return -1;
|
||||
}
|
||||
size_t filesize = atoi(current_header.file_size_in_bytes);
|
||||
if (fix_mips_elf(f, filesize)) {
|
||||
return -1;
|
||||
|
||||
if (filesize >= SELFMAG) {
|
||||
uint8_t magic[SELFMAG];
|
||||
|
||||
if (1 != fread(magic, SELFMAG, 1, f)) {
|
||||
printf("Failed to read ELF magic\n");
|
||||
return -1;
|
||||
}
|
||||
fseek(f, -SELFMAG, SEEK_CUR);
|
||||
|
||||
if (memcmp(magic, ELFMAG, SELFMAG) == 0) {
|
||||
if (fix_mips_elf(f, filesize)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (filesize % 2 == 1)
|
||||
filesize++;
|
||||
fseek(f, filesize - sizeof(Elf32_Ehdr), SEEK_CUR);
|
||||
fseek(f, filesize, SEEK_CUR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user