diff --git a/.gitattributes b/.gitattributes index fcadb2cf9..980b4bf4d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,22 @@ -* text eol=lf +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# force C files to unix endings regardless of host platform +# for compatibility with IDO cc +*.c text eol=lf diff=c +*.h text eol=lf diff=c + +# List text files in case git doesn't characterize correctly +*.s text +*.in text +*.js text +*.md text +*.py text diff=python +*.sh text +*.ld text +*.inc text +*.txt text +*.json text +*.yaml text +*.toml text +*.rs text diff=rust diff --git a/Makefile b/Makefile index 6d060627f..cbb4683ca 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,10 @@ ifeq ($(VERSION),us) TARGET := mk64.us endif +### Utility Functions ### +# Returns the path to the command $(1) if exists. Otherwise returns an empty string. +find-command = $(shell which $(1) 2>/dev/null) + ################ Target Executable and Sources ############### # BUILD_DIR is location where all build artifacts are placed @@ -110,29 +114,36 @@ TOOLS_DIR := tools ifeq ($(USE_QEMU_IRIX),1) # Verify that qemu-irix exists - QEMU_IRIX := $(shell which qemu-irix) - ifeq (, $(QEMU_IRIX)) + QEMU_IRIX := $(call find-command,qemu-irix) + ifeq (,$(QEMU_IRIX)) $(error Using the IDO compiler requires qemu-irix. Please install qemu-irix package or set the QEMU_IRIX environment variable to the full qemu-irix binary path) endif endif ifeq ($(USE_QEMU_IRIX),1) IRIX_ROOT := $(TOOLS_DIR)/ido5.3_compiler - CC := $(QEMU_IRIX) -silent -L $(IRIX_ROOT) $(IRIX_ROOT)/usr/bin/cc + CC := $(QEMU_IRIX) -silent -L $(IRIX_ROOT) $(IRIX_ROOT)/usr/bin/cc else IDO_ROOT := tools/ido5.3_recomp - CC := $(IDO_ROOT)/cc + CC := $(IDO_ROOT)/cc endif AS := $(CROSS)as - -CPP := cpp -P -Wno-trigraphs LD := $(CROSS)ld AR := $(CROSS)ar OBJDUMP := $(CROSS)objdump OBJCOPY := $(CROSS)objcopy PYTHON := python3 +# Prefer clang as C preprocessor if installed on the system +ifneq (,$(call find-command,clang)) + CPP := clang + CPPFLAGS := -E -P -x c -Wno-trigraphs +else + CPP := cpp + CPPFLAGS := -P -Wno-trigraphs +endif + MIPSISET := -mips2 -32 OPT_FLAGS := -O2 @@ -466,7 +477,7 @@ $(GLOBAL_ASM_O_FILES): CC := $(PYTHON) tools/asm_processor/build.py $(CC) -- $(A $(GLOBAL_ASM_AUDIO_O_FILES): CC := $(PYTHON) tools/asm_processor/build.py $(CC) -- $(AS) $(ASFLAGS) -- $(BUILD_DIR)/$(LD_SCRIPT): $(LD_SCRIPT) #repeat for other files - $(CPP) $(VERSION_CFLAGS) -DBUILD_DIR=$(BUILD_DIR) -MMD -MP -MT $@ -MF $@.d -o $@ $< + $(CPP) $(CPPFLAGS) $(VERSION_CFLAGS) -DBUILD_DIR=$(BUILD_DIR) -MMD -MP -MT $@ -MF $@.d -o $@ $< #################### Libultra ##################### diff --git a/README.md b/README.md index 6efe1b3b8..e14b52c41 100644 --- a/README.md +++ b/README.md @@ -49,14 +49,25 @@ Compiling on Windows requires `MSYS2 MinGW x64`. The setup process is a tad inte [Instructions here](docs/BUILD_WINDOWS.md) +#### macOS + +Install [Homebrew](https://brew.sh), then install the following dependencies: +``` +brew update +brew install python3 capstone coreutils make pkg-config tehzz/n64-dev/mips64-elf-binutils +``` + +When building, use `gmake` to ensure that homebrew `make` is used instead of the old, macOS system `make`. + ## Building Place a US version of Mario Kart 64 called `baserom.us.z64` into the project folder for asset extraction. Run the following commands after pulling: - -* make -C tools -* make +```bash +make -C tools +make +``` ## Progress diff --git a/src/staff_ghosts.c b/src/staff_ghosts.c index ee276d892..cd65ab00f 100644 --- a/src/staff_ghosts.c +++ b/src/staff_ghosts.c @@ -237,7 +237,7 @@ void func_80005310(void) { } } -s32 func_8000546C(void) { +void func_8000546C(void) { u32 temp_a0; u32 temp_a1; UNUSED u16 unk; diff --git a/tools/gfxdis_multi.py b/tools/gfxdis_multi.py index 44d5ff077..d424b662d 100644 --- a/tools/gfxdis_multi.py +++ b/tools/gfxdis_multi.py @@ -1,62 +1,62 @@ -#!/usr/bin/env python3 -import os, sys - -# ./gfx.py input_file_no_extension startHex -if (sys.argv[1] == "-h" or sys.argv[1] == ""): - print("How to use: ") - print("Create copy of .bin named: filename_copy.bin") - print("./gfx.py input_file_no_extension startHex iterations symbol_name") - print("iterations are in 0x10") - sys.exit(0) - -# make sure to copy the .bin file and name it: filename_copy.bin - -# copy of bin to prevent read/write conflicts between gfxdis and python -# Did it this way without testing. Just assumed there would be conflicts - -# startHex no 0x - -debug = False - -execStr = "./gfxdis.f3dex -f "+sys.argv[1]+".bin -a " - -start = int(sys.argv[2], 16) - -r = open(sys.argv[1]+"_copy.bin", "rb") -r.seek(start) - -bRunIt = True - -it = int(sys.argv[3]) * 2 # iterations. *2 for 16 bytes per line -i = 0 -calls = 0 - -offset = int(0) - -for i in range(it): - if bRunIt: - if (len(sys.argv) > 4): # if symbol_name arg exists - print("Gfx "+sys.argv[4]+str(hex(offset+start).split('x')[-1].upper())+"[] = ") - - os.system(execStr+hex(offset+start)) - if debug: - print((execStr+hex(offset+start))) - bRunIt = False - calls += 1 - - r.seek(start+offset) - data = r.read(4).hex().upper() - if data == "B8000000": - bRunIt = True - if debug: - print("Running next: "+hex(offset+start)) - - if str(data) == "00000000": - print("Found no DL command"); - break; - - offset += 8 - -print("Program exited at: "+hex(offset+start)) -print("Ran gfxdis "+str(calls)+ " times.") +#!/usr/bin/env python3 +import os, sys + +# ./gfx.py input_file_no_extension startHex +if (sys.argv[1] == "-h" or sys.argv[1] == ""): + print("How to use: ") + print("Create copy of .bin named: filename_copy.bin") + print("./gfx.py input_file_no_extension startHex iterations symbol_name") + print("iterations are in 0x10") + sys.exit(0) + +# make sure to copy the .bin file and name it: filename_copy.bin + +# copy of bin to prevent read/write conflicts between gfxdis and python +# Did it this way without testing. Just assumed there would be conflicts + +# startHex no 0x + +debug = False + +execStr = "./gfxdis.f3dex -f "+sys.argv[1]+".bin -a " + +start = int(sys.argv[2], 16) + +r = open(sys.argv[1]+"_copy.bin", "rb") +r.seek(start) + +bRunIt = True + +it = int(sys.argv[3]) * 2 # iterations. *2 for 16 bytes per line +i = 0 +calls = 0 + +offset = int(0) + +for i in range(it): + if bRunIt: + if (len(sys.argv) > 4): # if symbol_name arg exists + print("Gfx "+sys.argv[4]+str(hex(offset+start).split('x')[-1].upper())+"[] = ") + + os.system(execStr+hex(offset+start)) + if debug: + print((execStr+hex(offset+start))) + bRunIt = False + calls += 1 + + r.seek(start+offset) + data = r.read(4).hex().upper() + if data == "B8000000": + bRunIt = True + if debug: + print("Running next: "+hex(offset+start)) + + if str(data) == "00000000": + print("Found no DL command"); + break; + + offset += 8 + +print("Program exited at: "+hex(offset+start)) +print("Ran gfxdis "+str(calls)+ " times.") r.close() \ No newline at end of file diff --git a/tools/ido5.3_recomp/Makefile b/tools/ido5.3_recomp/Makefile index 3f4e30d57..750be8805 100644 --- a/tools/ido5.3_recomp/Makefile +++ b/tools/ido5.3_recomp/Makefile @@ -9,7 +9,34 @@ acpp: OPT_CFLAGS := -O2 RECOMP := recomp -#ugen_c.c: RECOMP_FLAGS := --conservative +# determine host OS for flags + UNAME_S := $(shell uname -s) + UNAME_P := $(shell uname -p) + +ifeq ($(UNAME_S),Darwin) + HOST_OS := macOS +else ifeq ($(UNAME_S),Linux) + HOST_OS := linux +else ifeq ($(OS),Windows_NT) + HOST_OS := cygwin +else + $(error Unsupported host OS for Makefile) +endif + +CFLAGS := -fno-strict-aliasing -Wno-tautological-compare +CLIBS := -lm + +ifeq ($(HOST_OS),macOS) + CFLAGS += -Wno-deprecated-declarations + ifeq (,$(findstring arm,$(shell uname -p))) + # only add flags on x86_64 macOS + CFLAGS += -fno-pie + endif +else + CFLAGS += -no-pie +endif + +ugen_c.c: RECOMP_FLAGS := --conservative all: cc cfe uopt ugen as1 acpp copt ujoin uld umerge usplit err.english.cc @@ -17,10 +44,10 @@ clean: $(RM) cc* cfe* uopt* ugen* as1* acpp* copt* ujoin* uld* umerge* usplit* err.english.cc $(RECOMP) libc_impl.o $(RECOMP): recomp.cpp - $(CXX) $^ -o $@ -std=c++11 -O2 -Dugen53 -Wno-switch `pkg-config --cflags --libs capstone` + $(CXX) $^ -o $@ -std=c++11 -O2 -Wno-switch `pkg-config --cflags --libs capstone` libc_impl.o: libc_impl.c libc_impl.h - $(CC) $< -c -fno-strict-aliasing -O2 -DIDO53 + $(CC) $< -c -O2 -DIDO53 $(CFLAGS) err.english.cc: $(IRIX_ROOT)/usr/lib/err.english.cc cp $^ $@ @@ -29,9 +56,10 @@ cc_c.c: $(IRIX_ROOT)/usr/bin/cc $(RECOMP) ./$(RECOMP) $< > $@ %_c.c: $(IRIX_ROOT)/usr/lib/% $(RECOMP) - ./$(RECOMP) $< > $@ + ./$(RECOMP) $(RECOMP_FLAGS) $< > $@ %: %_c.c libc_impl.o - $(CC) libc_impl.o $< -o $@ $(OPT_CFLAGS) -fno-strict-aliasing -lm -no-pie + $(CC) libc_impl.o $< -o $@ $(OPT_CFLAGS) $(CFLAGS) $(CLIBS) .PHONY: all clean +.DEFAULT_TARGET := all diff --git a/tools/ido5.3_recomp/elf.h b/tools/ido5.3_recomp/elf.h old mode 100644 new mode 100755 diff --git a/tools/ido5.3_recomp/helpers.h b/tools/ido5.3_recomp/helpers.h old mode 100644 new mode 100755 diff --git a/tools/ido5.3_recomp/libc_impl.c b/tools/ido5.3_recomp/libc_impl.c old mode 100644 new mode 100755 index 7a7d47b9c..76eb34fed --- a/tools/ido5.3_recomp/libc_impl.c +++ b/tools/ido5.3_recomp/libc_impl.c @@ -16,8 +16,10 @@ #ifdef __CYGWIN__ #include #endif + #ifdef __APPLE__ - #include +#include +#include #endif #include @@ -186,21 +188,39 @@ static char bin_dir[PATH_MAX + 1]; #endif static int g_file_max = 3; -#ifdef __CYGWIN__ + +/* Compilation Target/Emulation Host Page Size Determination */ +#if defined(__CYGWIN__) || (defined(__linux__) && defined(__aarch64__)) +#define RUNTIME_PAGESIZE +/* ARM64 linux can have page sizes of 4kb, 16kb, or 64kb */ +/* Set in main before running the translated code */ static size_t g_Pagesize; -#endif + +#define TRUNC_PAGE(x) ((x) & ~(g_Pagesize - 1)) +#define ROUND_PAGE(x) (TRUNC_PAGE((x) + (g_Pagesize - 1))) + +#elif defined(__APPLE__) +/* https://developer.apple.com/documentation/apple-silicon/addressing-architectural-differences-in-your-macos-code */ +#define TRUNC_PAGE(x) (trunc_page((x))) +#define ROUND_PAGE(x) (round_page((x))) + +#else +/* A fixed 4KB page size for x64 linux (is there anything else?) */ +#define TRUNC_PAGE(x) ((x) & ~(0x1000 - 1)) +#define ROUND_PAGE(x) (TRUNC_PAGE((x) + (0x1000 - 1))) +#endif /* PageSize Macros */ static uint8_t *memory_map(size_t length) { #ifdef __CYGWIN__ uint8_t *mem = mmap(0, length, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); - g_Pagesize = sysconf(_SC_PAGESIZE); - assert(((uintptr_t)mem & (g_Pagesize-1)) == 0); #else uint8_t *mem = mmap(0, length, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); #endif + + assert(TRUNC_PAGE((uintptr_t)mem) == (uintptr_t)mem); if (mem == MAP_FAILED) { - perror("mmap"); + perror("mmap (memory_map)"); exit(1); } return mem; @@ -210,20 +230,26 @@ static void memory_allocate(uint8_t *mem, uint32_t start, uint32_t end) { assert(start >= MEM_REGION_START); assert(end <= MEM_REGION_START + MEM_REGION_SIZE); + // `start` will be passed to mmap, + // so it has to be host aligned in order to keep the guest's pages valid + assert(start == TRUNC_PAGE(start)); #ifdef __CYGWIN__ - uintptr_t _start = ((uintptr_t)mem + start) & ~(g_Pagesize-1); - uintptr_t _end = ((uintptr_t)mem + end + (g_Pagesize-1)) & ~(g_Pagesize-1); + uintptr_t _start = TRUNC_PAGE((uintptr_t)mem + start); + uintptr_t _end = ROUND_PAGE((uintptr_t)mem + end); if(mprotect((void*)_start, _end - _start, PROT_READ | PROT_WRITE) < 0) { - perror("mprotect"); + perror("mprotect (memory_allocate)"); exit(1); } #else - if (mmap(mem + start, end - start, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == MAP_FAILED) { - perror("mmap"); + void *addr = (void *)TRUNC_PAGE((uintptr_t)mem + start); + size_t len = end - start; + + if (mmap(addr, len, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == MAP_FAILED) { + perror("mmap (memory_allocate)"); exit(1); } -#endif +#endif /* __CYGWIN__ */ } static void memory_unmap(uint8_t *mem, size_t length) @@ -273,6 +299,9 @@ int main(int argc, char *argv[]) { int ret; find_bin_dir(); +#ifdef RUNTIME_PAGESIZE + g_Pagesize = sysconf(_SC_PAGESIZE); +#endif /* RUNTIME_PAGESIZE */ uint8_t *mem = memory_map(MEM_REGION_SIZE); mem -= MEM_REGION_START; @@ -287,7 +316,11 @@ int main(int argc, char *argv[]) { void mmap_initial_data_range(uint8_t *mem, uint32_t start, uint32_t end) { custom_libc_data_addr = end; +#ifdef __APPLE__ + end += vm_page_size; +#else end += 4096; +#endif /* __APPLE__ */ memory_allocate(mem, start, end); cur_sbrk = end; } @@ -331,8 +364,9 @@ static uint32_t strcpy2(uint8_t *mem, uint32_t dest_addr, uint32_t src_addr) { uint32_t wrapper_sbrk(uint8_t *mem, int increment) { uint32_t old = cur_sbrk; - memory_allocate(mem, old, (old + increment)); - cur_sbrk += increment; + size_t alignedInc = ROUND_PAGE(old + increment) - old; + memory_allocate(mem, old, old + alignedInc); + cur_sbrk += alignedInc; return old; } @@ -434,10 +468,10 @@ uint32_t wrapper_malloc(uint8_t *mem, uint32_t size) { uint32_t sbrk_request = 0x10000; if (8 + item_size > sbrk_request) { sbrk_request = 8 + item_size; - sbrk_request = (sbrk_request + 0xfff) & ~0xfff; + sbrk_request = ROUND_PAGE(sbrk_request); } uint32_t left_over = sbrk_request % (8 + item_size); - sbrk_request -= left_over & ~0xfff; + sbrk_request -= left_over & ~(4096 - 1); mem_allocated += sbrk_request; ++num_sbrks; node_ptr = wrapper_sbrk(mem, sbrk_request); @@ -988,6 +1022,30 @@ uint32_t wrapper_strtoul(uint8_t *mem, uint32_t nptr_addr, uint32_t endptr_addr, return res; } +uint64_t wrapper_strtoll(uint8_t *mem, uint32_t nptr_addr, uint32_t endptr_addr, int base) { + STRING(nptr) + char *endptr = NULL; + uint64_t res = strtoll(nptr, endptr_addr != 0 ? &endptr : NULL, base); + + if(endptr != NULL) { + MEM_U32(endptr_addr) = nptr_addr + (uint32_t)(endptr - nptr); + } + + return res; +} + +uint64_t wrapper_strtoull(uint8_t *mem, uint32_t nptr_addr, uint32_t endptr_addr, int base) { + STRING(nptr) + char *endptr = NULL; + uint64_t res = strtoull(nptr, endptr_addr != 0 ? &endptr : NULL, base); + + if(endptr != NULL) { + MEM_U32(endptr_addr) = nptr_addr + (uint32_t)(endptr - nptr); + } + + return res; +} + double wrapper_strtod(uint8_t *mem, uint32_t nptr_addr, uint32_t endptr_addr) { STRING(nptr) char *endptr = NULL; @@ -1336,7 +1394,7 @@ int wrapper_ftell(uint8_t *mem, uint32_t fp_addr) { return res; } -int wrapper_rewind(uint8_t *mem, uint32_t fp_addr) { +void wrapper_rewind(uint8_t *mem, uint32_t fp_addr) { (void)wrapper_fseek(mem, fp_addr, 0, SEEK_SET); struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr); f->_flag &= ~IOERR; @@ -1787,6 +1845,7 @@ int wrapper_setvbuf(uint8_t *mem, uint32_t fp_addr, uint32_t buf_addr, int mode, f->_ptr_addr = buf_addr; f->_cnt = 0; bufendtab[(fp_addr - IOB_ADDR) / sizeof(struct FILE_irix)] = size; + return 0; } int wrapper___semgetc(uint8_t *mem, uint32_t fp_addr) { diff --git a/tools/ido5.3_recomp/libc_impl.h b/tools/ido5.3_recomp/libc_impl.h old mode 100644 new mode 100755 index af03e3cfe..4dd53935a --- a/tools/ido5.3_recomp/libc_impl.h +++ b/tools/ido5.3_recomp/libc_impl.h @@ -31,6 +31,8 @@ int wrapper_atol(uint8_t *mem, uint32_t nptr_addr); double wrapper_atof(uint8_t *mem, uint32_t nptr_addr); int wrapper_strtol(uint8_t *mem, uint32_t nptr_addr, uint32_t endptr_addr, int base); uint32_t wrapper_strtoul(uint8_t *mem, uint32_t nptr_addr, uint32_t endptr_addr, int base); +uint64_t wrapper_strtoll(uint8_t *mem, uint32_t nptr_addr, uint32_t endptr_addr, int base); +uint64_t wrapper_strtoull(uint8_t *mem, uint32_t nptr_addr, uint32_t endptr_addr, int base); double wrapper_strtod(uint8_t *mem, uint32_t nptr_addr, uint32_t endptr_addr); uint32_t wrapper_strchr(uint8_t *mem, uint32_t str_addr, int c); uint32_t wrapper_strrchr(uint8_t *mem, uint32_t str_addr, int c); @@ -49,7 +51,7 @@ uint32_t wrapper_freopen(uint8_t *mem, uint32_t path_addr, uint32_t mode_addr, u int wrapper_fclose(uint8_t *mem, uint32_t fp_addr); int wrapper_fflush(uint8_t *mem, uint32_t fp_addr); int wrapper_ftell(uint8_t *mem, uint32_t fp_addr); -int wrapper_rewind(uint8_t *mem, uint32_t fp_addr); +void wrapper_rewind(uint8_t *mem, uint32_t fp_addr); int wrapper_fseek(uint8_t *mem, uint32_t fp_addr, int offset, int origin); int wrapper_lseek(uint8_t *mem, int fd, int offset, int whence); int wrapper_dup(uint8_t *mem, int fd); diff --git a/tools/ido5.3_recomp/recomp.cpp b/tools/ido5.3_recomp/recomp.cpp old mode 100644 new mode 100755 index 45d472ac5..dc991bda3 --- a/tools/ido5.3_recomp/recomp.cpp +++ b/tools/ido5.3_recomp/recomp.cpp @@ -3,35 +3,30 @@ #include #include #include +#include +#include #include #include #include #include -#if defined(_WIN32) || defined(_WIN64) -#include -#else #include -#endif #include "elf.h" +#if defined(_WIN32) && !defined(__CYGWIN__) +#include +#endif /* _WIN32 && !__CYGWIN__ */ + #define INSPECT_FUNCTION_POINTERS 0 // set this to 1 when testing a new program, to verify that no false function pointers are found #ifndef TRACE #define TRACE 0 #endif -#ifndef ugen53 -#define ugen53 0 -#endif - #define LABELS_64_BIT 1 -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - #define u32be(x) (uint32_t)(((x & 0xff) << 24) + ((x & 0xff00) << 8) + ((x & 0xff0000) >> 8) + ((uint32_t)(x) >> 24)) #define u16be(x) (uint16_t)(((x & 0xff) << 8) + ((x & 0xff00) >> 8)) #define read_u32_be(buf) (uint32_t)(((buf)[0] << 24) + ((buf)[1] << 16) + ((buf)[2] << 8) + ((buf)[3])) @@ -81,6 +76,8 @@ struct Function { bool referenced_by_function_pointer; }; +static bool conservative; + static csh handle; static const uint8_t *text_section; @@ -153,6 +150,8 @@ static const struct { {"atof", "dp"}, {"strtol", "ippi"}, {"strtoul", "uppi"}, + {"strtoll", "lppi"}, + {"strtoull", "jppi"}, {"strtod", "dpp"}, {"strchr", "ppi"}, {"strrchr", "ppi"}, @@ -170,7 +169,7 @@ static const struct { {"freopen", "pppp"}, {"fclose", "ip"}, {"ftell", "ip"}, - {"rewind", "ip"}, + {"rewind", "vp"}, {"fseek", "ipii"}, {"lseek", "iiii"}, {"fflush", "ip"}, @@ -286,24 +285,31 @@ static const struct { static void disassemble(void) { csh handle; cs_insn *disasm; - static size_t disasm_size; + size_t disasm_size = 0; assert(cs_open(CS_ARCH_MIPS, (cs_mode)(CS_MODE_MIPS64 | CS_MODE_BIG_ENDIAN), &handle) == CS_ERR_OK); cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); - disasm_size = cs_disasm(handle, text_section, text_section_len, text_vaddr, 0, &disasm); - for (size_t i = 0; i < disasm_size; i++) { - insns.push_back(Insn()); - Insn& insn = insns.back(); - insn.id = disasm[i].id; - insn.mnemonic = disasm[i].mnemonic; - insn.op_str = disasm[i].op_str; - if (disasm[i].detail != nullptr && disasm[i].detail->mips.op_count > 0) { - insn.op_count = disasm[i].detail->mips.op_count; - memcpy(insn.operands, disasm[i].detail->mips.operands, sizeof(insn.operands)); + insns.reserve(1 + text_section_len / sizeof(uint32_t)); // +1 for dummy instruction + while (text_section_len > disasm_size * sizeof(uint32_t)) { + size_t disasm_len = disasm_size * sizeof(uint32_t); + size_t remaining = text_section_len - disasm_len; + size_t current_len = std::min(remaining, 1024); + size_t cur_disasm_size = cs_disasm(handle, &text_section[disasm_len], current_len, text_vaddr + disasm_len, 0, &disasm); + disasm_size += cur_disasm_size; + for (size_t i = 0; i < cur_disasm_size; i++) { + insns.push_back(Insn()); + Insn& insn = insns.back(); + insn.id = disasm[i].id; + insn.mnemonic = disasm[i].mnemonic; + insn.op_str = disasm[i].op_str; + if (disasm[i].detail != nullptr && disasm[i].detail->mips.op_count > 0) { + insn.op_count = disasm[i].detail->mips.op_count; + memcpy(insn.operands, disasm[i].detail->mips.operands, sizeof(insn.operands)); + } + insn.is_jump = cs_insn_group(handle, &disasm[i], MIPS_GRP_JUMP) || insn.id == MIPS_INS_JAL || insn.id == MIPS_INS_BAL || insn.id == MIPS_INS_JALR; + insn.linked_insn = -1; } - insn.is_jump = cs_insn_group(handle, &disasm[i], MIPS_GRP_JUMP) || insn.id == MIPS_INS_JAL || insn.id == MIPS_INS_BAL || insn.id == MIPS_INS_JALR; - insn.linked_insn = -1; + cs_free(disasm, cur_disasm_size); } - cs_free(disasm, disasm_size); cs_close(&handle); { @@ -340,7 +346,7 @@ static void link_with_lui(int offset, uint32_t reg, int mem_imm) #define MAX_LOOKBACK 128 // don't attempt to compute addresses for zero offset // end search after some sane max number of instructions - int end_search = MAX(0, offset - MAX_LOOKBACK); + int end_search = std::max(0, offset - MAX_LOOKBACK); for (int search = offset - 1; search >= end_search; search--) { // use an `if` instead of `case` block to allow breaking out of the `for` loop if (insns[search].id == MIPS_INS_LUI) { @@ -427,7 +433,7 @@ static void link_with_lui(int offset, uint32_t reg, int mem_imm) static void link_with_jalr(int offset) { // end search after some sane max number of instructions - int end_search = MAX(0, offset - MAX_LOOKBACK); + int end_search = std::max(0, offset - MAX_LOOKBACK); for (int search = offset - 1; search >= end_search; search--) { if (insns[search].operands[0].reg == MIPS_REG_T9) { if (insns[search].id == MIPS_INS_LW || insns[search].id == MIPS_INS_LI) { @@ -1640,7 +1646,7 @@ static void dump_instr(int i) { printf("++cnt; printf(\"pc=0x%08x%s%s\\n\"); ", text_vaddr + i * 4, symbol_name ? " " : "", symbol_name ? symbol_name : ""); } Insn& insn = insns[i]; - if (!insn.is_jump && !ugen53) { + if (!insn.is_jump && !conservative) { switch (insn_to_type(insn)) { case TYPE_1S: if (!(insn.f_livein & map_reg(insn.operands[0].reg))) { @@ -2160,6 +2166,12 @@ static void dump_instr(int i) { printf("lo = %s * %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg)); printf("hi = (uint32_t)((uint64_t)%s * (uint64_t)%s >> 32);\n", r(insn.operands[0].reg), r(insn.operands[1].reg)); break; + case MIPS_INS_SQRT: + printf("%s = sqrtf(%s);\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg)); + break; + //case MIPS_INS_FSQRT: + // printf("%s = sqrtf(%s);\n", wr(insn.operands[0].reg), wr(insn.operands[1].reg)); + // break; case MIPS_INS_NEGU: printf("%s = -%s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg)); break; @@ -2338,27 +2350,35 @@ static void dump_c(void) { uint32_t max_addr = 0; if (data_section_len > 0) { - min_addr = MIN(min_addr, data_vaddr); - max_addr = MAX(max_addr, data_vaddr + data_section_len); + min_addr = std::min(min_addr, data_vaddr); + max_addr = std::max(max_addr, data_vaddr + data_section_len); } if (rodata_section_len > 0) { - min_addr = MIN(min_addr, rodata_vaddr); - max_addr = MAX(max_addr, rodata_vaddr + rodata_section_len); + min_addr = std::min(min_addr, rodata_vaddr); + max_addr = std::max(max_addr, rodata_vaddr + rodata_section_len); } if (bss_section_len) { - min_addr = MIN(min_addr, bss_vaddr); - max_addr = MAX(max_addr, bss_vaddr + bss_section_len); + min_addr = std::min(min_addr, bss_vaddr); + max_addr = std::max(max_addr, bss_vaddr + bss_section_len); } - min_addr = min_addr & ~0xfff; - max_addr = (max_addr + 0xfff) & ~0xfff; + // get pagesize at runtime +#if defined(_WIN32) && !defined(__CYGWIN__) + SYSTEM_INFO si; + GetSystemInfo(&si); + uint32_t page_size = si.dwPageSize; +#else + uint32_t page_size = sysconf(_SC_PAGESIZE); +#endif /* _WIN32 && !__CYGWIN__ */ + min_addr = min_addr & ~(page_size - 1); + max_addr = (max_addr + (page_size - 1)) & ~(page_size - 1); uint32_t stack_bottom = min_addr; min_addr -= 1 * 1024 * 1024; // 1 MB stack stack_bottom -= 16; // for main's stack frame printf("#include \"header.h\"\n"); - if (ugen53) { + if (conservative) { printf("static uint32_t s0, s1, s2, s3, s4, s5, s6, s7, fp;\n"); } printf("static const uint32_t rodata[] = {\n"); @@ -2486,7 +2506,7 @@ static void dump_c(void) { dump_function_signature(f, start_addr); printf(" {\n"); printf("const uint32_t zero = 0;\n"); - if (!ugen53) { + if (!conservative) { printf("uint32_t at = 0, v1 = 0, t0 = 0, t1 = 0, t2 = 0,\n"); printf("t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, s0 = 0, s1 = 0, s2 = 0, s3 = 0, s4 = 0, s5 = 0,\n"); printf("s6 = 0, s7 = 0, t8 = 0, t9 = 0, gp = 0, fp = 0, s8 = 0, ra = 0;\n"); @@ -2911,8 +2931,14 @@ size_t read_file(const char *file_name, uint8_t **data) { } int main(int argc, char *argv[]) { + const char *filename = argv[1]; + if (strcmp(filename, "--conservative") == 0) { + conservative = true; + filename = argv[2]; + } + uint8_t *data; - size_t len = read_file(argv[1], &data); + size_t len = read_file(filename, &data); parse_elf(data, len); assert(cs_open(CS_ARCH_MIPS, (cs_mode)(CS_MODE_MIPS64 | CS_MODE_BIG_ENDIAN), &handle) == CS_ERR_OK); cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);