mirror of
https://github.com/n64decomp/mk64.git
synced 2024-11-26 22:50:47 +00:00
Add building on macOS (#224)
* build OK macOS * add macOS building instructions * change return type of func_8000546C * prevent gitattributes from removing CRLF from ido binaries
This commit is contained in:
parent
491f37be4d
commit
0f0ff04779
23
.gitattributes
vendored
23
.gitattributes
vendored
@ -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
|
||||
|
25
Makefile
25
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 #####################
|
||||
|
17
README.md
17
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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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()
|
@ -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
|
||||
|
0
tools/ido5.3_recomp/elf.h
Normal file → Executable file
0
tools/ido5.3_recomp/elf.h
Normal file → Executable file
0
tools/ido5.3_recomp/helpers.h
Normal file → Executable file
0
tools/ido5.3_recomp/helpers.h
Normal file → Executable file
93
tools/ido5.3_recomp/libc_impl.c
Normal file → Executable file
93
tools/ido5.3_recomp/libc_impl.c
Normal file → Executable file
@ -16,8 +16,10 @@
|
||||
#ifdef __CYGWIN__
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach/vm_page_size.h>
|
||||
#endif
|
||||
|
||||
#include <sys/mman.h>
|
||||
@ -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) {
|
||||
|
4
tools/ido5.3_recomp/libc_impl.h
Normal file → Executable file
4
tools/ido5.3_recomp/libc_impl.h
Normal file → Executable file
@ -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);
|
||||
|
106
tools/ido5.3_recomp/recomp.cpp
Normal file → Executable file
106
tools/ido5.3_recomp/recomp.cpp
Normal file → Executable file
@ -3,35 +3,30 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <capstone/capstone.h>
|
||||
#else
|
||||
#include <capstone.h>
|
||||
#endif
|
||||
|
||||
#include "elf.h"
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#include <windows.h>
|
||||
#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<size_t>(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);
|
||||
|
Loading…
Reference in New Issue
Block a user