diff --git a/Makefile b/Makefile index faf687a2..84874447 100644 --- a/Makefile +++ b/Makefile @@ -36,11 +36,9 @@ else ifeq ($(CONSOLE),bb) endif # COMPILER - selects the C compiler to use -# ido - uses the SGI IRIS Development Option compiler, which is used to build -# an original matching N64 ROM # gcc - uses the GNU C Compiler COMPILER ?= gcc -$(eval $(call validate-option,COMPILER,ido gcc)) +$(eval $(call validate-option,COMPILER,gcc)) # SAVETYPE - selects the save type @@ -131,24 +129,7 @@ else ifeq ($(GRUCODE),super3d) # Super3D DEFINES += SUPER3D_GBI=1 F3D_NEW=1 endif - -# USE_QEMU_IRIX - when ido is selected, select which way to emulate IRIX programs -# 1 - use qemu-irix -# 0 - statically recompile the IRIX programs -USE_QEMU_IRIX ?= 0 -$(eval $(call validate-option,USE_QEMU_IRIX,0 1)) - -ifeq ($(COMPILER),ido) - ifeq ($(USE_QEMU_IRIX),1) - # Verify that qemu-irix exists - 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 - - MIPSISET := -mips2 -else ifeq ($(COMPILER),gcc) +ifeq ($(COMPILER),gcc) NON_MATCHING := 1 MIPSISET := -mips3 OPT_FLAGS := -O2 @@ -261,7 +242,7 @@ ifeq ($(filter clean distclean print-%,$(MAKECMDGOALS)),) # Make tools if out of date $(info Building tools...) - DUMMY != $(MAKE) -s -C $(TOOLS_DIR) $(if $(filter-out ido0,$(COMPILER)$(USE_QEMU_IRIX)),all-except-recomp,) >&2 || echo FAIL + DUMMY != $(MAKE) -s -C $(TOOLS_DIR) >&2 || echo FAIL ifeq ($(DUMMY),FAIL) $(error Failed to build tools) endif @@ -327,18 +308,6 @@ LIBZ_O_FILES := $(foreach file,$(LIBZ_C_FILES),$(BUILD_DIR)/$(file:.c=.o)) # Automatic dependency files DEP_FILES := $(O_FILES:.o=.d) $(LIBZ_O_FILES:.o=.d) $(BUILD_DIR)/$(LD_SCRIPT).d -# Files with GLOBAL_ASM blocks -ifeq ($(NON_MATCHING),0) - ifeq ($(VERSION),sh) - GLOBAL_ASM_C_FILES != grep -rl 'GLOBAL_ASM(' $(wildcard src/**/*.c) $(wildcard lib/src/*.c) - else - GLOBAL_ASM_C_FILES != grep -rl 'GLOBAL_ASM(' $(wildcard src/**/*.c) - endif -GLOBAL_ASM_O_FILES = $(foreach file,$(GLOBAL_ASM_C_FILES),$(BUILD_DIR)/$(file:.c=.o)) -GLOBAL_ASM_DEP = $(BUILD_DIR)/src/audio/non_matching_dep -endif - - #==============================================================================# # Compiler Options # #==============================================================================# @@ -361,18 +330,6 @@ export LD_LIBRARY_PATH=./tools AS := $(CROSS)as ifeq ($(COMPILER),gcc) CC := $(CROSS)gcc -else - ifeq ($(USE_QEMU_IRIX),1) - IRIX_ROOT := $(TOOLS_DIR)/ido5.3_compiler - CC := $(QEMU_IRIX) -silent -L $(IRIX_ROOT) $(IRIX_ROOT)/usr/bin/cc - ACPP := $(QEMU_IRIX) -silent -L $(IRIX_ROOT) $(IRIX_ROOT)/usr/lib/acpp - COPT := $(QEMU_IRIX) -silent -L $(IRIX_ROOT) $(IRIX_ROOT)/usr/lib/copt - else - IDO_ROOT := $(TOOLS_DIR)/ido5.3_recomp - CC := $(IDO_ROOT)/cc - ACPP := $(IDO_ROOT)/acpp - COPT := $(IDO_ROOT)/copt - endif endif # Prefer gcc's cpp if installed on the system ifneq (,$(call find-command,cpp-10)) @@ -402,10 +359,6 @@ endif C_DEFINES := $(foreach d,$(DEFINES),-D$(d)) DEF_INC_CFLAGS := $(foreach i,$(INCLUDE_DIRS),-I$(i)) $(C_DEFINES) -# Check code syntax with host compiler -CC_CHECK := gcc -CC_CHECK_CFLAGS := -fsyntax-only -fsigned-char $(CC_CFLAGS) $(TARGET_CFLAGS) -std=gnu90 -Wall -Wextra -Wno-format-security -Wno-main -DNON_MATCHING -DAVOID_UB $(DEF_INC_CFLAGS) - # C compiler options CFLAGS = -G 0 $(OPT_FLAGS) $(TARGET_CFLAGS) $(MIPSISET) $(DEF_INC_CFLAGS) ifeq ($(COMPILER),gcc) @@ -420,17 +373,6 @@ RSPASMFLAGS := $(foreach d,$(DEFINES),-definelabel $(subst =, ,$(d))) # C preprocessor flags CPPFLAGS := -P -Wno-trigraphs $(DEF_INC_CFLAGS) -ifeq ($(shell getconf LONG_BIT), 32) - # Work around memory allocation bug in QEMU - export QEMU_GUEST_BASE := 1 -else - # Ensure that gcc treats the code as 32-bit - CC_CHECK_CFLAGS += -m32 -endif - -# Prevent a crash with -sopt -export LANG := C - #==============================================================================# # Miscellaneous Tools # #==============================================================================# @@ -439,7 +381,6 @@ export LANG := C YAY0TOOL := $(TOOLS_DIR)/slienc RNCPACK := $(TOOLS_DIR)/rncpack ROMALIGN := $(TOOLS_DIR)/romalign -BFSIZE := $(TOOLS_DIR)/bfsize FILESIZER := $(TOOLS_DIR)/filesizer N64CKSUM := $(TOOLS_DIR)/n64cksum N64GRAPHICS := $(TOOLS_DIR)/n64graphics @@ -714,17 +655,6 @@ $(BUILD_DIR)/include/level_headers.h: levels/level_headers.h.in $(call print,Preprocessing level headers:,$<,$@) $(V)$(CPP) $(CPPFLAGS) -I . levels/level_headers.h.in | $(PYTHON) $(TOOLS_DIR)/output_level_headers.py > $(BUILD_DIR)/include/level_headers.h -# Run asm_processor on files that have NON_MATCHING code -ifeq ($(NON_MATCHING),0) -$(GLOBAL_ASM_O_FILES): CC := $(V)$(PYTHON) $(TOOLS_DIR)/asm_processor/build.py $(CC) -- $(AS) $(ASFLAGS) -- -endif - -# Rebuild files with 'GLOBAL_ASM' if the NON_MATCHING flag changes. -$(GLOBAL_ASM_O_FILES): $(GLOBAL_ASM_DEP).$(NON_MATCHING) -$(GLOBAL_ASM_DEP).$(NON_MATCHING): - @$(RM) $(GLOBAL_ASM_DEP).* - $(V)touch $@ - # Generate version_data.h $(BUILD_DIR)/src/game/version_data.h: tools/make_version.sh @$(PRINT) "$(GREEN)Generating: $(BLUE)$@ $(NO_COL)\n" @@ -737,70 +667,15 @@ $(BUILD_DIR)/src/game/version_data.h: tools/make_version.sh # Compile C code $(BUILD_DIR)/%.o: %.c $(call print,Compiling:,$<,$@) -ifeq ($(COMPILER),ido) - @$(CC_CHECK) $(CC_CHECK_CFLAGS) -MMD -MP -MT $@ -MF $(BUILD_DIR)/$*.d $< - $(V)$(CC) -c $(CFLAGS) -o $@ $< -else $(V)$(CC) -c $(CFLAGS) -MMD -MF $(BUILD_DIR)/$*.d -o $@ $< -endif $(BUILD_DIR)/%.o: $(BUILD_DIR)/%.c $(call print,Compiling:,$<,$@) -ifeq ($(COMPILER),ido) - @$(CC_CHECK) $(CC_CHECK_CFLAGS) -MMD -MP -MT $@ -MF $(BUILD_DIR)/$*.d $< - $(V)$(CC) -c $(CFLAGS) -o $@ $< -else $(V)$(CC) -c $(CFLAGS) -MMD -MF $(BUILD_DIR)/$*.d -o $@ $< -endif - -# Alternate compiler flags needed for matching -ifeq ($(COMPILER),ido) - $(BUILD_DIR)/levels/%/leveldata.o: OPT_FLAGS := -g - $(BUILD_DIR)/actors/%.o: OPT_FLAGS := -g - $(BUILD_DIR)/bin/%.o: OPT_FLAGS := -g - ifeq ($(VERSION),eu) - $(BUILD_DIR)/lib/src/_Litob.o: OPT_FLAGS := -O3 - $(BUILD_DIR)/lib/src/_Ldtob.o: OPT_FLAGS := -O3 - $(BUILD_DIR)/lib/src/_Printf.o: OPT_FLAGS := -O3 - $(BUILD_DIR)/lib/src/sprintf.o: OPT_FLAGS := -O3 - - # Enable loop unrolling except for external.c (external.c might also have used - # unrolling, but it makes one loop harder to match). - # For all audio files other than external.c and port_eu.c, put string literals - # in .data. (In Shindou, the port_eu.c string literals also moved to .data.) - $(BUILD_DIR)/src/audio/%.o: OPT_FLAGS := -O2 -use_readwrite_const - $(BUILD_DIR)/src/audio/port_eu.o: OPT_FLAGS := -O2 - $(BUILD_DIR)/src/audio/external.o: OPT_FLAGS := -O2 -Wo,-loopunroll,0 - endif - ifeq ($(VERSION_JP_US),true) - $(BUILD_DIR)/src/audio/%.o: OPT_FLAGS := -O2 -Wo,-loopunroll,0 - $(BUILD_DIR)/src/audio/load.o: OPT_FLAGS := -O2 -framepointer -Wo,-loopunroll,0 - endif - ifeq ($(VERSION_JP_US),true) - # The source-to-source optimizer copt is enabled for audio. This makes it use - # acpp, which needs -Wp,-+ to handle C++-style comments. - # All other files than external.c should really use copt, but only a few have - # been matched so far. - $(BUILD_DIR)/src/audio/effects.o: OPT_FLAGS := -O2 -Wo,-loopunroll,0 -sopt,-inline=sequence_channel_process_sound,-scalaroptimize=1 -Wp,-+ - $(BUILD_DIR)/src/audio/synthesis.o: OPT_FLAGS := -O2 -sopt,-scalaroptimize=1 -Wp,-+ - endif - -# Add a target for build/eu/src/audio/*.copt to make it easier to see debug -$(BUILD_DIR)/src/audio/%.acpp: src/audio/%.c - $(ACPP) $(TARGET_CFLAGS) $(DEF_INC_CFLAGS) -D__sgi -+ $< > $@ -$(BUILD_DIR)/src/audio/%.copt: $(BUILD_DIR)/src/audio/%.acpp - $(COPT) -signed -I=$< -CMP=$@ -cp=i -scalaroptimize=1 $(COPTFLAGS) -$(BUILD_DIR)/src/audio/seqplayer.copt: COPTFLAGS := -inline_manual - -endif # Assemble assembly code $(BUILD_DIR)/%.o: %.s $(call print,Assembling:,$<,$@) -ifeq ($(COMPILER),ido) - $(V)$(CPP) $(CPPFLAGS) $< | $(AS) $(ASFLAGS) -MD $(BUILD_DIR)/$*.d -o $@ -else $(V)$(CC) -c $(CFLAGS) $(foreach i,$(INCLUDE_DIRS),-Wa,-I$(i)) -x assembler-with-cpp -MMD -MF $(BUILD_DIR)/$*.d -o $@ $< -endif $(BUILD_DIR)/sound/sequences/00_sound_player.o: sound/sequences/00_sound_player.s $(call print,Assembling:,$<,$@) diff --git a/tools/.gitignore b/tools/.gitignore index 9dddd0ca..288321f4 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -1,7 +1,6 @@ /aifc_decode /aiff_extract_codebook /armips -/bfsize /extract_data_for_mio /filesizer /mio0 diff --git a/tools/Makefile b/tools/Makefile index 33b8bd71..af5c5a2b 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -7,7 +7,7 @@ CC := gcc CXX := g++ CFLAGS := -I . -Wall -Wextra -Wno-unused-parameter -pedantic -O2 -s LDFLAGS := -lm -ALL_PROGRAMS := armips bfsize filesizer rncpack n64graphics n64graphics_ci mio0 slienc n64cksum textconv patch_libultra_math aifc_decode aiff_extract_codebook vadpcm_enc tabledesign extract_data_for_mio skyconv +ALL_PROGRAMS := armips filesizer rncpack n64graphics n64graphics_ci mio0 slienc n64cksum textconv patch_libultra_math aifc_decode aiff_extract_codebook vadpcm_enc tabledesign extract_data_for_mio skyconv LIBAUDIOFILE := audiofile/libaudiofile.a # Only build armips from tools if it is not found on the system @@ -19,8 +19,6 @@ endif default: all -bfsize_SOURCES := bfsize.c - filesizer_SOURCES := filesizer.c rncpack_SOURCES := rncpack.c @@ -69,24 +67,20 @@ endif all-except-recomp: $(LIBAUDIOFILE) $(BUILD_PROGRAMS) -all: all-except-recomp ido5.3_recomp +all: all-except-recomp clean: $(RM) $(ALL_PROGRAMS) $(MAKE) -C audiofile clean - $(MAKE) -C ido5.3_recomp clean define COMPILE $(1): $($1_SOURCES) $$(CC) $(CFLAGS) $($1_CFLAGS) $$^ -o $$@ $($1_LDFLAGS) $(LDFLAGS) endef -ido5.3_recomp: - $(MAKE) -C ido5.3_recomp - $(foreach p,$(BUILD_PROGRAMS),$(eval $(call COMPILE,$(p)))) $(LIBAUDIOFILE): @$(MAKE) -C audiofile -.PHONY: all all-except-recomp clean default ido5.3_recomp +.PHONY: all all-except-recomp clean default diff --git a/tools/asm_processor/asm-processor.py b/tools/asm_processor/asm-processor.py deleted file mode 100644 index ea18c384..00000000 --- a/tools/asm_processor/asm-processor.py +++ /dev/null @@ -1,1150 +0,0 @@ -#!/usr/bin/env python3 -import argparse -import tempfile -import struct -import copy -import sys -import re -import os -from collections import namedtuple -from io import StringIO - -MAX_FN_SIZE = 100 -SLOW_CHECKS = False - -EI_NIDENT = 16 -EI_CLASS = 4 -EI_DATA = 5 -EI_VERSION = 6 -EI_OSABI = 7 -EI_ABIVERSION = 8 -STN_UNDEF = 0 - -SHN_UNDEF = 0 -SHN_ABS = 0xfff1 -SHN_COMMON = 0xfff2 -SHN_XINDEX = 0xffff -SHN_LORESERVE = 0xff00 - -STT_NOTYPE = 0 -STT_OBJECT = 1 -STT_FUNC = 2 -STT_SECTION = 3 -STT_FILE = 4 -STT_COMMON = 5 -STT_TLS = 6 - -STB_LOCAL = 0 -STB_GLOBAL = 1 -STB_WEAK = 2 - -STV_DEFAULT = 0 -STV_INTERNAL = 1 -STV_HIDDEN = 2 -STV_PROTECTED = 3 - -SHT_NULL = 0 -SHT_PROGBITS = 1 -SHT_SYMTAB = 2 -SHT_STRTAB = 3 -SHT_RELA = 4 -SHT_HASH = 5 -SHT_DYNAMIC = 6 -SHT_NOTE = 7 -SHT_NOBITS = 8 -SHT_REL = 9 -SHT_SHLIB = 10 -SHT_DYNSYM = 11 -SHT_INIT_ARRAY = 14 -SHT_FINI_ARRAY = 15 -SHT_PREINIT_ARRAY = 16 -SHT_GROUP = 17 -SHT_SYMTAB_SHNDX = 18 -SHT_MIPS_GPTAB = 0x70000003 -SHT_MIPS_DEBUG = 0x70000005 -SHT_MIPS_REGINFO = 0x70000006 -SHT_MIPS_OPTIONS = 0x7000000d - -SHF_WRITE = 0x1 -SHF_ALLOC = 0x2 -SHF_EXECINSTR = 0x4 -SHF_MERGE = 0x10 -SHF_STRINGS = 0x20 -SHF_INFO_LINK = 0x40 -SHF_LINK_ORDER = 0x80 -SHF_OS_NONCONFORMING = 0x100 -SHF_GROUP = 0x200 -SHF_TLS = 0x400 - -R_MIPS_32 = 2 -R_MIPS_26 = 4 -R_MIPS_HI16 = 5 -R_MIPS_LO16 = 6 - - -class ElfHeader: - """ - typedef struct { - unsigned char e_ident[EI_NIDENT]; - Elf32_Half e_type; - Elf32_Half e_machine; - Elf32_Word e_version; - Elf32_Addr e_entry; - Elf32_Off e_phoff; - Elf32_Off e_shoff; - Elf32_Word e_flags; - Elf32_Half e_ehsize; - Elf32_Half e_phentsize; - Elf32_Half e_phnum; - Elf32_Half e_shentsize; - Elf32_Half e_shnum; - Elf32_Half e_shstrndx; - } Elf32_Ehdr; - """ - - def __init__(self, data): - self.e_ident = data[:EI_NIDENT] - self.e_type, self.e_machine, self.e_version, self.e_entry, self.e_phoff, self.e_shoff, self.e_flags, self.e_ehsize, self.e_phentsize, self.e_phnum, self.e_shentsize, self.e_shnum, self.e_shstrndx = struct.unpack('>HHIIIIIHHHHHH', data[EI_NIDENT:]) - assert self.e_ident[EI_CLASS] == 1 # 32-bit - assert self.e_ident[EI_DATA] == 2 # big-endian - assert self.e_type == 1 # relocatable - assert self.e_machine == 8 # MIPS I Architecture - assert self.e_phoff == 0 # no program header - assert self.e_shoff != 0 # section header - assert self.e_shstrndx != SHN_UNDEF - - def to_bin(self): - return self.e_ident + struct.pack('>HHIIIIIHHHHHH', self.e_type, - self.e_machine, self.e_version, self.e_entry, self.e_phoff, - self.e_shoff, self.e_flags, self.e_ehsize, self.e_phentsize, - self.e_phnum, self.e_shentsize, self.e_shnum, self.e_shstrndx) - - -class Symbol: - """ - typedef struct { - Elf32_Word st_name; - Elf32_Addr st_value; - Elf32_Word st_size; - unsigned char st_info; - unsigned char st_other; - Elf32_Half st_shndx; - } Elf32_Sym; - """ - - def __init__(self, data, strtab): - self.st_name, self.st_value, self.st_size, st_info, self.st_other, self.st_shndx = struct.unpack('>IIIBBH', data) - assert self.st_shndx != SHN_XINDEX, "too many sections (SHN_XINDEX not supported)" - self.bind = st_info >> 4 - self.type = st_info & 15 - self.name = strtab.lookup_str(self.st_name) - self.visibility = self.st_other & 3 - - def to_bin(self): - st_info = (self.bind << 4) | self.type - return struct.pack('>IIIBBH', self.st_name, self.st_value, self.st_size, st_info, self.st_other, self.st_shndx) - - -class Relocation: - def __init__(self, data, sh_type): - self.sh_type = sh_type - if sh_type == SHT_REL: - self.r_offset, self.r_info = struct.unpack('>II', data) - else: - self.r_offset, self.r_info, self.r_addend = struct.unpack('>III', data) - self.sym_index = self.r_info >> 8 - self.rel_type = self.r_info & 0xff - - def to_bin(self): - self.r_info = (self.sym_index << 8) | self.rel_type - if self.sh_type == SHT_REL: - return struct.pack('>II', self.r_offset, self.r_info) - else: - return struct.pack('>III', self.r_offset, self.r_info, self.r_addend) - - -class Section: - """ - typedef struct { - Elf32_Word sh_name; - Elf32_Word sh_type; - Elf32_Word sh_flags; - Elf32_Addr sh_addr; - Elf32_Off sh_offset; - Elf32_Word sh_size; - Elf32_Word sh_link; - Elf32_Word sh_info; - Elf32_Word sh_addralign; - Elf32_Word sh_entsize; - } Elf32_Shdr; - """ - - def __init__(self, header, data, index): - self.sh_name, self.sh_type, self.sh_flags, self.sh_addr, self.sh_offset, self.sh_size, self.sh_link, self.sh_info, self.sh_addralign, self.sh_entsize = struct.unpack('>IIIIIIIIII', header) - assert not self.sh_flags & SHF_LINK_ORDER - if self.sh_entsize != 0: - assert self.sh_size % self.sh_entsize == 0 - if self.sh_type == SHT_NOBITS: - self.data = b'' - else: - self.data = data[self.sh_offset:self.sh_offset + self.sh_size] - self.index = index - self.relocated_by = [] - - @staticmethod - def from_parts(sh_name, sh_type, sh_flags, sh_link, sh_info, sh_addralign, sh_entsize, data, index): - header = struct.pack('>IIIIIIIIII', sh_name, sh_type, sh_flags, 0, 0, len(data), sh_link, sh_info, sh_addralign, sh_entsize) - return Section(header, data, index) - - def lookup_str(self, index): - assert self.sh_type == SHT_STRTAB - to = self.data.find(b'\0', index) - assert to != -1 - return self.data[index:to].decode('latin1') - - def add_str(self, string): - assert self.sh_type == SHT_STRTAB - ret = len(self.data) - self.data += string.encode('latin1') + b'\0' - return ret - - def is_rel(self): - return self.sh_type == SHT_REL or self.sh_type == SHT_RELA - - def header_to_bin(self): - if self.sh_type != SHT_NOBITS: - self.sh_size = len(self.data) - return struct.pack('>IIIIIIIIII', self.sh_name, self.sh_type, self.sh_flags, self.sh_addr, self.sh_offset, self.sh_size, self.sh_link, self.sh_info, self.sh_addralign, self.sh_entsize) - - def late_init(self, sections): - if self.sh_type == SHT_SYMTAB: - self.init_symbols(sections) - elif self.is_rel(): - self.rel_target = sections[self.sh_info] - self.rel_target.relocated_by.append(self) - self.init_relocs() - - def find_symbol(self, name): - assert self.sh_type == SHT_SYMTAB - for s in self.symbol_entries: - if s.name == name: - return (s.st_shndx, s.st_value) - return None - - def find_symbol_in_section(self, name, section): - pos = self.find_symbol(name) - assert pos is not None - assert pos[0] == section.index - return pos[1] - - def init_symbols(self, sections): - assert self.sh_type == SHT_SYMTAB - assert self.sh_entsize == 16 - self.strtab = sections[self.sh_link] - entries = [] - for i in range(0, self.sh_size, self.sh_entsize): - entries.append(Symbol(self.data[i:i+self.sh_entsize], self.strtab)) - self.symbol_entries = entries - - def init_relocs(self): - assert self.is_rel() - entries = [] - for i in range(0, self.sh_size, self.sh_entsize): - entries.append(Relocation(self.data[i:i+self.sh_entsize], self.sh_type)) - self.relocations = entries - - def local_symbols(self): - assert self.sh_type == SHT_SYMTAB - return self.symbol_entries[:self.sh_info] - - def global_symbols(self): - assert self.sh_type == SHT_SYMTAB - return self.symbol_entries[self.sh_info:] - - -class ElfFile: - def __init__(self, data): - self.data = data - assert data[:4] == b'\x7fELF', "not an ELF file" - - self.elf_header = ElfHeader(data[0:52]) - - offset, size = self.elf_header.e_shoff, self.elf_header.e_shentsize - null_section = Section(data[offset:offset + size], data, 0) - num_sections = self.elf_header.e_shnum or null_section.sh_size - - self.sections = [null_section] - for i in range(1, num_sections): - ind = offset + i * size - self.sections.append(Section(data[ind:ind + size], data, i)) - - symtab = None - for s in self.sections: - if s.sh_type == SHT_SYMTAB: - assert not symtab - symtab = s - assert symtab is not None - self.symtab = symtab - - shstr = self.sections[self.elf_header.e_shstrndx] - for s in self.sections: - s.name = shstr.lookup_str(s.sh_name) - s.late_init(self.sections) - - def find_section(self, name): - for s in self.sections: - if s.name == name: - return s - return None - - def add_section(self, name, sh_type, sh_flags, sh_link, sh_info, sh_addralign, sh_entsize, data): - shstr = self.sections[self.elf_header.e_shstrndx] - sh_name = shstr.add_str(name) - s = Section.from_parts(sh_name=sh_name, sh_type=sh_type, - sh_flags=sh_flags, sh_link=sh_link, sh_info=sh_info, - sh_addralign=sh_addralign, sh_entsize=sh_entsize, data=data, - index=len(self.sections)) - self.sections.append(s) - s.name = name - s.late_init(self.sections) - return s - - def drop_irrelevant_sections(self): - # We can only drop sections at the end, since otherwise section - # references might be wrong. Luckily, these sections typically are. - while self.sections[-1].sh_type in [SHT_MIPS_DEBUG, SHT_MIPS_GPTAB]: - self.sections.pop() - - def write(self, filename): - outfile = open(filename, 'wb') - outidx = 0 - def write_out(data): - nonlocal outidx - outfile.write(data) - outidx += len(data) - def pad_out(align): - if align and outidx % align: - write_out(b'\0' * (align - outidx % align)) - - self.elf_header.e_shnum = len(self.sections) - write_out(self.elf_header.to_bin()) - - for s in self.sections: - if s.sh_type != SHT_NOBITS and s.sh_type != SHT_NULL: - pad_out(s.sh_addralign) - s.sh_offset = outidx - write_out(s.data) - - pad_out(4) - self.elf_header.e_shoff = outidx - for s in self.sections: - write_out(s.header_to_bin()) - - outfile.seek(0) - outfile.write(self.elf_header.to_bin()) - outfile.close() - - -def is_temp_name(name): - return name.startswith('_asmpp_') - - -# https://stackoverflow.com/a/241506 -def re_comment_replacer(match): - s = match.group(0) - if s[0] in "/#": - return " " - else: - return s - - -re_comment_or_string = re.compile( - r'#.*|/\*.*?\*/|"(?:\\.|[^\\"])*"' -) - - -class Failure(Exception): - def __init__(self, message): - self.message = message - - def __str__(self): - return self.message - - -class GlobalState: - def __init__(self, min_instr_count, skip_instr_count, use_jtbl_for_rodata): - # A value that hopefully never appears as a 32-bit rodata constant (or we - # miscompile late rodata). Increases by 1 in each step. - self.late_rodata_hex = 0xE0123456 - self.namectr = 0 - self.min_instr_count = min_instr_count - self.skip_instr_count = skip_instr_count - self.use_jtbl_for_rodata = use_jtbl_for_rodata - - def next_late_rodata_hex(self): - dummy_bytes = struct.pack('>I', self.late_rodata_hex) - if (self.late_rodata_hex & 0xffff) == 0: - # Avoid lui - self.late_rodata_hex += 1 - self.late_rodata_hex += 1 - return dummy_bytes - - def make_name(self, cat): - self.namectr += 1 - return '_asmpp_{}{}'.format(cat, self.namectr) - - -Function = namedtuple('Function', ['text_glabels', 'asm_conts', 'late_rodata_dummy_bytes', 'jtbl_rodata_size', 'late_rodata_asm_conts', 'fn_desc', 'data']) - - -class GlobalAsmBlock: - def __init__(self, fn_desc): - self.fn_desc = fn_desc - self.cur_section = '.text' - self.asm_conts = [] - self.late_rodata_asm_conts = [] - self.late_rodata_alignment = 0 - self.late_rodata_alignment_from_content = False - self.text_glabels = [] - self.fn_section_sizes = { - '.text': 0, - '.data': 0, - '.bss': 0, - '.rodata': 0, - '.late_rodata': 0, - } - self.fn_ins_inds = [] - self.glued_line = '' - self.num_lines = 0 - - def fail(self, message, line=None): - context = self.fn_desc - if line: - context += ", at line \"" + line + "\"" - raise Failure(message + "\nwithin " + context) - - def count_quoted_size(self, line, z, real_line, output_enc): - line = line.encode(output_enc).decode('latin1') - in_quote = False - num_parts = 0 - ret = 0 - i = 0 - digits = "0123456789" # 0-7 would be more sane, but this matches GNU as - while i < len(line): - c = line[i] - i += 1 - if not in_quote: - if c == '"': - in_quote = True - num_parts += 1 - else: - if c == '"': - in_quote = False - continue - ret += 1 - if c != '\\': - continue - if i == len(line): - self.fail("backslash at end of line not supported", real_line) - c = line[i] - i += 1 - # (if c is in "bfnrtv", we have a real escaped literal) - if c == 'x': - # hex literal, consume any number of hex chars, possibly none - while i < len(line) and line[i] in digits + "abcdefABCDEF": - i += 1 - elif c in digits: - # octal literal, consume up to two more digits - it = 0 - while i < len(line) and line[i] in digits and it < 2: - i += 1 - it += 1 - - if in_quote: - self.fail("unterminated string literal", real_line) - if num_parts == 0: - self.fail(".ascii with no string", real_line) - return ret + num_parts if z else ret - - def align2(self): - while self.fn_section_sizes[self.cur_section] % 2 != 0: - self.fn_section_sizes[self.cur_section] += 1 - - def align4(self): - while self.fn_section_sizes[self.cur_section] % 4 != 0: - self.fn_section_sizes[self.cur_section] += 1 - - def add_sized(self, size, line): - if self.cur_section in ['.text', '.late_rodata']: - if size % 4 != 0: - self.fail("size must be a multiple of 4", line) - if size < 0: - self.fail("size cannot be negative", line) - self.fn_section_sizes[self.cur_section] += size - if self.cur_section == '.text': - if not self.text_glabels: - self.fail(".text block without an initial glabel", line) - self.fn_ins_inds.append((self.num_lines - 1, size // 4)) - - def process_line(self, line, output_enc): - self.num_lines += 1 - if line.endswith('\\'): - self.glued_line += line[:-1] - return - line = self.glued_line + line - self.glued_line = '' - - real_line = line - line = re.sub(re_comment_or_string, re_comment_replacer, line) - line = line.strip() - line = re.sub(r'^[a-zA-Z0-9_]+:\s*', '', line) - changed_section = False - emitting_double = False - if line.startswith('glabel ') and self.cur_section == '.text': - self.text_glabels.append(line.split()[1]) - if not line: - pass # empty line - elif line.startswith('glabel ') or (' ' not in line and line.endswith(':')): - pass # label - elif line.startswith('.section') or line in ['.text', '.data', '.rdata', '.rodata', '.bss', '.late_rodata']: - # section change - self.cur_section = '.rodata' if line == '.rdata' else line.split(',')[0].split()[-1] - if self.cur_section not in ['.data', '.text', '.rodata', '.late_rodata', '.bss']: - self.fail("unrecognized .section directive", real_line) - changed_section = True - elif line.startswith('.late_rodata_alignment'): - if self.cur_section != '.late_rodata': - self.fail(".late_rodata_alignment must occur within .late_rodata section", real_line) - value = int(line.split()[1]) - if value not in [4, 8]: - self.fail(".late_rodata_alignment argument must be 4 or 8", real_line) - if self.late_rodata_alignment and self.late_rodata_alignment != value: - self.fail(".late_rodata_alignment alignment assumption conflicts with earlier .double directive. Make sure to provide explicit alignment padding.") - self.late_rodata_alignment = value - changed_section = True - elif line.startswith('.incbin'): - self.add_sized(int(line.split(',')[-1].strip(), 0), real_line) - elif line.startswith('.word') or line.startswith('.float'): - self.align4() - self.add_sized(4 * len(line.split(',')), real_line) - elif line.startswith('.double'): - self.align4() - if self.cur_section == '.late_rodata': - align8 = self.fn_section_sizes[self.cur_section] % 8 - # Automatically set late_rodata_alignment, so the generated C code uses doubles. - # This gives us correct alignment for the transferred doubles even when the - # late_rodata_alignment is wrong, e.g. for non-matching compilation. - if not self.late_rodata_alignment: - self.late_rodata_alignment = 8 - align8 - self.late_rodata_alignment_from_content = True - elif self.late_rodata_alignment != 8 - align8: - if self.late_rodata_alignment_from_content: - self.fail("found two .double directives with different start addresses mod 8. Make sure to provide explicit alignment padding.", real_line) - else: - self.fail(".double at address that is not 0 mod 8 (based on .late_rodata_alignment assumption). Make sure to provide explicit alignment padding.", real_line) - self.add_sized(8 * len(line.split(',')), real_line) - emitting_double = True - elif line.startswith('.space'): - self.add_sized(int(line.split()[1], 0), real_line) - elif line.startswith('.balign') or line.startswith('.align'): - align = int(line.split()[1]) - if align != 4: - self.fail("only .balign 4 is supported", real_line) - self.align4() - elif line.startswith('.asci'): - z = (line.startswith('.asciz') or line.startswith('.asciiz')) - self.add_sized(self.count_quoted_size(line, z, real_line, output_enc), real_line) - elif line.startswith('.byte'): - self.add_sized(len(line.split(',')), real_line) - elif line.startswith('.half'): - self.align2() - self.add_sized(2*len(line.split(',')), real_line) - elif line.startswith('.'): - # .macro, ... - self.fail("asm directive not supported", real_line) - else: - # Unfortunately, macros are hard to support for .rodata -- - # we don't know how how space they will expand to before - # running the assembler, but we need that information to - # construct the C code. So if we need that we'll either - # need to run the assembler twice (at least in some rare - # cases), or change how this program is invoked. - # Similarly, we can't currently deal with pseudo-instructions - # that expand to several real instructions. - if self.cur_section != '.text': - self.fail("instruction or macro call in non-.text section? not supported", real_line) - self.add_sized(4, real_line) - if self.cur_section == '.late_rodata': - if not changed_section: - if emitting_double: - self.late_rodata_asm_conts.append(".align 0") - self.late_rodata_asm_conts.append(real_line) - if emitting_double: - self.late_rodata_asm_conts.append(".align 2") - else: - self.asm_conts.append(real_line) - - def finish(self, state): - src = [''] * (self.num_lines + 1) - late_rodata_dummy_bytes = [] - jtbl_rodata_size = 0 - late_rodata_fn_output = [] - - num_instr = self.fn_section_sizes['.text'] // 4 - - if self.fn_section_sizes['.late_rodata'] > 0: - # Generate late rodata by emitting unique float constants. - # This requires 3 instructions for each 4 bytes of rodata. - # If we know alignment, we can use doubles, which give 3 - # instructions for 8 bytes of rodata. - size = self.fn_section_sizes['.late_rodata'] // 4 - skip_next = False - needs_double = (self.late_rodata_alignment != 0) - for i in range(size): - if skip_next: - skip_next = False - continue - # Jump tables give 9 instructions for >= 5 words of rodata, and should be - # emitted when: - # - -O2 or -O2 -g3 are used, which give the right codegen - # - we have emitted our first .float/.double (to ensure that we find the - # created rodata in the binary) - # - we have emitted our first .double, if any (to ensure alignment of doubles - # in shifted rodata sections) - # - we have at least 5 words of rodata left to emit (otherwise IDO does not - # generate a jump table) - # - we have at least 10 more instructions to go in this function (otherwise our - # function size computation will be wrong since the delay slot goes unused) - if (not needs_double and state.use_jtbl_for_rodata and i >= 1 and - size - i >= 5 and num_instr - len(late_rodata_fn_output) >= 10): - cases = " ".join("case {}:".format(case) for case in range(size - i)) - late_rodata_fn_output.append("switch (*(volatile int*)0) { " + cases + " ; }") - late_rodata_fn_output.extend([""] * 8) - jtbl_rodata_size = (size - i) * 4 - break - dummy_bytes = state.next_late_rodata_hex() - late_rodata_dummy_bytes.append(dummy_bytes) - if self.late_rodata_alignment == 4 * ((i + 1) % 2 + 1) and i + 1 < size: - dummy_bytes2 = state.next_late_rodata_hex() - late_rodata_dummy_bytes.append(dummy_bytes2) - fval, = struct.unpack('>d', dummy_bytes + dummy_bytes2) - late_rodata_fn_output.append('*(volatile double*)0 = {};'.format(fval)) - skip_next = True - needs_double = True - else: - fval, = struct.unpack('>f', dummy_bytes) - late_rodata_fn_output.append('*(volatile float*)0 = {}f;'.format(fval)) - late_rodata_fn_output.append('') - late_rodata_fn_output.append('') - - text_name = None - if self.fn_section_sizes['.text'] > 0 or late_rodata_fn_output: - text_name = state.make_name('func') - src[0] = 'void {}(void) {{'.format(text_name) - src[self.num_lines] = '}' - instr_count = self.fn_section_sizes['.text'] // 4 - if instr_count < state.min_instr_count: - self.fail("too short .text block") - tot_emitted = 0 - tot_skipped = 0 - fn_emitted = 0 - fn_skipped = 0 - rodata_stack = late_rodata_fn_output[::-1] - for (line, count) in self.fn_ins_inds: - for _ in range(count): - if (fn_emitted > MAX_FN_SIZE and instr_count - tot_emitted > state.min_instr_count and - (not rodata_stack or rodata_stack[-1])): - # Don't let functions become too large. When a function reaches 284 - # instructions, and -O2 -framepointer flags are passed, the IRIX - # compiler decides it is a great idea to start optimizing more. - fn_emitted = 0 - fn_skipped = 0 - src[line] += ' }} void {}(void) {{ '.format(state.make_name('large_func')) - if fn_skipped < state.skip_instr_count: - fn_skipped += 1 - tot_skipped += 1 - elif rodata_stack: - src[line] += rodata_stack.pop() - else: - src[line] += '*(volatile int*)0 = 0;' - tot_emitted += 1 - fn_emitted += 1 - if rodata_stack: - size = len(late_rodata_fn_output) // 3 - available = instr_count - tot_skipped - self.fail( - "late rodata to text ratio is too high: {} / {} must be <= 1/3\n" - "add .late_rodata_alignment (4|8) to the .late_rodata " - "block to double the allowed ratio." - .format(size, available)) - - rodata_name = None - if self.fn_section_sizes['.rodata'] > 0: - rodata_name = state.make_name('rodata') - src[self.num_lines] += ' const char {}[{}] = {{1}};'.format(rodata_name, self.fn_section_sizes['.rodata']) - - data_name = None - if self.fn_section_sizes['.data'] > 0: - data_name = state.make_name('data') - src[self.num_lines] += ' char {}[{}] = {{1}};'.format(data_name, self.fn_section_sizes['.data']) - - bss_name = None - if self.fn_section_sizes['.bss'] > 0: - bss_name = state.make_name('bss') - src[self.num_lines] += ' char {}[{}];'.format(bss_name, self.fn_section_sizes['.bss']) - - fn = Function( - text_glabels=self.text_glabels, - asm_conts=self.asm_conts, - late_rodata_dummy_bytes=late_rodata_dummy_bytes, - jtbl_rodata_size=jtbl_rodata_size, - late_rodata_asm_conts=self.late_rodata_asm_conts, - fn_desc=self.fn_desc, - data={ - '.text': (text_name, self.fn_section_sizes['.text']), - '.data': (data_name, self.fn_section_sizes['.data']), - '.rodata': (rodata_name, self.fn_section_sizes['.rodata']), - '.bss': (bss_name, self.fn_section_sizes['.bss']), - }) - return src, fn - -cutscene_data_regexpr = re.compile(r"CutsceneData (.|\n)*\[\] = {") -float_regexpr = re.compile(r"[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?f") - -def repl_float_hex(m): - return str(struct.unpack(">I", struct.pack(">f", float(m.group(0).strip().rstrip("f"))))[0]) - -def parse_source(f, opt, framepointer, input_enc, output_enc, print_source=None): - if opt in ['O2', 'O1']: - if framepointer: - min_instr_count = 6 - skip_instr_count = 5 - else: - min_instr_count = 2 - skip_instr_count = 1 - elif opt == 'g': - if framepointer: - min_instr_count = 7 - skip_instr_count = 7 - else: - min_instr_count = 4 - skip_instr_count = 4 - else: - if opt != 'g3': - raise Failure("must pass one of -g, -O1, -O2, -O2 -g3") - if framepointer: - min_instr_count = 4 - skip_instr_count = 4 - else: - min_instr_count = 2 - skip_instr_count = 2 - - use_jtbl_for_rodata = False - if opt in ['O2', 'g3'] and not framepointer: - use_jtbl_for_rodata = True - - state = GlobalState(min_instr_count, skip_instr_count, use_jtbl_for_rodata) - - global_asm = None - asm_functions = [] - output_lines = [] - - is_cutscene_data = False - - for line_no, raw_line in enumerate(f, 1): - raw_line = raw_line.rstrip() - line = raw_line.lstrip() - - # Print exactly one output line per source line, to make compiler - # errors have correct line numbers. These will be overridden with - # reasonable content further down. - output_lines.append('') - - if global_asm is not None: - if line.startswith(')'): - src, fn = global_asm.finish(state) - for i, line2 in enumerate(src): - output_lines[start_index + i] = line2 - asm_functions.append(fn) - global_asm = None - else: - global_asm.process_line(raw_line, output_enc) - else: - if line in ['GLOBAL_ASM(', '#pragma GLOBAL_ASM(']: - global_asm = GlobalAsmBlock("GLOBAL_ASM block at line " + str(line_no)) - start_index = len(output_lines) - elif ((line.startswith('GLOBAL_ASM("') or line.startswith('#pragma GLOBAL_ASM("')) - and line.endswith('")')): - fname = line[line.index('(') + 2 : -2] - global_asm = GlobalAsmBlock(fname) - with open(fname, encoding=input_enc) as f: - for line2 in f: - global_asm.process_line(line2.rstrip(), output_enc) - src, fn = global_asm.finish(state) - output_lines[-1] = ''.join(src) - asm_functions.append(fn) - global_asm = None - elif line.startswith('#include "') and line.endswith('" EARLY'): - # C includes qualified with EARLY (i.e. #include "file.c" EARLY) will be - # processed recursively when encountered - fpath = os.path.dirname(f.name) - fname = line[line.index(' ') + 2 : -7] - include_src = StringIO() - with open(fpath + os.path.sep + fname, encoding=input_enc) as include_file: - parse_source(include_file, opt, framepointer, input_enc, output_enc, include_src) - output_lines[-1] = include_src.getvalue() - include_src.write('#line ' + str(line_no) + '\n') - include_src.close() - else: - # This is a hack to replace all floating-point numbers in an array of a particular type - # (in this case CutsceneData) with their corresponding IEEE-754 hexadecimal representation - if cutscene_data_regexpr.search(line) is not None: - is_cutscene_data = True - elif line.endswith("};"): - is_cutscene_data = False - if is_cutscene_data: - raw_line = re.sub(float_regexpr, repl_float_hex, raw_line) - output_lines[-1] = raw_line - - if print_source: - if isinstance(print_source, StringIO): - for line in output_lines: - print_source.write(line + '\n') - else: - for line in output_lines: - print_source.write(line.encode(output_enc) + b'\n') - print_source.flush() - if print_source != sys.stdout.buffer: - print_source.close() - - return asm_functions - -def fixup_objfile(objfile_name, functions, asm_prelude, assembler, output_enc): - SECTIONS = ['.data', '.text', '.rodata', '.bss'] - - with open(objfile_name, 'rb') as f: - objfile = ElfFile(f.read()) - - prev_locs = { - '.text': 0, - '.data': 0, - '.rodata': 0, - '.bss': 0, - } - to_copy = { - '.text': [], - '.data': [], - '.rodata': [], - '.bss': [], - } - asm = [] - all_late_rodata_dummy_bytes = [] - all_jtbl_rodata_size = [] - late_rodata_asm = [] - late_rodata_source_name_start = None - late_rodata_source_name_end = None - - # Generate an assembly file with all the assembly we need to fill in. For - # simplicity we pad with nops/.space so that addresses match exactly, so we - # don't have to fix up relocations/symbol references. - all_text_glabels = set() - for function in functions: - ifdefed = False - for sectype, (temp_name, size) in function.data.items(): - if temp_name is None: - continue - assert size > 0 - loc = objfile.symtab.find_symbol(temp_name) - if loc is None: - ifdefed = True - break - loc = loc[1] - prev_loc = prev_locs[sectype] - if loc < prev_loc: - raise Failure("Wrongly computed size for section {} (diff {}). This is an asm-processor bug!".format(sectype, prev_loc- loc)) - if loc != prev_loc: - asm.append('.section ' + sectype) - if sectype == '.text': - for i in range((loc - prev_loc) // 4): - asm.append('nop') - else: - asm.append('.space {}'.format(loc - prev_loc)) - to_copy[sectype].append((loc, size, temp_name, function.fn_desc)) - prev_locs[sectype] = loc + size - if not ifdefed: - all_text_glabels.update(function.text_glabels) - all_late_rodata_dummy_bytes.append(function.late_rodata_dummy_bytes) - all_jtbl_rodata_size.append(function.jtbl_rodata_size) - late_rodata_asm.append(function.late_rodata_asm_conts) - for sectype, (temp_name, size) in function.data.items(): - if temp_name is not None: - asm.append('.section ' + sectype) - asm.append('glabel ' + temp_name + '_asm_start') - asm.append('.text') - for line in function.asm_conts: - asm.append(line) - for sectype, (temp_name, size) in function.data.items(): - if temp_name is not None: - asm.append('.section ' + sectype) - asm.append('glabel ' + temp_name + '_asm_end') - if any(late_rodata_asm): - late_rodata_source_name_start = '_asmpp_late_rodata_start' - late_rodata_source_name_end = '_asmpp_late_rodata_end' - asm.append('.rdata') - asm.append('glabel {}'.format(late_rodata_source_name_start)) - for conts in late_rodata_asm: - asm.extend(conts) - asm.append('glabel {}'.format(late_rodata_source_name_end)) - - o_file = tempfile.NamedTemporaryFile(prefix='asm-processor', suffix='.o', delete=False) - o_name = o_file.name - o_file.close() - s_file = tempfile.NamedTemporaryFile(prefix='asm-processor', suffix='.s', delete=False) - s_name = s_file.name - try: - s_file.write(asm_prelude + b'\n') - for line in asm: - s_file.write(line.encode(output_enc) + b'\n') - s_file.close() - ret = os.system(assembler + " " + s_name + " -o " + o_name) - if ret != 0: - raise Failure("failed to assemble") - with open(o_name, 'rb') as f: - asm_objfile = ElfFile(f.read()) - - # Remove some clutter from objdump output - objfile.drop_irrelevant_sections() - - # Unify reginfo sections - target_reginfo = objfile.find_section('.reginfo') - source_reginfo_data = list(asm_objfile.find_section('.reginfo').data) - data = list(target_reginfo.data) - for i in range(20): - data[i] |= source_reginfo_data[i] - target_reginfo.data = bytes(data) - - # Move over section contents - modified_text_positions = set() - jtbl_rodata_positions = set() - last_rodata_pos = 0 - for sectype in SECTIONS: - if not to_copy[sectype]: - continue - source = asm_objfile.find_section(sectype) - assert source is not None, "didn't find source section: " + sectype - for (pos, count, temp_name, fn_desc) in to_copy[sectype]: - loc1 = asm_objfile.symtab.find_symbol_in_section(temp_name + '_asm_start', source) - loc2 = asm_objfile.symtab.find_symbol_in_section(temp_name + '_asm_end', source) - assert loc1 == pos, "assembly and C files don't line up for section " + sectype + ", " + fn_desc - if loc2 - loc1 != count: - raise Failure("incorrectly computed size for section " + sectype + ", " + fn_desc + ". If using .double, make sure to provide explicit alignment padding.") - if sectype == '.bss': - continue - target = objfile.find_section(sectype) - assert target is not None, "missing target section of type " + sectype - data = list(target.data) - for (pos, count, _, _) in to_copy[sectype]: - data[pos:pos + count] = source.data[pos:pos + count] - if sectype == '.text': - assert count % 4 == 0 - assert pos % 4 == 0 - for i in range(count // 4): - modified_text_positions.add(pos + 4 * i) - elif sectype == '.rodata': - last_rodata_pos = pos + count - target.data = bytes(data) - - # Move over late rodata. This is heuristic, sadly, since I can't think - # of another way of doing it. - moved_late_rodata = {} - if any(all_late_rodata_dummy_bytes) or any(all_jtbl_rodata_size): - source = asm_objfile.find_section('.rodata') - target = objfile.find_section('.rodata') - source_pos = asm_objfile.symtab.find_symbol_in_section(late_rodata_source_name_start, source) - source_end = asm_objfile.symtab.find_symbol_in_section(late_rodata_source_name_end, source) - if source_end - source_pos != sum(map(len, all_late_rodata_dummy_bytes)) * 4 + sum(all_jtbl_rodata_size): - raise Failure("computed wrong size of .late_rodata") - new_data = list(target.data) - for dummy_bytes_list, jtbl_rodata_size in zip(all_late_rodata_dummy_bytes, all_jtbl_rodata_size): - for index, dummy_bytes in enumerate(dummy_bytes_list): - pos = target.data.index(dummy_bytes, last_rodata_pos) - # This check is nice, but makes time complexity worse for large files: - if SLOW_CHECKS and target.data.find(dummy_bytes, pos + 4) != -1: - raise Failure("multiple occurrences of late_rodata hex magic. Change asm-processor to use something better than 0xE0123456!") - if index == 0 and len(dummy_bytes_list) > 1 and target.data[pos+4:pos+8] == b'\0\0\0\0': - # Ugly hack to handle double alignment for non-matching builds. - # We were told by .late_rodata_alignment (or deduced from a .double) - # that a function's late_rodata started out 4 (mod 8), and emitted - # a float and then a double. But it was actually 0 (mod 8), so our - # double was moved by 4 bytes. To make them adjacent to keep jump - # tables correct, move the float by 4 bytes as well. - new_data[pos:pos+4] = b'\0\0\0\0' - pos += 4 - new_data[pos:pos+4] = source.data[source_pos:source_pos+4] - moved_late_rodata[source_pos] = pos - last_rodata_pos = pos + 4 - source_pos += 4 - if jtbl_rodata_size > 0: - assert dummy_bytes_list, "should always have dummy bytes before jtbl data" - pos = last_rodata_pos - new_data[pos : pos + jtbl_rodata_size] = \ - source.data[source_pos : source_pos + jtbl_rodata_size] - for i in range(0, jtbl_rodata_size, 4): - moved_late_rodata[source_pos + i] = pos + i - jtbl_rodata_positions.add(pos + i) - last_rodata_pos += jtbl_rodata_size - source_pos += jtbl_rodata_size - target.data = bytes(new_data) - - # Merge strtab data. - strtab_adj = len(objfile.symtab.strtab.data) - objfile.symtab.strtab.data += asm_objfile.symtab.strtab.data - - # Find relocated symbols - relocated_symbols = set() - for sectype in SECTIONS: - for obj in [asm_objfile, objfile]: - sec = obj.find_section(sectype) - if sec is None: - continue - for reltab in sec.relocated_by: - for rel in reltab.relocations: - relocated_symbols.add(obj.symtab.symbol_entries[rel.sym_index]) - - # Move over symbols, deleting the temporary function labels. - # Sometimes this naive procedure results in duplicate symbols, or UNDEF - # symbols that are also defined the same .o file. Hopefully that's fine. - # Skip over local symbols that aren't used relocated against, to avoid - # conflicts. - new_local_syms = [s for s in objfile.symtab.local_symbols() if not is_temp_name(s.name)] - new_global_syms = [s for s in objfile.symtab.global_symbols() if not is_temp_name(s.name)] - for i, s in enumerate(asm_objfile.symtab.symbol_entries): - is_local = (i < asm_objfile.symtab.sh_info) - if is_local and s not in relocated_symbols: - continue - if is_temp_name(s.name): - continue - if s.st_shndx not in [SHN_UNDEF, SHN_ABS]: - section_name = asm_objfile.sections[s.st_shndx].name - if section_name not in SECTIONS: - raise Failure("generated assembly .o must only have symbols for .text, .data, .rodata, ABS and UNDEF, but found " + section_name) - s.st_shndx = objfile.find_section(section_name).index - # glabel's aren't marked as functions, making objdump output confusing. Fix that. - if s.name in all_text_glabels: - s.type = STT_FUNC - if objfile.sections[s.st_shndx].name == '.rodata' and s.st_value in moved_late_rodata: - s.st_value = moved_late_rodata[s.st_value] - s.st_name += strtab_adj - if is_local: - new_local_syms.append(s) - else: - new_global_syms.append(s) - new_syms = new_local_syms + new_global_syms - for i, s in enumerate(new_syms): - s.new_index = i - objfile.symtab.data = b''.join(s.to_bin() for s in new_syms) - objfile.symtab.sh_info = len(new_local_syms) - - # Move over relocations - for sectype in SECTIONS: - source = asm_objfile.find_section(sectype) - target = objfile.find_section(sectype) - - if target is not None: - # fixup relocation symbol indices, since we butchered them above - for reltab in target.relocated_by: - nrels = [] - for rel in reltab.relocations: - if (sectype == '.text' and rel.r_offset in modified_text_positions or - sectype == '.rodata' and rel.r_offset in jtbl_rodata_positions): - # don't include relocations for late_rodata dummy code - continue - # hopefully we don't have relocations for local or - # temporary symbols, so new_index exists - rel.sym_index = objfile.symtab.symbol_entries[rel.sym_index].new_index - nrels.append(rel) - reltab.relocations = nrels - reltab.data = b''.join(rel.to_bin() for rel in nrels) - - if not source: - continue - - target_reltab = objfile.find_section('.rel' + sectype) - target_reltaba = objfile.find_section('.rela' + sectype) - for reltab in source.relocated_by: - for rel in reltab.relocations: - rel.sym_index = asm_objfile.symtab.symbol_entries[rel.sym_index].new_index - if sectype == '.rodata' and rel.r_offset in moved_late_rodata: - rel.r_offset = moved_late_rodata[rel.r_offset] - new_data = b''.join(rel.to_bin() for rel in reltab.relocations) - if reltab.sh_type == SHT_REL: - if not target_reltab: - target_reltab = objfile.add_section('.rel' + sectype, - sh_type=SHT_REL, sh_flags=0, - sh_link=objfile.symtab.index, sh_info=target.index, - sh_addralign=4, sh_entsize=8, data=b'') - target_reltab.data += new_data - else: - if not target_reltaba: - target_reltaba = objfile.add_section('.rela' + sectype, - sh_type=SHT_RELA, sh_flags=0, - sh_link=objfile.symtab.index, sh_info=target.index, - sh_addralign=4, sh_entsize=12, data=b'') - target_reltaba.data += new_data - - objfile.write(objfile_name) - finally: - s_file.close() - os.remove(s_name) - try: - os.remove(o_name) - except: - pass - -def run_wrapped(argv, outfile, functions): - parser = argparse.ArgumentParser(description="Pre-process .c files and post-process .o files to enable embedding assembly into C.") - parser.add_argument('filename', help="path to .c code") - parser.add_argument('--post-process', dest='objfile', help="path to .o file to post-process") - parser.add_argument('--assembler', dest='assembler', help="assembler command (e.g. \"mips-linux-gnu-as -march=vr4300 -mabi=32\")") - parser.add_argument('--asm-prelude', dest='asm_prelude', help="path to a file containing a prelude to the assembly file (with .set and .macro directives, e.g.)") - parser.add_argument('--input-enc', default='latin1', help="Input encoding (default: latin1)") - parser.add_argument('--output-enc', default='latin1', help="Output encoding (default: latin1)") - parser.add_argument('-framepointer', dest='framepointer', action='store_true') - parser.add_argument('-g3', dest='g3', action='store_true') - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-O1', dest='opt', action='store_const', const='O1') - group.add_argument('-O2', dest='opt', action='store_const', const='O2') - group.add_argument('-g', dest='opt', action='store_const', const='g') - args = parser.parse_args(argv) - opt = args.opt - if args.g3: - if opt != 'O2': - raise Failure("-g3 is only supported together with -O2") - opt = 'g3' - - if args.objfile is None: - with open(args.filename, encoding=args.input_enc) as f: - return parse_source(f, opt=opt, framepointer=args.framepointer, input_enc=args.input_enc, output_enc=args.output_enc, print_source=outfile) - else: - if args.assembler is None: - raise Failure("must pass assembler command") - if functions is None: - with open(args.filename, encoding=args.input_enc) as f: - functions = parse_source(f, opt=opt, framepointer=args.framepointer, input_enc=args.input_enc, output_enc=args.output_enc) - if not functions: - return - asm_prelude = b'' - if args.asm_prelude: - with open(args.asm_prelude, 'rb') as f: - asm_prelude = f.read() - fixup_objfile(args.objfile, functions, asm_prelude, args.assembler, args.output_enc) - -def run(argv, outfile=sys.stdout.buffer, functions=None): - try: - return run_wrapped(argv, outfile, functions) - except Failure as e: - print("Error:", e, file=sys.stderr) - sys.exit(1) - -if __name__ == "__main__": - run(sys.argv[1:]) diff --git a/tools/asm_processor/build.py b/tools/asm_processor/build.py deleted file mode 100644 index 228dcb03..00000000 --- a/tools/asm_processor/build.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 -import sys -import os -import shlex -import subprocess -import tempfile - -dir_path = os.path.dirname(os.path.realpath(__file__)) -asm_processor = ['python3', os.path.join(dir_path, "asm-processor.py")] -prelude = os.path.join(dir_path, "prelude.inc") - -all_args = sys.argv[1:] -sep1 = all_args.index('--') -sep2 = all_args.index('--', sep1+1) - -compiler = all_args[:sep1] - -assembler = all_args[sep1+1:sep2] -assembler_sh = ' '.join(shlex.quote(x) for x in assembler) - -compile_args = all_args[sep2+1:] -in_file = compile_args[-1] -out_ind = compile_args.index('-o') -out_file = compile_args[out_ind + 1] -del compile_args[-1] -del compile_args[out_ind + 1] -del compile_args[out_ind] - -in_dir = os.path.split(os.path.realpath(in_file))[0] -opt_flags = [x for x in compile_args if x in ['-g', '-O2', '-O1', '-framepointer']] - -preprocessed_file = tempfile.NamedTemporaryFile(prefix='preprocessed', suffix='.c') - -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(asm_processor + opt_flags + [in_file, '--post-process', out_file, '--assembler', assembler_sh, '--asm-prelude', prelude]) diff --git a/tools/asm_processor/prelude.inc b/tools/asm_processor/prelude.inc deleted file mode 100644 index 0c111a2a..00000000 --- a/tools/asm_processor/prelude.inc +++ /dev/null @@ -1,5 +0,0 @@ -.set noat -.set noreorder -.set gp=64 -.include "macros.inc" - diff --git a/tools/bfsize.c b/tools/bfsize.c deleted file mode 100644 index 7b2e9224..00000000 --- a/tools/bfsize.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2011 - * - * This is free software, licensed under the GNU General Public License v2. - * See /LICENSE for more information. - * - */ - -#include -#include -#include - -static void print_usage(const char *name) -{ - printf("Usage: %s file\n", name); -} - -int main(int argc, char **argv) -{ - FILE *fd; - long size; - - if (argc != 2) - { - print_usage(argv[0]); - exit(1); - } - - fd = fopen(argv[1], "rb"); - if (fd == NULL) - { - printf("Could not read the file '%s'\n", argv[1]); - print_usage(argv[0]); - exit(1); - } - - size = fseek(fd, 0L, SEEK_END); - size = ftell(fd); - fclose(fd); - - printf("%ld\n", size); - - exit(0); -} diff --git a/tools/ido5.3_compiler/LICENSE.md b/tools/ido5.3_compiler/LICENSE.md deleted file mode 100644 index 015107d4..00000000 --- a/tools/ido5.3_compiler/LICENSE.md +++ /dev/null @@ -1,18 +0,0 @@ -# Silicon Graphics Freeware Legal Notice -## Copyright 1995, Silicon Graphics, Inc. -- ALL RIGHTS RESERVED - -You may copy, modify, use and distribute this software, (i) provided that you include the entirety of this reservation of rights notice in all such copies, and (ii) you comply with any additional or different obligations and/or use restrictions specified by any third party owner or supplier of the software in other notices that may be included with the software. - -**SGI DISCLAIMS ALL WARRANTIES WITH RESPECT TO THIS SOFTWARE, EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ALL WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. SGI SHALL NOT BE LIABLE FOR ANY SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING, WITHOUT LIMITATION, LOST REVENUES, LOST PROFITS, OR LOSS OF PROSPECTIVE ECONOMIC ADVANTAGE, RESULTING FROM THE USE OR MISUSE OF THIS SOFTWARE.** - -**U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:** - -Use, duplication or disclosure by the Government is subject to restrictions as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or in similar or successor clauses in the FAR, or the DOD or NASA FAR Supplement. Unpublished - rights reserved under the Copyright Laws of United States. Contractor/manufacturer is Silicon Graphics, Inc., 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311. - -## Product Support - -Freeware products are not supported by Silicon Graphics or any of its support providers. The software contained in this package is made available through the generous efforts of their authors. Although they are interested in your feedback, they are under no obligation to address bugs, enhancements, or answer questions. - ----- - -**NOTE:** This license was copied verbatim from https://web.archive.org/web/19991008090202/http://toolbox.sgi.com/TasteOfDT/public/freeware1.0/legal_notice.html . diff --git a/tools/ido5.3_compiler/lib/libmalloc.so b/tools/ido5.3_compiler/lib/libmalloc.so deleted file mode 100644 index a58e1034..00000000 Binary files a/tools/ido5.3_compiler/lib/libmalloc.so and /dev/null differ diff --git a/tools/ido5.3_compiler/lib/libmalloc_old.so b/tools/ido5.3_compiler/lib/libmalloc_old.so deleted file mode 100644 index 2a14987d..00000000 Binary files a/tools/ido5.3_compiler/lib/libmalloc_old.so and /dev/null differ diff --git a/tools/ido5.3_compiler/lib/rld b/tools/ido5.3_compiler/lib/rld deleted file mode 100755 index 727b4269..00000000 Binary files a/tools/ido5.3_compiler/lib/rld and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/bin/cc b/tools/ido5.3_compiler/usr/bin/cc deleted file mode 100755 index 2936fc3f..00000000 Binary files a/tools/ido5.3_compiler/usr/bin/cc and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/acpp b/tools/ido5.3_compiler/usr/lib/acpp deleted file mode 100755 index d5392cf6..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/acpp and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/as0 b/tools/ido5.3_compiler/usr/lib/as0 deleted file mode 100755 index badf8c83..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/as0 and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/as1 b/tools/ido5.3_compiler/usr/lib/as1 deleted file mode 100755 index c246db53..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/as1 and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/cfe b/tools/ido5.3_compiler/usr/lib/cfe deleted file mode 100755 index 305a50be..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/cfe and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/copt b/tools/ido5.3_compiler/usr/lib/copt deleted file mode 100755 index 2e689fdc..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/copt and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/crt1.o b/tools/ido5.3_compiler/usr/lib/crt1.o deleted file mode 100644 index 3052ae27..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/crt1.o and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/err.english.cc b/tools/ido5.3_compiler/usr/lib/err.english.cc deleted file mode 100644 index 6976e38a..00000000 --- a/tools/ido5.3_compiler/usr/lib/err.english.cc +++ /dev/null @@ -1,1260 +0,0 @@ -@ - 358 358 358 - 6464 6482 6553 - 6553 6593 6728 - 6728 6746 6803 - 6803 6808 6808 - 6808 6818 6818 - 6818 6826 6826 - 6826 6847 6847 - 6847 6875 6922 - 6922 6930 6930 - 6930 6939 6939 - 6939 6948 6948 - 6948 6974 7120 - 7120 7149 7204 - 7210 7248 7311 - 7317 7350 7442 - 7450 7497 7627 - 7635 7709 7930 - 7938 7975 8063 - 8071 8113 8253 - 8261 8289 8289 - 8298 8338 8445 - 8460 8502 8635 - 8650 8690 8819 - 8834 8857 8965 - 8965 9008 9113 - 9119 9142 9227 - 9235 9282 9451 - 9451 9462 9462 - 9462 9477 9477 - 9477 9497 9497 - 9497 9545 9545 - 9545 9584 9584 - 9584 9604 9662 - 9662 9682 9720 - 9720 9749 9749 - 9749 9788 9788 - 9788 9802 9802 - 9802 9829 9829 - 9829 9861 9861 - 9861 9904 9904 - 9904 9920 9920 - 9920 9962 9962 - 9962 9988 9988 - 9988 10014 10014 -10014 10035 10035 -10035 10054 10097 -10097 10115 10115 -10115 10147 10147 -10147 10183 10183 -10183 10208 10208 -10208 10236 10236 -10236 10269 10269 -10269 10304 10304 -10304 10328 10328 -10328 10351 10351 -10351 10371 10371 -10371 10402 10402 -10402 10447 10447 -10447 10497 10497 -10497 10533 10533 -10533 10598 10598 -10606 10630 10630 -10640 10671 10671 -10690 10719 10719 -10728 10752 10795 -10795 10837 10837 -10837 10876 10876 -10876 10900 10900 -10900 10948 10948 -10960 11021 11103 -11103 11128 11128 -11128 11153 11153 -11153 11216 11216 -11216 11239 11239 -11239 11303 11303 -11303 11347 11347 -11357 11393 11393 -11393 11432 11432 -11442 11494 11494 -11494 11536 11536 -11536 11595 11595 -11595 11622 11622 -11622 11684 11684 -11684 11726 11726 -11738 11778 11778 -11782 11813 11813 -11813 11850 11850 -11850 11900 12087 -12111 12120 12120 -12120 12129 12129 -12129 12158 12158 -12158 12192 12192 -12192 12237 12237 -12237 12273 12273 -12273 12326 12326 -12330 12366 12366 -12366 12423 12423 -12427 12482 12482 -12486 12560 12560 -12568 12631 12631 -12637 12691 12691 -12691 12743 12743 -12743 12785 12785 -12785 12826 12826 -12826 12865 12865 -12865 12883 12883 -12883 12946 12946 -12956 12995 12995 -13005 13066 13066 -13077 13163 13163 -13163 13211 13211 -13211 13270 13270 -13270 13318 13318 -13318 13350 13350 -13350 13387 13387 -13387 13428 13428 -13428 13464 13533 -13533 13580 13737 -13737 13776 13854 -13854 13913 13913 -13913 13950 13950 -13950 14118 14118 -14118 14150 14150 -14150 14163 14194 -14194 14224 14255 -14255 14275 14319 -14319 14353 14458 -14466 14484 14530 -14534 14567 14567 -14567 14635 14682 -14690 14742 14742 -14742 14789 14789 -14801 14875 14875 -14886 14947 14947 -14947 14992 14992 -14992 15035 15085 -15085 15134 15205 -15214 15267 15448 -15454 15496 16810 -16822 16875 16960 -16972 17053 17179 -17191 17236 17332 -17344 17491 17841 -17853 17939 18304 -18316 18471 18774 -18786 18952 19323 -19335 19364 19496 -19500 19527 19598 -19598 19613 19776 -19797 19808 19837 -19837 19862 19862 -19868 19927 20026 -20034 20075 20179 -20187 20223 20223 -20223 20290 20382 -20392 20441 20589 -20601 20656 20656 -20656 20699 20818 -20826 20860 21038 -21046 21094 21191 -21203 21236 21314 -21326 21395 21457 -21469 21502 21502 -21502 21587 21731 -21756 21789 21864 -21875 21901 21976 -22013 22059 22220 -22257 22397 22561 -22561 22595 22595 -22603 22623 22623 -22631 22667 22828 -22865 22919 22994 -23031 23059 23120 -23132 23201 23201 -23212 23274 23274 -23285 23345 23345 -23356 23393 23393 -23399 23431 23532 -23542 23587 23646 -23656 23697 23745 -23755 23796 23844 -23854 23876 23928 -23942 23971 24153 -24160 24243 24243 -24247 24273 24743 -24755 24784 24984 -24996 25034 25034 -25034 25075 25273 -25281 25332 25410 -25420 25467 25544 -25554 25583 25744 -25754 25783 26061 -26071 26111 26185 -26194 26239 26525 -26535 26568 26914 -26924 26951 26998 -27008 27035 27082 -27093 27120 27167 -27178 27206 27251 -27261 27289 27334 -27345 27391 27931 -27938 27959 28007 -28019 28037 28037 -28043 28069 28069 -28077 28147 28199 -28207 28266 28266 -28274 28306 28306 -28314 28339 28339 -28347 28404 28510 -28518 28567 28682 -28690 28728 28728 -28736 28782 29023 -29033 29085 29234 -29246 29303 29383 -29395 29432 29570 -29592 29631 29644 -29644 29693 29758 -29767 29810 29875 -29875 29911 29976 -29984 30014 30014 -30027 30086 30151 -30157 30223 30293 -30301 30369 30445 -30457 30511 30568 -30580 30630 30743 -30755 30812 30874 -30886 30959 31035 -31043 31076 31175 -31183 31243 31243 -31251 31323 31323 -31331 31433 31433 -31445 31544 31686 -31698 31740 31740 -31740 31783 31783 -31783 31824 31824 -31824 31873 31996 -32008 32056 32164 -32176 32210 32210 -32229 32271 32271 -32279 32323 32569 -32581 32642 32718 -32739 32779 32916 -32926 32953 33047 -33057 33116 33315 -33325 33373 33373 -33373 33407 33469 -33494 33527 33527 -33536 33573 33573 -33584 33650 33697 -33705 33763 33763 -33763 33797 33797 -33797 33829 33906 -33915 33976 33976 -33985 34016 34098 -34098 34133 34198 -34198 34261 34261 -34269 34312 34312 -34324 34363 34438 -34444 34530 34530 -34538 34596 34626 -34636 34675 34754 -34764 34821 34821 -34821 34867 34950 -34959 35016 35135 -35145 35198 35198 -35208 35266 35344 -35355 35382 35537 -35547 35576 35629 -35637 35705 35705 -35713 35764 35764 -35764 35784 35876 -35888 35932 35950 -35950 36013 36138 -36150 36191 36280 -36286 36314 36419 -36431 36516 36516 -36516 36554 36642 -36642 36689 36808 -36818 36881 37105 -37113 37183 37204 -37204 37225 37225 -37225 37255 37348 -37348 37388 37388 -37388 37454 37454 -37454 37518 37518 -37518 37584 37584 -37584 37717 37717 -37717 37752 37752 -37752 37783 37889 -37901 37928 38034 -38046 38115 38115 -38115 38140 38187 -38195 38219 38339 -38351 38422 38422 -38422 38486 38486 -38486 38555 38555 -38555 38619 38619 -38619 38641 38641 -38641 38758 38758 -38758 38929 38929 -38929 38975 39043 -39055 39084 39133 -39133 39175 39265 -39275 39310 39494 -39504 39547 39576 -39587 39614 39668 -39674 39697 39797 -39797 39845 40094 -40094 40158 40264 -40264 40369 40523 -40523 40593 40593 -40593 40629 40876 -40876 40911 40971 -40977 41026 41026 -41038 41077 41077 -41077 41116 41116 -41116 41156 41156 -41156 41195 41195 -41195 41237 41237 -41237 41285 41285 -41285 41304 41304 -41304 41371 41371 -41371 41429 41429 -41429 41491 41491 -41491 41519 41519 -41519 41572 41572 -41572 41642 41642 -41642 41676 41676 -41676 41713 41713 -41713 41751 41751 -41751 41792 41792 -41792 41856 41856 -41856 41881 41881 -41881 41936 41936 -41936 41977 41977 -41977 42018 42018 -42018 42090 42090 -42090 42162 42162 -42162 42205 42205 -42205 42267 42267 -42267 42294 42294 -42294 42309 42309 -42309 42338 42386 -42393 42425 42522 -42530 42577 42577 -42577 42623 42623 -42623 42643 42725 -42725 42748 42748 -42748 42829 42897 -42901 42952 42952 -42952 42978 43025 -43025 43116 43116 -43116 43171 43171 -43171 43204 43376 -43386 43453 43471 -43471 43547 43780 -43798 43921 44116 -44120 44120 44120 -Out of memory: %s -There is no more memory left in the system for compiling this program. -Internal Error Unknown Error Message %s -1) An internal error, while attempting to print an unavailable message -2) The error message file is inaccessible or has other problems -Unknown Signal %s -1) An unknown signal has been caught -2) 2 Nested signals -line -Warning: -Fatal: -Source not available -Too many errors... goodbye. -There is a limit of 30 errors before aborting. -Error: -reserved -reserved -Unknown Control Statement -1) The line begins with a '#' and is not of the form: - # "" -2) Please compile this program with the preprocessor enabled. -Unknown character %s ignored -The character is not part of the source character set. -2.2.1 -Unknown control character \%s ignored -The control character is not part of the source character set. -2.2.1 -Illegal character %s in exponent -1) Digits or sign expected after 'e' or 'E'. -2) Digits are expected after sign in exponent. -3.1.3.1 -Constant is out of range and may be truncated. -The constant is too large to be accurately represented and may be -truncated. The limits are in the system include file limits.h. -2.2.4.2 -Constant is out of range for a 32-bit data type, but accepted as written. -The constant is too large to fit in a 32-bit data type, but will be -accurately represented in a wider data type. The value may be truncated, -depending on its context. The limits are in the system include file -limits.h. -2.2.4.2 -Character constant size out of range -1) No characters in a character constant. -2) More than 4 bytes in a character constant. -3.1.3.4 -Wide character constant size out of range -1) No characters in the multibyte sequence (0 assumed). -2) More than 1 byte in the multi-byte sequence (only the first byte was converted). -3.1.3.4 -Invalid multibyte character -4.10.7.2 -Newline in string or character constant -1) Terminate your string or character constant with closing quotes. -2) Put a backslash before the newline. -3.1.3.4, 3.1.4 -Octal character escape too large: %s > %s -1) Terminate end of octal sequence with a non-octal character. -2) Select a character value within the limits. -Value may be truncated -3.1.3.4, 3.1.4 -Hex character escape too large: %s > %s -1) Terminate end of hex sequence with a non-hex character. -2) Select a character value within the limits. -Value may be truncated -3.1.3.4, 3.1.4 -Unexpected End-of-file -1) Unterminated string or character constant -2) Missing closing comment marker (*/) -3) File system problems -Unrecognized escape sequence in string \%s -Recognized escape sequences are \a, \b, \f, \n, \r, \t, and \v. -Character will be treated as un-escaped. -3.9.2 -Illegal octal digit %s -Octal constants, beginning with 0, must only have digits between 0 and 7, -inclusive. -3.1.3.2 -Unable to open temporary file for compiling %s -1) TMPDIR environment variable is set to a directory that you have no - permissions for. -2) The file system is full. -3) System errors beyond the scope of the compiler. -%s: Hangup -%s: Interrupt -%s: Quit (ASCII FS) -%s: Illegal instruction (not reset when caught) -%s: Trace trap (not reset when caught) -%s: IOT instruction -Also SIGABRT, used by abort, replace SIGIOT in the future -%s: EMT instruction -Also SIGXCPU, Exceeded CPU time limit -%s: Floating point exception -%s: Kill (cannot be caught or ignored) -%s: Bus error -%s: Segmentation violation -%s: Bad argument to system call -%s: Write on a pipe with no one to read it -%s: Alarm clock -%s: Software termination signal from kill -%s: User defined signal 1 -%s: User defined signal 2 -%s: Death of a child -Power-fail restart -%s: Also SIGXFSZ, exceeded file size limit -%s: Window change -%s: Handset, line status change -%s: Sendablestop signalnot from tty -%s: Stop signal from tty -%s: Pollable event occurred -%s: Input/Output possible signal -%s: Urgent condition on IO channel -%s: Window size changes -%s: Virtual time alarm -%s: Profiling alarm -%s: Continue a stopped process -%s: To readers pgrp upon background tty read -%s: Like TTIN for output if (tp->t_local<OSTOP) -%s: Resource lost (eg, record-lock) -'auto' and 'register' are not allowed in an external declaration -3.7(10) -must have function type -3.7.1(30) -Functions cannot return arrays -3.7.1(33), 3.3.2.2 -Declaration list not allowed -3.7.1(5) -Too many input files %s -The command line may contain only one file -cpp internal error: input stack underflow -cpp internal error: if stack underflow -Cannot open the file %s -No new-line character at the end of the file %s -2.1.1.2(30) -Fatal: Exceeded the limit of nesting level for #include file -Fatal: Exceeded the limit of nesting level for #include file. This limit -is 200. -Fail to read the file %s -Cannot write the file %s -%s: %s: An if directive is not terminated properly in the file -%s: %s: nested comment -%s:%s: Illegal macro name %s; macro name shall be an identifier -%s:%s: Illegal preprocessing token sequence -3.8.3(35) -%s:%s: Illegal macro parameter name -%s:%s: Non-unique macro parameter name -3.8.3(18) -%s:%s: Missing ')' in parameter list for #define %s -%s:%s: Missing ')' in macro instantiation -%s:%s: Bad punctuator in the parameter list for #define %s -%s:%s: Macro %s redefined. -%s:%s: # operator should be followed by a macro argument name -%s:%s: Badly formed constant expression%s -3.4(9), 3.8 -%s:%s: Division by zero in #if or #elif -3.8 -unknown command line option %s -extraneous input/output file name %s -%s: %s: Unterminated string or character constant -A preprocessing string or character constant token was not -terminated. Note that preprocessing directives are processed -after the source file has been divided into preprocessing tokens. -2.1.1.2(30) 3.1(18) 3.8 -%s: %s: -%s: %s: -%s: %s: Unterminated comment -%s: %s: Unknown directive type %s -%s: %s: #elif or #else after #else directive -%s: %s: Bad identifier after the %s -%s: %s: #%s accepts only one identifier as parameter -3.8 -%s: %s: Bad identifier after the %s -%s: %s: text following #%s violates the ANSI C standard. -3.8 -%s: %s: Bad character %s occurs after the # directive. -3.8 -%s: %s: the ## operator shall not be the %s token in the replacement list -3.8.3.3 -%s: %s: the defined operator takes identifier as operand only. -3.8.1 -%s: %s: Not in a conditional directive while using %s -%s: %s: Illegal filename specification for #include -%s: %s: Invalid file name %s for #include -%s: %s: Cannot open file %s for #include -%s: %s: Bad argument for #line command -%s: %s: #error %s -%s: %s: Tried to redefine predefined macro %s, attempt ignored -3.8.7(22) -%s: %s: Undefining predefined macro %s -3.8.7(22) -%s: %s: Undefined the ANSI standard library defined macro %s -4.1.2.1(9) -%s: %s: The number of arguments in the macro invocation does not match the definition -%s: %s: Illegal character %s in preprocessor if -%s: %s: Illegal character %s for number in preprocessor if -%s: %s: No string is allowed in preprocessor if -%s: %s: Not supported pragma %s -%s: %s: Not supported #pragma format -%s: %s: ANSI C does not allow #ident; %s -%s: %s: Not supported #ident format -This cpp extension accepts the following format: -#ident "any string" -%s: %s: Not supported #assert/#unassert format -This cpp extension accepts the following format: -#assert identifier -#assert identifier ( pp-tokens ) -#unassert identifier -#unassert identifier ( pp-tokens ) -%s: %s: Bad assertion predicate format -The correct syntax for this cpp extension is: -#assert identifier ( pp-token ) -%s: %s: directive is an upward-compatible ANSI C extension -%s: This option requires an argument -%s: %s: A macro has expanded recursively more than %s times. Further expansion will be disabled! Use command-line option: -Wp,-max_rec_depth=depth to recurse deeper. -A status return from cpp to cfe -Syntax Error -The token read was unexpected. -Syntax Error -- cannot backup -The token read was unexpected. -Yacc stack overflow -The expression is too complicated to parse. -Trailing comma in enumerator list -The use of a trailing comma in an enumerator list is not standard C. There -may be portability problems. -3.5.2.2 -Empty declaration -Empty declarations are invalid in standard C. -3.5 -%s declared, but not referenced. -redeclaration of '%s'; previous declaration at line %s in file '%s' -Identifier redeclared in the same scope/block. -3.1.2.3 -'%s' undefined; reoccurrences will not be reported. -Non-function name referenced in function call. -3.3.2.2(18) -The number of arguments doesn't agree with the number in the declaration. -3.3.2.2(5) -'%s' section name longer than 8 characters. Name truncated. -'%s' is already placed by pragma alloc_text. -Cannot write ucode file while compiling %s -1) The file system is full -2) Permissions problem -Must have corresponding formal argument for '%s' -Parameter found in the declaration part, but not in the argument list. -3.7.1(7) -Non-prototype declaration is an obsolescent feature. -The use of function definitions with separate parameter identifier -and declaration lists (not prototype-format parameter type and -identifier declarators) is an obsolescent feature. -3.9.5 -Incompatible function declarations for %s -For two function types to be compatible, both shall specify compatible -return types. Moreover, the parameter type lists, if both are present, -shall agree in the number of parameters and in use of the ellipsis -terminator; corresponding parameters shall have compatible types. If -one type has a parameter type list and the other type is specified by -a function declarator that is not part of a function definition and -contains an empty identifier list, the parameter list shall not have -an ellipsis terminator and the type of each parameter shall be -compatible with they type that results from application of the default -argument promotions. If one type has a parameter type list and the -other is specified by a function definition that contains a (possibly -empty) identifier list, both shall agree in the number of parameters, -and the type of each prototype parameter shall be compatible with the -type that results from application of the default argument promotions -to the type of the corresponding identifier. (For each parameter -declared with function or array type, its type for these comparisons -is the one that results from conversion to a pointer type. For each -parameter declared with qualified type, its type for these comparisons -is the unqualified version of its declared type.) There you have it! -3.5.4.3(15) -Incompatible function return type for this function. -For two function types to be compatible, both shall specify compatible -return types. -3.5.4.3(15) -The number of parameters for function is different from the previous declaration -The parameter type lists, if both are present, shall agree in the -number of parameters and in use of the ellipsis terminator. -3.5.4.3(15) -Incompatible type for the function parameter -If both parameter type lists are present, corresponding -parameters shall have compatible types. -3.5.4.3(15) -Function %s is redeclared with an incompatible argument type (after default argument promotion), which could lead to undefined run-time behaviour. -The redeclaration could cause arguments at a call site to be passed -inconsistently with what the function implementation expects, and -parameters would therefore be accessed erroneously when executing the -function body. Note that a float argument is promoted to a double -when passed (potentially through fp registers) to an unprototyped -function. -3.5.4.3(15) -prototype and non-prototype declaration found for %s, ellipsis terminator not allowed -If one type has a parameter type list and the other type is specified -by a function declarator that is not part of a function definition and -contains an empty identifier list, the parameter list shall not have -an ellipsis terminator and the type of each parameter shall be -compatible with they type that results from application of the default -argument promotions. -3.5.4.3(15) -prototype and non-prototype declaration found for %s, the type of this parameter is not compatible with the type after applying default argument promotion -If one type has a parameter type list and the other type is specified -by a function declarator that is not part of a function definition and -contains an empty identifier list, the type of each parameter shall be -compatible with the type that results from application of the default -argument promotions. -3.5.4.3(15) -prototype declaration and non-prototype definition found for %s, the type of this parameter is not compatible with the type after applying default argument promotion -If one type has a parameter type list and the other is specified by a -function definition that contains a (possibly empty) identifier list, -both shall agree in the number of parameters, and the type of each -prototype parameter shall be compatible with the type that results -from application of the default argument promotions to the type of the -corresponding identifier. -3.5.4.3(15) -Empty declaration specifiers -Standard C requires at least a storage class specifier, type specifier, -or a type qualifier in declarations. 'extern int' assumed. -3.5 -Can't write to the file %s -1) The output file cannot be opened for writing. -2) Out of file space. -Duplicate '%s' -typedef, extern, static, auto, register, const, volatile may not -appear more than once in the same specifier list or qualifier list. -Duplicate occurrence ignored. -3.5.1(10) , 3.5.3(5) -Null input -There is nothing to compile. -Illegal type combination -3.5.2 -Missing ';' at end of structure / union member declaration -In standard C, each member declaration must be terminated by a ';'. A -terminating ';' is assumed. -3.5.2.1 -Missing member name in structure / union -In standard C, each member declaration have a member name. The missing -member is assumed to not exist. -3.5.2.1 -This variable is initialized twice. -Neither 'const' or 'volatile' have any effect on function results. -Qualifiers only apply to expressions designating an object that -can be altered or examined. -3.5.3(10) -An integer constant expression is required here. -The expression that defines the value of an enumeration constant -shall be an integral constant expression that has a value -representable as an int. -3.5.2.2(28) -(previous declaration of '%s' at line %s in file '%s') -Must be an integer type greater than zero. -The array size must be either a char, signed or unsigned integer or -an enumerated type with a value greater than zero. -3.5.4.2 -Array size cannot be a long long. -Arrays with more than 2^32 elements are not yet supported. -The array size must be either a char, signed or unsigned integer or -an enumerated type with a value greater than zero. -3.5.4.2 -bit-field '%s' width is not an integer constant -The expression that specifies the width of a bit-field shall be an -integral constant expression. -3.5.2.1(15) -bit-field '%s' width is negative -The expression that specifies the width of a bit-field shall be -non-negative. -3.5.2.1(15) -bit-field '%s' type required to be int, unsigned int, or signed int. -A bit-field shall have type int, unsigned int, or signed int. -3.5.2.1(30) -bit-field %s's type not integer. -Non-scalar type or pointer type to a non-object for increment or decrement operator. -The operand of the prefix/postfix increment or decrement operator shall have scalar type; if it is of pointer type, it must point to an object. -3.3.2.4(37), 3.3.3.1(25) -Assign value to a function type. -An assignment operator shall have a modifiable lvalue as its left operand. -3.2.2.1(5) -Assign value to an array. -An assignment operator shall have a modifiable lvalue as its left operand. -3.3.2.4(36), 3.3.3.1(24), 3.2.2.1(5) -Change value for variable of incomplete type. -The operand of increment and decrement operator shall be a modifiable -scalar lvalue. An assignment operator shall have a modifiable lvalue -as its left operand. -3.3.2.4(36), 3.3.3.1(24), 3.2.2.1(5) -The left-hand side of the '.' operator must be an addressable lvalue, when a bit-field is not contained within a unit of 32 bits alignment. -This is a restriction in our implementation, which can be worked -around by always accessing long long bit-fields indirectly (i.e. -by means of the '->' operator). -This expression is not an lvalue. -3.2.2.1 -Modified an rvalue. -3.2.2.1 -Change value for constant variable. -The operand of increment and decrement operators shall be modifiable -scalar lvalues. An assignment operator shall have a modifiable lvalue -as its left operand. -3.3.2.4(36), 3.3.3.1(24), 3.2.2.1(5) -Change value for constant field of a struct or union. -An assignment operator shall have a modifiable lvalue as its left operand. -3.3.2.4(36), 3.3.3.1(24), 3.2.2.1(5) -Dereferenced a non-pointer. -The operand of the unary * operator shall have pointer type. -3.3.3.2(39) -The operand of the unary + or - operator shall have arithmetic type. -3.3.3.3(6) -The operand of the unary ~ operator shall have integral type. -3.3.3.3(6) -The operand of the unary ! operator shall have scalar type. -3.3.3.3(6) -Constants must have arithmetic type. -3.1.3 -Bad type name for cast operator -The type name for the cast operator should either be void or a -qualified or unqualified scalar type. -3.3.4(22) -Improper cast of non-scalar type expression. -The operand for the cast operator shall be of scalar type. -3.3.4(23) -Cast a pointer into a non-integral type. -A pointer may be converted to an integral type. -3.3.4(31) -Cast a non-integral type into a pointer. -An integral type may be converted to a pointer. -3.3.4(31) -Duplicate member '%s' -Two members of a struct may not have the same name. -3.1.2.2(7,25) -Invalid constant expression. -Constant expressions shall not contain assignment, increment, decrement, -function-call, or comma operators, except when they are contained within -the operand of the sizeof operator. -3.4(9) -Constant expressions must be derived from a constant value or a constant -variable. -3.4 -Dangerous operand of '&'. -The operand of the unary & operator shall be either a function -designator or an lvalue that designates an object that is not a -bit-field and is not declared with the register storage-class -specifier. This operand is NOT an lvalue, but we let it pass. -Note that a segmentation error with possible core dump will result -when the resulting address does not denote a valid (declared) -storage location. This feature will be discontinued in future -releases of the compiler! -3.3.3.2(36) -Unacceptable operand of '&'. -The operand of the unary & operator shall be either a function -designator or an lvalue that designates an object that is not a -bit-field and is not declared with the register storage-class -specifier. -3.3.3.2(36) -'&' before array or function; ignored -Unacceptable operand of sizeof operator. -The sizeof operator shall not be applied to an expression that has -function type or an incomplete type, to the parenthesized name of such -a type, or to an lvalue that designates a bit-field object. -3.3.3.4 -Unacceptable operand of a multiplicative operator. -Each of the operands of a multiplicative operator shall have arithmetic type. -3.3.5(18) -Unacceptable operand of the remainder operator -Each of the operands of the remainder (%) operator shall have integral type. -3.3.5(18) -Unacceptable operand of '+'. -For the + operator, either both operands shall have arithmetic type, or -one operand shall be a pointer to an object type and the other shall -have integral type. -3.3.6(39) -Unacceptable operand of '-'. -For the subtraction operator, one of the following shall hold: both operands -have arithmetic type; operands are pointers to qualified or unqualified -versions of compatible object types; or the left operand is a pointer -to an object type and the right operand has integral type. -3.3.6(39) -Unacceptable operand of shift operator. -Each of the operands of bitwise shift operators shall have integral type. -3.3.7(9) -Unacceptable operand of relational operator. -For relational operators, one of the following shall hold: both -operands have arithmetic type; both operands are pointers to qualified -or unqualified versions of compatible object types; or both operands -are pointers to qualified or unqualified versions of compatible -incomplete types. -3.3.8(32) -Unacceptable operand of == or != -For the == or != operator, one of the following shall hold: both operands -are pointers to qualified or unqualified versions of compatible types; one -operand is a pointer to an object or incomplete type and the other is a -pointer to a qualified or unqualified version of void; or one operand is -a pointer and the other is a null pointer constant. -3.3.9(21) -Unacceptable operand of &. -Each of the operands shall have integral type. -3.3.10(7) -Unacceptable operand of ^. -Each of the operands shall have integral type. -3.3.11(18) -Unacceptable operand of |. -Each of the operands shall have integral type. -3.3.12(30) -Unacceptable operand of &&. -Each of the operands shall have scalar type. -3.3.13(7) -Unacceptable operand of ||. -Each of the operands shall have scalar type. -3.3.14(20) -Unacceptable operand of conditional operator. -The first operand of conditional operator shall have scalar type. One -of the following shall hold for the second and third operands: -both operands have arithmetic type; both operands have compatible -structure or union types; both operands have void type; both operands -are pointers to qualified or unqualified versions of compatible types; -one operand is a pointer and the other is a null pointer constant; or -one operand is pointer to an object or incomplete type and the other -is a pointer to a qualified or unqualified version of void. -3.3.15 -Duplicate label '%s' -A label name can only occur once in a function. -3.1.2.1(25) -Division by zero. -3.3.5 -Subscripting a non-array. -3.3.2.1 -Subscripting an array of incomplete type which is not an object type. -The element of the array shall have an object type. -3.3.2.1 -Should only subscript an array with an integral expression -3.3.2.1 -Subscripting an unbounded array -3.3.2.1 -Array index out of range -3.3.2.1 -Selector requires struct/union pointer as left hand side -In K&R mode the expression is implicitly converted to the '.' selector -for a struct/union left-hand side. -3.3.2.3 -Selector requires struct/union as left hand side -In K&R mode the expression is implicitly converted to the '->' selector -for a struct/union pointer left-hand side. -3.3.2.3 -member of structure or union required -3.3.2.3 -types have different qualifier specifications -For two qualified types to be compatible, both shall have the -identically qualified version of a compatible type; qualified -and unqualified versions of a type are distinct types. For two -types to be compatible their types must be the same. -3.5.3(26) -Incompatible array type due to different array size -For two array types to be compatible, both shall have compatible element -types; if both size specifiers are present, they shall have the -same value. -3.5.4.2(11) -Incompatible array type due to incompatible element type -For two array types to be compatible, both shall have compatible element -types. -3.5.4.2(11) -Incompatible pointer type assignment -The type pointed to by the left-hand side of simple assignment -statement is incompatible with the type pointed to by the right-hand side. -3.3.16.1, 3.5.4.1(21) -Incompatible base type of pointer type -K&R feature. -Type %s of %s is incompatible with type %s of %s -Incompatible types can be resolved by casting or by other means. -3.3.16.1 -illegal combination of pointer and integer -Assigning an integral expression to a pointer is a bad practice. -Type for %s is incompatible with %s -Incompatible types can be resolved by casting or by other means. -3.1.2.6 -Bad operand type for += or -= -3.3.16.2(26) -A case or default label appears outside a switch statement -A case or default label shall appear only in a switch statement. -3.6.1 -The controlling expression of the if statement is not scalar type -The controlling expression of an if statement shall have scalar type. -3.6.4.1 -The controlling expression of switch statement is not integral type -The controlling expression of an switch statement shall have integral type. -3.6.4.2(20) -The case label is not an integral constant expression -The case label shall be an integral constant expression. -3.6.4.2(22) -Duplicate case label in the same switch statement -No two of the case constant expressions in the same switch statement -shall have the same value after conversion. -3.6.4.2(22) -More than one default label in the same switch statement -There may be at most one default label in a switch statement. -3.6.4.2(23) -The controlling expression of the iteration statement is not scalar -type -The controlling expression of a iteration statement shall have scalar -type. -3.6.5.1 -label '%s' used, but not defined -The identifier in a goto statement shall name a label located -somewhere in the enclosing function. -3.6.6.1 -A continue statement shall appear only in or as a loop body -3.6.6.2 -A break statement shall appear only in or as a switch body or loop body -3.6.6.3 -A return statement with an expression should not appear -in a function '%s', whose return type is void -3.6.6.4(24) -A return statement without an expression appears in a -function '%s', whose return type is not void -If a return statement without an expression is executed, and the value -of the function call is used by the caller, the behavior is undefined. -3.6.6.4(33) -Internal Error: statement stack underflow -Long double not supported; double assumed. -Long float not standard; double assumed. -Only 'register' allowed in parameter declaration -The only storage-class specifier that shall occur in a parameter -declaration is 'register'; illegal storage class ignored. -3.5.4.3(25) -Name(s) without types in a function declaration -An old-style function declaration is not allowed to have names -in the parameter list; useless names ignored -3.5.4.3(26) -Functions cannot return functions -3.7.1(33), 3.3.2.2 -Functions cannot return a non-object type -3.3.2.2 -enum declaration must contain enum literals -Although structs or unions may delay the declaration of their members, -a similar construction with enum does not exist and is not necessary, -as there can be no mutual dependencies between the declaration of an -enumerated type and any other type. -3.5.2.3(27) -Register qualification has no effect for this type of object -Register declarations for array, struct, and function types have -no effect. -3.5.1(16), 3.5.1(19) -Functions cannot be declared 'register' -The declaration of an identifier for a function that has block -scope shall have no explicit storage-class specifier other than -'extern'. -3.5.1(19) -'%s' cannot be initialized -The type of the entity to be initialized shall be an object type -or an array of unknown size. -3.5.7(32) -Cannot initialize 'extern' variable '%s' within a function -If the declaration of an identifier has block scope, and the -identifier has 'extern' or 'static' linkage, the declaration -shall have no initializer for the identifier; initialization -allowed anyway. -3.5.7(35) -initializing an 'extern' is an ANSI C extension -conflicting declarations for '%s' -'static' and 'extern' declarations conflict. Which is meant? -3.1.2.2(15), 3.1.2.2(27) -Too many initial values for '%s' -3.5.7(1) -incompatible types in initialization -3.3.16(35) -redefinition of '%s'; previous definition at line %s in file '%s' -Identifier redeclared in the same scope/block. -3.1.2.3 -bit-fields as members of a union are an ANSI C invention. -storage size for '%s' isn't known -type mismatch in initialization -Missing braces in a union initialization or illegally formed -initialization. -3.5.7(5) -union '%s' only allowed one initializer for the first member -3.5.7(5) -width of '%s' exceeds its type -the specified bitfield width is too large to be contained within a -bitfield type. -structure has no member named '%s' -This is allowed for compatibility with AT&T pcc-based compilers. -Reference of an expression of void type or an incomplete type. -3.2.2.1 -element size of an array shall not be zero -3.2.2.5(25) -invalid combination of type specifiers -Although order is unimportant, not all type specifiers can occur together. -3.5.2 -declaration must at least declare an identifier, tag, or the member of an enumeration -3.5(16) -at most one storage class may be given in the declaration -Duplicate occurrence ignored. -3.5.1(10) -size of function's return type is zero -The return type of a function must be void or an object type other than array. -3.7.1(33) -Expecting an integral return type from the main function -identifier missing from parameter declaration -Prototypes for function definitions require identifiers in parameter -declarations. -3.7.1(4) -only 'register' allowed for storage class for parameters -The declarations in the declaration list shall contain no storage class -other than 'register', and no initializations. -3.7.1(10) -parameters declarations can not have initializations -3.7.1(10) -only one instance of 'void' allowed in the parameter list -'void' must occur by itself (specifying that the function has no parameters). -3.5.4.3(1) -%s must have function type -1) An argument list must be explicitly present in the declarator; it cannot - be inherited from a typedef (3.5.4.3). -2) The declarator is not a function. -3.7.1(30) -Illegal hexadecimal constant -You have no digits after the 0x or 0X. 0x0 assumed. -3.1.3.2 -value overflows its type in this context. Value is set to be '%s'! -3.2.1.4 -value is outside range representable for type '%s' -missing member name -K&R mode permits a missing member name; otherwise, only bitfields can omit -the member name. -3.5.2.1(10) -useless keyword or type name in declaration -Type was ignored. -'%s' declared within and is limited to this function prototype -Possible program error, since parameter type checking will always fail -unless the type declaration is visible to the caller. -3.1.2.1(35) -Extra spaces within operator, %s assumed -In ANSI C, the compound assignment operator cannot have embedded -white space characters. -3.1.5 -missing size for array '%s' -Incomplete types permitted for identifiers with internal or -external linkage, but not automatic linkage. -3.1.2.5(10) -can't jump into (from outside of) the body of a 'try' or into either type of handler -'%s' missing, please #include excpt.h -excpt.h required to declare exception statements, intrinsics or compiler -runtime names. -local function declarations cannot be 'static' -A function declaration can only contain the storage-class 'static' -if it is at file scope. Declaration made 'extern'. -3.5.1(19) -static function '%s' declared and referenced, but not defined. -If an identifier declared with internal linkage is used in an -expression (other than as a part of the operand of a sizeof -operator), there shall be exactly one external definition for -the identifier in the translation unit. -3.7(12) -pragma argument '%s' must be declared prior to being used in a pragma -Pragma name ignored. -Pragma not supported -'%s' not enabled as intrinsic -It may have already appeared in a function pragma, or never occurred in -an intrinsic pragma. -'%s' is already enabled as an intrinsic -weak definition for '%s' is later redefined; pragma weak ignored. -definition of primary name '%s' not found; pragma weak ignored. -definition of secondary name '%s' not found; pragma weak ignored. -primary name '%s' is declared as a common or external, and is not defined -with initial value within this file; pragma weak ignored. -useless '%s' storage class ignored -array of functions not allowed -The element type must be an object type representing a region -of data storage which can represent values. -3.1.2.5(23) -array of voids not allowed -The element type must be an object type representing a region -of data storage which can represent values. -3.1.2.5(23) -argument for pragma pack must be an integer constant; pragma ignored -'%s' has wrong tag type. -Identifier redeclared in the same scope/block. -3.1.2.3 -missing dimension bound -For multidimensional arrays, the constant bounds of the array may be -omitted only for the first member of the sequence. -3.1.2.5(23) -Internal error in parameters to function substr; loc: '%s'; len: '%s'. -Internal error in parameters to function insertstr; indx: '%s'. -Internal error in function get_tag_name; input is a non-tagged type. -Internal error in function gen_type_str -- not a type tree '%s' -Cannot open file '%s' -Prototype should be moved after tag or a typedef declaration. -Please look for comments in the extracted header file. -The extracted header file includes prototypes for static functions, -which should be removed, if you wish to include the header in a source file -other than the originator. -ANSI C requires formal parameter before "..." -This extension is meant to be used for compatibility with varargs.h -3.5.4.3(35) -syntax error: "&..." invalid -extension used to access "..." formal arguments. -function '%s' initialized like a variable -The type of entity to be initialized shall be an object type or an -array of unknown size. -3.5.7(31) -initializer not an array aggregate -The initializer for an object that has aggregate type shall be a -brace-enclosed list of initializers for the members of the aggregate, -written in increasing subscript or member order. -3.5.7(20) -'%s' type is incomplete; cannot initialize -Was the struct ever defined? -3.5.7.(31) -'%s' is not standard ANSI. -This keyword/type is not defined in strict ANSI mode. -3.1.1 -not a legal asm string -The first operand of an asm string should be, after argument substitution, -a legal assembly string. -The -float option will be ignored in ANSI mode. -The -float option is ignored, since otherwise program semantics would -violate the ANSI standard. In particular, fp constants are always -'double' with ANSI-C, while with -float the type of fp constants will -depend on the context and may be 'float'. -ANSI C support unavailable with C compiler bundled with RISC/os -The C compiler bundled with RISC/os does not support ANSI C. ANSI -C support requires a separate license. -Ignored invalid warning number(s) in -woff option, %s%s ! -Warning numbers must be in the range %s to %s. -The set of warning numbers in cfe is disjoint from the set of warning numbers -in accom, since accom warnings cannot be mapped one-to-one to cfe warnings. -'%s' not handled as an intrinsic due to incompatible argument types . -'__unalign' only qualifies pointers -'__unalign' indicates the object pointed at by pointer is unaligned (e.g., -int * __unalign p). This is an extension to ANSI C and like 'volatile' -and 'const' can follow the '*' in pointer declarations, but unlike both -cannot qualify a base type. -index expression is an anachronism -ANSI C++ doesn't support array index expressions in delete. -5.3.4 -member cannot be of function or incomplete type. -3.5.2.1(12) -Illegal lint option, '%s', is ignored. -cannot open header message buffer file -cannot write header message buffer file -cannot read header message buffer file -cannot seek in header message buffer file -struct/union/enum '%s' is used, but not defined -static '%s' unused -nonportable character comparison (chars may be signed or unsigned) -redundant comparison of unsigned with constant expression -redundant statement, control flow cannot reach this statement -'%s' may be used before set -function parameter '%s' is not used in function '%s' -'%s' can be const qualified, since it is not set within its lifetime. -'%s' is not used in function '%s' -'%s' set but unused in function '%s' -control may fall through %s statement -function '%s' has return(e); and return; -function '%s' may return random value to place of invocation %s -label without goto: '%s' -width of %s constant is smaller than size of type (%s) -explicit conversion from '%s' to '%s' %s -implicit conversion from '%s' to '%s' %s -'%s' may be indistinguishable from '%s' due to internal name truncation -Promoted formal parameter and promoted argument have incompatible types -No prototype for the definition of '%s' %s -References to '%s' are substituted by its literal initializer - (as included in %s) -============== -unsupported language linkage -string-literal specifies an unsupported linkage -7.4(1) -No prototype for the call to %s -To achieve better type-checking, there should be a full prototype for -the function being called. -3.5.4.3 -'inline' only applies to function declarations -leave statment can occur only within try body -Microsoft extension -Use of a Microsoft extension detected without usage of the -compiler option -msft. -No parameter mentioned -A file with no declarations or definitions is accepted as an extension to ANSI C -The translation unit must contain at least one external definition. -3.7 -Incompatible signed and unsigned version of a type -Yacc initialization error -Internal error: yacc cannot initialize itself. -The cfe option %s may not be in future releases. We suggest that you not use this option! -Incompatible char and unsigned char versions of a type -Lshift with undefined behaviour. -Lshift with a negative right operand, or a right operand that is greater -than or equal to the width in bits of the promoted left operand, results -in undefined behaviour. -3.3.7(11) -useless type name in declaration, possibly a semicolon is missing. -Type was ignored. -constant initializer expression is invalid (refers to automatic variables). -All the expressions in an initializer for an object that has static storage -duration or in the initializer list for an object that has aggregate or -union type shall be constant expressions. Otherwise, unexpected results -may occur. -3.5.7(32) and 3.4 -invalid explicit or implicit conversion of an address constant to an integral value in a constant initializing expression. -An address constant in a constant initializing expression can neither -initialize a bit-field nor be directly or indirectly converted to an -integral type of size different from an address type. -6.4 diff --git a/tools/ido5.3_compiler/usr/lib/libc.so.1 b/tools/ido5.3_compiler/usr/lib/libc.so.1 deleted file mode 100755 index 17495ef6..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/libc.so.1 and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/libexc.so b/tools/ido5.3_compiler/usr/lib/libexc.so deleted file mode 100644 index 209c5366..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/libexc.so and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/libgen.so b/tools/ido5.3_compiler/usr/lib/libgen.so deleted file mode 100644 index 7b8ec7fd..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/libgen.so and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/libm.so b/tools/ido5.3_compiler/usr/lib/libm.so deleted file mode 100644 index 05bf4781..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/libm.so and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/ugen b/tools/ido5.3_compiler/usr/lib/ugen deleted file mode 100755 index beb81f4b..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/ugen and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/ujoin b/tools/ido5.3_compiler/usr/lib/ujoin deleted file mode 100755 index 23a4cbbd..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/ujoin and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/uld b/tools/ido5.3_compiler/usr/lib/uld deleted file mode 100755 index bd182fdc..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/uld and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/umerge b/tools/ido5.3_compiler/usr/lib/umerge deleted file mode 100755 index e8e09e66..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/umerge and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/uopt b/tools/ido5.3_compiler/usr/lib/uopt deleted file mode 100755 index 5451428b..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/uopt and /dev/null differ diff --git a/tools/ido5.3_compiler/usr/lib/usplit b/tools/ido5.3_compiler/usr/lib/usplit deleted file mode 100755 index 112abfcd..00000000 Binary files a/tools/ido5.3_compiler/usr/lib/usplit and /dev/null differ diff --git a/tools/ido5.3_recomp/.gitignore b/tools/ido5.3_recomp/.gitignore deleted file mode 100644 index 6b747aba..00000000 --- a/tools/ido5.3_recomp/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -/recomp -/recomp-conservative - -/cc* -/cfe* -/uopt* -/ugen* -/as1* -/acpp* -/copt* -/ujoin* -/uld* -/umerge* -/usplit* - -/err.english.cc diff --git a/tools/ido5.3_recomp/Makefile b/tools/ido5.3_recomp/Makefile deleted file mode 100644 index 84a5de31..00000000 --- a/tools/ido5.3_recomp/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -IRIX_ROOT := ../ido5.3_compiler - -cc: OPT_CFLAGS := -O2 -cfe: OPT_CFLAGS := -O2 -uopt: OPT_CFLAGS := -O2 -ugen: OPT_CFLAGS := -O2 -as1: OPT_CFLAGS := -O2 -acpp: OPT_CFLAGS := -O2 - -RECOMP := recomp - -ugen_c.c: RECOMP_FLAGS := --conservative - -all: cc cfe uopt ugen as1 acpp copt ujoin uld umerge usplit err.english.cc - -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 -Wno-switch `pkg-config --cflags --libs capstone` - -libc_impl.o: libc_impl.c libc_impl.h - $(CC) $< -c -fno-strict-aliasing -O2 -DIDO53 - -err.english.cc: $(IRIX_ROOT)/usr/lib/err.english.cc - cp $^ $@ - -cc_c.c: $(IRIX_ROOT)/usr/bin/cc $(RECOMP) - ./$(RECOMP) $(RECOMP_FLAGS) $< > $@ - -%_c.c: $(IRIX_ROOT)/usr/lib/% $(RECOMP) - ./$(RECOMP) $(RECOMP_FLAGS) $< > $@ - -%: %_c.c libc_impl.o - $(CC) libc_impl.o $< -o $@ $(OPT_CFLAGS) -fno-strict-aliasing -lm -no-pie - -.PHONY: all clean diff --git a/tools/ido5.3_recomp/elf.h b/tools/ido5.3_recomp/elf.h deleted file mode 100644 index 91ba5fe2..00000000 --- a/tools/ido5.3_recomp/elf.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef ELF_H -#define ELF_H - -#include - -#define EI_DATA 5 -#define EI_NIDENT 16 -#define SHT_SYMTAB 2 -#define SHT_DYNAMIC 6 -#define SHT_REL 9 -#define SHT_DYNSYM 11 -#define SHT_MIPS_REGINFO 0x70000006 -#define STN_UNDEF 0 -#define STT_OBJECT 1 -#define STT_FUNC 2 -#define DT_PLTGOT 3 -#define DT_MIPS_LOCAL_GOTNO 0x7000000a -#define DT_MIPS_SYMTABNO 0x70000011 -#define DT_MIPS_GOTSYM 0x70000013 - -#define ELF32_R_SYM(info) ((info) >> 8) -#define ELF32_R_TYPE(info) ((info) & 0xff) - -#define ELF32_ST_TYPE(info) ((info) & 0xf) - -#define R_MIPS_26 4 -#define R_MIPS_HI16 5 -#define R_MIPS_LO16 6 - -#define SHN_UNDEF 0 -#define SHN_COMMON 0xfff2 -#define SHN_MIPS_ACOMMON 0xff00 -#define SHN_MIPS_TEXT 0xff01 -#define SHN_MIPS_DATA 0xff02 - -typedef uint32_t Elf32_Addr; -typedef uint32_t Elf32_Off; - -typedef struct { - uint8_t e_ident[EI_NIDENT]; - uint16_t e_type; - uint16_t e_machine; - uint32_t e_version; - Elf32_Addr e_entry; - Elf32_Off e_phoff; - Elf32_Off e_shoff; - uint32_t e_flags; - uint16_t e_ehsize; - uint16_t e_phentsize; - uint16_t e_phnum; - uint16_t e_shentsize; - uint16_t e_shnum; - uint16_t e_shstrndx; -} Elf32_Ehdr; - -typedef struct { - uint32_t sh_name; - uint32_t sh_type; - uint32_t sh_flags; - Elf32_Addr sh_addr; - Elf32_Off sh_offset; - uint32_t sh_size; - uint32_t sh_link; - uint32_t sh_info; - uint32_t sh_addralign; - uint32_t sh_entsize; -} Elf32_Shdr; - -typedef struct { - uint32_t st_name; - Elf32_Addr st_value; - uint32_t st_size; - uint8_t st_info; - uint8_t st_other; - uint16_t st_shndx; -} Elf32_Sym; - -typedef struct { - Elf32_Addr r_offset; - uint32_t r_info; -} Elf32_Rel; - -typedef struct -{ - uint32_t ri_gprmask; /* General registers used. */ - uint32_t ri_cprmask[4]; /* Coprocessor registers used. */ - int32_t ri_gp_value; /* $gp register value. */ -} Elf32_RegInfo; - -typedef struct -{ - int32_t d_tag; /* Dynamic entry type */ - union { - uint32_t d_val; /* Integer value */ - Elf32_Addr d_ptr; /* Address value */ - } d_un; -} Elf32_Dyn; - -#endif diff --git a/tools/ido5.3_recomp/header.h b/tools/ido5.3_recomp/header.h deleted file mode 100644 index b4cd0d31..00000000 --- a/tools/ido5.3_recomp/header.h +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "libc_impl.h" -#include "helpers.h" - -#define RM_RN 0 -#define RM_RZ 1 -#define RM_RP 2 -#define RM_RM 3 - -union FloatReg { - float f[2]; - uint32_t w[2]; - double d; -}; - -#define cvt_w_d(f) \ - ((fcsr & RM_RZ) ? ((isnan(f) || f <= -2147483649.0 || f >= 2147483648.0) ? (fcsr |= 0x40, 2147483647) : (int)f) : (assert(0), 0)) - -#define cvt_w_s(f) cvt_w_d((double)f) - -static union FloatReg f0 = {{0, 0}}, f2 = {{0, 0}}, f4 = {{0, 0}}, f6 = {{0, 0}}, f8 = {{0, 0}}, -f10 = {{0, 0}}, f12 = {{0, 0}}, f14 = {{0, 0}}, f16 = {{0, 0}}, f18 = {{0, 0}}, f20 = {{0, 0}}, -f22 = {{0, 0}}, f24 = {{0, 0}}, f26 = {{0, 0}}, f28 = {{0, 0}}, f30 = {{0, 0}}; -static uint32_t fcsr = 1; diff --git a/tools/ido5.3_recomp/helpers.h b/tools/ido5.3_recomp/helpers.h deleted file mode 100644 index b2bd2351..00000000 --- a/tools/ido5.3_recomp/helpers.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef HELPERS_H -#define HELPERS_H - -#include - -#define MEM_U32(a) (*(uint32_t *)(mem + a)) -#define MEM_S32(a) (*(int32_t *)(mem + a)) -#define MEM_U16(a) (*(uint16_t *)(mem + ((a) ^ 2))) -#define MEM_S16(a) (*(int16_t *)(mem + ((a) ^ 2))) -#define MEM_U8(a) (*(uint8_t *)(mem + ((a) ^ 3))) -#define MEM_S8(a) (*(int8_t *)(mem + ((a) ^ 3))) - -#endif diff --git a/tools/ido5.3_recomp/libc_impl.c b/tools/ido5.3_recomp/libc_impl.c deleted file mode 100644 index 929d58fa..00000000 --- a/tools/ido5.3_recomp/libc_impl.c +++ /dev/null @@ -1,2543 +0,0 @@ -#define _GNU_SOURCE // for sigset -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __CYGWIN__ -#include -#endif -#ifdef __APPLE__ - #include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libc_impl.h" -#include "helpers.h" - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - -#define STRING(param) size_t param##_len = wrapper_strlen(mem, param##_addr); \ - char param[param##_len + 1]; \ - for (size_t i = 0; i <= param##_len; i++) { \ - param[i] = MEM_S8(param##_addr + i); \ - } - -#if !defined(IDO53) && !defined(IDO71) -#define IDO71 -#endif - -#define MEM_REGION_START 0xfb00000 -#define MEM_REGION_SIZE (512 * 1024 * 1024) - -#ifdef IDO53 -// IDO 5.3 -#define IOB_ADDR 0x0fb528e4 -#define ERRNO_ADDR 0x0fb52720 -#define CTYPE_ADDR 0x0fb504f0 -#define LIBC_ADDR 0x0fb50000 -#define LIBC_SIZE 0x3000 -#endif - -#ifdef IDO71 -// IDO 7.1 -#define IOB_ADDR 0x0fb4ee44 -#define ERRNO_ADDR 0x0fb4ec80 -#define CTYPE_ADDR 0x0fb4cba0 -#define LIBC_ADDR 0x0fb4c000 -#define LIBC_SIZE 0x3000 -#endif - -#define STDIN_ADDR IOB_ADDR -#define STDOUT_ADDR (IOB_ADDR + 0x10) -#define STDERR_ADDR (IOB_ADDR + 0x20) -#define STDIN ((struct FILE_irix *)&MEM_U32(STDIN_ADDR)) -#define STDOUT ((struct FILE_irix *)&MEM_U32(STDOUT_ADDR)) -#define STDERR ((struct FILE_irix *)&MEM_U32(STDERR_ADDR)) - -#define MALLOC_BINS_ADDR custom_libc_data_addr -#define STRTOK_DATA_ADDR (MALLOC_BINS_ADDR + (30 - 3) * 4) -#define INTBUF_ADDR (STRTOK_DATA_ADDR + 4) - -#define SIGNAL_HANDLER_STACK_START LIBC_ADDR - -#define NFILE 100 - -#define IOFBF 0000 /* full buffered */ -#define IOLBF 0100 /* line buffered */ -#define IONBF 0004 /* not buffered */ -#define IOEOF 0020 /* EOF reached on read */ -#define IOERR 0040 /* I/O error from system */ - -#define IOREAD 0001 /* currently reading */ -#define IOWRT 0002 /* currently writing */ -#define IORW 0200 /* opened for reading and writing */ -#define IOMYBUF 0010 /* stdio malloc()'d buffer */ - -#define STDIO_BUFSIZE 16384 - -struct timespec_t_irix { - int tv_sec; - int tv_nsec; -}; - -struct FILE_irix { - int _cnt; - uint32_t _ptr_addr; - uint32_t _base_addr; - uint8_t pad[2]; - uint8_t _file; - uint8_t _flag; -}; - -static struct { - struct { - uint64_t (*trampoline)(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest); - uint8_t *mem; - uint32_t fp_dest; - } handlers[65]; - volatile uint32_t recursion_level; -} signal_context; - -static uint32_t cur_sbrk; -static uint32_t bufendtab[NFILE]; // this version contains the size and not the end ptr -static uint32_t custom_libc_data_addr; - -#define _U 01 /* Upper case */ -#define _L 02 /* Lower case */ -#define _N 04 /* Numeral (digit) */ -#define _S 010 /* Spacing character */ -#define _P 020 /* Punctuation */ -#define _C 040 /* Control character */ -#define _B 0100 /* Blank */ -#define _X 0200 /* heXadecimal digit */ - -static char ctype[] = { 0, - -/* 0 1 2 3 4 5 6 7 */ - -/* 0*/ _C, _C, _C, _C, _C, _C, _C, _C, -/* 10*/ _C, _S|_C, _S|_C, _S|_C, _S|_C, _S|_C, _C, _C, -/* 20*/ _C, _C, _C, _C, _C, _C, _C, _C, -/* 30*/ _C, _C, _C, _C, _C, _C, _C, _C, -/* 40*/ _S|_B, _P, _P, _P, _P, _P, _P, _P, -/* 50*/ _P, _P, _P, _P, _P, _P, _P, _P, -/* 60*/ _N|_X, _N|_X, _N|_X, _N|_X, _N|_X, _N|_X, _N|_X, _N|_X, -/* 70*/ _N|_X, _N|_X, _P, _P, _P, _P, _P, _P, -/*100*/ _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, -/*110*/ _U, _U, _U, _U, _U, _U, _U, _U, -/*120*/ _U, _U, _U, _U, _U, _U, _U, _U, -/*130*/ _U, _U, _U, _P, _P, _P, _P, _P, -/*140*/ _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, -/*150*/ _L, _L, _L, _L, _L, _L, _L, _L, -/*160*/ _L, _L, _L, _L, _L, _L, _L, _L, -/*170*/ _L, _L, _L, _P, _P, _P, _P, _C, -/*200*/ 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -#define REDIRECT_USR_LIB - -#ifdef REDIRECT_USR_LIB -static char bin_dir[PATH_MAX + 1]; -#endif -static int g_file_max = 3; - -#ifdef __CYGWIN__ -static size_t g_Pagesize; -#endif - -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 - if (mem == MAP_FAILED) { - perror("mmap"); - exit(1); - } - return mem; -} - -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); -#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); - - if(mprotect((void*)_start, _end - _start, PROT_READ | PROT_WRITE) < 0) { - perror("mprotect"); - 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"); - exit(1); - } -#endif -} - -static void memory_unmap(uint8_t *mem, size_t length) -{ - if (munmap(mem, length)) { - perror("munmap"); - exit(1); - } -} - - -static void free_all_file_bufs(uint8_t *mem) { - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(IOB_ADDR); - for (int i = 0; i < g_file_max; i++) { - if (f[i]._flag & IOMYBUF) { - wrapper_free(mem, f[i]._base_addr); - } - } -} - -static void find_bin_dir(void) { -#ifdef REDIRECT_USR_LIB - // gets the current executable's path - char path[PATH_MAX + 1] = {0}; -#ifdef __CYGWIN__ - uint32_t size = GetModuleFileName(NULL, path, PATH_MAX); - if (size == 0 || size == PATH_MAX) { - return; - } -#elif defined __APPLE__ - uint32_t size = PATH_MAX; - if (_NSGetExecutablePath(path, &size) < 0) { - return; - } -#else - ssize_t size = readlink("/proc/self/exe", path, PATH_MAX); - if (size < 0 || size == PATH_MAX) { - return; - } -#endif - - strcpy(bin_dir, dirname(path)); -#endif -} - -int main(int argc, char *argv[]) { - int ret; - - find_bin_dir(); - - uint8_t *mem = memory_map(MEM_REGION_SIZE); - mem -= MEM_REGION_START; - int run(uint8_t *mem, int argc, char *argv[]); - ret = run(mem, argc, argv); - wrapper_fflush(mem, 0); - free_all_file_bufs(mem); - mem += MEM_REGION_START; - memory_unmap(mem, MEM_REGION_SIZE); - return ret; -} - -void mmap_initial_data_range(uint8_t *mem, uint32_t start, uint32_t end) { - custom_libc_data_addr = end; - end += 4096; - memory_allocate(mem, start, end); - cur_sbrk = end; -} - -void setup_libc_data(uint8_t *mem) { - memory_allocate(mem, LIBC_ADDR, (LIBC_ADDR + LIBC_SIZE)); - for (size_t i = 0; i < sizeof(ctype); i++) { - MEM_S8(CTYPE_ADDR + i) = ctype[i]; - } - STDIN->_flag = IOREAD; - STDIN->_file = 0; - STDOUT->_flag = IOWRT; - STDOUT->_file = 1; - STDERR->_flag = IOWRT | IONBF; - STDERR->_file = 2; -} - -static uint32_t strcpy1(uint8_t *mem, uint32_t dest_addr, const char *str) { - for (;;) { - char c = *str; - ++str; - MEM_S8(dest_addr) = c; - ++dest_addr; - if (c == '\0') { - return dest_addr - 1; - } - } -} - -static uint32_t strcpy2(uint8_t *mem, uint32_t dest_addr, uint32_t src_addr) { - for (;;) { - char c = MEM_S8(src_addr); - ++src_addr; - MEM_S8(dest_addr) = c; - ++dest_addr; - if (c == '\0') { - return dest_addr - 1; - } - } -} - -uint32_t wrapper_sbrk(uint8_t *mem, int increment) { - uint32_t old = cur_sbrk; - memory_allocate(mem, old, (old + increment)); - cur_sbrk += increment; - return old; -} - -#if 0 -uint32_t wrapper_malloc(uint8_t *mem, uint32_t size) { - uint32_t orig_size = size; - size += 8; - size = (size + 0xfff) & ~0xfff; - uint32_t ret = wrapper_sbrk(mem, size); - MEM_U32(ret) = orig_size; - return ret + 8; -} - -uint32_t wrapper_calloc(uint8_t *mem, uint32_t num, uint32_t size) { - uint64_t new_size = (uint64_t)num * size; - assert(new_size == (uint32_t)new_size); - uint32_t ret = wrapper_malloc(mem, new_size); - return wrapper_memset(mem, ret, 0, new_size); -} - -uint32_t wrapper_realloc(uint8_t *mem, uint32_t data_addr, uint32_t size) { - if (data_addr == 0) { - return wrapper_malloc(mem, size); - } - uint32_t orig_size = MEM_U32(data_addr - 8); - if (size < orig_size || orig_size < 4088 && size < 4088) { - MEM_U32(data_addr - 8) = size; - return data_addr; - } - uint32_t new_addr = wrapper_malloc(mem, size); - return wrapper_memcpy(mem, new_addr, data_addr, MIN(size, orig_size)); -} - -void wrapper_free(uint8_t *mem, uint32_t data_addr) { - // NOP -} -#else - -/* -Simple bin-based malloc algorithm - -The memory is divided into bins of item sizes 8, 16, 32, 64, 128, ..., 2^30. -Size requests are divided into these bin sizes and each bin is handled -completely separate from other bins. - -For each bin there is a linked list of free'd items. -Linked list node: -struct FreeListNode { - struct Node *next; - size_t free_space_after; - uint8_t data[bin_item_size]; -}; -At most one value of next and space_after is non-zero. -If a node exists in the linked list, it is the memory node to return. -struct AllocatedNode { - int bin; - uint32_t current_size; - uint8_t data[bin_item_size]; -}; -The returned address is the data element. -When the last list node is returned, and free_space_after is big enough -for a new node, a new node is created having free_space_after set to -(free_space_after - (8 + bin_item_size)), and is appended to the list. - -If the list was empty, a new memory chunk is requested from the system -of 65536 bytes, or at least (8 + bin_item_size), rounded up to nearest -page size boundary. It can also be smaller if it leaves holes bigger than -4096 bytes that can never be used. This chunk is then inserted to the list, -and the algorithm restarts. - -This algorithm, for each bin, never uses more than twice as much as is -maximally in use (plus 65536 bytes). -The malloc/free calls run in O(1) and calloc/realloc calls run in O(size). -*/ - -size_t mem_used; -size_t mem_allocated; -size_t max_mem_used; -size_t num_sbrks; -size_t num_allocs; -uint32_t wrapper_malloc(uint8_t *mem, uint32_t size) { - int bin = -1; - for (int i = 3; i < 30; i++) { - if (size <= (1 << i)) { - bin = i; - break; - } - } - if (bin == -1) { - return 0; - } - ++num_allocs; - mem_used += size; - max_mem_used = MAX(mem_used, max_mem_used); - uint32_t item_size = 1 << bin; - uint32_t list_ptr = MALLOC_BINS_ADDR + (bin - 3) * 4; - uint32_t node_ptr = MEM_U32(list_ptr); - if (node_ptr == 0) { - uint32_t sbrk_request = 0x10000; - if (8 + item_size > sbrk_request) { - sbrk_request = 8 + item_size; - sbrk_request = (sbrk_request + 0xfff) & ~0xfff; - } - uint32_t left_over = sbrk_request % (8 + item_size); - sbrk_request -= left_over & ~0xfff; - mem_allocated += sbrk_request; - ++num_sbrks; - node_ptr = wrapper_sbrk(mem, sbrk_request); - MEM_U32(node_ptr + 4) = sbrk_request - (8 + item_size); - } - uint32_t next = MEM_U32(node_ptr); - if (next == 0) { - uint32_t free_space_after = MEM_U32(node_ptr + 4); - if (free_space_after >= 8 + item_size) { - next = node_ptr + 8 + item_size; - MEM_U32(next + 4) = free_space_after - (8 + item_size); - } - } else { - assert(MEM_U32(node_ptr + 4) == 0); - } - MEM_U32(list_ptr) = next; - MEM_U32(node_ptr) = bin; - MEM_U32(node_ptr + 4) = size; - return node_ptr + 8; -} - -uint32_t wrapper_calloc(uint8_t *mem, uint32_t num, uint32_t size) { - uint64_t new_size = (uint64_t)num * size; - assert(new_size == (uint32_t)new_size); - uint32_t ret = wrapper_malloc(mem, new_size); - return wrapper_memset(mem, ret, 0, new_size); -} - -uint32_t wrapper_realloc(uint8_t *mem, uint32_t data_addr, uint32_t size) { - if (data_addr == 0) { - return wrapper_malloc(mem, size); - } else { - uint32_t node_ptr = data_addr - 8; - int bin = MEM_U32(node_ptr); - uint32_t old_size = MEM_U32(node_ptr + 4); - uint32_t max_size = 1 << bin; - assert(bin >= 3 && bin < 30); - assert(old_size <= max_size); - if (size <= max_size) { - mem_used = mem_used - old_size + size; - MEM_U32(node_ptr + 4) = size; - return data_addr; - } else { - uint32_t new_addr = wrapper_malloc(mem, size); - wrapper_memcpy(mem, new_addr, data_addr, old_size); - wrapper_free(mem, data_addr); - return new_addr; - } - } -} - -void wrapper_free(uint8_t *mem, uint32_t data_addr) { - uint32_t node_ptr = data_addr - 8; - int bin = MEM_U32(node_ptr); - uint32_t size = MEM_U32(node_ptr + 4); - uint32_t list_ptr = MALLOC_BINS_ADDR + (bin - 3) * 4; - assert(bin >= 3 && bin < 30); - assert(size <= (1 << bin)); - MEM_U32(node_ptr) = MEM_U32(list_ptr); - MEM_U32(node_ptr + 4) = 0; - MEM_U32(list_ptr) = node_ptr; - mem_used -= size; -} -#endif - -int wrapper_fscanf(uint8_t *mem, uint32_t fp_addr, uint32_t format_addr, uint32_t sp) { - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr); - STRING(format) // for debug - - int ret = 0; - char c; - int ch; - sp += 2 * 4; - for (;;) { - c = MEM_S8(format_addr); - ++format_addr; - if (c == '%') { - c = MEM_S8(format_addr); - ++format_addr; - if (c == '%') { - goto percent; - } - for (;;) { - ch = wrapper_fgetc(mem, fp_addr); - if (ch == -1) { - return ret; - } - if (!isspace(ch)) { - //wrapper_ungetc(mem, ch, fp_addr); - break; - } - } - bool l = false; - continue_format: - switch (c) { - case 'l': - assert(!l && "ll not implemented in fscanf"); - l = true; - c = MEM_S8(format_addr); - ++format_addr; - goto continue_format; - case 'd': - { - int64_t num = 0; - int sign = 1; - bool found_first = false; - if (ch == '-') { - sign = -1; - ch = wrapper_fgetc(mem, fp_addr); - if (ch == -1) { - return ret; - } - } - for (;;) { - if (isdigit(ch)) { - num *= 10; - num += ch - '0'; - found_first = true; - ch = wrapper_fgetc(mem, fp_addr); - if (ch == -1) { - break; - } - } else { - wrapper_ungetc(mem, ch, fp_addr); - break; - } - } - if (found_first) { - uint32_t int_addr = MEM_U32(sp); - sp += 4; - MEM_S32(int_addr) = (int)(num * sign); - ++ret; - } else { - return ret; - } - break; - } - default: - assert(0 && "fscanf format not implemented"); - } - } else if (c == '\0') { - break; - } else { - percent: - ch = wrapper_fgetc(mem, fp_addr); - if (ch == -1) { - break; - } - if ((char)ch != c) { - break; - } - } - } - - return ret; -} - -int wrapper_printf(uint8_t *mem, uint32_t format_addr, uint32_t sp) { - STRING(format) - if (!strcmp(format, " child died due to signal %d.\n")) { - printf(format, MEM_U32(sp + 4)); - return 1; - } - assert(0 && "printf not implemented"); - return 0; -} - -int wrapper_sprintf(uint8_t *mem, uint32_t str_addr, uint32_t format_addr, uint32_t sp) { - STRING(format) // for debug - char temp[32]; - - if (!strcmp(format, "%.16e")) { - union { - uint32_t w[2]; - double d; - } d; - d.w[1] = MEM_U32(sp + 2 * 4); - d.w[0] = MEM_U32(sp + 3 * 4); - sprintf(temp, "%.16e", d.d); - strcpy1(mem, str_addr, temp); - return 1; - } - if (!strcmp(format, "\\%03o")) { - sprintf(temp, "\\%03o", MEM_U32(sp + 2 * 4)); - strcpy1(mem, str_addr, temp); - return 1; - } - if (!strcmp(format, "%*ld=")) { - sprintf(temp, "%*d=", MEM_U32(sp + 2 * 4), MEM_U32(sp + 3 * 4)); - strcpy1(mem, str_addr, temp); - return 1; - } - - uint32_t orig_str_addr = str_addr; - uint32_t pos = 0; - int ret = 0; - char c; - sp += 2 * 4; - for (;;) { - c = MEM_S8(format_addr + pos); - ++pos; - if (c == '%') { - bool l = false; - c = MEM_S8(format_addr + pos); - ++pos; - uint32_t zeros = 0; - bool zero_prefix = false; - continue_format: - switch (c) { - case '0': - do { - c = MEM_S8(format_addr + pos); - ++pos; - if (c >= '0' && c <= '9') { - zeros *= 10; - zeros += c - '0'; - } - } while (c >= '0' && c <= '9'); - goto continue_format; - case '#': - c = MEM_S8(format_addr + pos); - ++pos; - zero_prefix = true; - goto continue_format; - break; - case 'l': - assert(!l && "ll not implemented in fscanf"); - c = MEM_S8(format_addr + pos); - ++pos; - l = true; - goto continue_format; - break; - case 'd': - if (zeros != 0) { - char temp1[32]; - sprintf(temp1, "%%0%dd", zeros); - sprintf(temp, temp1, MEM_S32(sp)); - } else { - sprintf(temp, "%d", MEM_S32(sp)); - } - sp += 4; - str_addr = strcpy1(mem, str_addr, temp); - ++ret; - break; - case 'o': - if (zero_prefix) { - sprintf(temp, "%#o", MEM_S32(sp)); - } else { - sprintf(temp, "%o", MEM_S32(sp)); - } - sp += 4; - str_addr = strcpy1(mem, str_addr, temp); - ++ret; - break; - case 'x': - if (zero_prefix) { - sprintf(temp, "%#x", MEM_S32(sp)); - } else { - sprintf(temp, "%x", MEM_S32(sp)); - } - sp += 4; - str_addr = strcpy1(mem, str_addr, temp); - ++ret; - break; - case 'u': - sprintf(temp, "%u", MEM_S32(sp)); - sp += 4; - str_addr = strcpy1(mem, str_addr, temp); - ++ret; - break; - case 's': - str_addr = strcpy2(mem, str_addr, MEM_U32(sp)); - sp += 4; - ++ret; - break; - case 'c': - MEM_S8(str_addr) = (char)MEM_U32(sp); - ++str_addr; - sp += 4; - ++ret; - break; - case '%': - MEM_S8(str_addr) = '%'; - ++str_addr; - break; - default: - fprintf(stderr, "%s\n", format); - assert(0 && "non-implemented sprintf format"); - } - } else if (c == '\0') { - break; - } else { - MEM_S8(str_addr) = c; - ++str_addr; - } - } - - MEM_S8(str_addr) = '\0'; - STRING(orig_str) // for debug - //printf("result: '%s' '%s'\n", format, orig_str); - return ret; -} - -int wrapper_fprintf(uint8_t *mem, uint32_t fp_addr, uint32_t format_addr, uint32_t sp) { - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr); - STRING(format) - sp += 8; - /*if (!strcmp(format, "%s")) { - uint32_t s_addr = MEM_U32(sp); - STRING(s) - if (fp_addr == STDERR_ADDR) { - fprintf(stderr, "%s", s); - fflush(stderr); - return 1; - } - } - if (!strcmp(format, "%s: %s: ")) { - uint32_t s1_addr = MEM_U32(sp), s2_addr = MEM_U32(sp + 4); - STRING(s1) - STRING(s2) - if (fp_addr == STDERR_ADDR) { - fprintf(stderr, "%s: %s: ", s1, s2); - fflush(stderr); - return 1; - } - }*/ - int ret = 0; - for (;;) { - uint32_t pos = format_addr; - char ch = MEM_S8(pos); - while (ch != '%' && ch != '\0') { - ++pos; - ch = MEM_S8(pos); - } - if (format_addr != pos) { - if (wrapper_fwrite(mem, format_addr, 1, pos - format_addr, fp_addr) != pos - format_addr) { - break; - } - } - if (ch == '\0') { - break; - } - ++pos; - ch = MEM_S8(pos); - switch (ch) { - case 'd': - { - char buf[32]; - sprintf(buf, "%d", MEM_U32(sp)); - strcpy1(mem, INTBUF_ADDR, buf); - if (wrapper_fputs(mem, INTBUF_ADDR, fp_addr) == -1) { - return ret; - } - sp += 4; - ++ret; - break; - } - case 's': - { - if (wrapper_fputs(mem, MEM_U32(sp), fp_addr) == -1) { - return ret; - } - sp += 4; - ++ret; - break; - } - case 'c': - { - char buf[32]; - sprintf(buf, "%c", MEM_U32(sp)); - strcpy1(mem, INTBUF_ADDR, buf); - if (wrapper_fputs(mem, INTBUF_ADDR, fp_addr) == -1) { - return ret; - } - sp += 4; - ++ret; - break; - } - default: - fprintf(stderr, "missing format: '%s'\n", format); - assert(0 && "non-implemented fprintf format"); - } - format_addr = ++pos; - } - return ret; -} - -int wrapper__doprnt(uint8_t *mem, uint32_t format_addr, uint32_t params_addr, uint32_t fp_addr) { - assert(0 && "_doprnt not implemented"); - return 0; -} - -uint32_t wrapper_strlen(uint8_t *mem, uint32_t str_addr) { - uint32_t len = 0; - while (MEM_S8(str_addr) != '\0') { - ++str_addr; - ++len; - } - return len; -} - -int wrapper_open(uint8_t *mem, uint32_t pathname_addr, int flags, int mode) { - STRING(pathname) - int f = flags & O_ACCMODE; - if (flags & 0x100) { - f |= O_CREAT; - } - if (flags & 0x200) { - f |= O_TRUNC; - } - if (flags & 0x400) { - f |= O_EXCL; - } - if (flags & 0x800) { - f |= O_NOCTTY; - } - if (flags & 0x08) { - f |= O_APPEND; - } - int fd = open(pathname, f, mode); - MEM_U32(ERRNO_ADDR) = errno; - return fd; -} - -int wrapper_creat(uint8_t *mem, uint32_t pathname_addr, int mode) { - STRING(pathname) - int ret = creat(pathname, mode); - if (ret < 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -int wrapper_access(uint8_t *mem, uint32_t pathname_addr, int mode) { - STRING(pathname) - int ret = access(pathname, mode); - if (ret != 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -int wrapper_rename(uint8_t *mem, uint32_t oldpath_addr, uint32_t newpath_addr) { - STRING(oldpath) - STRING(newpath) - int ret = rename(oldpath, newpath); - if (ret != 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -int wrapper_utime(uint8_t *mem, uint32_t filename_addr, uint32_t times_addr) { - STRING(filename) - struct utimbuf buf = {0, 0}; - int ret = utime(filename, times_addr == 0 ? NULL : &buf); - if (ret == 0) { - if (times_addr != 0) { - MEM_U32(times_addr + 0) = buf.actime; - MEM_U32(times_addr + 4) = buf.modtime; - } - } else { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -int wrapper_flock(uint8_t *mem, int fd, int operation) { - int ret = flock(fd, operation); - if (ret != 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -int wrapper_chmod(uint8_t *mem, uint32_t path_addr, uint32_t mode) { - STRING(path) - int ret = chmod(path, mode); - if (ret < 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -int wrapper_umask(int mode) { - return umask(mode); -} - -uint32_t wrapper_ecvt(uint8_t *mem, double number, int ndigits, uint32_t decpt_addr, uint32_t sign_addr) { - assert(0); -} - -uint32_t wrapper_fcvt(uint8_t *mem, double number, int ndigits, uint32_t decpt_addr, uint32_t sign_addr) { - assert(0); -} - -double wrapper_sqrt(double v) { - return sqrt(v); -} - -float wrapper_sqrtf(float v) { - return sqrtf(v); -} - -int wrapper_atoi(uint8_t *mem, uint32_t nptr_addr) { - STRING(nptr) - return atoi(nptr); -} - -int wrapper_atol(uint8_t *mem, uint32_t nptr_addr) { - return wrapper_atoi(mem, nptr_addr); -} - -double wrapper_atof(uint8_t *mem, uint32_t nptr_addr) { - STRING(nptr); - return atof(nptr); -} - -int wrapper_strtol(uint8_t *mem, uint32_t nptr_addr, uint32_t endptr_addr, int base) { - STRING(nptr) - char *endptr = NULL; - int64_t res = strtoll(nptr, endptr_addr != 0 ? &endptr : NULL, base); - if (res > INT_MAX) { - MEM_U32(ERRNO_ADDR) = ERANGE; - res = INT_MAX; - } - if (res < INT_MIN) { - MEM_U32(ERRNO_ADDR) = ERANGE; - res = INT_MIN; - } - if (endptr != NULL) { - MEM_U32(endptr_addr) = nptr_addr + (uint32_t)(endptr - nptr); - } - return res; -} - -uint32_t wrapper_strtoul(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 (res > INT_MAX) { - MEM_U32(ERRNO_ADDR) = ERANGE; - res = INT_MAX; - } - 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; - errno = 0; - double res = strtod(nptr, endptr_addr != 0 ? &endptr : NULL); - if (errno != 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - if (endptr != NULL) { - MEM_U32(endptr_addr) = nptr_addr + (uint32_t)(endptr - nptr); - } - return res; -} - -uint32_t wrapper_strchr(uint8_t *mem, uint32_t str_addr, int c) { - c = c & 0xff; - for (;;) { - unsigned char ch = MEM_U8(str_addr); - if (ch == c) { - return str_addr; - } - if (ch == '\0') { - return 0; - } - ++str_addr; - } -} - -uint32_t wrapper_strrchr(uint8_t *mem, uint32_t str_addr, int c) { - c = c & 0xff; - uint32_t ret = 0; - for (;;) { - unsigned char ch = MEM_U8(str_addr); - if (ch == c) { - ret = str_addr; - } - if (ch == '\0') { - return ret; - } - ++str_addr; - } -} - -uint32_t wrapper_strcspn(uint8_t *mem, uint32_t str_addr, uint32_t invalid_addr) { - STRING(invalid) - uint32_t n = strlen(invalid); - uint32_t pos = 0; - char c; - while ((c = MEM_S8(str_addr)) != 0) { - for (int i = 0; i < n; i++) { - if (c == invalid[i]) { - return pos; - } - } - ++pos; - ++str_addr; - } - return pos; -} - -uint32_t wrapper_strpbrk(uint8_t *mem, uint32_t str_addr, uint32_t accept_addr) { - STRING(accept) - uint32_t n = strlen(accept); - char c; - while ((c = MEM_S8(str_addr)) != 0) { - for (int i = 0; i < n; i++) { - if (c == accept[i]) { - return str_addr; - } - } - ++str_addr; - } - return 0; -} - -static void stat_common(uint8_t *mem, uint32_t buf_addr, struct stat *statbuf) { - struct irix_stat { - int st_dev; - int pad1[3]; - int st_ino; - int st_mode; - int st_nlink; - int st_uid; - int st_gid; - int st_rdev; - int pad2[2]; - int st_size; - int pad3; - struct timespec_t_irix st_atim; - struct timespec_t_irix st_mtim; - struct timespec_t_irix st_ctim; - int st_blksize; - int st_blocks; - } s; - s.st_dev = statbuf->st_dev; - s.st_ino = statbuf->st_ino; - s.st_mode = statbuf->st_mode; - s.st_nlink = statbuf->st_nlink; - s.st_uid = statbuf->st_uid; - s.st_gid = statbuf->st_gid; - s.st_rdev = statbuf->st_rdev; - s.st_size = statbuf->st_size; -#ifdef __APPLE__ - s.st_atim.tv_sec = statbuf->st_atimespec.tv_sec; - s.st_atim.tv_nsec = statbuf->st_atimespec.tv_nsec; - s.st_mtim.tv_sec = statbuf->st_mtimespec.tv_sec; - s.st_mtim.tv_nsec = statbuf->st_mtimespec.tv_nsec; - s.st_ctim.tv_sec = statbuf->st_ctimespec.tv_sec; - s.st_ctim.tv_nsec = statbuf->st_ctimespec.tv_nsec; -#else - s.st_atim.tv_sec = statbuf->st_atim.tv_sec; - s.st_atim.tv_nsec = statbuf->st_atim.tv_nsec; - s.st_mtim.tv_sec = statbuf->st_mtim.tv_sec; - s.st_mtim.tv_nsec = statbuf->st_mtim.tv_nsec; - s.st_ctim.tv_sec = statbuf->st_ctim.tv_sec; - s.st_ctim.tv_nsec = statbuf->st_ctim.tv_nsec; -#endif - memcpy(&MEM_U32(buf_addr), &s, sizeof(s)); -} - -int wrapper_fstat(uint8_t *mem, int fildes, uint32_t buf_addr) { - struct stat statbuf; - if (fstat(fildes, &statbuf) < 0) { - MEM_U32(ERRNO_ADDR) = errno; - return -1; - } else { - stat_common(mem, buf_addr, &statbuf); - return 0; - } -} - -int wrapper_stat(uint8_t *mem, uint32_t pathname_addr, uint32_t buf_addr) { - STRING(pathname) - struct stat statbuf; - if (stat(pathname, &statbuf) < 0) { - MEM_U32(ERRNO_ADDR) = errno; - return -1; - } else { - stat_common(mem, buf_addr, &statbuf); - return 0; - } -} - -int wrapper_ftruncate(uint8_t *mem, int fd, int length) { - int ret = ftruncate(fd, length); - if (ret != 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -void wrapper_bcopy(uint8_t *mem, uint32_t src_addr, uint32_t dst_addr, uint32_t len) { - wrapper_memcpy(mem, dst_addr, src_addr, len); -} - -uint32_t wrapper_memcpy(uint8_t *mem, uint32_t dst_addr, uint32_t src_addr, uint32_t len) { - uint32_t saved = dst_addr; - if (dst_addr % 4 == 0 && src_addr % 4 == 0 && len % 4 == 0) { - memcpy(&MEM_U32(dst_addr), &MEM_U32(src_addr), len); - } else { - while (len--) { - MEM_U8(dst_addr) = MEM_U8(src_addr); - ++dst_addr; - ++src_addr; - } - } - return saved; -} - -uint32_t wrapper_memccpy(uint8_t *mem, uint32_t dst_addr, uint32_t src_addr, int c, uint32_t len) { - while (len--) { - uint8_t ch = MEM_U8(src_addr); - MEM_U8(dst_addr) = ch; - ++dst_addr; - ++src_addr; - if (ch == c) { - return dst_addr; - } - } - return 0; -} - -int wrapper_read(uint8_t *mem, int fd, uint32_t buf_addr, uint32_t nbytes) { - uint8_t *buf = (uint8_t *)malloc(nbytes); - ssize_t ret = read(fd, buf, nbytes); - if (ret < 0) { - MEM_U32(ERRNO_ADDR) = errno; - } else { - for (ssize_t i = 0; i < ret; i++) { - MEM_U8(buf_addr + i) = buf[i]; - } - } - free(buf); - return (int)ret; -} - -int wrapper_write(uint8_t *mem, int fd, uint32_t buf_addr, uint32_t nbytes) { - uint8_t *buf = (uint8_t *)malloc(nbytes); - for (size_t i = 0; i < nbytes; i++) { - buf[i] = MEM_U8(buf_addr + i); - } - ssize_t ret = write(fd, buf, nbytes); - if (ret < 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - free(buf); - return (int)ret; -} - -static uint32_t init_file(uint8_t *mem, int fd, int i, const char *path, const char *mode) { - int flags = O_RDONLY; - if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0) { - flags = O_RDONLY; - } else if (strcmp(mode, "w") == 0 || strcmp(mode, "wb") == 0) { - flags = O_WRONLY | O_CREAT | O_TRUNC; - } else if (strcmp(mode, "a") == 0 || strcmp(mode, "ab") == 0) { - flags = O_WRONLY | O_CREAT | O_APPEND; - } else if (strcmp(mode, "r+") == 0 || strcmp(mode, "r+b") == 0) { - flags = O_RDWR; - } else if (strcmp(mode, "w+") == 0 || strcmp(mode, "w+b") == 0) { - flags = O_RDWR | O_CREAT | O_TRUNC; - } else if (strcmp(mode, "a+") == 0 || strcmp(mode, "a+b") == 0) { - flags = O_RDWR | O_CREAT | O_APPEND; - } - if (fd == -1) { - -#ifdef REDIRECT_USR_LIB - char fixed_path[PATH_MAX + 1]; - if (!strcmp(path, "/usr/lib/err.english.cc") && bin_dir[0] != '\0') { - int n = snprintf(fixed_path, sizeof(fixed_path), "%s/err.english.cc", bin_dir); - if (n >= 0 && n < sizeof(fixed_path)) { - path = fixed_path; - } - } -#endif - fd = open(path, flags, 0666); - if (fd < 0) { - MEM_U32(ERRNO_ADDR) = errno; - return 0; - } - } - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(IOB_ADDR); - uint32_t ret = 0; - if (i == -1) { - for (i = 3; i < NFILE; i++) { - if (f[i]._flag == 0) { - break; - } - } - } - assert(i < NFILE); - g_file_max = i + 1; - ret = IOB_ADDR + i * sizeof(struct FILE_irix); - f[i]._cnt = 0; - f[i]._ptr_addr = 0; - f[i]._base_addr = 0; - f[i]._file = fd; - f[i]._flag = (flags & O_ACCMODE) == O_RDONLY ? IOREAD : 0; - f[i]._flag |= (flags & O_ACCMODE) == O_WRONLY ? IOWRT : 0; - f[i]._flag |= (flags & O_ACCMODE) == O_RDWR ? IORW : 0; - bufendtab[i] = 0; - return ret; -} - -uint32_t wrapper_fopen(uint8_t *mem, uint32_t path_addr, uint32_t mode_addr) { - STRING(path) - STRING(mode) - return init_file(mem, -1, -1, path, mode); -} - -uint32_t wrapper_freopen(uint8_t *mem, uint32_t path_addr, uint32_t mode_addr, uint32_t fp_addr) { - STRING(path) - STRING(mode) - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr); - wrapper_fclose(mem, fp_addr); - return init_file(mem, -1, f - (struct FILE_irix *)&MEM_U32(IOB_ADDR), path, mode); -} - -int wrapper_fclose(uint8_t *mem, uint32_t fp_addr) { - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr); - wrapper_fflush(mem, fp_addr); - if (f->_flag & IOMYBUF) { - wrapper_free(mem, f->_base_addr); - } - f->_flag = 0; - close(f->_file); - return 0; -} - -static int flush_all(uint8_t *mem) { - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(IOB_ADDR); - int ret = 0; - for (int i = 0; i < g_file_max; i++) { - if (f[i]._flag & IOWRT) { - ret |= wrapper_fflush(mem, IOB_ADDR + i * sizeof(struct FILE_irix)); - } - } - return ret; -} - -int wrapper_fflush(uint8_t *mem, uint32_t fp_addr) { - if (fp_addr == 0) { - // Flush all - return flush_all(mem); - } - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr); - if (f->_flag & IOWRT) { - int p = 0; - int to_flush = f->_ptr_addr - f->_base_addr; - int c = to_flush; - while (c > 0) { - int r = wrapper_write(mem, f->_file, f->_base_addr + p, c); - if (r < 0) { - f->_file |= IOERR; - return -1; - } - p += r; - c -= r; - } - f->_ptr_addr = f->_base_addr; - f->_cnt += to_flush; - } - return 0; -} - -int wrapper_ftell(uint8_t *mem, uint32_t fp_addr) { - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr); - int adjust; - if (f->_cnt < 0) { - f->_cnt = 0; - } - if (f->_flag & IOREAD) { - adjust = -f->_cnt; - } else if (f->_flag & (IOWRT | IORW)) { - adjust = 0; - if ((f->_flag & IOWRT) && f->_base_addr != 0 && (f->_flag & IONBF) == 0) { - adjust = f->_ptr_addr - f->_base_addr; - } - } else { - return -1; - } - int res = wrapper_lseek(mem, f->_file, 0, 1); - if (res >= 0) { - res += adjust; - } - return res; -} - -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; -} - -int wrapper_fseek(uint8_t *mem, uint32_t fp_addr, int offset, int origin) { - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr); - int c, p; - f->_flag &= ~IOEOF; - if (f->_flag & IOREAD) { - if (origin < SEEK_END && f->_base_addr && !(f->_flag & IONBF)) { - c = f->_cnt; - p = offset; - if (origin == SEEK_SET) { - p += c - lseek(f->_file, 0L, SEEK_CUR); - } else { - offset -= c; - } - if (!(f->_flag & IORW) && c > 0 && p <= c && p >= f->_base_addr - f->_ptr_addr) { - f->_ptr_addr += p; - f->_cnt -= p; - return 0; - } - } - if (f->_flag & IORW) { - f->_ptr_addr = f->_base_addr; - f->_flag &= ~IOREAD; - } - p = lseek(f->_file, offset, origin); - f->_cnt = 0; - } else if (f->_flag & (IOWRT | IORW)) { - wrapper_fflush(mem, fp_addr); - if (f->_flag & IORW) { - f->_cnt = 0; - f->_flag &= ~IOWRT; - f->_ptr_addr = f->_base_addr; - } - p = lseek(f->_file, offset, origin); - } - if (p < 0) { - MEM_U32(ERRNO_ADDR) = errno; - return p; - } - return 0; -} - -int wrapper_lseek(uint8_t *mem, int fd, int offset, int whence) { - int ret = (int)lseek(fd, offset, whence); - if (ret == -1) { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -int wrapper_dup(uint8_t *mem, int fd) { - fd = dup(fd); - if (fd < 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - return fd; -} - -int wrapper_dup2(uint8_t *mem, int oldfd, int newfd) { - int fd = dup2(oldfd, newfd); - if (fd < 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - return fd; -} - -int wrapper_pipe(uint8_t *mem, uint32_t pipefd_addr) { - int pipefd[2]; - int ret = pipe(pipefd); - if (ret == 0) { - MEM_U32(pipefd_addr + 0) = pipefd[0]; - MEM_U32(pipefd_addr + 4) = pipefd[1]; - } else { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -void wrapper_perror(uint8_t *mem, uint32_t str_addr) { - STRING(str) - perror(str); -} - -int wrapper_fdopen(uint8_t *mem, int fd, uint32_t mode_addr) { - STRING(mode) - return init_file(mem, fd, -1, NULL, mode); -} - -uint32_t wrapper_memset(uint8_t *mem, uint32_t dest_addr, int byte, uint32_t n) { - uint32_t saved = dest_addr; - if (dest_addr % 4 == 0 && n % 4 == 0) { - memset(&MEM_U32(dest_addr), byte, n); - } else { - while (n--) { - MEM_U8(dest_addr) = (uint8_t)byte; - ++dest_addr; - } - } - return saved; -} - -int wrapper_bcmp(uint8_t *mem, uint32_t s1_addr, uint32_t s2_addr, uint32_t n) { - while (n--) { - if (MEM_U8(s1_addr) != MEM_U8(s2_addr)) { - return 1; - } - ++s1_addr; - ++s2_addr; - } - return 0; -} - -int wrapper_memcmp(uint8_t *mem, uint32_t s1_addr, uint32_t s2_addr, uint32_t n) { - while (n--) { - unsigned char c1 = MEM_U8(s1_addr); - unsigned char c2 = MEM_U8(s2_addr); - if (c1 < c2) { - return -1; - } - if (c1 > c2) { - return 1; - } - ++s1_addr; - ++s2_addr; - } - return 0; -} - -int wrapper_getpid(void) { - return getpid(); -} - -int wrapper_getpgrp(uint8_t *mem) { - int ret = getpgrp(); - if (ret == -1) { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -int wrapper_remove(uint8_t *mem, uint32_t path_addr) { - STRING(path) - int ret = remove(path); - if (ret < 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -int wrapper_unlink(uint8_t *mem, uint32_t path_addr) { - if (path_addr == 0) { - fprintf(stderr, "Warning: unlink with NULL as arguement\n"); - MEM_U32(ERRNO_ADDR) = EFAULT; - return -1; - } - STRING(path) - int ret = unlink(path); - if (ret < 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -int wrapper_close(uint8_t *mem, int fd) { - int ret = close(fd); - if (ret < 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -int wrapper_strcmp(uint8_t *mem, uint32_t s1_addr, uint32_t s2_addr) { - for (;;) { - char c1 = MEM_S8(s1_addr); - char c2 = MEM_S8(s2_addr); - if (c1 != c2) { - return c1 < c2 ? -1 : 1; - } - if (c1 == '\0') { - return 0; - } - ++s1_addr; - ++s2_addr; - } -} - -int wrapper_strncmp(uint8_t *mem, uint32_t s1_addr, uint32_t s2_addr, uint32_t n) { - if (n == 0) { - return 0; - } - for (;;) { - char c1 = MEM_S8(s1_addr); - char c2 = MEM_S8(s2_addr); - if (c1 != c2) { - return c1 < c2 ? -1 : 1; - } - if (--n == 0 || c1 == '\0') { - return 0; - } - ++s1_addr; - ++s2_addr; - } -} - -uint32_t wrapper_strcpy(uint8_t *mem, uint32_t dest_addr, uint32_t src_addr) { - uint32_t saved = dest_addr; - for (;;) { - char c = MEM_S8(src_addr); - ++src_addr; - MEM_S8(dest_addr) = c; - ++dest_addr; - if (c == '\0') { - return saved; - } - } -} - -uint32_t wrapper_strncpy(uint8_t *mem, uint32_t dest_addr, uint32_t src_addr, uint32_t n) { - uint32_t i; - for (i = 0; i < n && MEM_S8(src_addr) != '\0'; i++) { - MEM_S8(dest_addr + i) = MEM_S8(src_addr + i); - } - for (; i < n; i++) { - MEM_S8(dest_addr + i) = '\0'; - } - return dest_addr; -} - -uint32_t wrapper_strcat(uint8_t *mem, uint32_t dest_addr, uint32_t src_addr) { - uint32_t saved = dest_addr; - while (MEM_S8(dest_addr) != '\0') { - ++dest_addr; - } - while (MEM_S8(src_addr) != '\0') { - MEM_S8(dest_addr) = MEM_S8(src_addr); - ++src_addr; - ++dest_addr; - } - MEM_S8(dest_addr) = '\0'; - return saved; -} - -uint32_t wrapper_strncat(uint8_t *mem, uint32_t dest_addr, uint32_t src_addr, uint32_t n) { - uint32_t saved = dest_addr; - while (MEM_S8(dest_addr) != '\0') { - ++dest_addr; - } - while (n-- && MEM_S8(src_addr) != '\0') { - MEM_S8(dest_addr) = MEM_S8(src_addr); - ++src_addr; - ++dest_addr; - } - MEM_S8(dest_addr) = '\0'; - return saved; -} - -uint32_t wrapper_strtok(uint8_t *mem, uint32_t str_addr, uint32_t delimiters_addr) { - if (str_addr == 0) { - str_addr = MEM_U32(STRTOK_DATA_ADDR); - } - if (str_addr == 0) { - // nothing remaining - return 0; - } - uint32_t p; - for (p = str_addr; MEM_S8(p) != '\0'; p++) { - uint32_t q; - for (q = delimiters_addr; MEM_S8(q) != '\0' && MEM_S8(q) != MEM_S8(p); q++) { - } - if (MEM_S8(q) == '\0') { - break; - } - } - if (MEM_S8(p) == '\0') { - return 0; - } - uint32_t ret = p; - for (;;) { - uint32_t q; - for (q = delimiters_addr; MEM_S8(q) != '\0' && MEM_S8(q) != MEM_S8(p); q++) { - } - if (MEM_S8(q) != '\0') { - MEM_S8(p) = '\0'; - MEM_U32(STRTOK_DATA_ADDR) = ++p; - return ret; - } - char next = MEM_S8(p); - ++p; - if (next == '\0') { - MEM_U32(STRTOK_DATA_ADDR) = 0; - return ret; - } - } -} - -uint32_t wrapper_strstr(uint8_t *mem, uint32_t str1_addr, uint32_t str2_addr) { - for (;;) { - if (MEM_S8(str1_addr) == '\0') { - return 0; - } - uint32_t s1 = str1_addr; - uint32_t s2 = str2_addr; - for (;;) { - char c2 = MEM_S8(s2); - if (c2 == '\0') { - return str1_addr; - } - if (MEM_S8(s1) == c2) { - ++s1; - ++s2; - } else { - break; - } - } - ++str1_addr; - } -} - -uint32_t wrapper_strdup(uint8_t *mem, uint32_t str_addr) { - uint32_t len = wrapper_strlen(mem, str_addr) + 1; - uint32_t ret = wrapper_malloc(mem, len); - if (ret == 0) { - MEM_U32(ERRNO_ADDR) = ENOMEM; - return 0; - } - return wrapper_memcpy(mem, ret, str_addr, len); -} - -int wrapper_toupper(int c) { - return toupper(c); -} - -int wrapper_tolower(int c) { - return tolower(c); -} - -int wrapper_gethostname(uint8_t *mem, uint32_t name_addr, uint32_t len) { - char buf[256] = {0}; - if (len > 256) { - len = 256; - } - int ret = gethostname(buf, len); - if (ret < 0) { - MEM_U32(ERRNO_ADDR) = errno; - } else { - for (uint32_t i = 0; i < len; i++) { - MEM_S8(name_addr + i) = buf[i]; - } - } - return ret; -} - -int wrapper_isatty(uint8_t *mem, int fd) { - int ret = isatty(fd); - if (ret == 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -uint32_t wrapper_strftime(uint8_t *mem, uint32_t ptr_addr, uint32_t maxsize, uint32_t format_addr, uint32_t timeptr_addr) { - //assert(0 && "strftime not implemented"); - MEM_S8(ptr_addr) = 0; - return 0; -} - -int wrapper_times(uint8_t *mem, uint32_t buffer_addr) { - struct tms_irix { - int tms_utime; - int tms_stime; - int tms_cutime; - int tms_cstime; - } r; - struct tms t; - clock_t ret = times(&t); - if (ret == (clock_t)-1) { - MEM_U32(ERRNO_ADDR) = errno; - } else { - r.tms_utime = t.tms_utime; - r.tms_stime = t.tms_stime; - r.tms_cutime = t.tms_cutime; - r.tms_cstime = t.tms_cstime; - } - return (int)ret; -} - -int wrapper_clock(void) { - return (int)clock(); -} - -uint32_t wrapper_ctime(uint8_t *mem, uint32_t timep_addr) { - time_t t = MEM_S32(timep_addr); - char *res = ctime(&t); - size_t len = strlen(res) + 1; - uint32_t ret_addr = wrapper_malloc(mem, len); - uint32_t pos = ret_addr; - while (len--) { - MEM_S8(pos) = *res; - ++pos; - ++res; - } - return ret_addr; - //assert(0 && "ctime not implemented"); - //return 0; -} - -uint32_t wrapper_localtime(uint8_t *mem, uint32_t timep_addr) { - time_t t = MEM_S32(timep_addr); - struct irix_tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; - }; - uint32_t ret = wrapper_malloc(mem, sizeof(struct irix_tm)); - struct irix_tm *r = (struct irix_tm *)&MEM_U32(ret); - struct tm *l = localtime(&t); - r->tm_sec = l->tm_sec; - r->tm_min = l->tm_min; - r->tm_hour = l->tm_hour; - r->tm_mday = l->tm_mday; - r->tm_mon = l->tm_mon; - r->tm_year = l->tm_year; - r->tm_wday = l->tm_wday; - r->tm_yday = l->tm_yday; - r->tm_isdst = l->tm_isdst; - return ret; -} - -int wrapper_setvbuf(uint8_t *mem, uint32_t fp_addr, uint32_t buf_addr, int mode, uint32_t size) { - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr); - wrapper_fflush(mem, fp_addr); - if ((f->_flag & IOMYBUF) && f->_base_addr != 0) { - wrapper_free(mem, f->_base_addr); - } - size &= ~0xf; - f->_flag &= ~IOMYBUF; - f->_base_addr = buf_addr; - 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) { - assert(0); -} - -int wrapper___semputc(uint8_t *mem, int c, uint32_t fp_addr) { - assert(0); -} - -int wrapper_fgetc(uint8_t *mem, uint32_t fp_addr) { - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr); - if (--f->_cnt < 0) { - return wrapper___filbuf(mem, fp_addr); - } else { - int ret = MEM_U8(f->_ptr_addr); - ++f->_ptr_addr; - return ret; - } -} - -int wrapper_fgets(uint8_t *mem, uint32_t str_addr, int count, uint32_t fp_addr) { - bool modified = false; - uint32_t saved = str_addr; - for (count--; count > 0; count--) { - int ch = wrapper_fgetc(mem, fp_addr); - if (ch == -1) { - MEM_S8(str_addr) = '\0'; - return modified ? saved : 0; - } - modified = true; - MEM_S8(str_addr) = (char)ch; - ++str_addr; - if (ch == '\n') { - break; - } - } - MEM_S8(str_addr) = '\0'; - return saved; -} - -static void file_assign_buffer(uint8_t *mem, struct FILE_irix *f) { - f->_base_addr = wrapper_malloc(mem, STDIO_BUFSIZE); - f->_ptr_addr = f->_base_addr; - f->_flag |= IOMYBUF; - f->_cnt = 0; - bufendtab[f - (struct FILE_irix *)&MEM_U32(IOB_ADDR)] = STDIO_BUFSIZE; -} - -int wrapper___filbuf(uint8_t *mem, uint32_t fp_addr) { - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr); - if (!(f->_flag & IOREAD)) { - if (f->_flag & IORW) { - f->_flag |= IOREAD; - } else { - MEM_U32(ERRNO_ADDR) = 9; // EBADF - return -1; - } - } - if (f->_base_addr == 0) { - file_assign_buffer(mem, f); - } - uint32_t size = bufendtab[(fp_addr - IOB_ADDR) / sizeof(struct FILE_irix)]; - int nread = wrapper_read(mem, f->_file, f->_base_addr, size); - int ret = -1; - if (nread > 0) { - f->_ptr_addr = f->_base_addr; - f->_cnt = nread; - ret = MEM_U8(f->_ptr_addr); - ++f->_ptr_addr; - --f->_cnt; - } else if (nread == 0) { - f->_flag |= IOEOF; - } else { - f->_flag |= IOERR; - } - return ret; -} - -int wrapper___flsbuf(uint8_t *mem, int ch, uint32_t fp_addr) { - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr); - if (wrapper_fflush(mem, fp_addr) != 0) { - return -1; - } - if (f->_base_addr == 0) { - file_assign_buffer(mem, f); - f->_cnt = bufendtab[f - (struct FILE_irix *)&MEM_U32(IOB_ADDR)]; - } - MEM_U8(f->_ptr_addr) = ch; - ++f->_ptr_addr; - --f->_cnt; - if (f->_flag & IONBF) { - if (wrapper_fflush(mem, fp_addr) != 0) { - return -1; - } - f->_cnt = 0; - } - return ch; -} - -int wrapper_ungetc(uint8_t *mem, int ch, uint32_t fp_addr) { - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr); - if (ch == -1 || f->_ptr_addr == f->_base_addr) { - return -1; - } - --f->_ptr_addr; - MEM_U8(f->_ptr_addr) = (uint8_t)ch; - ++f->_cnt; - f->_flag &= ~IOEOF; - return ch; -} - -uint32_t wrapper_gets(uint8_t *mem, uint32_t str_addr) { - uint32_t p, str0 = str_addr; - int n; - - for (;;) { - if (STDIN->_cnt <= 0) { - if (wrapper___filbuf(mem, STDIN_ADDR) == -1) { - if (str0 == str_addr) { - return 0; - } - break; - } - --STDIN->_ptr_addr; - ++STDIN->_cnt; - } - n = STDIN->_cnt; - if ((p = wrapper_memccpy(mem, str_addr, STDIN->_ptr_addr, '\n', n)) != 0) { - n = p - str_addr; - } - str_addr += n; - STDIN->_cnt -= n; - STDIN->_ptr_addr += n; - // bufsync - if (p != 0) { - // found '\n' in buffer - --str_addr; - break; - } - } - MEM_S8(str_addr) = '\0'; - return str0; -} - -uint32_t wrapper_fread(uint8_t *mem, uint32_t data_addr, uint32_t size, uint32_t count, uint32_t fp_addr) { - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr); - int nleft = count * size; - int n; - for (;;) { - if (f->_cnt <= 0) { - if (wrapper___filbuf(mem, fp_addr) == -1) { - return count - (nleft + size - 1) / size; - } - --f->_ptr_addr; - ++f->_cnt; - } - n = MIN(nleft, f->_cnt); - data_addr = wrapper_memcpy(mem, data_addr, f->_ptr_addr, n) + n; - f->_cnt -= n; - f->_ptr_addr += n; - if ((nleft -= n) <= 0) { - return count; - } - } -} - -uint32_t wrapper_fwrite(uint8_t *mem, uint32_t data_addr, uint32_t size, uint32_t count, uint32_t fp_addr) { - struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr); - if (size > 0 && count > 0 && f->_base_addr == 0) { - file_assign_buffer(mem, f); - f->_cnt = bufendtab[f - (struct FILE_irix *)&MEM_U32(IOB_ADDR)]; - f->_flag |= IOWRT; - } - uint32_t num_written = 0; - while (count--) { - uint32_t s = size; - while (s > 0) { - uint32_t to_write = f->_cnt; - if (s < to_write) { - to_write = s; - } - if (f->_cnt == 0) { - if (wrapper_fflush(mem, fp_addr) != 0) { - return num_written; - } - } - wrapper_memcpy(mem, f->_ptr_addr, data_addr, to_write); - data_addr += to_write; - f->_ptr_addr += to_write; - f->_cnt -= to_write; - s -= to_write; - } - num_written++; - } - if (f->_flag & IONBF) { - wrapper_fflush(mem, fp_addr); // TODO check error return value - } - return num_written; -} - -int wrapper_fputs(uint8_t *mem, uint32_t str_addr, uint32_t fp_addr) { - uint32_t len = wrapper_strlen(mem, str_addr); - uint32_t ret = wrapper_fwrite(mem, str_addr, 1, len, fp_addr); - return ret == 0 && len != 0 ? -1 : 0; -} - -int wrapper_puts(uint8_t *mem, uint32_t str_addr) { - int ret = wrapper_fputs(mem, str_addr, STDOUT_ADDR); - if (ret != 0) { - return ret; - } - struct FILE_irix *f = STDOUT; - if (--f->_cnt < 0) { - if (wrapper___flsbuf(mem, '\n', STDOUT_ADDR) != '\n') { - return -1; - } - } else { - MEM_S8(f->_ptr_addr) = '\n'; - ++f->_ptr_addr; - } - return 0; -} - -uint32_t wrapper_getcwd(uint8_t *mem, uint32_t buf_addr, uint32_t size) { - char buf[size]; - if (getcwd(buf, size) == NULL) { - MEM_U32(ERRNO_ADDR) = errno; - return 0; - } else { - if (buf_addr == 0) { - buf_addr = wrapper_malloc(mem, size); - } - strcpy1(mem, buf_addr, buf); - return buf_addr; - } -} - -int wrapper_time(uint8_t *mem, uint32_t tloc_addr) { - time_t ret = time(NULL); - if (ret == (time_t)-1) { - MEM_U32(ERRNO_ADDR) = errno; - } else if (tloc_addr != 0) { - MEM_S32(tloc_addr) = ret; - } - return ret; -} - -void wrapper_bzero(uint8_t *mem, uint32_t str_addr, uint32_t n) { - while (n--) { - MEM_U8(str_addr) = 0; - ++str_addr; - } -} - -int wrapper_fp_class_d(double d) { - union { - uint32_t w[2]; - double d; - } bits; - bits.d = d; - uint32_t a2 = bits.w[1]; - uint32_t a1 = a2 >> 20; - uint32_t a0 = a1; - a2 &= 0xfffff; - uint32_t a3 = bits.w[0]; - a1 &= 0x7ff; - a0 &= 0x800; - if (a1 == 0x7ff) { - if (a2 == 0 && a3 == 0) { - return a0 == 0 ? 2 : 3; - } - a0 = a2 & 0x80000; - return a0 == 0 ? 1 : 0; - } - if (a1 == 0) { - if (a2 == 0 && a3 == 0) { - return a0 == 0 ? 8 : 9; - } - return a0 == 0 ? 6 : 7; - } - return a0 == 0 ? 4 : 5; -} - -double wrapper_ldexp(double d, int i) { - return ldexp(d, i); -} - -int64_t wrapper___ll_mul(int64_t a0, int64_t a1) { - return a0 * a1; -} - -int64_t wrapper___ll_div(int64_t a0, int64_t a1) { - return a0 / a1; -} - -int64_t wrapper___ll_rem(uint64_t a0, int64_t a1) { - return a0 % a1; -} - -int64_t wrapper___ll_lshift(int64_t a0, uint64_t shift) { - return a0 << (shift & 0x3f); -} - -int64_t wrapper___ll_rshift(int64_t a0, uint64_t shift) { - return a0 >> (shift & 0x3f); -} - -uint64_t wrapper___ull_div(uint64_t a0, uint64_t a1) { - return a0 / a1; -} - -uint64_t wrapper___ull_rem(uint64_t a0, uint64_t a1) { - return a0 % a1; -} - -uint64_t wrapper___ull_rshift(uint64_t a0, uint64_t shift) { - return a0 >> (shift & 0x3f); -} - -uint64_t wrapper___d_to_ull(double d) { - return d; -} - -int64_t wrapper___d_to_ll(double d) { - return d; -} - -uint64_t wrapper___f_to_ull(float f) { - return f; -} - -int64_t wrapper___f_to_ll(float f) { - return f; -} - -float wrapper___ull_to_f(uint64_t v) { - return v; -} - -float wrapper___ll_to_f(int64_t v) { - return v; -} - -double wrapper___ull_to_d(uint64_t v) { - return v; -} - -double wrapper___ll_to_d(int64_t v) { - return v; -} - -void wrapper_abort(uint8_t *mem) { - abort(); -} - -void wrapper_exit(uint8_t *mem, int status) { - exit(status); -} - -void wrapper__exit(uint8_t *mem, int status) { - assert(0 && "_exit not implemented"); // exit() is already overridden -} - -void wrapper__cleanup(uint8_t *mem) { -} - -uint32_t wrapper__rld_new_interface(uint8_t *mem, uint32_t operation, uint32_t sp) { - assert(0 && "_rld_new_interface not implemented"); - return 0; -} - -void wrapper__exithandle(uint8_t *mem) { - assert(0 && "_exithandle not implemented"); -} - -int wrapper__prctl(uint8_t *mem, int operation, uint32_t sp) { - assert(0 && "_prctl not implemented"); - return 0; -} - -double wrapper__atod(uint8_t *mem, uint32_t buffer_addr, int ndigits, int dexp) { - // ftp://atoum.hst.nerim.net/irix/src/irix-6.5.5-src/6.5.5/m/irix/lib/libc/src/math/atod.c - assert(0 && "_atod not implemented"); - return 0.0; -} - -int wrapper_pathconf(uint8_t *mem, uint32_t path_addr, int name) { - STRING(path) - if (name == 5) { - errno = 0; - int ret = pathconf(path, _PC_PATH_MAX); - if (errno != 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; - } - assert(0 && "pathconf not implemented for the specific 'name'"); - return 0; -} - -uint32_t wrapper_getenv(uint8_t *mem, uint32_t name_addr) { - // Return null for everything, for now - return 0; -} - -uint32_t wrapper_gettxt(uint8_t *mem, uint32_t msgid_addr, uint32_t default_str_addr) { - // Return default for now - return default_str_addr; -} - -uint32_t wrapper_setlocale(uint8_t *mem, int category, uint32_t locale_addr) { - assert(locale_addr != 0); - STRING(locale) - assert(category == 6); // LC_ALL - char *ret = setlocale(LC_ALL, locale); - // Let's hope the caller doesn't use the return value - return 0; -} - -uint32_t wrapper_mmap(uint8_t *mem, uint32_t addr, uint32_t length, int prot, int flags, int fd, int offset) { - assert(0 && "mmap not implemented"); - return 0; -} - -int wrapper_munmap(uint8_t *mem, uint32_t addr, uint32_t length) { - assert(0 && "munmap not implemented"); - return 0; -} - -int wrapper_mprotect(uint8_t *mem, uint32_t addr, uint32_t length, int prot) { - assert(0 && "mprotect not implemented"); - return 0; -} - -int wrapper_sysconf(uint8_t *mem, int name) { - assert(0 && "sysconf not implemented"); - return 0; -} - -int wrapper_getpagesize(uint8_t *mem) { - return 4096; -} - -int wrapper_strerror(uint8_t *mem, int errnum) { - errno = errnum; - perror("strerror"); - assert(0 && "strerror not implemented"); - return 0; -} - -int wrapper_ioctl(uint8_t *mem, int fd, uint32_t request, uint32_t sp) { - assert(0 && "ioctl not implemented"); - return 0; -} - -int wrapper_fcntl(uint8_t *mem, int fd, int cmd, uint32_t sp) { - assert(0 && "fcntl not implemented"); - return 0; -} - -static void signal_handler(int signum) { - uint32_t level = signal_context.recursion_level++; - uint8_t *mem = signal_context.handlers[signum].mem; - uint32_t fp_dest = signal_context.handlers[signum].fp_dest; - uint32_t sp = SIGNAL_HANDLER_STACK_START - 16 - level * 0x1000; - signal_context.handlers[signum].trampoline(mem, sp, signum, 0, 0, 0, fp_dest); - signal_context.recursion_level--; -} - -uint32_t wrapper_signal(uint8_t *mem, int signum, uint64_t (*trampoline)(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest), uint32_t handler_addr, uint32_t sp) { - //assert(0 && "signal not implemented"); - return 0; -} - -uint32_t wrapper_sigset(uint8_t *mem, int signum, uint64_t (*trampoline)(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest), uint32_t disp_addr, uint32_t sp) { - void (*handler)(int) = signal_handler; - - if ((int)disp_addr >= -1 && (int)disp_addr <= 1) { - // SIG_DFL etc. - handler = (void (*)(int))(intptr_t)(int)disp_addr; - } - - switch (signum) { - case 2: - signum = SIGINT; - break; - case 13: - signum = SIGPIPE; - break; - case 15: - signum = SIGTERM; - break; - default: - assert(0 && "sigset with this signum not implemented"); - break; - } - - signal_context.handlers[signum].trampoline = trampoline; - signal_context.handlers[signum].mem = mem; - signal_context.handlers[signum].fp_dest = disp_addr; - - return (uint32_t)(uintptr_t)sigset(signum, handler); // for now only support SIG_DFL etc. as return value -} - -int wrapper_get_fpc_csr(uint8_t *mem) { - //assert(0 && "get_fpc_csr not implemented"); - return 0; -} - -int wrapper_set_fpc_csr(uint8_t *mem, int csr) { - //assert(0 && "set_fpc_csr not implemented"); - return 0; -} - -int wrapper_setjmp(uint8_t *mem, uint32_t addr) { - return 0; -} - -void wrapper_longjmp(uint8_t *mem, uint32_t addr, int status) { - assert(0 && "longjmp not implemented"); -} - -uint32_t wrapper_tempnam(uint8_t *mem, uint32_t dir_addr, uint32_t pfx_addr) { - STRING(dir) - STRING(pfx) - char *ret = tempnam(dir, pfx); - char *ret_saved = ret; - if (ret == NULL) { - MEM_U32(ERRNO_ADDR) = errno; - return 0; - } - size_t len = strlen(ret) + 1; - uint32_t ret_addr = wrapper_malloc(mem, len); - uint32_t pos = ret_addr; - while (len--) { - MEM_S8(pos) = *ret; - ++pos; - ++ret; - } - free(ret_saved); - return ret_addr; -} - -uint32_t wrapper_tmpnam(uint8_t *mem, uint32_t str_addr) { - char buf[1024]; - assert(str_addr != 0 && "s NULL not implemented for tmpnam"); - char *ret = tmpnam(buf); - if (ret == NULL) { - return 0; - } else { - strcpy1(mem, str_addr, ret); - return str_addr; - } -} - -uint32_t wrapper_mktemp(uint8_t *mem, uint32_t template_addr) { - STRING(template) - mktemp(template); - strcpy1(mem, template_addr, template); - return template_addr; -} - -int wrapper_mkstemp(uint8_t *mem, uint32_t name_addr) { - STRING(name) - int fd = mkstemp(name); - if (fd < 0) { - MEM_U32(ERRNO_ADDR) = errno; - } else { - strcpy1(mem, name_addr, name); - } - return fd; -} - -uint32_t wrapper_tmpfile(uint8_t *mem) { - // create and fopen a temporary file that is removed when the program exits - char name[] = "/tmp/copt_temp_XXXXXX"; - int fd = mkstemp(name); - if (fd < 0) { - MEM_U32(ERRNO_ADDR) = errno; - return 0; - } - - // the file will be removed from disk when it's closed later - unlink(name); - - // fdopen: - uint32_t ret = init_file(mem, fd, -1, NULL, "w+"); - if (ret == 0) { - close(fd); - } - return ret; -} - -int wrapper_wait(uint8_t *mem, uint32_t wstatus_addr) { - int wstatus; - pid_t ret = wait(&wstatus); - MEM_S32(wstatus_addr) = wstatus; - return ret; -} - -int wrapper_kill(uint8_t *mem, int pid, int sig) { - int ret = kill(pid, sig); - if (ret != 0) { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -int wrapper_execlp(uint8_t *mem, uint32_t file_addr, uint32_t sp) { - uint32_t argv_addr = sp + 4; - return wrapper_execvp(mem, file_addr, argv_addr); -} - -int wrapper_execv(uint8_t *mem, uint32_t pathname_addr, uint32_t argv_addr) { - STRING(pathname) - uint32_t argc = 0; - while (MEM_U32(argv_addr + argc * 4) != 0) { - ++argc; - } - char *argv[argc + 1]; - for (uint32_t i = 0; i < argc; i++) { - uint32_t str_addr = MEM_U32(argv_addr + i * 4); - uint32_t len = wrapper_strlen(mem, str_addr) + 1; - argv[i] = (char *)malloc(len); - char *pos = argv[i]; - while (len--) { - *pos++ = MEM_S8(str_addr); - ++str_addr; - } - } - argv[argc] = NULL; - execv(pathname, argv); - MEM_U32(ERRNO_ADDR) = errno; - for (uint32_t i = 0; i < argc; i++) { - free(argv[i]); - } - return -1; -} - -int wrapper_execvp(uint8_t *mem, uint32_t file_addr, uint32_t argv_addr) { - STRING(file) - uint32_t argc = 0; - while (MEM_U32(argv_addr + argc * 4) != 0) { - ++argc; - } - char *argv[argc + 1]; - for (uint32_t i = 0; i < argc; i++) { - uint32_t str_addr = MEM_U32(argv_addr + i * 4); - uint32_t len = wrapper_strlen(mem, str_addr) + 1; - argv[i] = (char *)malloc(len); - char *pos = argv[i]; - while (len--) { - *pos++ = MEM_S8(str_addr); - ++str_addr; - } - } - argv[argc] = NULL; - -#ifdef REDIRECT_USR_LIB - if (!strncmp(file, "/usr/lib/", 9) && bin_dir[0] != '\0') { - char fixed_path[PATH_MAX + 1]; -#ifdef __CYGWIN__ - int n = snprintf(fixed_path, sizeof(fixed_path), "%s/%s.exe", bin_dir, file + 9); -#else - int n = snprintf(fixed_path, sizeof(fixed_path), "%s/%s", bin_dir, file + 9); -#endif - if (n > 0 && n < sizeof(fixed_path)) { - execvp(fixed_path, argv); - } else { - execvp(file, argv); - } - } else { - execvp(file, argv); - } -#else - execvp(file, argv); -#endif - - MEM_U32(ERRNO_ADDR) = errno; - for (uint32_t i = 0; i < argc; i++) { - free(argv[i]); - } - return -1; -} - -int wrapper_fork(uint8_t *mem) { - int ret = fork(); - if (ret == -1) { - MEM_U32(ERRNO_ADDR) = errno; - } - return ret; -} - -int wrapper_system(uint8_t *mem, uint32_t command_addr) { - STRING(command) - return system(command); // no errno -} - -static int name_compare(uint8_t *mem, uint32_t a_addr, uint32_t b_addr) { - //printf("pc=0x00438180\n"); - return wrapper_strcmp(mem, MEM_U32(a_addr), MEM_U32(b_addr)); -} - -static uint32_t tsearch_tfind(uint8_t *mem, uint32_t key_addr, uint32_t rootp_addr, uint32_t compar_addr, bool insert) { - //assert(compar_addr == 0x438180); // name_compare in as1 - - if (rootp_addr == 0) { - return 0; - } - while (MEM_U32(rootp_addr) != 0) { - uint32_t node_addr = MEM_U32(rootp_addr); - int r = name_compare(mem, key_addr, MEM_U32(node_addr)); - if (r == 0) { - return node_addr; - } - rootp_addr = r < 0 ? node_addr + 4 : node_addr + 8; - } - if (insert) { - uint32_t node_addr = wrapper_malloc(mem, 12); - if (node_addr != 0) { - MEM_U32(rootp_addr) = node_addr; - MEM_U32(node_addr) = key_addr; - MEM_U32(node_addr + 4) = 0; - MEM_U32(node_addr + 8) = 0; - return node_addr; - } - } - return 0; -} - -uint32_t wrapper_tsearch(uint8_t *mem, uint32_t key_addr, uint32_t rootp_addr, uint32_t compar_addr) { - return tsearch_tfind(mem, key_addr, rootp_addr, compar_addr, true); -} - -uint32_t wrapper_tfind(uint8_t *mem, uint32_t key_addr, uint32_t rootp_addr, uint32_t compar_addr) { - return tsearch_tfind(mem, key_addr, rootp_addr, compar_addr, false); -} - -uint32_t wrapper_qsort(uint8_t *mem, uint32_t base_addr, uint32_t num, uint32_t size, uint64_t (*trampoline)(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest), uint32_t compare_addr, uint32_t sp) { - assert(0 && "qsort not implemented"); - return 0; -} - -uint32_t wrapper_regcmp(uint8_t *mem, uint32_t string1_addr, uint32_t sp) { - STRING(string1); - fprintf(stderr, "regex string: %s\n", string1); - assert(0 && "regcmp not implemented"); - return 0; -} - -uint32_t wrapper_regex(uint8_t *mem, uint32_t re_addr, uint32_t subject_addr, uint32_t sp) { - STRING(subject); - assert(0 && "regex not implemented"); - return 0; -} - -void wrapper___assert(uint8_t *mem, uint32_t assertion_addr, uint32_t file_addr, int line) { - STRING(assertion) - STRING(file) - __assert(assertion, file, line); -} diff --git a/tools/ido5.3_recomp/libc_impl.h b/tools/ido5.3_recomp/libc_impl.h deleted file mode 100644 index 0f1d920f..00000000 --- a/tools/ido5.3_recomp/libc_impl.h +++ /dev/null @@ -1,163 +0,0 @@ -#include - -void mmap_initial_data_range(uint8_t *mem, uint32_t start, uint32_t end); -void setup_libc_data(uint8_t *mem); - -uint32_t wrapper_sbrk(uint8_t *mem, int increment); -uint32_t wrapper_malloc(uint8_t *mem, uint32_t size); -uint32_t wrapper_calloc(uint8_t *mem, uint32_t num, uint32_t size); -uint32_t wrapper_realloc(uint8_t *mem, uint32_t data_addr, uint32_t size); -int wrapper_fscanf(uint8_t *mem, uint32_t fp_addr, uint32_t format_addr, uint32_t sp); -int wrapper_printf(uint8_t *mem, uint32_t format_addr, uint32_t sp); -int wrapper_sprintf(uint8_t *mem, uint32_t str_addr, uint32_t format_addr, uint32_t sp); -int wrapper_fprintf(uint8_t *mem, uint32_t fp_addr, uint32_t format_addr, uint32_t sp); -int wrapper__doprnt(uint8_t *mem, uint32_t format_addr, uint32_t params_addr, uint32_t fp_addr); -void wrapper_free(uint8_t *mem, uint32_t data_addr); -uint32_t wrapper_strlen(uint8_t *mem, uint32_t str_addr); -int wrapper_open(uint8_t *mem, uint32_t pathname_addr, int flags, int mode); -int wrapper_creat(uint8_t *mem, uint32_t pathname_addr, int mode); -int wrapper_access(uint8_t *mem, uint32_t pathname_addr, int mode); -int wrapper_rename(uint8_t *mem, uint32_t oldpath_addr, uint32_t newpath_addr); -int wrapper_utime(uint8_t *mem, uint32_t filename_addr, uint32_t times_addr); -int wrapper_flock(uint8_t *mem, int fd, int operation); -int wrapper_chmod(uint8_t *mem, uint32_t path_addr, uint32_t mode); -int wrapper_umask(int mode); -uint32_t wrapper_ecvt(uint8_t *mem, double number, int ndigits, uint32_t decpt_addr, uint32_t sign_addr); -uint32_t wrapper_fcvt(uint8_t *mem, double number, int ndigits, uint32_t decpt_addr, uint32_t sign_addr); -double wrapper_sqrt(double v); -float wrapper_sqrtf(float v); -int wrapper_atoi(uint8_t *mem, uint32_t nptr_addr); -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); -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); -uint32_t wrapper_strcspn(uint8_t *mem, uint32_t str_addr, uint32_t invalid_addr); -uint32_t wrapper_strpbrk(uint8_t *mem, uint32_t str_addr, uint32_t accept_addr); -int wrapper_fstat(uint8_t *mem, int fildes, uint32_t buf_addr); -int wrapper_stat(uint8_t *mem, uint32_t pathname_addr, uint32_t buf_addr); -int wrapper_ftruncate(uint8_t *mem, int fd, int length); -void wrapper_bcopy(uint8_t *mem, uint32_t src_addr, uint32_t dst_addr, uint32_t len); -uint32_t wrapper_memcpy(uint8_t *mem, uint32_t dst_addr, uint32_t src_addr, uint32_t len); -uint32_t wrapper_memccpy(uint8_t *mem, uint32_t dst_addr, uint32_t src_addr, int c, uint32_t len); -int wrapper_read(uint8_t *mem, int fd, uint32_t buf_addr, uint32_t nbytes); -int wrapper_write(uint8_t *mem, int fd, uint32_t buf_addr, uint32_t nbytes); -uint32_t wrapper_fopen(uint8_t *mem, uint32_t path_addr, uint32_t mode_addr); -uint32_t wrapper_freopen(uint8_t *mem, uint32_t path_addr, uint32_t mode_addr, 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_ftell(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); -int wrapper_dup2(uint8_t *mem, int oldfd, int newfd); -int wrapper_pipe(uint8_t *mem, uint32_t pipefd_addr); -void wrapper_perror(uint8_t *mem, uint32_t str_addr); -int wrapper_fdopen(uint8_t *mem, int fd, uint32_t mode_addr); -uint32_t wrapper_memset(uint8_t *mem, uint32_t dest_addr, int byte, uint32_t n); -int wrapper_bcmp(uint8_t *mem, uint32_t s1_addr, uint32_t s2_addr, uint32_t n); -int wrapper_memcmp(uint8_t *mem, uint32_t s1_addr, uint32_t s2_addr, uint32_t n); -int wrapper_getpid(void); -int wrapper_getpgrp(uint8_t *mem); -int wrapper_remove(uint8_t *mem, uint32_t path_addr); -int wrapper_unlink(uint8_t *mem, uint32_t path_addr); -int wrapper_close(uint8_t *mem, int fd); -int wrapper_strcmp(uint8_t *mem, uint32_t s1_addr, uint32_t s2_addr); -int wrapper_strncmp(uint8_t *mem, uint32_t s1_addr, uint32_t s2_addr, uint32_t n); -uint32_t wrapper_strcpy(uint8_t *mem, uint32_t dest_addr, uint32_t src_addr); -uint32_t wrapper_strncpy(uint8_t *mem, uint32_t dest_addr, uint32_t src_addr, uint32_t n); -uint32_t wrapper_strcat(uint8_t *mem, uint32_t dest_addr, uint32_t src_addr); -uint32_t wrapper_strncat(uint8_t *mem, uint32_t dest_addr, uint32_t src_addr, uint32_t n); -uint32_t wrapper_strtok(uint8_t *mem, uint32_t str_addr, uint32_t delimiters_addr); -uint32_t wrapper_strstr(uint8_t *mem, uint32_t str1_addr, uint32_t str2_addr); -uint32_t wrapper_strdup(uint8_t *mem, uint32_t str_addr); -int wrapper_toupper(int c); -int wrapper_tolower(int c); -int wrapper_gethostname(uint8_t *mem, uint32_t name_addr, uint32_t len); -int wrapper_isatty(uint8_t *mem, int fd); -int wrapper_times(uint8_t *mem, uint32_t buffer_addr); -uint32_t wrapper_strftime(uint8_t *mem, uint32_t ptr_addr, uint32_t maxsize, uint32_t format_addr, uint32_t timeptr_addr); -int wrapper_clock(void); -uint32_t wrapper_ctime(uint8_t *mem, uint32_t timep_addr); -uint32_t wrapper_localtime(uint8_t *mem, uint32_t timep_addr); -int wrapper_setvbuf(uint8_t *mem, uint32_t fp_addr, uint32_t buf_addr, int mode, uint32_t size); -int wrapper___semgetc(uint8_t *mem, uint32_t fp_addr); -int wrapper___semputc(uint8_t *mem, int c, uint32_t fp_addr); -int wrapper_fgetc(uint8_t *mem, uint32_t fp_addr); -int wrapper_fgets(uint8_t *mem, uint32_t str_addr, int count, uint32_t fp_addr); -int wrapper___filbuf(uint8_t *mem, uint32_t fp_addr); -int wrapper___flsbuf(uint8_t *mem, int ch, uint32_t fp_addr); -int wrapper_ungetc(uint8_t *mem, int ch, uint32_t fp_addr); -uint32_t wrapper_gets(uint8_t *mem, uint32_t str_addr); -uint32_t wrapper_fread(uint8_t *mem, uint32_t data_addr, uint32_t size, uint32_t count, uint32_t fp_addr); -uint32_t wrapper_fwrite(uint8_t *mem, uint32_t data_addr, uint32_t size, uint32_t count, uint32_t fp_addr); -int wrapper_fputs(uint8_t *mem, uint32_t str_addr, uint32_t fp_addr); -int wrapper_puts(uint8_t *mem, uint32_t str_addr); -uint32_t wrapper_getcwd(uint8_t *mem, uint32_t buf_addr, uint32_t size); -int wrapper_time(uint8_t *mem, uint32_t tloc_addr); -void wrapper_bzero(uint8_t *mem, uint32_t str_addr, uint32_t n); -int wrapper_fp_class_d(double d); -double wrapper_ldexp(double d, int i); -int64_t wrapper___ll_mul(int64_t a0, int64_t a1); -int64_t wrapper___ll_div(int64_t a0, int64_t a1); -int64_t wrapper___ll_rem(uint64_t a0, int64_t a1); -int64_t wrapper___ll_lshift(int64_t a0, uint64_t shift); -int64_t wrapper___ll_rshift(int64_t a0, uint64_t shift); -uint64_t wrapper___ull_div(uint64_t a0, uint64_t a1); -uint64_t wrapper___ull_rem(uint64_t a0, uint64_t a1); -uint64_t wrapper___ull_rshift(uint64_t a0, uint64_t shift); -uint64_t wrapper___d_to_ull(double d); -int64_t wrapper___d_to_ll(double d); -uint64_t wrapper___f_to_ull(float f); -int64_t wrapper___f_to_ll(float f); -float wrapper___ull_to_f(uint64_t v); -float wrapper___ll_to_f(int64_t v); -double wrapper___ull_to_d(uint64_t v); -double wrapper___ll_to_d(int64_t v); -void wrapper_abort(uint8_t *mem); -void wrapper_exit(uint8_t *mem, int status); -void wrapper__exit(uint8_t *mem, int status); -void wrapper__cleanup(uint8_t *mem); -uint32_t wrapper__rld_new_interface(uint8_t *mem, uint32_t operation, uint32_t sp); -void wrapper__exithandle(uint8_t *mem); -int wrapper__prctl(uint8_t *mem, int operation, uint32_t sp); -double wrapper__atod(uint8_t *mem, uint32_t buffer_addr, int ndigits, int dexp); -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_gettxt(uint8_t *mem, uint32_t msgid_addr, uint32_t default_str_addr); -uint32_t wrapper_setlocale(uint8_t *mem, int category, uint32_t locale_addr); -uint32_t wrapper_mmap(uint8_t *mem, uint32_t addr, uint32_t length, int prot, int flags, int fd, int offset); -int wrapper_munmap(uint8_t *mem, uint32_t addr, uint32_t length); -int wrapper_mprotect(uint8_t *mem, uint32_t addr, uint32_t length, int prot); -int wrapper_sysconf(uint8_t *mem, int name); -int wrapper_getpagesize(uint8_t *mem); -int wrapper_strerror(uint8_t *mem, int errnum); -int wrapper_ioctl(uint8_t *mem, int fd, uint32_t request, uint32_t sp); -int wrapper_fcntl(uint8_t *mem, int fd, int cmd, uint32_t sp); -uint32_t wrapper_signal(uint8_t *mem, int signum, uint64_t (*trampoline)(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest), uint32_t handler_addr, uint32_t sp); -uint32_t wrapper_sigset(uint8_t *mem, int signum, uint64_t (*trampoline)(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest), uint32_t disp_addr, uint32_t sp); -int wrapper_get_fpc_csr(uint8_t *mem); -int wrapper_set_fpc_csr(uint8_t *mem, int csr); -int wrapper_setjmp(uint8_t *mem, uint32_t addr); -void wrapper_longjmp(uint8_t *mem, uint32_t addr, int status); -uint32_t wrapper_tempnam(uint8_t *mem, uint32_t dir_addr, uint32_t pfx_addr); -uint32_t wrapper_tmpnam(uint8_t *mem, uint32_t str_addr); -uint32_t wrapper_mktemp(uint8_t *mem, uint32_t template_addr); -int wrapper_mkstemp(uint8_t *mem, uint32_t name_addr); -uint32_t wrapper_tmpfile(uint8_t *mem); -int wrapper_wait(uint8_t *mem, uint32_t wstatus_addr); -int wrapper_kill(uint8_t *mem, int pid, int sig); -int wrapper_execlp(uint8_t *mem, uint32_t file_addr, uint32_t sp); -int wrapper_execv(uint8_t *mem, uint32_t pathname_addr, uint32_t argv_addr); -int wrapper_execvp(uint8_t *mem, uint32_t file_addr, uint32_t argv_addr); -int wrapper_fork(uint8_t *mem); -int wrapper_system(uint8_t *mem, uint32_t command_addr); -uint32_t wrapper_tsearch(uint8_t *mem, uint32_t key_addr, uint32_t rootp_addr, uint32_t compar_addr); -uint32_t wrapper_tfind(uint8_t *mem, uint32_t key_addr, uint32_t rootp_addr, uint32_t compar_addr); -uint32_t wrapper_qsort(uint8_t *mem, uint32_t base_addr, uint32_t num, uint32_t size, uint64_t (*trampoline)(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest), uint32_t compare_addr, uint32_t sp); -uint32_t wrapper_regcmp(uint8_t *mem, uint32_t string1_addr, uint32_t sp); -uint32_t wrapper_regex(uint8_t *mem, uint32_t re_addr, uint32_t subject_addr, uint32_t sp); -void wrapper___assert(uint8_t *mem, uint32_t assertion_addr, uint32_t file_addr, int line); diff --git a/tools/ido5.3_recomp/recomp.cpp b/tools/ido5.3_recomp/recomp.cpp deleted file mode 100644 index 59543056..00000000 --- a/tools/ido5.3_recomp/recomp.cpp +++ /dev/null @@ -1,2933 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "elf.h" - -#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 - -#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])) - -using namespace std; - -struct Edge { - uint32_t i; - uint8_t function_entry: 1; - uint8_t function_exit: 1; - uint8_t extern_function: 1; - uint8_t function_pointer: 1; -}; - -struct Insn { - uint32_t id; - uint8_t op_count; - string mnemonic; - string op_str; - cs_mips_op operands[8]; - - uint8_t is_jump: 1; - uint8_t is_global_got_memop: 1; - uint8_t no_following_successor: 1; - int linked_insn; - union { - uint32_t linked_value; - float linked_float; - }; - uint32_t jtbl_addr; - uint32_t num_cases; - mips_reg index_reg; - vector successors; - vector predecessors; - uint64_t b_liveout; - uint64_t b_livein; - uint64_t f_livein; - uint64_t f_liveout; -}; - -struct Function { - vector returns; //points to delay slots - uint32_t end_addr; //address after end - uint32_t nargs; - uint32_t nret; - bool v0_in; - bool referenced_by_function_pointer; -}; - -static bool conservative; - -static csh handle; - -static const uint8_t *text_section; -static uint32_t text_section_len; -static uint32_t text_vaddr; - -static const uint8_t *rodata_section; -static uint32_t rodata_section_len; -static uint32_t rodata_vaddr; - -static const uint8_t *data_section; -static uint32_t data_section_len; -static uint32_t data_vaddr; - -static uint32_t bss_section_len; -static uint32_t bss_vaddr; - -static vector insns; -static set label_addresses; -static vector got_globals; -static vector got_locals; -static uint32_t gp_value; -static uint32_t gp_value_adj; - -static map symbol_names; - -static vector> data_function_pointers; -static set li_function_pointers; -static map functions; -static uint32_t main_addr; -static uint32_t mcount_addr; -static uint32_t procedure_table_start; -static uint32_t procedure_table_len; - -#define FLAG_NO_MEM 1 -#define FLAG_VARARG 2 - -static const struct { - const char *name; - const char *params; - int flags; -} extern_functions[] = { - {"exit", "vi"}, // override exit from application - {"abort", "v"}, - {"sbrk", "pi"}, - {"malloc", "pu"}, - {"calloc", "puu"}, - {"realloc", "ppu"}, - {"free", "vp"}, - {"fscanf", "ipp", FLAG_VARARG}, - {"printf", "ip", FLAG_VARARG}, - {"sprintf", "ipp", FLAG_VARARG}, - {"fprintf", "ipp", FLAG_VARARG}, - {"_doprnt", "ippp"}, - {"strlen", "up"}, - {"open", "ipii"}, - {"creat", "ipi"}, - {"access", "ipi"}, - {"rename", "ipp"}, - {"utime", "ipp"}, - {"flock", "iii"}, - {"chmod", "ipu"}, - {"umask", "ii", FLAG_NO_MEM}, - {"ecvt", "pdipp"}, - {"fcvt", "pdipp"}, - {"sqrt", "dd", FLAG_NO_MEM}, - {"sqrtf", "ff", FLAG_NO_MEM}, - {"atoi", "ip"}, - {"atol", "ip"}, - {"atof", "dp"}, - {"strtol", "ippi"}, - {"strtoul", "uppi"}, - {"strtod", "dpp"}, - {"strchr", "ppi"}, - {"strrchr", "ppi"}, - {"strcspn", "upp"}, - {"strpbrk", "ppp"}, - {"fstat", "iip"}, - {"stat", "ipp"}, - {"ftruncate", "iii"}, - {"bcopy", "vppu"}, - {"memcpy", "pppu"}, - {"memccpy", "pppiu"}, - {"read", "iipu"}, - {"write", "iipu"}, - {"fopen", "ppp"}, - {"freopen", "pppp"}, - {"fclose", "ip"}, - {"ftell", "ip"}, - {"rewind", "vp"}, - {"fseek", "ipii"}, - {"lseek", "iiii"}, - {"fflush", "ip"}, - {"dup", "ii"}, - {"dup2", "iii"}, - {"pipe", "ip"}, - {"perror", "vp"}, - {"fdopen", "iip"}, - {"memset", "ppiu"}, - {"bcmp", "ippu"}, - {"memcmp", "ippu"}, - {"getpid", "i", FLAG_NO_MEM}, - {"getpgrp", "i"}, - {"remove", "ip"}, - {"unlink", "ip"}, - {"close", "ii"}, - {"strcmp", "ipp"}, - {"strncmp", "ippu"}, - {"strcpy", "ppp"}, - {"strncpy", "pppu"}, - {"strcat", "ppp"}, - {"strncat", "pppu"}, - {"strtok", "ppp"}, - {"strstr", "ppp"}, - {"strdup", "pp"}, - {"toupper", "ii", FLAG_NO_MEM}, - {"tolower", "ii", FLAG_NO_MEM}, - {"gethostname", "ipu"}, - {"isatty", "ii"}, - {"strftime", "upupp"}, - {"times", "ip"}, - {"clock", "i", FLAG_NO_MEM}, - {"ctime", "pp"}, - {"localtime", "pp"}, - {"setvbuf", "ippiu"}, - {"__semgetc", "ip"}, - {"__semputc", "iip"}, - {"fgetc", "ip"}, - {"fgets", "ipip"}, - {"__filbuf", "ip"}, - {"__flsbuf", "iip"}, - {"ungetc", "iip"}, - {"gets", "pp"}, - {"fread", "upuup"}, - {"fwrite", "upuup"}, - {"fputs", "ipp"}, - {"puts", "ip"}, - {"getcwd", "ppu"}, - {"time", "ip"}, - {"bzero", "vpu"}, - {"fp_class_d", "id", FLAG_NO_MEM}, - {"ldexp", "ddi", FLAG_NO_MEM}, - {"__ll_mul", "lll", FLAG_NO_MEM}, - {"__ll_div", "lll", FLAG_NO_MEM}, - {"__ll_rem", "ljl", FLAG_NO_MEM}, - {"__ll_lshift", "llj", FLAG_NO_MEM}, - {"__ll_rshift", "llj", FLAG_NO_MEM}, - {"__ull_div", "jjj", FLAG_NO_MEM}, - {"__ull_rem", "jjj", FLAG_NO_MEM}, - {"__ull_rshift", "jjj", FLAG_NO_MEM}, - {"__d_to_ull", "jd", FLAG_NO_MEM}, - {"__d_to_ll", "ld", FLAG_NO_MEM}, - {"__f_to_ull", "jf", FLAG_NO_MEM}, - {"__f_to_ll", "lf", FLAG_NO_MEM}, - {"__ull_to_f", "fj", FLAG_NO_MEM}, - {"__ll_to_f", "fl", FLAG_NO_MEM}, - {"__ull_to_d", "dj", FLAG_NO_MEM}, - {"__ll_to_d", "dl", FLAG_NO_MEM}, - {"_exit", "vi"}, - {"_cleanup", "v"}, - {"_rld_new_interface", "pu", FLAG_VARARG}, - {"_exithandle", "v"}, - {"_prctl", "ii", FLAG_VARARG}, - {"_atod", "dpii"}, - {"pathconf", "ipi"}, - {"getenv", "pp"}, - {"gettxt", "ppp"}, - {"setlocale", "pip"}, - {"mmap", "ppuiiii"}, - {"munmap", "ipu"}, - {"mprotect", "ipui"}, - {"sysconf", "ii"}, - {"getpagesize", "i"}, - {"strerror", "pi"}, - {"ioctl", "iiu", FLAG_VARARG}, - {"fcntl", "iii", FLAG_VARARG}, - {"signal", "pit"}, - {"sigset", "pit"}, - {"get_fpc_csr", "i"}, - {"set_fpc_csr", "ii"}, - {"setjmp", "ip"}, - {"longjmp", "vpi"}, - {"tempnam", "ppp"}, - {"tmpnam", "pp"}, - {"mktemp", "pp"}, - {"mkstemp", "ip"}, - {"tmpfile", "p"}, - {"wait", "ip"}, - {"kill", "iii"}, - {"execlp", "ip", FLAG_VARARG}, - {"execv", "ipp"}, - {"execvp", "ipp"}, - {"fork", "i"}, - {"system", "ip"}, - {"tsearch", "pppp"}, - {"tfind", "pppp"}, - {"qsort", "vpuut"}, - {"regcmp", "pp", FLAG_VARARG}, - {"regex", "ppp", FLAG_VARARG}, - {"__assert", "vppi"}, -}; - -static void disassemble(void) { - csh handle; - cs_insn *disasm; - static size_t disasm_size; - 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)); - } - 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); - - { - // Add dummy instruction to avoid out of bounds - insns.push_back(Insn()); - Insn& insn = insns.back(); - insn.id = MIPS_INS_NOP; - insn.mnemonic = "nop"; - insn.no_following_successor = true; - } -} - -static void add_function(uint32_t addr) { - if (addr >= text_vaddr && addr < text_vaddr + text_section_len) { - functions[addr]; - } -} - -static map::iterator find_function(uint32_t addr) { - if (functions.size() == 0) { - return functions.end(); - } - auto it = functions.upper_bound(addr); - if (it == functions.begin()) { - return functions.end(); - } - --it; - return it; -} - -// try to find a matching LUI for a given register -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); - 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) { - uint32_t rd = insns[search].operands[0].reg; - if (reg == rd) { - break; - } - } else if (insns[search].id == MIPS_INS_LW || - insns[search].id == MIPS_INS_LD || - insns[search].id == MIPS_INS_ADDIU || - //insns[search].id == MIPS_INS_ADDU || used in jump tables for offset - insns[search].id == MIPS_INS_ADD || - insns[search].id == MIPS_INS_SUB || - insns[search].id == MIPS_INS_SUBU) { - uint32_t rd = insns[search].operands[0].reg; - if (reg == rd) { - if (insns[search].id == MIPS_INS_LW && insns[search].operands[1].mem.base == MIPS_REG_GP) { - int mem_imm0 = (int)insns[search].operands[1].mem.disp; - uint32_t got_entry = (mem_imm0 + gp_value_adj) / sizeof(uint32_t); - if (got_entry < got_locals.size()) { - // used for static functions - char buf[32]; - uint32_t addr = got_locals[got_entry] + mem_imm; - insns[search].linked_insn = offset; - insns[search].linked_value = addr; - insns[offset].linked_insn = search; - insns[offset].linked_value = addr; - - //vaddr_references[addr].insert(text_vaddr + offset * 4); - - insns[search].id = MIPS_INS_LI; - insns[search].mnemonic = "li"; - sprintf(buf, "$%s, 0x%x", cs_reg_name(handle, rd), addr); - insns[search].op_str = buf; - insns[search].operands[1].type = MIPS_OP_IMM; - insns[search].operands[1].imm = addr; - - switch (insns[offset].id) { - case MIPS_INS_ADDIU: - insns[offset].id = MIPS_INS_MOVE; - insns[offset].operands[1].type = MIPS_OP_REG; - insns[offset].mnemonic = "move"; - sprintf(buf, "$%s, $%s", cs_reg_name(handle, insns[offset].operands[0].reg), cs_reg_name(handle, rd)); - insns[offset].op_str = buf; - if (addr >= text_vaddr && addr < text_vaddr + text_section_len) { - add_function(addr); - } - break; - case MIPS_INS_LB: - case MIPS_INS_LBU: - case MIPS_INS_SB: - case MIPS_INS_LH: - case MIPS_INS_LHU: - case MIPS_INS_SH: - case MIPS_INS_LW: - case MIPS_INS_SW: - case MIPS_INS_LDC1: - case MIPS_INS_LWC1: - case MIPS_INS_SWC1: - insns[offset].operands[1].mem.disp = 0; - sprintf(buf, "$%s, ($%s)", cs_reg_name(handle, insns[offset].operands[0].reg), cs_reg_name(handle, rd)); - insns[offset].op_str = buf; - break; - default: - assert(0); - } - } - break; - } else { - // ignore: reg is pointer, offset is probably struct data member - break; - } - } - } else if (insns[search].id == MIPS_INS_JR && - insns[search].operands[0].reg == MIPS_REG_RA && offset - search >= 2) { - // stop looking when previous `jr ra` is hit, - // but ignore if `offset` is branch delay slot for this `jr ra` - break; - } - } -} - -// for a given `jalr t9`, find the matching t9 load -static void link_with_jalr(int offset) -{ - // end search after some sane max number of instructions - int end_search = 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) { - if (insns[search].is_global_got_memop || insns[search].id == MIPS_INS_LI) { - char buf[32]; - sprintf(buf, "0x%x", insns[search].linked_value); - insns[search].linked_insn = offset; - insns[offset].linked_insn = search; - insns[offset].linked_value = insns[search].linked_value; - //insns[offset].label = insns[search].label; - //function_entry_points.insert(insns[search].linked_value); - insns[offset].id = MIPS_INS_JAL; - insns[offset].mnemonic = "jal"; - insns[offset].op_str = buf; - insns[offset].operands[0].type = MIPS_OP_IMM; - insns[offset].operands[0].imm = insns[search].linked_value; - insns[search].id = MIPS_INS_NOP; - insns[search].mnemonic = "nop"; - insns[search].op_str = ""; - insns[search].is_global_got_memop = false; - add_function(insns[search].linked_value); - } - break; - } else if (insns[search].id == MIPS_INS_ADDIU) { - if (insns[search].linked_insn != -1) { - //function_entry_points.insert(insns[search].linked_value); - uint32_t first = insns[search].linked_insn; - insns[search].linked_insn = offset; - insns[offset].linked_insn = first; - insns[offset].linked_value = insns[search].linked_value; - } - break; - } else if (insns[search].id == MIPS_INS_LI) { - if (insns[search].linked_insn != -1) { - //function_entry_points.insert(insns[search].linked_value); - uint32_t first = insns[search].linked_insn; - insns[search].linked_insn = offset; - insns[offset].linked_insn = first; - insns[offset].linked_value = insns[search].linked_value; - insns[search].id = MIPS_INS_NOP; - insns[search].mnemonic = "nop"; - insns[search].op_str = ""; - } - break; - } else if (insns[search].id == MIPS_INS_LD || - insns[search].id == MIPS_INS_ADDU || - insns[search].id == MIPS_INS_ADD || - insns[search].id == MIPS_INS_SUB || - insns[search].id == MIPS_INS_SUBU) { - break; - } - } else if (insns[search].id == MIPS_INS_JR && - insns[search].operands[0].reg == MIPS_REG_RA) - { - // stop looking when previous `jr ra` is hit - break; - } - } -} - -static void pass1(void) { - for (size_t i = 0; i < insns.size(); i++) { - Insn& insn = insns[i]; - if (insn.id == MIPS_INS_BAL) { - insn.id = MIPS_INS_JAL; - insn.mnemonic = "jal"; - } - if (insn.is_jump) { - if (insn.id == MIPS_INS_JAL || insn.id == MIPS_INS_J) { - uint32_t target = (uint32_t)insn.operands[0].imm; - label_addresses.insert(target); - add_function(target); - } else if (insn.id == MIPS_INS_JR) { - // sltiu $at, $ty, z - // sw $reg, offset($sp) (very seldom, one or more, usually in func entry) - // lw $gp, offset($sp) (if PIC, and very seldom) - // beqz $at, .L - // some other instruction (not always) - // lui $at, %hi(jtbl) - // sll $tx, $ty, 2 - // addu $at, $at, $tx - // lw $tx, %lo(jtbl)($at) - // nop (code compiled with 5.3) - // addu $tx, $tx, $gp (if PIC) - // jr $tx - - // IDO 7.1: - //lw at,offset(gp) - //andi t9,t8,0x3f - //sll t9,t9,0x2 - //addu at,at,t9 - //lw t9,offset(at) - //addu t9,t9,gp - //jr t9 - - // IDO 5.3: - //lw at,offset(gp) - //andi t3,t2,0x3f - //sll t3,t3,0x2 - //addu at,at,t3 - //something - //lw t3,offset(at) - //something - //addu t3,t3,gp - //jr t3 - if (i >= 7 && rodata_section != NULL) { - bool is_pic = insns[i - 1].id == MIPS_INS_ADDU && insns[i - 1].operands[2].reg == MIPS_REG_GP; - bool has_nop = insns[i - is_pic - 1].id == MIPS_INS_NOP; - bool has_extra = insns[i - is_pic - has_nop - 5].id != MIPS_INS_BEQZ; - int lw = i - is_pic - has_nop - 1; - if (insns[lw].id != MIPS_INS_LW) { - --lw; - } - if (insns[lw].id == MIPS_INS_LW && insns[lw].linked_insn != -1) { - int sltiu_index = -1; - int andi_index = -1; - uint32_t addu_index = lw - 1; - uint32_t num_cases; - bool found = false; - bool and_variant = false; - int end = 14; - if (insns[addu_index].id != MIPS_INS_ADDU) { - --addu_index; - } - mips_reg index_reg = (mips_reg)insns[addu_index - 1].operands[1].reg; - if (insns[addu_index].id != MIPS_INS_ADDU) { - goto skip; - } - if (insns[addu_index - 1].id != MIPS_INS_SLL) { - goto skip; - } - if (insns[addu_index - 1].operands[0].reg != insn.operands[0].reg) { - goto skip; - } - for (int j = 3; j <= 4; j++) { - if (insns[lw - j].id == MIPS_INS_ANDI) { - andi_index = lw - j; - break; - } - } - if (i == 368393) { - // In copt - end = 18; - } - for (int j = 5; j <= end; j++) { - if (insns[lw - has_extra - j].id == MIPS_INS_SLTIU && - insns[lw - has_extra - j].operands[0].reg == MIPS_REG_AT) - { - sltiu_index = j; - break; - } - if (insns[lw - has_extra - j].id == MIPS_INS_JR) { - // Prevent going into a previous switch - break; - } - } - if (sltiu_index != -1) { - andi_index = -1; - } - if (sltiu_index != -1 && insns[lw - has_extra - sltiu_index].id == MIPS_INS_SLTIU) { - num_cases = insns[lw - has_extra - sltiu_index].operands[2].imm; - found = true; - } else if (andi_index != -1) { - num_cases = insns[andi_index].operands[2].imm + 1; - found = true; - and_variant = true; - } else if (i == 219382) { - // Special hard case in copt where the initial sltiu is in another basic block - found = true; - num_cases = 13; - } else if (i == 370995) { - // Special hard case in copt where the initial sltiu is in another basic block - found = true; - num_cases = 12; - } - if (found) { - uint32_t jtbl_addr = insns[lw].linked_value; - if (is_pic) { - insns[i - 1].id = MIPS_INS_NOP; - } - //printf("jump table at %08x, size %u\n", jtbl_addr, num_cases); - insn.jtbl_addr = jtbl_addr; - insn.num_cases = num_cases; - insn.index_reg = index_reg; - insns[lw].id = MIPS_INS_NOP; - insns[addu_index].id = MIPS_INS_NOP; - insns[addu_index - 1].id = MIPS_INS_NOP; - if (!and_variant) { - insns[addu_index - 2].id = MIPS_INS_NOP; - } - - if (jtbl_addr < rodata_vaddr || jtbl_addr + num_cases * sizeof(uint32_t) > rodata_vaddr + rodata_section_len) { - fprintf(stderr, "jump table outside rodata\n"); - exit(EXIT_FAILURE); - } - for (uint32_t i = 0; i < num_cases; i++) { - uint32_t target_addr = read_u32_be(rodata_section + (jtbl_addr - rodata_vaddr) + i * sizeof(uint32_t)); - target_addr += gp_value; - //printf("%08X\n", target_addr); - label_addresses.insert(target_addr); - } - } - skip:; - } - } - } else { - for (int j = 0; j < insn.op_count; j++) { - if (insn.operands[j].type == MIPS_OP_IMM) { - uint32_t target = (uint32_t)insn.operands[j].imm; - label_addresses.insert(target); - } - } - } - } - switch (insns[i].id) { - // find floating point LI - case MIPS_INS_MTC1: - { - unsigned int rt = insns[i].operands[0].reg; - for (int s = i - 1; s >= 0; s--) { - if (insns[s].id == MIPS_INS_LUI && insns[s].operands[0].reg == rt) { - float f; - uint32_t lui_imm = (uint32_t)(insns[s].operands[1].imm << 16); - memcpy(&f, &lui_imm, sizeof(f)); - insns[s].operands[1].imm <<= 16; - // link up the LUI with this instruction and the float - insns[s].linked_insn = i; - insns[s].linked_float = f; - // rewrite LUI instruction to be LI - insns[s].id = MIPS_INS_LI; - insns[s].mnemonic = "li"; - break; - } else if (insns[s].id == MIPS_INS_LW || - insns[s].id == MIPS_INS_LD || - insns[s].id == MIPS_INS_LH || - insns[s].id == MIPS_INS_LHU || - insns[s].id == MIPS_INS_LB || - insns[s].id == MIPS_INS_LBU || - insns[s].id == MIPS_INS_ADDIU || - insns[s].id == MIPS_INS_ADD || - insns[s].id == MIPS_INS_SUB || - insns[s].id == MIPS_INS_SUBU) { - unsigned int rd = insns[s].operands[0].reg; - if (rt == rd) { - break; - } - } else if (insns[s].id == MIPS_INS_JR && - insns[s].operands[0].reg == MIPS_REG_RA) { - // stop looking when previous `jr ra` is hit - break; - } - } - break; - } - case MIPS_INS_SD: - case MIPS_INS_SW: - case MIPS_INS_SH: - case MIPS_INS_SB: - case MIPS_INS_LB: - case MIPS_INS_LBU: - case MIPS_INS_LD: - case MIPS_INS_LDL: - case MIPS_INS_LDR: - case MIPS_INS_LH: - case MIPS_INS_LHU: - case MIPS_INS_LW: - case MIPS_INS_LWU: - case MIPS_INS_LDC1: - case MIPS_INS_LWC1: - case MIPS_INS_LWC2: - case MIPS_INS_LWC3: - case MIPS_INS_SWC1: - case MIPS_INS_SWC2: - case MIPS_INS_SWC3: - { - unsigned int mem_rs = insns[i].operands[1].mem.base; - int mem_imm = (int)insns[i].operands[1].mem.disp; - if (mem_rs == MIPS_REG_GP) { - unsigned int got_entry = (mem_imm + gp_value_adj) / sizeof(unsigned int); - if (got_entry >= got_locals.size()) { - got_entry -= got_locals.size(); - if (got_entry < got_globals.size()) { - assert(insn.id == MIPS_INS_LW); - //printf("gp 0x%08x %s\n", mem_imm, got_globals[got_entry].name); - unsigned int dest_vaddr = got_globals[got_entry]; - insns[i].is_global_got_memop = true; - insns[i].linked_value = dest_vaddr; - //insns[i].label = got_globals[got_entry].name; - - //vaddr_references[dest_vaddr].insert(vaddr + i * 4); - //disasm_add_data_addr(state, dest_vaddr); - insns[i].id = MIPS_INS_LI; - insns[i].operands[1].imm = dest_vaddr; - char buf[32]; - sprintf(buf, "$%s, 0x%x", cs_reg_name(handle, insn.operands[0].reg), dest_vaddr); - insns[i].op_str = buf; - } - } - } else { - link_with_lui(i, mem_rs, mem_imm); - } - break; - } - case MIPS_INS_ADDIU: - case MIPS_INS_ORI: - { - unsigned int rd = insns[i].operands[0].reg; - unsigned int rs = insns[i].operands[1].reg; - int64_t imm = insns[i].operands[2].imm; - if (rs == MIPS_REG_ZERO) { // becomes LI - char buf[32]; - insns[i].id = MIPS_INS_LI; - insns[i].operands[1].imm = imm; - insns[i].mnemonic = "li"; - sprintf(buf, "$%s, %" PRIi64, cs_reg_name(handle, rd), imm); - insns[i].op_str = buf; - } else if (/*rd == rs &&*/ rd != MIPS_REG_GP) { // only look for LUI if rd and rs are the same - link_with_lui(i, rs, (int)imm); - } - break; - } - case MIPS_INS_JALR: - { - unsigned int r = insn.operands[0].reg; - if (r == MIPS_REG_T9) { - link_with_jalr(i); - if (insn.linked_insn != -1) { - char buf[32]; - sprintf(buf, "0x%x", insn.linked_value); - insn.id = MIPS_INS_JAL; - insn.mnemonic = "jal"; - insn.op_str = buf; - insn.operands[0].type = MIPS_OP_IMM; - insn.operands[0].imm = insn.linked_value; - label_addresses.insert(insn.linked_value); - add_function(insn.linked_value); - } - } - break; - } - } - if (insn.id == MIPS_INS_ADDU && insn.operands[0].reg == MIPS_REG_GP && insn.operands[1].reg == MIPS_REG_GP && insn.operands[2].reg == MIPS_REG_T9 && i >= 2) { - //state->function_entry_points.insert(vaddr + (i - 2) * 4); - for (int j = i - 2; j <= i; j++) { - insns[j].id = MIPS_INS_NOP; - insns[j].mnemonic = "nop"; - insns[j].op_str = ""; - } - } - } -} - -static uint32_t addr_to_i(uint32_t addr) { - return (addr - text_vaddr) / 4; -} - -static void pass2(void) { - // Find returns in each function - for (size_t i = 0; i < insns.size(); i++) { - uint32_t addr = text_vaddr + i * 4; - Insn& insn = insns[i]; - if (insn.id == MIPS_INS_JR && insn.operands[0].reg == MIPS_REG_RA) { - auto it = find_function(addr); - assert(it != functions.end()); - it->second.returns.push_back(addr + 4); - } - if (insn.is_global_got_memop && text_vaddr <= insn.operands[1].imm && insn.operands[1].imm < text_vaddr + text_section_len) { - uint32_t faddr = insn.operands[1].imm; - li_function_pointers.insert(faddr); - functions[faddr].referenced_by_function_pointer = true; -#if INSPECT_FUNCTION_POINTERS - fprintf(stderr, "li function pointer: 0x%x at 0x%x\n", faddr, addr); -#endif - } - } - for (auto it = functions.begin(); it != functions.end(); ++it) { - if (it->second.returns.size() == 0) { - uint32_t i = addr_to_i(it->first); - auto str_it = symbol_names.find(it->first); - if (str_it != symbol_names.end() && str_it->second == "__start") { - - } else if (str_it != symbol_names.end() && str_it->second == "xmalloc") { - // orig 5.3: - /* - 496bf4: 3c1c0fb9 lui gp,0xfb9 - 496bf8: 279c366c addiu gp,gp,13932 - 496bfc: 0399e021 addu gp,gp,t9 - 496c00: 27bdffd8 addiu sp,sp,-40 - 496c04: 8f858de8 lw a1,-29208(gp) - 496c08: 10000006 b 496c24 - 496c0c: afbf0020 sw ra,32(sp) - */ - - // jal alloc_new - // lui $a1, malloc_scb - // jr $ra - // nop - uint32_t alloc_new_addr = text_vaddr + (i + 7) * 4; - insns[i].id = MIPS_INS_JAL; - insns[i].op_count = 1; - insns[i].mnemonic = "jal"; - insns[i].op_str = "alloc_new"; - insns[i].operands[0].imm = alloc_new_addr; - assert(symbol_names.count(alloc_new_addr) && symbol_names[alloc_new_addr] == "alloc_new"); - i++; - if (insns[i + 5].id == MIPS_INS_LI) { - // 7.1 - insns[i] = insns[i + 5]; - } else { - // 5.3 - insns[i] = insns[i + 3]; - } - i++; - insns[i].id = MIPS_INS_JR; - insns[i].op_count = 1; - insns[i].mnemonic = "jr"; - insns[i].op_str = "$ra"; - insns[i].operands[0].reg = MIPS_REG_RA; - it->second.returns.push_back(text_vaddr + i * 4 + 4); - i++; - for (uint32_t j = 0; j < 4; j++) { - insns[i].id = MIPS_INS_NOP; - insns[i].op_count = 0; - insns[i].mnemonic = "nop"; - i++; - } - } else if (str_it != symbol_names.end() && str_it->second == "xfree") { - // jal alloc_dispose - // lui $a1, malloc_scb - // jr $ra - // nop - uint32_t alloc_dispose_addr = text_vaddr + (i + 4) * 4; - if (symbol_names.count(alloc_dispose_addr + 4) && symbol_names[alloc_dispose_addr + 4] == "alloc_dispose") { - alloc_dispose_addr += 4; - } - insns[i].id = MIPS_INS_JAL; - insns[i].op_count = 1; - insns[i].mnemonic = "jal"; - insns[i].op_str = "alloc_dispose"; - insns[i].operands[0].imm = alloc_dispose_addr; - assert(symbol_names.count(alloc_dispose_addr) && symbol_names[alloc_dispose_addr] == "alloc_dispose"); - i++; - insns[i] = insns[i + 2]; - i++; - insns[i].id = MIPS_INS_JR; - insns[i].op_count = 1; - insns[i].mnemonic = "jr"; - insns[i].op_str = "$ra"; - insns[i].operands[0].reg = MIPS_REG_RA; - it->second.returns.push_back(text_vaddr + i * 4 + 4); - i++; - insns[i].id = MIPS_INS_NOP; - insns[i].op_count = 0; - insns[i].mnemonic = "nop"; - } else if (insns[i].id == MIPS_INS_LW && insns[i + 1].id == MIPS_INS_MOVE && insns[i + 2].id == MIPS_INS_JALR) { - /* - 408f50: 8f998010 lw t9,-32752(gp) - 408f54: 03e07821 move t7,ra - 408f58: 0320f809 jalr t9 - */ - } else if (it->first > mcount_addr) { - fprintf(stderr, "no ret: 0x%x\n", it->first); - abort(); - } - } - auto next = it; - ++next; - if (next == functions.end()) { - it->second.end_addr = text_vaddr + text_section_len; - } else { - it->second.end_addr = next->first; - } - } -} - -static void add_edge(uint32_t from, uint32_t to, bool function_entry = false, bool function_exit = false, bool extern_function = false, bool function_pointer = false) { - Edge fe = Edge(), be = Edge(); - fe.i = to; - be.i = from; - fe.function_entry = function_entry; - be.function_entry = function_entry; - fe.function_exit = function_exit; - be.function_exit = function_exit; - fe.extern_function = extern_function; - be.extern_function = extern_function; - fe.function_pointer = function_pointer; - be.function_pointer = function_pointer; - insns[from].successors.push_back(fe); - insns[to].predecessors.push_back(be); -} - -static void pass3(void) { - // Build graph - for (size_t i = 0; i < insns.size(); i++) { - uint32_t addr = text_vaddr + i * 4; - Insn& insn = insns[i]; - if (insn.no_following_successor) { - continue; - } - switch (insn.id) { - case MIPS_INS_BEQ: - case MIPS_INS_BGEZ: - case MIPS_INS_BGTZ: - case MIPS_INS_BLEZ: - case MIPS_INS_BLTZ: - case MIPS_INS_BNE: - case MIPS_INS_BEQZ: - case MIPS_INS_BNEZ: - case MIPS_INS_BC1F: - case MIPS_INS_BC1T: - add_edge(i, i + 1); - add_edge(i + 1, addr_to_i((uint32_t)insn.operands[insn.op_count - 1].imm)); - break; - - case MIPS_INS_BEQL: - case MIPS_INS_BGEZL: - case MIPS_INS_BGTZL: - case MIPS_INS_BLEZL: - case MIPS_INS_BLTZL: - case MIPS_INS_BNEL: - case MIPS_INS_BC1FL: - case MIPS_INS_BC1TL: - add_edge(i, i + 1); - add_edge(i, i + 2); - add_edge(i + 1, addr_to_i((uint32_t)insn.operands[insn.op_count - 1].imm)); - insns[i + 1].no_following_successor = true; // don't inspect delay slot - break; - - case MIPS_INS_B: - case MIPS_INS_J: - add_edge(i, i + 1); - add_edge(i + 1, addr_to_i((uint32_t)insn.operands[0].imm)); - insns[i + 1].no_following_successor = true; // don't inspect delay slot - break; - - case MIPS_INS_JR: { - add_edge(i, i + 1); - if (insn.jtbl_addr != 0) { - uint32_t jtbl_pos = insn.jtbl_addr - rodata_vaddr; - assert(jtbl_pos < rodata_section_len && jtbl_pos + insn.num_cases * 4 <= rodata_section_len); - for (uint32_t j = 0; j < insn.num_cases; j++) { - uint32_t dest_addr = read_u32_be(rodata_section + jtbl_pos + j * 4) + gp_value; - add_edge(i + 1, addr_to_i(dest_addr)); - } - } else { - assert(insn.operands[0].reg == MIPS_REG_RA && "jump to address in register not supported"); - } - insns[i + 1].no_following_successor = true; // don't inspect delay slot - break; - } - - case MIPS_INS_JAL: { - add_edge(i, i + 1); - uint32_t dest = (uint32_t)insn.operands[0].imm; - if (dest > mcount_addr && dest >= text_vaddr && dest < text_vaddr + text_section_len) { - add_edge(i + 1, addr_to_i(dest), true); - auto it = functions.find(dest); - assert(it != functions.end()); - for (uint32_t ret_instr : it->second.returns) { - add_edge(addr_to_i(ret_instr), i + 2, false, true); - } - } else { - add_edge(i + 1, i + 2, false, false, true); - } - insns[i + 1].no_following_successor = true; // don't inspect delay slot - break; - } - - case MIPS_INS_JALR: - // function pointer - add_edge(i, i + 1); - add_edge(i + 1, i + 2, false, false, false, true); - insns[i + 1].no_following_successor = true; // don't inspect delay slot - break; - - default: - add_edge(i, i + 1); - break; - } - } -} - -static uint64_t map_reg(int32_t reg) { - if (reg > MIPS_REG_31) { - if (reg == MIPS_REG_HI) { - reg = MIPS_REG_31 + 1; - } else if (reg == MIPS_REG_LO) { - reg = MIPS_REG_31 + 2; - } else { - return 0; - } - } - return (uint64_t)1 << (reg - MIPS_REG_0 + 1); -} - -static uint64_t temporary_regs(void) { - return - map_reg(MIPS_REG_T0) | - map_reg(MIPS_REG_T1) | - map_reg(MIPS_REG_T2) | - map_reg(MIPS_REG_T3) | - map_reg(MIPS_REG_T4) | - map_reg(MIPS_REG_T5) | - map_reg(MIPS_REG_T6) | - map_reg(MIPS_REG_T7) | - map_reg(MIPS_REG_T8) | - map_reg(MIPS_REG_T9); -} - -typedef enum { - TYPE_NOP, - TYPE_1S, - TYPE_2S, - TYPE_1D, - TYPE_1D_1S, - TYPE_1D_2S, - TYPE_D_LO_HI_2S, - TYPE_1S_POS1 -} TYPE; -static TYPE insn_to_type(Insn& i) { - switch (i.id) { - case MIPS_INS_ADD: - case MIPS_INS_ADDU: - if (i.mnemonic != "add.s" && i.mnemonic != "add.d") { - return TYPE_1D_2S; - } else { - return TYPE_NOP; - } - - case MIPS_INS_ADDI: - case MIPS_INS_ADDIU: - case MIPS_INS_ANDI: - case MIPS_INS_ORI: - case MIPS_INS_LB: - case MIPS_INS_LBU: - case MIPS_INS_LH: - case MIPS_INS_LHU: - case MIPS_INS_LW: - case MIPS_INS_LWL: - //case MIPS_INS_LWR: - case MIPS_INS_MOVE: - case MIPS_INS_NEGU: - case MIPS_INS_NOT: - case MIPS_INS_SLL: - case MIPS_INS_SLTI: - case MIPS_INS_SLTIU: - case MIPS_INS_SRA: - case MIPS_INS_SRL: - case MIPS_INS_XORI: - return TYPE_1D_1S; - - case MIPS_INS_MFHI: - i.operands[1].reg = MIPS_REG_HI; - return TYPE_1D_1S; - - case MIPS_INS_MFLO: - i.operands[1].reg = MIPS_REG_LO; - return TYPE_1D_1S; - - case MIPS_INS_AND: - case MIPS_INS_OR: - case MIPS_INS_NOR: - case MIPS_INS_SLLV: - case MIPS_INS_SLT: - case MIPS_INS_SLTU: - case MIPS_INS_SRAV: - case MIPS_INS_SRLV: - case MIPS_INS_SUBU: - case MIPS_INS_XOR: - return TYPE_1D_2S; - - case MIPS_INS_CFC1: - case MIPS_INS_MFC1: - case MIPS_INS_LI: - case MIPS_INS_LUI: - return TYPE_1D; - - case MIPS_INS_CTC1: - case MIPS_INS_BGEZ: - case MIPS_INS_BGEZL: - case MIPS_INS_BGTZ: - case MIPS_INS_BGTZL: - case MIPS_INS_BLEZ: - case MIPS_INS_BLEZL: - case MIPS_INS_BLTZ: - case MIPS_INS_BLTZL: - case MIPS_INS_BEQZ: - case MIPS_INS_BNEZ: - case MIPS_INS_MTC1: - return TYPE_1S; - - case MIPS_INS_BEQ: - case MIPS_INS_BEQL: - case MIPS_INS_BNE: - case MIPS_INS_BNEL: - case MIPS_INS_SB: - case MIPS_INS_SH: - case MIPS_INS_SW: - case MIPS_INS_SWL: - //case MIPS_INS_SWR: - case MIPS_INS_TNE: - case MIPS_INS_TEQ: - case MIPS_INS_TGE: - case MIPS_INS_TGEU: - case MIPS_INS_TLT: - return TYPE_2S; - - case MIPS_INS_DIV: - if (i.mnemonic != "div.s" && i.mnemonic != "div.d") { - return TYPE_D_LO_HI_2S; - } else { - return TYPE_NOP; - } - - case MIPS_INS_DIVU: - case MIPS_INS_MULT: - case MIPS_INS_MULTU: - return TYPE_D_LO_HI_2S; - - case MIPS_INS_NEG: - if (i.mnemonic != "neg.s" && i.mnemonic != "neg.d") { - return TYPE_1D_1S; - } else { - return TYPE_NOP; - } - - case MIPS_INS_JALR: - return TYPE_1S; - - case MIPS_INS_JR: - if (i.jtbl_addr != 0) { - i.operands[0].reg = i.index_reg; - } - if (i.operands[0].reg == MIPS_REG_RA) { - return TYPE_NOP; - } - return TYPE_1S; - - case MIPS_INS_LWC1: - case MIPS_INS_LDC1: - case MIPS_INS_SWC1: - case MIPS_INS_SDC1: - return TYPE_1S_POS1; - - default: - return TYPE_NOP; - } -} - -static void pass4(void) { - vector q; - uint64_t livein_func_start = 1U | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) | map_reg(MIPS_REG_SP) | map_reg(MIPS_REG_ZERO); - - q.push_back(main_addr); - insns[addr_to_i(main_addr)].f_livein = livein_func_start; - - for (auto& it : data_function_pointers) { - q.push_back(it.second); - insns[addr_to_i(it.second)].f_livein = livein_func_start | map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3); - } - for (auto& addr : li_function_pointers) { - q.push_back(addr); - insns[addr_to_i(addr)].f_livein = livein_func_start | map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3); - } - - while (!q.empty()) { - uint32_t addr = q.back(); - q.pop_back(); - uint32_t idx = addr_to_i(addr); - Insn& i = insns[idx]; - uint64_t live = i.f_livein | 1; - switch (insn_to_type(i)) { - case TYPE_1D: - live |= map_reg(i.operands[0].reg); - break; - - case TYPE_1D_1S: - if (live & map_reg(i.operands[1].reg)) { - live |= map_reg(i.operands[0].reg); - } - break; - - case TYPE_1D_2S: - if ((live & map_reg(i.operands[1].reg)) && (live & map_reg(i.operands[2].reg))) { - live |= map_reg(i.operands[0].reg); - } - break; - - case TYPE_D_LO_HI_2S: - if ((live & map_reg(i.operands[0].reg)) && (live & map_reg(i.operands[1].reg))) { - live |= map_reg(MIPS_REG_LO); - live |= map_reg(MIPS_REG_HI); - } - break; - } - if ((i.f_liveout | live) == i.f_liveout) { - // No new bits - continue; - } - live |= i.f_liveout; - i.f_liveout = live; - - bool function_entry = false; - for (Edge& e : i.successors) { - uint64_t new_live = live; - if (e.function_exit) { - new_live &= 1U | map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_V1) | map_reg(MIPS_REG_ZERO); - } else if (e.function_entry) { - new_live &= 1U | map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) | - map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_SP) | map_reg(MIPS_REG_ZERO); - function_entry = true; - } else if (e.extern_function) { - string name; - bool is_extern_function = false; - size_t extern_function_id; - auto it = symbol_names.find(insns[idx - 1].operands[0].imm); - if (it != symbol_names.end()) { - name = it->second; - for (size_t i = 0; i < sizeof(extern_functions) / sizeof(extern_functions[0]); i++) { - if (name == extern_functions[i].name) { - is_extern_function = true; - extern_function_id = i; - break; - } - } - if (!is_extern_function) { - fprintf(stderr, "missing extern function: %s\n", name.c_str()); - } - } - assert(is_extern_function); - auto& fn = extern_functions[extern_function_id]; - char ret_type = fn.params[0]; - new_live &= ~(map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) | - map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_V1) | temporary_regs()); - switch (ret_type) { - case 'i': - case 'u': - case 'p': - new_live |= map_reg(MIPS_REG_V0); - break; - case 'f': - break; - case 'd': - break; - case 'v': - break; - case 'l': - case 'j': - new_live |= map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_V1); - break; - } - } else if (e.function_pointer) { - new_live &= ~(map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) | - map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_V1) | temporary_regs()); - new_live |= map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_V1); - } - if ((insns[e.i].f_livein | new_live) != insns[e.i].f_livein) { - insns[e.i].f_livein |= new_live; - q.push_back(text_vaddr + e.i * 4); - } - } - if (function_entry) { - // add one edge that skips the function call, for callee-saved register liveness propagation - live &= ~(map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) | - map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_V1) | temporary_regs()); - if ((insns[idx + 1].f_livein | live) != insns[idx + 1].f_livein) { - insns[idx + 1].f_livein |= live; - q.push_back(text_vaddr + (idx + 1) * 4); - } - } - } -} - -static void pass5(void) { - vector q; - - assert(functions.count(main_addr)); - - q = functions[main_addr].returns; - for (auto addr : q) { - insns[addr_to_i(addr)].b_liveout = 1U | map_reg(MIPS_REG_V0); - } - for (auto& it : data_function_pointers) { - for (auto addr : functions[it.second].returns) { - q.push_back(addr); - insns[addr_to_i(addr)].b_liveout = 1U | map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_V1); - } - } - for (auto& func_addr : li_function_pointers) { - for (auto addr : functions[func_addr].returns) { - q.push_back(addr); - insns[addr_to_i(addr)].b_liveout = 1U | map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_V1); - } - } - for (size_t i = 0; i < insns.size(); i++) { - if (insns[i].f_livein != 0) { - // Instruction is reachable - q.push_back(text_vaddr + i * 4); - } - } - - while (!q.empty()) { - uint32_t addr = q.back(); - q.pop_back(); - uint32_t idx = addr_to_i(addr); - Insn& i = insns[idx]; - uint64_t live = i.b_liveout | 1; - switch (insn_to_type(i)) { - case TYPE_1S: - live |= map_reg(i.operands[0].reg); - break; - - case TYPE_1S_POS1: - live |= map_reg(i.operands[1].reg); - break; - - case TYPE_2S: - live |= map_reg(i.operands[0].reg); - live |= map_reg(i.operands[1].reg); - break; - - case TYPE_1D: - live &= ~map_reg(i.operands[0].reg); - break; - - case TYPE_1D_1S: - if (live & map_reg(i.operands[0].reg)) { - live &= ~map_reg(i.operands[0].reg); - live |= map_reg(i.operands[1].reg); - } - break; - - case TYPE_1D_2S: - if (live & map_reg(i.operands[0].reg)) { - live &= ~map_reg(i.operands[0].reg); - live |= map_reg(i.operands[1].reg); - live |= map_reg(i.operands[2].reg); - } - break; - - case TYPE_D_LO_HI_2S: { - bool used = (live & map_reg(MIPS_REG_LO)) || (live & map_reg(MIPS_REG_HI)); - live &= ~map_reg(MIPS_REG_LO); - live &= ~map_reg(MIPS_REG_HI); - if (used) { - live |= map_reg(i.operands[0].reg); - live |= map_reg(i.operands[1].reg); - } - break; - } - } - if ((i.b_livein | live) == i.b_livein) { - // No new bits - continue; - } - live |= i.b_livein; - i.b_livein = live; - - bool function_exit = false; - for (Edge& e : i.predecessors) { - uint64_t new_live = live; - if (e.function_exit) { - new_live &= 1U | map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_V1); - function_exit = true; - } else if (e.function_entry) { - new_live &= 1U | map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) | - map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_SP); - } else if (e.extern_function) { - string name; - bool is_extern_function = false; - size_t extern_function_id; - auto it = symbol_names.find(insns[idx - 2].operands[0].imm); - if (it != symbol_names.end()) { - name = it->second; - for (size_t i = 0; i < sizeof(extern_functions) / sizeof(extern_functions[0]); i++) { - if (name == extern_functions[i].name) { - is_extern_function = true; - extern_function_id = i; - break; - } - } - } - assert(is_extern_function); - auto& fn = extern_functions[extern_function_id]; - uint64_t args = 1U; - if (fn.flags & FLAG_VARARG) { - // Assume the worst, that all four registers are used - for (int j = 0; j < 4; j++) { - args |= map_reg(MIPS_REG_A0 + j); - } - } - int pos = 0; - int pos_float = 0; - bool only_floats_so_far = true; - for (const char *p = fn.params + 1; *p != '\0'; ++p) { - switch (*p) { - case 'i': - case 'u': - case 'p': - case 't': - only_floats_so_far = false; - if (pos < 4) { - args |= map_reg(MIPS_REG_A0 + pos); - } - ++pos; - break; - case 'f': - if (only_floats_so_far && pos_float < 4) { - pos_float += 2; - } else if (pos < 4) { - args |= map_reg(MIPS_REG_A0 + pos); - } - ++pos; - break; - case 'd': - if (pos % 1 != 0) { - ++pos; - } - if (only_floats_so_far && pos_float < 4) { - pos_float += 2; - } else if (pos < 4) { - args |= map_reg(MIPS_REG_A0 + pos) | map_reg(MIPS_REG_A0 + pos + 1); - } - pos += 2; - break; - case 'l': - case 'j': - if (pos % 1 != 0) { - ++pos; - } - only_floats_so_far = false; - if (pos < 4) { - args |= map_reg(MIPS_REG_A0 + pos) | map_reg(MIPS_REG_A0 + pos + 1); - } - pos += 2; - break; - } - } - args |= map_reg(MIPS_REG_SP); - new_live &= ~(map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) | - map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_V1) | temporary_regs()); - new_live |= args; - } else if (e.function_pointer) { - new_live &= ~(map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) | - map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_V1) | temporary_regs()); - new_live |= map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) | map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3); - } - if ((insns[e.i].b_liveout | new_live) != insns[e.i].b_liveout) { - insns[e.i].b_liveout |= new_live; - q.push_back(text_vaddr + e.i * 4); - } - } - if (function_exit) { - // add one edge that skips the function call, for callee-saved register liveness propagation - live &= ~(map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) | - map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_V1) | temporary_regs()); - if ((insns[idx - 1].b_liveout | live) != insns[idx - 1].b_liveout) { - insns[idx - 1].b_liveout |= live; - q.push_back(text_vaddr + (idx - 1) * 4); - } - } - } -} - -static void pass6(void) { - for (auto& it : functions) { - uint32_t addr = it.first; - Function& f = it.second; - for (uint32_t ret : f.returns) { - Insn& i = insns[addr_to_i(ret)]; - if (i.f_liveout & i.b_liveout & map_reg(MIPS_REG_V1)) { - f.nret = 2; - } else if ((i.f_liveout & i.b_liveout & map_reg(MIPS_REG_V0)) && f.nret == 0) { - f.nret = 1; - } - } - Insn& insn = insns.at(addr_to_i(addr)); - for (int i = 0; i < 4; i++) { - if (insn.f_livein & insn.b_livein & map_reg(MIPS_REG_A0 + i)) { - f.nargs = 1 + i; - } - } - f.v0_in = (insn.f_livein & insn.b_livein & map_reg(MIPS_REG_V0)) != 0 && !f.referenced_by_function_pointer; - } -} - -static void dump(void) { - for (size_t i = 0; i < insns.size(); i++) { - Insn& insn = insns[i]; - uint32_t vaddr = text_vaddr + i * 4; - if (label_addresses.count(vaddr)) { - if (symbol_names.count(vaddr)) { - printf("L%08x: //%s\n", vaddr, symbol_names[vaddr].c_str()); - } else { - printf("L%08x:\n", vaddr); - } - } - printf("\t%s %s\n", insn.mnemonic.c_str(), insn.op_str.c_str()); - } -} - -static const char *r(uint32_t reg) { - return cs_reg_name(handle, reg); -} - -static const char *wr(uint32_t reg) { - static const char *regs[] = { - "f0.w[0]", "f0.w[1]", - "f2.w[0]", "f2.w[1]", - "f4.w[0]", "f4.w[1]", - "f6.w[0]", "f6.w[1]", - "f8.w[0]", "f8.w[1]", - "f10.w[0]", "f10.w[1]", - "f12.w[0]", "f12.w[1]", - "f14.w[0]", "f14.w[1]", - "f16.w[0]", "f16.w[1]", - "f18.w[0]", "f18.w[1]", - "f20.w[0]", "f20.w[1]", - "f22.w[0]", "f22.w[1]", - "f24.w[0]", "f24.w[1]", - "f26.w[0]", "f26.w[1]", - "f28.w[0]", "f28.w[1]", - "f30.w[0]", "f30.w[1]" - }; - assert(reg >= MIPS_REG_F0 && reg <= MIPS_REG_F31); - return regs[reg - MIPS_REG_F0]; -} - -static const char *fr(uint32_t reg) { - static const char *regs[] = { - "f0.f[0]", "f0.f[1]", - "f2.f[0]", "f2.f[1]", - "f4.f[0]", "f4.f[1]", - "f6.f[0]", "f6.f[1]", - "f8.f[0]", "f8.f[1]", - "f10.f[0]", "f10.f[1]", - "f12.f[0]", "f12.f[1]", - "f14.f[0]", "f14.f[1]", - "f16.f[0]", "f16.f[1]", - "f18.f[0]", "f18.f[1]", - "f20.f[0]", "f20.f[1]", - "f22.f[0]", "f22.f[1]", - "f24.f[0]", "f24.f[1]", - "f26.f[0]", "f26.f[1]", - "f28.f[0]", "f28.f[1]", - "f30.f[0]", "f30.f[1]" - }; - assert(reg >= MIPS_REG_F0 && reg <= MIPS_REG_F31); - return regs[reg - MIPS_REG_F0]; -} - -static const char *dr(uint32_t reg) { - static const char *regs[] = { - "f0.d", - "f2.d", - "f4.d", - "f6.d", - "f8.d", - "f10.d", - "f12.d", - "f14.d", - "f16.d", - "f18.d", - "f20.d", - "f22.d", - "f24.d", - "f26.d", - "f28.d", - "f30.d" - }; - assert(reg >= MIPS_REG_F0 && reg <= MIPS_REG_F31 && (reg - MIPS_REG_F0) % 2 == 0); - return regs[(reg - MIPS_REG_F0) / 2]; -} - -static void dump_instr(int i); - -static void dump_cond_branch(int i, const char *lhs, const char *op, const char *rhs) { - Insn& insn = insns[i]; - const char *cast1 = ""; - const char *cast2 = ""; - if (strcmp(op, "==") && strcmp(op, "!=")) { - cast1 = "(int)"; - if (strcmp(rhs, "0")) { - cast2 = "(int)"; - } - } - printf("if (%s%s %s %s%s) {", cast1, lhs, op, cast2, rhs); - dump_instr(i + 1); - printf("goto L%x;}\n", (uint32_t)insn.operands[insn.op_count - 1].imm); -} - -static void dump_cond_branch_likely(int i, const char *lhs, const char *op, const char *rhs) { - uint32_t target = text_vaddr + (i + 2) * 4; - dump_cond_branch(i, lhs, op, rhs); - if (!TRACE) { - printf("else goto L%x;\n", target); - } else { - printf("else {printf(\"pc=0x%08x (ignored)\\n\"); goto L%x;}\n", text_vaddr + (i + 1) * 4, target); - } - label_addresses.insert(target); -} - -static void dump_instr(int i) { - const char *symbol_name = NULL; - if (symbol_names.count(text_vaddr + i * 4) != 0) { - symbol_name = symbol_names[text_vaddr + i * 4].c_str(); - printf("//%s:\n", symbol_name); - } - if (TRACE) { - 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 && !conservative) { - switch (insn_to_type(insn)) { - case TYPE_1S: - if (!(insn.f_livein & map_reg(insn.operands[0].reg))) { - printf("// fdead %llx ", (unsigned long long)insn.f_livein); - } - break; - case TYPE_1S_POS1: - if (!(insn.f_livein & map_reg(insn.operands[1].reg))) { - printf("// fdead %llx ", (unsigned long long)insn.f_livein); - } - break; - case TYPE_2S: - if (!(insn.f_livein & map_reg(insn.operands[0].reg)) || !(insn.f_livein & map_reg(insn.operands[1].reg))) { - printf("// fdead %llx ", (unsigned long long)insn.f_livein); - } - break; - case TYPE_1D_2S: - if (!(insn.f_livein & map_reg(insn.operands[2].reg))) { - printf("// fdead %llx ", (unsigned long long)insn.f_livein); - break; - } - // fallthrough - case TYPE_1D_1S: - if (!(insn.f_livein & map_reg(insn.operands[1].reg))) { - printf("// fdead %llx ", (unsigned long long)insn.f_livein); - break; - } - // fallthrough - case TYPE_1D: - if (!(insn.b_liveout & map_reg(insn.operands[0].reg))) { - printf("// bdead %llx ", (unsigned long long)insn.b_liveout); - } - break; - case TYPE_D_LO_HI_2S: - if (!(insn.f_livein & map_reg(insn.operands[0].reg)) || !(insn.f_livein & map_reg(insn.operands[1].reg))) { - printf("// fdead %llx ", (unsigned long long)insn.f_livein); - break; - } - if (!(insn.b_liveout & (map_reg(MIPS_REG_LO) | map_reg(MIPS_REG_HI)))) { - printf("// bdead %llx ", (unsigned long long)insn.b_liveout); - } - break; - } - } - switch (insn.id) { - case MIPS_INS_ADD: - case MIPS_INS_ADDU: - if (insn.mnemonic == "add.s") { - printf("%s = %s + %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg), fr(insn.operands[2].reg)); - } else if (insn.mnemonic == "add.d") { - printf("%s = %s + %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg), dr(insn.operands[2].reg)); - } else { - printf("%s = %s + %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg)); - } - break; - case MIPS_INS_ADDI: - case MIPS_INS_ADDIU: - printf("%s = %s + 0x%x;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm); - break; - case MIPS_INS_AND: - printf("%s = %s & %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg)); - break; - case MIPS_INS_ANDI: - printf("%s = %s & 0x%x;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm); - break; - case MIPS_INS_BEQ: - dump_cond_branch(i, r(insn.operands[0].reg), "==", r(insn.operands[1].reg)); - break; - case MIPS_INS_BEQL: - dump_cond_branch_likely(i, r(insn.operands[0].reg), "==", r(insn.operands[1].reg)); - break; - case MIPS_INS_BGEZ: - dump_cond_branch(i, r(insn.operands[0].reg), ">=", "0"); - break; - case MIPS_INS_BGEZL: - dump_cond_branch_likely(i, r(insn.operands[0].reg), ">=", "0"); - break; - case MIPS_INS_BGTZ: - dump_cond_branch(i, r(insn.operands[0].reg), ">", "0"); - break; - case MIPS_INS_BGTZL: - dump_cond_branch_likely(i, r(insn.operands[0].reg), ">", "0"); - break; - case MIPS_INS_BLEZ: - dump_cond_branch(i, r(insn.operands[0].reg), "<=", "0"); - break; - case MIPS_INS_BLEZL: - dump_cond_branch_likely(i, r(insn.operands[0].reg), "<=", "0"); - break; - case MIPS_INS_BLTZ: - dump_cond_branch(i, r(insn.operands[0].reg), "<", "0"); - break; - case MIPS_INS_BLTZL: - dump_cond_branch_likely(i, r(insn.operands[0].reg), "<", "0"); - break; - case MIPS_INS_BNE: - dump_cond_branch(i, r(insn.operands[0].reg), "!=", r(insn.operands[1].reg)); - break; - case MIPS_INS_BNEL: - dump_cond_branch_likely(i, r(insn.operands[0].reg), "!=", insn.mnemonic == "bnezl" ? "0" : r(insn.operands[1].reg)); - break; - case MIPS_INS_BREAK: - printf("abort();\n"); - break; - case MIPS_INS_BEQZ: - dump_cond_branch(i, r(insn.operands[0].reg), "==", "0"); - break; - /*case MIPS_INS_BEQZL: - dump_cond_branch_likely(i, r(insn.operands[0].reg), "==", "0"); - break;*/ - case MIPS_INS_B: - dump_instr(i + 1); - printf("goto L%x;\n", (int32_t)insn.operands[0].imm); - break; - case MIPS_INS_BC1F: - case MIPS_INS_BC1T: - printf("if (%scf) {", insn.id == MIPS_INS_BC1F ? "!" : ""); - dump_instr(i + 1); - printf("goto L%x;}\n", (int32_t)insn.operands[0].imm); - break; - case MIPS_INS_BC1FL: - case MIPS_INS_BC1TL: - { - uint32_t target = text_vaddr + (i + 2) * 4; - printf("if (%scf) {", insn.id == MIPS_INS_BC1FL ? "!" : ""); - dump_instr(i + 1); - printf("goto L%x;}\n", (int32_t)insn.operands[0].imm); - if (!TRACE) { - printf("else goto L%x;\n", target); - } else { - printf("else {printf(\"pc=0x%08x (ignored)\\n\"); goto L%x;}\n", text_vaddr + (i + 1) * 4, target); - } - label_addresses.insert(target); - break; - } - case MIPS_INS_BNEZ: - dump_cond_branch(i, r(insn.operands[0].reg), "!=", "0"); - break; - /*case MIPS_INS_BNEZL: - dump_cond_branch_likely(i, r(insn.operands[0].reg), "!=", "0"); - break;*/ - case MIPS_INS_C: - if (insn.mnemonic == "c.lt.s") { - printf("cf = %s < %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg)); - } else if (insn.mnemonic == "c.le.s") { - printf("cf = %s <= %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg)); - } else if (insn.mnemonic == "c.eq.s") { - printf("cf = %s == %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg)); - } else if (insn.mnemonic == "c.lt.d") { - printf("cf = %s < %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg)); - } else if (insn.mnemonic == "c.le.d") { - printf("cf = %s <= %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg)); - } else if (insn.mnemonic == "c.eq.d") { - printf("cf = %s == %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg)); - } - break; - case MIPS_INS_CVT: - if (insn.mnemonic == "cvt.s.w") { - printf("%s = (int)%s;\n", fr(insn.operands[0].reg), wr(insn.operands[1].reg)); - } else if (insn.mnemonic == "cvt.d.w") { - printf("%s = (int)%s;\n", dr(insn.operands[0].reg), wr(insn.operands[1].reg)); - } else if (insn.mnemonic == "cvt.d.s") { - printf("%s = %s;\n", dr(insn.operands[0].reg), fr(insn.operands[1].reg)); - } else if (insn.mnemonic == "cvt.s.d") { - printf("%s = %s;\n", fr(insn.operands[0].reg), dr(insn.operands[1].reg)); - } else if (insn.mnemonic == "cvt.w.d") { - printf("%s = cvt_w_d(%s);\n", wr(insn.operands[0].reg), dr(insn.operands[1].reg)); - } else if (insn.mnemonic == "cvt.w.s") { - printf("%s = cvt_w_s(%s);\n", wr(insn.operands[0].reg), fr(insn.operands[1].reg)); - } else { - goto unimplemented; - } - break; - case MIPS_INS_CFC1: - assert(insn.operands[1].reg == MIPS_REG_31); - printf("%s = fcsr;\n", r(insn.operands[0].reg)); - break; - case MIPS_INS_CTC1: - assert(insn.operands[1].reg == MIPS_REG_31); - printf("fcsr = %s;\n", r(insn.operands[0].reg)); - break; - case MIPS_INS_DIV: - if (insn.mnemonic == "div.s") { - assert(insn.op_count == 3); - printf("%s = %s / %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg), fr(insn.operands[2].reg)); - } else if (insn.mnemonic == "div.d") { - assert(insn.op_count == 3); - printf("%s = %s / %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg), dr(insn.operands[2].reg)); - } else { - assert(insn.op_count == 2); - printf("lo = (int)%s / (int)%s; ", r(insn.operands[0].reg), r(insn.operands[1].reg)); - printf("hi = (int)%s %% (int)%s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg)); - } - break; - case MIPS_INS_DIVU: - assert(insn.op_count == 2); - printf("lo = %s / %s; ", r(insn.operands[0].reg), r(insn.operands[1].reg)); - printf("hi = %s %% %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg)); - break; - case MIPS_INS_MOV: - if (insn.mnemonic == "mov.s") { - printf("%s = %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg)); - } else if (insn.mnemonic == "mov.d") { - printf("%s = %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg)); - } else { - goto unimplemented; - } - break; - case MIPS_INS_MUL: - if (insn.mnemonic == "mul.s") { - printf("%s = %s * %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg), fr(insn.operands[2].reg)); - } else if (insn.mnemonic == "mul.d") { - printf("%s = %s * %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg), dr(insn.operands[2].reg)); - } else { - goto unimplemented; - } - break; - case MIPS_INS_NEG: - if (insn.mnemonic == "neg.s") { - printf("%s = -%s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg)); - } else if (insn.mnemonic == "neg.d") { - printf("%s = -%s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg)); - } else { - printf("%s = -%s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg)); - } - break; - case MIPS_INS_SUB: - if (insn.mnemonic == "sub.s") { - printf("%s = %s - %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg), fr(insn.operands[2].reg)); - } else if (insn.mnemonic == "sub.d") { - printf("%s = %s - %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg), dr(insn.operands[2].reg)); - } else { - goto unimplemented; - } - break; - case MIPS_INS_J: - dump_instr(i + 1); - printf("goto L%x;\n", (uint32_t)insn.operands[0].imm); - break; - case MIPS_INS_JAL: - { - string name; - bool is_extern_function = false; - size_t extern_function_id; - auto it = symbol_names.find(insn.operands[0].imm); - if (it != symbol_names.end()) { - name = it->second; - for (size_t i = 0; i < sizeof(extern_functions) / sizeof(extern_functions[0]); i++) { - if (name == extern_functions[i].name) { - is_extern_function = true; - extern_function_id = i; - break; - } - } - } - dump_instr(i + 1); - if (is_extern_function) { - auto& fn = extern_functions[extern_function_id]; - if (fn.flags & FLAG_VARARG) { - for (int j = 0; j < 4; j++) { - printf("MEM_U32(sp + %d) = %s;\n", j * 4, r(MIPS_REG_A0 + j)); - } - } - char ret_type = fn.params[0]; - if (ret_type != 'v') { - switch (ret_type) { - case 'i': - case 'u': - case 'p': - printf("%s = ", r(MIPS_REG_V0)); - break; - case 'f': - printf("%s = ", fr(MIPS_REG_F0)); - break; - case 'd': - printf("%s = ", dr(MIPS_REG_F0)); - break; - case 'l': - case 'j': - printf("temp64 = "); - break; - } - } - printf("wrapper_%s(", name.c_str()); - bool first = true; - if (!(fn.flags & FLAG_NO_MEM)) { - printf("mem"); - first = false; - } - int pos = 0; - int pos_float = 0; - bool only_floats_so_far = true; - bool needs_sp = false; - for (const char *p = fn.params + 1; *p != '\0'; ++p) { - if (!first) { - printf(", "); - } - first = false; - switch (*p) { - case 't': - printf("trampoline, "); - needs_sp = true; - // fallthrough - case 'i': - case 'u': - case 'p': - only_floats_so_far = false; - if (pos < 4) { - printf("%s", r(MIPS_REG_A0 + pos)); - } else { - printf("MEM_%c32(sp + %d)", *p == 'i' ? 'S' : 'U', pos * 4); - } - ++pos; - break; - case 'f': - if (only_floats_so_far && pos_float < 4) { - printf("%s", fr(MIPS_REG_F12 + pos_float)); - pos_float += 2; - } else if (pos < 4) { - printf("BITCAST_U32_TO_F32(%s)", r(MIPS_REG_A0 + pos)); - } else { - printf("BITCAST_U32_TO_F32(MEM_U32(sp + %d))", pos * 4); - } - ++pos; - break; - case 'd': - if (pos % 1 != 0) { - ++pos; - } - if (only_floats_so_far && pos_float < 4) { - printf("%s", dr(MIPS_REG_F12 + pos_float)); - pos_float += 2; - } else if (pos < 4) { - printf("BITCAST_U64_TO_F64(((uint64_t)%s << 32) | (uint64_t)%s)", r(MIPS_REG_A0 + pos), r(MIPS_REG_A0 + pos + 1)); - } else { - printf("BITCAST_U64_TO_F64(((uint64_t)MEM_U32(sp + %d) << 32) | (uint64_t)MEM_U32(sp + %d))", pos * 4, (pos + 1) * 4); - } - pos += 2; - break; - case 'l': - case 'j': - if (pos % 1 != 0) { - ++pos; - } - only_floats_so_far = false; - if (*p == 'l') { - printf("(int64_t)"); - } - if (pos < 4) { - printf("(((uint64_t)%s << 32) | (uint64_t)%s)", r(MIPS_REG_A0 + pos), r(MIPS_REG_A0 + pos + 1)); - } else { - printf("(((uint64_t)MEM_U32(sp + %d) << 32) | (uint64_t)MEM_U32(sp + %d))", pos * 4, (pos + 1) * 4); - } - pos += 2; - break; - } - } - if ((fn.flags & FLAG_VARARG) || needs_sp) { - printf("%s%s", first ? "" : ", ", r(MIPS_REG_SP)); - } - printf(");\n"); - if (ret_type == 'l' || ret_type == 'j') { - printf("%s = (uint32_t)(temp64 >> 32);\n", r(MIPS_REG_V0)); - printf("%s = (uint32_t)temp64;\n", r(MIPS_REG_V1)); - } - if (!name.empty()) { - //printf("printf(\"%s %%x\\n\", %s);\n", name.c_str(), r(MIPS_REG_A0)); - } - } else { - Function& f = functions.find((uint32_t)insn.operands[0].imm)->second; - if (f.nret == 1) { - printf("v0 = "); - } else if (f.nret == 2) { - printf("temp64 = "); - } - if (!name.empty()) { - //printf("printf(\"%s %%x\\n\", %s);\n", name.c_str(), r(MIPS_REG_A0)); - printf("f_%s", name.c_str()); - } else { - printf("func_%x", (uint32_t)insn.operands[0].imm); - } - printf("(mem, sp"); - if (f.v0_in) { - printf(", %s", r(MIPS_REG_V0)); - } - for (uint32_t i = 0; i < f.nargs; i++) { - printf(", %s", r(MIPS_REG_A0 + i)); - } - printf(");\n"); - if (f.nret == 2) { - printf("%s = (uint32_t)(temp64 >> 32);\n", r(MIPS_REG_V0)); - printf("%s = (uint32_t)temp64;\n", r(MIPS_REG_V1)); - } - } - printf("goto L%x;\n", text_vaddr + (i + 2) * 4); - label_addresses.insert(text_vaddr + (i + 2) * 4); - break; - } - case MIPS_INS_JALR: - printf("fp_dest = %s;\n", r(insn.operands[0].reg)); - dump_instr(i + 1); - printf("temp64 = trampoline(mem, sp, %s, %s, %s, %s, fp_dest);\n", - r(MIPS_REG_A0), r(MIPS_REG_A1), r(MIPS_REG_A2), r(MIPS_REG_A3)); - printf("%s = (uint32_t)(temp64 >> 32);\n", r(MIPS_REG_V0)); - printf("%s = (uint32_t)temp64;\n", r(MIPS_REG_V1)); - printf("goto L%x;\n", text_vaddr + (i + 2) * 4); - label_addresses.insert(text_vaddr + (i + 2) * 4); - break; - case MIPS_INS_JR: - if (insn.jtbl_addr != 0) { - uint32_t jtbl_pos = insn.jtbl_addr - rodata_vaddr; - assert(jtbl_pos < rodata_section_len && jtbl_pos + insn.num_cases * 4 <= rodata_section_len); -#if 1 - printf(";static void *const Lswitch%x[] = {\n", insn.jtbl_addr); - for (uint32_t i = 0; i < insn.num_cases; i++) { - uint32_t dest_addr = read_u32_be(rodata_section + jtbl_pos + i * 4) + gp_value; - printf("&&L%x,\n", dest_addr); - label_addresses.insert(dest_addr); - } - printf("};\n"); - printf("dest = Lswitch%x[%s];\n", insn.jtbl_addr, r(insn.index_reg)); - dump_instr(i + 1); - printf("goto *dest;\n"); -#else - assert(insns[i + 1].id == MIPS_INS_NOP); - printf("switch (%s) {\n", r(insn.index_reg)); - for (uint32_t i = 0; i < insn.num_cases; i++) { - uint32_t dest_addr = read_u32_be(rodata_section + jtbl_pos + i * 4) + gp_value; - printf("case %u: goto L%x;\n", i, dest_addr); - label_addresses.insert(dest_addr); - } - printf("}\n"); -#endif - } else { - if (insn.operands[0].reg != MIPS_REG_RA) { - printf("UNSUPPORTED JR %s %s\n", insn.op_str.c_str(), r(insn.operands[0].reg)); - } else { - dump_instr(i + 1); - switch (find_function(text_vaddr + i * 4)->second.nret) { - case 0: - printf("return;\n"); - break; - case 1: - printf("return v0;\n"); - break; - case 2: - printf("return ((uint64_t)v0 << 32) | v1;\n"); - break; - } - } - } - break; - case MIPS_INS_LB: - printf("%s = MEM_S8(%s + %d);\n", r(insn.operands[0].reg), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp); - break; - case MIPS_INS_LBU: - printf("%s = MEM_U8(%s + %d);\n", r(insn.operands[0].reg), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp); - break; - case MIPS_INS_LH: - printf("%s = MEM_S16(%s + %d);\n", r(insn.operands[0].reg), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp); - break; - case MIPS_INS_LHU: - printf("%s = MEM_U16(%s + %d);\n", r(insn.operands[0].reg), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp); - break; - case MIPS_INS_LUI: - printf("%s = 0x%x;\n", r(insn.operands[0].reg), ((uint32_t)insn.operands[1].imm) << 16); - break; - case MIPS_INS_LW: - printf("%s = MEM_U32(%s + %d);\n", r(insn.operands[0].reg), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp); - break; - case MIPS_INS_LWC1: - printf("%s = MEM_U32(%s + %d);\n", wr(insn.operands[0].reg), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp); - break; - case MIPS_INS_LDC1: - assert((insn.operands[0].reg - MIPS_REG_F0) % 2 == 0); - printf("%s = MEM_U32(%s + %d);\n", wr(insn.operands[0].reg + 1), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp); - printf("%s = MEM_U32(%s + %d + 4);\n", wr(insn.operands[0].reg), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp); - break; - case MIPS_INS_LWL: - { - const char *reg = r(insn.operands[0].reg); - printf("%s = %s + %d; ", reg, r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp); - printf("%s = (MEM_U8(%s) << 24) | (MEM_U8(%s + 1) << 16) | (MEM_U8(%s + 2) << 8) | MEM_U8(%s + 3);\n", reg, reg, reg, reg, reg); - break; - } - case MIPS_INS_LWR: - printf("//lwr %s\n", insn.op_str.c_str()); - break; - case MIPS_INS_LI: - if (insn.is_global_got_memop && text_vaddr <= insn.operands[1].imm && insn.operands[1].imm < text_vaddr + text_section_len) { - printf("%s = 0x%x; // function pointer\n", r(insn.operands[0].reg), (uint32_t)insn.operands[1].imm); - label_addresses.insert((uint32_t)insn.operands[1].imm); - } else { - printf("%s = 0x%x;\n", r(insn.operands[0].reg), (uint32_t)insn.operands[1].imm); - } - break; - case MIPS_INS_MFC1: - printf("%s = %s;\n", r(insn.operands[0].reg), wr(insn.operands[1].reg)); - break; - case MIPS_INS_MFHI: - printf("%s = hi;\n", r(insn.operands[0].reg)); - break; - case MIPS_INS_MFLO: - printf("%s = lo;\n", r(insn.operands[0].reg)); - break; - case MIPS_INS_MOVE: - printf("%s = %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg)); - break; - case MIPS_INS_MTC1: - printf("%s = %s;\n", wr(insn.operands[1].reg), r(insn.operands[0].reg)); - break; - case MIPS_INS_MULT: - printf("lo = %s * %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg)); - printf("hi = (uint32_t)((int64_t)(int)%s * (int64_t)(int)%s >> 32);\n", r(insn.operands[0].reg), r(insn.operands[1].reg)); - break; - case MIPS_INS_MULTU: - 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_NEGU: - printf("%s = -%s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg)); - break; - case MIPS_INS_NOR: - printf("%s = ~(%s | %s);\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg)); - break; - case MIPS_INS_NOT: - printf("%s = ~%s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg)); - break; - case MIPS_INS_OR: - printf("%s = %s | %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg)); - break; - case MIPS_INS_ORI: - printf("%s = %s | 0x%x;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm); - break; - case MIPS_INS_SB: - printf("MEM_U8(%s + %d) = (uint8_t)%s;\n", r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp, r(insn.operands[0].reg)); - break; - case MIPS_INS_SH: - printf("MEM_U16(%s + %d) = (uint16_t)%s;\n", r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp, r(insn.operands[0].reg)); - break; - case MIPS_INS_SLL: - printf("%s = %s << %d;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm); - break; - case MIPS_INS_SLLV: - printf("%s = %s << (%s & 0x1f);\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg)); - break; - case MIPS_INS_SLT: - printf("%s = (int)%s < (int)%s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg)); - break; - case MIPS_INS_SLTI: - printf("%s = (int)%s < (int)0x%x;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm); - break; - case MIPS_INS_SLTIU: - printf("%s = %s < 0x%x;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm); - break; - case MIPS_INS_SLTU: - printf("%s = %s < %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg)); - break; - case MIPS_INS_SRA: - printf("%s = (int)%s >> %d;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm); - break; - case MIPS_INS_SRAV: - printf("%s = (int)%s >> (%s & 0x1f);\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg)); - break; - case MIPS_INS_SRL: - printf("%s = %s >> %d;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm); - break; - case MIPS_INS_SRLV: - printf("%s = %s >> (%s & 0x1f);\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg)); - break; - case MIPS_INS_SUBU: - printf("%s = %s - %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg)); - break; - case MIPS_INS_SW: - printf("MEM_U32(%s + %d) = %s;\n", r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp, r(insn.operands[0].reg)); - break; - case MIPS_INS_SWC1: - printf("MEM_U32(%s + %d) = %s;\n", r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp, wr(insn.operands[0].reg)); - break; - case MIPS_INS_SDC1: - assert((insn.operands[0].reg - MIPS_REG_F0) % 2 == 0); - printf("MEM_U32(%s + %d) = %s;\n", r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp, wr(insn.operands[0].reg + 1)); - printf("MEM_U32(%s + %d + 4) = %s;\n", r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp, wr(insn.operands[0].reg)); - break; - case MIPS_INS_SWL: - for (int i = 0; i < 4; i++) { - printf("MEM_U8(%s + %d + %d) = (uint8_t)(%s >> %d);\n", r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp, i, r(insn.operands[0].reg), (3 - i) * 8); - } - break; - case MIPS_INS_SWR: - printf("//swr %s\n", insn.op_str.c_str()); - break; - case MIPS_INS_TRUNC: - if (insn.mnemonic == "trunc.w.s") { - printf("%s = (int)%s;\n", wr(insn.operands[0].reg), fr(insn.operands[1].reg)); - } else if (insn.mnemonic == "trunc.w.d") { - printf("%s = (int)%s;\n", wr(insn.operands[0].reg), dr(insn.operands[1].reg)); - } else { - goto unimplemented; - } - break; - case MIPS_INS_XOR: - printf("%s = %s ^ %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg)); - break; - case MIPS_INS_XORI: - printf("%s = %s ^ 0x%x;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm); - break; - case MIPS_INS_TNE: - printf("assert(%s == %s && \"tne %d\");\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (int)insn.operands[2].imm); - break; - case MIPS_INS_TEQ: - printf("assert(%s != %s && \"teq %d\");\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (int)insn.operands[2].imm); - break; - case MIPS_INS_TGE: - printf("assert((int)%s < (int)%s && \"tge %d\");\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (int)insn.operands[2].imm); - break; - case MIPS_INS_TGEU: - printf("assert(%s < %s && \"tgeu %d\");\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (int)insn.operands[2].imm); - break; - case MIPS_INS_TLT: - printf("assert((int)%s >= (int)%s && \"tlt %d\");\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (int)insn.operands[2].imm); - break; - case MIPS_INS_NOP: - printf("//nop;\n"); - break; - default: - unimplemented: - printf("UNIMPLEMENTED %s %s\n", insn.mnemonic.c_str(), insn.op_str.c_str()); - break; - } -} - -static void inspect_data_function_pointers(vector>& ret, const uint8_t *section, uint32_t section_vaddr, uint32_t len) { - for (uint32_t i = 0; i < len; i += 4) { - uint32_t addr = read_u32_be(section + i); - if (addr == 0x430b00 || addr == 0x433b00) { - // in as1, not function pointers (normal integers) - continue; - } - if (addr == 0x4a0000) { - // in copt - continue; - } - if (section_vaddr + i >= procedure_table_start && section_vaddr + i < procedure_table_start + procedure_table_len) { - // some linking table with a "all" functions, in as1 5.3 - continue; - } - if (addr >= text_vaddr && addr < text_vaddr + text_section_len && addr % 4 == 0) { -#if INSPECT_FUNCTION_POINTERS - fprintf(stderr, "assuming function pointer 0x%x at 0x%x\n", addr, section_vaddr + i); -#endif - ret.push_back(make_pair(section_vaddr + i, addr)); - label_addresses.insert(addr); - functions[addr].referenced_by_function_pointer = true; - } - } -} - -static void dump_function_signature(Function& f, uint32_t vaddr) { - printf("static "); - switch (f.nret) { - case 0: - printf("void "); - break; - case 1: - printf("uint32_t "); - break; - case 2: - printf("uint64_t "); - break; - } - auto name_it = symbol_names.find(vaddr); - if (name_it != symbol_names.end()) { - printf("f_%s", name_it->second.c_str()); - } else { - printf("func_%x", vaddr); - } - printf("(uint8_t *mem, uint32_t sp"); - if (f.v0_in) { - printf(", uint32_t %s", r(MIPS_REG_V0)); - } - for (uint32_t i = 0; i < f.nargs; i++) { - printf(", uint32_t %s", r(MIPS_REG_A0 + i)); - } - printf(")"); -} - -static void dump_c(void) { - map symbol_names_inv; - for (auto& it : symbol_names) { - symbol_names_inv[it.second] = it.first; - } - - uint32_t min_addr = ~0; - 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); - } - if (rodata_section_len > 0) { - min_addr = MIN(min_addr, rodata_vaddr); - max_addr = 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 = min_addr & ~0xfff; - max_addr = (max_addr + 0xfff) & ~0xfff; - - 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 (conservative) { - printf("static uint32_t s0, s1, s2, s3, s4, s5, s6, s7, fp;\n"); - } - printf("static const uint32_t rodata[] = {\n"); - for (size_t i = 0; i < rodata_section_len; i += 4) { - printf("0x%x,%s", read_u32_be(rodata_section + i), i % 32 == 28 ? "\n" : ""); - } - printf("};\n"); - printf("static const uint32_t data[] = {\n"); - for (size_t i = 0; i < data_section_len; i += 4) { - printf("0x%x,%s", read_u32_be(data_section + i), i % 32 == 28 ? "\n" : ""); - } - printf("};\n"); - - /*if (!data_function_pointers.empty()) { - printf("static const struct { uint32_t orig_addr; void *recompiled_addr; } data_function_pointers[] = {\n"); - for (auto item : data_function_pointers) { - printf("{0x%x, &&L%x},\n", item.first, item.second); - } - printf("};\n"); - }*/ - - if (TRACE) { - printf("static unsigned long long int cnt = 0;\n"); - } - - for (auto& f_it : functions) { - if (insns[addr_to_i(f_it.first)].f_livein != 0) { - // Function is used - dump_function_signature(f_it.second, f_it.first); - printf(";\n"); - } - } - - if (!data_function_pointers.empty() || !li_function_pointers.empty()) { - printf("uint64_t trampoline(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest) {\n"); - printf("switch (fp_dest) {\n"); - for (auto& it : functions) { - Function& f = it.second; - if (f.referenced_by_function_pointer) { - printf("case 0x%x: ", it.first); - if (f.nret == 1) { - printf("return (uint64_t)"); - } else if (f.nret == 2) { - printf("return "); - } - auto name_it = symbol_names.find(it.first); - if (name_it != symbol_names.end()) { - printf("f_%s", name_it->second.c_str()); - } else { - printf("func_%x", it.first); - } - printf("(mem, sp"); - for (int i = 0; i < f.nargs; i++) { - printf(", a%d", i); - } - printf(")"); - if (f.nret == 1) { - printf(" << 32"); - } - printf(";"); - if (f.nret == 0) { - printf(" return 0;"); - } - printf("\n"); - } - } - printf("default: abort();"); - printf("}\n"); - printf("}\n"); - } - - printf("int run(uint8_t *mem, int argc, char *argv[]) {\n"); - printf("mmap_initial_data_range(mem, 0x%x, 0x%x);\n", min_addr, max_addr); - - printf("memcpy(mem + 0x%x, rodata, 0x%x);\n", rodata_vaddr, rodata_section_len); - printf("memcpy(mem + 0x%x, data, 0x%x);\n", data_vaddr, data_section_len); - - /*if (!data_function_pointers.empty()) { - if (!LABELS_64_BIT) { - printf("for (int i = 0; i < %d; i++) MEM_U32(data_function_pointers[i].orig_addr) = (uint32_t)(uintptr_t)data_function_pointers[i].recompiled_addr;\n", (int)data_function_pointers.size()); - } else { - printf("for (int i = 0; i < %d; i++) MEM_U32(data_function_pointers[i].orig_addr) = (uint32_t)((uintptr_t)data_function_pointers[i].recompiled_addr - (uintptr_t)&&Loffset);\n", (int)data_function_pointers.size()); - } - }*/ - - printf("MEM_S32(0x%x) = argc;\n", symbol_names_inv.at("__Argc")); - printf("MEM_S32(0x%x) = argc;\n", stack_bottom); - printf("uint32_t al = argc * 4; for (int i = 0; i < argc; i++) al += strlen(argv[i]) + 1;\n"); - printf("uint32_t arg_addr = wrapper_malloc(mem, al);\n"); - printf("MEM_U32(0x%x) = arg_addr;\n", symbol_names_inv.at("__Argv")); - printf("MEM_U32(0x%x) = arg_addr;\n", stack_bottom + 4); - printf("uint32_t arg_strpos = arg_addr + argc * 4;\n"); - printf("for (int i = 0; i < argc; i++) {MEM_U32(arg_addr + i * 4) = arg_strpos; uint32_t p = 0; do { MEM_S8(arg_strpos) = argv[i][p]; ++arg_strpos; } while (argv[i][p++] != '\\0');}\n"); - - printf("setup_libc_data(mem);\n"); - - //printf("gp = 0x%x;\n", gp_value); // only to recreate the outcome when ugen reads uninitialized stack memory - - printf("int ret = f_main(mem, 0x%x", stack_bottom); - Function& main_func = functions[main_addr]; - if (main_func.nargs >= 1) { - printf(", argc"); - } - if (main_func.nargs >= 2) { - printf(", arg_addr"); - } - printf(");\n"); - if (TRACE) { - printf("end: fprintf(stderr, \"cnt: %%llu\\n\", cnt);\n"); - } - printf("return ret;\n"); - printf("}\n"); - - for (auto& f_it : functions) { - Function& f = f_it.second; - uint32_t start_addr = f_it.first; - uint32_t end_addr = f.end_addr; - - if (insns[addr_to_i(start_addr)].f_livein == 0) { - // Non-used function, skip - continue; - } - - printf("\n"); - dump_function_signature(f, start_addr); - printf(" {\n"); - printf("const uint32_t zero = 0;\n"); - 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"); - } else { - 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, t8 = 0, t9 = 0, gp = 0x10000, ra = 0x10000;\n"); - } - printf("uint32_t lo = 0, hi = 0;\n"); - printf("int cf = 0;\n"); - printf("uint64_t temp64;\n"); - printf("uint32_t fp_dest;\n"); - printf("void *dest;\n"); - if (!f.v0_in) { - printf("uint32_t v0 = 0;\n"); - } - for (uint32_t j = f.nargs; j < 4; j++) { - printf("uint32_t %s = 0;\n", r(MIPS_REG_A0 + j)); - } - - for (size_t i = addr_to_i(start_addr), end_i = addr_to_i(end_addr); i < end_i; i++) { - Insn& insn = insns[i]; - uint32_t vaddr = text_vaddr + i * 4; - if (label_addresses.count(vaddr)) { - printf("L%x:\n", vaddr); - } - dump_instr(i); - } - - printf("}\n"); - } - /*for (size_t i = 0; i < insns.size(); i++) { - Insn& insn = insns[i]; - uint32_t vaddr = text_vaddr + i * 4; - auto fn_it = functions.find(vaddr); - if (fn_it != functions.end()) { - Function& f = fn_it->second; - printf("}\n\n"); - switch (f.nret) { - case 0: - printf("void "); - break; - case 1: - printf("uint32_t "); - break; - case 2: - printf("uint64_t "); - break; - } - auto name_it = symbol_names.find(vaddr); - if (name_it != symbol_names.end()) { - printf("%s", name_it->second.c_str()); - } else { - printf("func_%x", vaddr); - } - printf("(uint8_t *mem, uint32_t sp"); - if (f.v0_in) { - printf(", uint32_t %s", r(MIPS_REG_V0)); - } - for (uint32_t i = 0; i < f.nargs; i++) { - printf(", uint32_t %s", r(MIPS_REG_A0 + i)); - } - printf(") {\n"); - printf("const uint32_t zero = 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("s6 = 0, s7 = 0, t8 = 0, t9 = 0, gp = 0, fp = 0, s8 = 0, ra = 0;\n"); - printf("uint32_t lo = 0, hi = 0;\n"); - printf("int cf = 0;\n"); - if (!f.v0_in) { - printf("uint32_t v0 = 0;\n"); - } - for (uint32_t j = f.nargs; j < 4; j++) { - printf("uint32_t %s = 0;\n", r(MIPS_REG_A0 + j)); - } - } - if (label_addresses.count(vaddr)) { - printf("L%x:\n", vaddr); - } - dump_instr(i); - }*/ -} - -static void parse_elf(const uint8_t *data, size_t file_len) { - Elf32_Ehdr *ehdr; - Elf32_Shdr *shdr, *str_shdr, *sym_shdr = NULL, *dynsym_shdr, *dynamic_shdr, *reginfo_shdr, *got_shdr, *sym_strtab, *sym_dynstr; - int text_section_index = -1; - int symtab_section_index = -1; - int dynsym_section_index = -1; - int reginfo_section_index = -1; - int dynamic_section_index = -1; - int got_section_index = -1; - int rodata_section_index = -1; - int data_section_index = -1; - int bss_section_index = -1; - uint32_t text_offset = 0; - uint32_t vaddr_adj = 0; - - if (file_len < 4 || data[0] != 0x7f || data[1] != 'E' || data[2] != 'L' || data[3] != 'F') { - fprintf(stderr, "Not an ELF file.\n"); - exit(EXIT_FAILURE); - } - - ehdr = (Elf32_Ehdr *) data; - if (ehdr->e_ident[EI_DATA] != 2 || u16be(ehdr->e_machine) != 8) { - fprintf(stderr, "Not big-endian MIPS.\n"); - exit(EXIT_FAILURE); - } - - if (u16be(ehdr->e_shstrndx) == 0) { - // (We could look at program headers instead in this case.) - fprintf(stderr, "Missing section headers; stripped binaries are not yet supported.\n"); - exit(EXIT_FAILURE); - } - -#define SECTION(index) (Elf32_Shdr *)(data + u32be(ehdr->e_shoff) + (index) * u16be(ehdr->e_shentsize)) -#define STR(strtab, offset) (const char *)(data + u32be(strtab->sh_offset) + offset) - - str_shdr = SECTION(u16be(ehdr->e_shstrndx)); - for (int i = 0; i < u16be(ehdr->e_shnum); i++) { - shdr = SECTION(i); - const char *name = STR(str_shdr, u32be(shdr->sh_name)); - if (strcmp(name, ".text") == 0) { - text_offset = u32be(shdr->sh_offset); - text_vaddr = u32be(shdr->sh_addr); - vaddr_adj = text_vaddr - u32be(shdr->sh_addr); - text_section_len = u32be(shdr->sh_size); - text_section = data + text_offset; - text_section_index = i; - } - if (u32be(shdr->sh_type) == SHT_SYMTAB) { - symtab_section_index = i; - } - if (u32be(shdr->sh_type) == SHT_DYNSYM) { - dynsym_section_index = i; - } - if (u32be(shdr->sh_type) == SHT_MIPS_REGINFO) { - reginfo_section_index = i; - } - if (u32be(shdr->sh_type) == SHT_DYNAMIC) { - dynamic_section_index = i; - } - if (strcmp(name, ".got") == 0) { - got_section_index = i; - } - if (strcmp(name, ".rodata") == 0) { - rodata_section_index = i; - } - if (strcmp(name, ".data") == 0) { - data_section_index = i; - } - if (strcmp(name, ".bss") == 0) { - bss_section_index = i; - } - } - - if (text_section_index == -1) { - fprintf(stderr, "Missing .text section.\n"); - exit(EXIT_FAILURE); - } - - if (symtab_section_index == -1 && dynsym_section_index == -1) { - fprintf(stderr, "Missing .symtab or .dynsym section.\n"); - exit(EXIT_FAILURE); - } - - if (dynsym_section_index != -1) { - if (reginfo_section_index == -1) { - fprintf(stderr, "Missing .reginfo section.\n"); - exit(EXIT_FAILURE); - } - if (dynamic_section_index == -1) { - fprintf(stderr, "Missing .dynamic section.\n"); - exit(EXIT_FAILURE); - } - if (got_section_index == -1) { - fprintf(stderr, "Missing .got section.\n"); - exit(EXIT_FAILURE); - } - } - - if (rodata_section_index != -1) { - shdr = SECTION(rodata_section_index); - uint32_t size = u32be(shdr->sh_size); - rodata_section = data + u32be(shdr->sh_offset); - rodata_section_len = size; - rodata_vaddr = u32be(shdr->sh_addr); - } - - if (data_section_index != -1) { - shdr = SECTION(data_section_index); - uint32_t size = u32be(shdr->sh_size); - data_section = data + u32be(shdr->sh_offset); - data_section_len = size; - data_vaddr = u32be(shdr->sh_addr); - } - - if (bss_section_index != -1) { - shdr = SECTION(bss_section_index); - uint32_t size = u32be(shdr->sh_size); - bss_section_len = size; - bss_vaddr = u32be(shdr->sh_addr); - } - - - // add symbols - if (symtab_section_index != -1) { - sym_shdr = SECTION(symtab_section_index); - sym_strtab = SECTION(u32be(sym_shdr->sh_link)); - assert(0 && ".symtab not supported - use a program with .dynsym instead"); - - assert(u32be(sym_shdr->sh_entsize) == sizeof(Elf32_Sym)); - for (uint32_t i = 0; i < u32be(sym_shdr->sh_size); i += sizeof(Elf32_Sym)) { - Elf32_Sym *sym = (Elf32_Sym *)(data + u32be(sym_shdr->sh_offset) + i); - const char *name = STR(sym_strtab, u32be(sym->st_name)); - uint32_t addr = u32be(sym->st_value); - if (u16be(sym->st_shndx) != text_section_index || name[0] == '.') { - continue; - } - addr += vaddr_adj; - //disasm_label_add(state, name, addr, u32be(sym->st_size), true); - } - } - - if (dynsym_section_index != -1) { - dynsym_shdr = SECTION(dynsym_section_index); - sym_dynstr = SECTION(u32be(dynsym_shdr->sh_link)); - reginfo_shdr = SECTION(reginfo_section_index); - dynamic_shdr = SECTION(dynamic_section_index); - got_shdr = SECTION(got_section_index); - - Elf32_RegInfo *reg_info = (Elf32_RegInfo *)(data + u32be(reginfo_shdr->sh_offset)); - uint32_t gp_base = u32be(reg_info->ri_gp_value); // gp should have this value through the program run - uint32_t got_start = 0; - uint32_t local_got_no = 0; - uint32_t first_got_sym = 0; - uint32_t dynsym_no = 0; // section size can't be used due to alignment 16 padding - - assert(u32be(dynamic_shdr->sh_entsize) == sizeof(Elf32_Dyn)); - for (uint32_t i = 0; i < u32be(dynamic_shdr->sh_size); i += sizeof(Elf32_Dyn)) { - Elf32_Dyn *dyn = (Elf32_Dyn *)(data + u32be(dynamic_shdr->sh_offset) + i); - if (u32be(dyn->d_tag) == DT_PLTGOT) { - got_start = u32be(dyn->d_un.d_ptr); - } - if (u32be(dyn->d_tag) == DT_MIPS_LOCAL_GOTNO) { - local_got_no = u32be(dyn->d_un.d_val); - } - if (u32be(dyn->d_tag) == DT_MIPS_GOTSYM) { - first_got_sym = u32be(dyn->d_un.d_val); - } - if (u32be(dyn->d_tag) == DT_MIPS_SYMTABNO) { - dynsym_no = u32be(dyn->d_un.d_val); - } - } - - assert(got_start != 0); - - // value to add to asm gp offset, for example 32752, if -32752(gp) refers to the first entry in got. - uint32_t gp_adj = gp_base - got_start; - assert(gp_adj < 0x10000); - - assert(u32be(dynsym_shdr->sh_entsize) == sizeof(Elf32_Sym)); - uint32_t global_got_no = dynsym_no - first_got_sym; - //global_got_entry *global_entries = (global_got_entry *)calloc(global_got_no, sizeof(global_got_entry)); - got_globals.resize(global_got_no); - - uint32_t common_start = ~0U; - vector common_order; - - for (uint32_t i = 0; i < dynsym_no; i++) { - Elf32_Sym *sym = (Elf32_Sym *)(data + u32be(dynsym_shdr->sh_offset) + i * sizeof(Elf32_Sym)); - const char *name = STR(sym_dynstr, u32be(sym->st_name)); - uint32_t addr = u32be(sym->st_value); - addr += vaddr_adj; - uint8_t type = ELF32_ST_TYPE(sym->st_info); - if (!strcmp(name, "_procedure_table")) { - procedure_table_start = addr; - } else if (!strcmp(name, "_procedure_table_size")) { - procedure_table_len = 40 * u32be(sym->st_value); - } - if ((u16be(sym->st_shndx) == SHN_MIPS_TEXT && type == STT_FUNC) || - (type == STT_OBJECT && (u16be(sym->st_shndx) == SHN_MIPS_ACOMMON || u16be(sym->st_shndx) == SHN_MIPS_DATA))) - { - //disasm_label_add(state, name, addr, u32be(sym->st_size), true); - if (type == STT_OBJECT) { - } - if (u16be(sym->st_shndx) == SHN_MIPS_ACOMMON) { - if (addr < common_start) { - common_start = addr; - } - common_order.push_back(name); - } - if (type == STT_FUNC) { - add_function(addr); - if (strcmp(name, "main") == 0) { - main_addr = addr; - } - if (strcmp(name, "_mcount") == 0) { - mcount_addr = addr; - } - symbol_names[addr] = name; - } - } - if (i >= first_got_sym) { - uint32_t got_value = u32be(*(uint32_t *)(data + u32be(got_shdr->sh_offset) + (local_got_no + (i - first_got_sym)) * sizeof(uint32_t))); - if (u16be(sym->st_shndx) == SHN_MIPS_TEXT && type == STT_FUNC) { - //got_globals[i - first_got_sym] = got_value; - //label_addresses.insert(got_value); - got_globals[i - first_got_sym] = addr; // to include the 3 instr gp header thing - label_addresses.insert(addr); - } else if (type == STT_OBJECT && (u16be(sym->st_shndx) == SHN_UNDEF || u16be(sym->st_shndx) == SHN_COMMON)) { - // symbol defined externally (for example in libc) - got_globals[i - first_got_sym] = got_value; - } else { - got_globals[i - first_got_sym] = addr; - } - symbol_names[got_globals[i - first_got_sym]] = name; - } - } - - uint32_t *local_entries = (uint32_t *)calloc(local_got_no, sizeof(uint32_t)); - got_locals.resize(local_got_no); - for (uint32_t i = 0; i < local_got_no; i++) { - uint32_t *entry = (uint32_t *)(data + u32be(got_shdr->sh_offset) + i * sizeof(uint32_t)); - got_locals[i] = u32be(*entry); - } - - gp_value = gp_base; - gp_value_adj = gp_adj; - //disasm_got_entries_set(state, gp_base, gp_adj, local_entries, local_got_no, global_entries, global_got_no); - - //out_range.common_start = common_start; - //out_range.common_order.swap(common_order); - } - - // add relocations - for (int i = 0; i < u16be(ehdr->e_shnum); i++) { - Elf32_Rel *prevHi = NULL; - shdr = SECTION(i); - if (u32be(shdr->sh_type) != SHT_REL || u32be(shdr->sh_info) != (uint32_t) text_section_index) - continue; - - if (sym_shdr == NULL) { - fprintf(stderr, "Relocations without .symtab section\n"); - exit(EXIT_FAILURE); - } - - assert(u32be(shdr->sh_link) == (uint32_t) symtab_section_index); - assert(u32be(shdr->sh_entsize) == sizeof(Elf32_Rel)); - for (uint32_t i = 0; i < u32be(shdr->sh_size); i += sizeof(Elf32_Rel)) { - Elf32_Rel *rel = (Elf32_Rel *)(data + u32be(shdr->sh_offset) + i); - uint32_t offset = text_offset + u32be(rel->r_offset); - uint32_t symIndex = ELF32_R_SYM(u32be(rel->r_info)); - uint32_t rtype = ELF32_R_TYPE(u32be(rel->r_info)); - const char *symName = "0"; - if (symIndex != STN_UNDEF) { - Elf32_Sym *sym = (Elf32_Sym *)(data + u32be(sym_shdr->sh_offset) + symIndex * sizeof(Elf32_Sym)); - symName = STR(sym_strtab, u32be(sym->st_name)); - } - - if (rtype == R_MIPS_HI16) { - if (prevHi != NULL) { - fprintf(stderr, "Consecutive R_MIPS_HI16.\n"); - exit(EXIT_FAILURE); - } - prevHi = rel; - continue; - } - if (rtype == R_MIPS_LO16) { - int32_t addend = (int16_t)((data[offset + 2] << 8) + data[offset + 3]); - if (prevHi != NULL) { - uint32_t offset2 = text_offset + u32be(prevHi->r_offset); - addend += (uint32_t)((data[offset2 + 2] << 8) + data[offset2 + 3]) << 16; - //add_reloc(state, offset2, symName, addend, out_range.vaddr); - } - prevHi = NULL; - //add_reloc(state, offset, symName, addend, out_range.vaddr); - } - else if (rtype == R_MIPS_26) { - int32_t addend = (u32be(*(uint32_t*)(data + offset)) & ((1 << 26) - 1)) << 2; - if (addend >= (1 << 27)) { - addend -= 1 << 28; - } - //add_reloc(state, offset, symName, addend, out_range.vaddr); - } - else { - fprintf(stderr, "Bad relocation type %d.\n", rtype); - exit(EXIT_FAILURE); - } - } - if (prevHi != NULL) { - fprintf(stderr, "R_MIPS_HI16 without matching R_MIPS_LO16.\n"); - exit(EXIT_FAILURE); - } - } -} -#undef SECTION -#undef STR - -size_t read_file(const char *file_name, uint8_t **data) { - FILE *in; - uint8_t *in_buf = NULL; - long file_size; - long bytes_read; - in = fopen(file_name, "rb"); - assert(in != nullptr); - - // allocate buffer to read from offset to end of file - fseek(in, 0, SEEK_END); - file_size = ftell(in); - assert(file_size != -1L); - - in_buf = (uint8_t *)malloc(file_size); - fseek(in, 0, SEEK_SET); - - // read bytes - bytes_read = fread(in_buf, 1, file_size, in); - assert(bytes_read == file_size); - - fclose(in); - *data = in_buf; - return bytes_read; -} - -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(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); - disassemble(); - inspect_data_function_pointers(data_function_pointers, rodata_section, rodata_vaddr, rodata_section_len); - inspect_data_function_pointers(data_function_pointers, data_section, data_vaddr, data_section_len); - pass1(); - pass2(); - pass3(); - pass4(); - pass5(); - pass6(); - //dump(); - dump_c(); - free(data); - cs_close(&handle); -} - diff --git a/tools/slienc b/tools/slienc deleted file mode 100755 index fedaa169..00000000 Binary files a/tools/slienc and /dev/null differ