Add MSYS2 MinGW x64 Support (#108)
* Added MSYS2 MinGW x64 Support * Updated recomp * Updated tools
This commit is contained in:
parent
cdb3ca63aa
commit
48a06f2fa5
20
README.md
20
README.md
|
|
@ -24,15 +24,31 @@ The build system has the following package requirements:
|
||||||
binutils-mips >= 2.27
|
binutils-mips >= 2.27
|
||||||
python3 >= 3.6
|
python3 >= 3.6
|
||||||
libaudiofile
|
libaudiofile
|
||||||
qemu-irix
|
|
||||||
|
|
||||||
To add submodules run `git submodule update --init --recursive` after cloning.
|
To add submodules run `git submodule update --init --recursive` after cloning.
|
||||||
|
|
||||||
Debian / Ubuntu
|
##### Debian / Ubuntu
|
||||||
```
|
```
|
||||||
sudo apt install build-essential pkg-config git binutils-mips-linux-gnu python3 zlib1g-dev libaudiofile-dev
|
sudo apt install build-essential pkg-config git binutils-mips-linux-gnu python3 zlib1g-dev libaudiofile-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### Arch Linux
|
||||||
|
|
||||||
|
To install build dependencies:
|
||||||
|
```
|
||||||
|
sudo pacman -S base-devel capstone python
|
||||||
|
```
|
||||||
|
Install the following AUR packages:
|
||||||
|
* [mips64-elf-binutils](https://aur.archlinux.org/packages/mips64-elf-binutils) (AUR)
|
||||||
|
|
||||||
|
Review the n64decomp/sm64 readme for instructions to compile in other distributions.
|
||||||
|
|
||||||
|
##### Windows
|
||||||
|
|
||||||
|
Compiling on Windows requires `MSYS2 MinGW x64`. The setup process is a tad intensive.
|
||||||
|
|
||||||
|
[Instructions here](docs/BUILD_WINDOWS.md)
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
Place a US version of Mario Kart 64 called `baserom.us.z64` into the project folder for asset extraction.
|
Place a US version of Mario Kart 64 called `baserom.us.z64` into the project folder for asset extraction.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
### These instructions are a WIP and may be missing steps
|
||||||
|
|
||||||
|
## Compiling mk64 Decomp In Windows
|
||||||
|
|
||||||
|
The extraneous and convoluted process to building mk64 decomp on Windows begins with disabling your anti-virus program or adding an exception to the mk64 decomp folder and/or the msys2 installation folder.
|
||||||
|
Please note that this action may impact the security of your system. Prior to proceeding, make sure to understand the increased security risks that may result from this step. Nobody except you, is responsible and liable for your system and its security.
|
||||||
|
|
||||||
|
### Preamble
|
||||||
|
Any misteps may require a complete uninstall of `MSYS2 MinGW x64` and restarting from the very beginning.
|
||||||
|
It is unknown if `MSYS MinGW x32` works.
|
||||||
|
|
||||||
|
### Step 1: Download MSYS2 MinGW x64
|
||||||
|
|
||||||
|
https://www.msys2.org/
|
||||||
|
|
||||||
|
Follow the initial instructions to update the base packages. Ignore installing any extra packages in-case they conflict with the below steps.
|
||||||
|
|
||||||
|
MinGW is a separate program from Msys2. However, it must be wrapped right into msys2.
|
||||||
|
Compiling recomp requires steps using `MSYS2 MSYS` *and* `MSYS2 MinGW x64`. The instructions will clearly differentiate which program to launch and run in the section titles.
|
||||||
|
|
||||||
|
##### Why flip-flop between both?
|
||||||
|
Compiling the recomp executable that generates the source files for compiling the compiler requires capstone. A disassembly, analysis, and reverse-engineering framework. Capstone is only available on `MSYS2 MinGW x64`. It is not available on `MSYS2 MSYS`. However, compiling the compiler itself requires `MSYS2 MSYS` because it contains an equivallent dependency for `mman`. A memory mapping library. `MSYS2 MinGW x64` does not contain an equivallent dependancy.
|
||||||
|
|
||||||
|
|
||||||
|
### Step 2: Install Dependancies in MSYS2 MinGW x64
|
||||||
|
```
|
||||||
|
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-capstone pkgconf make python3 git
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Install Dependencies in MSYS2 MSYS
|
||||||
|
```
|
||||||
|
pacman -S gcc
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Compile Binutils For mips and Install
|
||||||
|
Download and run: [get_bin.sh](get_bin.sh)
|
||||||
|
|
||||||
|
### Step 5: Compiling recomp.exe in `MSYS2 MinGW x64`
|
||||||
|
In `MSYS2 MinGW x64` run in `mk64/tools/ido5.3_recomp/`:
|
||||||
|
```
|
||||||
|
g++ recomp.cpp -o recomp -g -lcapstone -Dugen53
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 6: Compiling the recomp compiler in `MSYS2 MSYS`
|
||||||
|
In `MSYS2 MSYS` run:
|
||||||
|
```
|
||||||
|
make -C tools
|
||||||
|
```
|
||||||
|
If the make file is broken then manually compile each executable.
|
||||||
|
Generate C file in `mk64/tools/ido5.3_recomp/`:
|
||||||
|
```
|
||||||
|
./recomp ~/ido7.1_compiler/usr/lib/as1 > as1_c.c
|
||||||
|
```
|
||||||
|
Compile generated C file:
|
||||||
|
```
|
||||||
|
gcc libc_impl.c as1_c.c -o as1 -g -fno-strict-aliasing -lm -no-pie -DIDO53 -O2
|
||||||
|
```
|
||||||
|
`-O2` is an optional optimization flag.
|
||||||
|
mk64 requires the following: as1, cc, cfe, copt, ugen, ujoin, uld, umerge, uopt
|
||||||
|
|
||||||
|
### Step 7: Compile mk64 in `MSYS2 MinGW x64`
|
||||||
|
In `/mk64/` run:
|
||||||
|
```
|
||||||
|
make -j#
|
||||||
|
```
|
||||||
|
Replace # with your number of CPU cores for qucker compilation.
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# --- Useful Variables --- #
|
||||||
|
|
||||||
|
# This is the specific binutils version that will be downloaded
|
||||||
|
binutils=binutils-2.36
|
||||||
|
|
||||||
|
# Where the built files will end up.
|
||||||
|
# If this directory doesn't already exist it will be created automatically.
|
||||||
|
destFolder=./tools/binutils
|
||||||
|
|
||||||
|
# The temporary folder name to work from.
|
||||||
|
tempFolder=build_temp
|
||||||
|
|
||||||
|
# The prefix appended to the start of the built files.
|
||||||
|
prefix=mips64-elf-
|
||||||
|
|
||||||
|
# Folder names within the binutils directory.
|
||||||
|
binFolder=binutils
|
||||||
|
ldFolder=ld
|
||||||
|
gasFolder=gas
|
||||||
|
|
||||||
|
# How many threads to use with make (All of them)
|
||||||
|
threadCount=$(nproc --all)
|
||||||
|
|
||||||
|
# --- Useful Macros --- #
|
||||||
|
|
||||||
|
PRINT_STEP () {
|
||||||
|
echo "($1) ==== $2 ==== "
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTALL_FILE() {
|
||||||
|
cp ./$tempFolder/$binutils/$2/$1 $destFolder/$prefix$1
|
||||||
|
echo "Installed mips64-elf-$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
RENAME_AND_INSTALL_FILE() {
|
||||||
|
cp ./$tempFolder/$binutils/$2/$1 $destFolder/$prefix$3
|
||||||
|
echo "Installed mips64-elf-$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Script --- #
|
||||||
|
|
||||||
|
# Make the destintation folder if it already doesn't exist.
|
||||||
|
mkdir -p $destFolder
|
||||||
|
|
||||||
|
# Having a temp folder makes things easy to cleanup
|
||||||
|
#rm -Rf $tempFolder # This will remove the temp folder if it exists for some reason.
|
||||||
|
mkdir $tempFolder
|
||||||
|
cd $tempFolder
|
||||||
|
|
||||||
|
PRINT_STEP 1 "DOWNLOADING BINUTILS FROM GNU.ORG"
|
||||||
|
wget ftp://ftp.gnu.org/gnu/binutils/$binutils.tar.xz
|
||||||
|
|
||||||
|
PRINT_STEP 2 "EXTRACTING TAR FILE"
|
||||||
|
tar -xf $binutils.tar.xz
|
||||||
|
|
||||||
|
PRINT_STEP 3 "CONFIGURING THE MAKEFILE"
|
||||||
|
cd $binutils
|
||||||
|
|
||||||
|
# Credit goes to queueRAM for letting me know what the correct arguments are.
|
||||||
|
./configure --target=mips64-elf --prefix=/usr --with-sysroot=/usr/mips64-elf --with-gnu-as --with-gnu-ld --enable-64-bit-bfd --enable-multilib --enable-plugins --disable-gold --disable-nls --disable-shared --disable-werror
|
||||||
|
|
||||||
|
PRINT_STEP 4 "MAKING BINUTILS"
|
||||||
|
make -j$threadCount
|
||||||
|
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
PRINT_STEP 5 "INSTALLING BUILT FILES"
|
||||||
|
|
||||||
|
# Add or remove programs here.
|
||||||
|
INSTALL_FILE ar $binFolder
|
||||||
|
INSTALL_FILE objcopy $binFolder
|
||||||
|
INSTALL_FILE objdump $binFolder
|
||||||
|
RENAME_AND_INSTALL_FILE as-new $gasFolder as
|
||||||
|
RENAME_AND_INSTALL_FILE ld-new $ldFolder ld
|
||||||
|
|
||||||
|
PRINT_STEP 6 "CLEANING UP"
|
||||||
|
#rm -Rf $tempFolder
|
||||||
|
|
||||||
|
PRINT_STEP - "DONE!"
|
||||||
|
|
@ -236,9 +236,10 @@ def main():
|
||||||
else: # pull directly from same block as CI data
|
else: # pull directly from same block as CI data
|
||||||
pal_offset = int(meta["pal"], 0)
|
pal_offset = int(meta["pal"], 0)
|
||||||
pal_input = image[pal_offset : pal_offset + pal_size]
|
pal_input = image[pal_offset : pal_offset + pal_size]
|
||||||
tmp_pal = tempfile.NamedTemporaryFile(prefix="asset_pal")
|
tmp_pal = tempfile.NamedTemporaryFile(prefix="asset_pal", delete=False)
|
||||||
tmp_pal.write(pal_input)
|
tmp_pal.write(pal_input)
|
||||||
tmp_pal.flush()
|
tmp_pal.flush()
|
||||||
|
tmp_pal.close()
|
||||||
# append the palette commands
|
# append the palette commands
|
||||||
cmd.extend([
|
cmd.extend([
|
||||||
"-c", ci_fmt,
|
"-c", ci_fmt,
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,8 @@ del compile_args[out_ind]
|
||||||
in_dir = os.path.split(os.path.realpath(in_file))[0]
|
in_dir = os.path.split(os.path.realpath(in_file))[0]
|
||||||
opt_flags = [x for x in compile_args if x in ['-g', '-O2', '-framepointer']]
|
opt_flags = [x for x in compile_args if x in ['-g', '-O2', '-framepointer']]
|
||||||
|
|
||||||
preprocessed_file = tempfile.NamedTemporaryFile(prefix='preprocessed', suffix='.c')
|
|
||||||
|
preprocessed_file = tempfile.NamedTemporaryFile(prefix='preprocessed', suffix='.c', delete=False)
|
||||||
|
|
||||||
subprocess.check_call(asm_processor + opt_flags + [in_file], stdout=preprocessed_file)
|
subprocess.check_call(asm_processor + opt_flags + [in_file], stdout=preprocessed_file)
|
||||||
subprocess.check_call(compiler + compile_args + ['-I', in_dir, '-o', out_file, preprocessed_file.name])
|
subprocess.check_call(compiler + compile_args + ['-I', in_dir, '-o', out_file, preprocessed_file.name])
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,11 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#include <io.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define EI_DATA 5
|
#define EI_DATA 5
|
||||||
#define EI_NIDENT 16
|
#define EI_NIDENT 16
|
||||||
|
|
||||||
|
|
@ -179,6 +184,17 @@ static bool elf_get_section_range(uint8_t *file, const char *searched_name, uint
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FILE *mio0_open_out_file(const char *out_file) {
|
||||||
|
if (strcmp(out_file, "-") == 0) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
_setmode(_fileno(stdout), _O_BINARY);
|
||||||
|
#endif
|
||||||
|
return stdout;
|
||||||
|
} else {
|
||||||
|
return fopen(out_file, "wb");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
fprintf(stderr, "Usage: %s INFILE OUTFILE\n", argv[0]);
|
fprintf(stderr, "Usage: %s INFILE OUTFILE\n", argv[0]);
|
||||||
|
|
@ -299,9 +315,11 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *out = fopen(argv[2], "wb");
|
FILE *out = mio0_open_out_file(argv[2]);
|
||||||
fwrite(file + data_offset, 1, new_size, out);
|
fwrite(file + data_offset, 1, new_size, out);
|
||||||
fclose(out);
|
if (out != stdout) {
|
||||||
|
fclose(out);
|
||||||
|
}
|
||||||
|
|
||||||
free(file);
|
free(file);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ acpp: OPT_CFLAGS := -O2
|
||||||
|
|
||||||
RECOMP := recomp
|
RECOMP := recomp
|
||||||
|
|
||||||
ugen_c.c: RECOMP_FLAGS := --conservative
|
#ugen_c.c: RECOMP_FLAGS := --conservative
|
||||||
|
|
||||||
all: cc cfe uopt ugen as1 acpp copt ujoin uld umerge usplit err.english.cc
|
all: cc cfe uopt ugen as1 acpp copt ujoin uld umerge usplit err.english.cc
|
||||||
|
|
||||||
|
|
@ -17,7 +17,7 @@ clean:
|
||||||
$(RM) cc* cfe* uopt* ugen* as1* acpp* copt* ujoin* uld* umerge* usplit* err.english.cc $(RECOMP) libc_impl.o
|
$(RM) cc* cfe* uopt* ugen* as1* acpp* copt* ujoin* uld* umerge* usplit* err.english.cc $(RECOMP) libc_impl.o
|
||||||
|
|
||||||
$(RECOMP): recomp.cpp
|
$(RECOMP): recomp.cpp
|
||||||
$(CXX) $^ -o $@ -std=c++11 -O2 -Wno-switch `pkg-config --cflags --libs capstone`
|
$(CXX) $^ -o $@ -std=c++11 -O2 -Dugen53 -Wno-switch `pkg-config --cflags --libs capstone`
|
||||||
|
|
||||||
libc_impl.o: libc_impl.c libc_impl.h
|
libc_impl.o: libc_impl.c libc_impl.h
|
||||||
$(CC) $< -c -fno-strict-aliasing -O2 -DIDO53
|
$(CC) $< -c -fno-strict-aliasing -O2 -DIDO53
|
||||||
|
|
@ -26,10 +26,10 @@ err.english.cc: $(IRIX_ROOT)/usr/lib/err.english.cc
|
||||||
cp $^ $@
|
cp $^ $@
|
||||||
|
|
||||||
cc_c.c: $(IRIX_ROOT)/usr/bin/cc $(RECOMP)
|
cc_c.c: $(IRIX_ROOT)/usr/bin/cc $(RECOMP)
|
||||||
./$(RECOMP) $(RECOMP_FLAGS) $< > $@
|
./$(RECOMP) $< > $@
|
||||||
|
|
||||||
%_c.c: $(IRIX_ROOT)/usr/lib/% $(RECOMP)
|
%_c.c: $(IRIX_ROOT)/usr/lib/% $(RECOMP)
|
||||||
./$(RECOMP) $(RECOMP_FLAGS) $< > $@
|
./$(RECOMP) $< > $@
|
||||||
|
|
||||||
%: %_c.c libc_impl.o
|
%: %_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) -fno-strict-aliasing -lm -no-pie
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
param[i] = MEM_S8(param##_addr + i); \
|
param[i] = MEM_S8(param##_addr + i); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(IDO53) && !defined(IDO71)
|
#if !defined(IDO53) && !defined(IDO71) && !defined(IDO72)
|
||||||
#define IDO71
|
#define IDO71
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -68,6 +68,15 @@
|
||||||
#define LIBC_SIZE 0x3000
|
#define LIBC_SIZE 0x3000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef IDO72
|
||||||
|
// IDO 7.2
|
||||||
|
#define IOB_ADDR 0x0fb49454
|
||||||
|
#define ERRNO_ADDR 0x0fb49290
|
||||||
|
#define CTYPE_ADDR 0x0fb46db0
|
||||||
|
#define LIBC_ADDR 0x0fb46000
|
||||||
|
#define LIBC_SIZE 0x4000
|
||||||
|
#endif
|
||||||
|
|
||||||
#define STDIN_ADDR IOB_ADDR
|
#define STDIN_ADDR IOB_ADDR
|
||||||
#define STDOUT_ADDR (IOB_ADDR + 0x10)
|
#define STDOUT_ADDR (IOB_ADDR + 0x10)
|
||||||
#define STDERR_ADDR (IOB_ADDR + 0x20)
|
#define STDERR_ADDR (IOB_ADDR + 0x20)
|
||||||
|
|
@ -177,13 +186,13 @@ static char bin_dir[PATH_MAX + 1];
|
||||||
#endif
|
#endif
|
||||||
static int g_file_max = 3;
|
static int g_file_max = 3;
|
||||||
|
|
||||||
#if defined(__CYGWIN__) || defined(__APPLE__)
|
#ifdef __CYGWIN__
|
||||||
static size_t g_Pagesize;
|
static size_t g_Pagesize;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static uint8_t *memory_map(size_t length)
|
static uint8_t *memory_map(size_t length)
|
||||||
{
|
{
|
||||||
#if defined(__CYGWIN__) || defined(__APPLE__)
|
#ifdef __CYGWIN__
|
||||||
uint8_t *mem = mmap(0, length, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
|
uint8_t *mem = mmap(0, length, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
|
||||||
g_Pagesize = sysconf(_SC_PAGESIZE);
|
g_Pagesize = sysconf(_SC_PAGESIZE);
|
||||||
assert(((uintptr_t)mem & (g_Pagesize-1)) == 0);
|
assert(((uintptr_t)mem & (g_Pagesize-1)) == 0);
|
||||||
|
|
@ -201,7 +210,7 @@ static void memory_allocate(uint8_t *mem, uint32_t start, uint32_t end)
|
||||||
{
|
{
|
||||||
assert(start >= MEM_REGION_START);
|
assert(start >= MEM_REGION_START);
|
||||||
assert(end <= MEM_REGION_START + MEM_REGION_SIZE);
|
assert(end <= MEM_REGION_START + MEM_REGION_SIZE);
|
||||||
#if defined(__CYGWIN__) || defined(__APPLE__)
|
#ifdef __CYGWIN__
|
||||||
uintptr_t _start = ((uintptr_t)mem + start) & ~(g_Pagesize-1);
|
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 _end = ((uintptr_t)mem + end + (g_Pagesize-1)) & ~(g_Pagesize-1);
|
||||||
|
|
||||||
|
|
@ -1327,7 +1336,7 @@ int wrapper_ftell(uint8_t *mem, uint32_t fp_addr) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wrapper_rewind(uint8_t *mem, uint32_t fp_addr) {
|
int wrapper_rewind(uint8_t *mem, uint32_t fp_addr) {
|
||||||
(void)wrapper_fseek(mem, fp_addr, 0, SEEK_SET);
|
(void)wrapper_fseek(mem, fp_addr, 0, SEEK_SET);
|
||||||
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
|
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
|
||||||
f->_flag &= ~IOERR;
|
f->_flag &= ~IOERR;
|
||||||
|
|
@ -1778,7 +1787,6 @@ int wrapper_setvbuf(uint8_t *mem, uint32_t fp_addr, uint32_t buf_addr, int mode,
|
||||||
f->_ptr_addr = buf_addr;
|
f->_ptr_addr = buf_addr;
|
||||||
f->_cnt = 0;
|
f->_cnt = 0;
|
||||||
bufendtab[(fp_addr - IOB_ADDR) / sizeof(struct FILE_irix)] = size;
|
bufendtab[(fp_addr - IOB_ADDR) / sizeof(struct FILE_irix)] = size;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int wrapper___semgetc(uint8_t *mem, uint32_t fp_addr) {
|
int wrapper___semgetc(uint8_t *mem, uint32_t fp_addr) {
|
||||||
|
|
@ -2181,8 +2189,15 @@ int wrapper_pathconf(uint8_t *mem, uint32_t path_addr, int name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t wrapper_getenv(uint8_t *mem, uint32_t name_addr) {
|
uint32_t wrapper_getenv(uint8_t *mem, uint32_t name_addr) {
|
||||||
// Return null for everything, for now
|
STRING(name);
|
||||||
return 0;
|
const char *value = getenv(name);
|
||||||
|
if (value == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t value_size = strlen(value) + 1;
|
||||||
|
uint32_t buf_addr = wrapper_malloc(mem, value_size);
|
||||||
|
strcpy1(mem, buf_addr, value);
|
||||||
|
return buf_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t wrapper_gettxt(uint8_t *mem, uint32_t msgid_addr, uint32_t default_str_addr) {
|
uint32_t wrapper_gettxt(uint8_t *mem, uint32_t msgid_addr, uint32_t default_str_addr) {
|
||||||
|
|
@ -2355,7 +2370,19 @@ int wrapper_mkstemp(uint8_t *mem, uint32_t name_addr) {
|
||||||
|
|
||||||
uint32_t wrapper_tmpfile(uint8_t *mem) {
|
uint32_t wrapper_tmpfile(uint8_t *mem) {
|
||||||
// create and fopen a temporary file that is removed when the program exits
|
// create and fopen a temporary file that is removed when the program exits
|
||||||
char name[] = "/tmp/copt_temp_XXXXXX";
|
const char *tmpdir = getenv("TMPDIR");
|
||||||
|
if (tmpdir == NULL) {
|
||||||
|
tmpdir = "/tmp";
|
||||||
|
}
|
||||||
|
|
||||||
|
char name[PATH_MAX + 1] = {0};
|
||||||
|
int n = snprintf(name, sizeof(name), "%s/copt_temp_XXXXXX", tmpdir);
|
||||||
|
if (n < 0 || n >= sizeof(name)) {
|
||||||
|
// This isn't the best errno code, but it is one that can be returned by tmpfile
|
||||||
|
MEM_U32(ERRNO_ADDR) = EACCES;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int fd = mkstemp(name);
|
int fd = mkstemp(name);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
MEM_U32(ERRNO_ADDR) = errno;
|
MEM_U32(ERRNO_ADDR) = errno;
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,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_fclose(uint8_t *mem, uint32_t fp_addr);
|
||||||
int wrapper_fflush(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_ftell(uint8_t *mem, uint32_t fp_addr);
|
||||||
void wrapper_rewind(uint8_t *mem, uint32_t fp_addr);
|
int 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_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_lseek(uint8_t *mem, int fd, int offset, int whence);
|
||||||
int wrapper_dup(uint8_t *mem, int fd);
|
int wrapper_dup(uint8_t *mem, int fd);
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,16 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#include <capstone/capstone.h>
|
||||||
|
#else
|
||||||
#include <capstone.h>
|
#include <capstone.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
|
|
||||||
|
|
@ -20,8 +23,15 @@
|
||||||
#define TRACE 0
|
#define TRACE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef ugen53
|
||||||
|
#define ugen53 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#define LABELS_64_BIT 1
|
#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 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 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]))
|
#define read_u32_be(buf) (uint32_t)(((buf)[0] << 24) + ((buf)[1] << 16) + ((buf)[2] << 8) + ((buf)[3]))
|
||||||
|
|
@ -71,8 +81,6 @@ struct Function {
|
||||||
bool referenced_by_function_pointer;
|
bool referenced_by_function_pointer;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool conservative;
|
|
||||||
|
|
||||||
static csh handle;
|
static csh handle;
|
||||||
|
|
||||||
static const uint8_t *text_section;
|
static const uint8_t *text_section;
|
||||||
|
|
@ -162,7 +170,7 @@ static const struct {
|
||||||
{"freopen", "pppp"},
|
{"freopen", "pppp"},
|
||||||
{"fclose", "ip"},
|
{"fclose", "ip"},
|
||||||
{"ftell", "ip"},
|
{"ftell", "ip"},
|
||||||
{"rewind", "vp"},
|
{"rewind", "ip"},
|
||||||
{"fseek", "ipii"},
|
{"fseek", "ipii"},
|
||||||
{"lseek", "iiii"},
|
{"lseek", "iiii"},
|
||||||
{"fflush", "ip"},
|
{"fflush", "ip"},
|
||||||
|
|
@ -278,31 +286,24 @@ static const struct {
|
||||||
static void disassemble(void) {
|
static void disassemble(void) {
|
||||||
csh handle;
|
csh handle;
|
||||||
cs_insn *disasm;
|
cs_insn *disasm;
|
||||||
size_t disasm_size = 0;
|
static size_t disasm_size;
|
||||||
assert(cs_open(CS_ARCH_MIPS, (cs_mode)(CS_MODE_MIPS64 | CS_MODE_BIG_ENDIAN), &handle) == CS_ERR_OK);
|
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);
|
cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
|
||||||
insns.reserve(1 + text_section_len / sizeof(uint32_t)); // +1 for dummy instruction
|
disasm_size = cs_disasm(handle, text_section, text_section_len, text_vaddr, 0, &disasm);
|
||||||
while (text_section_len > disasm_size * sizeof(uint32_t)) {
|
for (size_t i = 0; i < disasm_size; i++) {
|
||||||
size_t disasm_len = disasm_size * sizeof(uint32_t);
|
insns.push_back(Insn());
|
||||||
size_t remaining = text_section_len - disasm_len;
|
Insn& insn = insns.back();
|
||||||
size_t current_len = std::min<size_t>(remaining, 1024);
|
insn.id = disasm[i].id;
|
||||||
size_t cur_disasm_size = cs_disasm(handle, &text_section[disasm_len], current_len, text_vaddr + disasm_len, 0, &disasm);
|
insn.mnemonic = disasm[i].mnemonic;
|
||||||
disasm_size += cur_disasm_size;
|
insn.op_str = disasm[i].op_str;
|
||||||
for (size_t i = 0; i < cur_disasm_size; i++) {
|
if (disasm[i].detail != nullptr && disasm[i].detail->mips.op_count > 0) {
|
||||||
insns.push_back(Insn());
|
insn.op_count = disasm[i].detail->mips.op_count;
|
||||||
Insn& insn = insns.back();
|
memcpy(insn.operands, disasm[i].detail->mips.operands, sizeof(insn.operands));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
cs_free(disasm, cur_disasm_size);
|
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, disasm_size);
|
||||||
cs_close(&handle);
|
cs_close(&handle);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -339,7 +340,7 @@ static void link_with_lui(int offset, uint32_t reg, int mem_imm)
|
||||||
#define MAX_LOOKBACK 128
|
#define MAX_LOOKBACK 128
|
||||||
// don't attempt to compute addresses for zero offset
|
// don't attempt to compute addresses for zero offset
|
||||||
// end search after some sane max number of instructions
|
// end search after some sane max number of instructions
|
||||||
int end_search = std::max(0, offset - MAX_LOOKBACK);
|
int end_search = MAX(0, offset - MAX_LOOKBACK);
|
||||||
for (int search = offset - 1; search >= end_search; search--) {
|
for (int search = offset - 1; search >= end_search; search--) {
|
||||||
// use an `if` instead of `case` block to allow breaking out of the `for` loop
|
// use an `if` instead of `case` block to allow breaking out of the `for` loop
|
||||||
if (insns[search].id == MIPS_INS_LUI) {
|
if (insns[search].id == MIPS_INS_LUI) {
|
||||||
|
|
@ -426,7 +427,7 @@ static void link_with_lui(int offset, uint32_t reg, int mem_imm)
|
||||||
static void link_with_jalr(int offset)
|
static void link_with_jalr(int offset)
|
||||||
{
|
{
|
||||||
// end search after some sane max number of instructions
|
// end search after some sane max number of instructions
|
||||||
int end_search = std::max(0, offset - MAX_LOOKBACK);
|
int end_search = MAX(0, offset - MAX_LOOKBACK);
|
||||||
for (int search = offset - 1; search >= end_search; search--) {
|
for (int search = offset - 1; search >= end_search; search--) {
|
||||||
if (insns[search].operands[0].reg == MIPS_REG_T9) {
|
if (insns[search].operands[0].reg == MIPS_REG_T9) {
|
||||||
if (insns[search].id == MIPS_INS_LW || insns[search].id == MIPS_INS_LI) {
|
if (insns[search].id == MIPS_INS_LW || insns[search].id == MIPS_INS_LI) {
|
||||||
|
|
@ -1639,7 +1640,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 : "");
|
printf("++cnt; printf(\"pc=0x%08x%s%s\\n\"); ", text_vaddr + i * 4, symbol_name ? " " : "", symbol_name ? symbol_name : "");
|
||||||
}
|
}
|
||||||
Insn& insn = insns[i];
|
Insn& insn = insns[i];
|
||||||
if (!insn.is_jump && !conservative) {
|
if (!insn.is_jump && !ugen53) {
|
||||||
switch (insn_to_type(insn)) {
|
switch (insn_to_type(insn)) {
|
||||||
case TYPE_1S:
|
case TYPE_1S:
|
||||||
if (!(insn.f_livein & map_reg(insn.operands[0].reg))) {
|
if (!(insn.f_livein & map_reg(insn.operands[0].reg))) {
|
||||||
|
|
@ -2337,16 +2338,16 @@ static void dump_c(void) {
|
||||||
uint32_t max_addr = 0;
|
uint32_t max_addr = 0;
|
||||||
|
|
||||||
if (data_section_len > 0) {
|
if (data_section_len > 0) {
|
||||||
min_addr = std::min(min_addr, data_vaddr);
|
min_addr = MIN(min_addr, data_vaddr);
|
||||||
max_addr = std::max(max_addr, data_vaddr + data_section_len);
|
max_addr = MAX(max_addr, data_vaddr + data_section_len);
|
||||||
}
|
}
|
||||||
if (rodata_section_len > 0) {
|
if (rodata_section_len > 0) {
|
||||||
min_addr = std::min(min_addr, rodata_vaddr);
|
min_addr = MIN(min_addr, rodata_vaddr);
|
||||||
max_addr = std::max(max_addr, rodata_vaddr + rodata_section_len);
|
max_addr = MAX(max_addr, rodata_vaddr + rodata_section_len);
|
||||||
}
|
}
|
||||||
if (bss_section_len) {
|
if (bss_section_len) {
|
||||||
min_addr = std::min(min_addr, bss_vaddr);
|
min_addr = MIN(min_addr, bss_vaddr);
|
||||||
max_addr = std::max(max_addr, bss_vaddr + bss_section_len);
|
max_addr = MAX(max_addr, bss_vaddr + bss_section_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
min_addr = min_addr & ~0xfff;
|
min_addr = min_addr & ~0xfff;
|
||||||
|
|
@ -2357,7 +2358,7 @@ static void dump_c(void) {
|
||||||
stack_bottom -= 16; // for main's stack frame
|
stack_bottom -= 16; // for main's stack frame
|
||||||
|
|
||||||
printf("#include \"header.h\"\n");
|
printf("#include \"header.h\"\n");
|
||||||
if (conservative) {
|
if (ugen53) {
|
||||||
printf("static uint32_t s0, s1, s2, s3, s4, s5, s6, s7, fp;\n");
|
printf("static uint32_t s0, s1, s2, s3, s4, s5, s6, s7, fp;\n");
|
||||||
}
|
}
|
||||||
printf("static const uint32_t rodata[] = {\n");
|
printf("static const uint32_t rodata[] = {\n");
|
||||||
|
|
@ -2485,7 +2486,7 @@ static void dump_c(void) {
|
||||||
dump_function_signature(f, start_addr);
|
dump_function_signature(f, start_addr);
|
||||||
printf(" {\n");
|
printf(" {\n");
|
||||||
printf("const uint32_t zero = 0;\n");
|
printf("const uint32_t zero = 0;\n");
|
||||||
if (!conservative) {
|
if (!ugen53) {
|
||||||
printf("uint32_t at = 0, v1 = 0, t0 = 0, t1 = 0, t2 = 0,\n");
|
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("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");
|
printf("s6 = 0, s7 = 0, t8 = 0, t9 = 0, gp = 0, fp = 0, s8 = 0, ra = 0;\n");
|
||||||
|
|
@ -2910,14 +2911,8 @@ size_t read_file(const char *file_name, uint8_t **data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
const char *filename = argv[1];
|
|
||||||
if (strcmp(filename, "--conservative") == 0) {
|
|
||||||
conservative = true;
|
|
||||||
filename = argv[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
size_t len = read_file(filename, &data);
|
size_t len = read_file(argv[1], &data);
|
||||||
parse_elf(data, len);
|
parse_elf(data, len);
|
||||||
assert(cs_open(CS_ARCH_MIPS, (cs_mode)(CS_MODE_MIPS64 | CS_MODE_BIG_ENDIAN), &handle) == CS_ERR_OK);
|
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);
|
cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
#include "libmio0.h"
|
#include "libmio0.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
// defines
|
// defines
|
||||||
|
|
||||||
#define MIO0_VERSION "0.1"
|
#define MIO0_VERSION "0.1"
|
||||||
|
|
@ -271,6 +270,7 @@ int mio0_encode(const unsigned char *in, unsigned int length, unsigned char *out
|
||||||
// compute final sizes and offsets
|
// compute final sizes and offsets
|
||||||
// +7 so int division accounts for all bits
|
// +7 so int division accounts for all bits
|
||||||
bit_length = ((bit_idx + 7) / 8);
|
bit_length = ((bit_idx + 7) / 8);
|
||||||
|
|
||||||
// compressed data after control bits and aligned to 4-byte boundary
|
// compressed data after control bits and aligned to 4-byte boundary
|
||||||
comp_offset = ALIGN(MIO0_HEADER_LENGTH + bit_length, 4);
|
comp_offset = ALIGN(MIO0_HEADER_LENGTH + bit_length, 4);
|
||||||
uncomp_offset = comp_offset + comp_idx;
|
uncomp_offset = comp_offset + comp_idx;
|
||||||
|
|
@ -282,7 +282,10 @@ int mio0_encode(const unsigned char *in, unsigned int length, unsigned char *out
|
||||||
write_u32_be(&out[8], comp_offset);
|
write_u32_be(&out[8], comp_offset);
|
||||||
write_u32_be(&out[12], uncomp_offset);
|
write_u32_be(&out[12], uncomp_offset);
|
||||||
// output data
|
// output data
|
||||||
|
memset(&out[MIO0_HEADER_LENGTH], 0, MIO0_HEADER_LENGTH + bit_length);
|
||||||
memcpy(&out[MIO0_HEADER_LENGTH], bit_buf, bit_length);
|
memcpy(&out[MIO0_HEADER_LENGTH], bit_buf, bit_length);
|
||||||
|
|
||||||
|
//print_hex(bit_buf, bit_length);
|
||||||
memcpy(&out[comp_offset], comp_buf, comp_idx);
|
memcpy(&out[comp_offset], comp_buf, comp_idx);
|
||||||
memcpy(&out[uncomp_offset], uncomp_buf, uncomp_idx);
|
memcpy(&out[uncomp_offset], uncomp_buf, uncomp_idx);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@
|
||||||
|
|
||||||
#include "libtkmk00.h"
|
#include "libtkmk00.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#include <io.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TKMK00_VERSION "0.1"
|
#define TKMK00_VERSION "0.1"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -238,6 +238,7 @@ int ia2raw(uint8_t *raw, const ia *img, int width, int height, int depth)
|
||||||
{
|
{
|
||||||
int size = (width * height * depth + 7) / 8;
|
int size = (width * height * depth + 7) / 8;
|
||||||
INFO("Converting IA%d %dx%d to raw\n", depth, width, height);
|
INFO("Converting IA%d %dx%d to raw\n", depth, width, height);
|
||||||
|
memset(raw, 0, size);
|
||||||
|
|
||||||
switch (depth) {
|
switch (depth) {
|
||||||
case 16:
|
case 16:
|
||||||
|
|
@ -290,6 +291,7 @@ int i2raw(uint8_t *raw, const ia *img, int width, int height, int depth)
|
||||||
{
|
{
|
||||||
int size = (width * height * depth + 7) / 8;
|
int size = (width * height * depth + 7) / 8;
|
||||||
INFO("Converting I%d %dx%d to raw\n", depth, width, height);
|
INFO("Converting I%d %dx%d to raw\n", depth, width, height);
|
||||||
|
memset(raw, 0, size);
|
||||||
|
|
||||||
switch (depth) {
|
switch (depth) {
|
||||||
case 8:
|
case 8:
|
||||||
|
|
@ -849,11 +851,11 @@ int main(int argc, char *argv[])
|
||||||
if (config.mode == MODE_IMPORT) {
|
if (config.mode == MODE_IMPORT) {
|
||||||
if (0 == strcmp("-", config.bin_filename)) {
|
if (0 == strcmp("-", config.bin_filename)) {
|
||||||
bin_fp = stdout;
|
bin_fp = stdout;
|
||||||
} else {
|
} else {
|
||||||
if (config.bin_truncate) {
|
if (config.bin_truncate) {
|
||||||
bin_fp = fopen(config.bin_filename, "w");
|
bin_fp = fopen(config.bin_filename, "wb");
|
||||||
} else {
|
} else {
|
||||||
bin_fp = fopen(config.bin_filename, "r+");
|
bin_fp = fopen(config.bin_filename, "r+b");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!bin_fp) {
|
if (!bin_fp) {
|
||||||
|
|
@ -904,9 +906,9 @@ int main(int argc, char *argv[])
|
||||||
int pal_length;
|
int pal_length;
|
||||||
|
|
||||||
if (config.pal_truncate) {
|
if (config.pal_truncate) {
|
||||||
pal_fp = fopen(config.pal_filename, "w");
|
pal_fp = fopen(config.pal_filename, "wb");
|
||||||
} else {
|
} else {
|
||||||
pal_fp = fopen(config.pal_filename, "r+");
|
pal_fp = fopen(config.pal_filename, "r+b");
|
||||||
}
|
}
|
||||||
if (!pal_fp) {
|
if (!pal_fp) {
|
||||||
ERROR("Error opening \"%s\"\n", config.pal_filename);
|
ERROR("Error opening \"%s\"\n", config.pal_filename);
|
||||||
|
|
@ -988,7 +990,7 @@ int main(int argc, char *argv[])
|
||||||
ERROR("Error: must set position width and height for export\n");
|
ERROR("Error: must set position width and height for export\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
bin_fp = fopen(config.bin_filename, "r");
|
bin_fp = fopen(config.bin_filename, "rb");
|
||||||
if (!bin_fp) {
|
if (!bin_fp) {
|
||||||
ERROR("Error opening \"%s\"\n", config.bin_filename);
|
ERROR("Error opening \"%s\"\n", config.bin_filename);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -1025,7 +1027,7 @@ int main(int argc, char *argv[])
|
||||||
INFO("Extracting %s offset 0x%X, pal.offset 0x%0X, pal.format %s\n", format2str(&config.format),
|
INFO("Extracting %s offset 0x%X, pal.offset 0x%0X, pal.format %s\n", format2str(&config.format),
|
||||||
config.bin_offset, config.pal_offset, format2str(&config.pal_format));
|
config.bin_offset, config.pal_offset, format2str(&config.pal_format));
|
||||||
|
|
||||||
pal_fp = fopen(config.pal_filename, "r");
|
pal_fp = fopen(config.pal_filename, "rb");
|
||||||
if (!pal_fp) {
|
if (!pal_fp) {
|
||||||
ERROR("Error opening \"%s\"\n", config.bin_filename);
|
ERROR("Error opening \"%s\"\n", config.bin_filename);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
|
||||||
|
|
@ -61,24 +61,48 @@ int fprint_write_output(FILE *fp, write_encoding encoding, const uint8_t *raw, i
|
||||||
int flength = 0;
|
int flength = 0;
|
||||||
const encoding_format *fmt = &enc_fmt[encoding];
|
const encoding_format *fmt = &enc_fmt[encoding];
|
||||||
switch (encoding) {
|
switch (encoding) {
|
||||||
case ENCODING_RAW:
|
case ENCODING_RAW:
|
||||||
flength = fwrite(raw, 1, length, fp);
|
flength = fwrite(raw, 1, length, fp);
|
||||||
break;
|
break;
|
||||||
case ENCODING_U8:
|
case ENCODING_U8:
|
||||||
case ENCODING_U16:
|
case ENCODING_U16:
|
||||||
case ENCODING_U32:
|
case ENCODING_U32:
|
||||||
case ENCODING_U64:
|
case ENCODING_U64:
|
||||||
for (int w = 0; w < length; w += fmt->bytes_per_val) {
|
for (int w = 0; w < length; w += fmt->bytes_per_val) {
|
||||||
flength += fprintf(fp, "0x");
|
flength += fprintf(fp, "0x");
|
||||||
for (int b = 0; b < fmt->bytes_per_val; b++) {
|
for (int b = 0; b < fmt->bytes_per_val; b++) {
|
||||||
int off = w + b;
|
int off = w + b;
|
||||||
flength += fprintf(fp, "%02x", off < length ? raw[off] : 0x00);
|
flength += fprintf(fp, "%02x", off < length ? raw[off] : 0x00);
|
||||||
}
|
}
|
||||||
flength += fprintf(fp, "%s%c", fmt->suffix, (w < length - fmt->bytes_per_val) ? ',' : '\n');
|
flength += fprintf(fp, "%s%c", fmt->suffix, (w < length - fmt->bytes_per_val) ? ',' : '\n');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
return flength;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fprint_hex(FILE *fp, const unsigned char *buf, int length)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
fprint_byte(fp, buf[i]);
|
||||||
|
fputc(' ', fp);
|
||||||
}
|
}
|
||||||
return flength;
|
}
|
||||||
|
|
||||||
|
void fprint_hex_source(FILE *fp, const unsigned char *buf, int length)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
if (i > 0) fputs(", ", fp);
|
||||||
|
fputs("0x", fp);
|
||||||
|
fprint_byte(fp, buf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_hex(const unsigned char *buf, int length)
|
||||||
|
{
|
||||||
|
fprint_hex(stdout, buf, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap_bytes(unsigned char *data, long length)
|
void swap_bytes(unsigned char *data, long length)
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,15 @@
|
||||||
(buf)[1] = ((val)) & 0xFF; \
|
(buf)[1] = ((val)) & 0xFF; \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
// print nibbles and bytes
|
||||||
|
#define fprint_nibble(FP, NIB_) fputc((NIB_) < 10 ? ('0' + (NIB_)) : ('A' + (NIB_) - 0xA), FP)
|
||||||
|
#define fprint_byte(FP, BYTE_) do { \
|
||||||
|
fprint_nibble(FP, (BYTE_) >> 4); \
|
||||||
|
fprint_nibble(FP, (BYTE_) & 0x0F); \
|
||||||
|
} while(0)
|
||||||
|
#define print_nibble(NIB_) fprint_nibble(stdout, NIB_)
|
||||||
|
#define print_byte(BYTE_) fprint_byte(stdout, BYTE_)
|
||||||
|
|
||||||
// Windows compatibility
|
// Windows compatibility
|
||||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
|
|
@ -72,6 +81,7 @@ extern int g_verbosity;
|
||||||
|
|
||||||
#define ERROR(...) fprintf(stderr, __VA_ARGS__)
|
#define ERROR(...) fprintf(stderr, __VA_ARGS__)
|
||||||
#define INFO(...) if (g_verbosity) printf(__VA_ARGS__)
|
#define INFO(...) if (g_verbosity) printf(__VA_ARGS__)
|
||||||
|
#define INFO_HEX(...) if (g_verbosity) print_hex(__VA_ARGS__)
|
||||||
|
|
||||||
// functions
|
// functions
|
||||||
|
|
||||||
|
|
@ -85,12 +95,14 @@ float read_f32_be(unsigned char *buf);
|
||||||
// returns 1 if val is power of 2, 0 otherwise
|
// returns 1 if val is power of 2, 0 otherwise
|
||||||
int is_power2(unsigned int val);
|
int is_power2(unsigned int val);
|
||||||
|
|
||||||
// print buffer as raw binary, hex u8, hex u16, hex u32, hex u64. pads to encoding size
|
// print buffer as hex bytes
|
||||||
// fp: file pointer
|
// fp: file pointer
|
||||||
// encoding: encoding type to use (see write_encoding)
|
|
||||||
// buf: buffer to read bytes from
|
// buf: buffer to read bytes from
|
||||||
// length: length of buffer to print
|
// length: length of buffer to print
|
||||||
int fprint_write_output(FILE *fp, write_encoding encoding, const uint8_t *buf, int length);
|
int fprint_write_output(FILE *fp, write_encoding, const uint8_t *buf, int length);
|
||||||
|
void fprint_hex(FILE *fp, const unsigned char *buf, int length);
|
||||||
|
void fprint_hex_source(FILE *fp, const unsigned char *buf, int length);
|
||||||
|
extern void print_hex(const unsigned char *buf, int length);
|
||||||
|
|
||||||
// perform byteswapping to convert from v64 to z64 ordering
|
// perform byteswapping to convert from v64 to z64 ordering
|
||||||
void swap_bytes(unsigned char *data, long length);
|
void swap_bytes(unsigned char *data, long length);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue