├── LICENSE ├── Makefile_A32 ├── Makefile_A64 ├── Makefile_Z80 ├── Makefile_m3 ├── Makefile_x86_64 ├── README.md ├── assets └── tests_il_A64.cpp ├── exercise.sh ├── ildump2cpp.py ├── lldb_x64.py ├── lldb_z80.py ├── main.cpp ├── runtime.cpp ├── runtime.h ├── sdcc2elf.py └── tests.c /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 VECTOR 35 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile_A32: -------------------------------------------------------------------------------- 1 | all: main 2 | 3 | # get ndk-r21d toolchain at https://developer.android.com/ndk/downloads, unzip 4 | # from android/build/tools run `./make_standalone_toolchain.py --arch arm --api 21 --install-dir /tmp/my-android-toolchain` 5 | # now mv /tmp/my-android-toolchain ~/android_arm_api21_toolchain 6 | 7 | BUILT_TOOLCHAIN ?= $(HOME)/android_arm_api21_toolchain 8 | GCC = $(BUILT_TOOLCHAIN)/bin/arm-linux-androideabi-gcc 9 | 10 | tests.o: tests.c 11 | $(GCC) -O0 -c tests.c -o tests.o 12 | 13 | tests_il.cpp: tests.o ildump2cpp.py 14 | ildump2cpp.py tests.o arm > tests_il.cpp 15 | 16 | main: tests_il.cpp runtime.cpp main.cpp 17 | g++ -g -O0 --std=c++11 -DARCH_ARM -DARCH_32BIT tests_il.cpp main.cpp runtime.cpp -o main 18 | 19 | clean: 20 | rm -f *.o main tests_il.cpp 21 | -------------------------------------------------------------------------------- /Makefile_A64: -------------------------------------------------------------------------------- 1 | all: main 2 | 3 | # get ndk-r21d toolchain at https://developer.android.com/ndk/downloads, unzip 4 | # from android/build/tools run `./make_standalone_toolchain.py --arch arm64 --api 21 --install-dir /tmp/my-android-toolchain` 5 | # now mv /tmp/my-android-toolchain ~/android_a64_api21_toolchain 6 | 7 | BUILT_TOOLCHAIN ?= $(HOME)/android_a64_api21_toolchain 8 | GCC = $(BUILT_TOOLCHAIN)/bin/aarch64-linux-android-gcc 9 | 10 | tests.o: tests.c 11 | $(GCC) -O0 -c tests.c -o tests.o 12 | 13 | tests_il.cpp: tests.o ildump2cpp.py 14 | ildump2cpp.py tests.o arm > tests_il.cpp 15 | 16 | main: tests_il.cpp runtime.cpp main.cpp 17 | g++ -g -O0 --std=c++11 -DARCH_A64 -DARCH_64BIT tests_il.cpp main.cpp runtime.cpp -o main 18 | 19 | clean: 20 | rm -f *.o main tests_il.cpp 21 | -------------------------------------------------------------------------------- /Makefile_Z80: -------------------------------------------------------------------------------- 1 | all: main 2 | 3 | GCC = sdcc 4 | 5 | tests.elf: tests.ihx tests.map 6 | sdcc2elf.py tests.ihx tests.map 7 | 8 | tests.ihx tests.map: tests.c 9 | $(GCC) -mz80 -DARCH_Z80 tests.c 10 | 11 | tests_il.cpp: tests.elf ildump2cpp.py 12 | ildump2cpp.py tests.elf z80 > tests_il.cpp 13 | 14 | main: tests_il.cpp runtime.cpp main.cpp 15 | g++ -g -O0 --std=c++11 -DARCH_Z80 -DARCH_16BIT -DLEADING_UNDERSCORE tests_il.cpp main.cpp runtime.cpp -o main 16 | 17 | clean: 18 | rm -f *.o main tests_il.cpp 19 | -------------------------------------------------------------------------------- /Makefile_m3: -------------------------------------------------------------------------------- 1 | all: main 2 | 3 | tests.o: tests.c 4 | gcc tests.c -c -o tests.o 5 | 6 | tests_il.cpp: tests.o ildump2cpp.py 7 | ildump2cpp.py tests.o > tests_il.cpp 8 | 9 | main: tests_il.cpp runtime.cpp main.cpp 10 | g++ -g -O0 --std=c++11 -DARCH_A64 -DARCH_64BIT -DLEADING_UNDERSCORE tests_il.cpp main.cpp runtime.cpp -o main 11 | 12 | clean: 13 | rm -f *.o main tests_il.cpp 14 | -------------------------------------------------------------------------------- /Makefile_x86_64: -------------------------------------------------------------------------------- 1 | all: main 2 | 3 | tests.o: tests.c 4 | gcc tests.c -c -o tests.o 5 | 6 | tests_il.cpp: tests.o ildump2cpp.py 7 | ildump2cpp.py tests.o > tests_il.cpp 8 | 9 | main: tests_il.cpp runtime.cpp main.cpp 10 | g++ -g -O0 --std=c++11 -DARCH_X64 -DARCH_64BIT -DLEADING_UNDERSCORE tests_il.cpp main.cpp runtime.cpp -o main 11 | 12 | disasm: 13 | objdump -d ./tests.o --x86-asm-syntax=intel 14 | 15 | clean: 16 | rm -f *.o main tests_il.cpp 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LLIL Transpiler 2 | 3 | Convert LLIL to compileable and executable C++. 4 | 5 | **GOALS**: 6 | 7 | * test lifting: accurate LLIL should compute like native code 8 | * provide LLIL semantics - [runtime.cpp](./runtime.cpp) contains a C/C++ implementation for many LLIL operations 9 | 10 | **QUICK START**: `make -f Makefile_x86_x64` `./main` 11 | 12 | **EXAMPLE**: [transpiled A64](./assets/tests_il_A64.cpp) 13 | 14 | ## How does it work? 15 | 16 | The LLIL gets mapped to C/C++ code: 17 | 18 | | LLIL | C/C++ | 19 | | ------------ | ------------------------------------------ | 20 | | LLIL_IF | if | 21 | | LLIL_GOTO | goto, with labels generated at every block | 22 | | LLIL_CALL | function call | 23 | | LLIL_JUMP_TO | switch | 24 | | LLIL_REG | `REG16()`, `REG32()`, `REG64()`, etc. | 25 | | LLIL_ADD | `ADD16()`, `ADD32()`, `ADD64()`, etc. | 26 | | LLIL_XXX | `XXX()` | 27 | 28 | See [ildump2cpp.py](./ildump2cpp.py) for the mapper, and [runtime.cpp](./runtime.cpp) for the C/C++ implementation of the LLIL operations. 29 | 30 | ## Workflow 31 | 32 | 1. compile tests.cpp into tests.o with the architecture you want to lift 33 | 2. extract the llil into tests\_il.cpp using ildump2cpp.py 34 | 3. compile tests\_il.cpp with runtime.cpp and main.cpp to main 35 | 4. `./main` 36 | 37 | Using make: `make x64` or `make arm` then `./main` 38 | 39 | ## How can I test my own architecture? 40 | 41 | 1. atop runtime.h, do an `#ifdef ARCH_XXX` and inside define your arch's register types, etc. 42 | 2. in main.cpp, do an `#ifdef ARCH_XXX` and inside define `vm_init_stack()`, `vm_set_arg0()`, etc. 43 | 3. create a Makefile, being sure to pass `-DARCH_XXX` 44 | 4. run `./main` 45 | 46 | ## What else? 47 | 48 | You could compile a routine in one architecture, transpile it's LLIL to C++, then compile the result to a new architecture. 49 | 50 | You could do the above many times, even with the same architecture, increasing code size and obfuscation. 51 | -------------------------------------------------------------------------------- /exercise.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | make -f Makefile_x86_64 clean 4 | make -f Makefile_x86_64 5 | ./main 6 | 7 | make -f Makefile_A32 clean 8 | make -f Makefile_A32 9 | ./main 10 | 11 | make -f Makefile_A64 clean 12 | make -f Makefile_A64 13 | ./main 14 | 15 | -------------------------------------------------------------------------------- /ildump2cpp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import re 5 | import sys 6 | import struct 7 | from subprocess import Popen, PIPE 8 | 9 | import binaryninja 10 | from binaryninja import core 11 | from binaryninja import binaryview 12 | from binaryninja import lowlevelil 13 | 14 | from binaryninja.enums import LowLevelILOperation 15 | 16 | arch = None 17 | bv = None 18 | init_mem_lines = [] 19 | current_llil = None 20 | 21 | def shellout(cmd): 22 | process = Popen(cmd, stdout=PIPE, stderr=PIPE) 23 | (stdout, stderr) = process.communicate() 24 | stdout = stdout.decode("utf-8") 25 | stderr = stderr.decode("utf-8") 26 | process.wait() 27 | return (stdout, stderr) 28 | 29 | # return size of il in bits 30 | def get_il_size(il): 31 | if isinstance(il, lowlevelil.ILRegister): 32 | if il.name.startswith('temp'): 33 | return 8 34 | else: 35 | return il.info.size 36 | elif isinstance(il, lowlevelil.ILFlag): 37 | return 0 38 | elif type(il) == int: 39 | return 0 40 | elif type(il) == float: 41 | return 0 42 | else: 43 | return il.size 44 | 45 | def get_il_size_token(il, prefix=''): 46 | sz = get_il_size(il) 47 | if not sz: return '' 48 | if il.operation.name in ['LLIL_FLOAT_CONV', 'LLIL_FADD', 'LLIL_FSUB', 'LLIL_FMUL', 'LLIL_FDIV']: 49 | return prefix + {2: 'H', 4:'S', 8:'D', 16:'T'}[il.size] 50 | else: 51 | return prefix + {1:'B', 2:'W', 4:'D', 8:'Q', 10:'T', 16:'O'}[il.size] 52 | 53 | def traverse_IL(il, depth=0): 54 | # il pass thru here will probably be: 55 | # LowLevelILInstruction 56 | # LowLevelILRegister 57 | # LowLevelILFlag 58 | 59 | global bv 60 | global init_mem_lines 61 | semi = True 62 | 63 | if isinstance(il, lowlevelil.LowLevelILInstruction): 64 | opname = il.operation.name 65 | if opname.startswith('LLIL_'): 66 | opname = opname[5:] 67 | 68 | if opname in ['CALL', 'TAILCALL']: 69 | print('%s(' % opname, end='') 70 | traverse_IL(il.operands[0], depth+1) 71 | print(', ', end='') 72 | 73 | handled = False 74 | oper = il.operands[0] 75 | addr = None 76 | if oper.operation == LowLevelILOperation.LLIL_EXTERN_PTR: 77 | addr = oper.operands[0] 78 | elif oper.operation == LowLevelILOperation.LLIL_CONST_PTR: 79 | addr = oper.constant 80 | 81 | if addr != None: 82 | #print('// got addr: 0x%X\n' % addr) 83 | sym = bv.get_symbol_at(addr) 84 | 85 | if sym and sym.full_name: 86 | #print('// %s sym.full_name: %s' % (str(il), sym.full_name)) 87 | #print('\tSET_REG("r0", MODU(REG("r0"), REG("r1")))', end='') 88 | func_name = sym.full_name.split('(',1)[0] 89 | print('%s, "%s"' % (func_name, func_name), end='') 90 | handled = True 91 | else: 92 | func_name = 'sub_%X' % addr 93 | print('sub_%X, "%s"' % (addr, func_name), end='') 94 | handled = True 95 | 96 | if not handled: 97 | raise Exception('unable to handle CALL: %s and %s' % (str(il), str(il.operands[0].operation))) 98 | 99 | print(')', end='') 100 | 101 | elif opname == 'CONST': 102 | val = il.operands[0] 103 | if val < 16: 104 | #print('/* CONST */ %d' % val, end='') 105 | print('%d' % val, end='') 106 | else: 107 | #print('/* CONST */ 0x%X' % val, end='') 108 | print('0x%X' % val, end='') 109 | 110 | elif opname == 'CONST_PTR': 111 | # is it a jump table? rip it 112 | sym = bv.get_symbol_at(il.operands[0]) 113 | dvar = bv.get_data_var_at(il.operands[0]) 114 | if sym and sym.name.startswith('jump_table_') and dvar: 115 | strdv = str(dvar.type) 116 | m = re.match(r'^uint32_t ?\[(.+)\]$', strdv) 117 | if not m: 118 | raise Exception('dunno how to parse type from: -%s-' % strdv) 119 | amt = m.group(1) 120 | if amt.startswith('0x'): 121 | amt = int(amt, 16) 122 | else: 123 | amt = int(amt) 124 | init_mem_lines.append('/* %s */' % str(sym)) 125 | for i in range(amt): 126 | addr = sym.address + 4*i 127 | value = struct.unpack(' []' % sys.argv[0]) 202 | print('') 203 | print('examples:') 204 | print(' %s tests.o' % sys.argv[0]) 205 | print(' %s tests.o arm' % sys.argv[0]) 206 | print(' %s tests.elf z80' % sys.argv[0]) 207 | print('') 208 | sys.exit(-1) 209 | 210 | if __name__ == '__main__': 211 | binaryninja._init_plugins() 212 | 213 | # arg1: path to object file from which to extract IL 214 | if sys.argv[1:]: 215 | fpath = sys.argv[1] 216 | else: 217 | usage() 218 | 219 | # arg2: architecture 'x64', 'arm', 'a64' 220 | arch = '' 221 | if sys.argv[2:]: 222 | arch = sys.argv[2] 223 | 224 | print('// %s' % shellout(['file', fpath])[0]) 225 | 226 | bv = binaryninja.BinaryViewType.get_view_of_file(fpath) 227 | bv.update_analysis_and_wait() 228 | 229 | assert bv.end < (16*1024) # VM_MEM_SZ 230 | 231 | print('#include ') 232 | print('') 233 | print('#include ') 234 | print('#include ') 235 | print('#include ') 236 | print('using namespace std;') 237 | print('') 238 | print('#include "runtime.h"') 239 | print('') 240 | print('extern uint8_t vm_mem[VM_MEM_SZ];') 241 | print('') 242 | 243 | # function prototypes 244 | for func in bv.functions: 245 | prototype = ''.join(map(lambda x: x.text, func.type_tokens)) 246 | m = re.match(r'^.* (.*)\(.*\)', prototype) 247 | if not m: 248 | print('malformed function prototype: %s' % prototype) 249 | func_name = m.group(1) 250 | print('void %s(void);' % func_name) 251 | print('') 252 | 253 | # loop over binaryninja.function.Function 254 | for func in bv.functions: 255 | #print('// function %s()' % func.name) 256 | prototype = ''.join(map(lambda x: x.text, func.type_tokens)) 257 | funcName = re.match(r'^.* (.*)\(.*\)', prototype).group(1) 258 | 259 | print('/* %s */' % prototype) 260 | print('void %s(void)' % funcName) 261 | print('{') 262 | 263 | blocks = list(func.low_level_il.basic_blocks) 264 | for block in blocks: 265 | print('\tloc_%d:' % block.start) 266 | 267 | # loop over binaryninja.basicblock.BasicBlock 268 | for insn in block: 269 | current_llil = func.low_level_il 270 | #print('\truntime_comment("%s\\n");' % str(insn)) 271 | print('\t// %s' % str(insn)) 272 | print('\t', end='') 273 | traverse_IL(insn) 274 | print('') 275 | 276 | # newline to separate blocks 277 | if block != blocks[-1]: 278 | print('') 279 | 280 | print('}') 281 | print('') 282 | 283 | # 284 | # print('const char *bv_image =') 285 | # tmp = bv.read(bv.start, bv.end) 286 | # while tmp: 287 | # chunk_sz = min(16, len(tmp)) 288 | # print('\t"' + ''.join(['\\x%02x'%b for b in tmp[0:chunk_sz]]) + '"') 289 | # tmp = tmp[chunk_sz:] 290 | # print(';') 291 | 292 | print('void initialize_memory()') 293 | print('{') 294 | print('\tmemset(vm_mem, 0, VM_MEM_SZ);') 295 | # print('\tmemcpy(vm_mem+0x%X, bv_image, %d);' % (bv.start, bv.end-bv.start)) 296 | print('\t' + '\n\t'.join(init_mem_lines)) 297 | print('}\n') 298 | 299 | # what other stuff would a runtime need to execute the IL? 300 | 301 | # see architecture.py 302 | # self.__dict__["name"] = core.BNGetArchitectureName(self.handle) 303 | # self.__dict__["endianness"] = Endianness(core.BNGetArchitectureEndianness(self.handle)) 304 | # self.__dict__["address_size"] = core.BNGetArchitectureAddressSize(self.handle) 305 | # self.__dict__["default_int_size"] = core.BNGetArchitectureDefaultIntegerSize(self.handle) 306 | # self.__dict__["instr_alignment"] = core.BNGetArchitectureInstructionAlignment(self.handle) 307 | # self.__dict__["max_instr_length"] = core.BNGetArchitectureMaxInstructionLength(self.handle) 308 | # self.__dict__["opcode_display_length"] = core.BNGetArchitectureOpcodeDisplayLength(self.handle) 309 | # self.__dict__["stack_pointer"] = core.BNGetArchi 310 | 311 | # emit register info (so runtime can know that (for example) writes to eax affect rax) 312 | # see definition of RegisterInfo in il_runtime.h 313 | print('map reg_infos = {') 314 | for (regName,regInfo) in bv.arch.regs.items(): 315 | print('\t{"%s", {%d, "%s", %d, %d, %d}}, /* %s */' % \ 316 | (regName, int(regInfo.index), regInfo.full_width_reg, regInfo.offset, regInfo.size, regInfo.extend, repr(regInfo)) 317 | ) 318 | print('};') 319 | print('') 320 | 321 | # emit stack register name 322 | print('string stack_reg_name = "%s";' % bv.arch.stack_pointer) 323 | # emit whether architecture uses a link register 324 | if bv.arch.link_reg: 325 | print('bool is_link_reg_arch = true;') 326 | print('string link_reg_name = "%s";' % bv.arch.link_reg) 327 | else: 328 | print('bool is_link_reg_arch = false;') 329 | print('string link_reg_name = "(error)";') 330 | 331 | -------------------------------------------------------------------------------- /lldb_x64.py: -------------------------------------------------------------------------------- 1 | import re 2 | import struct 3 | 4 | import lldb 5 | 6 | #------------------------------------------------------------------------------ 7 | # string formatting 8 | #------------------------------------------------------------------------------ 9 | 10 | def get_hex_dump(data, addr=0, grouping=1, endian='little', color=False): 11 | data = ''.join(map(chr, data)) 12 | result = '' 13 | while(data): 14 | ascii = '' 15 | buff16 = data[0:16] 16 | data = data[16:] 17 | if color: 18 | result += "\x1b[0;33m%08X\x1b[0m " % addr 19 | else: 20 | result += "%08X: " % addr 21 | i = 0 22 | while i < 16: 23 | if i+grouping <= len(buff16): 24 | f0 = { \ 25 | 'big': {1:'>B', 2:'>H', 4:'>I', 8:'>Q'}, \ 26 | 'little': {1:'= ' ' and char <= '~'): 40 | ascii += char 41 | else: 42 | if color and char=='\x00': 43 | ascii += '\x1b[0;34m.\x1b[0m' 44 | else: 45 | ascii += '.' 46 | else: 47 | if grouping == 1: 48 | result += ' '*3 49 | elif grouping == 2: 50 | result += ' '*5 51 | elif grouping == 4: 52 | result += ' '*9 53 | elif grouping == 8: 54 | result += ' '*17 55 | i += grouping 56 | result += ' %s\n' % ascii 57 | addr += 16; 58 | 59 | return result 60 | 61 | #------------------------------------------------------------------------------ 62 | # access VM mem, regs, etc. 63 | #------------------------------------------------------------------------------ 64 | 65 | def get_vm_map(name): 66 | result = {} 67 | 68 | var = lldb.target.FindFirstGlobalVariable(name) 69 | vstr = str(var) 70 | for m in re.finditer(r'\(first = "(.*?)", second = (.*?)\)', vstr): 71 | (var, val) = m.group(1, 2) 72 | result[var] = int(val, 10) 73 | 74 | return result 75 | 76 | def get_vm_mem(): 77 | mem = lldb.target.FindFirstGlobalVariable("vm_mem") 78 | mem = mem.GetData()._read_all_uint8() 79 | return mem 80 | 81 | #------------------------------------------------------------------------------ 82 | # print junk 83 | #------------------------------------------------------------------------------ 84 | 85 | def print_vm_stack(): 86 | mem = get_vm_mem() 87 | #print(get_vm_map('vm_regs')) 88 | rsp = get_vm_map('vm_regs')['rsp'] 89 | 90 | ptr = rsp - 32 91 | ptr = (ptr >> 4) << 4 92 | 93 | print(get_hex_dump(mem[ptr:], addr=ptr, grouping=4, endian='little', color=True)) 94 | 95 | def print_map_016X(foo): 96 | for (key, val) in foo.items(): 97 | print('%s: %016X' % (key, val)) 98 | 99 | def print_map_1(foo): 100 | for (key, val) in foo.items(): 101 | print('%s: %d' % (key, val)) 102 | 103 | def print_vm_regs(): 104 | print_vm_map('vm_regs') 105 | 106 | def print_vm_context(): 107 | tmp = get_vm_map('vm_regs') 108 | if tmp: 109 | print('-regs------------') 110 | print_map_016X(tmp) 111 | 112 | tmp = get_vm_map('vm_flags') 113 | if tmp: 114 | print('-flags-----------') 115 | print_map_1(tmp) 116 | 117 | tmp = get_vm_map('vm_regs_temp') 118 | if tmp: 119 | print('-temp------------') 120 | print_map_016X(tmp) 121 | 122 | tmp = get_vm_map('vm_regs') 123 | if tmp: 124 | print('-regs------------') 125 | print_map_016X(tmp) 126 | 127 | print('-stack----------') 128 | print_vm_stack() 129 | 130 | #------------------------------------------------------------------------------ 131 | # hookup with lldb 132 | #------------------------------------------------------------------------------ 133 | 134 | def vm(debugger, command, result, internal_dict): 135 | import lldb 136 | print_vm_context() 137 | 138 | # And the initialization code to add your commands 139 | # install with command script import go.py 140 | def __lldb_init_module(debugger, internal_dict): 141 | debugger.HandleCommand('command script add -f lldb_x64.vm vm') 142 | print 'The "vm" python command has been installed and is ready for use.' 143 | -------------------------------------------------------------------------------- /lldb_z80.py: -------------------------------------------------------------------------------- 1 | import re 2 | import struct 3 | 4 | import lldb 5 | 6 | def get_vm_map(name): 7 | result = {} 8 | 9 | var = lldb.target.FindFirstGlobalVariable(name) 10 | vstr = str(var) 11 | for m in re.finditer(r'\(first = "(.*?)", second = (.*?)\)', vstr): 12 | (var, val) = m.group(1, 2) 13 | result[var] = int(val, 10) 14 | 15 | return result 16 | 17 | def get_vm_mem(): 18 | mem = lldb.target.FindFirstGlobalVariable("vm_mem") 19 | mem = mem.GetData()._read_all_uint8() 20 | return mem 21 | 22 | def print_vm_stack(): 23 | mem = get_vm_mem() 24 | print(get_vm_map('vm_regs')) 25 | sp = get_vm_map('vm_regs')['SP'] 26 | while sp < 2048: 27 | word = (mem[sp+1] << 8) | mem[sp] 28 | print('%04X: %04X' % (sp, word)) 29 | sp += 2 30 | 31 | def print_map_04X(foo): 32 | for (key, val) in foo.items(): 33 | print('%s: %04X' % (key, val)) 34 | 35 | def print_map_1(foo): 36 | for (key, val) in foo.items(): 37 | print('%s: %d' % (key, val)) 38 | 39 | def print_vm_regs(): 40 | print_vm_map('vm_regs') 41 | 42 | def print_vm_context(): 43 | tmp = get_vm_map('vm_regs') 44 | if tmp: 45 | print('-regs------------') 46 | print_map_04X(tmp) 47 | 48 | tmp = get_vm_map('vm_flags') 49 | if tmp: 50 | print('-flags-----------') 51 | print_map_1(tmp) 52 | 53 | tmp = get_vm_map('vm_regs_temp') 54 | if tmp: 55 | print('-temp------------') 56 | print_map_04X(tmp) 57 | 58 | tmp = get_vm_map('vm_regs') 59 | if tmp: 60 | print('-regs------------') 61 | print_map_04X(tmp) 62 | 63 | print('-stack----------') 64 | print_vm_stack() 65 | 66 | def vm(debugger, command, result, internal_dict): 67 | import lldb 68 | print_vm_context() 69 | 70 | # And the initialization code to add your commands 71 | # install with command script import go.py 72 | def __lldb_init_module(debugger, internal_dict): 73 | debugger.HandleCommand('command script add -f lldb_z80.vm vm') 74 | print 'The "vm" python command has been installed and is ready for use.' 75 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | #ifndef assert 10 | #define assert(cond) if(!(cond)) __builtin_debugtrap(); 11 | #endif 12 | 13 | /* VM components */ 14 | #include "runtime.h" 15 | extern vector vm_stack; 16 | extern uint8_t vm_mem[VM_MEM_SZ]; 17 | extern map vm_regs; 18 | 19 | //----------------------------------------------------------------------------- 20 | // functions from tests_il.o 21 | //----------------------------------------------------------------------------- 22 | 23 | #ifdef LEADING_UNDERSCORE 24 | #define life_universe_everything _life_universe_everything 25 | #define add _add 26 | #define test_byte_e_10 _test_byte_e_10 27 | #define test_byte_ne_10 _test_byte_ne_10 28 | #define test_byte_slt_10 _test_byte_slt_10 29 | #define test_byte_ult_10 _test_byte_ult_10 30 | #define test_byte_sle_10 _test_byte_sle_10 31 | #define test_byte_ule_10 _test_byte_ule_10 32 | #define test_byte_sge_10 _test_byte_sge_10 33 | #define test_byte_uge_10 _test_byte_uge_10 34 | #define test_byte_sgt_10 _test_byte_sgt_10 35 | #define test_byte_ugt_10 _test_byte_ugt_10 36 | #define test_byte_neg _test_byte_neg 37 | #define test_byte_pos _test_byte_pos 38 | #define test_word_e_10 _test_word_e_10 39 | #define test_word_ne_10 _test_word_ne_10 40 | #define test_word_slt_10 _test_word_slt_10 41 | #define test_word_ult_10 _test_word_ult_10 42 | #define test_word_sle_10 _test_word_sle_10 43 | #define test_word_ule_10 _test_word_ule_10 44 | #define test_word_sge_10 _test_word_sge_10 45 | #define test_word_uge_10 _test_word_uge_10 46 | #define test_word_sgt_10 _test_word_sgt_10 47 | #define test_word_ugt_10 _test_word_ugt_10 48 | #define test_word_neg _test_word_neg 49 | #define test_word_pos _test_word_pos 50 | #define triangle_up _triangle_up 51 | #define triangle_down _triangle_down 52 | #define multiply_u8 _multiply_u8 53 | #define multiply _multiply 54 | #define multiply_loop _multiply_loop 55 | #define div _div 56 | #define mod _mod 57 | #define exp_dummy _exp_dummy 58 | #define expmod _expmod 59 | #define gcd _gcd 60 | #define gcd_recursive _gcd_recursive 61 | #define switch_doubler _switch_doubler 62 | #define factorial _factorial 63 | #define fp_single_add _fp_single_add 64 | #define fp_single_sub _fp_single_sub 65 | #define fp_single_mul _fp_single_mul 66 | #define fp_single_div _fp_single_div 67 | #define fp_convert_double_to_single _fp_convert_double_to_single 68 | #define fp_convert_double_product_to_single _fp_convert_double_product_to_single 69 | #endif 70 | 71 | /* functions from generated tests_il.o we'll be using */ 72 | void life_universe_everything(); 73 | void initialize_memory(); 74 | void add(); 75 | void test_byte_e_10(); 76 | void test_byte_ne_10(); 77 | void test_byte_slt_10(); 78 | void test_byte_ult_10(); 79 | void test_byte_sle_10(); 80 | void test_byte_ule_10(); 81 | void test_byte_sge_10(); 82 | void test_byte_uge_10(); 83 | void test_byte_sgt_10(); 84 | void test_byte_ugt_10(); 85 | void test_byte_neg(); 86 | void test_byte_pos(); 87 | void test_word_e_10(); 88 | void test_word_ne_10(); 89 | void test_word_slt_10(); 90 | void test_word_ult_10(); 91 | void test_word_sle_10(); 92 | void test_word_ule_10(); 93 | void test_word_sge_10(); 94 | void test_word_uge_10(); 95 | void test_word_sgt_10(); 96 | void test_word_ugt_10(); 97 | void test_word_neg(); 98 | void test_word_pos(); 99 | void triangle_up(); 100 | void triangle_down(); 101 | void multiply(); 102 | void multiply_u8(); 103 | void multiply_loop(); 104 | void div(); 105 | void mod(); 106 | void exp_dummy(); 107 | void expmod(); 108 | void gcd(); 109 | void gcd_recursive(); 110 | void switch_doubler(); 111 | void factorial(); 112 | void fp_single_add(); 113 | void fp_single_sub(); 114 | void fp_single_mul(); 115 | void fp_single_div(); 116 | void fp_convert_double_to_single(); 117 | void fp_convert_double_product_to_single(); 118 | 119 | //----------------------------------------------------------------------------- 120 | // architecture-specific VM utilities to init stack, set args, return values 121 | //----------------------------------------------------------------------------- 122 | 123 | #ifdef ARCH_X64 124 | void vm_init_stack() { reg_set_uint64("rsp", VM_MEM_SZ); } 125 | void vm_set_arg0(int a) { reg_set_uint64("rdi", a); } 126 | void vm_set_arg1(int a) { reg_set_uint64("rsi", a); } 127 | void vm_set_arg2(int a) { reg_set_uint64("rdx", a); } 128 | void vm_precall() 129 | { 130 | // synthesize a push of "CALLERCALLER" 131 | reg_set_uint64("rsp", reg_get_uint64("rsp")-8); 132 | *(uint64_t *)(vm_mem + reg_get_uint64("rsp")) = RETURN_ADDRESS_CANARY; 133 | } 134 | 135 | void vm_set_arg(int order, type_val tv) 136 | { 137 | // System V AMD64 ABI 138 | // The first six integer or pointer arguments are passed in registers RDI, RSI, RDX, RCX, R8, R9 139 | if(tv.type == TV_TYPE_UINT64) { 140 | switch(order) { 141 | case 0: reg_set_uint64("rdi", tv_get_uint64(tv)); break; 142 | case 1: reg_set_uint64("rsi", tv_get_uint64(tv)); break; 143 | case 2: reg_set_uint64("rdx", tv_get_uint64(tv)); break; 144 | case 3: reg_set_uint64("rcx", tv_get_uint64(tv)); break; 145 | case 4: reg_set_uint64("r8", tv_get_uint64(tv)); break; 146 | case 5: reg_set_uint64("r9", tv_get_uint64(tv)); break; 147 | break; 148 | } 149 | } 150 | else if(tv.type == TV_TYPE_UINT32) { 151 | switch(order) { 152 | case 0: reg_set_uint64("rdi", tv_get_uint32(tv)); break; 153 | case 1: reg_set_uint64("rsi", tv_get_uint32(tv)); break; 154 | case 2: reg_set_uint64("rdx", tv_get_uint32(tv)); break; 155 | case 3: reg_set_uint64("rcx", tv_get_uint32(tv)); break; 156 | case 4: reg_set_uint64("r8", tv_get_uint32(tv)); break; 157 | case 5: reg_set_uint64("r9", tv_get_uint32(tv)); break; 158 | break; 159 | } 160 | } 161 | // ...while XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 and XMM7 are used for the first floating point arguments 162 | else if(tv.type == TV_TYPE_FLOAT32) { 163 | switch(order) { 164 | case 0: reg_set_float32("xmm0", tv_get_float32(tv)); break; 165 | case 1: reg_set_float32("xmm1", tv_get_float32(tv)); break; 166 | case 2: reg_set_float32("xmm2", tv_get_float32(tv)); break; 167 | case 3: reg_set_float32("xmm3", tv_get_float32(tv)); break; 168 | case 4: reg_set_float32("xmm4", tv_get_float32(tv)); break; 169 | case 5: reg_set_float32("xmm5", tv_get_float32(tv)); break; 170 | case 6: reg_set_float32("xmm6", tv_get_float32(tv)); break; 171 | case 7: reg_set_float32("xmm7", tv_get_float32(tv)); break; 172 | case 8: reg_set_float32("xmm8", tv_get_float32(tv)); break; 173 | break; 174 | } 175 | } 176 | else if(tv.type == TV_TYPE_FLOAT64) { 177 | switch(order) { 178 | case 0: reg_set_float64("xmm0", tv_get_float64(tv)); break; 179 | case 1: reg_set_float64("xmm1", tv_get_float64(tv)); break; 180 | case 2: reg_set_float64("xmm2", tv_get_float64(tv)); break; 181 | case 3: reg_set_float64("xmm3", tv_get_float64(tv)); break; 182 | case 4: reg_set_float64("xmm4", tv_get_float64(tv)); break; 183 | case 5: reg_set_float64("xmm5", tv_get_float64(tv)); break; 184 | case 6: reg_set_float64("xmm6", tv_get_float64(tv)); break; 185 | case 7: reg_set_float64("xmm7", tv_get_float64(tv)); break; 186 | case 8: reg_set_float64("xmm8", tv_get_float64(tv)); break; 187 | break; 188 | } 189 | } 190 | else 191 | { 192 | assert(false); 193 | } 194 | } 195 | 196 | type_val vm_get_retval(enum TV_TYPE ret_type) 197 | { 198 | switch(ret_type) 199 | { 200 | case TV_TYPE_UINT8: return tv_new_uint8(reg_get_uint8("al")); 201 | case TV_TYPE_UINT16: return tv_new_uint16(reg_get_uint16("ax")); 202 | case TV_TYPE_UINT32: return tv_new_uint32(reg_get_uint32("eax")); 203 | case TV_TYPE_UINT64: return tv_new_uint64(reg_get_uint64("rax")); 204 | case TV_TYPE_FLOAT32: 205 | { 206 | __uint128_t tmp = reg_get_uint128("xmm0"); 207 | type_val tv = tv_new_float32(*(float *)(&tmp)); 208 | return tv; 209 | } 210 | case TV_TYPE_FLOAT64: 211 | { 212 | __uint128_t tmp = reg_get_uint128("xmm0"); 213 | type_val tv = tv_new_float64(*(double *)(&tmp)); 214 | return tv; 215 | } 216 | default: 217 | assert(false); 218 | } 219 | } 220 | #endif 221 | 222 | #ifdef ARCH_ARM 223 | void vm_init_stack() { reg_set_uint32("sp", VM_MEM_SZ); } 224 | void vm_set_arg(int order, type_val tv) 225 | { 226 | if(tv.type == TV_TYPE_UINT32 || tv.type == TV_TYPE_FLOAT32) { 227 | switch(order) { 228 | case 0: reg_set_uint32("r0", tv_get_uint32(tv)); break; 229 | case 1: reg_set_uint32("r1", tv_get_uint32(tv)); break; 230 | case 2: reg_set_uint32("r2", tv_get_uint32(tv)); break; 231 | break; 232 | } 233 | } 234 | else 235 | { 236 | assert(false); 237 | } 238 | } 239 | 240 | void vm_precall() 241 | { 242 | reg_set_uint32("lr", RETURN_ADDRESS_CANARY); 243 | } 244 | 245 | type_val vm_get_retval(enum TV_TYPE ret_type) 246 | { 247 | switch(ret_type) 248 | { 249 | case TV_TYPE_UINT32: 250 | return tv_new_uint32(reg_get_uint32("r0")); 251 | case TV_TYPE_FLOAT32: 252 | return tv_new_float32(reg_get_float32("r0")); 253 | default: 254 | assert(false); 255 | } 256 | } 257 | #endif 258 | 259 | #ifdef ARCH_A64 260 | void vm_init_stack() 261 | { 262 | reg_set_uint64("sp", VM_MEM_SZ); 263 | } 264 | void vm_precall() 265 | { 266 | reg_set_uint64("sp", reg_get_uint64("sp") - 8); 267 | *(uint64_t *)vm_mem = RETURN_ADDRESS_CANARY; 268 | } 269 | void vm_set_arg(int order, type_val tv) 270 | { 271 | if(tv.type == TV_TYPE_UINT32) { 272 | if(order==0) reg_set_uint32("w0", tv_get_uint32(tv)); 273 | else if(order==1) reg_set_uint32("w1", tv_get_uint32(tv)); 274 | else if(order==2) reg_set_uint32("w2", tv_get_uint32(tv)); 275 | else if(order==3) reg_set_uint32("w3", tv_get_uint32(tv)); 276 | } 277 | else if(tv.type == TV_TYPE_UINT64) { 278 | if(order==0) reg_set_uint64("x0", tv_get_uint64(tv)); 279 | else if(order==1) reg_set_uint64("x1", tv_get_uint64(tv)); 280 | else if(order==2) reg_set_uint64("x2", tv_get_uint64(tv)); 281 | else if(order==3) reg_set_uint64("x3", tv_get_uint64(tv)); 282 | } 283 | else if(tv.type == TV_TYPE_FLOAT32) { 284 | if(order==0) reg_set_float32("s0", tv_get_float32(tv)); 285 | else if(order==1) reg_set_float32("s1", tv_get_float32(tv)); 286 | else if(order==2) reg_set_float32("s2", tv_get_float32(tv)); 287 | else if(order==3) reg_set_float32("s3", tv_get_float32(tv)); 288 | } 289 | else if(tv.type == TV_TYPE_FLOAT64) { 290 | if(order==0) reg_set_float64("d0", tv_get_float64(tv)); 291 | else if(order==1) reg_set_float64("d1", tv_get_float64(tv)); 292 | else if(order==2) reg_set_float64("d2", tv_get_float64(tv)); 293 | else if(order==3) reg_set_float64("d3", tv_get_float64(tv)); 294 | } 295 | else { 296 | assert(false); 297 | } 298 | } 299 | type_val vm_get_retval(enum TV_TYPE type) 300 | { 301 | type_val result; 302 | 303 | switch(type) 304 | { 305 | case TV_TYPE_UINT32: 306 | { 307 | uint32_t temp = reg_get_uint32("w0"); 308 | result = tv_new_uint32(temp); 309 | break; 310 | } 311 | case TV_TYPE_UINT64: 312 | { 313 | uint32_t temp = reg_get_uint32("x0"); 314 | result = tv_new_uint64(temp); 315 | break; 316 | } 317 | case TV_TYPE_FLOAT32: 318 | { 319 | float temp = reg_get_float32("s0"); 320 | result = tv_new_float32(temp); 321 | break; 322 | } 323 | default: 324 | assert(false); 325 | } 326 | 327 | result.type = type; 328 | return result; 329 | } 330 | #endif 331 | 332 | #ifdef ARCH_Z80 333 | void vm_init_stack() { vm_regs["SP"] = VM_MEM_SZ; } 334 | void vm_set_arg0(int16_t a) { vm_regs["SP"] -= 2; *(int16_t *)(vm_mem + vm_regs["SP"]) = a; } 335 | void vm_set_arg1(int16_t a) { vm_set_arg0(a); } 336 | void vm_set_arg2(int16_t a) { vm_set_arg0(a); } 337 | void vm_precall() { vm_regs["SP"] -= 2; *(uint16_t *)(vm_mem + vm_regs["SP"]) = 0xAAAA; } 338 | int16_t vm_get_retval() { return (int16_t)vm_regs["HL"]; } 339 | #endif 340 | 341 | //----------------------------------------------------------------------------- 342 | // architecture-independent VM utilities 343 | //----------------------------------------------------------------------------- 344 | 345 | void vm_reset() 346 | { 347 | memset(vm_mem, 0, VM_MEM_SZ); 348 | vm_regs.clear(); 349 | vm_init_stack(); 350 | /* from tests_il.cpp, generated to include switch lookup tables */ 351 | initialize_memory(); 352 | } 353 | 354 | typedef void (*VM_FUNC)(void); 355 | typedef void (*VM_FUNC_SET_ARG)(type_val tv); 356 | 357 | /* call a function in the vm */ 358 | type_val vm_call(VM_FUNC pfunc, type_val *args, enum TV_TYPE ret_type) 359 | { 360 | vm_reset(); 361 | vm_precall(); 362 | 363 | /* set function arguments */ 364 | for(int i=0; args[i].type != TV_TYPE_NONE; i++) 365 | vm_set_arg(i, args[i]); 366 | 367 | /* call the function, return result */ 368 | pfunc(); 369 | return vm_get_retval(ret_type); 370 | } 371 | 372 | //----------------------------------------------------------------------------- 373 | // testing convenience functions 374 | //----------------------------------------------------------------------------- 375 | 376 | void check(type_val actual, type_val expected) 377 | { 378 | char actual_str[128], expected_str[128]; 379 | tv_to_str(actual, actual_str, 128); 380 | tv_to_str(expected, expected_str, 128); 381 | 382 | printf("actual: "); 383 | for(int i=0; i<16; i++) 384 | printf("%02X ", actual.data[i]); 385 | printf("\n"); 386 | 387 | printf("expect: "); 388 | for(int i=0; i<16; i++) 389 | printf("%02X ", expected.data[i]); 390 | printf("\n"); 391 | 392 | if(tv_cmp(actual, expected)==0) 393 | printf(" \x1B[32mPASSED\x1B[0m (actual,expected) = (%s,%s)\n", actual_str, expected_str); 394 | else { 395 | printf(" \x1B[31mFAILED\x1B[0m (actual,expected) = (%s,%s)\n", actual_str, expected_str); 396 | exit(-1); 397 | } 398 | } 399 | 400 | // u32 foo(void) 401 | void test(const char *func_name, VM_FUNC pfunc, uint32_t expected) 402 | { 403 | printf("%s()...\n", func_name); 404 | type_val args[1]; 405 | args[0] = tv_new_none(); 406 | type_val result = vm_call(pfunc, args, TV_TYPE_UINT32); 407 | type_val expected_tv = tv_new_uint32(expected); 408 | check(result, expected_tv); 409 | } 410 | 411 | // u32 foo(u32) 412 | void test(const char *func_name, VM_FUNC pfunc, uint32_t arg0, uint32_t expected) 413 | { 414 | printf("%s()...\n", func_name); 415 | type_val args[2]; 416 | args[0] = tv_new_uint32(arg0); 417 | args[1] = tv_new_none(); 418 | type_val result = vm_call(pfunc, args, TV_TYPE_UINT32); 419 | type_val expected_tv = tv_new_uint32(expected); 420 | check(result, expected_tv); 421 | } 422 | 423 | // u32 foo(u32, u32) 424 | void test(const char *func_name, VM_FUNC pfunc, uint32_t arg0, uint32_t arg1, uint32_t expected) 425 | { 426 | printf("%s()...\n", func_name); 427 | type_val args[3]; 428 | args[0] = tv_new_uint32(arg0); 429 | args[1] = tv_new_uint32(arg1); 430 | args[2] = tv_new_none(); 431 | type_val result = vm_call(pfunc, args, TV_TYPE_UINT32); 432 | type_val expected_tv = tv_new_uint32(expected); 433 | check(result, expected_tv); 434 | } 435 | 436 | // u32 foo(u32, u32, u32) 437 | void test(const char *func_name, VM_FUNC pfunc, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t expected) 438 | { 439 | printf("%s()...\n", func_name); 440 | type_val args[4]; 441 | args[0] = tv_new_uint32(arg0); 442 | args[1] = tv_new_uint32(arg1); 443 | args[2] = tv_new_uint32(arg2); 444 | args[3] = tv_new_none(); 445 | type_val result = vm_call(pfunc, args, TV_TYPE_UINT32); 446 | type_val expected_tv = tv_new_uint32(expected); 447 | check(result, expected_tv); 448 | } 449 | 450 | // float32 foo(float32, float32) 451 | void test_s(const char *func_name, VM_FUNC pfunc, float arg0, float arg1, float expected) 452 | { 453 | printf("%s()...\n", func_name); 454 | type_val args[3]; 455 | args[0] = tv_new_float32(arg0); 456 | args[1] = tv_new_float32(arg1); 457 | args[2] = tv_new_none(); 458 | type_val result = vm_call(pfunc, args, TV_TYPE_FLOAT32); 459 | type_val expected_tv = tv_new_float32(expected); 460 | check(result, expected_tv); 461 | } 462 | 463 | // float32 foo(float64) 464 | void test_s_d(const char *func_name, VM_FUNC pfunc, double arg0, float expected) 465 | { 466 | printf("%s()...\n", func_name); 467 | type_val args[2]; 468 | args[0] = tv_new_float64(arg0); 469 | args[1] = tv_new_none(); 470 | type_val result = vm_call(pfunc, args, TV_TYPE_FLOAT32); 471 | type_val expected_tv = tv_new_float32(expected); 472 | check(result, expected_tv); 473 | } 474 | 475 | // float32 foo(float64, float64) 476 | void test_s_d_d(const char *func_name, VM_FUNC pfunc, double arg0, double arg1, float expected) 477 | { 478 | printf("%s()...\n", func_name); 479 | type_val args[3]; 480 | args[0] = tv_new_float64(arg0); 481 | args[1] = tv_new_float64(arg1); 482 | args[2] = tv_new_none(); 483 | type_val result = vm_call(pfunc, args, TV_TYPE_FLOAT32); 484 | type_val expected_tv = tv_new_float32(expected); 485 | check(result, expected_tv); 486 | } 487 | 488 | //----------------------------------------------------------------------------- 489 | // main 490 | //----------------------------------------------------------------------------- 491 | 492 | int main(int ac, char **av) 493 | { 494 | int result; 495 | 496 | test("life_universe_everything", life_universe_everything, 42); 497 | 498 | /* add */ 499 | test("add", add, 4,7, 11); 500 | test("add", add, -4,7, 3); 501 | test("add", add, -4,-7, -11); 502 | test("add", add, 123,456, 579); 503 | 504 | /* comparison, 1 byte */ 505 | 506 | //void test_byte_e_10(); 507 | test("test_byte_e_10", test_byte_e_10,3, 13); 508 | test("test_byte_e_10", test_byte_e_10,7, 13); 509 | test("test_byte_e_10", test_byte_e_10,10, 7); 510 | test("test_byte_e_10", test_byte_e_10,13, 13); 511 | 512 | //void test_byte_ne_10(); 513 | test("test_byte_ne_10", test_byte_ne_10,3, 7); 514 | test("test_byte_ne_10", test_byte_ne_10,7, 7); 515 | test("test_byte_ne_10", test_byte_ne_10,10, 13); 516 | test("test_byte_ne_10", test_byte_ne_10,13, 7); 517 | 518 | //void test_byte_slt_10(); 519 | test("test_byte_slt_10", test_byte_slt_10,3, 7); 520 | test("test_byte_slt_10", test_byte_slt_10,7, 7); 521 | test("test_byte_slt_10", test_byte_slt_10,10, 13); 522 | test("test_byte_slt_10", test_byte_slt_10,13, 13); 523 | 524 | //void test_byte_ult_10(); 525 | test("test_byte_ult_10", test_byte_ult_10,3, 7); 526 | test("test_byte_ult_10", test_byte_ult_10,7, 7); 527 | test("test_byte_ult_10", test_byte_ult_10,10, 13); 528 | test("test_byte_ult_10", test_byte_ult_10,13, 13); 529 | 530 | //void test_byte_sle_10(); 531 | test("test_byte_sle_10", test_byte_sle_10,3, 7); 532 | test("test_byte_sle_10", test_byte_sle_10,7, 7); 533 | test("test_byte_sle_10", test_byte_sle_10,10, 7); 534 | test("test_byte_sle_10", test_byte_sle_10,13, 13); 535 | 536 | //void test_byte_ule_10(); 537 | test("test_byte_ule_10", test_byte_ule_10,3, 7); 538 | test("test_byte_ule_10", test_byte_ule_10,7, 7); 539 | test("test_byte_ule_10", test_byte_ule_10,10, 7); 540 | test("test_byte_ule_10", test_byte_ule_10,13, 13); 541 | 542 | //void test_byte_sge_10(); 543 | test("test_byte_sge_10", test_byte_sge_10,3, 13); 544 | test("test_byte_sge_10", test_byte_sge_10,7, 13); 545 | test("test_byte_sge_10", test_byte_sge_10,10, 7); 546 | test("test_byte_sge_10", test_byte_sge_10,13, 7); 547 | 548 | //void test_byte_uge_10(); 549 | test("test_byte_uge_10", test_byte_uge_10,3, 13); 550 | test("test_byte_uge_10", test_byte_uge_10,7, 13); 551 | test("test_byte_uge_10", test_byte_uge_10,10, 7); 552 | test("test_byte_uge_10", test_byte_uge_10,13, 7); 553 | 554 | //void test_byte_sgt_10(); 555 | test("test_byte_sgt_10", test_byte_sgt_10,3, 13); 556 | test("test_byte_sgt_10", test_byte_sgt_10,7, 13); 557 | test("test_byte_sgt_10", test_byte_sgt_10,10, 13); 558 | test("test_byte_sgt_10", test_byte_sgt_10,13, 7); 559 | 560 | //void test_byte_ugt_10(); 561 | test("test_byte_ugt_10", test_byte_ugt_10,3, 13); 562 | test("test_byte_ugt_10", test_byte_ugt_10,7, 13); 563 | test("test_byte_ugt_10", test_byte_ugt_10,10, 13); 564 | test("test_byte_ugt_10", test_byte_ugt_10,13, 7); 565 | 566 | //void test_byte_neg(); 567 | test("test_byte_neg", test_byte_neg,-23, 7); 568 | test("test_byte_neg", test_byte_neg,-7, 7); 569 | test("test_byte_neg", test_byte_neg,0, 13); 570 | test("test_byte_neg", test_byte_neg,7, 13); 571 | test("test_byte_neg", test_byte_neg,23, 13); 572 | 573 | //void test_byte_pos(); 574 | test("test_byte_pos", test_byte_pos,-23, 13); 575 | test("test_byte_pos", test_byte_pos,-7, 13); 576 | test("test_byte_pos", test_byte_pos,0, 7); 577 | test("test_byte_pos", test_byte_pos,7, 7); 578 | test("test_byte_pos", test_byte_pos,23, 7); 579 | 580 | /* comparison, more bytes */ 581 | //void test_word_e_10(); 582 | test("test_word_e_10", test_word_e_10,3, 13); 583 | test("test_word_e_10", test_word_e_10,7, 13); 584 | test("test_word_e_10", test_word_e_10,10, 7); 585 | test("test_word_e_10", test_word_e_10,13, 13); 586 | 587 | //void test_word_ne_10(); 588 | test("test_word_ne_10", test_word_ne_10,3, 7); 589 | test("test_word_ne_10", test_word_ne_10,7, 7); 590 | test("test_word_ne_10", test_word_ne_10,10, 13); 591 | test("test_word_ne_10", test_word_ne_10,13, 7); 592 | 593 | //void test_word_slt_10(); 594 | test("test_word_slt_10", test_word_slt_10,3, 7); 595 | test("test_word_slt_10", test_word_slt_10,7, 7); 596 | test("test_word_slt_10", test_word_slt_10,10, 13); 597 | test("test_word_slt_10", test_word_slt_10,13, 13); 598 | 599 | //void test_word_ult_10(); 600 | test("test_word_ult_10", test_word_ult_10,3, 7); 601 | test("test_word_ult_10", test_word_ult_10,7, 7); 602 | test("test_word_ult_10", test_word_ult_10,10, 13); 603 | test("test_word_ult_10", test_word_ult_10,13, 13); 604 | 605 | //void test_word_sle_10(); 606 | test("test_word_sle_10", test_word_sle_10,3, 7); 607 | test("test_word_sle_10", test_word_sle_10,7, 7); 608 | test("test_word_sle_10", test_word_sle_10,10, 7); 609 | test("test_word_sle_10", test_word_sle_10,13, 13); 610 | 611 | //void test_word_ule_10(); 612 | test("test_word_ule_10", test_word_ule_10,3, 7); 613 | test("test_word_ule_10", test_word_ule_10,7, 7); 614 | test("test_word_ule_10", test_word_ule_10,10, 7); 615 | test("test_word_ule_10", test_word_ule_10,13, 13); 616 | 617 | //void test_word_sge_10(); 618 | test("test_word_sge_10", test_word_sge_10,3, 13); 619 | test("test_word_sge_10", test_word_sge_10,7, 13); 620 | test("test_word_sge_10", test_word_sge_10,10, 7); 621 | test("test_word_sge_10", test_word_sge_10,13, 7); 622 | 623 | //void test_word_uge_10(); 624 | test("test_word_uge_10", test_word_uge_10,3, 13); 625 | test("test_word_uge_10", test_word_uge_10,7, 13); 626 | test("test_word_uge_10", test_word_uge_10,10, 7); 627 | test("test_word_uge_10", test_word_uge_10,13, 7); 628 | 629 | //void test_word_sgt_10(); 630 | test("test_word_sgt_10", test_word_sgt_10,3, 13); 631 | test("test_word_sgt_10", test_word_sgt_10,7, 13); 632 | test("test_word_sgt_10", test_word_sgt_10,10, 13); 633 | test("test_word_sgt_10", test_word_sgt_10,13, 7); 634 | 635 | //void test_word_ugt_10(); 636 | test("test_word_ugt_10", test_word_ugt_10,3, 13); 637 | test("test_word_ugt_10", test_word_ugt_10,7, 13); 638 | test("test_word_ugt_10", test_word_ugt_10,10, 13); 639 | test("test_word_ugt_10", test_word_ugt_10,13, 7); 640 | 641 | //void test_word_neg(); 642 | test("test_word_neg", test_word_neg,-23, 7); 643 | test("test_word_neg", test_word_neg,-7, 7); 644 | test("test_word_neg", test_word_neg,0, 13); 645 | test("test_word_neg", test_word_neg,7, 13); 646 | test("test_word_neg", test_word_neg,23, 13); 647 | 648 | //void test_word_pos(); 649 | test("test_word_pos", test_word_pos,-23, 13); 650 | test("test_word_pos", test_word_pos,-7, 13); 651 | test("test_word_pos", test_word_pos,0, 7); 652 | test("test_word_pos", test_word_pos,7, 7); 653 | test("test_word_pos", test_word_pos,23, 7); 654 | 655 | /* triangle numbers */ 656 | test("triangle_up", triangle_up,4, 10); 657 | test("triangle_up", triangle_up,7, 28); 658 | test("triangle_up", triangle_up,10, 55); 659 | test("triangle_up", triangle_up,100, 5050); 660 | test("triangle_down", triangle_down,4, 10); 661 | test("triangle_down", triangle_down,7, 28); 662 | test("triangle_down", triangle_down,10, 55); 663 | test("triangle_down", triangle_down,100, 5050); 664 | 665 | /* multiply: easy case with MUL instruction, else kinda tough */ 666 | test("multiply", multiply,4,7, 28); 667 | test("multiply", multiply,-4,7, -28); 668 | test("multiply", multiply,-4,-7, 28); 669 | test("multiply", multiply,151,217, 32767); 670 | 671 | /* multiply: using loop */ 672 | test("multiply_loop", multiply_loop,4,7, 28); 673 | test("multiply_loop", multiply_loop,-4,7, -28); 674 | test("multiply_loop", multiply_loop,-4,-7, 28); 675 | test("multiply_loop", multiply_loop,151,217, 32767); 676 | 677 | /* div */ 678 | test("div", div,4,-2, -2); 679 | test("div", div,4,7, 0); 680 | test("div", div,7,4, 1); 681 | test("div", div,28,7, 4); 682 | test("div", div,151,-50, -3); 683 | 684 | /* mod */ 685 | test("mod", mod,4,7, 4); 686 | test("mod", mod,7,4, 3); 687 | test("mod", mod,28,7, 0); 688 | test("mod", mod,151,50, 1); 689 | 690 | /* exponentiate */ 691 | test("exp", exp_dummy,4,7, 16384); 692 | test("exp", exp_dummy,2,14, 16384); 693 | test("exp", exp_dummy,3,7, 2187); 694 | test("exp", exp_dummy,-2,7, -128); 695 | 696 | /* exponentiate with a modulus */ 697 | test("expmod", expmod,4,7,5, 4); 698 | test("expmod", expmod,2,16,17, 1); 699 | test("expmod", expmod,3,17,19, 13); 700 | test("expmod", expmod,17,3,23, 14); 701 | 702 | /* greatest common divisor */ 703 | test("gcd", gcd,5,15, 5); 704 | test("gcd", gcd,16,24, 8); 705 | test("gcd", gcd,51,77, 1); 706 | test("gcd", gcd,51,119, 17); 707 | 708 | /* recursion */ 709 | test("factorial", factorial,0, 1); 710 | test("factorial", factorial,5, 120); 711 | #if REGWIDTH == 16 712 | /* be nice and don't let tests set MSB -> negative */ 713 | test("factorial", factorial,6, 720); 714 | test("factorial", factorial,7, 5040); 715 | #else 716 | test("factorial", factorial,8, 40320); 717 | test("factorial", factorial,11, 39916800); 718 | #endif 719 | 720 | /* recursive version: greatest common divisor */ 721 | test("gcd_recursive", gcd_recursive,5,15, 5); 722 | test("gcd_recursive", gcd_recursive,16,24, 8); 723 | test("gcd_recursive", gcd_recursive,51,77, 1); 724 | test("gcd_recursive", gcd_recursive,51,119, 17); 725 | 726 | /* floating point */ 727 | test_s("fp_single_add", fp_single_add,1.0,2.0, 3.0); 728 | test_s("fp_single_add", fp_single_add,1.5,2.5, 4.0); 729 | test_s("fp_single_add", fp_single_add,2.5,3.5, 6.0); 730 | test_s("fp_single_add", fp_single_add,2.5,-3.5, -1.0); 731 | 732 | test_s("fp_single_sub", fp_single_sub,1.0,2.0, -1.0); 733 | test_s("fp_single_sub", fp_single_sub,1.5,2.5, -1.0); 734 | test_s("fp_single_sub", fp_single_sub,2.5,3.5, -1.0); 735 | test_s("fp_single_sub", fp_single_sub,2.5,-3.5, 6.0); 736 | 737 | test_s("fp_single_mul", fp_single_mul,1.0,2.0, 2.0); 738 | test_s("fp_single_mul", fp_single_mul,1.5,2.5, 3.75); 739 | test_s("fp_single_mul", fp_single_mul,2.5,3.5, 8.75); 740 | test_s("fp_single_mul", fp_single_mul,2.5,-3.5, -8.75); 741 | 742 | test_s("fp_single_div(1.0, 2.0)", fp_single_div,1.0,2.0, 0.5); 743 | test_s("fp_single_div(1.5, 2.5)", fp_single_div,1.5,2.5, 0.6); 744 | test_s("fp_single_div(2.5, 4.0)", fp_single_div,2.5,4.0, 0.625); 745 | test_s("fp_single_div(2.5, 4.0)", fp_single_div,2.5,-4.0, -0.625); 746 | 747 | test_s_d("fp_convert_double_to_single", fp_convert_double_to_single, 0.1, 0.1); 748 | test_s_d("fp_convert_double_to_single", fp_convert_double_to_single, 0.5, 0.5); 749 | test_s_d("fp_convert_double_to_single", fp_convert_double_to_single, 0.6, 0.6); 750 | test_s_d("fp_convert_double_to_single", fp_convert_double_to_single, 0.625, 0.625); 751 | 752 | /* 2.0*1.5 = 3.0 */ 753 | test_s_d_d("fp_convert_double_product_to_single(2.0, 1.5)", fp_convert_double_product_to_single, 2.0, 1.5, 3.0); 754 | test_s_d_d("fp_convert_double_product_to_single(3.0, 3.0)", fp_convert_double_product_to_single, 3.0, 3.0, 9.0); 755 | test_s_d_d("fp_convert_double_product_to_single(1.2, 4.0)", fp_convert_double_product_to_single, 1.2, 4.0, 4.8); 756 | test_s_d_d("fp_convert_double_product_to_single(1.5, 0.5)", fp_convert_double_product_to_single, 1.5, 0.5, 0.75); 757 | 758 | /* switch statements */ 759 | test("switch_doubler", switch_doubler,0, 0); 760 | test("switch_doubler", switch_doubler,2, 4); 761 | test("switch_doubler", switch_doubler,999, -1); 762 | test("switch_doubler", switch_doubler,9, 18); 763 | } 764 | -------------------------------------------------------------------------------- /runtime.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include // for isnan() 6 | using namespace std; 7 | 8 | #include 9 | 10 | #include "runtime.h" 11 | 12 | #ifndef assert 13 | #define assert(cond) if(!(cond)) __builtin_debugtrap(); 14 | #endif 15 | 16 | #define DEBUG_RUNTIME_ALL 17 | #define DEBUG_RUNTIME_SETS 18 | #define DEBUG_RUNTIME_STACK 19 | 20 | #define debug printf 21 | 22 | #if defined(DEBUG_RUNTIME_SETS) || defined(DEBUG_RUNTIME_ALL) 23 | #define debug_set printf 24 | #else 25 | #define debug_set(...) while(0); 26 | #endif 27 | 28 | #if defined(DEBUG_RUNTIME_STACK) || defined(DEBUG_RUNTIME_ALL) 29 | #define debug_stack printf 30 | #else 31 | #define debug_stack(...) while(0); 32 | #endif 33 | 34 | /* the foo_il.c must export this, else we can't implement PUSH */ 35 | extern string stack_reg_name; 36 | extern bool is_link_reg_arch; 37 | extern string link_reg_name; 38 | extern map reg_infos; 39 | 40 | /* VM components */ 41 | uint8_t vm_mem[VM_MEM_SZ]; 42 | map vm_regs; 43 | map vm_flags; 44 | 45 | // this is needed because some architecture return values in different locations 46 | // depending on the type of the data, eg: arm ... TODO 47 | 48 | /*****************************************************************************/ 49 | /* type_val and helpers */ 50 | /*****************************************************************************/ 51 | 52 | type_val tv_init(enum TV_TYPE type) { type_val tv; tv.type = type; memset(tv.data, 0, sizeof(tv.data)); return tv; }; 53 | type_val tv_new_uint8(uint8_t val) { type_val tv = tv_init(TV_TYPE_UINT8); *(uint8_t *)(tv.data) = val; return tv; } 54 | type_val tv_new_uint16(uint16_t val) { type_val tv = tv_init(TV_TYPE_UINT16); *(uint16_t *)(tv.data) = val; return tv; } 55 | type_val tv_new_uint32(uint32_t val) { type_val tv = tv_init(TV_TYPE_UINT32); *(uint32_t *)(tv.data) = val; return tv; } 56 | type_val tv_new_uint64(uint64_t val) { type_val tv = tv_init(TV_TYPE_UINT64); *(uint64_t *)(tv.data) = val; return tv; } 57 | type_val tv_new_float32(float val) { type_val tv = tv_init(TV_TYPE_FLOAT32); *(float *)(tv.data) = val; return tv; } 58 | type_val tv_new_float64(double val) { type_val tv = tv_init(TV_TYPE_FLOAT64); *(double *)(tv.data) = val; return tv; } 59 | type_val tv_new_none() { type_val tv = tv_init(TV_TYPE_NONE); memset(tv.data, 0, sizeof(tv.data)); return tv; } 60 | 61 | uint8_t tv_get_uint8(type_val tv) { return *(uint8_t *)(tv.data); } 62 | uint16_t tv_get_uint16(type_val tv) { return *(uint16_t *)(tv.data); } 63 | uint32_t tv_get_uint32(type_val tv) { return *(uint32_t *)(tv.data); } 64 | uint64_t tv_get_uint64(type_val tv) { return *(uint64_t *)(tv.data); } 65 | float tv_get_float32(type_val tv) { return *(float *)(tv.data); } 66 | double tv_get_float64(type_val tv) { return *(double *)(tv.data); } 67 | 68 | void tv_set_uint8(type_val tv, uint8_t val) { tv.type = TV_TYPE_UINT8; *(uint8_t *)(tv.data) = val; } 69 | void tv_set_uint16(type_val tv, uint16_t val) { tv.type = TV_TYPE_UINT16; *(uint16_t *)(tv.data) = val; } 70 | void tv_set_uint32(type_val tv, uint32_t val) { tv.type = TV_TYPE_UINT32; *(uint32_t *)(tv.data) = val; } 71 | void tv_set_uint64(type_val tv, uint64_t val) { tv.type = TV_TYPE_UINT64; *(uint64_t *)(tv.data) = val; } 72 | 73 | void tv_to_str(type_val tv, char *str, int buflen) 74 | { 75 | switch(tv.type) { 76 | case TV_TYPE_UINT8: 77 | snprintf(str, buflen, "0x%02X", tv_get_uint8(tv)); 78 | break; 79 | case TV_TYPE_UINT16: 80 | snprintf(str, buflen, "0x%04X", tv_get_uint16(tv)); 81 | break; 82 | case TV_TYPE_UINT32: 83 | snprintf(str, buflen, "0x%08X", tv_get_uint32(tv)); 84 | break; 85 | case TV_TYPE_UINT64: 86 | snprintf(str, buflen, "0x%016llX", tv_get_uint64(tv)); 87 | break; 88 | case TV_TYPE_FLOAT32: 89 | snprintf(str, buflen, "%f", tv_get_float32(tv)); 90 | break; 91 | default: 92 | str[0] = '\0'; 93 | } 94 | } 95 | 96 | int tv_cmp(type_val a, type_val b) 97 | { 98 | return memcmp(a.data, b.data, sizeof(a.data)); 99 | } 100 | 101 | /*****************************************************************************/ 102 | /* register setting/getting */ 103 | /*****************************************************************************/ 104 | 105 | bool is_temp_reg(string reg_name) 106 | { 107 | return reg_name.rfind("temp", 0) == 0; 108 | } 109 | 110 | // return the register's ENTIRE type_val (possibly a larger parent register) 111 | // 112 | type_val reg_get_type_val(string reg_name) 113 | { 114 | type_val result; 115 | 116 | /* temp registers simply come from the temp regs file */ 117 | if(is_temp_reg(reg_name)) 118 | result = vm_regs[reg_name]; 119 | else 120 | { 121 | /* otherwise we need to resolve sub-register relationships */ 122 | RegisterInfo reg_info = reg_infos[reg_name]; 123 | 124 | /* full width */ 125 | if(reg_info.full_width_reg == reg_name) 126 | result = vm_regs[reg_name]; 127 | /* sub register */ 128 | else 129 | result = vm_regs[reg_info.full_width_reg]; 130 | 131 | /* returned registers retain type indicating their size */ 132 | switch(reg_info.size) 133 | { 134 | case 1: result.type = TV_TYPE_UINT8; 135 | case 2: result.type = TV_TYPE_UINT16; 136 | case 4: result.type = TV_TYPE_UINT32; 137 | case 8: result.type = TV_TYPE_UINT64; 138 | case 16: result.type = TV_TYPE_UINT128; 139 | } 140 | } 141 | 142 | return result; 143 | } 144 | 145 | // set the register's type_val (possibly in a parent register) 146 | void reg_set_type_val(string reg_name, type_val tv) 147 | { 148 | //printf("setting %s to ", reg_name.c_str()); 149 | //for(int i=0; i<16; i++) 150 | // printf("%02X ", tv.data[i]&0xFF); 151 | //printf("\n"); 152 | 153 | if(is_temp_reg(reg_name)) { 154 | vm_regs[reg_name] = tv; 155 | return; 156 | } 157 | 158 | RegisterInfo reg_info = reg_infos[reg_name]; 159 | 160 | if(reg_info.full_width_reg == reg_name) { 161 | vm_regs[reg_name] = tv; 162 | return; 163 | } 164 | 165 | vm_regs[reg_info.full_width_reg] = tv; 166 | } 167 | 168 | // return the register's offset into type_val.data of its parent register 169 | // eg: 170 | // rax is offset 0 into rax, return 0 171 | // eax is offset 0 into rax, return 1 172 | // ah is offset 1 into rax, return 1 173 | int reg_get_type_val_offset(string reg_name) 174 | { 175 | if(is_temp_reg(reg_name)) 176 | return 0; 177 | 178 | RegisterInfo reg_info = reg_infos[reg_name]; 179 | 180 | assert((reg_info.full_width_reg != reg_name) || reg_info.offset==0); 181 | 182 | return reg_info.offset; 183 | } 184 | 185 | /* internal register getters */ 186 | 187 | float reg_get_float32_nocheck(string name) 188 | { 189 | type_val tv = reg_get_type_val(name); 190 | int offset = reg_get_type_val_offset(name); 191 | return *(float *)(tv.data + offset); 192 | } 193 | 194 | uint8_t reg_get_uint8(string name) 195 | { 196 | //assert(is_temp_reg(name) || reg_infos[name].size == 1); 197 | type_val tv = reg_get_type_val(name); 198 | int offset = reg_get_type_val_offset(name); 199 | return *(uint8_t *)(tv.data + offset); 200 | } 201 | 202 | uint16_t reg_get_uint16(string name) 203 | { 204 | //assert(is_temp_reg(name) || reg_infos[name].size == 2); 205 | type_val tv = reg_get_type_val(name); 206 | int offset = reg_get_type_val_offset(name); 207 | return *(uint16_t *)(tv.data + offset); 208 | } 209 | 210 | uint32_t reg_get_uint32(string name) 211 | { 212 | //assert(is_temp_reg(name) || reg_infos[name].size == 4); 213 | type_val tv = reg_get_type_val(name); 214 | int offset = reg_get_type_val_offset(name); 215 | return *(uint32_t *)(tv.data + offset); 216 | } 217 | 218 | uint64_t reg_get_uint64(string name) 219 | { 220 | //assert(is_temp_reg(name) || reg_infos[name].size == 8); 221 | type_val tv = reg_get_type_val(name); 222 | int offset = reg_get_type_val_offset(name); 223 | return *(uint64_t *)(tv.data + offset); 224 | } 225 | 226 | __uint128_t reg_get_uint128(string name) 227 | { 228 | //assert(is_temp_reg(name) || reg_infos[name].size == 16); 229 | type_val tv = reg_get_type_val(name); 230 | int offset = reg_get_type_val_offset(name); 231 | return *(__uint128_t *)(tv.data + offset); 232 | } 233 | 234 | float reg_get_float32(string name) 235 | { 236 | assert(is_temp_reg(name) || reg_infos[name].size == 4); 237 | return reg_get_float32_nocheck(name); 238 | } 239 | 240 | /* internal register setters */ 241 | 242 | void reg_set_uint8_nocheck(string name, uint8_t val) 243 | { 244 | type_val tv = reg_get_type_val(name); 245 | int offset = reg_get_type_val_offset(name); 246 | *(uint8_t *)(tv.data + offset) = val; 247 | reg_set_type_val(name, tv); 248 | } 249 | 250 | void reg_set_uint16_nocheck(string name, uint16_t val) 251 | { 252 | type_val tv = reg_get_type_val(name); 253 | int offset = reg_get_type_val_offset(name); 254 | *(uint16_t *)(tv.data + offset) = val; 255 | reg_set_type_val(name, tv); 256 | } 257 | 258 | void reg_set_uint32_nocheck(string name, uint32_t val) 259 | { 260 | type_val tv = reg_get_type_val(name); 261 | int offset = reg_get_type_val_offset(name); 262 | *(uint32_t *)(tv.data + offset) = val; 263 | reg_set_type_val(name, tv); 264 | } 265 | 266 | void reg_set_uint64_nocheck(string name, uint64_t val) 267 | { 268 | type_val tv = reg_get_type_val(name); 269 | int offset = reg_get_type_val_offset(name); 270 | *(uint64_t *)(tv.data + offset) = val; 271 | reg_set_type_val(name, tv); 272 | } 273 | 274 | void reg_set_uint128_nocheck(string name, __uint128_t val) 275 | { 276 | type_val tv = reg_get_type_val(name); 277 | int offset = reg_get_type_val_offset(name); 278 | *(__uint128_t *)(tv.data + offset) = val; 279 | reg_set_type_val(name, tv); 280 | } 281 | 282 | void reg_set_uint8(string name, uint8_t val) 283 | { 284 | assert(is_temp_reg(name) || reg_infos[name].size == 1); 285 | reg_set_uint8_nocheck(name, val); 286 | } 287 | 288 | void reg_set_uint16(string name, uint16_t val) 289 | { 290 | assert(is_temp_reg(name) || reg_infos[name].size == 2); 291 | reg_set_uint16_nocheck(name, val); 292 | } 293 | 294 | void reg_set_uint32(string name, uint32_t val) 295 | { 296 | assert(is_temp_reg(name) || reg_infos[name].size == 4); 297 | reg_set_uint32_nocheck(name, val); 298 | } 299 | 300 | void reg_set_uint64(string name, uint64_t val) 301 | { 302 | assert(is_temp_reg(name) || reg_infos[name].size == 8); 303 | reg_set_uint64_nocheck(name, val); 304 | } 305 | 306 | void reg_set_uint128(string name, __uint128_t val) 307 | { 308 | assert(is_temp_reg(name) || reg_infos[name].size == 16); 309 | reg_set_uint128_nocheck(name, val); 310 | } 311 | 312 | void reg_set_float32(string name, float val) 313 | { 314 | // do not force size check: often the low-bits of a floating point register 315 | // are reserved for smaller float types, eg: 128-bit xmm0 can have low 32 316 | // bits for a normal single precision float 317 | 318 | //assert(is_temp_reg(name) || reg_infos[name].size == 32); 319 | type_val tv = reg_get_type_val(name); 320 | int offset = reg_get_type_val_offset(name); 321 | *(float *)(tv.data + offset) = val; 322 | reg_set_type_val(name, tv); 323 | } 324 | 325 | void reg_set_float64(string name, double val) 326 | { 327 | type_val tv = reg_get_type_val(name); 328 | int offset = reg_get_type_val_offset(name); 329 | *(double *)(tv.data + offset) = val; 330 | reg_set_type_val(name, tv); 331 | } 332 | 333 | /*****************************************************************************/ 334 | /* operations */ 335 | /*****************************************************************************/ 336 | 337 | /* LowLevelILOperation.LLIL_NOP: [] */ 338 | void NOP(void) 339 | { 340 | return; 341 | } 342 | 343 | /* LowLevelILOperation.LLIL_REG: [("src", "reg")] */ 344 | 345 | /* get an 8-bit register, or the 8-bit low bits of a register */ 346 | uint8_t REG_B(string name) 347 | { 348 | uint8_t result = reg_get_uint8(name); 349 | debug("REG_B 0x%02X (value of %s)\n", result, name.c_str()); 350 | return result; 351 | } 352 | 353 | /* get a 16-bit register, or the 16-bit low bits of a register */ 354 | uint16_t REG_W(string name) 355 | { 356 | uint16_t result = reg_get_uint16(name); 357 | debug("REG_W 0x%04X (value of %s)\n", result, name.c_str()); 358 | return result; 359 | } 360 | 361 | /* get a 32-bit register, or the 32-bit low bits of a register */ 362 | uint32_t REG_D(string name) 363 | { 364 | uint32_t result = reg_get_uint32(name); 365 | float result_f = *(float *)&result; 366 | debug("REG_D 0x%08X (as float: %f) (value of %s)\n", result, result_f, name.c_str()); 367 | return result; 368 | } 369 | 370 | /* get a 64-bit register, or the 64-bit low bits of a register */ 371 | uint64_t REG_Q(string name) 372 | { 373 | uint64_t result = reg_get_uint64(name); 374 | debug("REG_Q 0x%016llX (value of %s)\n", (uint64_t)result, name.c_str()); 375 | return result; 376 | } 377 | 378 | /* get a 128-bit register */ 379 | __uint128_t REG_O(string name) 380 | { 381 | __uint128_t result = reg_get_uint128(name); 382 | debug("REG_O 0x%016llX%016llX (value of %s)\n", (uint64_t)(result>>64), (uint64_t)result, name.c_str()); 383 | return result; 384 | } 385 | 386 | /* LowLevelILOperation.LLIL_SET_REG: [("dest", "reg"), ("src", "expr")] */ 387 | void SET_REG_B(string reg_name, uint8_t value) 388 | { 389 | reg_set_uint8_nocheck(reg_name, value); 390 | debug_set("SET_REG_B %s = 0x%02X\n", reg_name.c_str(), value); 391 | } 392 | 393 | void SET_REG_W(string reg_name, uint16_t value) 394 | { 395 | reg_set_uint16_nocheck(reg_name, value); 396 | debug_set("SET_REG_W %s = 0x%04X\n", reg_name.c_str(), value); 397 | } 398 | 399 | void SET_REG_D(string reg_name, uint32_t value) 400 | { 401 | reg_set_uint32_nocheck(reg_name, value); 402 | debug_set("SET_REG_D %s = 0x%08X\n", reg_name.c_str(), value); 403 | } 404 | 405 | void SET_REG_Q(string reg_name, uint64_t value) 406 | { 407 | reg_set_uint64_nocheck(reg_name, value); 408 | debug_set("SET_REG_Q %s = 0x%016llX\n", reg_name.c_str(), value); 409 | } 410 | 411 | void SET_REG_O(string reg_name, __uint128_t value) 412 | { 413 | reg_set_uint128_nocheck(reg_name, value); 414 | debug_set("SET_REG_O %s = 0x%016llX%016llX\n", reg_name.c_str(), (uint64_t)(value>>64), (uint64_t)value); 415 | } 416 | 417 | /* LowLevelILOperation.LLIL_SET_REG_SPLIT: [("hi", "reg"), ("lo", "reg"), ("src", "expr")] */ 418 | 419 | /* split a 64-bit value into two 32-bit registers, eg: 420 | * edx:eax = 0xDEADBEEF:0xCAFEBABE = 0xDEADBEEFCAFEBABE */ 421 | void SET_REG_SPLIT_D(string reg_hi, string reg_lo, uint64_t src_val) 422 | { 423 | uint32_t dst_val_hi = (src_val >> 32) & 0xFFFFFFFF; 424 | uint32_t dst_val_lo = src_val & 0xFFFFFFFF; 425 | reg_set_uint32(reg_hi, dst_val_hi); 426 | reg_set_uint32(reg_lo, dst_val_lo); 427 | debug_set("SET_REG_SPLIT_D %s:%s = 0x%08X:0x%08X = 0x%016llX\n", 428 | reg_hi.c_str(), reg_lo.c_str(), dst_val_hi, dst_val_lo, src_val); 429 | } 430 | 431 | /* LowLevelILOperation.LLIL_REG_SPLIT: [("hi", "reg"), ("lo", "reg")] */ 432 | 433 | /* join two 32-bit values into a 64-bit value */ 434 | uint64_t REG_SPLIT_D(string reg_hi, string reg_lo) 435 | { 436 | uint32_t src_hi = reg_get_uint32(reg_hi); 437 | uint32_t src_lo = reg_get_uint32(reg_lo); 438 | uint64_t result = ((uint64_t)src_hi << 32) | src_lo; 439 | debug("REG_SPLIT_D 0x%016llX = 0x%08X:0x%08X = %s:%s\n", result, src_hi, src_lo, reg_hi.c_str(), reg_lo.c_str()); 440 | return result; 441 | } 442 | 443 | /* LowLevelILOperation.LLIL_SET_REG_STACK_REL: [("stack", "reg_stack"), ("dest", "expr"), ("src", "expr")] */ 444 | /* LowLevelILOperation.LLIL_REG_STACK_PUSH: [("stack", "reg_stack"), ("src", "expr")] */ 445 | /* LowLevelILOperation.LLIL_SET_FLAG: [("dest", "flag"), ("src", "expr")] */ 446 | void SET_FLAG(string left, bool right) 447 | { 448 | vm_flags[left] = right; 449 | debug_set("SET_FLAG %s = %d\n", left.c_str(), right); 450 | } 451 | 452 | /* LowLevelILOperation.LLIL_LOAD: [("src", "expr")] */ 453 | uint8_t LOAD_B(REGTYPE expr) 454 | { 455 | uint8_t result = vm_mem[expr]; 456 | debug("LOAD_B 0x%X = mem[" FMT_REG "]\n", result, expr); 457 | return result; 458 | } 459 | 460 | uint16_t LOAD_W(REGTYPE expr) 461 | { 462 | uint16_t result = *(uint16_t *)(vm_mem + expr); 463 | debug("LOAD_W 0x%X = mem[" FMT_REG "]\n", result, expr); 464 | return result; 465 | } 466 | 467 | uint32_t LOAD_D(REGTYPE expr) 468 | { 469 | uint32_t result = *(uint32_t *)(vm_mem + expr); 470 | debug("LOAD_D 0x%X = mem[" FMT_REG "]\n", result, expr); 471 | return result; 472 | } 473 | 474 | uint64_t LOAD_Q(REGTYPE expr) 475 | { 476 | uint64_t result = *(uint64_t *)(vm_mem + expr); 477 | debug("LOAD_Q 0x%llX = mem[" FMT_REG "]\n", result, expr); 478 | return result; 479 | } 480 | 481 | __uint128_t LOAD_O(REGTYPE expr) 482 | { 483 | __uint128_t result = *(__uint128_t *)(vm_mem + expr); 484 | debug("LOAD_O 0x%llX%08llX = mem[" FMT_REG "]\n", (uint64_t)(result>>64), (uint64_t)result, expr); 485 | return result; 486 | } 487 | 488 | /* LowLevelILOperation.LLIL_STORE: [("dest", "expr"), ("src", "expr")] */ 489 | void STORE_B(REGTYPE dest, uint8_t src) 490 | { 491 | debug("STORE_B byte[" FMT_REG "] = 0x%02X\n", dest, src); 492 | *(uint8_t *)(vm_mem + dest) = src; 493 | } 494 | 495 | void STORE_W(REGTYPE dest, uint16_t src) 496 | { 497 | debug("STORE_W word[" FMT_REG "] = 0x%04X\n", dest, src); 498 | *(uint16_t *)(vm_mem + dest) = src; 499 | } 500 | 501 | void STORE_D(REGTYPE dest, uint32_t src) 502 | { 503 | debug("STORE_D dword[" FMT_REG "] = 0x%08X\n", dest, src); 504 | *(uint32_t *)(vm_mem + dest) = src; 505 | } 506 | 507 | void STORE_Q(REGTYPE dest, uint64_t src) 508 | { 509 | debug("STORE_Q qword[" FMT_REG "] = 0x%016llX\n", dest, src); 510 | *(uint64_t *)(vm_mem + dest) = src; 511 | } 512 | 513 | /* LowLevelILOperation.LLIL_PUSH: [("src", "expr")] */ 514 | void PUSH_Q(REGTYPE src) 515 | { 516 | /* decrement stack pointer */ 517 | REG_SET_ADDR(stack_reg_name, REG_GET_ADDR(stack_reg_name) - sizeof(REGTYPE)); 518 | /* store on stack */ 519 | ADDRTYPE ea = REG_GET_ADDR(stack_reg_name); 520 | debug_stack("PUSH_Q mem[" FMT_REG "] = " FMT_REG "\n", ea, src); 521 | *(REGTYPE *)(vm_mem + ea) = src; 522 | } 523 | 524 | /* LowLevelILOperation.LLIL_POP: [] */ 525 | REGTYPE POP_Q(void) 526 | { 527 | /* retrieve from stack */ 528 | ADDRTYPE ea = REG_GET_ADDR(stack_reg_name); 529 | REGTYPE val = *(ADDRTYPE *)(vm_mem + ea); 530 | debug_stack("POP_Q " FMT_ADDR " = mem[" FMT_ADDR "]\n", val, ea); 531 | /* increment stack pointer */ 532 | REG_SET_ADDR(stack_reg_name, REG_GET_ADDR(stack_reg_name) + sizeof(REGTYPE)); 533 | return val; 534 | } 535 | 536 | /* LowLevelILOperation.LLIL_REG_STACK_REL: [("stack", "reg_stack"), ("src", "expr")] */ 537 | /* LowLevelILOperation.LLIL_REG_STACK_POP: [("stack", "reg_stack")] */ 538 | /* LowLevelILOperation.LLIL_REG_STACK_FREE_REG: [("dest", "reg")] */ 539 | /* LowLevelILOperation.LLIL_REG_STACK_FREE_REL: [("stack", "reg_stack"), ("dest", "expr")] */ 540 | /* LowLevelILOperation.LLIL_CONST: [("constant", "int")] */ 541 | /* LowLevelILOperation.LLIL_CONST_PTR: [("constant", "int")] */ 542 | /* LowLevelILOperation.LLIL_EXTERN_PTR: [("constant", "int"), ("offset", "int")] */ 543 | SREGTYPE EXTERN_PTR(SREGTYPE constant, SREGTYPE offset) 544 | { 545 | return constant + offset; 546 | } 547 | 548 | /* LowLevelILOperation.LLIL_FLOAT_CONST: [("constant", "float")] */ 549 | uint32_t FLOAT_CONST_D(float input) 550 | { 551 | uint32_t result = *(uint32_t *)&input; 552 | debug("FLOAT_CONST_D 0x%08X (%f)\n", result, input); 553 | return result; 554 | } 555 | 556 | /* LowLevelILOperation.LLIL_FLAG: [("src", "flag")] */ 557 | bool FLAG(string src) 558 | { 559 | bool result = vm_flags[src]; 560 | debug("FLAG %d = vm_flags[%s]\n", result, src.c_str()); 561 | return result; 562 | } 563 | 564 | /* LowLevelILOperation.LLIL_FLAG_BIT: [("src", "flag"), ("bit", "int")] */ 565 | 566 | /* LowLevelILOperation.LLIL_ADD: [("left", "expr"), ("right", "expr")] */ 567 | uint8_t ADD_B(uint8_t left, uint8_t right) 568 | { 569 | uint8_t result = left + right; 570 | debug("ADD_B 0x%02X = 0x%02X + 0x%02X\n", result & 0xFF, left & 0xFF, right & 0xFF); 571 | return result; 572 | } 573 | 574 | uint16_t ADD_W(uint16_t left, uint16_t right) 575 | { 576 | uint16_t result = left + right; 577 | debug("ADD_W 0x%04X = 0x%04X + 0x%04X\n", result & 0xFFFF, left & 0xFFFF, right & 0xFFFF); 578 | return result; 579 | } 580 | 581 | uint32_t ADD_D(uint32_t left, uint32_t right) 582 | { 583 | uint32_t result = left + right; 584 | debug("ADD_D 0x%08X = 0x%08X + 0x%08X\n", result, left, right); 585 | return result; 586 | } 587 | 588 | uint64_t ADD_Q(uint64_t left, uint64_t right) 589 | { 590 | uint64_t result = left + right; 591 | debug("ADD_Q 0x%016llX = 0x%016llX + 0x%016llX\n", result, left, right); 592 | return result; 593 | } 594 | 595 | /* LowLevelILOperation.LLIL_ADC: [("left", "expr"), ("right", "expr"), ("carry", "expr")] */ 596 | SREGTYPE ADC(SREGTYPE left, SREGTYPE right, bool carry) 597 | { 598 | SREGTYPE result = left + right + carry; 599 | debug("ADC " FMT_REG " = " FMT_REG " + " FMT_REG " + %d\n", result, left, right, carry); 600 | return result; 601 | } 602 | 603 | /* LowLevelILOperation.LLIL_SUB: [("left", "expr"), ("right", "expr")] */ 604 | uint8_t SUB_B(uint8_t a, uint8_t b) 605 | { 606 | uint8_t result = a - b; 607 | debug("SUB_B 0x%02X = 0x%02X - 0x%02X\n", result, a, b); 608 | return result; 609 | } 610 | 611 | uint16_t SUB_W(uint16_t a, uint16_t b) 612 | { 613 | uint16_t result = a - b; 614 | debug("SUB_W 0x%04X = 0x%04X - 0x%04X\n", result, a, b); 615 | return result; 616 | } 617 | 618 | uint32_t SUB_D(uint32_t a, uint32_t b) 619 | { 620 | uint32_t result = a - b; 621 | debug("SUB_D 0x%08X = 0x%08X - 0x%08X\n", result, a, b); 622 | return result; 623 | } 624 | 625 | uint64_t SUB_Q(uint64_t a, uint64_t b) 626 | { 627 | uint64_t result = a - b; 628 | debug("SUB_Q 0x%016llX = 0x%016llX - 0x%016llX\n", result, a, b); 629 | return result; 630 | } 631 | 632 | /* LowLevelILOperation.LLIL_SBB: [("left", "expr"), ("right", "expr"), ("carry", "expr")] */ 633 | uint8_t SBB_B(uint8_t a, uint8_t b, uint8_t c) 634 | { 635 | uint8_t result = a - b - c; 636 | debug("SBB1 0x%02X = 0x%02X - 0x%02X - %d\n", result, a, b, c); 637 | return result; 638 | } 639 | 640 | uint16_t SBB_W(uint16_t a, uint16_t b, uint16_t c) 641 | { 642 | uint16_t result = a - b - c; 643 | debug("SBB2 0x%04X = 0x%04X - 0x%04X - %d\n", result, a, b, c); 644 | return result; 645 | } 646 | 647 | uint32_t SBB_D(uint32_t a, uint32_t b, uint32_t c) 648 | { 649 | uint32_t result = a - b - c; 650 | debug("SBB4 0x%08X = 0x%08X - 0x%08X - %d\n", result, a, b, c); 651 | return result; 652 | } 653 | 654 | uint64_t SBB64(uint64_t a, uint64_t b, uint64_t c) 655 | { 656 | uint64_t result = a - b - c; 657 | debug("SBB8 0x%016llX = 0x%016llX - 0x%016llX - %lld\n", result, a, b, c); 658 | return result; 659 | } 660 | 661 | /* LowLevelILOperation.LLIL_AND: [("left", "expr"), ("right", "expr")] */ 662 | uint32_t AND_D(uint32_t left, uint32_t right) 663 | { 664 | uint32_t result = left & right; 665 | debug("AND_D 0x%08X = 0x%08X & 0x%08X\n", result, left, right); 666 | return result; 667 | } 668 | 669 | /* LowLevelILOperation.LLIL_OR: [("left", "expr"), ("right", "expr")] */ 670 | REGTYPE OR(REGTYPE left, REGTYPE right) 671 | { 672 | REGTYPE result = left | right; 673 | debug("OR " FMT_REG " = " FMT_REG " | " FMT_REG "\n", result, left, right); 674 | return result; 675 | } 676 | 677 | /* LowLevelILOperation.LLIL_XOR: [("left", "expr"), ("right", "expr")] */ 678 | REGTYPE XOR(REGTYPE left, REGTYPE right) 679 | { 680 | REGTYPE result = left ^ right; 681 | debug("XOR " FMT_REG " = " FMT_REG " ^ " FMT_REG "\n", result, left, right); 682 | return result; 683 | } 684 | 685 | /* LowLevelILOperation.LLIL_LSL: [("left", "expr"), ("right", "expr")] */ 686 | uint64_t LSL_Q(uint64_t left, uint64_t right) 687 | { 688 | uint64_t result = left << right; 689 | debug("LSL_Q " FMT_REG " = " FMT_REG " << " FMT_REG "\n", result, left, right); 690 | return result; 691 | } 692 | 693 | /* LowLevelILOperation.LLIL_LSR: [("left", "expr"), ("right", "expr")] */ 694 | REGTYPE LSR(REGTYPE left, REGTYPE right) 695 | { 696 | REGTYPE result = left >> right; 697 | debug("LSR " FMT_REG " = " FMT_REG " << " FMT_REG "\n", result, left, right); 698 | return result; 699 | } 700 | 701 | /* LowLevelILOperation.LLIL_ASR: [("left", "expr"), ("right", "expr")] */ 702 | int32_t ASR_D(int32_t left, uint32_t right) 703 | { 704 | int32_t result = left >> right; 705 | debug("ASR_D 0x%08X = 0x%08X >> 0x%08X\n", result, left, right); 706 | return result; 707 | } 708 | 709 | /* LowLevelILOperation.LLIL_ROL: [("left", "expr"), ("right", "expr")] */ 710 | uint8_t ROL_B(uint8_t value, uint8_t amt) 711 | { 712 | amt = amt % 8; 713 | uint8_t result = (value << amt) | (value >> (8-amt)); 714 | debug("ROL1 0x%02X = ROL(0x%02X, %d)\n", result, value, amt); 715 | return result; 716 | } 717 | 718 | uint16_t ROL_W(uint16_t value, uint16_t amt) 719 | { 720 | amt = amt % 16; 721 | uint16_t result = (value << amt) | (value >> (16-amt)); 722 | debug("ROL2 0x%04X = ROL(0x%04X, %d)\n", result, value, amt); 723 | return result; 724 | } 725 | 726 | uint32_t ROL_D(uint32_t value, uint32_t amt) 727 | { 728 | amt = amt % 32; 729 | uint32_t result = (value << amt) | (value >> (8-amt)); 730 | debug("ROL4 0x%08X = ROL(0x%08X, %d)\n", result, value, amt); 731 | return result; 732 | } 733 | 734 | uint64_t ROL64(uint64_t value, uint64_t amt) 735 | { 736 | amt = amt % 64; 737 | uint64_t result = (value << amt) | (value >> (8-amt)); 738 | debug("ROL8 0x%08llX = ROL(0x%016llX, %lld)\n", result, value, amt); 739 | return result; 740 | } 741 | 742 | /* LowLevelILOperation.LLIL_RLC: [("left", "expr"), ("right", "expr"), ("carry", "expr")] */ 743 | uint8_t RLC_B(uint8_t value, uint8_t amt, bool carry) 744 | { 745 | uint8_t result = value; 746 | 747 | if(amt) { 748 | amt = amt % 8; 749 | // normal carry 750 | uint8_t a = (value << amt); 751 | uint8_t b = (value >> (8-amt)); 752 | // insert c 753 | b = (b >> 1) | (carry << (amt-1)); 754 | // 755 | result = a | b; 756 | } 757 | 758 | debug("RLC1 0x%X = 0x%X <<< %d and carry = %d\n", result, value, amt, carry); 759 | return result; 760 | } 761 | 762 | /* LowLevelILOperation.LLIL_ROR: [("left", "expr"), ("right", "expr")] */ 763 | uint8_t ROR_B(uint8_t value, uint8_t amt) 764 | { 765 | amt = amt % 8; 766 | uint8_t result = (value >> amt) | (value << (8-amt)); 767 | debug("ROR1(0x%02X, %d) returns 0x%02X\n", value, amt, result); 768 | return result; 769 | } 770 | 771 | uint16_t ROR_W(uint16_t value, uint16_t amt) 772 | { 773 | amt = amt % 16; 774 | uint16_t result = (value >> amt) | (value << (16-amt)); 775 | debug("ROR16(0x%04X, %d) returns 0x%04X\n", value, amt, result); 776 | return result; 777 | } 778 | 779 | uint32_t ROR_D(uint32_t value, uint32_t amt) 780 | { 781 | amt = amt % 32; 782 | uint32_t result = (value >> amt) | (value << (8-amt)); 783 | debug("ROR32(0x%08X, %d) returns 0x%08X\n", value, amt, result); 784 | return result; 785 | } 786 | 787 | uint64_t ROR64(uint64_t value, uint64_t amt) 788 | { 789 | amt = amt % 64; 790 | uint64_t result = (value >> amt) | (value << (8-amt)); 791 | debug("ROR64(0x%016llX, %lld) returns 0x%016llX\n", value, amt, result); 792 | return result; 793 | } 794 | 795 | /* LowLevelILOperation.LLIL_RRC: [("left", "expr"), ("right", "expr"), ("carry", "expr")] */ 796 | uint8_t RRC_B(uint8_t value, uint8_t amt, bool carry) 797 | { 798 | uint8_t result = value; 799 | 800 | if(amt) { 801 | amt = amt % 8; 802 | // normal carry 803 | uint8_t a = value >> amt; 804 | uint8_t b = value << (8-amt+1); 805 | uint8_t c = value << (8-amt); 806 | result = a | b | c; 807 | } 808 | 809 | debug("RRC8 0x%X = 0x%X >>> %d and carry = %d\n", result, value, amt, carry); 810 | return result; 811 | } 812 | 813 | int32_t MUL_D(int32_t left, int32_t right) 814 | { 815 | int32_t result = left * right; 816 | debug("MUL_D 0x%08X = 0x%08X & 0x%08X\n", result, left, right); 817 | return result; 818 | } 819 | 820 | /* LowLevelILOperation.LLIL_MULU_DP: [("left", "expr"), ("right", "expr")] */ 821 | /* LowLevelILOperation.LLIL_MULS_DP: [("left", "expr"), ("right", "expr")] */ 822 | /* LowLevelILOperation.LLIL_DIVU: [("left", "expr"), ("right", "expr")] */ 823 | /* LowLevelILOperation.LLIL_DIVU_DP: [("left", "expr"), ("right", "expr")] */ 824 | 825 | /* LowLevelILOperation.LLIL_DIVS: [("left", "expr"), ("right", "expr")] */ 826 | uint32_t DIVS_D(uint32_t left, uint32_t right) 827 | { 828 | int32_t ai = *(int32_t *)&left; 829 | int32_t bi = *(int32_t *)&right; 830 | int32_t ci = ai / bi; 831 | uint32_t result = *(uint32_t *)&ci; 832 | debug("DIVS_D 0x%08X (%d) = 0x%08X (%d) / 0x%08X (%d)\n", result, ci, left, ai, right, bi); 833 | return result; 834 | } 835 | 836 | /* LowLevelILOperation.LLIL_DIVS_DP: [("left", "expr"), ("right", "expr")] */ 837 | // TODO: figure out "DP" 838 | SREGTYPE DIVS_DP(SREGTYPE left, SREGTYPE_HALF right) 839 | { 840 | SREGTYPE result = left / right; 841 | debug("DIVS_DP " FMT_SREG " = " FMT_SREG " / " FMT_REG_HALF "\n", result, left, right); 842 | return result; 843 | } 844 | 845 | /* LowLevelILOperation.LLIL_MODU: [("left", "expr"), ("right", "expr")] */ 846 | REGTYPE MODU(REGTYPE left, REGTYPE right) 847 | { 848 | REGTYPE result = left % right; 849 | debug("MODU " FMT_REG " = " FMT_REG " %% " FMT_REG "\n", result, left, right); 850 | return result; 851 | } 852 | 853 | /* LowLevelILOperation.LLIL_MODU_DP: [("left", "expr"), ("right", "expr")] */ 854 | // TODO: figure out what DP's supposed to do different 855 | REGTYPE MODU_DP(REGTYPE left, REGTYPE right) 856 | { 857 | REGTYPE result = left % right; 858 | debug("MODU_DP " FMT_REG " = " FMT_REG " %% " FMT_REG "\n", result, left, right); 859 | return result; 860 | } 861 | 862 | /* LowLevelILOperation.LLIL_MODS: [("left", "expr"), ("right", "expr")] */ 863 | SREGTYPE MODS(SREGTYPE left, SREGTYPE right) 864 | { 865 | SREGTYPE result = left % right; 866 | debug("MODS " FMT_SREG " = " FMT_SREG " %% " FMT_SREG "\n", result, left, right); 867 | return result; 868 | } 869 | 870 | /* LowLevelILOperation.LLIL_MODS_DP: [("left", "expr"), ("right", "expr")] */ 871 | // TODO: figure out what DP's supposed to do different 872 | SREGTYPE MODS_DP(SREGTYPE left, SREGTYPE right) 873 | { 874 | SREGTYPE result = left % right; 875 | debug("MODS_DP " FMT_SREG " = " FMT_SREG " %% " FMT_SREG "\n", result, left, right); 876 | return result; 877 | } 878 | 879 | /* LowLevelILOperation.LLIL_NEG: [("src", "expr")] */ 880 | uint8_t NEG_B(uint8_t src) 881 | { 882 | uint8_t result = (src ^ 0xFF) + 1; 883 | debug("NEG8 0x%02X = neg(0x%02X)\n", result, src); 884 | return result; 885 | } 886 | 887 | uint16_t NEG_W(uint16_t src) 888 | { 889 | uint16_t result = (src ^ 0xFFFF) + 1; 890 | debug("NEG16 0x%04X = neg(0x%04X)\n", result, src); 891 | return result; 892 | } 893 | 894 | uint32_t NEG_D(uint32_t src) 895 | { 896 | uint32_t result = (src ^ 0xFFFFFFFF) + 1; 897 | debug("NEG32 0x%08X = neg(0x%08X)\n", result, src); 898 | return result; 899 | } 900 | 901 | uint64_t NEG64(uint64_t src) 902 | { 903 | uint64_t result = (src ^ 0xFFFFFFFFFFFFFFFF) + 1; 904 | debug("NEG64 0x%016llX = neg(0x%016llX)\n", result, src); 905 | return result; 906 | } 907 | 908 | /* LowLevelILOperation.LLIL_NOT: [("src", "expr")] */ 909 | uint8_t NOT0(uint8_t left) 910 | { 911 | /* size 0 is special case which means treat as bool 912 | nonzero -> zero 913 | zero -> 1 914 | */ 915 | uint8_t result = !!(left); 916 | debug("NOT0 0x%02X = 0x%02X ^ 1\n", result, left); 917 | return result; 918 | } 919 | 920 | uint8_t NOT_B(uint8_t left) 921 | { 922 | uint8_t result = ~left; 923 | debug("NOT8 0x%02X = ~0x%02X\n", result, left); 924 | return result; 925 | } 926 | 927 | uint16_t NOT_W(uint16_t left) 928 | { 929 | uint16_t result = ~left; 930 | debug("NOT16 0x%04X = ~0x%04X\n", result, left); 931 | return result; 932 | } 933 | 934 | uint32_t NOT_D(uint32_t left) 935 | { 936 | uint32_t result = ~left; 937 | debug("NOT32 0x%08X = ~0x%08X\n", result, left); 938 | return result; 939 | } 940 | 941 | uint64_t NOT64(uint64_t left) 942 | { 943 | uint64_t result = ~left; 944 | debug("NOT64 0x%016llX = ~0x%016llX\n", result, left); 945 | return result; 946 | } 947 | 948 | /* LowLevelILOperation.LLIL_SX: [("src", "expr")] */ 949 | 950 | /* sign extend a byte to a word */ 951 | int16_t SX_W_b(int8_t src) 952 | { 953 | uint16_t result = (src & 0x80) ? 0xFF00 | src : src; 954 | debug("SX_W 0x%02X -> 0x%04X\n", src, result); 955 | return result; 956 | } 957 | 958 | /* sign extend a byte to a double word */ 959 | int32_t SX_D_b(int8_t src) 960 | { 961 | uint32_t result = (src & 0x80) ? 0xFFFFFF00 | src : src; 962 | debug("SX_D 0x%02X -> 0x%08X\n", src, result); 963 | return result; 964 | } 965 | 966 | /* sign extend a word to a double word */ 967 | int32_t SX_D_w(int16_t src) 968 | { 969 | int32_t result = (src & 0x8000) ? 0xFFFF0000 | src : src; 970 | debug("SX_D 0x%04X -> 0x%08X\n", src, result); 971 | return result; 972 | } 973 | 974 | /* sign extend a byte to a quad word */ 975 | int64_t SX_Q_b(int8_t src) 976 | { 977 | int64_t result = (src & 0x80) ? 0xFFFFFFFFFFFFFF00 | src : src; 978 | debug("SX_Q %02X -> 0x%016llX\n", src, result); 979 | return result; 980 | } 981 | 982 | /* sign extend a word to a quad word */ 983 | int64_t SX_Q_w(int16_t src) 984 | { 985 | int64_t result = (src & 0x8000) ? 0xFFFFFFFFFFFF0000 | src : src; 986 | debug("SX_Q %04X -> 0x%016llX\n", src, result); 987 | return result; 988 | } 989 | 990 | /* sign extend a double word to a quad word */ 991 | int64_t SX_Q_d(int32_t src) 992 | { 993 | int64_t result = (src & 0x80000000) ? 0xFFFFFFFF00000000 | src : src; 994 | debug("SX_Q %08X -> 0x%016llX\n", src, result); 995 | return result; 996 | } 997 | 998 | /* LowLevelILOperation.LLIL_TRAP: [("vector", "int")] */ 999 | void TRAP(int32_t src) 1000 | { 1001 | debug("TRAP 0n%d, 0x%X", src, src); 1002 | } 1003 | 1004 | /* LowLevelILOperation.LLIL_ZX: [("src", "expr")] */ 1005 | uint32_t ZX_D(uint32_t src) 1006 | { 1007 | uint32_t result = src; 1008 | debug("ZX_D 0x%08X -> 0x%08X\n", src, result); 1009 | return result; 1010 | } 1011 | 1012 | uint64_t ZX_Q(uint64_t src) 1013 | { 1014 | uint64_t result = src; 1015 | debug("ZX_Q 0x%016llX -> 0x%016llX\n", src, result); 1016 | return result; 1017 | } 1018 | 1019 | __uint128_t ZX_O(__uint128_t src) 1020 | { 1021 | __uint128_t result = src; 1022 | debug("ZX_O 0x%016llX%016llX -> 0x%016llX%016llX\n", (uint64_t)(src>>64), (uint64_t)src, (uint64_t)(result>>64), (uint64_t)result); 1023 | return result; 1024 | } 1025 | 1026 | /* LowLevelILOperation.LLIL_LOW_PART: [("src", "expr")] */ 1027 | uint8_t LOW_PART_B(REGTYPE left) 1028 | { 1029 | uint8_t result = left & 0xFF; 1030 | debug("LOW_PART_B " FMT_REG " -> 0x%02X\n", left, result); 1031 | return result; 1032 | } 1033 | 1034 | uint16_t LOW_PART_W(REGTYPE left) 1035 | { 1036 | uint16_t result = left & 0xFFFF; 1037 | debug("LOW_PART_W " FMT_REG " -> 0x%04X\n", left, result); 1038 | return result; 1039 | } 1040 | 1041 | uint32_t LOW_PART_D(REGTYPE left) 1042 | { 1043 | uint32_t result = left & 0xFFFFFFFF; 1044 | debug("LOW_PART_D " FMT_REG " -> 0x%08X\n", left, result); 1045 | return result; 1046 | } 1047 | 1048 | uint64_t LOW_PART_Q(REGTYPE left) 1049 | { 1050 | uint64_t result = left & 0xFFFFFFFFFFFFFFFF; 1051 | debug("LOW_PART_Q " FMT_REG " -> 0x%016llX\n", left, result); 1052 | return result; 1053 | } 1054 | 1055 | /* LowLevelILOperation.LLIL_JUMP: [("dest", "expr")] */ 1056 | RETURN_ACTION JUMP(REGTYPE dest) 1057 | { 1058 | if(dest == RETURN_ADDRESS_CANARY) 1059 | return RETURN_TRUE; 1060 | 1061 | printf("ERROR: JUMP to " FMT_REG " is out of LLIL land, something went wrong in transpilation\n", dest); 1062 | exit(-1); 1063 | return RETURN_FALSE; 1064 | } 1065 | 1066 | /* LowLevelILOperation.LLIL_JUMP_TO: [("dest", "expr"), ("targets", "int_list")] */ 1067 | /* LowLevelILOperation.LLIL_CALL: [("dest", "expr")] */ 1068 | void CALL(REGTYPE dest, void (*pfunc)(void), const char *func_name) 1069 | { 1070 | if(is_link_reg_arch) { 1071 | /* this is a link register style of architecture, so set the LR */ 1072 | REG_SET_ADDR(link_reg_name, RETURN_ADDRESS_CANARY); 1073 | debug_set("SET %s = " FMT_REG "\n", link_reg_name.c_str(), RETURN_ADDRESS_CANARY); 1074 | } 1075 | else { 1076 | /* this is a push-the-return-address style of architecture 1077 | so push a dummy return address */ 1078 | REG_SET_ADDR(stack_reg_name, REG_GET_ADDR(stack_reg_name) - sizeof(ADDRTYPE)); 1079 | 1080 | *(ADDRTYPE *)(vm_mem + REG_GET_ADDR(stack_reg_name)) = RETURN_ADDRESS_CANARY; 1081 | 1082 | debug_stack("CALL " FMT_REG " mem[" FMT_REG "] = " FMT_REG " %s()\n", 1083 | dest, REG_GET_ADDR(stack_reg_name), RETURN_ADDRESS_CANARY, func_name); 1084 | } 1085 | 1086 | return pfunc(); 1087 | } 1088 | 1089 | /* LowLevelILOperation.LLIL_CALL_STACK_ADJUST: [("dest", "expr"), ("stack_adjustment", "int"), ("reg_stack_adjustments", "reg_stack_adjust")] */ 1090 | /* LowLevelILOperation.LLIL_TAILCALL: [("dest", "expr")] */ 1091 | 1092 | void TAILCALL(REGTYPE dest, void (*pfunc)(void), const char *func_name) 1093 | { 1094 | /* dummy push of return address */ 1095 | debug_stack("TAILCALL " FMT_REG " %s()\n", dest, func_name); 1096 | 1097 | return pfunc(); 1098 | } 1099 | 1100 | /* LowLevelILOperation.LLIL_RET: [("dest", "expr")] */ 1101 | void RET(REGTYPE dest) 1102 | { 1103 | /* IL semantics of RET are _not_ necessarily to pop and jump (but can be) 1104 | an x86 style ret will be RET(POP()) 1105 | an arm style ret might be RET(REG("lr")) */ 1106 | 1107 | // DO NOT: 1108 | // vm_regs[stack_reg_name] += sizeof(REGTYPE); 1109 | debug_stack("RET " FMT_REG "\n", dest); 1110 | } 1111 | 1112 | /* LowLevelILOperation.LLIL_NORET: [] */ 1113 | /* LowLevelILOperation.LLIL_IF: [("condition", "expr"), ("true", "int"), ("false", "int")] */ 1114 | /* LowLevelILOperation.LLIL_GOTO: [("dest", "int")] */ 1115 | /* LowLevelILOperation.LLIL_FLAG_COND: [("condition", "cond"), ("semantic_class", "sem_class")] */ 1116 | /* LowLevelILOperation.LLIL_FLAG_GROUP: [("semantic_group", "sem_group")] */ 1117 | /* LowLevelILOperation.LLIL_CMP_E: [("left", "expr"), ("right", "expr")] */ 1118 | bool CMP_E_D(uint32_t left, uint32_t right) 1119 | { 1120 | bool result = left == right; 1121 | debug("CMP_E_D %d = (0x%08X == 0x%08X)\n", result, left, right); 1122 | return result; 1123 | } 1124 | 1125 | /* LowLevelILOperation.LLIL_CMP_NE: [("left", "expr"), ("right", "expr")] */ 1126 | bool CMP_NE_D(uint32_t left, uint32_t right) 1127 | { 1128 | bool result = left != right; 1129 | debug("CMP_NE_D %d = (0x%08X != 0x%08X)\n", result, left, right); 1130 | return result; 1131 | } 1132 | 1133 | /* LowLevelILOperation.LLIL_CMP_SLT: [("left", "expr"), ("right", "expr")] */ 1134 | bool CMP_SLT_B(int8_t left, int8_t right) 1135 | { 1136 | bool result = left < right; 1137 | debug("CMP_SLT8 %d = (%d < %d)\n", result, left, right); 1138 | return result; 1139 | } 1140 | 1141 | bool CMP_SLT_W(int16_t left, int16_t right) 1142 | { 1143 | bool result = left < right; 1144 | debug("CMP_SLT16 %d = (%d < %d)\n", result, left, right); 1145 | return result; 1146 | } 1147 | 1148 | bool CMP_SLT_D(int32_t left, int32_t right) 1149 | { 1150 | bool result = left < right; 1151 | debug("CMP_SLT32 %d = (%d < %d)\n", result, left, right); 1152 | return result; 1153 | } 1154 | 1155 | /* LowLevelILOperation.LLIL_CMP_ULT: [("left", "expr"), ("right", "expr")] */ 1156 | bool CMP_ULT(REGTYPE left, REGTYPE right) 1157 | { 1158 | bool result = left < right; 1159 | debug("CMP_ULT %d = " FMT_REG " < " FMT_REG "\n", result, left, right); 1160 | return result; 1161 | } 1162 | 1163 | /* LowLevelILOperation.LLIL_CMP_SLE: [("left", "expr"), ("right", "expr")] */ 1164 | bool CMP_SLE_B(int8_t left, int8_t right) 1165 | { 1166 | bool result = left <= right; 1167 | debug("CMP_SLE_B %d = %d <= %d\n", result, left, right); 1168 | return result; 1169 | } 1170 | 1171 | bool CMP_SLE_W(int16_t left, int16_t right) 1172 | { 1173 | bool result = left <= right; 1174 | debug("CMP_SLE_W %d = %d <= %d\n", result, left, right); 1175 | return result; 1176 | } 1177 | 1178 | bool CMP_SLE_D(int32_t left, int32_t right) 1179 | { 1180 | bool result = left <= right; 1181 | debug("CMP_SLE_D %d = %d <= %d\n", result, left, right); 1182 | return result; 1183 | } 1184 | 1185 | /* LowLevelILOperation.LLIL_CMP_ULE: [("left", "expr"), ("right", "expr")] */ 1186 | bool CMP_ULE(REGTYPE left, REGTYPE right) 1187 | { 1188 | bool result = left <= right; 1189 | debug("CMP_ULE %d = " FMT_REG " <= " FMT_REG "\n", result, left, right); 1190 | return result; 1191 | } 1192 | 1193 | /* LowLevelILOperation.LLIL_CMP_SGE: [("left", "expr"), ("right", "expr")] */ 1194 | bool CMP_SGE_B(int8_t left, int8_t right) 1195 | { 1196 | bool result = left >= right; 1197 | debug("CMP_SGE_B %d = %d >= %d\n", result, left, right); 1198 | return result; 1199 | } 1200 | 1201 | bool CMP_SGE_W(int16_t left, int16_t right) 1202 | { 1203 | bool result = left >= right; 1204 | debug("CMP_SGE_W %d = %d >= %d\n", result, left, right); 1205 | return result; 1206 | } 1207 | 1208 | bool CMP_SGE_D(int32_t left, int32_t right) 1209 | { 1210 | bool result = left >= right; 1211 | debug("CMP_SGE_D %d = %d >= %d\n", result, left, right); 1212 | return result; 1213 | } 1214 | 1215 | /* LowLevelILOperation.LLIL_CMP_UGE: [("left", "expr"), ("right", "expr")] */ 1216 | bool CMP_UGE(REGTYPE left, REGTYPE right) 1217 | { 1218 | bool result = left >= right; 1219 | debug("CMP_UGE %d = " FMT_REG " >= " FMT_REG "\n", result, left, right); 1220 | return result; 1221 | } 1222 | 1223 | /* LowLevelILOperation.LLIL_CMP_SGT: [("left", "expr"), ("right", "expr")] */ 1224 | bool CMP_SGT_B(int8_t left, int8_t right) 1225 | { 1226 | bool result = left > right; 1227 | debug("CMP_SGT_B %d = %d > %d\n", result, left, right); 1228 | return result; 1229 | } 1230 | 1231 | bool CMP_SGT_W(int16_t left, int16_t right) 1232 | { 1233 | bool result = left > right; 1234 | debug("CMP_SGT_W %d = %d > %d\n", result, left, right); 1235 | return result; 1236 | } 1237 | 1238 | bool CMP_SGT_D(int32_t left, int32_t right) 1239 | { 1240 | bool result = left > right; 1241 | debug("CMP_SGT_D %d = %d > %d\n", result, left, right); 1242 | return result; 1243 | } 1244 | 1245 | /* LowLevelILOperation.LLIL_CMP_UGT: [("left", "expr"), ("right", "expr")] */ 1246 | bool CMP_UGT_Q(uint64_t left, uint64_t right) 1247 | { 1248 | bool result = left > right; 1249 | debug("CMP_UGT_Q %d = " FMT_REG " > " FMT_REG "\n", result, left, right); 1250 | return result; 1251 | } 1252 | 1253 | /* LowLevelILOperation.LLIL_TEST_BIT: [("left", "expr"), ("right", "expr")] */ 1254 | bool TEST_BIT(REGTYPE value, REGTYPE mask) 1255 | { 1256 | bool result = !!(value & mask); 1257 | debug("TEST_BIT %d = bool(" FMT_REG " & " FMT_REG ")\n", result, value, mask); 1258 | return result; 1259 | } 1260 | 1261 | /* LowLevelILOperation.LLIL_BOOL_TO_INT: [("src", "expr")] */ 1262 | /* LowLevelILOperation.LLIL_ADD_OVERFLOW: [("left", "expr"), ("right", "expr")] */ 1263 | bool ADD_OVERFLOW_B(uint8_t a, uint8_t b) 1264 | { 1265 | bool result = a >= 256 - b; 1266 | debug("ADD_OVERFLOW_B %d (when %d + %d)\n", result, a, b); 1267 | return result; 1268 | } 1269 | 1270 | bool ADD_OVERFLOW_W(uint16_t a, uint16_t b) 1271 | { 1272 | bool result = a >= 65536 - b; 1273 | debug("ADD_OVERFLOW_W %d (when %d + %d)\n", result, a, b); 1274 | return result; 1275 | } 1276 | 1277 | bool ADD_OVERFLOW_D(uint32_t a, uint32_t b) 1278 | { 1279 | bool result = a >= 4294967296 - b; 1280 | debug("ADD_OVERFLOW_D %d (when %d + %d)\n", result, a, b); 1281 | return result; 1282 | } 1283 | 1284 | /* LowLevelILOperation.LLIL_SYSCALL: [] */ 1285 | /* LowLevelILOperation.LLIL_INTRINSIC: [("output", "reg_or_flag_list"), ("intrinsic", "intrinsic"), ("param", "expr")] */ 1286 | /* LowLevelILOperation.LLIL_INTRINSIC_SSA: [("output", "reg_or_flag_ssa_list"), ("intrinsic", "intrinsic"), ("param", "expr")] */ 1287 | /* LowLevelILOperation.LLIL_BP: [] */ 1288 | /* LowLevelILOperation.LLIL_TRAP: [("vector", "int")] */ 1289 | /* LowLevelILOperation.LLIL_UNDEF: [] */ 1290 | 1291 | /* LowLevelILOperation.LLIL_UNIMPL: [] */ 1292 | REGTYPE UNIMPL() 1293 | { 1294 | debug("UNIMPL"); 1295 | exit(-1); 1296 | return 0; 1297 | } 1298 | 1299 | REGTYPE UNIMPL(REGTYPE) 1300 | { 1301 | debug("UNIMPL"); 1302 | return 0; 1303 | } 1304 | 1305 | /* LowLevelILOperation.LLIL_UNIMPL_MEM: [("src", "expr")] */ 1306 | 1307 | /* LowLevelILOperation.LLIL_FADD: [("left", "expr"), ("right", "expr")] */ 1308 | 1309 | /* floating point add, single precision */ 1310 | uint32_t FADD_S(uint32_t a, uint32_t b) 1311 | { 1312 | float af = *(float *)&a; 1313 | float bf = *(float *)&b; 1314 | float cf = af + bf; 1315 | debug("FADD_S %f = %f + %f\n", cf, af, bf); 1316 | return *(uint32_t *)&cf; 1317 | } 1318 | 1319 | /* floating point add, double precision */ 1320 | uint64_t FADD_D(uint64_t a, uint64_t b) 1321 | { 1322 | double af = *(double *)&a; 1323 | double bf = *(double *)&b; 1324 | double cf = af + bf; 1325 | debug("FADD_D %f = %f + %f\n", cf, af, bf); 1326 | return *(uint64_t *)&cf; 1327 | } 1328 | 1329 | /* LowLevelILOperation.LLIL_FSUB: [("left", "expr"), ("right", "expr")] */ 1330 | 1331 | /* floating point subtract, single precision */ 1332 | uint32_t FSUB_S(uint32_t a, uint32_t b) 1333 | { 1334 | float af = *(float *)&a; 1335 | float bf = *(float *)&b; 1336 | float cf = af - bf; 1337 | debug("FSUB_S %f = %f - %f\n", cf, af, bf); 1338 | return *(uint32_t *)&cf; 1339 | } 1340 | 1341 | /* LowLevelILOperation.LLIL_FMUL: [("left", "expr"), ("right", "expr")] */ 1342 | 1343 | /* floating point multiplication, single precision */ 1344 | uint32_t FMUL_S(uint32_t a, uint32_t b) 1345 | { 1346 | float af = *(float *)&a; 1347 | float bf = *(float *)&b; 1348 | float cf = af * bf; 1349 | debug("FMUL_D %f = %f * %f\n", cf, af, bf); 1350 | return *(uint32_t *)&cf; 1351 | } 1352 | 1353 | /* floating point multiplication, double precision */ 1354 | uint64_t FMUL_D(uint64_t a, uint64_t b) 1355 | { 1356 | double af = *(double *)&a; 1357 | double bf = *(double *)&b; 1358 | double cf = af * bf; 1359 | debug("FMUL_Q %f = %f * %f\n", cf, af, bf); 1360 | return *(uint64_t *)&cf; 1361 | } 1362 | 1363 | /* LowLevelILOperation.LLIL_FDIV: [("left", "expr"), ("right", "expr")] */ 1364 | uint32_t FDIV_S(uint32_t a, uint32_t b) 1365 | { 1366 | float af = *(float *)&a; 1367 | float bf = *(float *)&b; 1368 | float cf = af / bf; 1369 | debug("FDIV_S %f = %f / %f\n", cf, af, bf); 1370 | return *(uint32_t *)&cf; 1371 | } 1372 | 1373 | uint64_t FDIV_D(uint64_t a, uint64_t b) 1374 | { 1375 | double af = *(double *)&a; 1376 | double bf = *(double *)&b; 1377 | double cf = af / bf; 1378 | debug("FDIV_D %f = %f / %f\n", cf, af, bf); 1379 | return *(uint64_t *)&cf; 1380 | } 1381 | 1382 | /* LowLevelILOperation.LLIL_FSQRT: [("src", "expr")] */ 1383 | /* LowLevelILOperation.LLIL_FNEG: [("src", "expr")] */ 1384 | /* LowLevelILOperation.LLIL_FABS: [("src", "expr")] */ 1385 | /* LowLevelILOperation.LLIL_FLOAT_TO_INT: [("src", "expr")] */ 1386 | /* LowLevelILOperation.LLIL_INT_TO_FLOAT: [("src", "expr")] */ 1387 | 1388 | /* LowLevelILOperation.LLIL_FLOAT_CONV: [("src", "expr")] */ 1389 | 1390 | /* convert a double precision float to single precision */ 1391 | uint32_t FLOAT_CONV_S(uint64_t input) 1392 | { 1393 | double input_f = *(double *)&input; 1394 | float output_f = input_f; 1395 | uint32_t output = *(uint32_t *)&output_f; 1396 | debug("FLOAT_CONV_S 0x%08X (%f) = 0x%016llX (%f)\n", output, output_f, input, input_f); 1397 | return output; 1398 | } 1399 | 1400 | /* convert a single precision float to double precision */ 1401 | uint32_t FLOAT_CONV_D(uint64_t input) 1402 | { 1403 | double input_f = *(double *)&input; 1404 | float output_f = input_f; 1405 | uint32_t output = *(uint32_t *)&output_f; 1406 | debug("FLOAT_CONV_D 0x%08X (%f) = 0x%016llX (%f)\n", output, output_f, input, input_f); 1407 | return output; 1408 | } 1409 | 1410 | /* LowLevelILOperation.LLIL_ROUND_TO_INT: [("src", "expr")] */ 1411 | /* LowLevelILOperation.LLIL_FLOOR: [("src", "expr")] */ 1412 | /* LowLevelILOperation.LLIL_CEIL: [("src", "expr")] */ 1413 | /* LowLevelILOperation.LLIL_FTRUNC: [("src", "expr")] */ 1414 | /* LowLevelILOperation.LLIL_FCMP_E: [("left", "expr"), ("right", "expr")] */ 1415 | /* LowLevelILOperation.LLIL_FCMP_NE: [("left", "expr"), ("right", "expr")] */ 1416 | /* LowLevelILOperation.LLIL_FCMP_LT: [("left", "expr"), ("right", "expr")] */ 1417 | /* LowLevelILOperation.LLIL_FCMP_LE: [("left", "expr"), ("right", "expr")] */ 1418 | /* LowLevelILOperation.LLIL_FCMP_GE: [("left", "expr"), ("right", "expr")] */ 1419 | /* LowLevelILOperation.LLIL_FCMP_GT: [("left", "expr"), ("right", "expr")] */ 1420 | /* LowLevelILOperation.LLIL_FCMP_O: [("left", "expr"), ("right", "expr")] */ 1421 | /* LowLevelILOperation.LLIL_FCMP_UO: [("left", "expr"), ("right", "expr")] */ 1422 | 1423 | bool FCMP_E_D(double left, double right) 1424 | { 1425 | bool result = left == right; 1426 | debug("FCMP_E32_D %d = %f == %f\n", result, left, right); 1427 | return result; 1428 | } 1429 | 1430 | bool FCMP_NE_D(double left, double right) 1431 | { 1432 | bool result = left != right; 1433 | debug("FCMP_NE32_D %d = %f != %f\n", result, left, right); 1434 | return result; 1435 | } 1436 | 1437 | bool FCMP_GE_D(double left, double right) 1438 | { 1439 | bool result = left >= right; 1440 | debug("FCMP_GE32_D %d = %f >= %f\n", result, left, right); 1441 | return result; 1442 | } 1443 | 1444 | bool FCMP_LE_D(double left, double right) 1445 | { 1446 | bool result = left <= right; 1447 | debug("FCMP_GE32_D %d = %f <= %f\n", result, left, right); 1448 | return result; 1449 | } 1450 | 1451 | bool FCMP_UO_D(double left, double right) 1452 | { 1453 | bool result = !(isnan(left) || isnan(right)); 1454 | debug("FCMP_UO32_D %d = %f <= %f\n", result, left, right); 1455 | return result; 1456 | } 1457 | 1458 | /* LowLevelILOperation.LLIL_SET_REG_SSA: [("dest", "reg_ssa"), ("src", "expr")] */ 1459 | /* LowLevelILOperation.LLIL_SET_REG_SSA_PARTIAL: [("full_reg", "reg_ssa"), ("dest", "reg"), ("src", "expr")] */ 1460 | /* LowLevelILOperation.LLIL_SET_REG_SPLIT_SSA: [("hi", "expr"), ("lo", "expr"), ("src", "expr")] */ 1461 | /* LowLevelILOperation.LLIL_SET_REG_STACK_REL_SSA: [("stack", "expr"), ("dest", "expr"), ("top", "expr"), ("src", "expr")] */ 1462 | /* LowLevelILOperation.LLIL_SET_REG_STACK_ABS_SSA: [("stack", "expr"), ("dest", "reg"), ("src", "expr")] */ 1463 | /* LowLevelILOperation.LLIL_REG_SPLIT_DEST_SSA: [("dest", "reg_ssa")] */ 1464 | /* LowLevelILOperation.LLIL_REG_STACK_DEST_SSA: [("src", "reg_stack_ssa_dest_and_src")] */ 1465 | /* LowLevelILOperation.LLIL_REG_SSA: [("src", "reg_ssa")] */ 1466 | /* LowLevelILOperation.LLIL_REG_SSA_PARTIAL: [("full_reg", "reg_ssa"), ("src", "reg")] */ 1467 | /* LowLevelILOperation.LLIL_REG_SPLIT_SSA: [("hi", "reg_ssa"), ("lo", "reg_ssa")] */ 1468 | /* LowLevelILOperation.LLIL_REG_STACK_REL_SSA: [("stack", "reg_stack_ssa"), ("src", "expr"), ("top", "expr")] */ 1469 | /* LowLevelILOperation.LLIL_REG_STACK_ABS_SSA: [("stack", "reg_stack_ssa"), ("src", "reg")] */ 1470 | /* LowLevelILOperation.LLIL_REG_STACK_FREE_REL_SSA: [("stack", "expr"), ("dest", "expr"), ("top", "expr")] */ 1471 | /* LowLevelILOperation.LLIL_REG_STACK_FREE_ABS_SSA: [("stack", "expr"), ("dest", "reg")] */ 1472 | /* LowLevelILOperation.LLIL_SET_FLAG_SSA: [("dest", "flag_ssa"), ("src", "expr")] */ 1473 | /* LowLevelILOperation.LLIL_FLAG_SSA: [("src", "flag_ssa")] */ 1474 | /* LowLevelILOperation.LLIL_FLAG_BIT_SSA: [("src", "flag_ssa"), ("bit", "int")] */ 1475 | /* LowLevelILOperation.LLIL_CALL_SSA: [("output", "expr"), ("dest", "expr"), ("stack", "expr"), ("param", "expr")] */ 1476 | /* LowLevelILOperation.LLIL_SYSCALL_SSA: [("output", "expr"), ("stack", "expr"), ("param", "expr")] */ 1477 | /* LowLevelILOperation.LLIL_TAILCALL_SSA: [("output", "expr"), ("dest", "expr"), ("stack", "expr"), ("param", "expr")] */ 1478 | /* LowLevelILOperation.LLIL_CALL_OUTPUT_SSA: [("dest_memory", "int"), ("dest", "reg_ssa_list")] */ 1479 | /* LowLevelILOperation.LLIL_CALL_STACK_SSA: [("src", "reg_ssa"), ("src_memory", "int")] */ 1480 | /* LowLevelILOperation.LLIL_CALL_PARAM: [("src", "expr_list")] */ 1481 | /* LowLevelILOperation.LLIL_LOAD_SSA: [("src", "expr"), ("src_memory", "int")] */ 1482 | /* LowLevelILOperation.LLIL_STORE_SSA: [("dest", "expr"), ("dest_memory", "int"), ("src_memory", "int"), ("src", "expr")] */ 1483 | /* LowLevelILOperation.LLIL_REG_PHI: [("dest", "reg_ssa"), ("src", "reg_ssa_list")] */ 1484 | /* LowLevelILOperation.LLIL_REG_STACK_PHI: [("dest", "reg_stack_ssa"), ("src", "reg_stack_ssa_list")] */ 1485 | /* LowLevelILOperation.LLIL_FLAG_PHI: [("dest", "flag_ssa"), ("src", "flag_ssa_list")] */ 1486 | /* LowLevelILOperation.LLIL_MEM_PHI: [("dest_memory", "int"), ("src_memory", "int_list")] */ 1487 | 1488 | void runtime_comment(const char *msg) 1489 | { 1490 | #if defined(DEBUG_RUNTIME_ALL) || defined(DEBUG_RUNTIME_SETS) 1491 | //printf("\x1B[36m%s\x1B[0m", msg); 1492 | printf("\n%s", msg); 1493 | printf("----------------\n"); 1494 | #endif 1495 | } 1496 | 1497 | #ifdef ARCH_ARM 1498 | void __aeabi_idiv() 1499 | { 1500 | SREGTYPE a = reg_get_uint32("r0"); 1501 | SREGTYPE b = reg_get_uint32("r1"); 1502 | SREGTYPE result = a / b; 1503 | REG_SET_ADDR("r0", result); 1504 | debug("__aeabi_idiv() returns " FMT_SREG " = " FMT_SREG " / " FMT_SREG "\n", result, a, b); 1505 | } 1506 | 1507 | void __aeabi_idivmod() 1508 | { 1509 | SREGTYPE a = reg_get_uint32("r0"); 1510 | SREGTYPE b = reg_get_uint32("r1"); 1511 | SREGTYPE q = a / b; 1512 | SREGTYPE r = a % b; 1513 | REG_SET_ADDR("r0", q); 1514 | REG_SET_ADDR("r1", r); 1515 | debug("__aeabi_idivmod() returns q=" FMT_SREG " r=" FMT_SREG " " FMT_SREG " %% " FMT_SREG "\n", 1516 | q, r, a, b); 1517 | } 1518 | #endif 1519 | -------------------------------------------------------------------------------- /runtime.h: -------------------------------------------------------------------------------- 1 | #define VM_MEM_SZ (16*1024) 2 | 3 | #ifdef ARCH_32BIT 4 | #define RETURN_ADDRESS_CANARY (uint32_t)0x00C41132 /* "CALLER" */ 5 | #endif 6 | 7 | #ifdef ARCH_64BIT 8 | #define RETURN_ADDRESS_CANARY (uint64_t)0x00C4113200C41132 /* "CALLERCALLER" */ 9 | #endif 10 | 11 | #ifdef ARCH_64BIT 12 | #define REGWIDTH 64 13 | #define REGTYPE uint64_t /* register type */ 14 | #define ADDRTYPE REGTYPE 15 | #define SREGTYPE int64_t /* signed register type */ 16 | #define REGTYPE_HALF uint32_t /* half register type */ 17 | #define SREGTYPE_HALF int32_t 18 | #define REG_GET_ADDR reg_get_uint64 19 | #define REG_SET_ADDR reg_set_uint64 20 | #endif 21 | 22 | #ifdef ARCH_32BIT 23 | #define REGWIDTH 32 24 | #define REGTYPE uint32_t /* register type */ 25 | #define SREGTYPE int32_t /* signed register type */ 26 | #define REGTYPE_HALF uint16_t /* half register type */ 27 | #define SREGTYPE_HALF int16_t 28 | #define REG_GET_ADDR reg_get_uint32 29 | #define REG_SET_ADDR reg_set_uint32 30 | #endif 31 | 32 | #ifdef ARCH_16BIT 33 | #define REGWIDTH 16 34 | #define REGTYPE uint16_t /* register type */ 35 | #define SREGTYPE int32_t /* signed register type */ 36 | #define REGTYPE_HALF uint8_t /* half register type */ 37 | #define SREGTYPE_HALF int8_t 38 | #define REG_GET_ADDR reg_get_uint16 39 | #define REG_SET_ADDR reg_set_uint16 40 | #endif 41 | 42 | #define ADDRTYPE REGTYPE 43 | #define PREGTYPE (REGTYPE *) /* pointer to register type */ 44 | #define REGMASK (~0) /* eg: 0xFFFF */ 45 | #define REGMASKLOHALF (( (REGTYPE)1 << (REGWIDTH/2) )-1) /* eg: 0x00FF */ 46 | #define REGMASKHIHALF (REGMASKLOHALF<<(REGWIDTH/2)) /* eg: 0xFF00 */ 47 | #define PREGTYPE_HALF (REGTYPE_HALF *) 48 | 49 | #if REGWIDTH == 64 50 | #define FMT_REG "0x%llX" 51 | #define FMT_REG_HALF "0x%X" 52 | #define FMT_SREG "0x%llX" 53 | #elif REGWIDTH == 32 54 | #define FMT_REG "0x%X" 55 | #define FMT_REG_HALF "0x%X" 56 | #define FMT_SREG "%d" 57 | #elif REGWIDTH == 16 58 | #define FMT_REG "0x%04X" 59 | #define FMT_REG_HALF "0x%02X" 60 | #define FMT_SREG "%d" 61 | #endif 62 | 63 | #define FMT_ADDR FMT_REG 64 | 65 | typedef struct Storage_ 66 | { 67 | uint8_t data[16]; 68 | } Storage; 69 | 70 | struct RegisterInfo { 71 | int index; /* register index */ 72 | string full_width_reg; /* name of full-width register (same if a full-width reg) */ 73 | int offset; /* offset within full-width register */ 74 | int size; /* in bytes */ 75 | int extend; /* zero or sign */ 76 | }; 77 | 78 | typedef enum _RETURN_ACTION 79 | { 80 | RETURN_FALSE = 0, 81 | RETURN_TRUE = 1 82 | } RETURN_ACTION; 83 | 84 | /* LowLevelILOperation.LLIL_NOP: [] */ 85 | void NOP(void); 86 | 87 | /* LowLevelILOperation.LLIL_SET_REG: [("dest", "reg"), ("src", "expr")] */ 88 | void SET_REG(string dest, uint8_t src); 89 | void SET_REG(string dest, uint16_t src); 90 | void SET_REG(string dest, uint32_t src); 91 | void SET_REG(string dest, uint64_t src); 92 | void SET_REG(string dest, __uint128_t src); 93 | 94 | void SET_REG_B(string dest, uint8_t src); 95 | void SET_REG_W(string dest, uint16_t src); 96 | void SET_REG_D(string dest, uint32_t src); 97 | void SET_REG_Q(string dest, uint64_t src); 98 | void SET_REG_O(string dest, __uint128_t src); 99 | 100 | /* LowLevelILOperation.LLIL_SET_REG_SPLIT: [("hi", "reg"), ("lo", "reg"), ("src", "expr")] */ 101 | void SET_REG_SPLIT_D(string hi, string lo, uint64_t src); /* "D" size destinations, source is "Q" */ 102 | 103 | /* LowLevelILOperation.LLIL_SET_REG_STACK_REL: [("stack", "reg_stack"), ("dest", "expr"), ("src", "expr")] */ 104 | /* LowLevelILOperation.LLIL_REG_STACK_PUSH: [("stack", "reg_stack"), ("src", "expr")] */ 105 | 106 | /* LowLevelILOperation.LLIL_SET_FLAG: [("dest", "flag"), ("src", "expr")] */ 107 | void SET_FLAG(string left, bool right); 108 | 109 | /* LowLevelILOperation.LLIL_LOAD: [("src", "expr")] */ 110 | uint8_t LOAD_B(REGTYPE expr); 111 | uint16_t LOAD_W(REGTYPE expr); 112 | uint32_t LOAD_D(REGTYPE expr); 113 | uint64_t LOAD_Q(REGTYPE expr); 114 | 115 | /* LowLevelILOperation.LLIL_STORE: [("dest", "expr"), ("src", "expr")] */ 116 | void STORE_B(REGTYPE dest, uint8_t src); 117 | void STORE_W(REGTYPE dest, uint16_t src); 118 | void STORE_D(REGTYPE dest, uint32_t src); 119 | void STORE_Q(REGTYPE dest, uint64_t src); 120 | 121 | /* LowLevelILOperation.LLIL_PUSH: [("src", "expr")] */ 122 | void PUSH_Q(REGTYPE src); 123 | 124 | /* LowLevelILOperation.LLIL_POP: [] */ 125 | REGTYPE POP_Q(void); 126 | 127 | /* LowLevelILOperation.LLIL_REG: [("src", "reg")] */ 128 | uint8_t REG_B(string src); 129 | uint16_t REG_W(string src); 130 | uint32_t REG_D(string src); 131 | uint64_t REG_Q(string src); 132 | __uint128_t REG_O(string src); 133 | 134 | /* LowLevelILOperation.LLIL_REG_SPLIT: [("hi", "reg"), ("lo", "reg")] */ 135 | REGTYPE REG_SPLIT_D(string hi, string lo); 136 | 137 | /* LowLevelILOperation.LLIL_REG_STACK_REL: [("stack", "reg_stack"), ("src", "expr")] */ 138 | /* LowLevelILOperation.LLIL_REG_STACK_POP: [("stack", "reg_stack")] */ 139 | /* LowLevelILOperation.LLIL_REG_STACK_FREE_REG: [("dest", "reg")] */ 140 | /* LowLevelILOperation.LLIL_REG_STACK_FREE_REL: [("stack", "reg_stack"), ("dest", "expr")] */ 141 | /* LowLevelILOperation.LLIL_CONST: [("constant", "int")] */ 142 | /* LowLevelILOperation.LLIL_CONST_PTR: [("constant", "int")] */ 143 | /* LowLevelILOperation.LLIL_EXTERN_PTR: [("constant", "int"), ("offset", "int")] */ 144 | SREGTYPE EXTERN_PTR(SREGTYPE constant, SREGTYPE offset); 145 | 146 | /* LowLevelILOperation.LLIL_FLOAT_CONST: [("constant", "float")] */ 147 | uint32_t FLOAT_CONST_D(float input); 148 | 149 | /* LowLevelILOperation.LLIL_FLAG: [("src", "flag")] */ 150 | bool FLAG(string src); 151 | 152 | /* LowLevelILOperation.LLIL_FLAG_BIT: [("src", "flag"), ("bit", "int")] */ 153 | /* LowLevelILOperation.LLIL_ADD: [("left", "expr"), ("right", "expr")] */ 154 | uint8_t ADD_B(uint8_t left, uint8_t right); 155 | uint16_t ADD_W(uint16_t left, uint16_t right); 156 | uint32_t ADD_D(uint32_t left, uint32_t right); 157 | uint64_t ADD_Q(uint64_t left, uint64_t right); 158 | 159 | /* LowLevelILOperation.LLIL_ADC: [("left", "expr"), ("right", "expr"), ("carry", "expr")] */ 160 | SREGTYPE ADC(SREGTYPE left, SREGTYPE right, bool carry); 161 | 162 | /* LowLevelILOperation.LLIL_SUB: [("left", "expr"), ("right", "expr")] */ 163 | uint8_t SUB_B(uint8_t a, uint8_t b); 164 | uint16_t SUB_W(uint16_t a, uint16_t b); 165 | uint32_t SUB_D(uint32_t a, uint32_t b); 166 | uint64_t SUB_Q(uint64_t a, uint64_t b); 167 | 168 | /* LowLevelILOperation.LLIL_SBB: [("left", "expr"), ("right", "expr"), ("carry", "expr")] */ 169 | uint8_t SBB_B(uint8_t a, uint8_t b, uint8_t c); 170 | uint16_t SBB_W(uint16_t a, uint16_t b, uint16_t c); 171 | uint32_t SBB_D(uint32_t a, uint32_t b, uint32_t c); 172 | uint64_t SBB_Q(uint64_t a, uint64_t b, uint64_t c); 173 | 174 | /* LowLevelILOperation.LLIL_AND: [("left", "expr"), ("right", "expr")] */ 175 | uint32_t AND_D(uint32_t left, uint32_t right); 176 | 177 | /* LowLevelILOperation.LLIL_OR: [("left", "expr"), ("right", "expr")] */ 178 | REGTYPE OR(REGTYPE left, REGTYPE right); 179 | 180 | /* LowLevelILOperation.LLIL_XOR: [("left", "expr"), ("right", "expr")] */ 181 | REGTYPE XOR(REGTYPE left, REGTYPE right); 182 | 183 | /* LowLevelILOperation.LLIL_LSL: [("left", "expr"), ("right", "expr")] */ 184 | uint64_t LSL_Q(uint64_t left, uint64_t right); 185 | 186 | /* LowLevelILOperation.LLIL_LSR: [("left", "expr"), ("right", "expr")] */ 187 | REGTYPE LSR(REGTYPE left, REGTYPE right); 188 | 189 | /* LowLevelILOperation.LLIL_ASR: [("left", "expr"), ("right", "expr")] */ 190 | int32_t ASR_D(int32_t left, uint32_t right); 191 | 192 | /* LowLevelILOperation.LLIL_ROL: [("left", "expr"), ("right", "expr")] */ 193 | uint8_t ROL_B(uint8_t value, uint8_t amt); 194 | uint16_t ROL_W(uint16_t value, uint16_t amt); 195 | uint32_t ROL_D(uint32_t value, uint32_t amt); 196 | uint64_t ROL_Q(uint64_t value, uint64_t amt); 197 | 198 | /* LowLevelILOperation.LLIL_RLC: [("left", "expr"), ("right", "expr"), ("carry", "expr")] */ 199 | uint8_t RLC_B(uint8_t value, uint8_t amt, bool carry); 200 | 201 | /* LowLevelILOperation.LLIL_ROR: [("left", "expr"), ("right", "expr")] */ 202 | uint8_t ROR_B(uint8_t value, uint8_t amt); 203 | uint16_t ROR_W(uint16_t value, uint16_t amt); 204 | uint32_t ROR_D(uint32_t value, uint32_t amt); 205 | uint64_t ROR_Q(uint64_t value, uint64_t amt); 206 | 207 | /* LowLevelILOperation.LLIL_RRC: [("left", "expr"), ("right", "expr"), ("carry", "expr")] */ 208 | uint8_t RRC_B(uint8_t value, uint8_t amt, bool carry); 209 | 210 | int32_t MUL_D(int32_t left, int32_t right); 211 | 212 | /* LowLevelILOperation.LLIL_MULU_DP: [("left", "expr"), ("right", "expr")] */ 213 | /* LowLevelILOperation.LLIL_MULS_DP: [("left", "expr"), ("right", "expr")] */ 214 | 215 | /* LowLevelILOperation.LLIL_DIVU: [("left", "expr"), ("right", "expr")] */ 216 | /* LowLevelILOperation.LLIL_DIVU_DP: [("left", "expr"), ("right", "expr")] */ 217 | 218 | /* LowLevelILOperation.LLIL_DIVS: [("left", "expr"), ("right", "expr")] */ 219 | uint32_t DIVS_D(uint32_t left, uint32_t right); 220 | 221 | /* LowLevelILOperation.LLIL_DIVS_DP: [("left", "expr"), ("right", "expr")] */ 222 | SREGTYPE DIVS_DP(SREGTYPE left, SREGTYPE_HALF right); 223 | 224 | /* LowLevelILOperation.LLIL_MODU: [("left", "expr"), ("right", "expr")] */ 225 | REGTYPE MODU(REGTYPE left, REGTYPE right); 226 | 227 | /* LowLevelILOperation.LLIL_MODU_DP: [("left", "expr"), ("right", "expr")] */ 228 | REGTYPE MODU_DP(REGTYPE left, REGTYPE right); 229 | 230 | /* LowLevelILOperation.LLIL_MODS: [("left", "expr"), ("right", "expr")] */ 231 | SREGTYPE MODS(SREGTYPE left, SREGTYPE right); 232 | 233 | /* LowLevelILOperation.LLIL_MODS_DP: [("left", "expr"), ("right", "expr")] */ 234 | SREGTYPE MODS_DP(SREGTYPE left, SREGTYPE right); 235 | 236 | /* LowLevelILOperation.LLIL_NEG: [("src", "expr")] */ 237 | uint8_t NEG_B(uint8_t src); 238 | uint16_t NEG_W(uint16_t src); 239 | uint32_t NEG_D(uint32_t src); 240 | uint64_t NEG_Q(uint64_t src); 241 | 242 | /* LowLevelILOperation.LLIL_NOT: [("src", "expr")] */ 243 | uint8_t NOT0(uint8_t left); 244 | uint8_t NOT_B(uint8_t left); 245 | uint16_t NOT_W(uint16_t left); 246 | uint32_t NOT_D(uint32_t left); 247 | uint64_t NOT_Q(uint64_t left); 248 | 249 | /* LowLevelILOperation.LLIL_SX: [("src", "expr")] */ 250 | int16_t SX_W_b(int8_t src); 251 | 252 | int32_t SX_D_b(int8_t src); 253 | int32_t SX_D_w(int16_t src); 254 | 255 | int64_t SX_Q_b(int8_t src); 256 | int64_t SX_Q_w(int16_t src); 257 | int64_t SX_Q_d(int32_t src); 258 | 259 | /* LowLevelILOperation.LLIL_TRAP: [("vector", "int")] */ 260 | void TRAP(int32_t src); 261 | 262 | /* LowLevelILOperation.LLIL_ZX: [("src", "expr")] */ 263 | uint32_t ZX_D(uint32_t src); 264 | uint64_t ZX_Q(uint64_t src); 265 | __uint128_t ZX_O(__uint128_t src); 266 | 267 | /* LowLevelILOperation.LLIL_LOW_PART: [("src", "expr")] */ 268 | uint8_t LOW_PART_B(REGTYPE left); 269 | uint16_t LOW_PART_W(REGTYPE left); 270 | uint32_t LOW_PART_D(REGTYPE left); 271 | uint64_t LOW_PART_Q(REGTYPE left); 272 | 273 | /* LowLevelILOperation.LLIL_JUMP: [("dest", "expr")] */ 274 | /* bool is whether or not this JUMP implements a return */ 275 | RETURN_ACTION JUMP(REGTYPE dest); 276 | 277 | /* LowLevelILOperation.LLIL_JUMP_TO: [("dest", "expr"), ("targets", "int_list")] */ 278 | /* LowLevelILOperation.LLIL_CALL: [("dest", "expr")] */ 279 | void CALL(REGTYPE dest, void (*)(void), const char *func_name); 280 | 281 | /* LowLevelILOperation.LLIL_CALL_STACK_ADJUST: [("dest", "expr"), ("stack_adjustment", "int"), ("reg_stack_adjustments", "reg_stack_adjust")] */ 282 | 283 | /* LowLevelILOperation.LLIL_TAILCALL: [("dest", "expr")] */ 284 | void TAILCALL(REGTYPE dest, void (*)(void), const char *func_name); 285 | 286 | /* LowLevelILOperation.LLIL_RET: [("dest", "expr")] */ 287 | void RET(REGTYPE dest); 288 | 289 | /* LowLevelILOperation.LLIL_NORET: [] */ 290 | /* LowLevelILOperation.LLIL_IF: [("condition", "expr"), ("true", "int"), ("false", "int")] */ 291 | /* LowLevelILOperation.LLIL_GOTO: [("dest", "int")] */ 292 | /* LowLevelILOperation.LLIL_FLAG_COND: [("condition", "cond"), ("semantic_class", "sem_class")] */ 293 | /* LowLevelILOperation.LLIL_FLAG_GROUP: [("semantic_group", "sem_group")] */ 294 | /* LowLevelILOperation.LLIL_CMP_E: [("left", "expr"), ("right", "expr")] */ 295 | bool CMP_E_D(uint32_t left, uint32_t right); 296 | /* LowLevelILOperation.LLIL_CMP_NE: [("left", "expr"), ("right", "expr")] */ 297 | bool CMP_NE_D(uint32_t left, uint32_t right); 298 | 299 | /* LowLevelILOperation.LLIL_CMP_SLT: [("left", "expr"), ("right", "expr")] */ 300 | bool CMP_SLT_B(int8_t left, int8_t right); 301 | bool CMP_SLT_W(int16_t left, int16_t right); 302 | bool CMP_SLT_D(int32_t left, int32_t right); 303 | 304 | /* LowLevelILOperation.LLIL_CMP_ULT: [("left", "expr"), ("right", "expr")] */ 305 | bool CMP_ULT(REGTYPE left, REGTYPE right); 306 | 307 | /* LowLevelILOperation.LLIL_CMP_SLE: [("left", "expr"), ("right", "expr")] */ 308 | bool CMP_SLE_B(int8_t left, int8_t right); 309 | bool CMP_SLE_W(int16_t left, int16_t right); 310 | bool CMP_SLE_D(int32_t left, int32_t right); 311 | 312 | /* LowLevelILOperation.LLIL_CMP_ULE: [("left", "expr"), ("right", "expr")] */ 313 | bool CMP_ULE(REGTYPE left, REGTYPE right); 314 | 315 | /* LowLevelILOperation.LLIL_CMP_SGE: [("left", "expr"), ("right", "expr")] */ 316 | bool CMP_SGE_B(int8_t left, int8_t right); 317 | bool CMP_SGE_W(int16_t left, int16_t right); 318 | bool CMP_SGE_D(int32_t left, int32_t right); 319 | 320 | /* LowLevelILOperation.LLIL_CMP_UGE: [("left", "expr"), ("right", "expr")] */ 321 | bool CMP_UGE(REGTYPE left, REGTYPE right); 322 | 323 | /* LowLevelILOperation.LLIL_CMP_SGT: [("left", "expr"), ("right", "expr")] */ 324 | bool CMP_SGT_B(int8_t left, int8_t right); 325 | bool CMP_SGT_W(int16_t left, int16_t right); 326 | bool CMP_SGT_D(int32_t left, int32_t right); 327 | 328 | /* LowLevelILOperation.LLIL_CMP_UGT: [("left", "expr"), ("right", "expr")] */ 329 | bool CMP_UGT_Q(uint64_t left, uint64_t right); 330 | 331 | /* LowLevelILOperation.LLIL_TEST_BIT: [("left", "expr"), ("right", "expr")] */ 332 | bool TEST_BIT(REGTYPE value, REGTYPE mask); 333 | 334 | /* LowLevelILOperation.LLIL_BOOL_TO_INT: [("src", "expr")] */ 335 | /* LowLevelILOperation.LLIL_ADD_OVERFLOW: [("left", "expr"), ("right", "expr")] */ 336 | bool ADD_OVERFLOW_B(uint8_t a, uint8_t b); 337 | bool ADD_OVERFLOW_W(uint16_t a, uint16_t b); 338 | bool ADD_OVERFLOW_D(uint32_t a, uint32_t b); 339 | 340 | /* LowLevelILOperation.LLIL_SYSCALL: [] */ 341 | /* LowLevelILOperation.LLIL_INTRINSIC: [("output", "reg_or_flag_list"), ("intrinsic", "intrinsic"), ("param", "expr")] */ 342 | /* LowLevelILOperation.LLIL_INTRINSIC_SSA: [("output", "reg_or_flag_ssa_list"), ("intrinsic", "intrinsic"), ("param", "expr")] */ 343 | /* LowLevelILOperation.LLIL_BP: [] */ 344 | /* LowLevelILOperation.LLIL_TRAP: [("vector", "int")] */ 345 | /* LowLevelILOperation.LLIL_UNDEF: [] */ 346 | 347 | /* LowLevelILOperation.LLIL_UNIMPL: [] */ 348 | REGTYPE UNIMPL(void); 349 | REGTYPE UNIMPL(REGTYPE); 350 | 351 | /* LowLevelILOperation.LLIL_UNIMPL_MEM: [("src", "expr")] */ 352 | 353 | /* LowLevelILOperation.LLIL_FADD: [("left", "expr"), ("right", "expr")] */ 354 | uint32_t FADD_S(uint32_t a, uint32_t b); 355 | uint64_t FADD_D(uint64_t a, uint64_t b); 356 | 357 | /* LowLevelILOperation.LLIL_FSUB: [("left", "expr"), ("right", "expr")] */ 358 | uint32_t FSUB_S(uint32_t a, uint32_t b); 359 | 360 | /* LowLevelILOperation.LLIL_FMUL: [("left", "expr"), ("right", "expr")] */ 361 | uint32_t FMUL_S(uint32_t a, uint32_t b); 362 | uint64_t FMUL_D(uint64_t a, uint64_t b); 363 | 364 | /* LowLevelILOperation.LLIL_FDIV: [("left", "expr"), ("right", "expr")] */ 365 | uint32_t FDIV_S(uint32_t a, uint32_t b); 366 | uint64_t FDIV_D(uint64_t a, uint64_t b); 367 | 368 | /* LowLevelILOperation.LLIL_FSQRT: [("src", "expr")] */ 369 | /* LowLevelILOperation.LLIL_FNEG: [("src", "expr")] */ 370 | /* LowLevelILOperation.LLIL_FABS: [("src", "expr")] */ 371 | /* LowLevelILOperation.LLIL_FLOAT_TO_INT: [("src", "expr")] */ 372 | /* LowLevelILOperation.LLIL_INT_TO_FLOAT: [("src", "expr")] */ 373 | /* LowLevelILOperation.LLIL_FLOAT_CONV: [("src", "expr")] */ 374 | uint32_t FLOAT_CONV_S(uint64_t input); 375 | uint32_t FLOAT_CONV_D(uint32_t input); 376 | /* LowLevelILOperation.LLIL_ROUND_TO_INT: [("src", "expr")] */ 377 | /* LowLevelILOperation.LLIL_FLOOR: [("src", "expr")] */ 378 | /* LowLevelILOperation.LLIL_CEIL: [("src", "expr")] */ 379 | /* LowLevelILOperation.LLIL_FTRUNC: [("src", "expr")] */ 380 | /* LowLevelILOperation.LLIL_FCMP_E: [("left", "expr"), ("right", "expr")] */ 381 | /* LowLevelILOperation.LLIL_FCMP_NE: [("left", "expr"), ("right", "expr")] */ 382 | /* LowLevelILOperation.LLIL_FCMP_LT: [("left", "expr"), ("right", "expr")] */ 383 | /* LowLevelILOperation.LLIL_FCMP_LE: [("left", "expr"), ("right", "expr")] */ 384 | /* LowLevelILOperation.LLIL_FCMP_GE: [("left", "expr"), ("right", "expr")] */ 385 | /* LowLevelILOperation.LLIL_FCMP_GT: [("left", "expr"), ("right", "expr")] */ 386 | /* LowLevelILOperation.LLIL_FCMP_O: [("left", "expr"), ("right", "expr")] */ 387 | /* LowLevelILOperation.LLIL_FCMP_UO: [("left", "expr"), ("right", "expr")] */ 388 | bool FCMP_E_D(double left, double right); 389 | bool FCMP_NE_D(double left, double right); 390 | bool FCMP_GE_D(double left, double right); 391 | bool FCMP_LE_D(double left, double right); 392 | bool FCMP_UO_D(double left, double right); 393 | 394 | /* LowLevelILOperation.LLIL_SET_REG_SSA: [("dest", "reg_ssa"), ("src", "expr")] */ 395 | /* LowLevelILOperation.LLIL_SET_REG_SSA_PARTIAL: [("full_reg", "reg_ssa"), ("dest", "reg"), ("src", "expr")] */ 396 | /* LowLevelILOperation.LLIL_SET_REG_SPLIT_SSA: [("hi", "expr"), ("lo", "expr"), ("src", "expr")] */ 397 | /* LowLevelILOperation.LLIL_SET_REG_STACK_REL_SSA: [("stack", "expr"), ("dest", "expr"), ("top", "expr"), ("src", "expr")] */ 398 | /* LowLevelILOperation.LLIL_SET_REG_STACK_ABS_SSA: [("stack", "expr"), ("dest", "reg"), ("src", "expr")] */ 399 | /* LowLevelILOperation.LLIL_REG_SPLIT_DEST_SSA: [("dest", "reg_ssa")] */ 400 | /* LowLevelILOperation.LLIL_REG_STACK_DEST_SSA: [("src", "reg_stack_ssa_dest_and_src")] */ 401 | /* LowLevelILOperation.LLIL_REG_SSA: [("src", "reg_ssa")] */ 402 | /* LowLevelILOperation.LLIL_REG_SSA_PARTIAL: [("full_reg", "reg_ssa"), ("src", "reg")] */ 403 | /* LowLevelILOperation.LLIL_REG_SPLIT_SSA: [("hi", "reg_ssa"), ("lo", "reg_ssa")] */ 404 | /* LowLevelILOperation.LLIL_REG_STACK_REL_SSA: [("stack", "reg_stack_ssa"), ("src", "expr"), ("top", "expr")] */ 405 | /* LowLevelILOperation.LLIL_REG_STACK_ABS_SSA: [("stack", "reg_stack_ssa"), ("src", "reg")] */ 406 | /* LowLevelILOperation.LLIL_REG_STACK_FREE_REL_SSA: [("stack", "expr"), ("dest", "expr"), ("top", "expr")] */ 407 | /* LowLevelILOperation.LLIL_REG_STACK_FREE_ABS_SSA: [("stack", "expr"), ("dest", "reg")] */ 408 | /* LowLevelILOperation.LLIL_SET_FLAG_SSA: [("dest", "flag_ssa"), ("src", "expr")] */ 409 | /* LowLevelILOperation.LLIL_FLAG_SSA: [("src", "flag_ssa")] */ 410 | /* LowLevelILOperation.LLIL_FLAG_BIT_SSA: [("src", "flag_ssa"), ("bit", "int")] */ 411 | /* LowLevelILOperation.LLIL_CALL_SSA: [("output", "expr"), ("dest", "expr"), ("stack", "expr"), ("param", "expr")] */ 412 | /* LowLevelILOperation.LLIL_SYSCALL_SSA: [("output", "expr"), ("stack", "expr"), ("param", "expr")] */ 413 | /* LowLevelILOperation.LLIL_TAILCALL_SSA: [("output", "expr"), ("dest", "expr"), ("stack", "expr"), ("param", "expr")] */ 414 | /* LowLevelILOperation.LLIL_CALL_OUTPUT_SSA: [("dest_memory", "int"), ("dest", "reg_ssa_list")] */ 415 | /* LowLevelILOperation.LLIL_CALL_STACK_SSA: [("src", "reg_ssa"), ("src_memory", "int")] */ 416 | /* LowLevelILOperation.LLIL_CALL_PARAM: [("src", "expr_list")] */ 417 | /* LowLevelILOperation.LLIL_LOAD_SSA: [("src", "expr"), ("src_memory", "int")] */ 418 | /* LowLevelILOperation.LLIL_STORE_SSA: [("dest", "expr"), ("dest_memory", "int"), ("src_memory", "int"), ("src", "expr")] */ 419 | /* LowLevelILOperation.LLIL_REG_PHI: [("dest", "reg_ssa"), ("src", "reg_ssa_list")] */ 420 | /* LowLevelILOperation.LLIL_REG_STACK_PHI: [("dest", "reg_stack_ssa"), ("src", "reg_stack_ssa_list")] */ 421 | /* LowLevelILOperation.LLIL_FLAG_PHI: [("dest", "flag_ssa"), ("src", "flag_ssa_list")] */ 422 | /* LowLevelILOperation.LLIL_MEM_PHI: [("dest_memory", "int"), ("src_memory", "int_list")] */ 423 | 424 | /* type_val stuff */ 425 | 426 | enum TV_TYPE 427 | { 428 | TV_TYPE_NONE = 0, /* must be 0, so memset() sets TYPE_NONE */ 429 | TV_TYPE_UINT8, 430 | TV_TYPE_UINT16, 431 | TV_TYPE_UINT32, 432 | TV_TYPE_UINT64, 433 | TV_TYPE_UINT128, 434 | TV_TYPE_FLOAT16, /* half-precision */ 435 | TV_TYPE_FLOAT32, /* single-precision */ 436 | TV_TYPE_FLOAT64 /* double-precision */ 437 | }; 438 | 439 | typedef struct type_val_ 440 | { 441 | enum TV_TYPE type; 442 | uint8_t data[16]; 443 | } type_val; 444 | 445 | type_val tv_init(enum TV_TYPE type); 446 | type_val tv_new_none(); 447 | type_val tv_new_uint8(uint8_t val); 448 | type_val tv_new_uint16(uint16_t val); 449 | type_val tv_new_uint32(uint32_t val); 450 | type_val tv_new_uint64(uint64_t val); 451 | type_val tv_new_float32(float val); 452 | type_val tv_new_float64(double val); 453 | 454 | uint8_t tv_get_uint8(type_val tv); 455 | uint16_t tv_get_uint16(type_val tv); 456 | uint32_t tv_get_uint32(type_val tv); 457 | uint64_t tv_get_uint64(type_val tv); 458 | float tv_get_float32(type_val tv); 459 | double tv_get_float64(type_val tv); 460 | 461 | void tv_set_uint8(type_val tv, uint8_t val); 462 | void tv_set_uint16(type_val tv, uint16_t val); 463 | void tv_set_uint32(type_val tv, uint32_t val); 464 | void tv_set_uint64(type_val tv, uint64_t val); 465 | 466 | void tv_to_str(type_val tv, char *str, int buflen); 467 | int tv_cmp(type_val a, type_val b); 468 | 469 | /* register helpers */ 470 | 471 | void runtime_comment(const char *msg); 472 | 473 | type_val reg_get_type_val(string reg_name); 474 | void reg_set_type_val(string reg_name, type_val tv); 475 | 476 | uint8_t reg_get_uint8(string name); 477 | uint16_t reg_get_uint16(string name); 478 | uint32_t reg_get_uint32(string name); 479 | uint64_t reg_get_uint64(string name); 480 | __uint128_t reg_get_uint128(string name); 481 | float reg_get_float32(string name); 482 | 483 | void reg_set_uint8(string name, uint8_t val); 484 | void reg_set_uint16(string name, uint16_t val); 485 | void reg_set_uint32(string name, uint32_t val); 486 | void reg_set_uint64(string name, uint64_t val); 487 | void reg_set_uint128(string name, __uint128_t val); 488 | void reg_set_float32(string name, float val); 489 | void reg_set_float64(string name, double val); 490 | 491 | #ifdef ARCH_ARM 492 | void __aeabi_idiv(); 493 | void __aeabi_idivmod(); 494 | #endif 495 | 496 | -------------------------------------------------------------------------------- /sdcc2elf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # convert SDCC .rel files to 32-bit ELF relocatable 4 | # 5 | # resulting file is simple: 6 | # 7 | # ------------------------ 8 | # ELF header 9 | # ------------------------ 10 | # .text section 11 | # .shstrtab section 12 | # .strtab section 13 | # .symtab section 14 | # ------------------------ 15 | # NULL elf32_shdr 16 | # .text elf32_shdr 17 | # .shstrtab elf32_shdr 18 | # .symtab elf32_shdr 19 | # .strtab elf32_shdr 20 | # ------------------------ 21 | 22 | import os 23 | import re 24 | import sys 25 | from struct import pack 26 | 27 | #------------------------------------------------------------------------------ 28 | # ELF helpers 29 | #------------------------------------------------------------------------------ 30 | 31 | (PF_X, PF_W, PF_R) = (1,2,4) 32 | (SHT_NULL, SHT_PROGBITS, SHT_STRTAB) = (0,1,3) 33 | 34 | sz_ehdr = 0x34 35 | sz_shdr = 0x28 36 | 37 | def align(fp, to=4, pad=b'\x00'): 38 | while fp.tell() % to: 39 | fp.write(pad) 40 | 41 | #------------------------------------------------------------------------------ 42 | # read .map file for symbols 43 | #------------------------------------------------------------------------------ 44 | 45 | fpath_map = sys.argv[2] 46 | assert fpath_map.endswith('.map') 47 | 48 | with open(fpath_map) as fp: 49 | lines = fp.readlines() 50 | 51 | (_CODE_ADDR, _CODE_SZ) = (None, None) 52 | (i_code, i_header) = (None, None) 53 | for (i, line) in enumerate(lines): 54 | if line.startswith('_CODE'): 55 | m = re.match(r'^_CODE\s+([A-F0-9]{8})\s+([A-F0-9]{8})', line) 56 | (addr, size) = map(lambda x: int(x, 16), m.group(1,2)) 57 | 58 | if not i_code: 59 | i_code = i 60 | _CODE_ADDR = addr 61 | _CODE_SZ = size 62 | else: 63 | if addr != _CODE_ADDR: 64 | raise Exception('conflicting code segment addresses') 65 | if size != _CODE_SZ: 66 | raise Exception('conflicting code segment sizes') 67 | 68 | if line.startswith('_HEADER0'): 69 | i_header = i 70 | break 71 | assert i_code and i_header and i_code < i_header 72 | 73 | syms = [] 74 | for line in lines[i_code:i_header]: 75 | m = re.search(r'([A-F0-9]{8})\s+(_\w+)', line) 76 | if m: 77 | (addr, symname) = m.group(1, 2) 78 | print('found %s: %s' % (addr, symname)) 79 | syms.append((symname, int(addr, 16))); 80 | 81 | assert syms 82 | print('_CODE [%08X, %08X)' % (_CODE_ADDR, _CODE_ADDR+_CODE_SZ)) 83 | print('_CODE symbols from') 84 | for (name, addr) in syms: 85 | print('%08X: %s' % (addr, name)) 86 | 87 | #------------------------------------------------------------------------------ 88 | # read .ihx file 89 | #------------------------------------------------------------------------------ 90 | 91 | fpath_ihx = sys.argv[1] 92 | assert fpath_ihx.endswith('.ihx') 93 | 94 | code_area = [b'\x00'] * (_CODE_ADDR + _CODE_SZ) 95 | 96 | with open(fpath_ihx) as fp: 97 | for line in fp.readlines(): 98 | 99 | m = re.match(r'^:(..)(....)00(.*)(..)', line) 100 | if m: 101 | (count, addr, data, csum) = m.group(1,2,3,4) 102 | count = int(count,16) 103 | assert count == len(data)/2 104 | addr = int(addr,16) 105 | if not (addr >= _CODE_ADDR and addr < (_CODE_ADDR + _CODE_SZ)): 106 | continue 107 | print('%08X: ' % addr, end='') 108 | for i in range(count): 109 | byte_str = data[2*i]+data[2*i+1] 110 | print('%s ' % byte_str, end='') 111 | code_area[addr + i] = pack('B', int(byte_str, 16)) 112 | print('') 113 | continue 114 | 115 | m = re.match(r'^:00000001FF', line) 116 | if m: 117 | break 118 | 119 | raise Exception('got unexpected IHX line: %s' % line) 120 | 121 | assert code_area 122 | #print(code_area) 123 | 124 | #------------------------------------------------------------------------------ 125 | # write ELF 126 | #------------------------------------------------------------------------------ 127 | 128 | # process symbols, build string table 129 | syms = sorted(syms, key=lambda name_addr: name_addr[1]) 130 | func2size = {} 131 | func2stroffs = {} 132 | strtab = b'\x00' 133 | for i in range(len(syms)): 134 | (name, addr) = syms[i] 135 | 136 | if i == len(syms)-1: 137 | func2size[name] = len(code_area) - addr 138 | else: 139 | func2size[name] = syms[i+1][1] - addr 140 | 141 | func2stroffs[name] = len(strtab) 142 | strtab = strtab + name.encode('utf-8') + b'\x00' 143 | 144 | print('%04X: %s size %X' % (addr, name, func2size[name])) 145 | 146 | fp = open('tests.elf', 'wb') 147 | 148 | # elf32_hdr (placeholder, we'll come back to fill in offsets) 149 | print('elf32_hdr @ %X' % fp.tell()) 150 | fp.write(b'\x00' * sz_ehdr) 151 | 152 | # .text section contents 153 | o_text = fp.tell() 154 | print('placing .text @ %X' % o_text) 155 | for byte in code_area: 156 | fp.write(byte) 157 | sz_text = fp.tell() - o_text 158 | 159 | # .shstrtab section contents 160 | scn_shstrtab = b'\x00.text\x00.shstrtab\x00.symtab\x00.strtab\x00' 161 | align(fp) 162 | o_shstrtab = fp.tell() 163 | print('placing .shstrtab @ %X' % o_shstrtab) 164 | fp.write(scn_shstrtab) 165 | sz_shstrtab = fp.tell() - o_shstrtab 166 | 167 | # .symtab section contents 168 | align(fp) 169 | o_symtab = fp.tell() 170 | print('placing .symtab @ %X' % o_symtab) 171 | for (name, addr) in syms: 172 | st_name = func2stroffs[name] 173 | st_value = addr 174 | st_size = func2size[name] 175 | st_info = 0x12 # bind:1(GLOBAL) type:2(FUNC) 176 | st_other = 0 177 | st_shndx = 0x1 # section header index: 0'th: NULL 1'th: .text 178 | Elf32_Sym = pack('= 10) 65 | return 7; 66 | else 67 | return 13; 68 | } 69 | 70 | unsigned int test_byte_uge_10(unsigned char a) 71 | { 72 | if(a >= 10) 73 | return 7; 74 | else 75 | return 13; 76 | } 77 | 78 | unsigned int test_byte_sgt_10(signed char a) 79 | { 80 | if(a > 10) 81 | return 7; 82 | else 83 | return 13; 84 | } 85 | 86 | unsigned int test_byte_ugt_10(unsigned char a) 87 | { 88 | if(a > 10) 89 | return 7; 90 | else 91 | return 13; 92 | } 93 | 94 | unsigned int test_byte_neg(signed char a) 95 | { 96 | if(a < 0) 97 | return 7; 98 | else 99 | return 13; 100 | } 101 | 102 | unsigned int test_byte_pos(signed char a) 103 | { 104 | if(a >= 0) 105 | return 7; 106 | else 107 | return 13; 108 | } 109 | 110 | // 111 | 112 | unsigned int test_word_e_10(unsigned short a) 113 | { 114 | if(a == 10) 115 | return 7; 116 | else 117 | return 13; 118 | } 119 | 120 | unsigned int test_word_ne_10(unsigned short a) 121 | { 122 | if(a != 10) 123 | return 7; 124 | else 125 | return 13; 126 | } 127 | 128 | unsigned int test_word_slt_10(signed short a) 129 | { 130 | if(a < 10) 131 | return 7; 132 | else 133 | return 13; 134 | } 135 | 136 | unsigned int test_word_ult_10(unsigned short a) 137 | { 138 | if(a < 10) 139 | return 7; 140 | else 141 | return 13; 142 | } 143 | 144 | unsigned int test_word_sle_10(signed short a) 145 | { 146 | if(a <= 10) 147 | return 7; 148 | else 149 | return 13; 150 | } 151 | 152 | unsigned int test_word_ule_10(unsigned short a) 153 | { 154 | if(a <= 10) 155 | return 7; 156 | else 157 | return 13; 158 | } 159 | 160 | unsigned int test_word_sge_10(signed short a) 161 | { 162 | if(a >= 10) 163 | return 7; 164 | else 165 | return 13; 166 | } 167 | 168 | unsigned int test_word_uge_10(unsigned short a) 169 | { 170 | if(a >= 10) 171 | return 7; 172 | else 173 | return 13; 174 | } 175 | 176 | unsigned int test_word_sgt_10(signed short a) 177 | { 178 | if(a > 10) 179 | return 7; 180 | else 181 | return 13; 182 | } 183 | 184 | unsigned int test_word_ugt_10(unsigned short a) 185 | { 186 | if(a > 10) 187 | return 7; 188 | else 189 | return 13; 190 | } 191 | 192 | unsigned int test_word_neg(signed short a) 193 | { 194 | if(a < 0) 195 | return 7; 196 | else 197 | return 13; 198 | } 199 | 200 | unsigned int test_word_pos(signed short a) 201 | { 202 | if(a >= 0) 203 | return 7; 204 | else 205 | return 13; 206 | } 207 | 208 | /* establish ability to loop and conditionally jump */ 209 | int triangle_up(int a) 210 | { 211 | int i, result = 0; 212 | for(i=1; i<=a; ++i) 213 | { 214 | result += i; 215 | } 216 | 217 | return result; 218 | } 219 | 220 | int triangle_down(int a) 221 | { 222 | int i, result = 0; 223 | for(i=a; i>0; --i) 224 | { 225 | result += i; 226 | } 227 | 228 | return result; 229 | } 230 | 231 | /* this is pretty hard if arch doesn't have a mul instruction */ 232 | unsigned char multiply_u8(unsigned char a, unsigned char b) 233 | { 234 | return a * b; 235 | } 236 | 237 | int multiply(int a, int b) 238 | { 239 | return a * b; 240 | } 241 | 242 | int multiply_loop(int a, int b) 243 | { 244 | int i; 245 | int result = 0; 246 | int neg = 1; 247 | 248 | if(b < 0) { 249 | b = -b; 250 | neg = -neg; 251 | } 252 | 253 | for(i=0; i> 1; 300 | } 301 | 302 | return result; 303 | } 304 | 305 | int gcd(int a, int b) 306 | { 307 | int result; 308 | 309 | while(1) { 310 | if(a == 0) { 311 | result = b; 312 | break; 313 | } 314 | if(b == 0) { 315 | result = a; 316 | break; 317 | } 318 | 319 | if(a > b) 320 | a = a % b; 321 | else 322 | b = b % a; 323 | } 324 | 325 | return result; 326 | } 327 | 328 | int gcd_recursive(int a, int b) 329 | { 330 | if(a == 0) return b; 331 | if(b == 0) return a; 332 | if(a == b) return a; 333 | if(a > b) return gcd_recursive(a - b, b); 334 | return gcd_recursive(a, b - a); 335 | } 336 | 337 | int switch_doubler(unsigned int a) 338 | { 339 | int result; 340 | 341 | switch(a) { 342 | case 0: result=0; break; 343 | case 1: result=2; break; 344 | case 2: result=4; break; 345 | case 3: result=6; break; 346 | case 4: result=8; break; 347 | case 5: result=10; break; 348 | case 6: result=12; break; 349 | case 7: result=14; break; 350 | case 8: result=16; break; 351 | case 9: result=18; break; 352 | case 10: result=20; break; 353 | default: result=-1; 354 | } 355 | 356 | return result; 357 | } 358 | 359 | int factorial(int n) 360 | { 361 | if(n <= 1) 362 | return 1; 363 | else 364 | return n * factorial(n-1); 365 | } 366 | 367 | /* primitive floating point */ 368 | float fp_single_add(float a, float b) 369 | { 370 | return a + b; 371 | } 372 | 373 | float fp_single_sub(float a, float b) 374 | { 375 | return a - b; 376 | } 377 | 378 | float fp_single_mul(float a, float b) 379 | { 380 | return a * b; 381 | } 382 | 383 | float fp_single_div(float a, float b) 384 | { 385 | return a / b; 386 | } 387 | 388 | float test_float_e_10(float a) 389 | { 390 | if(a == 10) return 7; 391 | return 13; 392 | } 393 | 394 | float test_float_ne_10(float a) 395 | { 396 | if(a != 10) return 7; 397 | return 13; 398 | } 399 | 400 | float test_float_slt_10(float a) 401 | { 402 | if(a < 10) 403 | return 7; 404 | else 405 | return 13; 406 | } 407 | 408 | float test_float_ult_10(float a) 409 | { 410 | if(a < 10) 411 | return 7; 412 | else 413 | return 13; 414 | } 415 | 416 | 417 | /* 418 | void test() 419 | { 420 | float tmp = fp_single_div(1.0, 2.0); 421 | tmp = fp_single_div(3.57, 11.13); 422 | } 423 | */ 424 | 425 | float fp_convert_double_to_single(double a) 426 | { 427 | return a; 428 | } 429 | 430 | float fp_convert_double_product_to_single(double a, double b) 431 | { 432 | return a * b; 433 | } 434 | 435 | #ifdef ARCH_Z80 436 | int main() 437 | { 438 | return -1; 439 | } 440 | #endif 441 | 442 | --------------------------------------------------------------------------------