From cdcf78faa98ec61d992f5f379fc889c978f6d956 Mon Sep 17 00:00:00 2001 From: Peter Goodman Date: Tue, 15 Sep 2020 15:18:19 -0400 Subject: [PATCH 001/130] This branch contains support for new architectures. --- CMakeLists.txt | 12 +- cmake/BCCompiler.cmake | 1 + cmake/settings.cmake | 6 +- remill/Arch/AArch64/Arch.cpp | 348 +++++++++- remill/Arch/AArch64/Runtime/BasicBlock.cpp | 336 +-------- remill/Arch/AArch64/Runtime/Instructions.cpp | 2 + remill/Arch/AArch64/Semantics/CALL_RET.cpp | 6 +- remill/Arch/Arch.cpp | 685 ++++--------------- remill/Arch/Arch.h | 41 +- remill/Arch/X86/Arch.cpp | 400 ++++++++++- remill/Arch/X86/Runtime/BasicBlock.cpp | 313 +-------- remill/Arch/X86/Runtime/Instructions.cpp | 2 + remill/BC/Compat/CTypes.h | 25 + remill/BC/Lifter.cpp | 117 +++- remill/BC/Lifter.h | 29 +- remill/BC/Optimizer.h | 4 +- remill/BC/Util.cpp | 1 + remill/BC/Util.h | 3 + remill/Version/Version.h | 27 +- scripts/travis.bat | 2 +- tools/lift/Lift.cpp | 13 +- 21 files changed, 1063 insertions(+), 1310 deletions(-) create mode 100644 remill/BC/Compat/CTypes.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fdfa680d0..19d0ae5c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,8 +30,8 @@ include(CTest) if (LLVM_Z3_INSTALL_DIR) find_package(Z3 4.7.1) set(need_z3 TRUE) -elseif(DEFINED ENV{TRAILOFBITS_LIBRARIES}) - set(LLVM_Z3_INSTALL_DIR "$ENV{TRAILOFBITS_LIBRARIES}/z3") +elseif(DEFINED CXX_COMMON_REPOSITORY_ROOT) + set(LLVM_Z3_INSTALL_DIR "${CXX_COMMON_REPOSITORY_ROOT}/z3") set(need_z3 TRUE) else() set(need_z3 FALSE) @@ -67,6 +67,7 @@ endif() # libraries # +# LLVM find_package(LLVM REQUIRED CONFIG HINTS ${FINDPACKAGE_LLVM_HINTS}) string(REPLACE "." ";" LLVM_VERSION_LIST ${LLVM_PACKAGE_VERSION}) @@ -234,7 +235,7 @@ endfunction() set(INSTALLED_CLANG_NAME "remill-clang-${REMILL_LLVM_VERSION}${executable_extension}") set(INSTALLED_LLVMLINK_NAME "remill-llvm-link-${REMILL_LLVM_VERSION}${executable_extension}") -if("${LIBRARY_REPOSITORY_ROOT}" STREQUAL "" OR NOT EXISTS "${LIBRARY_REPOSITORY_ROOT}/llvm") +if("${CXX_COMMON_REPOSITORY_ROOT}" STREQUAL "" OR NOT EXISTS "${CXX_COMMON_REPOSITORY_ROOT}/llvm") set(INSTALLED_LIBLLVM_NAME "${dynamic_lib_prefix}LLVM-${REMILL_LLVM_VERSION}.${dynamic_lib_extension}") # system binaries are not built statically, so we need to fix the rpath @@ -268,10 +269,10 @@ if("${LIBRARY_REPOSITORY_ROOT}" STREQUAL "" OR NOT EXISTS "${LIBRARY_REPOSITORY_ else() # The executable in our binary repository are statically built, meaning that we don't need # to change the rpath - InstallExternalTarget("ext_clang" "${LIBRARY_REPOSITORY_ROOT}/llvm/bin/clang${executable_extension}" + InstallExternalTarget("ext_clang" "${CXX_COMMON_REPOSITORY_ROOT}/llvm/bin/clang${executable_extension}" "${install_folder}/bin" "${INSTALLED_CLANG_NAME}") - InstallExternalTarget("ext_llvmlink" "${LIBRARY_REPOSITORY_ROOT}/llvm/bin/llvm-link${executable_extension}" + InstallExternalTarget("ext_llvmlink" "${CXX_COMMON_REPOSITORY_ROOT}/llvm/bin/llvm-link${executable_extension}" "${install_folder}/bin" "${INSTALLED_LLVMLINK_NAME}") endif() @@ -316,6 +317,7 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/Attributes.h" "${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/BitcodeReaderWriter.h" "${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/CallingConvention.h" + "${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/CTypes.h" "${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/DataLayout.h" "${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/DebugInfo.h" "${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/Error.h" diff --git a/cmake/BCCompiler.cmake b/cmake/BCCompiler.cmake index 58ccbab59..54766a35a 100644 --- a/cmake/BCCompiler.cmake +++ b/cmake/BCCompiler.cmake @@ -17,6 +17,7 @@ set(DEFAULT_BC_COMPILER_FLAGS -ffreestanding -fno-common -fno-builtin -fno-exceptions -fno-rtti -fno-asynchronous-unwind-tables -Wno-unneeded-internal-declaration -Wno-unused-function -Wgnu-inline-cpp-without-extern -std=c++14 + -Wno-pass-failed=transform-warning ${EXTRA_BC_SYSROOT} ) diff --git a/cmake/settings.cmake b/cmake/settings.cmake index bda52399a..5258529ea 100644 --- a/cmake/settings.cmake +++ b/cmake/settings.cmake @@ -29,13 +29,13 @@ macro(main) # if(DEFINED ENV{TRAILOFBITS_LIBRARIES}) - set(LIBRARY_REPOSITORY_ROOT $ENV{TRAILOFBITS_LIBRARIES} + set(CXX_COMMON_REPOSITORY_ROOT $ENV{TRAILOFBITS_LIBRARIES} CACHE PATH "Location of cxx-common libraries." ) endif() - if(DEFINED LIBRARY_REPOSITORY_ROOT) - set(TOB_CMAKE_INCLUDE "${LIBRARY_REPOSITORY_ROOT}/cmake_modules/repository.cmake") + if(DEFINED CXX_COMMON_REPOSITORY_ROOT) + set(TOB_CMAKE_INCLUDE "${CXX_COMMON_REPOSITORY_ROOT}/cmake_modules/repository.cmake") if(NOT EXISTS "${TOB_CMAKE_INCLUDE}") message(FATAL_ERROR "The library repository could not be found!") endif() diff --git a/remill/Arch/AArch64/Arch.cpp b/remill/Arch/AArch64/Arch.cpp index f15b58896..e30ee923b 100644 --- a/remill/Arch/AArch64/Arch.cpp +++ b/remill/Arch/AArch64/Arch.cpp @@ -18,7 +18,9 @@ #include #include #include +#include #include +#include #include #include @@ -35,9 +37,17 @@ #include "remill/Arch/Arch.h" #include "remill/Arch/Instruction.h" #include "remill/Arch/Name.h" +#include "remill/BC/ABI.h" +#include "remill/BC/Util.h" #include "remill/BC/Version.h" #include "remill/OS/OS.h" +// clang-format off +#define ADDRESS_SIZE 64 +#include "Runtime/State.h" + +// clang-format on + namespace remill { namespace { @@ -102,23 +112,27 @@ class AArch64Arch final : public Arch { virtual ~AArch64Arch(void); // Returns the name of the stack pointer register. - const char *StackPointerRegisterName(void) const final; + const char *StackPointerRegisterName(void) const override; // Returns the name of the program counter register. - const char *ProgramCounterRegisterName(void) const final; + const char *ProgramCounterRegisterName(void) const override; // Decode an instruction. bool DecodeInstruction(uint64_t address, std::string_view instr_bytes, - Instruction &inst) const final; + Instruction &inst) const override; // Maximum number of bytes in an instruction. - uint64_t MaxInstructionSize(void) const final; + uint64_t MaxInstructionSize(void) const override; - llvm::Triple Triple(void) const final; - llvm::DataLayout DataLayout(void) const final; + llvm::Triple Triple(void) const override; + llvm::DataLayout DataLayout(void) const override; // Default calling convention for this architecture. - llvm::CallingConv::ID DefaultCallingConv(void) const final; + llvm::CallingConv::ID DefaultCallingConv(void) const override; + + // Populate the `__remill_basic_block` function with variables. + void PopulateBasicBlockFunction(llvm::Module *module, + llvm::Function *bb_func) const override; private: AArch64Arch(void) = delete; @@ -135,6 +149,326 @@ llvm::CallingConv::ID AArch64Arch::DefaultCallingConv(void) const { return llvm::CallingConv::C; } +// Populate the `__remill_basic_block` function with variables. +void AArch64Arch::PopulateBasicBlockFunction(llvm::Module *module, + llvm::Function *bb_func) const { + +#define OFFSET_OF(type, access) \ + (reinterpret_cast(&reinterpret_cast( \ + static_cast(nullptr)->access))) + +#define REG(name, access, type) \ + AddRegister(#name, type, OFFSET_OF(AArch64State, access), nullptr) + +#define SUB_REG(name, access, type, parent_reg_name) \ + AddRegister(#name, type, OFFSET_OF(AArch64State, access), #parent_reg_name) + + auto &context = module->getContext(); + auto u8 = llvm::Type::getInt8Ty(context); + auto u16 = llvm::Type::getInt16Ty(context); + auto u32 = llvm::Type::getInt32Ty(context); + auto u64 = llvm::Type::getInt64Ty(context); + auto u128 = llvm::Type::getInt128Ty(context); + + auto v128u8 = llvm::ArrayType::get(u8, 128u / 8u); + auto v128u16 = llvm::ArrayType::get(u16, 128u / 16u); + auto v128u32 = llvm::ArrayType::get(u32, 128u / 32u); + auto v128u64 = llvm::ArrayType::get(u64, 128u / 64u); + auto v128u128 = llvm::ArrayType::get(u128, 128u / 128u); + + auto addr = u64; + auto zero_u32 = llvm::Constant::getNullValue(u32); + auto zero_u64 = llvm::Constant::getNullValue(u64); + + const auto entry_block = &bb_func->getEntryBlock(); + llvm::IRBuilder<> ir(entry_block); + + REG(X0, gpr.x0.qword, u64); + REG(X1, gpr.x1.qword, u64); + REG(X2, gpr.x2.qword, u64); + REG(X3, gpr.x3.qword, u64); + REG(X4, gpr.x4.qword, u64); + REG(X5, gpr.x5.qword, u64); + REG(X6, gpr.x6.qword, u64); + REG(X7, gpr.x7.qword, u64); + REG(X8, gpr.x8.qword, u64); + REG(X9, gpr.x9.qword, u64); + REG(X10, gpr.x10.qword, u64); + REG(X11, gpr.x11.qword, u64); + REG(X12, gpr.x12.qword, u64); + REG(X13, gpr.x13.qword, u64); + REG(X14, gpr.x14.qword, u64); + REG(X15, gpr.x15.qword, u64); + REG(X16, gpr.x16.qword, u64); + REG(X17, gpr.x17.qword, u64); + REG(X18, gpr.x18.qword, u64); + REG(X19, gpr.x19.qword, u64); + REG(X20, gpr.x20.qword, u64); + REG(X21, gpr.x21.qword, u64); + REG(X22, gpr.x22.qword, u64); + REG(X23, gpr.x23.qword, u64); + REG(X24, gpr.x24.qword, u64); + REG(X25, gpr.x25.qword, u64); + REG(X26, gpr.x26.qword, u64); + REG(X27, gpr.x27.qword, u64); + REG(X28, gpr.x28.qword, u64); + REG(X29, gpr.x29.qword, u64); + REG(X30, gpr.x30.qword, u64); + + SUB_REG(W0, gpr.x0.dword, u32, X0); + SUB_REG(W1, gpr.x1.dword, u32, X1); + SUB_REG(W2, gpr.x2.dword, u32, X2); + SUB_REG(W3, gpr.x3.dword, u32, X3); + SUB_REG(W4, gpr.x4.dword, u32, X4); + SUB_REG(W5, gpr.x5.dword, u32, X5); + SUB_REG(W6, gpr.x6.dword, u32, X6); + SUB_REG(W7, gpr.x7.dword, u32, X7); + SUB_REG(W8, gpr.x8.dword, u32, X8); + SUB_REG(W9, gpr.x9.dword, u32, X9); + SUB_REG(W10, gpr.x10.dword, u32, X10); + SUB_REG(W11, gpr.x11.dword, u32, X11); + SUB_REG(W12, gpr.x12.dword, u32, X12); + SUB_REG(W13, gpr.x13.dword, u32, X13); + SUB_REG(W14, gpr.x14.dword, u32, X14); + SUB_REG(W15, gpr.x15.dword, u32, X15); + SUB_REG(W16, gpr.x16.dword, u32, X16); + SUB_REG(W17, gpr.x17.dword, u32, X17); + SUB_REG(W18, gpr.x18.dword, u32, X18); + SUB_REG(W19, gpr.x19.dword, u32, X19); + SUB_REG(W20, gpr.x20.dword, u32, X20); + SUB_REG(W21, gpr.x21.dword, u32, X21); + SUB_REG(W22, gpr.x22.dword, u32, X22); + SUB_REG(W23, gpr.x23.dword, u32, X23); + SUB_REG(W24, gpr.x24.dword, u32, X24); + SUB_REG(W25, gpr.x25.dword, u32, X25); + SUB_REG(W26, gpr.x26.dword, u32, X26); + SUB_REG(W27, gpr.x27.dword, u32, X27); + SUB_REG(W28, gpr.x28.dword, u32, X28); + SUB_REG(W29, gpr.x29.dword, u32, X29); + SUB_REG(W30, gpr.x30.dword, u32, X30); + + REG(PC, gpr.pc.qword, u64); + SUB_REG(WPC, gpr.pc.dword, u32, PC); + + REG(SP, gpr.sp.qword, u64); + SUB_REG(WSP, gpr.sp.dword, u32, SP); + + SUB_REG(LP, gpr.x30.qword, u32, X30); + SUB_REG(WLP, gpr.x30.dword, u32, LP); + + REG(V0, simd.v[0].bytes.elems[0], v128u8); + REG(V1, simd.v[1].bytes.elems[0], v128u8); + REG(V2, simd.v[2].bytes.elems[0], v128u8); + REG(V3, simd.v[3].bytes.elems[0], v128u8); + REG(V4, simd.v[4].bytes.elems[0], v128u8); + REG(V5, simd.v[5].bytes.elems[0], v128u8); + REG(V6, simd.v[6].bytes.elems[0], v128u8); + REG(V7, simd.v[7].bytes.elems[0], v128u8); + REG(V8, simd.v[8].bytes.elems[0], v128u8); + REG(V9, simd.v[9].bytes.elems[0], v128u8); + REG(V10, simd.v[10].bytes.elems[0], v128u8); + REG(V11, simd.v[11].bytes.elems[0], v128u8); + REG(V12, simd.v[12].bytes.elems[0], v128u8); + REG(V13, simd.v[13].bytes.elems[0], v128u8); + REG(V14, simd.v[14].bytes.elems[0], v128u8); + REG(V15, simd.v[15].bytes.elems[0], v128u8); + REG(V16, simd.v[16].bytes.elems[0], v128u8); + REG(V17, simd.v[17].bytes.elems[0], v128u8); + REG(V18, simd.v[18].bytes.elems[0], v128u8); + REG(V19, simd.v[19].bytes.elems[0], v128u8); + REG(V20, simd.v[20].bytes.elems[0], v128u8); + REG(V21, simd.v[21].bytes.elems[0], v128u8); + REG(V22, simd.v[22].bytes.elems[0], v128u8); + REG(V23, simd.v[23].bytes.elems[0], v128u8); + REG(V24, simd.v[24].bytes.elems[0], v128u8); + REG(V25, simd.v[25].bytes.elems[0], v128u8); + REG(V26, simd.v[26].bytes.elems[0], v128u8); + REG(V27, simd.v[27].bytes.elems[0], v128u8); + REG(V28, simd.v[28].bytes.elems[0], v128u8); + REG(V29, simd.v[29].bytes.elems[0], v128u8); + REG(V30, simd.v[30].bytes.elems[0], v128u8); + REG(V31, simd.v[31].bytes.elems[0], v128u8); + + SUB_REG(B0, simd.v[0].bytes.elems[0], v128u8, V0); + SUB_REG(B1, simd.v[1].bytes.elems[0], v128u8, V1); + SUB_REG(B2, simd.v[2].bytes.elems[0], v128u8, V2); + SUB_REG(B3, simd.v[3].bytes.elems[0], v128u8, V3); + SUB_REG(B4, simd.v[4].bytes.elems[0], v128u8, V4); + SUB_REG(B5, simd.v[5].bytes.elems[0], v128u8, V5); + SUB_REG(B6, simd.v[6].bytes.elems[0], v128u8, V6); + SUB_REG(B7, simd.v[7].bytes.elems[0], v128u8, V7); + SUB_REG(B8, simd.v[8].bytes.elems[0], v128u8, V8); + SUB_REG(B9, simd.v[9].bytes.elems[0], v128u8, V9); + SUB_REG(B10, simd.v[10].bytes.elems[0], v128u8, V10); + SUB_REG(B11, simd.v[11].bytes.elems[0], v128u8, V11); + SUB_REG(B12, simd.v[12].bytes.elems[0], v128u8, V12); + SUB_REG(B13, simd.v[13].bytes.elems[0], v128u8, V13); + SUB_REG(B14, simd.v[14].bytes.elems[0], v128u8, V14); + SUB_REG(B15, simd.v[15].bytes.elems[0], v128u8, V15); + SUB_REG(B16, simd.v[16].bytes.elems[0], v128u8, V16); + SUB_REG(B17, simd.v[17].bytes.elems[0], v128u8, V17); + SUB_REG(B18, simd.v[18].bytes.elems[0], v128u8, V18); + SUB_REG(B19, simd.v[19].bytes.elems[0], v128u8, V19); + SUB_REG(B20, simd.v[20].bytes.elems[0], v128u8, V20); + SUB_REG(B21, simd.v[21].bytes.elems[0], v128u8, V21); + SUB_REG(B22, simd.v[22].bytes.elems[0], v128u8, V22); + SUB_REG(B23, simd.v[23].bytes.elems[0], v128u8, V23); + SUB_REG(B24, simd.v[24].bytes.elems[0], v128u8, V24); + SUB_REG(B25, simd.v[25].bytes.elems[0], v128u8, V25); + SUB_REG(B26, simd.v[26].bytes.elems[0], v128u8, V26); + SUB_REG(B27, simd.v[27].bytes.elems[0], v128u8, V27); + SUB_REG(B28, simd.v[28].bytes.elems[0], v128u8, V28); + SUB_REG(B29, simd.v[29].bytes.elems[0], v128u8, V29); + SUB_REG(B30, simd.v[30].bytes.elems[0], v128u8, V30); + SUB_REG(B31, simd.v[31].bytes.elems[0], v128u8, V31); + + SUB_REG(H0, simd.v[0].words.elems[0], v128u16, V0); + SUB_REG(H1, simd.v[1].words.elems[0], v128u16, V1); + SUB_REG(H2, simd.v[2].words.elems[0], v128u16, V2); + SUB_REG(H3, simd.v[3].words.elems[0], v128u16, V3); + SUB_REG(H4, simd.v[4].words.elems[0], v128u16, V4); + SUB_REG(H5, simd.v[5].words.elems[0], v128u16, V5); + SUB_REG(H6, simd.v[6].words.elems[0], v128u16, V6); + SUB_REG(H7, simd.v[7].words.elems[0], v128u16, V7); + SUB_REG(H8, simd.v[8].words.elems[0], v128u16, V8); + SUB_REG(H9, simd.v[9].words.elems[0], v128u16, V9); + SUB_REG(H10, simd.v[10].words.elems[0], v128u16, V10); + SUB_REG(H11, simd.v[11].words.elems[0], v128u16, V11); + SUB_REG(H12, simd.v[12].words.elems[0], v128u16, V12); + SUB_REG(H13, simd.v[13].words.elems[0], v128u16, V13); + SUB_REG(H14, simd.v[14].words.elems[0], v128u16, V14); + SUB_REG(H15, simd.v[15].words.elems[0], v128u16, V15); + SUB_REG(H16, simd.v[16].words.elems[0], v128u16, V16); + SUB_REG(H17, simd.v[17].words.elems[0], v128u16, V17); + SUB_REG(H18, simd.v[18].words.elems[0], v128u16, V18); + SUB_REG(H19, simd.v[19].words.elems[0], v128u16, V19); + SUB_REG(H20, simd.v[20].words.elems[0], v128u16, V20); + SUB_REG(H21, simd.v[21].words.elems[0], v128u16, V21); + SUB_REG(H22, simd.v[22].words.elems[0], v128u16, V22); + SUB_REG(H23, simd.v[23].words.elems[0], v128u16, V23); + SUB_REG(H24, simd.v[24].words.elems[0], v128u16, V24); + SUB_REG(H25, simd.v[25].words.elems[0], v128u16, V25); + SUB_REG(H26, simd.v[26].words.elems[0], v128u16, V26); + SUB_REG(H27, simd.v[27].words.elems[0], v128u16, V27); + SUB_REG(H28, simd.v[28].words.elems[0], v128u16, V28); + SUB_REG(H29, simd.v[29].words.elems[0], v128u16, V29); + SUB_REG(H30, simd.v[30].words.elems[0], v128u16, V30); + SUB_REG(H31, simd.v[31].words.elems[0], v128u16, V31); + + SUB_REG(S0, simd.v[0].dwords.elems[0], v128u32, V0); + SUB_REG(S1, simd.v[1].dwords.elems[0], v128u32, V1); + SUB_REG(S2, simd.v[2].dwords.elems[0], v128u32, V2); + SUB_REG(S3, simd.v[3].dwords.elems[0], v128u32, V3); + SUB_REG(S4, simd.v[4].dwords.elems[0], v128u32, V4); + SUB_REG(S5, simd.v[5].dwords.elems[0], v128u32, V5); + SUB_REG(S6, simd.v[6].dwords.elems[0], v128u32, V6); + SUB_REG(S7, simd.v[7].dwords.elems[0], v128u32, V7); + SUB_REG(S8, simd.v[8].dwords.elems[0], v128u32, V8); + SUB_REG(S9, simd.v[9].dwords.elems[0], v128u32, V9); + SUB_REG(S10, simd.v[10].dwords.elems[0], v128u32, V10); + SUB_REG(S11, simd.v[11].dwords.elems[0], v128u32, V11); + SUB_REG(S12, simd.v[12].dwords.elems[0], v128u32, V12); + SUB_REG(S13, simd.v[13].dwords.elems[0], v128u32, V13); + SUB_REG(S14, simd.v[14].dwords.elems[0], v128u32, V14); + SUB_REG(S15, simd.v[15].dwords.elems[0], v128u32, V15); + SUB_REG(S16, simd.v[16].dwords.elems[0], v128u32, V16); + SUB_REG(S17, simd.v[17].dwords.elems[0], v128u32, V17); + SUB_REG(S18, simd.v[18].dwords.elems[0], v128u32, V18); + SUB_REG(S19, simd.v[19].dwords.elems[0], v128u32, V19); + SUB_REG(S20, simd.v[20].dwords.elems[0], v128u32, V20); + SUB_REG(S21, simd.v[21].dwords.elems[0], v128u32, V21); + SUB_REG(S22, simd.v[22].dwords.elems[0], v128u32, V22); + SUB_REG(S23, simd.v[23].dwords.elems[0], v128u32, V23); + SUB_REG(S24, simd.v[24].dwords.elems[0], v128u32, V24); + SUB_REG(S25, simd.v[25].dwords.elems[0], v128u32, V25); + SUB_REG(S26, simd.v[26].dwords.elems[0], v128u32, V26); + SUB_REG(S27, simd.v[27].dwords.elems[0], v128u32, V27); + SUB_REG(S28, simd.v[28].dwords.elems[0], v128u32, V28); + SUB_REG(S29, simd.v[29].dwords.elems[0], v128u32, V29); + SUB_REG(S30, simd.v[30].dwords.elems[0], v128u32, V30); + SUB_REG(S31, simd.v[31].dwords.elems[0], v128u32, V31); + + SUB_REG(D0, simd.v[0].qwords.elems[0], v128u64, V0); + SUB_REG(D1, simd.v[1].qwords.elems[0], v128u64, V1); + SUB_REG(D2, simd.v[2].qwords.elems[0], v128u64, V2); + SUB_REG(D3, simd.v[3].qwords.elems[0], v128u64, V3); + SUB_REG(D4, simd.v[4].qwords.elems[0], v128u64, V4); + SUB_REG(D5, simd.v[5].qwords.elems[0], v128u64, V5); + SUB_REG(D6, simd.v[6].qwords.elems[0], v128u64, V6); + SUB_REG(D7, simd.v[7].qwords.elems[0], v128u64, V7); + SUB_REG(D8, simd.v[8].qwords.elems[0], v128u64, V8); + SUB_REG(D9, simd.v[9].qwords.elems[0], v128u64, V9); + SUB_REG(D10, simd.v[10].qwords.elems[0], v128u64, V10); + SUB_REG(D11, simd.v[11].qwords.elems[0], v128u64, V11); + SUB_REG(D12, simd.v[12].qwords.elems[0], v128u64, V12); + SUB_REG(D13, simd.v[13].qwords.elems[0], v128u64, V13); + SUB_REG(D14, simd.v[14].qwords.elems[0], v128u64, V14); + SUB_REG(D15, simd.v[15].qwords.elems[0], v128u64, V15); + SUB_REG(D16, simd.v[16].qwords.elems[0], v128u64, V16); + SUB_REG(D17, simd.v[17].qwords.elems[0], v128u64, V17); + SUB_REG(D18, simd.v[18].qwords.elems[0], v128u64, V18); + SUB_REG(D19, simd.v[19].qwords.elems[0], v128u64, V19); + SUB_REG(D20, simd.v[20].qwords.elems[0], v128u64, V20); + SUB_REG(D21, simd.v[21].qwords.elems[0], v128u64, V21); + SUB_REG(D22, simd.v[22].qwords.elems[0], v128u64, V22); + SUB_REG(D23, simd.v[23].qwords.elems[0], v128u64, V23); + SUB_REG(D24, simd.v[24].qwords.elems[0], v128u64, V24); + SUB_REG(D25, simd.v[25].qwords.elems[0], v128u64, V25); + SUB_REG(D26, simd.v[26].qwords.elems[0], v128u64, V26); + SUB_REG(D27, simd.v[27].qwords.elems[0], v128u64, V27); + SUB_REG(D28, simd.v[28].qwords.elems[0], v128u64, V28); + SUB_REG(D29, simd.v[29].qwords.elems[0], v128u64, V29); + SUB_REG(D30, simd.v[30].qwords.elems[0], v128u64, V30); + SUB_REG(D31, simd.v[31].qwords.elems[0], v128u64, V31); + + SUB_REG(Q0, simd.v[0].dqwords.elems[0], v128u128, V0); + SUB_REG(Q1, simd.v[1].dqwords.elems[0], v128u128, V1); + SUB_REG(Q2, simd.v[2].dqwords.elems[0], v128u128, V2); + SUB_REG(Q3, simd.v[3].dqwords.elems[0], v128u128, V3); + SUB_REG(Q4, simd.v[4].dqwords.elems[0], v128u128, V4); + SUB_REG(Q5, simd.v[5].dqwords.elems[0], v128u128, V5); + SUB_REG(Q6, simd.v[6].dqwords.elems[0], v128u128, V6); + SUB_REG(Q7, simd.v[7].dqwords.elems[0], v128u128, V7); + SUB_REG(Q8, simd.v[8].dqwords.elems[0], v128u128, V8); + SUB_REG(Q9, simd.v[9].dqwords.elems[0], v128u128, V9); + SUB_REG(Q10, simd.v[10].dqwords.elems[0], v128u128, V10); + SUB_REG(Q11, simd.v[11].dqwords.elems[0], v128u128, V11); + SUB_REG(Q12, simd.v[12].dqwords.elems[0], v128u128, V12); + SUB_REG(Q13, simd.v[13].dqwords.elems[0], v128u128, V13); + SUB_REG(Q14, simd.v[14].dqwords.elems[0], v128u128, V14); + SUB_REG(Q15, simd.v[15].dqwords.elems[0], v128u128, V15); + SUB_REG(Q16, simd.v[16].dqwords.elems[0], v128u128, V16); + SUB_REG(Q17, simd.v[17].dqwords.elems[0], v128u128, V17); + SUB_REG(Q18, simd.v[18].dqwords.elems[0], v128u128, V18); + SUB_REG(Q19, simd.v[19].dqwords.elems[0], v128u128, V19); + SUB_REG(Q20, simd.v[20].dqwords.elems[0], v128u128, V20); + SUB_REG(Q21, simd.v[21].dqwords.elems[0], v128u128, V21); + SUB_REG(Q22, simd.v[22].dqwords.elems[0], v128u128, V22); + SUB_REG(Q23, simd.v[23].dqwords.elems[0], v128u128, V23); + SUB_REG(Q24, simd.v[24].dqwords.elems[0], v128u128, V24); + SUB_REG(Q25, simd.v[25].dqwords.elems[0], v128u128, V25); + SUB_REG(Q26, simd.v[26].dqwords.elems[0], v128u128, V26); + SUB_REG(Q27, simd.v[27].dqwords.elems[0], v128u128, V27); + SUB_REG(Q28, simd.v[28].dqwords.elems[0], v128u128, V28); + SUB_REG(Q29, simd.v[29].dqwords.elems[0], v128u128, V29); + SUB_REG(Q30, simd.v[30].dqwords.elems[0], v128u128, V30); + SUB_REG(Q31, simd.v[31].dqwords.elems[0], v128u128, V31); + + REG(TPIDR_EL0, sr.tpidr_el0.qword, u64); + REG(TPIDRRO_EL0, sr.tpidrro_el0.qword, u64); + + const auto pc_arg = NthArgument(bb_func, kPCArgNum); + const auto state_ptr_arg = NthArgument(bb_func, kStatePointerArgNum); + ir.CreateStore(pc_arg, ir.CreateAlloca(addr, nullptr, "NEXT_PC")); + + ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "WZR")); + ir.CreateStore(zero_u64, ir.CreateAlloca(u64, nullptr, "XZR")); + ir.CreateAlloca(u32, nullptr, "IGNORE_WRITE_TO_WZR"); + ir.CreateAlloca(u64, nullptr, "IGNORE_WRITE_TO_XZR"); + ir.CreateAlloca(u64, nullptr, "SUPPRESS_WRITEBACK"); + (void) this->RegisterByName("PC")->AddressOf(state_ptr_arg, ir); +} + // Maximum number of bytes in an instruction for this particular architecture. uint64_t AArch64Arch::MaxInstructionSize(void) const { return 4; diff --git a/remill/Arch/AArch64/Runtime/BasicBlock.cpp b/remill/Arch/AArch64/Runtime/BasicBlock.cpp index 3567c9702..2b939300b 100644 --- a/remill/Arch/AArch64/Runtime/BasicBlock.cpp +++ b/remill/Arch/AArch64/Runtime/BasicBlock.cpp @@ -27,341 +27,7 @@ extern "C" { #pragma clang diagnostic ignored "-Wunused-variable" // Instructions will be lifted into clones of this function. -[[gnu::used]] Memory *__remill_basic_block(State &state, addr_t curr_pc, - Memory *memory) { - bool branch_taken = false; - addr_t monitor = 0; - addr_t return_pc = 0; - - // Note: These variables MUST be defined for all architectures. - auto &STATE = state; - auto &MEMORY = *memory; - auto &PC = state.gpr.pc.qword; - auto &NEXT_PC = curr_pc; - auto &BRANCH_TAKEN = branch_taken; - auto &RETURN_PC = return_pc; - - // `PC` should already have the correct value, but it's nice to make sure - // that `curr_pc` is used throughout, as it helps with certain downstream - // uses to be able to depend on the optimizer not eliminating `curr_pc`. - state.gpr.pc.qword = curr_pc; - - auto &WPC = state.gpr.pc.dword; - - // This is to support load-linked/store-conditional operations. - auto &MONITOR = monitor; - - auto &W0 = state.gpr.x0.dword; - auto &W1 = state.gpr.x1.dword; - auto &W2 = state.gpr.x2.dword; - auto &W3 = state.gpr.x3.dword; - - auto &W4 = state.gpr.x4.dword; - auto &W5 = state.gpr.x5.dword; - auto &W6 = state.gpr.x6.dword; - auto &W7 = state.gpr.x7.dword; - - auto &W8 = state.gpr.x8.dword; - auto &W9 = state.gpr.x9.dword; - auto &W10 = state.gpr.x10.dword; - auto &W11 = state.gpr.x11.dword; - - auto &W12 = state.gpr.x12.dword; - auto &W13 = state.gpr.x13.dword; - auto &W14 = state.gpr.x14.dword; - auto &W15 = state.gpr.x15.dword; - - auto &W16 = state.gpr.x16.dword; - auto &W17 = state.gpr.x17.dword; - auto &W18 = state.gpr.x18.dword; - auto &W19 = state.gpr.x19.dword; - - auto &W20 = state.gpr.x20.dword; - auto &W21 = state.gpr.x21.dword; - auto &W22 = state.gpr.x22.dword; - auto &W23 = state.gpr.x23.dword; - - auto &W24 = state.gpr.x24.dword; - auto &W25 = state.gpr.x25.dword; - auto &W26 = state.gpr.x26.dword; - auto &W27 = state.gpr.x27.dword; - - auto &W28 = state.gpr.x28.dword; - auto &W29 = state.gpr.x29.dword; - auto &W30 = state.gpr.x30.dword; - - auto &X0 = state.gpr.x0.qword; - auto &X1 = state.gpr.x1.qword; - auto &X2 = state.gpr.x2.qword; - auto &X3 = state.gpr.x3.qword; - - auto &X4 = state.gpr.x4.qword; - auto &X5 = state.gpr.x5.qword; - auto &X6 = state.gpr.x6.qword; - auto &X7 = state.gpr.x7.qword; - - auto &X8 = state.gpr.x8.qword; - auto &X9 = state.gpr.x9.qword; - auto &X10 = state.gpr.x10.qword; - auto &X11 = state.gpr.x11.qword; - - auto &X12 = state.gpr.x12.qword; - auto &X13 = state.gpr.x13.qword; - auto &X14 = state.gpr.x14.qword; - auto &X15 = state.gpr.x15.qword; - - auto &X16 = state.gpr.x16.qword; - auto &X17 = state.gpr.x17.qword; - auto &X18 = state.gpr.x18.qword; - auto &X19 = state.gpr.x19.qword; - - auto &X20 = state.gpr.x20.qword; - auto &X21 = state.gpr.x21.qword; - auto &X22 = state.gpr.x22.qword; - auto &X23 = state.gpr.x23.qword; - - auto &X24 = state.gpr.x24.qword; - auto &X25 = state.gpr.x25.qword; - auto &X26 = state.gpr.x26.qword; - auto &X27 = state.gpr.x27.qword; - - auto &X28 = state.gpr.x28.qword; - auto &X29 = state.gpr.x29.qword; - auto &X30 = state.gpr.x30.qword; - - auto &FP = state.gpr.x29.qword; - auto &WFP = state.gpr.x29.dword; - - auto &LP = state.gpr.x30.qword; - auto &WLP = state.gpr.x30.dword; - - auto &SP = state.gpr.sp.qword; - auto &WSP = state.gpr.sp.dword; - - uint32_t zero1 = 0; - auto &WZR = zero1; - - uint64_t zero2 = 0; - auto &XZR = zero2; - - uint32_t ignored1 = 0; - auto &IGNORE_WRITE_TO_WZR = ignored1; - - uint64_t ignored2 = 0; - auto &IGNORE_WRITE_TO_XZR = ignored2; - - // Used to suppress writeback for pre- and post-index memory operands when - // the base register and destination register are the same. - uint64_t ignored3 = 0; - auto &SUPPRESS_WRITEBACK = ignored3; - - auto &B0 = state.simd.v[0].bytes.elems[0]; - auto &B1 = state.simd.v[1].bytes.elems[0]; - auto &B2 = state.simd.v[2].bytes.elems[0]; - auto &B3 = state.simd.v[3].bytes.elems[0]; - auto &B4 = state.simd.v[4].bytes.elems[0]; - auto &B5 = state.simd.v[5].bytes.elems[0]; - auto &B6 = state.simd.v[6].bytes.elems[0]; - auto &B7 = state.simd.v[7].bytes.elems[0]; - auto &B8 = state.simd.v[8].bytes.elems[0]; - auto &B9 = state.simd.v[9].bytes.elems[0]; - auto &B10 = state.simd.v[10].bytes.elems[0]; - auto &B11 = state.simd.v[11].bytes.elems[0]; - auto &B12 = state.simd.v[12].bytes.elems[0]; - auto &B13 = state.simd.v[13].bytes.elems[0]; - auto &B14 = state.simd.v[14].bytes.elems[0]; - auto &B15 = state.simd.v[15].bytes.elems[0]; - auto &B16 = state.simd.v[16].bytes.elems[0]; - auto &B17 = state.simd.v[17].bytes.elems[0]; - auto &B18 = state.simd.v[18].bytes.elems[0]; - auto &B19 = state.simd.v[19].bytes.elems[0]; - auto &B20 = state.simd.v[20].bytes.elems[0]; - auto &B21 = state.simd.v[21].bytes.elems[0]; - auto &B22 = state.simd.v[22].bytes.elems[0]; - auto &B23 = state.simd.v[23].bytes.elems[0]; - auto &B24 = state.simd.v[24].bytes.elems[0]; - auto &B25 = state.simd.v[25].bytes.elems[0]; - auto &B26 = state.simd.v[26].bytes.elems[0]; - auto &B27 = state.simd.v[27].bytes.elems[0]; - auto &B28 = state.simd.v[28].bytes.elems[0]; - auto &B29 = state.simd.v[29].bytes.elems[0]; - auto &B30 = state.simd.v[30].bytes.elems[0]; - auto &B31 = state.simd.v[31].bytes.elems[0]; - - // NOTE(pag): These are kind of a lie: they are there to support load/store - // of half-words, but they don't have a 16-bit float data - // representation. - auto &H0 = state.simd.v[0].words.elems[0]; - auto &H1 = state.simd.v[1].words.elems[0]; - auto &H2 = state.simd.v[2].words.elems[0]; - auto &H3 = state.simd.v[3].words.elems[0]; - auto &H4 = state.simd.v[4].words.elems[0]; - auto &H5 = state.simd.v[5].words.elems[0]; - auto &H6 = state.simd.v[6].words.elems[0]; - auto &H7 = state.simd.v[7].words.elems[0]; - auto &H8 = state.simd.v[8].words.elems[0]; - auto &H9 = state.simd.v[9].words.elems[0]; - auto &H10 = state.simd.v[10].words.elems[0]; - auto &H11 = state.simd.v[11].words.elems[0]; - auto &H12 = state.simd.v[12].words.elems[0]; - auto &H13 = state.simd.v[13].words.elems[0]; - auto &H14 = state.simd.v[14].words.elems[0]; - auto &H15 = state.simd.v[15].words.elems[0]; - auto &H16 = state.simd.v[16].words.elems[0]; - auto &H17 = state.simd.v[17].words.elems[0]; - auto &H18 = state.simd.v[18].words.elems[0]; - auto &H19 = state.simd.v[19].words.elems[0]; - auto &H20 = state.simd.v[20].words.elems[0]; - auto &H21 = state.simd.v[21].words.elems[0]; - auto &H22 = state.simd.v[22].words.elems[0]; - auto &H23 = state.simd.v[23].words.elems[0]; - auto &H24 = state.simd.v[24].words.elems[0]; - auto &H25 = state.simd.v[25].words.elems[0]; - auto &H26 = state.simd.v[26].words.elems[0]; - auto &H27 = state.simd.v[27].words.elems[0]; - auto &H28 = state.simd.v[28].words.elems[0]; - auto &H29 = state.simd.v[29].words.elems[0]; - auto &H30 = state.simd.v[30].words.elems[0]; - auto &H31 = state.simd.v[31].words.elems[0]; - - auto &S0 = state.simd.v[0].dwords.elems[0]; - auto &S1 = state.simd.v[1].dwords.elems[0]; - auto &S2 = state.simd.v[2].dwords.elems[0]; - auto &S3 = state.simd.v[3].dwords.elems[0]; - auto &S4 = state.simd.v[4].dwords.elems[0]; - auto &S5 = state.simd.v[5].dwords.elems[0]; - auto &S6 = state.simd.v[6].dwords.elems[0]; - auto &S7 = state.simd.v[7].dwords.elems[0]; - auto &S8 = state.simd.v[8].dwords.elems[0]; - auto &S9 = state.simd.v[9].dwords.elems[0]; - auto &S10 = state.simd.v[10].dwords.elems[0]; - auto &S11 = state.simd.v[11].dwords.elems[0]; - auto &S12 = state.simd.v[12].dwords.elems[0]; - auto &S13 = state.simd.v[13].dwords.elems[0]; - auto &S14 = state.simd.v[14].dwords.elems[0]; - auto &S15 = state.simd.v[15].dwords.elems[0]; - auto &S16 = state.simd.v[16].dwords.elems[0]; - auto &S17 = state.simd.v[17].dwords.elems[0]; - auto &S18 = state.simd.v[18].dwords.elems[0]; - auto &S19 = state.simd.v[19].dwords.elems[0]; - auto &S20 = state.simd.v[20].dwords.elems[0]; - auto &S21 = state.simd.v[21].dwords.elems[0]; - auto &S22 = state.simd.v[22].dwords.elems[0]; - auto &S23 = state.simd.v[23].dwords.elems[0]; - auto &S24 = state.simd.v[24].dwords.elems[0]; - auto &S25 = state.simd.v[25].dwords.elems[0]; - auto &S26 = state.simd.v[26].dwords.elems[0]; - auto &S27 = state.simd.v[27].dwords.elems[0]; - auto &S28 = state.simd.v[28].dwords.elems[0]; - auto &S29 = state.simd.v[29].dwords.elems[0]; - auto &S30 = state.simd.v[30].dwords.elems[0]; - auto &S31 = state.simd.v[31].dwords.elems[0]; - - auto &D0 = state.simd.v[0].qwords.elems[0]; - auto &D1 = state.simd.v[1].qwords.elems[0]; - auto &D2 = state.simd.v[2].qwords.elems[0]; - auto &D3 = state.simd.v[3].qwords.elems[0]; - auto &D4 = state.simd.v[4].qwords.elems[0]; - auto &D5 = state.simd.v[5].qwords.elems[0]; - auto &D6 = state.simd.v[6].qwords.elems[0]; - auto &D7 = state.simd.v[7].qwords.elems[0]; - auto &D8 = state.simd.v[8].qwords.elems[0]; - auto &D9 = state.simd.v[9].qwords.elems[0]; - auto &D10 = state.simd.v[10].qwords.elems[0]; - auto &D11 = state.simd.v[11].qwords.elems[0]; - auto &D12 = state.simd.v[12].qwords.elems[0]; - auto &D13 = state.simd.v[13].qwords.elems[0]; - auto &D14 = state.simd.v[14].qwords.elems[0]; - auto &D15 = state.simd.v[15].qwords.elems[0]; - auto &D16 = state.simd.v[16].qwords.elems[0]; - auto &D17 = state.simd.v[17].qwords.elems[0]; - auto &D18 = state.simd.v[18].qwords.elems[0]; - auto &D19 = state.simd.v[19].qwords.elems[0]; - auto &D20 = state.simd.v[20].qwords.elems[0]; - auto &D21 = state.simd.v[21].qwords.elems[0]; - auto &D22 = state.simd.v[22].qwords.elems[0]; - auto &D23 = state.simd.v[23].qwords.elems[0]; - auto &D24 = state.simd.v[24].qwords.elems[0]; - auto &D25 = state.simd.v[25].qwords.elems[0]; - auto &D26 = state.simd.v[26].qwords.elems[0]; - auto &D27 = state.simd.v[27].qwords.elems[0]; - auto &D28 = state.simd.v[28].qwords.elems[0]; - auto &D29 = state.simd.v[29].qwords.elems[0]; - auto &D30 = state.simd.v[30].qwords.elems[0]; - auto &D31 = state.simd.v[31].qwords.elems[0]; - - auto &Q0 = state.simd.v[0].dqwords.elems[0]; - auto &Q1 = state.simd.v[1].dqwords.elems[0]; - auto &Q2 = state.simd.v[2].dqwords.elems[0]; - auto &Q3 = state.simd.v[3].dqwords.elems[0]; - auto &Q4 = state.simd.v[4].dqwords.elems[0]; - auto &Q5 = state.simd.v[5].dqwords.elems[0]; - auto &Q6 = state.simd.v[6].dqwords.elems[0]; - auto &Q7 = state.simd.v[7].dqwords.elems[0]; - auto &Q8 = state.simd.v[8].dqwords.elems[0]; - auto &Q9 = state.simd.v[9].dqwords.elems[0]; - auto &Q10 = state.simd.v[10].dqwords.elems[0]; - auto &Q11 = state.simd.v[11].dqwords.elems[0]; - auto &Q12 = state.simd.v[12].dqwords.elems[0]; - auto &Q13 = state.simd.v[13].dqwords.elems[0]; - auto &Q14 = state.simd.v[14].dqwords.elems[0]; - auto &Q15 = state.simd.v[15].dqwords.elems[0]; - auto &Q16 = state.simd.v[16].dqwords.elems[0]; - auto &Q17 = state.simd.v[17].dqwords.elems[0]; - auto &Q18 = state.simd.v[18].dqwords.elems[0]; - auto &Q19 = state.simd.v[19].dqwords.elems[0]; - auto &Q20 = state.simd.v[20].dqwords.elems[0]; - auto &Q21 = state.simd.v[21].dqwords.elems[0]; - auto &Q22 = state.simd.v[22].dqwords.elems[0]; - auto &Q23 = state.simd.v[23].dqwords.elems[0]; - auto &Q24 = state.simd.v[24].dqwords.elems[0]; - auto &Q25 = state.simd.v[25].dqwords.elems[0]; - auto &Q26 = state.simd.v[26].dqwords.elems[0]; - auto &Q27 = state.simd.v[27].dqwords.elems[0]; - auto &Q28 = state.simd.v[28].dqwords.elems[0]; - auto &Q29 = state.simd.v[29].dqwords.elems[0]; - auto &Q30 = state.simd.v[30].dqwords.elems[0]; - auto &Q31 = state.simd.v[31].dqwords.elems[0]; - - auto &V0 = state.simd.v[0]; - auto &V1 = state.simd.v[1]; - auto &V2 = state.simd.v[2]; - auto &V3 = state.simd.v[3]; - auto &V4 = state.simd.v[4]; - auto &V5 = state.simd.v[5]; - auto &V6 = state.simd.v[6]; - auto &V7 = state.simd.v[7]; - auto &V8 = state.simd.v[8]; - auto &V9 = state.simd.v[9]; - auto &V10 = state.simd.v[10]; - auto &V11 = state.simd.v[11]; - auto &V12 = state.simd.v[12]; - auto &V13 = state.simd.v[13]; - auto &V14 = state.simd.v[14]; - auto &V15 = state.simd.v[15]; - auto &V16 = state.simd.v[16]; - auto &V17 = state.simd.v[17]; - auto &V18 = state.simd.v[18]; - auto &V19 = state.simd.v[19]; - auto &V20 = state.simd.v[20]; - auto &V21 = state.simd.v[21]; - auto &V22 = state.simd.v[22]; - auto &V23 = state.simd.v[23]; - auto &V24 = state.simd.v[24]; - auto &V25 = state.simd.v[25]; - auto &V26 = state.simd.v[26]; - auto &V27 = state.simd.v[27]; - auto &V28 = state.simd.v[28]; - auto &V29 = state.simd.v[29]; - auto &V30 = state.simd.v[30]; - auto &V31 = state.simd.v[31]; - - auto &TPIDR_EL0 = state.sr.tpidr_el0.aword; - auto &TPIDRRO_EL0 = state.sr.tpidrro_el0.aword; - - // Lifted code will be placed here in clones versions of this function. - return memory; -} +[[gnu::used]] Memory *__remill_basic_block(State &, addr_t, Memory *); #pragma clang diagnostic pop diff --git a/remill/Arch/AArch64/Runtime/Instructions.cpp b/remill/Arch/AArch64/Runtime/Instructions.cpp index b15438370..34673329d 100644 --- a/remill/Arch/AArch64/Runtime/Instructions.cpp +++ b/remill/Arch/AArch64/Runtime/Instructions.cpp @@ -25,6 +25,7 @@ #include "remill/Arch/AArch64/Runtime/State.h" #include "remill/Arch/AArch64/Runtime/Types.h" #include "remill/Arch/AArch64/Runtime/Operators.h" + // clang-format on #define REG_PC state.gpr.pc.qword @@ -116,4 +117,5 @@ DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; #include "remill/Arch/AArch64/Semantics/SHIFT.cpp" #include "remill/Arch/AArch64/Semantics/SIMD.cpp" #include "remill/Arch/AArch64/Semantics/SYSTEM.cpp" + // clang-format on diff --git a/remill/Arch/AArch64/Semantics/CALL_RET.cpp b/remill/Arch/AArch64/Semantics/CALL_RET.cpp index 2058c1491..9593c1bbc 100644 --- a/remill/Arch/AArch64/Semantics/CALL_RET.cpp +++ b/remill/Arch/AArch64/Semantics/CALL_RET.cpp @@ -17,9 +17,11 @@ namespace { template -DEF_SEM(CALL, S target_addr, PC ret_addr, R64W, PC) { +DEF_SEM(CALL, S target_addr, PC ret_addr, R64W return_pc_dst) { Write(REG_LP, Read(ret_addr)); - Write(REG_PC, Read(target_addr)); + const auto return_pc = Read(target_addr); + Write(REG_PC, return_pc); + Write(return_pc_dst, return_pc); return memory; } diff --git a/remill/Arch/Arch.cpp b/remill/Arch/Arch.cpp index 8eac4f9dd..6d7e9a816 100644 --- a/remill/Arch/Arch.cpp +++ b/remill/Arch/Arch.cpp @@ -52,7 +52,7 @@ DECLARE_string(os); namespace remill { -class Arch::Impl { +class ArchImpl { public: // State type. llvm::StructType *state_type{nullptr}; @@ -63,7 +63,10 @@ class Arch::Impl { // Lifted function type. llvm::FunctionType *lifted_function_type{nullptr}; - std::vector registers; + // Metadata type ID for remill registers. + unsigned reg_md_id{0}; + + std::vector> registers; std::vector reg_by_offset; std::unordered_map reg_by_name; }; @@ -251,7 +254,7 @@ const Register *Arch::RegisterAtStateOffset(uint64_t offset) const { // Apply `cb` to every register. void Arch::ForEachRegister(std::function cb) const { for (const auto ® : impl->registers) { - cb(®); + cb(reg.get()); } } @@ -369,196 +372,6 @@ static bool BlockHasSpecialVars(llvm::Function *basic_block) { FindVarInFunction(basic_block, "BRANCH_TAKEN", true); } -// Iteratively accumulate the offset, following through GEPs and bitcasts. -static bool GetRegisterOffset(llvm::Module *module, llvm::Type *state_ptr_type, - llvm::Value *reg, uint64_t *offset) { - - auto val_name = reg->getName().str(); - const auto &dl = module->getDataLayout(); - *offset = 0; - do { - if (auto gep = llvm::dyn_cast(reg)) { - llvm::APInt gep_offset(dl.getPointerSizeInBits(0), 0); - if (!gep->accumulateConstantOffset(dl, gep_offset)) { - DLOG(INFO) << "Named variable " << val_name - << " is not a register in the " - << "state structure"; - } - *offset += gep_offset.getZExtValue(); - reg = gep->getPointerOperand(); - - } else if (auto c = llvm::dyn_cast(reg)) { - reg = c->getOperand(0); - - // Base case. - } else if (reg->getType() == state_ptr_type) { - break; - - } else { - DLOG(INFO) << "Named variable " << val_name - << " is not a register in the " - << "state structure"; - return false; - } - } while (reg); - - DLOG(INFO) << "Offset of register " << val_name << " in state structure is " - << *offset; - - return true; -} - -// Clang isn't guaranteed to play nice and name the LLVM values within the -// `__remill_basic_block` intrinsic with the same names as we find in the -// C++ definition of that function. However, we compile that function with -// debug information, and so we will try to recover the variables names for -// later lookup. -static void FixupBasicBlockVariables(llvm::Function *basic_block) { - std::unordered_map names; - std::unordered_map preferred_names; - std::unordered_set used_names; - std::vector stores; - std::vector remove_insts; - - std::unordered_map stored_val; - - for (auto &block : *basic_block) { - for (auto &inst : block) { - if (inst.hasName()) { - names[&inst] = inst.getName().str(); - } - } - } - - for (auto &block : *basic_block) { - for (auto &inst : block) { - if (auto debug_inst = llvm::dyn_cast(&inst)) { - if (auto decl_inst = llvm::dyn_cast(debug_inst)) { - auto addr = decl_inst->getAddress(); -#if LLVM_VERSION_NUMBER >= LLVM_VERSION(3, 7) - names[addr] = decl_inst->getVariable()->getName().str(); -#else - llvm::DIVariable var(decl_inst->getVariable()); - names[addr] = var.getName().str(); -#endif - } - remove_insts.push_back(debug_inst); - - // Get stores. - } else if (auto store_inst = llvm::dyn_cast(&inst)) { - auto dst_alloca = - llvm::dyn_cast(store_inst->getPointerOperand()); - if (dst_alloca) { - stored_val[dst_alloca] = store_inst->getValueOperand(); - } - stores.push_back(store_inst); - - // Forward stores to loads. - } else if (auto load_inst = llvm::dyn_cast(&inst)) { - auto src_alloca = - llvm::dyn_cast(load_inst->getPointerOperand()); - if (src_alloca) { - if (auto val = stored_val[src_alloca]) { - load_inst->replaceAllUsesWith(val); - remove_insts.push_back(load_inst); - } - } - - } else if (llvm::isa(&inst) || - llvm::isa(&inst) || - llvm::isa(&inst)) { - LOG(FATAL) << "Unsupported instruction in __remill_basic_block: " - << LLVMThingToString(&inst); - } - } - } - - // At this point, the instructions should have this form: - // - // %BH = alloca i8*, align 8 - // ... - // %24 = getelementptr inbounds ... - // store i8* %24, i8** %BH, align 8 - // - // Our goal is to eliminate the double indirection and get: - // - // %BH = getelementptr inbounds ... - - for (auto inst : stores) { - auto val = llvm::dyn_cast(inst->getValueOperand()); - auto ptr = llvm::dyn_cast(inst->getPointerOperand()); - - if (val && ptr && val->getType()->isPointerTy() && names.count(ptr)) { - preferred_names[val] = names[ptr]; - remove_insts.push_back(ptr); - remove_insts.push_back(inst); - } - } - - // Remove links between instructions. - for (auto inst : remove_insts) { - if (!inst->getType()->isVoidTy()) { - inst->replaceAllUsesWith(llvm::UndefValue::get(inst->getType())); - } - } - - // Remove unneeded instructions. - for (auto inst : remove_insts) { - for (auto &operand : inst->operands()) { - operand = nullptr; - } - inst->eraseFromParent(); - } - - for (auto &block : *basic_block) { - for (auto &inst : block) { - if (!inst.getType()->isVoidTy()) { - inst.setName(""); - } - } - } - - // First, apply names to preferred names, which are propagated. - for (auto &block : *basic_block) { - auto it = block.rbegin(); - auto end = block.rend(); - for (; it != end; ++it) { - auto &inst = *it; - auto name_it = preferred_names.find(&inst); - if (name_it != preferred_names.end()) { - auto &entry = *name_it; - if (!entry.first->getType()->isVoidTy() && - !used_names.count(entry.second)) { - entry.first->setName(entry.second); - used_names.insert(entry.second); - } - } - } - } - - // Finally, apply the previous names. These may conflict with the preferred - // names, but that - for (auto &block : *basic_block) { - auto it = block.rbegin(); - auto end = block.rend(); - for (; it != end; ++it) { - auto &inst = *it; - auto name_it = names.find(&inst); - if (name_it != names.end()) { - auto &entry = *name_it; - if (!entry.first->hasName() && !entry.first->getType()->isVoidTy() && - !used_names.count(entry.second)) { - entry.first->setName(entry.second); - used_names.insert(entry.second); - } - } - } - } - - CHECK(BlockHasSpecialVars(basic_block)) - << "Unable to locate required variables in `__remill_basic_block`."; -} - // Add attributes to llvm::Argument in a way portable across LLVMs static void AddNoAliasToArgument(llvm::Argument *arg) { IF_LLVM_LT_390(arg->addAttr(llvm::AttributeSet::get( @@ -567,67 +380,19 @@ static void AddNoAliasToArgument(llvm::Argument *arg) { IF_LLVM_GTE_390(arg->addAttr(llvm::Attribute::NoAlias);); } -// ensures that mandatory remill functions have the correct -// type signature and variable names -static void PrepareModuleRemillFunctions(llvm::Module *mod) { - auto basic_block = BasicBlockFunction(mod); - - InitFunctionAttributes(basic_block); - FixupBasicBlockVariables(basic_block); - - basic_block->setLinkage(llvm::GlobalValue::ExternalLinkage); - basic_block->setVisibility(llvm::GlobalValue::DefaultVisibility); - basic_block->removeFnAttr(llvm::Attribute::AlwaysInline); - basic_block->removeFnAttr(llvm::Attribute::InlineHint); - basic_block->addFnAttr(llvm::Attribute::OptimizeNone); - basic_block->addFnAttr(llvm::Attribute::NoInline); - basic_block->setVisibility(llvm::GlobalValue::DefaultVisibility); - - auto memory = remill::NthArgument(basic_block, kMemoryPointerArgNum); - auto state = remill::NthArgument(basic_block, kStatePointerArgNum); - - memory->setName(""); - state->setName(""); - remill::NthArgument(basic_block, kPCArgNum)->setName(""); - - AddNoAliasToArgument(state); - AddNoAliasToArgument(memory); -} - -// Compare two registers for sorting. -static bool RegisterComparator(const Register &lhs, const Register &rhs) { - - // Bigger to appear later in the array. E.g. RAX before EAX. - if (lhs.size > rhs.size) { - return true; - - } else if (lhs.size < rhs.size) { - return false; - - // Registers earlier in the state struct appear earlier in the - // sort. - } else if (lhs.offset < rhs.offset) { - return true; - - } else if (lhs.offset > rhs.offset) { - return false; - - } else { - return lhs.complexity < rhs.complexity; - } -} - } // namespace Register::Register(const std::string &name_, uint64_t offset_, uint64_t size_, - uint64_t complexity_, llvm::Type *type_) + llvm::Type *type_, const Register *parent_, + const ArchImpl *arch_) : name(name_), offset(offset_), size(size_), - complexity(complexity_), type(type_), constant_name( - llvm::ConstantDataArray::getString(type->getContext(), name_)) {} + llvm::ConstantDataArray::getString(type->getContext(), name_)), + parent(parent_), + arch(arch_) {} // Returns the enclosing register of size AT LEAST `size`, or `nullptr`. const Register *Register::EnclosingRegisterOfSize(uint64_t size_) const { @@ -656,30 +421,6 @@ const std::vector &Register::EnclosedRegisters(void) const { namespace { -// Return the complexity of this state indexing operation. -static unsigned Complexity(llvm::Value *base, llvm::Type *state_ptr_type) { - unsigned complexity = 0; - while (base) { - if (auto gep = llvm::dyn_cast(base)) { - complexity += gep->getNumOperands(); - base = gep->getPointerOperand(); - - } else if (auto bc = llvm::dyn_cast(base)) { - base = bc->getOperand(0); - complexity += 1; - - } else if (base->getType() == state_ptr_type) { - break; - - } else { - LOG(FATAL) << "Unexpected value " << LLVMThingToString(base) - << " in State structure indexing chain"; - base = nullptr; - } - } - return complexity; -} - // Compute the total offset of a GEP chain. static uint64_t TotalOffset(const llvm::DataLayout &dl, llvm::Value *base, llvm::Type *state_ptr_type) { @@ -793,7 +534,15 @@ FinishAddressOf(llvm::IRBuilder<> &ir, const llvm::DataLayout &dl, // a `State *`. llvm::Value *Register::AddressOf(llvm::Value *state_ptr, llvm::BasicBlock *add_to_end) const { - CHECK_EQ(&(type->getContext()), &(state_ptr->getContext())); + llvm::IRBuilder<> ir(add_to_end); + return AddressOf(state_ptr, ir); +} + + +llvm::Value *Register::AddressOf(llvm::Value *state_ptr, + llvm::IRBuilder<> &ir) const { + auto &context = type->getContext(); + CHECK_EQ(&context, &(state_ptr->getContext())); const auto state_ptr_type = llvm::dyn_cast(state_ptr->getType()); CHECK_NOTNULL(state_ptr_type); @@ -803,22 +552,35 @@ llvm::Value *Register::AddressOf(llvm::Value *state_ptr, llvm::dyn_cast(state_ptr_type->getPointerElementType()); CHECK_NOTNULL(state_type); - const auto module = add_to_end->getParent()->getParent(); + const auto module = ir.GetInsertBlock()->getParent()->getParent(); const auto &dl = module->getDataLayout(); - llvm::IRBuilder<> ir(add_to_end); + llvm::Value *gep = nullptr; if (auto const_state_ptr = llvm::dyn_cast(state_ptr); const_state_ptr) { gep = llvm::ConstantExpr::getInBoundsGetElementPtr( state_type, const_state_ptr, gep_index_list); } else { - gep = llvm::GetElementPtrInst::CreateInBounds( - state_type, state_ptr, gep_index_list, "", add_to_end); + gep = ir.CreateInBoundsGEP(state_type, state_ptr, gep_index_list); } auto state_size = dl.getTypeAllocSize(state_type); - return FinishAddressOf(ir, dl, state_ptr_type, state_size, this, addr_space, - gep); + auto ret = FinishAddressOf(ir, dl, state_ptr_type, state_size, this, + addr_space, gep); + + // Add the metadata to `inst`. + if (auto inst = llvm::dyn_cast(ret); inst) { +#if LLVM_VERSION_NUMBER >= LLVM_VERSION(3, 6) + auto reg_name_md = llvm::ValueAsMetadata::get(constant_name); + auto reg_name_node = llvm::MDNode::get(context, reg_name_md); +#else + auto reg_name_node = llvm::MDNode::get(context, reg->constant_name); +#endif + inst->setMetadata(arch->reg_md_id, reg_name_node); + inst->setName(name); + } + + return ret; } // Converts an LLVM module object to have the right triple / data layout @@ -854,315 +616,122 @@ void Arch::PrepareModuleDataLayout(llvm::Module *mod) const { void Arch::PrepareModule(llvm::Module *mod) const { CHECK_EQ(&(mod->getContext()), context); - llvm::Triple orig_mod_triple(mod->getTargetTriple()); - PrepareModuleRemillFunctions(mod); PrepareModuleDataLayout(mod); - if (!impl) { - impl.reset(new Impl); - CollectRegisters(mod); +} + +void Arch::AddRegister(const char *reg_name_, llvm::Type *val_type, + size_t offset, const char *parent_reg_name) const { + const std::string reg_name(reg_name_); + auto ® = impl->reg_by_name[reg_name]; + if (reg) { + return; + } + + const auto dl = this->DataLayout(); + + // If this is a sub-register, then link it in. + const Register *parent_reg = nullptr; + if (parent_reg_name) { + parent_reg = impl->reg_by_name[parent_reg_name]; + } + + auto reg_impl = new Register(reg_name, offset, dl.getTypeAllocSize(val_type), + val_type, parent_reg, impl.get()); + reg = reg_impl; + impl->registers.emplace_back(reg_impl); + + if (parent_reg) { + const_cast(reg->parent)->children.push_back(reg); + } + + reg_impl->gep_index_list.push_back( + llvm::Constant::getNullValue(llvm::Type::getInt32Ty(*context))); + std::tie(reg_impl->gep_offset, reg_impl->gep_type_at_offset) = BuildIndexes( + dl, impl->state_type, 0, reg->offset, reg_impl->gep_index_list); + + // Provide easy access to registers at specific offsets in the `State` + // structure. + for (auto i = reg->offset; i < (reg->offset + reg->size); ++i) { + auto ®_at_offset = impl->reg_by_offset[i]; + if (!reg_at_offset) { + reg_at_offset = reg; + } else if (reg_at_offset) { + CHECK_EQ(reg_at_offset->EnclosingRegister(), reg->EnclosingRegister()); + reg_at_offset = reg; + } } - llvm::Triple new_mod_triple(mod->getTargetTriple()); - - // // If `mod` was compiled on macOS, but we're targeting Linux, then strip - // // off leading underscore prefixes. - // if (orig_mod_triple.isMacOSX() && new_mod_triple.isOSLinux()) { - // for (auto &func : *mod) { - // if (!func.hasExternalLinkage() || - // !func.getName().startswith("_") || - // func.getName() == "main" || - // func.getName().startswith("__remill")) { - // continue; - // } - // - // auto unprefixed_name = func.getName().substr(1).str(); - // if (!mod->getFunction(unprefixed_name)) { - // func.setName(unprefixed_name); - // } - // } - // - // for (auto &var : mod->globals()) { - // if (!var.hasExternalLinkage() || !var.getName().startswith("_")) { - // continue; - // } - // - // auto unprefixed_name = var.getName().substr(1).str(); - // if (!mod->getGlobalVariable(unprefixed_name, false)) { - // var.setName(unprefixed_name); - // } - // } - // - // // If `mod` was compiled on Linux, but we're targeting macOS, then prefix - // // the external symbol names with underscores. - // } else if (orig_mod_triple.isOSLinux() && new_mod_triple.isMacOSX()) { - // for (auto &func : *mod) { - // if (!func.hasExternalLinkage() || - // !func.hasName() || - // func.getName() == "main" || - // func.getName().startswith("__remill")) { - // continue; - // } - // - // std::stringstream ss; - // ss << "_" << func.getName().str(); - // const auto prefixed_name = ss.str(); - // - // if (!mod->getFunction(prefixed_name)) { - // func.setName(prefixed_name); - // } - // } - // - // for (auto &var : mod->globals()) { - // if (!var.hasExternalLinkage() || !var.hasName()) { - // continue; - // } - // - // std::stringstream ss; - // ss << "_" << var.getName().str(); - // const auto prefixed_name = ss.str(); - // - // if (!mod->getGlobalVariable(prefixed_name, false)) { - // var.setName(prefixed_name); - // } - // } - // } } // Get all of the register information from the prepared module. -void Arch::CollectRegisters(llvm::Module *module) const { +void Arch::InitFromSemanticsModule(llvm::Module *module) const { + if (impl) { + return; + } + + impl.reset(new ArchImpl); CHECK(!impl->state_type); - llvm::DataLayout dl(module); + const auto &dl = module->getDataLayout(); const auto basic_block = BasicBlockFunction(module); const auto state_ptr_type = ::remill::StatePointerType(module); const auto state_type = llvm::dyn_cast(state_ptr_type->getElementType()); - const auto state_size = dl.getTypeAllocSize(state_type); - const auto index_type = llvm::Type::getInt32Ty(module->getContext()); impl->state_type = state_type; + impl->reg_by_offset.resize(dl.getTypeAllocSize(state_type)); impl->memory_type = ::remill::MemoryPointerType(module); impl->lifted_function_type = basic_block->getFunctionType(); + impl->reg_md_id = context->getMDKindID("remill_register"); - std::unordered_map prev_reg_by_name; - - llvm::Instruction *insert_loc = nullptr; - - // Collect all registers. - for (auto &block : *basic_block) { - for (auto &inst : block) { - if (llvm::isa(&inst)) { - insert_loc = &inst; - } - - uint64_t offset = 0; - if (!inst.hasName()) { - continue; - } - auto ptr_type = llvm::dyn_cast(inst.getType()); - if (!ptr_type || ptr_type->getElementType()->isPointerTy()) { - continue; - } - - auto reg_type = ptr_type->getElementType(); - if (!GetRegisterOffset(module, state_ptr_type, &inst, &offset)) { - continue; - } - - // In `__remill_basic_block`, register assignments are the "last" things, - // and aren't re-used for accessing sub-registers. - if (!inst.hasNUses(0)) { - continue; - } - - auto name = inst.getName().str(); - impl->registers.emplace_back(name, offset, dl.getTypeAllocSize(reg_type), - Complexity(&inst, state_ptr_type), reg_type); - - prev_reg_by_name[name] = &inst; - } - } - - CHECK_NOTNULL(insert_loc); + if (basic_block->isDeclaration()) { + basic_block->setLinkage(llvm::GlobalValue::ExternalLinkage); + basic_block->setVisibility(llvm::GlobalValue::DefaultVisibility); + basic_block->removeFnAttr(llvm::Attribute::AlwaysInline); + basic_block->removeFnAttr(llvm::Attribute::InlineHint); + basic_block->addFnAttr(llvm::Attribute::OptimizeNone); + basic_block->addFnAttr(llvm::Attribute::NoInline); + basic_block->setVisibility(llvm::GlobalValue::DefaultVisibility); - // Sort them in such a way that we can recover the parentage of registers. - std::sort(impl->registers.begin(), impl->registers.end(), RegisterComparator); + auto memory = remill::NthArgument(basic_block, kMemoryPointerArgNum); + auto state = remill::NthArgument(basic_block, kStatePointerArgNum); - impl->reg_by_offset.resize(dl.getTypeAllocSize(state_type)); + memory->setName("memory"); + state->setName("state"); + remill::NthArgument(basic_block, kPCArgNum)->setName("pc"); - // Figure out parentage of registers, and fill in the various maps. Now that - // `registers` is "finalized", it's safe to cross-link the various `Register`s - // by pointer, as we won't be sorting/resizing the vector anymore. - for (auto ® : impl->registers) { - impl->reg_by_name[reg.name] = ® - - for (uint64_t i = 0; i < reg.size; ++i) { - auto ®_at_offset = impl->reg_by_offset[reg.offset + i]; - if (!reg.parent) { - reg.parent = reg_at_offset; - if (reg_at_offset) { - const_cast(reg_at_offset)->children.push_back(®); - } - } else if (!reg_at_offset) { - LOG(FATAL) << "Register " << reg.name - << " is not fully enclosed by parent " << reg.parent->name; - } else if (reg.parent != reg_at_offset) { - LOG(FATAL) << "Can't set parent of register " << reg.name << " to " - << reg_at_offset->name << " because it already has " - << reg.parent->name << " as its parent"; - } - reg_at_offset = ® - } + AddNoAliasToArgument(state); + AddNoAliasToArgument(memory); - reg.gep_index_list.push_back(llvm::ConstantInt::get(index_type, 0, false)); + auto block = + llvm::BasicBlock::Create(module->getContext(), "", basic_block); + auto u8 = llvm::Type::getInt8Ty(*context); + auto addr = llvm::Type::getIntNTy(*context, address_size); + llvm::IRBuilder<> ir(block); - std::tie(reg.gep_offset, reg.gep_type_at_offset) = - BuildIndexes(dl, state_type, 0, reg.offset, reg.gep_index_list); + ir.CreateAlloca(u8, nullptr, "BRANCH_TAKEN"); + ir.CreateAlloca(addr, nullptr, "RETURN_PC"); + ir.CreateAlloca(addr, nullptr, "MONITOR"); - CHECK(reg.gep_type_at_offset != nullptr) - << "Unable to create index list for register '" << reg.name << "'"; - } + // NOTE(pag): `PC` and `NEXT_PC` are handled by + // `PopulateBasicBlockFunction`. - auto state_ptr = NthArgument(basic_block, remill::kStatePointerArgNum); - - std::unordered_map> - reg_indexes; - std::unordered_map reg_gep; - - auto adjust_indexes = [=](const Register ®, - llvm::SmallVector &index_vec) { - if (!reg.children.empty()) { - auto ptr_type = llvm::dyn_cast( - llvm::GetElementPtrInst::getGEPReturnType(state_type, state_ptr, - index_vec)); - while (!ptr_type->getElementType()->isStructTy()) { - index_vec.pop_back(); - CHECK(!index_vec.empty()); - ptr_type = llvm::dyn_cast( - llvm::GetElementPtrInst::getGEPReturnType(state_type, state_ptr, - index_vec)); - } - } - }; + ir.CreateStore(state, + ir.CreateAlloca(llvm::PointerType::get(impl->state_type, 0), + nullptr, "STATE")); + ir.CreateStore(memory, + ir.CreateAlloca(impl->memory_type, nullptr, "MEMORY")); - // Re-add register-specific instructions, but make sure that all GEPs for - // sub-regs are derived from those of parent regs. - for (auto ® : impl->registers) { - if (!reg.parent) { - auto index_vec = reg.gep_index_list; - adjust_indexes(reg, index_vec); - reg_gep[®] = llvm::GetElementPtrInst::CreateInBounds( - state_type, state_ptr, index_vec, llvm::Twine::createNull(), - insert_loc); + PopulateBasicBlockFunction(module, basic_block); - reg_indexes[®] = std::move(index_vec); + ir.SetInsertPoint(block); + ir.CreateRet(memory); - } else { - auto &parent_indexes = reg_indexes[reg.parent]; - auto parent_gep = reg_gep[reg.parent]; - CHECK_NOTNULL(parent_gep); - const auto parent_elem_type = - parent_gep->getType()->getPointerElementType(); - CHECK(parent_elem_type->isStructTy()) - << "Parent register " << reg.parent->name - << " truncated index list isn't pointing to a structure type; got: " - << LLVMThingToString(parent_elem_type) << " from " - << LLVMThingToString(parent_gep); - - if (1 < parent_indexes.size() && - parent_indexes.size() < reg.gep_index_list.size()) { - CHECK_EQ(parent_indexes.back(), - reg.gep_index_list[parent_indexes.size() - 1]); - - auto index_vec = reg.gep_index_list; - adjust_indexes(reg, index_vec); - - auto sub_indexes = index_vec; - - std::reverse(sub_indexes.begin(), sub_indexes.end()); - for (auto i = 0U; i < parent_indexes.size(); ++i) { - CHECK(!sub_indexes.empty()); - CHECK_EQ(sub_indexes.back(), parent_indexes[i]); - sub_indexes.pop_back(); - } - std::reverse(sub_indexes.begin(), sub_indexes.end()); - - auto gep = llvm::GetElementPtrInst::CreateInBounds( - parent_elem_type, parent_gep, sub_indexes, - llvm::Twine::createNull(), insert_loc); - - CHECK_LE(TotalOffset(dl, gep, state_ptr_type), reg.offset); - - reg_gep[®] = gep; - reg_indexes[®] = std::move(index_vec); - - } else if (parent_indexes.size() == reg.gep_index_list.size()) { - llvm::Value *sub_indices[] = {llvm::ConstantInt::get(index_type, 0)}; - auto gep = llvm::GetElementPtrInst::CreateInBounds( - parent_elem_type, parent_gep, sub_indices, - llvm::Twine::createNull(), insert_loc); - - CHECK_LE(TotalOffset(dl, gep, state_ptr_type), reg.offset); - - reg_gep[®] = gep; - reg_indexes[®] = reg.gep_index_list; - - } else { - auto gep = llvm::GetElementPtrInst::CreateInBounds( - parent_elem_type, parent_gep, reg.gep_index_list, - llvm::Twine::createNull(), insert_loc); - - CHECK_LE(TotalOffset(dl, gep, state_ptr_type), reg.offset); - reg_gep[®] = gep; - reg_indexes[®] = reg.gep_index_list; - } - } - } - - const auto reg_md_id = context->getMDKindID("remill_register"); - - // Replace the old versions of the registers with new versions. - const auto addr_space = state_ptr_type->getAddressSpace(); - llvm::IRBuilder<> ir(insert_loc); - for (auto ® : impl->registers) { - auto final = FinishAddressOf(ir, dl, state_ptr_type, state_size, ®, - addr_space, reg_gep[®]); - - auto prev_reg = prev_reg_by_name[reg.name]; - prev_reg->replaceAllUsesWith(final); - prev_reg->eraseFromParent(); - final->setName(reg.name); - - // Create the node for a `remill_register` annotation. - if (auto final_inst = llvm::dyn_cast(final); - final_inst) { -#if LLVM_VERSION_NUMBER >= LLVM_VERSION(3, 6) - auto reg_name_md = llvm::ValueAsMetadata::get(reg.constant_name); - auto reg_name_node = llvm::MDNode::get(*context, reg_name_md); -#else - auto reg_name_node = llvm::MDNode::get(*context, reg.constant_name); -#endif - final_inst->setMetadata(reg_md_id, reg_name_node); - } + } else { + CHECK(!impl->reg_by_name.empty()); } - // Run through and delete dead unnamed instructions. - std::vector to_remove; - for (auto changed = true; changed;) { - changed = false; - for (auto &block : *basic_block) { - for (auto &inst : block) { - if (inst.getType()->isPointerTy() && !inst.hasName() && - !inst.hasNUsesOrMore(1)) { - to_remove.push_back(&inst); - changed = true; - } - } - for (auto inst : to_remove) { - inst->eraseFromParent(); - } - to_remove.clear(); - } - } + CHECK(BlockHasSpecialVars(basic_block)) + << "Unable to locate required variables in `__remill_basic_block`."; } } // namespace remill diff --git a/remill/Arch/Arch.h b/remill/Arch/Arch.h index 3b7737443..0b841f822 100644 --- a/remill/Arch/Arch.h +++ b/remill/Arch/Arch.h @@ -16,10 +16,14 @@ #pragma once +// clang-format off +#include "remill/BC/Compat/CTypes.h" #include #include #include +#include #include +// clang-format on #include #include @@ -49,25 +53,18 @@ enum OSName : uint32_t; enum ArchName : uint32_t; class Arch; +class ArchImpl; class Instruction; struct Register { public: Register(const std::string &name_, uint64_t offset_, uint64_t size_, - uint64_t order_, llvm::Type *type_); + llvm::Type *type_, const Register *parent_, const ArchImpl *arch_); std::string name; // Name of the register. uint64_t offset; // Byte offset in `State`. uint64_t size; // Size of this register. - // How many indexes/casts it takes to get at this register withing the - // original bitcode of `__remill_basic_block`. This is a useful metric - // when trying to decide is something is a sub-register of another. For - // example, `Q0` is a sub register of `V0` on AArch64, even though they - // are the same size. The complexity allows us to see that it "takes more" - // to index into `Q0` than it does for `V0`, and thus `Q0` is a sub-register. - unsigned complexity; - // LLVM type associated with the field in `State`. llvm::Type *type; @@ -108,10 +105,13 @@ struct Register { llvm::Value *AddressOf(llvm::Value *state_ptr, llvm::BasicBlock *add_to_end) const; + llvm::Value *AddressOf(llvm::Value *state_ptr, llvm::IRBuilder<> &ir) const; + private: friend class Arch; - const Register *parent{nullptr}; + const Register *const parent; + const ArchImpl *const arch; // The directly enclosed registers. std::vector children; @@ -161,6 +161,12 @@ class Arch { // have the appropriate prototype and internal variables void PrepareModule(llvm::Module *mod) const; + // Get the state pointer and various other types from the `llvm::LLVMContext` + // associated with `module`. + // + // NOTE(pag): This is an internal API. + void InitFromSemanticsModule(llvm::Module *module) const; + inline void PrepareModule(const std::unique_ptr &mod) const { PrepareModule(mod.get()); } @@ -252,8 +258,16 @@ class Arch { protected: Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_); + // Populate the `__remill_basic_block` function with variables. + virtual void PopulateBasicBlockFunction(llvm::Module *module, + llvm::Function *bb_func) const = 0; + llvm::Triple BasicTriple(void) const; + // Add a register into this + void AddRegister(const char *reg_name, llvm::Type *val_type, size_t offset, + const char *parent_reg_name) const; + private: // Defined in `remill/Arch/X86/Arch.cpp`. static ArchPtr GetX86(llvm::LLVMContext *context, OSName os, @@ -263,12 +277,7 @@ class Arch { static ArchPtr GetAArch64(llvm::LLVMContext *context, OSName os, ArchName arch_name); - // Get all of the register information from the prepared module. - void CollectRegisters(llvm::Module *module) const; - - class Impl; - - mutable std::unique_ptr impl; + mutable std::unique_ptr impl; Arch(void) = delete; }; diff --git a/remill/Arch/X86/Arch.cpp b/remill/Arch/X86/Arch.cpp index 8001def10..251c7d757 100644 --- a/remill/Arch/X86/Arch.cpp +++ b/remill/Arch/X86/Arch.cpp @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include #include #include @@ -31,9 +33,19 @@ #include "remill/Arch/Instruction.h" #include "remill/Arch/Name.h" #include "remill/Arch/X86/XED.h" +#include "remill/BC/ABI.h" +#include "remill/BC/Util.h" #include "remill/BC/Version.h" #include "remill/OS/OS.h" +// clang-format off +#define HAS_FEATURE_AVX 1 +#define HAS_FEATURE_AVX512 1 +#define ADDRESS_SIZE 64 +#include "Runtime/State.h" + +// clang-format on + namespace remill { namespace { @@ -772,29 +784,33 @@ class X86Arch final : public Arch { virtual ~X86Arch(void); // Returns the name of the stack pointer register. - const char *StackPointerRegisterName(void) const final; + const char *StackPointerRegisterName(void) const override; // Returns the name of the program counter register. - const char *ProgramCounterRegisterName(void) const final; + const char *ProgramCounterRegisterName(void) const override; // Decode an instuction. bool DecodeInstruction(uint64_t address, std::string_view inst_bytes, - Instruction &inst) const final; + Instruction &inst) const override; // Fully decode any control-flow transfer instructions, but only partially // decode other instructions. To complete the decoding, call // `Instruction::FinalizeDecode`. bool LazyDecodeInstruction(uint64_t address, std::string_view inst_bytes, - Instruction &inst) const final; + Instruction &inst) const override; // Maximum number of bytes in an instruction. - uint64_t MaxInstructionSize(void) const final; + uint64_t MaxInstructionSize(void) const override; - llvm::Triple Triple(void) const final; - llvm::DataLayout DataLayout(void) const final; + llvm::Triple Triple(void) const override; + llvm::DataLayout DataLayout(void) const override; // Default calling convention for this architecture. - llvm::CallingConv::ID DefaultCallingConv(void) const final; + llvm::CallingConv::ID DefaultCallingConv(void) const override; + + // Populate the `__remill_basic_block` function with variables. + void PopulateBasicBlockFunction(llvm::Module *module, + llvm::Function *bb_func) const override; private: // Decode an instuction. @@ -804,7 +820,6 @@ class X86Arch final : public Arch { X86Arch(void) = delete; }; - X86Arch::X86Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_) : Arch(context_, os_name_, arch_name_) { @@ -1200,6 +1215,373 @@ bool X86Arch::LazyDecodeInstruction(uint64_t address, } } +// Populate the `__remill_basic_block` function with variables. +void X86Arch::PopulateBasicBlockFunction(llvm::Module *module, + llvm::Function *bb_func) const { + const auto &dl = module->getDataLayout(); + CHECK_EQ(sizeof(State), dl.getTypeAllocSize(StateStructType())) + << "Mismatch between size of State type for x86/amd64 and what is in " + << "the bitcode module"; + + bool has_avx = false; + bool has_avx512 = false; + switch (arch_name) { + case kArchX86_AVX: + case kArchAMD64_AVX: has_avx = true; break; + case kArchX86_AVX512: + case kArchAMD64_AVX512: + has_avx = true; + has_avx512 = true; + break; + default: break; + } + + auto &context = module->getContext(); + auto u8 = llvm::Type::getInt8Ty(context); + auto u16 = llvm::Type::getInt16Ty(context); + auto u32 = llvm::Type::getInt32Ty(context); + auto u64 = llvm::Type::getInt64Ty(context); + auto f64 = llvm::Type::getDoubleTy(context); + auto v128 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 128u / 8u); + auto v256 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 256u / 8u); + auto v512 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 512u / 8u); + auto addr = llvm::Type::getIntNTy(context, address_size); + auto zero_addr_val = llvm::Constant::getNullValue(addr); + + const auto entry_block = &bb_func->getEntryBlock(); + llvm::IRBuilder<> ir(entry_block); + +#define OFFSET_OF(type, access) \ + (reinterpret_cast(&reinterpret_cast( \ + static_cast(nullptr)->access))) + +#define REG(name, access, type) \ + AddRegister(#name, type, OFFSET_OF(State, access), nullptr) + +#define SUB_REG(name, access, type, parent_reg_name) \ + AddRegister(#name, type, OFFSET_OF(State, access), #parent_reg_name) + +#define SUB_REG64(name, access, type, parent_reg_name) \ + if (64 == address_size) { \ + SUB_REG(name, access, type, parent_reg_name); \ + } else { \ + REG(name, access, type); \ + } + +#define SUB_REGAVX512(name, access, type, parent_reg_name) \ + if (has_avx512) { \ + SUB_REG(name, access, type, parent_reg_name); \ + } else { \ + REG(name, access, type); \ + } + +#define SUB_REGAVX(name, access, type, parent_reg_name) \ + if (has_avx) { \ + SUB_REG(name, access, type, parent_reg_name); \ + } else { \ + REG(name, access, type); \ + } + + if (64 == address_size) { + REG(RAX, gpr.rax.qword, u64); + REG(RBX, gpr.rbx.qword, u64); + REG(RCX, gpr.rcx.qword, u64); + REG(RDX, gpr.rdx.qword, u64); + REG(RSI, gpr.rsi.qword, u64); + REG(RDI, gpr.rdi.qword, u64); + REG(RSP, gpr.rsp.qword, u64); + REG(RBP, gpr.rbp.qword, u64); + REG(RIP, gpr.rip.qword, u64); + + REG(R8, gpr.r8.qword, u64); + REG(R9, gpr.r9.qword, u64); + REG(R10, gpr.r10.qword, u64); + REG(R11, gpr.r11.qword, u64); + REG(R12, gpr.r12.qword, u64); + REG(R13, gpr.r13.qword, u64); + REG(R14, gpr.r14.qword, u64); + REG(R15, gpr.r15.qword, u64); + + SUB_REG(R8D, gpr.r8.dword, u32, R8); + SUB_REG(R9D, gpr.r9.dword, u32, R9); + SUB_REG(R10D, gpr.r10.dword, u32, R10); + SUB_REG(R11D, gpr.r11.dword, u32, R11); + SUB_REG(R12D, gpr.r12.dword, u32, R12); + SUB_REG(R13D, gpr.r13.dword, u32, R13); + SUB_REG(R14D, gpr.r14.dword, u32, R14); + SUB_REG(R15D, gpr.r15.dword, u32, R15); + + SUB_REG(R8W, gpr.r8.word, u16, R8D); + SUB_REG(R9W, gpr.r9.word, u16, R9D); + SUB_REG(R10W, gpr.r10.word, u16, R10D); + SUB_REG(R11W, gpr.r11.word, u16, R11D); + SUB_REG(R12W, gpr.r12.word, u16, R12D); + SUB_REG(R13W, gpr.r13.word, u16, R13D); + SUB_REG(R14W, gpr.r14.word, u16, R14D); + SUB_REG(R15W, gpr.r15.word, u16, R15D); + } + + SUB_REG64(EAX, gpr.rax.dword, u32, RAX); + SUB_REG64(EBX, gpr.rbx.dword, u32, RBX); + SUB_REG64(ECX, gpr.rcx.dword, u32, RCX); + SUB_REG64(EDX, gpr.rdx.dword, u32, RDX); + SUB_REG64(ESI, gpr.rsi.dword, u32, RSI); + SUB_REG64(EDI, gpr.rdi.dword, u32, RDI); + SUB_REG64(ESP, gpr.rsp.dword, u32, RSP); + SUB_REG64(EBP, gpr.rbp.dword, u32, RBP); + SUB_REG64(EIP, gpr.rip.dword, u32, RIP); + + SUB_REG(AX, gpr.rax.word, u16, EAX); + SUB_REG(BX, gpr.rbx.word, u16, EBX); + SUB_REG(CX, gpr.rcx.word, u16, ECX); + SUB_REG(DX, gpr.rdx.word, u16, EDX); + SUB_REG(SI, gpr.rsi.word, u16, ESI); + SUB_REG(DI, gpr.rdi.word, u16, EDI); + SUB_REG(SP, gpr.rsp.word, u16, ESP); + SUB_REG(BP, gpr.rbp.word, u16, EBP); + SUB_REG(IP, gpr.rip.word, u16, EIP); + SUB_REG(AH, gpr.rax.byte.high, u8, AX); + SUB_REG(BH, gpr.rbx.byte.high, u8, BX); + SUB_REG(CH, gpr.rcx.byte.high, u8, CX); + SUB_REG(DH, gpr.rdx.byte.high, u8, DX); + SUB_REG(AL, gpr.rax.byte.low, u8, AX); + SUB_REG(BL, gpr.rbx.byte.low, u8, BX); + SUB_REG(CL, gpr.rcx.byte.low, u8, CX); + SUB_REG(DL, gpr.rdx.byte.low, u8, DX); + + if (64 == address_size) { + SUB_REG(SIL, gpr.rsi.byte.low, u8, SI); + SUB_REG(DIL, gpr.rdi.byte.low, u8, DI); + SUB_REG(SPL, gpr.rsp.byte.low, u8, SP); + SUB_REG(BPL, gpr.rbp.byte.low, u8, BP); + SUB_REG(R8B, gpr.r8.byte.low, u8, R8W); + SUB_REG(R9B, gpr.r9.byte.low, u8, R9W); + SUB_REG(R10B, gpr.r10.byte.low, u8, R10W); + SUB_REG(R11B, gpr.r11.byte.low, u8, R11W); + SUB_REG(R12B, gpr.r12.byte.low, u8, R12W); + SUB_REG(R13B, gpr.r13.byte.low, u8, R13W); + SUB_REG(R14B, gpr.r14.byte.low, u8, R14W); + SUB_REG(R15B, gpr.r15.byte.low, u8, R15W); + } + + const auto pc_arg = NthArgument(bb_func, kPCArgNum); + const auto state_ptr_arg = NthArgument(bb_func, kStatePointerArgNum); + ir.CreateStore(pc_arg, ir.CreateAlloca(addr, nullptr, "NEXT_PC")); + + if (64 == address_size) { + SUB_REG(PC, gpr.rip.qword, u64, RIP); + } else { + SUB_REG(PC, gpr.rip.dword, u32, EIP); + } + + (void) this->RegisterByName("PC")->AddressOf(state_ptr_arg, ir); + + REG(SS, seg.ss.flat, u16); + REG(ES, seg.es.flat, u16); + REG(GS, seg.gs.flat, u16); + REG(FS, seg.fs.flat, u16); + REG(DS, seg.ds.flat, u16); + REG(CS, seg.cs.flat, u16); + + ir.CreateStore(zero_addr_val, ir.CreateAlloca(addr, nullptr, "SS_BASE")); + ir.CreateStore(zero_addr_val, ir.CreateAlloca(addr, nullptr, "ES_BASE")); + ir.CreateStore(zero_addr_val, ir.CreateAlloca(addr, nullptr, "DS_BASE")); + ir.CreateStore(zero_addr_val, ir.CreateAlloca(addr, nullptr, "CS_BASE")); + + if (64 == address_size) { + REG(GS_BASE, addr.gs_base.qword, addr); + REG(FS_BASE, addr.fs_base.qword, addr); + } else { + REG(GS_BASE, addr.gs_base.dword, addr); + REG(FS_BASE, addr.fs_base.dword, addr); + } + + if (has_avx) { + if (has_avx512) { + REG(ZMM0, vec[0].zmm, v512); + REG(ZMM1, vec[1].zmm, v512); + REG(ZMM2, vec[2].zmm, v512); + REG(ZMM3, vec[3].zmm, v512); + REG(ZMM4, vec[4].zmm, v512); + REG(ZMM5, vec[5].zmm, v512); + REG(ZMM6, vec[6].zmm, v512); + REG(ZMM7, vec[7].zmm, v512); + REG(ZMM8, vec[8].zmm, v512); + REG(ZMM9, vec[9].zmm, v512); + REG(ZMM10, vec[10].zmm, v512); + REG(ZMM11, vec[11].zmm, v512); + REG(ZMM12, vec[12].zmm, v512); + REG(ZMM13, vec[13].zmm, v512); + REG(ZMM14, vec[14].zmm, v512); + REG(ZMM15, vec[15].zmm, v512); + REG(ZMM16, vec[16].zmm, v512); + REG(ZMM17, vec[17].zmm, v512); + REG(ZMM18, vec[18].zmm, v512); + REG(ZMM19, vec[19].zmm, v512); + REG(ZMM20, vec[20].zmm, v512); + REG(ZMM21, vec[21].zmm, v512); + REG(ZMM22, vec[22].zmm, v512); + REG(ZMM23, vec[23].zmm, v512); + REG(ZMM24, vec[24].zmm, v512); + REG(ZMM25, vec[25].zmm, v512); + REG(ZMM26, vec[26].zmm, v512); + REG(ZMM27, vec[27].zmm, v512); + REG(ZMM28, vec[28].zmm, v512); + REG(ZMM29, vec[29].zmm, v512); + REG(ZMM30, vec[30].zmm, v512); + REG(ZMM31, vec[31].zmm, v512); + } + + SUB_REGAVX512(YMM0, vec[0].ymm, v256, ZMM0); + SUB_REGAVX512(YMM1, vec[1].ymm, v256, ZMM1); + SUB_REGAVX512(YMM2, vec[2].ymm, v256, ZMM2); + SUB_REGAVX512(YMM3, vec[3].ymm, v256, ZMM3); + SUB_REGAVX512(YMM4, vec[4].ymm, v256, ZMM4); + SUB_REGAVX512(YMM5, vec[5].ymm, v256, ZMM5); + SUB_REGAVX512(YMM6, vec[6].ymm, v256, ZMM6); + SUB_REGAVX512(YMM7, vec[7].ymm, v256, ZMM7); + + if (64 == address_size || has_avx512) { + SUB_REGAVX512(YMM8, vec[8].ymm, v256, ZMM8); + SUB_REGAVX512(YMM9, vec[9].ymm, v256, ZMM9); + SUB_REGAVX512(YMM10, vec[10].ymm, v256, ZMM10); + SUB_REGAVX512(YMM11, vec[11].ymm, v256, ZMM11); + SUB_REGAVX512(YMM12, vec[12].ymm, v256, ZMM12); + SUB_REGAVX512(YMM13, vec[13].ymm, v256, ZMM13); + SUB_REGAVX512(YMM14, vec[14].ymm, v256, ZMM14); + SUB_REGAVX512(YMM15, vec[15].ymm, v256, ZMM15); + } + + if (has_avx512) { + SUB_REGAVX512(YMM16, vec[16].ymm, v256, ZMM16); + SUB_REGAVX512(YMM17, vec[17].ymm, v256, ZMM17); + SUB_REGAVX512(YMM18, vec[18].ymm, v256, ZMM18); + SUB_REGAVX512(YMM19, vec[19].ymm, v256, ZMM19); + SUB_REGAVX512(YMM20, vec[20].ymm, v256, ZMM20); + SUB_REGAVX512(YMM21, vec[21].ymm, v256, ZMM21); + SUB_REGAVX512(YMM22, vec[22].ymm, v256, ZMM22); + SUB_REGAVX512(YMM23, vec[23].ymm, v256, ZMM23); + SUB_REGAVX512(YMM24, vec[24].ymm, v256, ZMM24); + SUB_REGAVX512(YMM25, vec[25].ymm, v256, ZMM25); + SUB_REGAVX512(YMM26, vec[26].ymm, v256, ZMM26); + SUB_REGAVX512(YMM27, vec[27].ymm, v256, ZMM27); + SUB_REGAVX512(YMM28, vec[28].ymm, v256, ZMM28); + SUB_REGAVX512(YMM29, vec[29].ymm, v256, ZMM29); + SUB_REGAVX512(YMM30, vec[30].ymm, v256, ZMM30); + SUB_REGAVX512(YMM31, vec[31].ymm, v256, ZMM31); + } + } + + SUB_REGAVX(XMM0, vec[0].xmm, v128, YMM0); + SUB_REGAVX(XMM1, vec[1].xmm, v128, YMM1); + SUB_REGAVX(XMM2, vec[2].xmm, v128, YMM2); + SUB_REGAVX(XMM3, vec[3].xmm, v128, YMM3); + SUB_REGAVX(XMM4, vec[4].xmm, v128, YMM4); + SUB_REGAVX(XMM5, vec[5].xmm, v128, YMM5); + SUB_REGAVX(XMM6, vec[6].xmm, v128, YMM6); + SUB_REGAVX(XMM7, vec[7].xmm, v128, YMM7); + + if (has_avx || 64 == address_size) { + SUB_REGAVX(XMM8, vec[8].xmm, v128, YMM8); + SUB_REGAVX(XMM9, vec[9].xmm, v128, YMM9); + SUB_REGAVX(XMM10, vec[10].xmm, v128, YMM10); + SUB_REGAVX(XMM11, vec[11].xmm, v128, YMM11); + SUB_REGAVX(XMM12, vec[12].xmm, v128, YMM12); + SUB_REGAVX(XMM13, vec[13].xmm, v128, YMM13); + SUB_REGAVX(XMM14, vec[14].xmm, v128, YMM14); + SUB_REGAVX(XMM15, vec[15].xmm, v128, YMM15); + } + + if (has_avx512) { + SUB_REG(XMM16, vec[16].xmm, v128, YMM16); + SUB_REG(XMM17, vec[17].xmm, v128, YMM17); + SUB_REG(XMM18, vec[18].xmm, v128, YMM18); + SUB_REG(XMM19, vec[19].xmm, v128, YMM19); + SUB_REG(XMM20, vec[20].xmm, v128, YMM20); + SUB_REG(XMM21, vec[21].xmm, v128, YMM21); + SUB_REG(XMM22, vec[22].xmm, v128, YMM22); + SUB_REG(XMM23, vec[23].xmm, v128, YMM23); + SUB_REG(XMM24, vec[24].xmm, v128, YMM24); + SUB_REG(XMM25, vec[25].xmm, v128, YMM25); + SUB_REG(XMM26, vec[26].xmm, v128, YMM26); + SUB_REG(XMM27, vec[27].xmm, v128, YMM27); + SUB_REG(XMM28, vec[28].xmm, v128, YMM28); + SUB_REG(XMM29, vec[29].xmm, v128, YMM29); + SUB_REG(XMM30, vec[30].xmm, v128, YMM30); + SUB_REG(XMM31, vec[31].xmm, v128, YMM31); + } + + REG(ST0, st.elems[0].val, f64); + REG(ST1, st.elems[1].val, f64); + REG(ST2, st.elems[2].val, f64); + REG(ST3, st.elems[3].val, f64); + REG(ST4, st.elems[4].val, f64); + REG(ST5, st.elems[5].val, f64); + REG(ST6, st.elems[6].val, f64); + REG(ST7, st.elems[7].val, f64); + +#if 0 // TODO(pag): Don't emulate directly for now. + if (32 == address_size) { + REG(FPU_LASTIP, fpu.u.x86.ip); + REG(FPU_LASTIP, fpu.u.x86.ip); + REG(FPU_LASTCS, fpu.u.x86.cs); + REG(FPU_LASTCS, fpu.u.x86.cs); + REG(FPU_LASTDP, fpu.u.x86.dp); + REG(FPU_LASTDP, fpu.u.x86.dp); + REG(FPU_LASTDS, fpu.u.x86.ds); + REG(FPU_LASTDS, fpu.u.x86.ds); + } else { + REG(FPU_LASTIP, fpu.u.amd64.ip); + REG(FPU_LASTIP, fpu.u.amd64.ip); + REG(FPU_LASTDP, fpu.u.amd64.dp); + REG(FPU_LASTDP, fpu.u.amd64.dp); + } +#endif + + // MMX technology registers. For simplicity, these are implemented separately + // from the FPU stack, and so they do not alias. This makes some things + // easier and some things harder. Marshaling native/lifted state becomes + // harder, but generating and optimizing bitcode becomes simpler. The trade- + // off is that analysis and native states will diverge in strange ways + // with code that mixes the two (X87 FPU ops, MMX ops). + REG(MM0, mmx.elems[0].val.qwords.elems[0], u64); + REG(MM1, mmx.elems[1].val.qwords.elems[0], u64); + REG(MM2, mmx.elems[2].val.qwords.elems[0], u64); + REG(MM3, mmx.elems[3].val.qwords.elems[0], u64); + REG(MM4, mmx.elems[4].val.qwords.elems[0], u64); + REG(MM5, mmx.elems[5].val.qwords.elems[0], u64); + REG(MM6, mmx.elems[6].val.qwords.elems[0], u64); + REG(MM7, mmx.elems[7].val.qwords.elems[0], u64); + + // Arithmetic flags. Data-flow analyses will clear these out ;-) + REG(AF, aflag.af, u8); + REG(CF, aflag.cf, u8); + REG(DF, aflag.df, u8); + REG(OF, aflag.of, u8); + REG(PF, aflag.pf, u8); + REG(SF, aflag.sf, u8); + REG(ZF, aflag.zf, u8); + + // // Debug registers. No-ops keep them from being stripped off the module. + // DR0 + // DR1 + // DR2 + // DR3 + // DR4 + // DR5 + // DR6 + // DR7 + + // REG(CR0, lat); + // REG(CR1, lat); + // REG(CR2, lat); + // REG(CR3, lat); + // REG(CR4, lat); + //#if 64 == ADDRESS_SIZE_BITS + // REG(CR8, lat); + //#endif +} + } // namespace // TODO(pag): We pretend that these are singletons, but they aren't really! diff --git a/remill/Arch/X86/Runtime/BasicBlock.cpp b/remill/Arch/X86/Runtime/BasicBlock.cpp index 57c6c89ad..f0caac2f3 100644 --- a/remill/Arch/X86/Runtime/BasicBlock.cpp +++ b/remill/Arch/X86/Runtime/BasicBlock.cpp @@ -48,318 +48,7 @@ extern CR8Reg gCR8; // each basic block in the code being lifted. // // Note: `curr_pc` is first to make sure it's not optimized away. -[[gnu::used]] Memory *__remill_basic_block(State &state, addr_t curr_pc, - Memory *memory) { - - bool branch_taken = false; - addr_t zero1 = 0; - addr_t zero2 = 0; - addr_t zero3 = 0; - addr_t zero4 = 0; - addr_t return_pc = 0; - - // Note: These variables MUST be defined for all architectures. - auto &STATE = state; - auto &MEMORY = *memory; - auto &PC = state.gpr.rip.aword; - auto &NEXT_PC = curr_pc; - auto &BRANCH_TAKEN = branch_taken; - auto &RETURN_PC = return_pc; - - // `PC` should already have the correct value, but it's nice to make sure - // that `curr_pc` is used throughout, as it helps with certain downstream - // uses to be able to depend on the optimizer not eliminating `curr_pc`. - PC = curr_pc; - - // We will reference these variables from the bitcode side of things so that - // we can map the name of a decoded register to a specific field in the - // `State` structure. - auto &AH = state.gpr.rax.byte.high; - auto &BH = state.gpr.rbx.byte.high; - auto &CH = state.gpr.rcx.byte.high; - auto &DH = state.gpr.rdx.byte.high; - auto &AL = state.gpr.rax.byte.low; - auto &BL = state.gpr.rbx.byte.low; - auto &CL = state.gpr.rcx.byte.low; - auto &DL = state.gpr.rdx.byte.low; -#if 64 == ADDRESS_SIZE_BITS - auto &SIL = state.gpr.rsi.byte.low; - auto &DIL = state.gpr.rdi.byte.low; - auto &SPL = state.gpr.rsp.byte.low; - auto &BPL = state.gpr.rbp.byte.low; - auto &R8B = state.gpr.r8.byte.low; - auto &R9B = state.gpr.r9.byte.low; - auto &R10B = state.gpr.r10.byte.low; - auto &R11B = state.gpr.r11.byte.low; - auto &R12B = state.gpr.r12.byte.low; - auto &R13B = state.gpr.r13.byte.low; - auto &R14B = state.gpr.r14.byte.low; - auto &R15B = state.gpr.r15.byte.low; -#endif // 64 == ADDRESS_SIZE_BITS - auto &AX = state.gpr.rax.word; - auto &BX = state.gpr.rbx.word; - auto &CX = state.gpr.rcx.word; - auto &DX = state.gpr.rdx.word; - auto &SI = state.gpr.rsi.word; - auto &DI = state.gpr.rdi.word; - auto &SP = state.gpr.rsp.word; - auto &BP = state.gpr.rbp.word; -#if 64 == ADDRESS_SIZE_BITS - auto &R8W = state.gpr.r8.word; - auto &R9W = state.gpr.r9.word; - auto &R10W = state.gpr.r10.word; - auto &R11W = state.gpr.r11.word; - auto &R12W = state.gpr.r12.word; - auto &R13W = state.gpr.r13.word; - auto &R14W = state.gpr.r14.word; - auto &R15W = state.gpr.r15.word; -#endif // 64 == ADDRESS_SIZE_BITS - auto &IP = state.gpr.rip.word; - - auto &EAX = state.gpr.rax.dword; - auto &EBX = state.gpr.rbx.dword; - auto &ECX = state.gpr.rcx.dword; - auto &EDX = state.gpr.rdx.dword; - auto &ESI = state.gpr.rsi.dword; - auto &EDI = state.gpr.rdi.dword; - auto &ESP = state.gpr.rsp.dword; - auto &EBP = state.gpr.rbp.dword; - auto &EIP = state.gpr.rip.dword; - -#if 64 == ADDRESS_SIZE_BITS - auto &R8D = state.gpr.r8.dword; - auto &R9D = state.gpr.r9.dword; - auto &R10D = state.gpr.r10.dword; - auto &R11D = state.gpr.r11.dword; - auto &R12D = state.gpr.r12.dword; - auto &R13D = state.gpr.r13.dword; - auto &R14D = state.gpr.r14.dword; - auto &R15D = state.gpr.r15.dword; - - auto &RAX = state.gpr.rax.qword; - auto &RBX = state.gpr.rbx.qword; - auto &RCX = state.gpr.rcx.qword; - auto &RDX = state.gpr.rdx.qword; - auto &RSI = state.gpr.rsi.qword; - auto &RDI = state.gpr.rdi.qword; - auto &RSP = state.gpr.rsp.qword; - auto &RBP = state.gpr.rbp.qword; - auto &R8 = state.gpr.r8.qword; - auto &R9 = state.gpr.r9.qword; - auto &R10 = state.gpr.r10.qword; - auto &R11 = state.gpr.r11.qword; - auto &R12 = state.gpr.r12.qword; - auto &R13 = state.gpr.r13.qword; - auto &R14 = state.gpr.r14.qword; - auto &R15 = state.gpr.r15.qword; - auto &RIP = state.gpr.rip.qword; -#endif // 64 == ADDRESS_SIZE_BITS - - auto &SS = state.seg.ss.flat; - auto &ES = state.seg.es.flat; - auto &GS = state.seg.gs.flat; - auto &FS = state.seg.fs.flat; - auto &DS = state.seg.ds.flat; - auto &CS = state.seg.cs.flat; - - auto &SS_BASE = zero1; - auto &ES_BASE = zero2; - auto &GS_BASE = state.addr.gs_base.aword; - auto &FS_BASE = state.addr.fs_base.aword; - auto &DS_BASE = zero3; - auto &CS_BASE = zero4; - -#if HAS_FEATURE_AVX -# if HAS_FEATURE_AVX512 - auto &ZMM0 = state.vec[0].zmm; - auto &ZMM1 = state.vec[1].zmm; - auto &ZMM2 = state.vec[2].zmm; - auto &ZMM3 = state.vec[3].zmm; - auto &ZMM4 = state.vec[4].zmm; - auto &ZMM5 = state.vec[5].zmm; - auto &ZMM6 = state.vec[6].zmm; - auto &ZMM7 = state.vec[7].zmm; - auto &ZMM8 = state.vec[8].zmm; - auto &ZMM9 = state.vec[9].zmm; - auto &ZMM10 = state.vec[10].zmm; - auto &ZMM11 = state.vec[11].zmm; - auto &ZMM12 = state.vec[12].zmm; - auto &ZMM13 = state.vec[13].zmm; - auto &ZMM14 = state.vec[14].zmm; - auto &ZMM15 = state.vec[15].zmm; - auto &ZMM16 = state.vec[16].zmm; - auto &ZMM17 = state.vec[17].zmm; - auto &ZMM18 = state.vec[18].zmm; - auto &ZMM19 = state.vec[19].zmm; - auto &ZMM20 = state.vec[20].zmm; - auto &ZMM21 = state.vec[21].zmm; - auto &ZMM22 = state.vec[22].zmm; - auto &ZMM23 = state.vec[23].zmm; - auto &ZMM24 = state.vec[24].zmm; - auto &ZMM25 = state.vec[25].zmm; - auto &ZMM26 = state.vec[26].zmm; - auto &ZMM27 = state.vec[27].zmm; - auto &ZMM28 = state.vec[28].zmm; - auto &ZMM29 = state.vec[29].zmm; - auto &ZMM30 = state.vec[30].zmm; - auto &ZMM31 = state.vec[31].zmm; -# endif // HAS_FEATURE_AVX512 - - auto &YMM0 = state.vec[0].ymm; - auto &YMM1 = state.vec[1].ymm; - auto &YMM2 = state.vec[2].ymm; - auto &YMM3 = state.vec[3].ymm; - auto &YMM4 = state.vec[4].ymm; - auto &YMM5 = state.vec[5].ymm; - auto &YMM6 = state.vec[6].ymm; - auto &YMM7 = state.vec[7].ymm; -# if HAS_FEATURE_AVX || 64 == ADDRESS_SIZE_BITS - auto &YMM8 = state.vec[8].ymm; - auto &YMM9 = state.vec[9].ymm; - auto &YMM10 = state.vec[10].ymm; - auto &YMM11 = state.vec[11].ymm; - auto &YMM12 = state.vec[12].ymm; - auto &YMM13 = state.vec[13].ymm; - auto &YMM14 = state.vec[14].ymm; - auto &YMM15 = state.vec[15].ymm; - -# endif // HAS_FEATURE_AVX || 64 == ADDRESS_SIZE_BITS - -# if HAS_FEATURE_AVX512 - auto &YMM16 = state.vec[16].ymm; - auto &YMM17 = state.vec[17].ymm; - auto &YMM18 = state.vec[18].ymm; - auto &YMM19 = state.vec[19].ymm; - auto &YMM20 = state.vec[20].ymm; - auto &YMM21 = state.vec[21].ymm; - auto &YMM22 = state.vec[22].ymm; - auto &YMM23 = state.vec[23].ymm; - auto &YMM24 = state.vec[24].ymm; - auto &YMM25 = state.vec[25].ymm; - auto &YMM26 = state.vec[26].ymm; - auto &YMM27 = state.vec[27].ymm; - auto &YMM28 = state.vec[28].ymm; - auto &YMM29 = state.vec[29].ymm; - auto &YMM30 = state.vec[30].ymm; - auto &YMM31 = state.vec[31].ymm; -# endif // HAS_FEATURE_AVX512 -#endif // HAS_FEATURE_AVX - - auto &XMM0 = state.vec[0].xmm; - auto &XMM1 = state.vec[1].xmm; - auto &XMM2 = state.vec[2].xmm; - auto &XMM3 = state.vec[3].xmm; - auto &XMM4 = state.vec[4].xmm; - auto &XMM5 = state.vec[5].xmm; - auto &XMM6 = state.vec[6].xmm; - auto &XMM7 = state.vec[7].xmm; - -#if HAS_FEATURE_AVX || 64 == ADDRESS_SIZE_BITS - auto &XMM8 = state.vec[8].xmm; - auto &XMM9 = state.vec[9].xmm; - auto &XMM10 = state.vec[10].xmm; - auto &XMM11 = state.vec[11].xmm; - auto &XMM12 = state.vec[12].xmm; - auto &XMM13 = state.vec[13].xmm; - auto &XMM14 = state.vec[14].xmm; - auto &XMM15 = state.vec[15].xmm; -#endif // HAS_FEATURE_AVX || 64 == ADDRESS_SIZE_BITS - -#if HAS_FEATURE_AVX512 - auto &XMM16 = state.vec[16].xmm; - auto &XMM17 = state.vec[17].xmm; - auto &XMM18 = state.vec[18].xmm; - auto &XMM19 = state.vec[19].xmm; - auto &XMM20 = state.vec[20].xmm; - auto &XMM21 = state.vec[21].xmm; - auto &XMM22 = state.vec[22].xmm; - auto &XMM23 = state.vec[23].xmm; - auto &XMM24 = state.vec[24].xmm; - auto &XMM25 = state.vec[25].xmm; - auto &XMM26 = state.vec[26].xmm; - auto &XMM27 = state.vec[27].xmm; - auto &XMM28 = state.vec[28].xmm; - auto &XMM29 = state.vec[29].xmm; - auto &XMM30 = state.vec[30].xmm; - auto &XMM31 = state.vec[31].xmm; - -#endif // HAS_FEATURE_AVX512 - - auto &ST0 = state.st.elems[0].val; - auto &ST1 = state.st.elems[1].val; - auto &ST2 = state.st.elems[2].val; - auto &ST3 = state.st.elems[3].val; - auto &ST4 = state.st.elems[4].val; - auto &ST5 = state.st.elems[5].val; - auto &ST6 = state.st.elems[6].val; - auto &ST7 = state.st.elems[7].val; - -#if 0 // TODO(pag): Don't emulate directly for now. -# if 32 == ADDRESS_SIZE_BITS - auto &FPU_LASTIP = state.fpu.u.x86.ip; - auto &FPU_LASTIP = state.fpu.u.x86.ip; - auto &FPU_LASTCS = state.fpu.u.x86.cs; - auto &FPU_LASTCS = state.fpu.u.x86.cs; - auto &FPU_LASTDP = state.fpu.u.x86.dp; - auto &FPU_LASTDP = state.fpu.u.x86.dp; - auto &FPU_LASTDS = state.fpu.u.x86.ds; - auto &FPU_LASTDS = state.fpu.u.x86.ds; -# else - auto &FPU_LASTIP = state.fpu.u.amd64.ip; - auto &FPU_LASTIP = state.fpu.u.amd64.ip; - auto &FPU_LASTDP = state.fpu.u.amd64.dp; - auto &FPU_LASTDP = state.fpu.u.amd64.dp; -# endif -#endif - - // MMX technology registers. For simplicity, these are implemented separately - // from the FPU stack, and so they do not alias. This makes some things - // easier and some things harder. Marshaling native/lifted state becomes - // harder, but generating and optimizing bitcode becomes simpler. The trade- - // off is that analysis and native states will diverge in strange ways - // with code that mixes the two (X87 FPU ops, MMX ops). - auto &MM0 = state.mmx.elems[0].val.qwords.elems[0]; - auto &MM1 = state.mmx.elems[1].val.qwords.elems[0]; - auto &MM2 = state.mmx.elems[2].val.qwords.elems[0]; - auto &MM3 = state.mmx.elems[3].val.qwords.elems[0]; - auto &MM4 = state.mmx.elems[4].val.qwords.elems[0]; - auto &MM5 = state.mmx.elems[5].val.qwords.elems[0]; - auto &MM6 = state.mmx.elems[6].val.qwords.elems[0]; - auto &MM7 = state.mmx.elems[7].val.qwords.elems[0]; - - // Arithmetic flags. Data-flow analyses will clear these out ;-) - auto &AF = state.aflag.af; - auto &CF = state.aflag.cf; - auto &DF = state.aflag.df; - auto &OF = state.aflag.of; - auto &PF = state.aflag.pf; - auto &SF = state.aflag.sf; - auto &ZF = state.aflag.zf; - - // Debug registers. No-ops keep them from being stripped off the module. - auto &_DR0 = DR0; - auto &_DR1 = DR1; - auto &_DR2 = DR2; - auto &_DR3 = DR3; - auto &_DR4 = DR4; - auto &_DR5 = DR5; - auto &_DR6 = DR6; - auto &_DR7 = DR7; - - // Control registers - auto &CR0 = gCR0.flat; - auto &CR1 = gCR1.flat; - auto &CR2 = gCR2.flat; - auto &CR3 = gCR3.flat; - auto &CR4 = gCR4.flat; -#if 64 == ADDRESS_SIZE_BITS - auto &CR8 = gCR8.flat; -#endif - - // Lifted code will be placed here in clones versions of this function. - return memory; -} - +[[gnu::used]] Memory *__remill_basic_block(State &, addr_t, Memory *); #pragma clang diagnostic pop } // extern C diff --git a/remill/Arch/X86/Runtime/Instructions.cpp b/remill/Arch/X86/Runtime/Instructions.cpp index c3a2a02f9..7292ec582 100644 --- a/remill/Arch/X86/Runtime/Instructions.cpp +++ b/remill/Arch/X86/Runtime/Instructions.cpp @@ -25,6 +25,7 @@ #include "remill/Arch/X86/Runtime/State.h" #include "remill/Arch/X86/Runtime/Types.h" #include "remill/Arch/X86/Runtime/Operators.h" + // clang-format on #define REG_IP state.gpr.rip.word @@ -200,4 +201,5 @@ DEF_HELPER(PopFromStack)->T { #include "remill/Arch/X86/Semantics/X87.cpp" #include "remill/Arch/X86/Semantics/XOP.cpp" #include "remill/Arch/X86/Semantics/XSAVE.cpp" + // clang-format on diff --git a/remill/BC/Compat/CTypes.h b/remill/BC/Compat/CTypes.h new file mode 100644 index 000000000..0a9657a2f --- /dev/null +++ b/remill/BC/Compat/CTypes.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +namespace llvm { +// TODO(pag): This is a rather ugly hack; had some issues with anvill not +// compiling on macOS due to these C types. +struct LLVMOpaqueNamedMDNode; +using LLVMNamedMDNodeRef = struct LLVMOpaqueNamedMDNode *; +} // namespace llvm diff --git a/remill/BC/Lifter.cpp b/remill/BC/Lifter.cpp index 873d58438..34b88fd8f 100644 --- a/remill/BC/Lifter.cpp +++ b/remill/BC/Lifter.cpp @@ -90,9 +90,20 @@ InstructionLifter::InstructionLifter(const Arch *arch_, intrinsics(intrinsics_), last_func(nullptr) {} +// Lift a single instruction into a basic block. `is_delayed` signifies that +// this instruction will execute within the delay slot of another instruction. +LiftStatus InstructionLifter::LiftIntoBlock(Instruction &inst, + llvm::BasicBlock *block, + bool is_delayed) { + return LiftIntoBlock(inst, block, + NthArgument(block->getParent(), kStatePointerArgNum), + is_delayed); +} + // Lift a single instruction into a basic block. LiftStatus InstructionLifter::LiftIntoBlock(Instruction &arch_inst, llvm::BasicBlock *block, + llvm::Value *state_ptr, bool is_delayed) { llvm::Function *const func = block->getParent(); @@ -131,10 +142,9 @@ LiftStatus InstructionLifter::LiftIntoBlock(Instruction &arch_inst, } llvm::IRBuilder<> ir(block); - const auto mem_ptr_ref = LoadRegAddress(block, "MEMORY"); - const auto state_ptr = LoadRegValue(block, "STATE"); - const auto pc_ref = LoadRegAddress(block, "PC"); - const auto next_pc_ref = LoadRegAddress(block, "NEXT_PC"); + const auto mem_ptr_ref = LoadRegAddress(block, state_ptr, "MEMORY"); + const auto pc_ref = LoadRegAddress(block, state_ptr, "PC"); + const auto next_pc_ref = LoadRegAddress(block, state_ptr, "NEXT_PC"); const auto next_pc = ir.CreateLoad(next_pc_ref); // If this instruction appears within a delay slot, then we're going to assume @@ -189,7 +199,7 @@ LiftStatus InstructionLifter::LiftIntoBlock(Instruction &arch_inst, auto arg = NthArgument(isel_func, arg_num); auto arg_type = arg->getType(); - auto operand = LiftOperand(arch_inst, block, arg, op); + auto operand = LiftOperand(arch_inst, block, state_ptr, arg, op); arg_num += 1; auto op_type = operand->getType(); CHECK(op_type == arg_type) @@ -236,6 +246,7 @@ LiftStatus InstructionLifter::LiftIntoBlock(Instruction &arch_inst, // Load the address of a register. llvm::Value *InstructionLifter::LoadRegAddress(llvm::BasicBlock *block, + llvm::Value *state_ptr, const std::string ®_name) { const auto func = block->getParent(); if (func != last_func) { @@ -245,8 +256,44 @@ llvm::Value *InstructionLifter::LoadRegAddress(llvm::BasicBlock *block, const auto reg_ptr_it = reg_ptr_cache.find(reg_name); if (reg_ptr_it != reg_ptr_cache.end()) { return reg_ptr_it->second; + + // It's a register known to this architecture, so go and build a GEP to it + // right now. We'll try to be careful about the placement of the actual + // indexing instructions so that they always follow the definition of the + // state pointer, and thus are most likely to dominate all future uses. + } else if (auto reg = arch->RegisterByName(reg_name); reg) { + + llvm::Value *reg_ptr = nullptr; + + // The state pointer is an argument. + if (auto state_arg = llvm::dyn_cast(state_ptr); state_arg) { + DCHECK_EQ(state_arg->getParent(), block->getParent()); + auto &target_block = block->getParent()->getEntryBlock(); + llvm::IRBuilder<> ir(&target_block, target_block.getFirstInsertionPt()); + reg_ptr = reg->AddressOf(state_ptr, ir); + + // The state pointer is an instruction, likely an `AllocaInst`. + } else if (auto state_inst = llvm::dyn_cast(state_ptr); + state_inst) { + llvm::IRBuilder<> ir(state_inst); + reg_ptr = reg->AddressOf(state_ptr, ir); + + // The state pointer is a constant, likely an `llvm::GlobalVariable`. + } else if (auto state_const = llvm::dyn_cast(state_ptr); + state_const) { + reg_ptr = reg->AddressOf(state_ptr, block); + + // Not sure. + } else { + LOG(FATAL) << "Unsupported value type for the State pointer: " + << LLVMThingToString(state_ptr); + } + + reg_ptr_cache.emplace(reg_name, reg_ptr); + return reg_ptr; + } else { - const auto reg_ptr = FindVarInFunction(func, reg_name); + const auto reg_ptr = FindVarInFunction(func, reg_name, true); reg_ptr_cache.emplace(reg_name, reg_ptr); return reg_ptr; } @@ -254,21 +301,22 @@ llvm::Value *InstructionLifter::LoadRegAddress(llvm::BasicBlock *block, // Load the value of a register. llvm::Value *InstructionLifter::LoadRegValue(llvm::BasicBlock *block, + llvm::Value *state_ptr, const std::string ®_name) { - return new llvm::LoadInst(LoadRegAddress(block, reg_name), "", block); + return new llvm::LoadInst(LoadRegAddress(block, state_ptr, reg_name), "", + block); } // Return a register value, or zero. -llvm::Value * -InstructionLifter::LoadWordRegValOrZero(llvm::BasicBlock *block, - const std::string ®_name, - llvm::ConstantInt *zero) { +llvm::Value *InstructionLifter::LoadWordRegValOrZero( + llvm::BasicBlock *block, llvm::Value *state_ptr, + const std::string ®_name, llvm::ConstantInt *zero) { if (reg_name.empty()) { return zero; } - auto val = LoadRegValue(block, reg_name); + auto val = LoadRegValue(block, state_ptr, reg_name); auto val_type = llvm::dyn_cast_or_null(val->getType()); auto word_type = zero->getType(); @@ -287,10 +335,9 @@ InstructionLifter::LoadWordRegValOrZero(llvm::BasicBlock *block, return val; } -llvm::Value * -InstructionLifter::LiftShiftRegisterOperand(Instruction &inst, - llvm::BasicBlock *block, - llvm::Argument *arg, Operand &op) { +llvm::Value *InstructionLifter::LiftShiftRegisterOperand( + Instruction &inst, llvm::BasicBlock *block, llvm::Value *state_ptr, + llvm::Argument *arg, Operand &op) { llvm::Function *func = block->getParent(); llvm::Module *module = func->getParent(); @@ -303,7 +350,7 @@ InstructionLifter::LiftShiftRegisterOperand(Instruction &inst, << "for instruction at " << std::hex << inst.pc; const llvm::DataLayout data_layout(module); - auto reg = LoadRegValue(block, arch_reg.name); + auto reg = LoadRegValue(block, state_ptr, arch_reg.name); auto reg_type = reg->getType(); auto reg_size = SizeOfTypeInBits(data_layout, reg_type); auto word_size = SizeOfTypeInBits(data_layout, word_type); @@ -472,6 +519,7 @@ ConvertToIntendedType(Instruction &inst, Operand &op, llvm::BasicBlock *block, // a pointer (e.g. when passing a vector to an instruction semantics function). llvm::Value *InstructionLifter::LiftRegisterOperand(Instruction &inst, llvm::BasicBlock *block, + llvm::Value *state_ptr, llvm::Argument *arg, Operand &op) { @@ -487,7 +535,7 @@ llvm::Value *InstructionLifter::LiftRegisterOperand(Instruction &inst, auto arg_type = IntendedArgumentType(arg); if (llvm::isa(arg_type)) { - auto val = LoadRegAddress(block, arch_reg.name); + auto val = LoadRegAddress(block, state_ptr, arch_reg.name); return ConvertToIntendedType(inst, op, block, val, real_arg_type); } else { @@ -495,7 +543,7 @@ llvm::Value *InstructionLifter::LiftRegisterOperand(Instruction &inst, << "Expected " << arch_reg.name << " to be an integral or float type " << "for instruction at " << std::hex << inst.pc; - auto val = LoadRegValue(block, arch_reg.name); + auto val = LoadRegValue(block, state_ptr, arch_reg.name); const llvm::DataLayout data_layout(module); auto val_type = val->getType(); @@ -585,6 +633,7 @@ InstructionLifter::LiftImmediateOperand(Instruction &inst, llvm::BasicBlock *, // Zero-extend a value to be the machine word size. llvm::Value *InstructionLifter::LiftAddressOperand(Instruction &inst, llvm::BasicBlock *block, + llvm::Value *state_ptr, llvm::Argument *, Operand &op) { auto &arch_addr = op.addr; @@ -601,12 +650,14 @@ llvm::Value *InstructionLifter::LiftAddressOperand(Instruction &inst, << "for instruction at " << std::hex << inst.pc << " is wider than the machine word size."; - auto addr = LoadWordRegValOrZero(block, arch_addr.base_reg.name, zero); - auto index = LoadWordRegValOrZero(block, arch_addr.index_reg.name, zero); + auto addr = + LoadWordRegValOrZero(block, state_ptr, arch_addr.base_reg.name, zero); + auto index = + LoadWordRegValOrZero(block, state_ptr, arch_addr.index_reg.name, zero); auto scale = llvm::ConstantInt::get( word_type, static_cast(arch_addr.scale), true); - auto segment = - LoadWordRegValOrZero(block, arch_addr.segment_base_reg.name, zero); + auto segment = LoadWordRegValOrZero(block, state_ptr, + arch_addr.segment_base_reg.name, zero); llvm::IRBuilder<> ir(block); @@ -646,7 +697,8 @@ llvm::Value *InstructionLifter::LiftAddressOperand(Instruction &inst, // Lift an operand for use by the instruction. llvm::Value * InstructionLifter::LiftOperand(Instruction &inst, llvm::BasicBlock *block, - llvm::Argument *arg, Operand &arch_op) { + llvm::Value *state_ptr, llvm::Argument *arg, + Operand &arch_op) { auto arg_type = arg->getType(); switch (arch_op.type) { case Operand::kTypeInvalid: @@ -658,7 +710,7 @@ InstructionLifter::LiftOperand(Instruction &inst, llvm::BasicBlock *block, << "Can't write to a shift register operand " << "for instruction at " << std::hex << inst.pc; - return LiftShiftRegisterOperand(inst, block, arg, arch_op); + return LiftShiftRegisterOperand(inst, block, state_ptr, arg, arch_op); case Operand::kTypeRegister: if (arch_op.size != arch_op.reg.size) { @@ -666,7 +718,7 @@ InstructionLifter::LiftOperand(Instruction &inst, llvm::BasicBlock *block, << arch_op.reg.name << " in instruction " << inst.Serialize(); } - return LiftRegisterOperand(inst, block, arg, arch_op); + return LiftRegisterOperand(inst, block, state_ptr, arg, arch_op); case Operand::kTypeImmediate: return LiftImmediateOperand(inst, block, arg, arch_op); @@ -680,7 +732,7 @@ InstructionLifter::LiftOperand(Instruction &inst, llvm::BasicBlock *block, << std::hex << inst.pc; } - return LiftAddressOperand(inst, block, arg, arch_op); + return LiftAddressOperand(inst, block, state_ptr, arg, arch_op); } LOG(FATAL) << "Got a unknown operand type of " @@ -960,9 +1012,12 @@ bool TraceLifter::Impl::Lift( // variables jumps to the block that will contain the first instruction // of the trace. CloneBlockFunctionInto(func); + auto state_ptr = NthArgument(func, kStatePointerArgNum); + if (auto entry_block = &(func->front())) { auto pc = LoadProgramCounterArg(func); - auto next_pc_ref = inst_lifter.LoadRegAddress(entry_block, "NEXT_PC"); + auto next_pc_ref = + inst_lifter.LoadRegAddress(entry_block, state_ptr, "NEXT_PC"); // Initialize `NEXT_PC`. (void) new llvm::StoreInst(pc, next_pc_ref, entry_block); @@ -1006,7 +1061,7 @@ bool TraceLifter::Impl::Lift( (void) arch->DecodeInstruction(inst_addr, inst_bytes, inst); - auto lift_status = inst_lifter.LiftIntoBlock(inst, block); + auto lift_status = inst_lifter.LiftIntoBlock(inst, block, state_ptr); if (kLiftedInstruction != lift_status) { AddTerminatingTailCall(block, intrinsics->error); continue; @@ -1036,8 +1091,8 @@ bool TraceLifter::Impl::Lift( on_branch_taken_path)) { return; } - lift_status = inst_lifter.LiftIntoBlock(delayed_inst, into_block, - true /* is_delayed */); + lift_status = inst_lifter.LiftIntoBlock( + delayed_inst, into_block, state_ptr, true /* is_delayed */); if (kLiftedInstruction != lift_status) { AddTerminatingTailCall(block, intrinsics->error); } diff --git a/remill/BC/Lifter.h b/remill/BC/Lifter.h index 72d1d7ad9..ba95769f5 100644 --- a/remill/BC/Lifter.h +++ b/remill/BC/Lifter.h @@ -67,8 +67,14 @@ class InstructionLifter { // Lift a single instruction into a basic block. `is_delayed` signifies that // this instruction will execute within the delay slot of another instruction. virtual LiftStatus LiftIntoBlock(Instruction &inst, llvm::BasicBlock *block, + llvm::Value *state_ptr, bool is_delayed = false); + // Lift a single instruction into a basic block. `is_delayed` signifies that + // this instruction will execute within the delay slot of another instruction. + LiftStatus LiftIntoBlock(Instruction &inst, llvm::BasicBlock *block, + bool is_delayed = false); + const Arch *const arch; // Machine word type for this architecture. @@ -78,11 +84,11 @@ class InstructionLifter { const IntrinsicTable *const intrinsics; // Load the address of a register. - llvm::Value *LoadRegAddress(llvm::BasicBlock *block, + llvm::Value *LoadRegAddress(llvm::BasicBlock *block, llvm::Value *state_ptr, const std::string ®_name); // Load the value of a register. - llvm::Value *LoadRegValue(llvm::BasicBlock *block, + llvm::Value *LoadRegValue(llvm::BasicBlock *block, llvm::Value *state_ptr, const std::string ®_name); protected: @@ -90,16 +96,19 @@ class InstructionLifter { // Lift an operand to an instruction. virtual llvm::Value *LiftOperand(Instruction &inst, llvm::BasicBlock *block, - llvm::Argument *arg, Operand &op); + llvm::Value *state_ptr, llvm::Argument *arg, + Operand &op); // Lift a register operand to a value. virtual llvm::Value * LiftShiftRegisterOperand(Instruction &inst, llvm::BasicBlock *block, - llvm::Argument *arg, Operand ®); + llvm::Value *state_ptr, llvm::Argument *arg, + Operand ®); // Lift a register operand to a value. virtual llvm::Value *LiftRegisterOperand(Instruction &inst, llvm::BasicBlock *block, + llvm::Value *state_ptr, llvm::Argument *arg, Operand ®); // Lift an immediate operand. @@ -108,14 +117,14 @@ class InstructionLifter { llvm::Argument *arg, Operand &op); // Lift an indirect memory operand to a value. - virtual llvm::Value *LiftAddressOperand(Instruction &inst, - llvm::BasicBlock *block, - llvm::Argument *arg, Operand &mem); + virtual llvm::Value * + LiftAddressOperand(Instruction &inst, llvm::BasicBlock *block, + llvm::Value *state_ptr, llvm::Argument *arg, Operand &mem); // Return a register value, or zero. - llvm::Value *LoadWordRegValOrZero(llvm::BasicBlock *block, - const std::string ®_name, - llvm::ConstantInt *zero); + llvm::Value * + LoadWordRegValOrZero(llvm::BasicBlock *block, llvm::Value *state_ptr, + const std::string ®_name, llvm::ConstantInt *zero); std::unordered_map reg_ptr_cache; diff --git a/remill/BC/Optimizer.h b/remill/BC/Optimizer.h index ed5d54d5c..0a5a2e6ac 100644 --- a/remill/BC/Optimizer.h +++ b/remill/BC/Optimizer.h @@ -16,6 +16,8 @@ #pragma once +#include + #include #include #include @@ -25,8 +27,6 @@ #include #include -#include - namespace llvm { class Function; } // namespace llvm diff --git a/remill/BC/Util.cpp b/remill/BC/Util.cpp index e7a9c62f3..9ebe73f9a 100644 --- a/remill/BC/Util.cpp +++ b/remill/BC/Util.cpp @@ -299,6 +299,7 @@ std::unique_ptr LoadArchSemantics(const Arch *arch) { LOG(INFO) << "Loading " << arch_name << " semantics from file " << path; auto module = LoadModuleFromFile(arch->context, path); arch->PrepareModule(module); + arch->InitFromSemanticsModule(module.get()); for (auto &func : *module) { Annotate(&func); } diff --git a/remill/BC/Util.h b/remill/BC/Util.h index e94d9bd39..95a1d3f28 100644 --- a/remill/BC/Util.h +++ b/remill/BC/Util.h @@ -16,9 +16,12 @@ #pragma once +// clang-format off +#include "remill/BC/Compat/CTypes.h" #include #include #include +// clang-format on #include #include diff --git a/remill/Version/Version.h b/remill/Version/Version.h index f2266f24d..b42eb9b85 100644 --- a/remill/Version/Version.h +++ b/remill/Version/Version.h @@ -1,21 +1,22 @@ #pragma once + // Copyright (C) 2020 Trail of Bits // Based on: https://github.com/andrew-hardin/cmake-git-version-tracking/blob/master/better-example/git.h // Which is (C) 2020 Andrew Hardin -// +// // MIT License // Copyright (c) 2020 Andrew Hardin -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -30,15 +31,15 @@ namespace remill { namespace Version { - bool HasVersionData(); - bool HasUncommittedChanges(); - std::string GetAuthorName(); - std::string GetAuthorEmail(); - std::string GetCommitHash(); - std::string GetCommitDate(); - std::string GetCommitSubject(); - std::string GetCommitBody(); - std::string GetVersionString(); +bool HasVersionData(); +bool HasUncommittedChanges(); +std::string GetAuthorName(); +std::string GetAuthorEmail(); +std::string GetCommitHash(); +std::string GetCommitDate(); +std::string GetCommitSubject(); +std::string GetCommitBody(); +std::string GetVersionString(); } // namespace Version } // namespace remill diff --git a/scripts/travis.bat b/scripts/travis.bat index 76d62f05d..5b887f78f 100755 --- a/scripts/travis.bat +++ b/scripts/travis.bat @@ -73,7 +73,7 @@ exit /B %ERRORLEVEL% set tob_libraries=%CD% popd - cmake -G "Visual Studio 16 2019" -T llvm -A x64 -DCMAKE_BUILD_TYPE=Release -DLIBRARY_REPOSITORY_ROOT=%tob_libraries% -DCMAKE_INSTALL_PREFIX=C:\ .. + cmake -G "Visual Studio 16 2019" -T llvm -A x64 -DCMAKE_BUILD_TYPE=Release -DCXX_COMMON_REPOSITORY_ROOT=%tob_libraries% -DCMAKE_INSTALL_PREFIX=C:\ .. if %ERRORLEVEL% equ 0 ( endlocal exit /B 0 diff --git a/tools/lift/Lift.cpp b/tools/lift/Lift.cpp index 3509e75e5..d3fc9b0c8 100644 --- a/tools/lift/Lift.cpp +++ b/tools/lift/Lift.cpp @@ -185,21 +185,22 @@ static void MuteStateEscape(llvm::Module *module, const char *func_name) { static void SetVersion() { std::stringstream ss; auto vs = remill::Version::GetVersionString(); - if(0 == vs.size()) { - vs = "unknown"; + if (0 == vs.size()) { + vs = "unknown"; } ss << vs << "\n"; - if(!remill::Version::HasVersionData()) { + if (!remill::Version::HasVersionData()) { ss << "No extended version information found!\n"; } else { ss << "Commit Hash: " << remill::Version::GetCommitHash() << "\n"; ss << "Commit Date: " << remill::Version::GetCommitDate() << "\n"; - ss << "Last commit by: " << remill::Version::GetAuthorName() << " [" << remill::Version::GetAuthorEmail() << "]\n"; + ss << "Last commit by: " << remill::Version::GetAuthorName() << " [" + << remill::Version::GetAuthorEmail() << "]\n"; ss << "Commit Subject: [" << remill::Version::GetCommitSubject() << "]\n"; ss << "\n"; - if(remill::Version::HasUncommittedChanges()) { + if (remill::Version::HasUncommittedChanges()) { ss << "Uncommitted changes were present during build.\n"; - } else { + } else { ss << "All changes were committed prior to building.\n"; } } From 98767019cb690f7e5bfbbde2b9d07ac091266095 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 15 Sep 2020 17:16:40 -0400 Subject: [PATCH 002/130] Initial start to support for AArch 32 --- CMakeLists.txt | 4 + remill/Arch/AArch32/Arch.cpp | 233 +++++++++++++++++++ remill/Arch/AArch32/Runtime/BasicBlock.cpp | 36 +++ remill/Arch/AArch32/Runtime/CMakeLists.txt | 57 +++++ remill/Arch/AArch32/Runtime/Instructions.cpp | 74 ++++++ remill/Arch/AArch32/Runtime/State.h | 85 +++++++ remill/Arch/Arch.cpp | 12 +- remill/Arch/Arch.h | 5 + remill/Arch/Instruction.cpp | 1 + remill/Arch/Name.cpp | 6 + remill/Arch/Name.h | 13 +- remill/Arch/Runtime/HyperCall.h | 1 + remill/BC/Util.cpp | 7 + 13 files changed, 532 insertions(+), 2 deletions(-) create mode 100644 remill/Arch/AArch32/Arch.cpp create mode 100644 remill/Arch/AArch32/Runtime/BasicBlock.cpp create mode 100644 remill/Arch/AArch32/Runtime/CMakeLists.txt create mode 100644 remill/Arch/AArch32/Runtime/Instructions.cpp create mode 100644 remill/Arch/AArch32/Runtime/State.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 19d0ae5c8..f5200bfef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,10 +122,12 @@ endif() set(REMILL_BUILD_SEMANTICS_DIR_X86 "${CMAKE_CURRENT_BINARY_DIR}/remill/Arch/X86/Runtime/") set(REMILL_BUILD_SEMANTICS_DIR_AARCH64 "${CMAKE_CURRENT_BINARY_DIR}/remill/Arch/AArch64/Runtime/") +set(REMILL_BUILD_SEMANTICS_DIR_AARCH32 "${CMAKE_CURRENT_BINARY_DIR}/remill/Arch/AArch32/Runtime/") list(APPEND PROJECT_DEFINITIONS "REMILL_INSTALL_SEMANTICS_DIR=\"${REMILL_INSTALL_SEMANTICS_DIR}/\"") list(APPEND PROJECT_DEFINITIONS "REMILL_BUILD_SEMANTICS_DIR_X86=\"${REMILL_BUILD_SEMANTICS_DIR_X86}\"") list(APPEND PROJECT_DEFINITIONS "REMILL_BUILD_SEMANTICS_DIR_AARCH64=\"${REMILL_BUILD_SEMANTICS_DIR_AARCH64}\"") +list(APPEND PROJECT_DEFINITIONS "REMILL_BUILD_SEMANTICS_DIR_AARCH32=\"${REMILL_BUILD_SEMANTICS_DIR_AARCH32}\"") # verion data add_subdirectory(remill/Version) @@ -135,6 +137,7 @@ add_library(${PROJECT_NAME} STATIC remill/Arch/AArch64/Decode.cpp remill/Arch/AArch64/Extract.cpp remill/Arch/X86/Arch.cpp + remill/Arch/AArch32/Arch.cpp remill/Arch/Arch.cpp remill/Arch/Instruction.cpp @@ -381,6 +384,7 @@ add_custom_target(semantics) # runtimes add_subdirectory(remill/Arch/X86/Runtime) add_subdirectory(remill/Arch/AArch64/Runtime) +add_subdirectory(remill/Arch/AArch32/Runtime) # tools add_subdirectory(tools) diff --git a/remill/Arch/AArch32/Arch.cpp b/remill/Arch/AArch32/Arch.cpp new file mode 100644 index 000000000..79a71d157 --- /dev/null +++ b/remill/Arch/AArch32/Arch.cpp @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "remill/Arch/Arch.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "remill/Arch/Instruction.h" +#include "remill/Arch/Name.h" +#include "remill/BC/ABI.h" +#include "remill/BC/Util.h" +#include "remill/BC/Version.h" +#include "remill/OS/OS.h" + +// clang-format off +#define ADDRESS_SIZE 32 +#include "Runtime/State.h" + +// clang-format on + +namespace remill { +namespace { + + + +class AArch32Arch final : public Arch { + public: + AArch32Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_); + + virtual ~AArch32Arch(void); + + // Returns the name of the stack pointer register. + const char *StackPointerRegisterName(void) const override; + + // Returns the name of the program counter register. + const char *ProgramCounterRegisterName(void) const override; + + // Decode an instuction. + bool DecodeInstruction(uint64_t address, std::string_view inst_bytes, + Instruction &inst) const override; + + // Maximum number of bytes in an instruction. + uint64_t MaxInstructionSize(void) const override; + + llvm::Triple Triple(void) const override; + llvm::DataLayout DataLayout(void) const override; + + // Default calling convention for this architecture. + llvm::CallingConv::ID DefaultCallingConv(void) const override; + + // Populate the `__remill_basic_block` function with variables. + void PopulateBasicBlockFunction(llvm::Module *module, + llvm::Function *bb_func) const override; + + private: + // Decode an instuction. + bool DecodeInstruction(uint64_t address, std::string_view inst_bytes, + Instruction &inst, bool is_lazy) const; + + AArch32Arch(void) = delete; +}; + +AArch32Arch::AArch32Arch(llvm::LLVMContext *context_, OSName os_name_, + ArchName arch_name_) + : Arch(context_, os_name_, arch_name_) {} + +AArch32Arch::~AArch32Arch(void) {} + +// Maximum number of bytes in an instruction for this particular architecture. +uint64_t AArch32Arch::MaxInstructionSize(void) const { + return 4; +} + +// Default calling convention for this architecture. +llvm::CallingConv::ID AArch32Arch::DefaultCallingConv(void) const { + return llvm::CallingConv::C; // cdecl. +} + +// Get the LLVM triple for this architecture. +llvm::Triple AArch32Arch::Triple(void) const { + auto triple = BasicTriple(); + switch (arch_name) { + case kArchAArch32LittleEndian: triple.setArch(llvm::Triple::arm); break; + default: + LOG(FATAL) << "Cannot get triple for non-aarch32 architecture " + << GetArchName(arch_name); + } + + return triple; +} + +// Get the LLVM DataLayout for a module. +llvm::DataLayout AArch32Arch::DataLayout(void) const { + std::string dl; + switch (os_name) { + case kOSInvalid: + LOG(FATAL) << "Cannot convert module for an unrecognized OS."; + break; + + case kOSLinux: + case kOSSolaris: + case kOSmacOS: + case kOSWindows: + dl = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"; + break; + } + + return llvm::DataLayout(dl); +} + +// Decode an instuction. +bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes, + Instruction &inst, bool is_lazy) const { + + inst.pc = address; + inst.arch_name = arch_name; + inst.category = Instruction::kCategoryInvalid; + + return false; +} + +// Returns the name of the stack pointer register. +const char *AArch32Arch::StackPointerRegisterName(void) const { + return "SP"; +} + +// Returns the name of the program counter register. +const char *AArch32Arch::ProgramCounterRegisterName(void) const { + return "PC"; +} + +bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes, + Instruction &inst) const { + inst.arch_for_decode = this; + return DecodeInstruction(address, inst_bytes, inst, false); +} + +// Populate the `__remill_basic_block` function with variables. +void AArch32Arch::PopulateBasicBlockFunction(llvm::Module *module, + llvm::Function *bb_func) const { + const auto &dl = module->getDataLayout(); + CHECK_EQ(sizeof(State), dl.getTypeAllocSize(StateStructType())) + << "Mismatch between size of State type for x86/amd64 and what is in " + << "the bitcode module"; + + auto &context = module->getContext(); +// auto u8 = llvm::Type::getInt8Ty(context); +// auto u16 = llvm::Type::getInt16Ty(context); + auto u32 = llvm::Type::getInt32Ty(context); +// auto u64 = llvm::Type::getInt64Ty(context); +// auto f64 = llvm::Type::getDoubleTy(context); +// auto v128 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 128u / 8u); +// auto v256 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 256u / 8u); +// auto v512 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 512u / 8u); + auto addr = llvm::Type::getIntNTy(context, address_size); + //auto zero_addr_val = llvm::Constant::getNullValue(addr); + + const auto entry_block = &bb_func->getEntryBlock(); + llvm::IRBuilder<> ir(entry_block); + +#define OFFSET_OF(type, access) \ + (reinterpret_cast(&reinterpret_cast( \ + static_cast(nullptr)->access))) + +#define REG(name, access, type) \ + AddRegister(#name, type, OFFSET_OF(State, access), nullptr) + +#define SUB_REG(name, access, type, parent_reg_name) \ + AddRegister(#name, type, OFFSET_OF(State, access), #parent_reg_name) + + REG(R0, gpr.r0.dword, u32); + REG(R1, gpr.r1.dword, u32); + REG(R2, gpr.r2.dword, u32); + REG(R3, gpr.r3.dword, u32); + REG(R4, gpr.r4.dword, u32); + REG(R5, gpr.r5.dword, u32); + REG(R6, gpr.r6.dword, u32); + REG(R7, gpr.r7.dword, u32); + REG(R8, gpr.r8.dword, u32); + REG(R9, gpr.r9.dword, u32); + REG(R10, gpr.r10.dword, u32); + REG(R11, gpr.r11.dword, u32); + REG(R12, gpr.r12.dword, u32); + REG(R13, gpr.r13.dword, u32); + REG(R14, gpr.r14.dword, u32); + REG(R15, gpr.r15.dword, u32); + + SUB_REG(SP, gpr.r13.dword, u32, R13); + SUB_REG(LR, gpr.r14.dword, u32, R14); + SUB_REG(PC, gpr.r15.dword, u32, R15); + + const auto pc_arg = NthArgument(bb_func, kPCArgNum); + const auto state_ptr_arg = NthArgument(bb_func, kStatePointerArgNum); + ir.CreateStore(pc_arg, ir.CreateAlloca(addr, nullptr, "NEXT_PC")); + + ir.CreateAlloca(u32, nullptr, "SUPPRESS_WRITEBACK"); + (void) this->RegisterByName("PC")->AddressOf(state_ptr_arg, ir); +} + +} // namespace + +// TODO(pag): We pretend that these are singletons, but they aren't really! +Arch::ArchPtr Arch::GetAArch32(llvm::LLVMContext *context_, OSName os_name_, + ArchName arch_name_) { + return std::make_unique(context_, os_name_, arch_name_); +} + +} // namespace remill diff --git a/remill/Arch/AArch32/Runtime/BasicBlock.cpp b/remill/Arch/AArch32/Runtime/BasicBlock.cpp new file mode 100644 index 000000000..7619fde1f --- /dev/null +++ b/remill/Arch/AArch32/Runtime/BasicBlock.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "remill/Arch/AArch32/Runtime/State.h" +#include "remill/Arch/Float.h" + +extern "C" { + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-variable" + +// Instructions will be lifted into clones of this function. +[[gnu::used]] Memory *__remill_basic_block(State &, addr_t, Memory *); + +#pragma clang diagnostic pop + +} // extern C + +#include "remill/Arch/Runtime/Intrinsics.cpp" diff --git a/remill/Arch/AArch32/Runtime/CMakeLists.txt b/remill/Arch/AArch32/Runtime/CMakeLists.txt new file mode 100644 index 000000000..804315222 --- /dev/null +++ b/remill/Arch/AArch32/Runtime/CMakeLists.txt @@ -0,0 +1,57 @@ +# Copyright (c) 2017 Trail of Bits, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.2) +project(arm_runtime) + +set(ARMRUNTIME_SOURCEFILES + Instructions.cpp + BasicBlock.cpp +) + +set_source_files_properties(Instructions.cpp PROPERTIES COMPILE_FLAGS "-O3 -g0") +set_source_files_properties(BasicBlock.cpp PROPERTIES COMPILE_FLAGS "-O0 -g3") + +if(DEFINED WIN32) + set(install_folder "${CMAKE_INSTALL_PREFIX}/remill/${REMILL_LLVM_VERSION}/semantics") +else() + set(install_folder "${CMAKE_INSTALL_PREFIX}/share/remill/${REMILL_LLVM_VERSION}/semantics") +endif() + +function(add_runtime_helper target_name address_bit_size little_endian) + message(" > Generating runtime target: ${target_name}") + + # Visual C++ requires C++14 + if(WIN32) + set(required_cpp_standard "c++14") + else() + set(required_cpp_standard "c++17") + endif() + + add_runtime(${target_name} + SOURCES ${ARMRUNTIME_SOURCEFILES} + ADDRESS_SIZE ${address_bit_size} + DEFINITIONS "LITTLE_ENDIAN=${little_endian}" + BCFLAGS "-std=${required_cpp_standard}" + INCLUDEDIRECTORIES "${CMAKE_SOURCE_DIR}" + INSTALLDESTINATION "${install_folder}" + + DEPENDENCIES + + ) +endfunction() + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + add_runtime_helper(aarch32 32 1) +endif() diff --git a/remill/Arch/AArch32/Runtime/Instructions.cpp b/remill/Arch/AArch32/Runtime/Instructions.cpp new file mode 100644 index 000000000..cea35d7a9 --- /dev/null +++ b/remill/Arch/AArch32/Runtime/Instructions.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +// clang-format off +#include "remill/Arch/Float.h" +#include "remill/Arch/Runtime/Intrinsics.h" +#include "remill/Arch/Runtime/Operators.h" +#include "remill/Arch/AArch32/Runtime/State.h" +//#include "remill/Arch/AArch32/Runtime/Types.h" +//#include "remill/Arch/AArch32/Runtime/Operators.h" + +// clang-format on + +#define REG_PC state.gpr.r15.dword +#define REG_SP state.gpr.r13.dword + +#define HYPER_CALL state.hyper_call +#define INTERRUPT_VECTOR state.hyper_call_vector +#define HYPER_CALL_VECTOR state.hyper_call_vector + +namespace { + +// Takes the place of an unsupported instruction. +DEF_SEM(HandleUnsupported) { + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kAArch32EmulateInstruction); +} + +// Takes the place of an invalid instruction. +DEF_SEM(HandleInvalidInstruction) { + HYPER_CALL = AsyncHyperCall::kInvalidInstruction; + return memory; +} + +} // namespace + +// Takes the place of an unsupported instruction. +DEF_ISEL(UNSUPPORTED_INSTRUCTION) = HandleUnsupported; +DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; + +// clang-format off +//#include "remill/Arch/AArch64/Semantics/FLAGS.cpp" +// +//#include "remill/Arch/AArch64/Semantics/BINARY.cpp" +//#include "remill/Arch/AArch64/Semantics/BITBYTE.cpp" +//#include "remill/Arch/AArch64/Semantics/BRANCH.cpp" +//#include "remill/Arch/AArch64/Semantics/CALL_RET.cpp" +//#include "remill/Arch/AArch64/Semantics/COND.cpp" +//#include "remill/Arch/AArch64/Semantics/CONVERT.cpp" +//#include "remill/Arch/AArch64/Semantics/DATAXFER.cpp" +//#include "remill/Arch/AArch64/Semantics/LOGICAL.cpp" +//#include "remill/Arch/AArch64/Semantics/MISC.cpp" +//#include "remill/Arch/AArch64/Semantics/SHIFT.cpp" +//#include "remill/Arch/AArch64/Semantics/SIMD.cpp" +//#include "remill/Arch/AArch64/Semantics/SYSTEM.cpp" + +// clang-format on diff --git a/remill/Arch/AArch32/Runtime/State.h b/remill/Arch/AArch32/Runtime/State.h new file mode 100644 index 000000000..92ca82b57 --- /dev/null +++ b/remill/Arch/AArch32/Runtime/State.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#pragma clang diagnostic push +#pragma clang diagnostic fatal "-Wpadded" + +#include "remill/Arch/Runtime/State.h" +#include "remill/Arch/Runtime/Types.h" + +struct Reg final { + alignas(4) uint32_t dword; +} __attribute__((packed)); + +static_assert(sizeof(uint32_t) == sizeof(Reg), "Invalid packing of `Reg`."); +static_assert(0 == __builtin_offsetof(Reg, dword), + "Invalid packing of `Reg::dword`."); + +struct alignas(8) GPR final { + + // Prevents LLVM from casting a `GPR` into an `i64` to access `X0`. + volatile uint32_t _0; + Reg r0; + volatile uint32_t _1; + Reg r1; + volatile uint32_t _2; + Reg r2; + volatile uint32_t _3; + Reg r3; + volatile uint32_t _4; + Reg r4; + volatile uint32_t _5; + Reg r5; + volatile uint32_t _6; + Reg r6; + volatile uint32_t _7; + Reg r7; + volatile uint32_t _8; + Reg r8; + volatile uint32_t _9; + Reg r9; + volatile uint32_t _10; + Reg r10; + volatile uint32_t _11; + Reg r11; + volatile uint32_t _12; + Reg r12; + // R13 is SP (stack pointer) + volatile uint32_t _13; + Reg r13; + // R14 is LR (link register) + volatile uint32_t _14; + Reg r14; + // R15 is PC (program counter) + volatile uint32_t _15; + Reg r15; + + +} __attribute__((packed)); + +struct alignas(16) State final : public ArchState { + + + GPR gpr; // 528 bytes. + + +} __attribute__((packed)); + +using AArch32State = State; + +#pragma clang diagnostic pop diff --git a/remill/Arch/Arch.cpp b/remill/Arch/Arch.cpp index 6d7e9a816..07a2bbb19 100644 --- a/remill/Arch/Arch.cpp +++ b/remill/Arch/Arch.cpp @@ -46,7 +46,7 @@ DEFINE_string(arch, REMILL_ARCH, "Architecture of the code being translated. " "Valid architectures: x86, amd64 (with or without " - "`_avx` or `_avx512` appended), aarch64"); + "`_avx` or `_avx512` appended), aarch64, aarch32"); DECLARE_string(os); @@ -85,6 +85,7 @@ static unsigned AddressSize(ArchName arch_name) { case kArchAMD64_AVX: case kArchAMD64_AVX512: case kArchAArch64LittleEndian: return 64; + case kArchAArch32LittleEndian: return 32; } return 0; } @@ -169,6 +170,11 @@ auto Arch::Build(llvm::LLVMContext *context_, OSName os_name_, return GetAArch64(context_, os_name_, arch_name_); } + case kArchAArch32LittleEndian: { + DLOG(INFO) << "Using architecture: AArch32, feature set: Little Endian"; + return GetAArch32(context_, os_name_, arch_name_); + } + case kArchX86: { DLOG(INFO) << "Using architecture: X86"; return GetX86(context_, os_name_, arch_name_); @@ -346,6 +352,10 @@ bool Arch::IsAArch64(void) const { return remill::kArchAArch64LittleEndian == arch_name; } +bool Arch::IsAArch32(void) const { + return remill::kArchAArch32LittleEndian == arch_name; +} + bool Arch::IsWindows(void) const { return remill::kOSWindows == os_name; } diff --git a/remill/Arch/Arch.h b/remill/Arch/Arch.h index 0b841f822..d5e118542 100644 --- a/remill/Arch/Arch.h +++ b/remill/Arch/Arch.h @@ -237,6 +237,7 @@ class Arch { bool IsX86(void) const; bool IsAMD64(void) const; bool IsAArch64(void) const; + bool IsAArch32(void) const; bool IsWindows(void) const; bool IsLinux(void) const; @@ -277,6 +278,10 @@ class Arch { static ArchPtr GetAArch64(llvm::LLVMContext *context, OSName os, ArchName arch_name); + // Defined in `remill/Arch/AArch32/Arch.cpp`. + static ArchPtr GetAArch32(llvm::LLVMContext *context, OSName os, + ArchName arch_name); + mutable std::unique_ptr impl; Arch(void) = delete; diff --git a/remill/Arch/Instruction.cpp b/remill/Arch/Instruction.cpp index 4cb927711..b2e5b7830 100644 --- a/remill/Arch/Instruction.cpp +++ b/remill/Arch/Instruction.cpp @@ -272,6 +272,7 @@ std::string Instruction::Serialize(void) const { case kArchX86_AVX: case kArchX86_AVX512: ss << "X86"; break; case kArchAArch64LittleEndian: ss << "AArch64"; break; + case kArchAArch32LittleEndian: ss << "AArch32"; break; } ss << " " << std::hex << pc; diff --git a/remill/Arch/Name.cpp b/remill/Arch/Name.cpp index 281bc1b68..a98c2cfa9 100644 --- a/remill/Arch/Name.cpp +++ b/remill/Arch/Name.cpp @@ -25,6 +25,8 @@ ArchName GetArchName(const llvm::Triple &triple) { case llvm::Triple::ArchType::x86: return kArchX86; case llvm::Triple::ArchType::x86_64: return kArchAMD64; case llvm::Triple::ArchType::aarch64: return kArchAArch64LittleEndian; + case llvm::Triple::ArchType::arm: return kArchAArch32LittleEndian; + case llvm::Triple::ArchType::thumb: return kArchAArch32LittleEndian; default: return kArchInvalid; } } @@ -51,6 +53,9 @@ ArchName GetArchName(const std::string &arch_name) { } else if (arch_name == "aarch64") { return kArchAArch64LittleEndian; + } else if (arch_name == "aarch32") { + return kArchAArch32LittleEndian; + } else { return kArchInvalid; } @@ -66,6 +71,7 @@ std::string GetArchName(ArchName arch_name) { case kArchAMD64_AVX: return "amd64_avx"; case kArchAMD64_AVX512: return "amd64_avx512"; case kArchAArch64LittleEndian: return "aarch64"; + case kArchAArch32LittleEndian: return "aarch32"; } return "invalid"; } diff --git a/remill/Arch/Name.h b/remill/Arch/Name.h index dc42c2319..b76f8b144 100644 --- a/remill/Arch/Name.h +++ b/remill/Arch/Name.h @@ -22,21 +22,31 @@ # define REMILL_ON_AMD64 1 # define REMILL_ON_X86 0 # define REMILL_ON_AARCH64 0 +# define REMILL_ON_AARCH32 0 # elif defined(__i386__) || defined(_M_X86) # define REMILL_ARCH "x86" # define REMILL_ON_AMD64 0 # define REMILL_ON_X86 1 # define REMILL_ON_AARCH64 0 +# define REMILL_ON_AARCH32 0 # elif defined(__aarch64__) # define REMILL_ARCH "aarch64" # define REMILL_ON_AMD64 0 # define REMILL_ON_X86 0 # define REMILL_ON_AARCH64 1 +# define REMILL_ON_AARCH32 0 +# elif defined(__arm__) || defined(__ARM_ARCH_7__) || defined(_M_ARM) +# define REMILL_ARCH "aarch32" +# define REMILL_ON_AARCH32 1 +# define REMILL_ON_AMD64 0 +# define REMILL_ON_X86 0 +# define REMILL_ON_AARCH64 0 # else # error "Cannot infer current architecture." # define REMILL_ON_AMD64 0 # define REMILL_ON_X86 0 # define REMILL_ON_AARCH64 0 +# define REMILL_ON_AARCH32 0 # endif #endif @@ -58,7 +68,8 @@ enum ArchName : uint32_t { kArchAMD64_AVX, kArchAMD64_AVX512, - kArchAArch64LittleEndian + kArchAArch64LittleEndian, + kArchAArch32LittleEndian }; ArchName GetArchName(const llvm::Triple &triple); diff --git a/remill/Arch/Runtime/HyperCall.h b/remill/Arch/Runtime/HyperCall.h index a353e1f4b..46ad3183f 100644 --- a/remill/Arch/Runtime/HyperCall.h +++ b/remill/Arch/Runtime/HyperCall.h @@ -60,6 +60,7 @@ class SyncHyperCall { // TODO(pag): How to distinguish little- and big-endian? kAArch64EmulateInstruction = 0x200U, kAArch64Breakpoint, + kAArch32EmulateInstruction = 0x300U, }; } __attribute__((packed)); diff --git a/remill/BC/Util.cpp b/remill/BC/Util.cpp index 9ebe73f9a..745eef00b 100644 --- a/remill/BC/Util.cpp +++ b/remill/BC/Util.cpp @@ -449,6 +449,12 @@ namespace { # define REMILL_BUILD_SEMANTICS_DIR_AARCH64 #endif // REMILL_BUILD_SEMANTICS_DIR_AARCH64 +#ifndef REMILL_BUILD_SEMANTICS_DIR_AARCH32 +# error \ + "Macro `REMILL_BUILD_SEMANTICS_DIR_AARCH32` must be defined to support AArch32 architecture." +# define REMILL_BUILD_SEMANTICS_DIR_AARCH32 +#endif // REMILL_BUILD_SEMANTICS_DIR_AARCH32 + #ifndef REMILL_INSTALL_SEMANTICS_DIR # error "Macro `REMILL_INSTALL_SEMANTICS_DIR` must be defined." # define REMILL_INSTALL_SEMANTICS_DIR @@ -463,6 +469,7 @@ static const char *gSemanticsSearchPaths[] = { // Derived from the build. REMILL_BUILD_SEMANTICS_DIR_X86 "\0", REMILL_BUILD_SEMANTICS_DIR_AARCH64 "\0", + REMILL_BUILD_SEMANTICS_DIR_AARCH32 "\0", REMILL_INSTALL_SEMANTICS_DIR "\0", "/usr/local/share/remill/" MAJOR_MINOR "/semantics", "/usr/share/remill/" MAJOR_MINOR "/semantics", From 78961ef98d61f930ecbc3af066558d3b53edfd69 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 17 Sep 2020 14:53:19 -0400 Subject: [PATCH 003/130] Progress --- CMakeLists.txt | 5 +++ remill/Arch/AArch32/Arch.cpp | 63 ++---------------------------------- remill/Arch/Instruction.cpp | 35 ++++++++++++++++++++ remill/Arch/Instruction.h | 21 ++++++++++++ 4 files changed, 63 insertions(+), 61 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f5200bfef..01e2ae5a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,10 +138,15 @@ add_library(${PROJECT_NAME} STATIC remill/Arch/AArch64/Extract.cpp remill/Arch/X86/Arch.cpp remill/Arch/AArch32/Arch.cpp + remill/Arch/AArch32/Arch.h + remill/Arch/AArch32/Decode.cpp remill/Arch/Arch.cpp + remill/Arch/Arch.h remill/Arch/Instruction.cpp + remill/Arch/Instruction.h remill/Arch/Name.cpp + remill/Arch/Name.h remill/BC/Annotate.cpp remill/BC/DeadStoreEliminator.cpp diff --git a/remill/Arch/AArch32/Arch.cpp b/remill/Arch/AArch32/Arch.cpp index 79a71d157..1abbeb399 100644 --- a/remill/Arch/AArch32/Arch.cpp +++ b/remill/Arch/AArch32/Arch.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "remill/Arch/Arch.h" +#include "Arch.h" #include #include @@ -44,46 +44,6 @@ // clang-format on namespace remill { -namespace { - - - -class AArch32Arch final : public Arch { - public: - AArch32Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_); - - virtual ~AArch32Arch(void); - - // Returns the name of the stack pointer register. - const char *StackPointerRegisterName(void) const override; - - // Returns the name of the program counter register. - const char *ProgramCounterRegisterName(void) const override; - - // Decode an instuction. - bool DecodeInstruction(uint64_t address, std::string_view inst_bytes, - Instruction &inst) const override; - - // Maximum number of bytes in an instruction. - uint64_t MaxInstructionSize(void) const override; - - llvm::Triple Triple(void) const override; - llvm::DataLayout DataLayout(void) const override; - - // Default calling convention for this architecture. - llvm::CallingConv::ID DefaultCallingConv(void) const override; - - // Populate the `__remill_basic_block` function with variables. - void PopulateBasicBlockFunction(llvm::Module *module, - llvm::Function *bb_func) const override; - - private: - // Decode an instuction. - bool DecodeInstruction(uint64_t address, std::string_view inst_bytes, - Instruction &inst, bool is_lazy) const; - - AArch32Arch(void) = delete; -}; AArch32Arch::AArch32Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_) @@ -133,17 +93,6 @@ llvm::DataLayout AArch32Arch::DataLayout(void) const { return llvm::DataLayout(dl); } -// Decode an instuction. -bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes, - Instruction &inst, bool is_lazy) const { - - inst.pc = address; - inst.arch_name = arch_name; - inst.category = Instruction::kCategoryInvalid; - - return false; -} - // Returns the name of the stack pointer register. const char *AArch32Arch::StackPointerRegisterName(void) const { return "SP"; @@ -154,12 +103,6 @@ const char *AArch32Arch::ProgramCounterRegisterName(void) const { return "PC"; } -bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes, - Instruction &inst) const { - inst.arch_for_decode = this; - return DecodeInstruction(address, inst_bytes, inst, false); -} - // Populate the `__remill_basic_block` function with variables. void AArch32Arch::PopulateBasicBlockFunction(llvm::Module *module, llvm::Function *bb_func) const { @@ -222,8 +165,6 @@ void AArch32Arch::PopulateBasicBlockFunction(llvm::Module *module, (void) this->RegisterByName("PC")->AddressOf(state_ptr_arg, ir); } -} // namespace - // TODO(pag): We pretend that these are singletons, but they aren't really! Arch::ArchPtr Arch::GetAArch32(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_) { diff --git a/remill/Arch/Instruction.cpp b/remill/Arch/Instruction.cpp index b2e5b7830..d881365a0 100644 --- a/remill/Arch/Instruction.cpp +++ b/remill/Arch/Instruction.cpp @@ -216,6 +216,30 @@ std::string Operand::Serialize(void) const { return ss.str(); } +std::string Condition::Serialize(void) const { + std::stringstream ss; + + ss << "("; + switch (kind) { + case Condition::kTypeIsEqual: + ss << "(REG_" << lhs_reg.size << " " << lhs_reg.name << ") = (REG_" + << rhs_reg.size << " " << rhs_reg.name << ")"; + break; + case Condition::kTypeIsOne: + ss << "(REG_" << lhs_reg.size << " " << lhs_reg.name << ") = 1"; + break; + case Condition::kTypeIsZero: + ss << "(REG_" << lhs_reg.size << " " << lhs_reg.name << ") = 0"; + break; + case Condition::kTypeTrue: + ss << "TRUE"; + break; + + } + return ss.str(); +} + + Instruction::Instruction(void) : pc(0), next_pc(0), @@ -228,6 +252,7 @@ Instruction::Instruction(void) has_branch_taken_delay_slot(false), has_branch_not_taken_delay_slot(false), in_delay_slot(false), + negate_conditions(false), category(Instruction::kCategoryInvalid) {} void Instruction::Reset(void) { @@ -241,9 +266,11 @@ void Instruction::Reset(void) { has_branch_taken_delay_slot = false; has_branch_not_taken_delay_slot = false; in_delay_slot = false; + negate_conditions = false; category = Instruction::kCategoryInvalid; arch_for_decode = nullptr; operands.clear(); + conditions.clear(); function.clear(); bytes.clear(); } @@ -353,6 +380,14 @@ std::string Instruction::Serialize(void) const { default: break; } + auto end = ""; + auto sep = " (CONDS "; + for (const auto &cond: conditions) { + ss << sep << cond.Serialize(); + sep = " AND "; + end = ")"; + } + ss << end; ss << ")"; return ss.str(); } diff --git a/remill/Arch/Instruction.h b/remill/Arch/Instruction.h index 753dfbbba..290430d74 100644 --- a/remill/Arch/Instruction.h +++ b/remill/Arch/Instruction.h @@ -127,6 +127,22 @@ class Operand { std::string Serialize(void) const; }; +class Condition { + public: + + enum Kind { + kTypeTrue, + kTypeIsOne, + kTypeIsZero, + kTypeIsEqual, + } kind; + + Operand::Register lhs_reg; + Operand::Register rhs_reg; + + std::string Serialize(void) const; +}; + // Generic instruction type. class Instruction { public: @@ -173,6 +189,10 @@ class Instruction { // Is this instruction decoded within the context of a delay slot? bool in_delay_slot; + // If `conditions` is non-empty then this tells us if we should negate the + // result of the condition. + bool negate_conditions; + enum Category { kCategoryInvalid, kCategoryNormal, @@ -189,6 +209,7 @@ class Instruction { } category; std::vector operands; + std::vector conditions; std::string Serialize(void) const; From f2923704800c13a93713c2992dd66595cd4a4a4f Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 17 Sep 2020 14:59:30 -0400 Subject: [PATCH 004/130] Forgot the new files --- remill/Arch/AArch32/Arch.h | 55 +++++ remill/Arch/AArch32/Decode.cpp | 417 +++++++++++++++++++++++++++++++++ 2 files changed, 472 insertions(+) create mode 100644 remill/Arch/AArch32/Arch.h create mode 100644 remill/Arch/AArch32/Decode.cpp diff --git a/remill/Arch/AArch32/Arch.h b/remill/Arch/AArch32/Arch.h new file mode 100644 index 000000000..1f8e8e5be --- /dev/null +++ b/remill/Arch/AArch32/Arch.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "remill/Arch/Arch.h" + +namespace remill { +class AArch32Arch final : public Arch { + public: + AArch32Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_); + + virtual ~AArch32Arch(void); + + // Returns the name of the stack pointer register. + const char *StackPointerRegisterName(void) const override; + + // Returns the name of the program counter register. + const char *ProgramCounterRegisterName(void) const override; + + // Decode an instuction. + bool DecodeInstruction(uint64_t address, std::string_view inst_bytes, + Instruction &inst) const override; + + // Maximum number of bytes in an instruction. + uint64_t MaxInstructionSize(void) const override; + + llvm::Triple Triple(void) const override; + llvm::DataLayout DataLayout(void) const override; + + // Default calling convention for this architecture. + llvm::CallingConv::ID DefaultCallingConv(void) const override; + + // Populate the `__remill_basic_block` function with variables. + void PopulateBasicBlockFunction(llvm::Module *module, + llvm::Function *bb_func) const override; + + private: + AArch32Arch(void) = delete; +}; + +} // namespace remill diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp new file mode 100644 index 000000000..be320ab09 --- /dev/null +++ b/remill/Arch/AArch32/Decode.cpp @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Arch.h" + +#include + +namespace remill { + +namespace { + +//Integer Data Processing (three register, immediate shift) +union IntDataProcessing { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _0 : 1; + uint32_t type : 2; + uint32_t imm5 : 5; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 3; + uint32_t _0000 : 4; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntDataProcessing) == 4, " "); + +static constexpr auto kPCRegNum = 15u; + +static const char * const kIntRegName[] = { + "R0", + "R1", + "R2", + "R3", + "R4", + "R5", + "R6", + "R7", + "R8", + "R9", + "R10", + "R11", + "R12", + "R13", + "R14", + "R15" +}; + +static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, + Operand::Action action) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.type = Operand::kTypeRegister; + op.size = size; + op.action = action; + op.reg.size = size; + op.reg.name = kIntRegName[index]; +} + +// Note: Order is significant; extracted bits may be casted to this type. +enum Shift : uint32_t { kShiftLSL, kShiftLSR, kShiftASR, kShiftROR }; + +// Translate a shift encoding into an operand shift type used by the shift +// register class. +static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { + switch (s) { + case kShiftLSL: + return Operand::ShiftRegister::kShiftLeftWithZeroes; + case kShiftLSR: + return Operand::ShiftRegister::kShiftUnsignedRight; + case kShiftASR: + return Operand::ShiftRegister::kShiftSignedRight; + case kShiftROR: + return Operand::ShiftRegister::kShiftRightAround; + } + return Operand::ShiftRegister::kShiftInvalid; +} + +static void AddShiftRegOperand(Instruction &inst, + uint32_t reg_num, uint32_t shift_type, + uint32_t shift_size) { + if (!shift_size) { + AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); + } else { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.shift_reg.reg.name = kIntRegName[reg_num]; + op.shift_reg.reg.size = 32; + op.shift_reg.shift_op = GetOperandShift(static_cast(shift_type)); + if (shift_type == Shift::kShiftLSR || shift_type == Shift::kShiftASR) { + if (!shift_size) { + shift_size = 32; + } + } else if (shift_type == Shift::kShiftROR) { + LOG_IF(FATAL, !shift_size) + << "Invalid use of AddShiftRegOperand RRX shifts not supported"; + } + op.shift_reg.shift_size = shift_size; + op.type = Operand::kTypeShiftRegister; + op.size = 32; + op.action = Operand::kActionRead; + } +} + +// Decode the condition field and fil in the instruction conditions accordingly +static void DecodeCondition(Instruction &inst, uint32_t cond) { + inst.conditions.emplace_back(); + auto &lhs_cond = inst.conditions.back(); + + switch (cond) { + case 0b0001: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b0000: { + lhs_cond.kind = Condition::kTypeIsOne; + lhs_cond.lhs_reg.name = "Z"; + lhs_cond.lhs_reg.size = 8; + break; + } + case 0b0011: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b0010: { + lhs_cond.kind = Condition::kTypeIsOne; + lhs_cond.lhs_reg.name = "C"; + lhs_cond.lhs_reg.size = 8; + break; + } + case 0b0101: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b0100: { + lhs_cond.kind = Condition::kTypeIsOne; + lhs_cond.lhs_reg.name = "N"; + lhs_cond.lhs_reg.size = 8; + break; + } + case 0b0111: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b0110: { + lhs_cond.kind = Condition::kTypeIsOne; + lhs_cond.lhs_reg.name = "V"; + lhs_cond.lhs_reg.size = 8; + break; + } + case 0b1001: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b1000: { + lhs_cond.kind = Condition::kTypeIsOne; + lhs_cond.lhs_reg.name = "C"; + lhs_cond.lhs_reg.size = 8; + + inst.conditions.emplace_back(); + auto &rhs_cond = inst.conditions.back(); + rhs_cond.kind = Condition::kTypeIsZero; + rhs_cond.rhs_reg.name = "Z"; + rhs_cond.rhs_reg.size = 8; + break; + } + case 0b1011: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b1010: { + lhs_cond.kind = Condition::kTypeIsEqual; + lhs_cond.lhs_reg.name = "N"; + lhs_cond.lhs_reg.size = 8; + + lhs_cond.rhs_reg.name = "V"; + lhs_cond.rhs_reg.size = 8; + break; + } + case 0b1101: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b1100: { + lhs_cond.kind = Condition::kTypeIsEqual; + lhs_cond.lhs_reg.name = "N"; + lhs_cond.lhs_reg.size = 8; + + lhs_cond.rhs_reg.name = "V"; + lhs_cond.rhs_reg.size = 8; + + inst.conditions.emplace_back(); + auto &rhs_cond = inst.conditions.back(); + rhs_cond.kind = Condition::kTypeIsZero; + rhs_cond.rhs_reg.name = "Z"; + rhs_cond.rhs_reg.size = 8; + break; + } + case 0b1111: + case 0b1110: + inst.conditions.pop_back(); + break; + default: + LOG(FATAL) << "Invalid condition bits " << cond << " in " << inst.Serialize(); + break; + } +} + +static bool TryDecodeIntegerDataProcessing(Instruction &inst, uint32_t bits) { + const IntDataProcessing enc = {bits}; + if (enc.cond == 0b1111u) { + return false; + } + if (enc.opc == 0b010u || enc.opc == 0b100u) { + + } + + DecodeCondition(inst, enc.cond); + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); + + if (enc.rd == kPCRegNum) { + inst.category = Instruction::kCategoryIndirectJump; + } else { + inst.category = Instruction::kCategoryNormal; + } + + return true; +} + +static bool (*const kBits27_to_21[])(Instruction&, uint32_t) = { + [0b0000000] = TryDecodeIntegerDataProcessing, + [0b0000001] = TryDecodeIntegerDataProcessing, + [0b0000010] = TryDecodeIntegerDataProcessing, + [0b0000011] = TryDecodeIntegerDataProcessing, + [0b0000100] = TryDecodeIntegerDataProcessing, + [0b0000101] = TryDecodeIntegerDataProcessing, + [0b0000110] = TryDecodeIntegerDataProcessing, + [0b0000111] = TryDecodeIntegerDataProcessing, + [0b0001000] = nullptr, + [0b0001001] = nullptr, + [0b0001010] = nullptr, + [0b0001011] = nullptr, + [0b0001100] = nullptr, + [0b0001101] = nullptr, + [0b0001110] = nullptr, + [0b0001111] = nullptr, + [0b0010000] = nullptr, + [0b0010001] = nullptr, + [0b0010010] = nullptr, + [0b0010011] = nullptr, + [0b0010100] = nullptr, + [0b0010101] = nullptr, + [0b0010110] = nullptr, + [0b0010111] = nullptr, + [0b0011000] = nullptr, + [0b0011001] = nullptr, + [0b0011010] = nullptr, + [0b0011011] = nullptr, + [0b0011100] = nullptr, + [0b0011101] = nullptr, + [0b0011110] = nullptr, + [0b0011111] = nullptr, + [0b0100000] = nullptr, + [0b0100001] = nullptr, + [0b0100010] = nullptr, + [0b0100011] = nullptr, + [0b0100100] = nullptr, + [0b0100101] = nullptr, + [0b0100110] = nullptr, + [0b0100111] = nullptr, + [0b0101000] = nullptr, + [0b0101001] = nullptr, + [0b0101010] = nullptr, + [0b0101011] = nullptr, + [0b0101100] = nullptr, + [0b0101101] = nullptr, + [0b0101110] = nullptr, + [0b0101111] = nullptr, + [0b0110000] = nullptr, + [0b0110001] = nullptr, + [0b0110010] = nullptr, + [0b0110011] = nullptr, + [0b0110100] = nullptr, + [0b0110101] = nullptr, + [0b0110110] = nullptr, + [0b0110111] = nullptr, + [0b0111000] = nullptr, + [0b0111001] = nullptr, + [0b0111010] = nullptr, + [0b0111011] = nullptr, + [0b0111100] = nullptr, + [0b0111101] = nullptr, + [0b0111110] = nullptr, + [0b0111111] = nullptr, + [0b1000000] = nullptr, + [0b1000001] = nullptr, + [0b1000010] = nullptr, + [0b1000011] = nullptr, + [0b1000100] = nullptr, + [0b1000101] = nullptr, + [0b1000110] = nullptr, + [0b1000111] = nullptr, + [0b1001000] = nullptr, + [0b1001001] = nullptr, + [0b1001010] = nullptr, + [0b1001011] = nullptr, + [0b1001100] = nullptr, + [0b1001101] = nullptr, + [0b1001110] = nullptr, + [0b1001111] = nullptr, + [0b1010000] = nullptr, + [0b1010001] = nullptr, + [0b1010010] = nullptr, + [0b1010011] = nullptr, + [0b1010100] = nullptr, + [0b1010101] = nullptr, + [0b1010110] = nullptr, + [0b1010111] = nullptr, + [0b1011000] = nullptr, + [0b1011001] = nullptr, + [0b1011010] = nullptr, + [0b1011011] = nullptr, + [0b1011100] = nullptr, + [0b1011101] = nullptr, + [0b1011110] = nullptr, + [0b1011111] = nullptr, + [0b1100000] = nullptr, + [0b1100001] = nullptr, + [0b1100010] = nullptr, + [0b1100011] = nullptr, + [0b1100100] = nullptr, + [0b1100101] = nullptr, + [0b1100110] = nullptr, + [0b1100111] = nullptr, + [0b1101000] = nullptr, + [0b1101001] = nullptr, + [0b1101010] = nullptr, + [0b1101011] = nullptr, + [0b1101100] = nullptr, + [0b1101101] = nullptr, + [0b1101110] = nullptr, + [0b1101111] = nullptr, + [0b1110000] = nullptr, + [0b1110001] = nullptr, + [0b1110010] = nullptr, + [0b1110011] = nullptr, + [0b1110100] = nullptr, + [0b1110101] = nullptr, + [0b1110110] = nullptr, + [0b1110111] = nullptr, + [0b1111000] = nullptr, + [0b1111001] = nullptr, + [0b1111010] = nullptr, + [0b1111011] = nullptr, + [0b1111100] = nullptr, + [0b1111101] = nullptr, + [0b1111110] = nullptr, + [0b1111111] = nullptr, +}; + + +static uint32_t BytesToBits(const uint8_t *bytes) { + uint32_t bits = 0; + bits = (bits << 8) | static_cast(bytes[0]); + bits = (bits << 8) | static_cast(bytes[1]); + bits = (bits << 8) | static_cast(bytes[2]); + bits = (bits << 8) | static_cast(bytes[3]); + return bits; +} + +} // namespace + +// Decode an instuction. +bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes, + Instruction &inst) const { + + inst.pc = address; + inst.next_pc = address + inst_bytes.size(); // Default fall-through. + inst.branch_taken_pc = 0; + inst.branch_not_taken_pc = 0; + inst.has_branch_taken_delay_slot = false; + inst.has_branch_not_taken_delay_slot = false; + inst.arch_name = arch_name; + inst.arch_for_decode = nullptr; + inst.category = Instruction::kCategoryInvalid; + inst.operands.clear(); + if (!inst.bytes.empty() && inst.bytes.data() == inst_bytes.data()) { + inst.bytes.resize(inst_bytes.size()); + } else { + inst.bytes = inst_bytes; + } + + const auto bytes = reinterpret_cast(inst.bytes.data()); + const auto bits = BytesToBits(bytes); + + auto decoder = kBits27_to_21[(bits >> 21) & 0b1111111u]; + if (!decoder) { + LOG(ERROR) << "unhandled bits"; + return false; + } + + auto ret = decoder(inst, bits); + LOG(ERROR) << inst.Serialize(); + return ret; +} + +} // namespace remill From b83e040c9b5d73c110a1f9d698eb974abd661310 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 23 Sep 2020 12:00:09 -0400 Subject: [PATCH 005/130] Added all data Integer processing instructions without S + ADDS and started ANDS --- remill/Arch/AArch32/Arch.cpp | 9 +- remill/Arch/AArch32/Decode.cpp | 108 ++++++++++- remill/Arch/AArch32/Runtime/CMakeLists.txt | 3 + remill/Arch/AArch32/Runtime/Instructions.cpp | 8 +- remill/Arch/AArch32/Runtime/Operators.h | 32 ++++ remill/Arch/AArch32/Runtime/State.h | 28 +++ remill/Arch/AArch32/Runtime/Types.h | 73 +++++++ remill/Arch/AArch32/Semantics/BINARY.cpp | 113 +++++++++++ remill/Arch/AArch32/Semantics/FLAGS.cpp | 189 +++++++++++++++++++ remill/BC/Util.cpp | 2 +- tools/lift/Lift.cpp | 3 + 11 files changed, 560 insertions(+), 8 deletions(-) create mode 100644 remill/Arch/AArch32/Runtime/Operators.h create mode 100644 remill/Arch/AArch32/Runtime/Types.h create mode 100644 remill/Arch/AArch32/Semantics/BINARY.cpp create mode 100644 remill/Arch/AArch32/Semantics/FLAGS.cpp diff --git a/remill/Arch/AArch32/Arch.cpp b/remill/Arch/AArch32/Arch.cpp index 1abbeb399..2b86f65dc 100644 --- a/remill/Arch/AArch32/Arch.cpp +++ b/remill/Arch/AArch32/Arch.cpp @@ -112,7 +112,7 @@ void AArch32Arch::PopulateBasicBlockFunction(llvm::Module *module, << "the bitcode module"; auto &context = module->getContext(); -// auto u8 = llvm::Type::getInt8Ty(context); + auto u8 = llvm::Type::getInt8Ty(context); // auto u16 = llvm::Type::getInt16Ty(context); auto u32 = llvm::Type::getInt32Ty(context); // auto u64 = llvm::Type::getInt64Ty(context); @@ -157,10 +157,17 @@ void AArch32Arch::PopulateBasicBlockFunction(llvm::Module *module, SUB_REG(LR, gpr.r14.dword, u32, R14); SUB_REG(PC, gpr.r15.dword, u32, R15); + REG(N, sr.n, u8); + REG(C, sr.c, u8); + REG(Z, sr.z, u8); + REG(V, sr.v, u8); + const auto pc_arg = NthArgument(bb_func, kPCArgNum); const auto state_ptr_arg = NthArgument(bb_func, kStatePointerArgNum); ir.CreateStore(pc_arg, ir.CreateAlloca(addr, nullptr, "NEXT_PC")); + auto zero_c = ir.CreateAlloca(u8, nullptr, "ZERO_C"); + ir.CreateStore(llvm::Constant::getNullValue(u8), zero_c); ir.CreateAlloca(u32, nullptr, "SUPPRESS_WRITEBACK"); (void) this->RegisterByName("PC")->AddressOf(state_ptr_arg, ir); } diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index be320ab09..5065d21ab 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -94,6 +94,11 @@ static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { static void AddShiftRegOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_size) { + auto is_rrx = false; + if (!shift_size && shift_type == Shift::kShiftROR) { + shift_size = 1; + is_rrx = true; + } if (!shift_size) { AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); } else { @@ -117,6 +122,66 @@ static void AddShiftRegOperand(Instruction &inst, } } +static void AddShiftCarryOperand(Instruction &inst, + uint32_t reg_num, uint32_t shift_type, + uint32_t shift_size, const char * carry_reg_name) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.shift_reg.extract_size = 1; + op.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; + + auto is_rrx = false; + if (!shift_size && shift_type == Shift::kShiftROR) { + shift_size = 1; + is_rrx = true; + } + + if (!shift_size) { + op.shift_reg.reg.name = carry_reg_name; + op.shift_reg.reg.size = 8; + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; + op.shift_reg.shift_size = 0; + } else { + op.shift_reg.reg.name = kIntRegName[reg_num]; + op.shift_reg.reg.size = 32; + switch (static_cast(shift_type)) { + case Shift::kShiftASR: + op.shift_reg.shift_size = shift_size - 1; + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftSignedRight; + break; + case Shift::kShiftLSL: + op.shift_reg.shift_size = 32 - shift_size; + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + break; + case Shift::kShiftLSR: + op.shift_reg.shift_size = shift_size - 1; + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + break; + case Shift::kShiftROR: + if (is_rrx) { + + } else { + op.shift_reg.shift_size = (shift_size + 31) % 32; + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + } + break; + } + + if (shift_type == Shift::kShiftLSR || shift_type == Shift::kShiftASR) { + if (!shift_size) { + shift_size = 32; + } + } else if (shift_type == Shift::kShiftROR) { + LOG_IF(FATAL, !shift_size) + << "Invalid use of AddShiftRegOperand RRX shifts not supported"; + } + op.shift_reg.shift_size = shift_size; + op.type = Operand::kTypeShiftRegister; + op.size = 32; + op.action = Operand::kActionRead; + } +} + // Decode the condition field and fil in the instruction conditions accordingly static void DecodeCondition(Instruction &inst, uint32_t cond) { inst.conditions.emplace_back(); @@ -214,6 +279,40 @@ static void DecodeCondition(Instruction &inst, uint32_t cond) { } } +//000 AND, ANDS (register) +//001 EOR, EORS (register) +//010 0 != 1101 SUB, SUBS (register) — SUB +//010 0 1101 SUB, SUBS (SP minus register) — SUB +//010 1 != 1101 SUB, SUBS (register) — SUBS +//010 1 1101 SUB, SUBS (SP minus register) — SUBS +//011 RSB, RSBS (register) +//100 0 != 1101 ADD, ADDS (register) — ADD +//100 0 1101 ADD, ADDS (SP plus register) — ADD +//100 1 != 1101 ADD, ADDS (register) — ADDS +//100 1 1101 ADD, ADDS (SP plus register) — ADDS +//101 ADC, ADCS (register) +//110 SBC, SBCS (register) +//111 RSC, RSCS (register) +// High 3 bit opc and low bit s, opc:s +static const char * const kIdpNames[] = { + [0b0000] = "ANDrr", + [0b0001] = "ANDSrr", + [0b0010] = "EORrr", + [0b0011] = "EORSrr", + [0b0100] = "SUBrr", + [0b0101] = "SUBSrr", + [0b0110] = "RSBrr", + [0b0111] = "RSBSrr", + [0b1000] = "ADDrr", + [0b1001] = "ADDSrr", + [0b1010] = "ADCrr", + [0b1011] = "ADCSrr", + [0b1100] = "SBCrr", + [0b1101] = "SBCSrr", + [0b1110] = "RSCrr", + [0b1111] = "RSCSrr" +}; + static bool TryDecodeIntegerDataProcessing(Instruction &inst, uint32_t bits) { const IntDataProcessing enc = {bits}; if (enc.cond == 0b1111u) { @@ -222,14 +321,19 @@ static bool TryDecodeIntegerDataProcessing(Instruction &inst, uint32_t bits) { if (enc.opc == 0b010u || enc.opc == 0b100u) { } - + inst.function = kIdpNames[ (enc.opc << 1u) | enc.s]; DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); if (enc.rd == kPCRegNum) { - inst.category = Instruction::kCategoryIndirectJump; + if (enc.s) { // Updates the flags (condition codes) + inst.category = Instruction::kCategoryError; + return false; + } else { + inst.category = Instruction::kCategoryIndirectJump; + } } else { inst.category = Instruction::kCategoryNormal; } diff --git a/remill/Arch/AArch32/Runtime/CMakeLists.txt b/remill/Arch/AArch32/Runtime/CMakeLists.txt index 804315222..0661e3a0f 100644 --- a/remill/Arch/AArch32/Runtime/CMakeLists.txt +++ b/remill/Arch/AArch32/Runtime/CMakeLists.txt @@ -48,6 +48,9 @@ function(add_runtime_helper target_name address_bit_size little_endian) INSTALLDESTINATION "${install_folder}" DEPENDENCIES + "${CMAKE_SOURCE_DIR}/remill/Arch/AArch32/Semantics/BINARY.cpp" + "${CMAKE_SOURCE_DIR}/remill/Arch/AArch32/Semantics/FLAGS.cpp" + ) endfunction() diff --git a/remill/Arch/AArch32/Runtime/Instructions.cpp b/remill/Arch/AArch32/Runtime/Instructions.cpp index cea35d7a9..58fd30482 100644 --- a/remill/Arch/AArch32/Runtime/Instructions.cpp +++ b/remill/Arch/AArch32/Runtime/Instructions.cpp @@ -23,8 +23,8 @@ #include "remill/Arch/Runtime/Intrinsics.h" #include "remill/Arch/Runtime/Operators.h" #include "remill/Arch/AArch32/Runtime/State.h" -//#include "remill/Arch/AArch32/Runtime/Types.h" -//#include "remill/Arch/AArch32/Runtime/Operators.h" +#include "remill/Arch/AArch32/Runtime/Types.h" +#include "remill/Arch/AArch32/Runtime/Operators.h" // clang-format on @@ -56,9 +56,9 @@ DEF_ISEL(UNSUPPORTED_INSTRUCTION) = HandleUnsupported; DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; // clang-format off -//#include "remill/Arch/AArch64/Semantics/FLAGS.cpp" +#include "remill/Arch/AArch32/Semantics/FLAGS.cpp" // -//#include "remill/Arch/AArch64/Semantics/BINARY.cpp" +#include "remill/Arch/AArch32/Semantics/BINARY.cpp" //#include "remill/Arch/AArch64/Semantics/BITBYTE.cpp" //#include "remill/Arch/AArch64/Semantics/BRANCH.cpp" //#include "remill/Arch/AArch64/Semantics/CALL_RET.cpp" diff --git a/remill/Arch/AArch32/Runtime/Operators.h b/remill/Arch/AArch32/Runtime/Operators.h new file mode 100644 index 000000000..2d3555ee0 --- /dev/null +++ b/remill/Arch/AArch32/Runtime/Operators.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace { + +// Read a register directly. Sometimes this is needed for suppressed operands. +ALWAYS_INLINE static addr_t _Read(Memory *, Reg reg) { + return reg.aword; +} + +// Write directly to a register. This is sometimes needed for suppressed +// register operands. +ALWAYS_INLINE static void _Write(Memory *, Reg ®, addr_t val) { + reg.aword = val; +} + +} // namespace diff --git a/remill/Arch/AArch32/Runtime/State.h b/remill/Arch/AArch32/Runtime/State.h index 92ca82b57..bd8558e78 100644 --- a/remill/Arch/AArch32/Runtime/State.h +++ b/remill/Arch/AArch32/Runtime/State.h @@ -72,10 +72,38 @@ struct alignas(8) GPR final { } __attribute__((packed)); +// System registers affecting control and status of the machine. +struct alignas(8) SR final { + + uint8_t _2; + uint8_t n; // Negative condition flag. + uint8_t _3; + uint8_t z; // Zero condition flag + uint8_t _4; + uint8_t c; // Carry condition flag + uint8_t _5; + uint8_t v; // Overflow condition flag + + uint8_t _6; + uint8_t ixc; // Inexact (cumulative). + uint8_t _7; + uint8_t ofc; // Overflow (cumulative). + uint8_t _8; + uint8_t ufc; // Underflow (cumulative). + uint8_t _9; + uint8_t idc; // Input denormal (cumulative). + uint8_t _10; + uint8_t ioc; // Invalid operation (cumulative). + + uint8_t _padding[6]; +} __attribute__((packed)); + struct alignas(16) State final : public ArchState { GPR gpr; // 528 bytes. + SR sr; + uint64_t _0; } __attribute__((packed)); diff --git a/remill/Arch/AArch32/Runtime/Types.h b/remill/Arch/AArch32/Runtime/Types.h new file mode 100644 index 000000000..20143f50c --- /dev/null +++ b/remill/Arch/AArch32/Runtime/Types.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// We need this for boolean conditions, used in branch instructions. +typedef RnW R8W; + +typedef RnW R8W; +typedef RnW R16W; + +// Note: AArch64 zero-extends like x86, but the smallest register size that +// can be accessed is 32 bits. +typedef RnW R32W; + +//typedef Rn R8; +//typedef Rn R16; +typedef Rn R32; + +typedef Vn V8; +typedef Vn V16; +typedef Vn V32; +typedef Vn V64; +typedef Vn V128; +typedef VnW V128W; + +typedef MnW M8W; +typedef MnW M16W; +typedef MnW M32W; +typedef MnW M64W; + +typedef MVnW MV8W; +typedef MVnW MV16W; +typedef MVnW MV32W; +typedef MVnW MV64W; +typedef MVnW MV128W; + +typedef Mn M8; +typedef Mn M16; + +typedef Mn M32; +typedef Mn M64; + +typedef MVn MV8; +typedef MVn MV16; +typedef MVn MV32; +typedef MVn MV64; +typedef MVn MV128; +typedef MVn MV256; + +typedef In I8; +typedef In I16; +typedef In I32; +typedef In I64; + +typedef In F32; +typedef In F64; + +typedef In PC; +typedef In ADDR; diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp new file mode 100644 index 000000000..8cd04318b --- /dev/null +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { + +template +T AddWithCarryNZCV(State &state, T lhs, T rhs, T carry) { + auto unsigned_result = UAdd(UAdd(ZExt(lhs), ZExt(rhs)), ZExt(carry)); + auto signed_result = SAdd(SAdd(SExt(lhs), SExt(rhs)), Signed(ZExt(carry))); + auto result = TruncTo(unsigned_result); + state.sr.n = SignFlag(result); + state.sr.z = ZeroFlag(result); + state.sr.c = UCmpNeq(ZExt(result), unsigned_result); + state.sr.v = SCmpNeq(SExt(result), signed_result); + return result; +} + + + +template +DEF_SEM(AND, D dst, S1 src1, S2 src2) { + Write(dst, UAnd(Read(src1), Read(src2))); + return memory; +} + +template +DEF_SEM(ANDS, D dst, S1 src1, S2 src2) { + auto res = UAnd(Read(src1), Read(src2)); + WriteZExt(dst, res); + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + state.sr.c = false; + // PSTATE.V unchanged + return memory; +} + +template +DEF_SEM(EOR, D dst, S1 src1, S2 src2) { + Write(dst, UXor(Read(src1), Read(src2))); + return memory; +} + +template +DEF_SEM(RSB, D dst, S1 src1, S2 src2) { + Write(dst, USub(Read(src2), Read(src1))); + return memory; +} + +template +DEF_SEM(SUB, D dst, S1 src1, S2 src2) { + Write(dst, USub(Read(src1), Read(src2))); + return memory; +} + +template +DEF_SEM(ADD, D dst, S1 src1, S2 src2) { + Write(dst, UAdd(Read(src1), Read(src2))); + return memory; +} + +template +DEF_SEM(ADDS, D dst, S1 src1, S2 src2) { + using T = typename BaseType::BT; + auto lhs = Read(src1); + auto rhs = Read(src2); + auto res = AddWithCarryNZCV(state, lhs, rhs, T(0)); + Write(dst, res); + return memory; +} + + +template +DEF_SEM(ADC, D dst, S1 src1, S2 src2) { + Write(dst, UAdd(UAdd(Read(src1), Read(src2)), ZExtTo(state.sr.c))); + return memory; +} + +template +DEF_SEM(SBC, D dst, S1 src1, S2 src2) { + Write(dst, UAdd(UAdd(Read(src1), UNot(Read(src2))), ZExtTo(state.sr.c))); + return memory; +} + +template +DEF_SEM(RSC, D dst, S1 src1, S2 src2) { + Write(dst, UAdd(UAdd(Read(src2), UNot(Read(src1))), ZExtTo(state.sr.c))); + return memory; +} + +} // namespace + +DEF_ISEL(ANDrr) = AND; +DEF_ISEL(EORrr) = EOR; +DEF_ISEL(ADDrr) = ADD; +DEF_ISEL(ADDSrr) = ADDS; +DEF_ISEL(ADCrr) = ADC; +DEF_ISEL(RSBrr) = RSB; +DEF_ISEL(SUBrr) = SUB; +DEF_ISEL(SBCrr) = SBC; +DEF_ISEL(RSCrr) = RSC; diff --git a/remill/Arch/AArch32/Semantics/FLAGS.cpp b/remill/Arch/AArch32/Semantics/FLAGS.cpp new file mode 100644 index 000000000..0432bf56f --- /dev/null +++ b/remill/Arch/AArch32/Semantics/FLAGS.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { + +// Used to select specializations of flags computations based on what operator +// is executed. +enum : uint32_t { kLHS = 2415899639U, kRHS = 70623199U }; + +// Zero flags, tells us whether or not a value is zero. +template +[[gnu::const]] ALWAYS_INLINE static bool ZeroFlag(T res) { + return T(0) == res; +} + +// Zero flags, tells us whether or not a value is zero. +template +[[gnu::const]] ALWAYS_INLINE static bool NotZeroFlag(T res) { + return T(0) != res; +} + +// Sign flag, tells us if a result is signed or unsigned. +template +[[gnu::const]] ALWAYS_INLINE static bool SignFlag(T res) { + return 0 > Signed(res); +} + +// Tests whether there is an even number of bits in the low order byte. +[[gnu::const]] ALWAYS_INLINE static bool ParityFlag(uint8_t r0) { + return !__builtin_parity(static_cast(r0)); + + // auto r1 = r0 >> 1_u8; + // auto r2 = r1 >> 1_u8; + // auto r3 = r2 >> 1_u8; + // auto r4 = r3 >> 1_u8; + // auto r5 = r4 >> 1_u8; + // auto r6 = r5 >> 1_u8; + // auto r7 = r6 >> 1_u8; + // + // return !(1 & (r0 ^ r1 ^ r2 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7)); +} + +struct tag_add {}; +struct tag_sub {}; +struct tag_div {}; +struct tag_mul {}; + +// Generic overflow flag. +template +struct Overflow; + +// Computes an overflow flag when two numbers are added together. +template <> +struct Overflow { + template + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { + static_assert(std::is_unsigned::value, + "Invalid specialization of `Overflow::Flag` for addition."); + enum { kSignShift = sizeof(T) * 8 - 1 }; + + const T sign_lhs = lhs >> kSignShift; + const T sign_rhs = rhs >> kSignShift; + const T sign_res = res >> kSignShift; + return 2 == (sign_lhs ^ sign_res) + (sign_rhs ^ sign_res); + } +}; + +// Computes an overflow flag when one number is subtracted from another. +template <> +struct Overflow { + template + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { + static_assert(std::is_unsigned::value, + "Invalid specialization of `Overflow::Flag` for " + "subtraction."); + enum { kSignShift = sizeof(T) * 8 - 1 }; + + const T sign_lhs = lhs >> kSignShift; + const T sign_rhs = rhs >> kSignShift; + const T sign_res = res >> kSignShift; + return 2 == (sign_lhs ^ sign_rhs) + (sign_lhs ^ sign_res); + } +}; + +// Computes an overflow flag when one number is multiplied with another. +template <> +struct Overflow { + + // Integer multiplication overflow check, where result is twice the width of + // the operands. + template + [[gnu::const]] ALWAYS_INLINE static bool + Flag(T, T, R res, + typename std::enable_if::type = 0) { + + return static_cast(static_cast(res)) != res; + } + + // Signed integer multiplication overflow check, where the result is + // truncated to the size of the operands. + template + [[gnu::const]] ALWAYS_INLINE static bool + Flag(T lhs, T rhs, T, + typename std::enable_if::value, int>::type = 0) { + auto lhs_wide = SExt(lhs); + auto rhs_wide = SExt(rhs); + return Flag(lhs, rhs, lhs_wide * rhs_wide); + } +}; + +// Generic carry flag. +template +struct Carry; + +// Computes an carry flag when two numbers are added together. +template <> +struct Carry { + template + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { + static_assert(std::is_unsigned::value, + "Invalid specialization of `Carry::Flag` for addition."); + return res < lhs || res < rhs; + } +}; + +// Computes an carry flag when one number is subtracted from another. +template <> +struct Carry { + template + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T) { + static_assert(std::is_unsigned::value, + "Invalid specialization of `Carry::Flag` for addition."); + return lhs < rhs; + } +}; + +ALWAYS_INLINE static void SetFPSRStatusFlags(State &state, int mask) { + // TODO(Sonya): Update these flags to work on AArch32 +// state.sr.ixc |= static_cast(0 != (mask & FE_INEXACT)); +// state.sr.ofc |= static_cast(0 != (mask & FE_OVERFLOW)); +// state.sr.ufc |= static_cast(0 != (mask & FE_UNDERFLOW)); +// state.sr.ioc |= static_cast(0 != (mask & FE_INVALID)); +} + +template +ALWAYS_INLINE static auto CheckedFloatUnaryOp(State &state, F func, T arg1) + -> decltype(func(arg1)) { + + //state.sr.idc |= IsDenormal(arg1); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + BarrierReorder(); + auto res = func(arg1); + BarrierReorder(); + auto new_except = __remill_fpu_exception_test_and_clear( + FE_ALL_EXCEPT, old_except /* zero */); + SetFPSRStatusFlags(state, new_except); + return res; +} + +template +ALWAYS_INLINE static auto CheckedFloatBinOp(State &state, F func, T arg1, + T arg2) + -> decltype(func(arg1, arg2)) { + + //state.sr.idc |= IsDenormal(arg1) | IsDenormal(arg2); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + BarrierReorder(); + auto res = func(arg1, arg2); + BarrierReorder(); + auto new_except = __remill_fpu_exception_test_and_clear( + FE_ALL_EXCEPT, old_except /* zero */); + SetFPSRStatusFlags(state, new_except); + return res; +} + +} // namespace diff --git a/remill/BC/Util.cpp b/remill/BC/Util.cpp index 745eef00b..7ac8e60e2 100644 --- a/remill/BC/Util.cpp +++ b/remill/BC/Util.cpp @@ -469,7 +469,7 @@ static const char *gSemanticsSearchPaths[] = { // Derived from the build. REMILL_BUILD_SEMANTICS_DIR_X86 "\0", REMILL_BUILD_SEMANTICS_DIR_AARCH64 "\0", - REMILL_BUILD_SEMANTICS_DIR_AARCH32 "\0", + REMILL_BUILD_SEMANTICS_DIR_AARCH32 "\0", REMILL_INSTALL_SEMANTICS_DIR "\0", "/usr/local/share/remill/" MAJOR_MINOR "/semantics", "/usr/share/remill/" MAJOR_MINOR "/semantics", diff --git a/tools/lift/Lift.cpp b/tools/lift/Lift.cpp index d3fc9b0c8..ef3c03442 100644 --- a/tools/lift/Lift.cpp +++ b/tools/lift/Lift.cpp @@ -264,6 +264,9 @@ int main(int argc, char *argv[]) { // `module`. trace_lifter.Lift(FLAGS_entry_address); + for (auto [ea, trace] : manager.traces) { + LOG(ERROR) << remill::LLVMThingToString(trace); + } // Optimize the module, but with a particular focus on only the functions // that we actually lifted. remill::OptimizationGuide guide = {}; From aa954cd9a836dbd84f5d0c1c5b19a06c68866b43 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 23 Sep 2020 12:48:56 -0400 Subject: [PATCH 006/130] Updated --- remill/Arch/AArch32/Decode.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 5065d21ab..394e6384a 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -111,7 +111,7 @@ static void AddShiftRegOperand(Instruction &inst, if (!shift_size) { shift_size = 32; } - } else if (shift_type == Shift::kShiftROR) { + } else if (is_rrx) { LOG_IF(FATAL, !shift_size) << "Invalid use of AddShiftRegOperand RRX shifts not supported"; } @@ -168,12 +168,7 @@ static void AddShiftCarryOperand(Instruction &inst, } if (shift_type == Shift::kShiftLSR || shift_type == Shift::kShiftASR) { - if (!shift_size) { - shift_size = 32; - } - } else if (shift_type == Shift::kShiftROR) { - LOG_IF(FATAL, !shift_size) - << "Invalid use of AddShiftRegOperand RRX shifts not supported"; + } op.shift_reg.shift_size = shift_size; op.type = Operand::kTypeShiftRegister; From e3923a28dde3accd02364699b83937d0f62f619d Mon Sep 17 00:00:00 2001 From: sschriner Date: Mon, 28 Sep 2020 18:01:32 -0400 Subject: [PATCH 007/130] Finished Integer Data Processing with three registers, added integer data processing with 2 regs + immediate, started MUL instructions --- remill/Arch/AArch32/Decode.cpp | 393 +++++++++++++++++++---- remill/Arch/AArch32/Runtime/Types.h | 1 - remill/Arch/AArch32/Semantics/BINARY.cpp | 181 ++++++++--- 3 files changed, 474 insertions(+), 101 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 394e6384a..985a4effa 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -23,7 +23,7 @@ namespace remill { namespace { //Integer Data Processing (three register, immediate shift) -union IntDataProcessing { +union IntDataProcessingRRR { uint32_t flat; struct { uint32_t rm : 4; @@ -38,7 +38,39 @@ union IntDataProcessing { uint32_t cond : 4; } __attribute__((packed)); } __attribute__((packed)); -static_assert(sizeof(IntDataProcessing) == 4, " "); +static_assert(sizeof(IntDataProcessingRRR) == 4, " "); + +//Integer Data Processing (2 register and immediate, immediate shift) +union IntDataProcessingRRI { + uint32_t flat; + struct { + uint32_t imm12 : 12; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 3; + uint32_t _0010 : 4; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntDataProcessingRRI) == 4, " "); + +// Multiply and Accumulate +union MultiplyAndAccumulate { + uint32_t flat; + struct { + uint32_t rn : 4; + uint32_t _1001 : 4; + uint32_t rm : 4; + uint32_t rdlo : 4; + uint32_t rdhi : 4; + uint32_t s : 1; + uint32_t opc : 3; + uint32_t _0000 : 4; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(MultiplyAndAccumulate) == 4, " "); static constexpr auto kPCRegNum = 15u; @@ -61,6 +93,62 @@ static const char * const kIntRegName[] = { "R15" }; +static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out) { + uint32_t unrotated_value = imm12 & (0b11111111u); + uint32_t rotation_amount = ((imm12 >> 8) & (0b1111u)) *2u; + auto num_ops = inst.operands.size(); + inst.operands.emplace_back(); + inst.operands.emplace_back(); + inst.operands.emplace_back(); + auto &op0 = inst.operands[num_ops]; + auto &op1 = inst.operands[num_ops + 1]; + auto &op2 = inst.operands[num_ops + 2]; + + op0.imm.is_signed = false; + op0.size = 32; + op0.action = Operand::kActionRead; + op0.type = Operand::kTypeImmediate; + + if (!rotation_amount) { + op0.imm.val = unrotated_value; + } else { + op0.imm.val = __builtin_rotateright32(unrotated_value, rotation_amount); + } + + // This is the 2nd part of RRX so we can reuse the same semantics + op1.imm.is_signed = false; + op1.imm.val = 0; + op1.size = 32; + op1.action = Operand::kActionRead; + op1.type = Operand::kTypeImmediate; + + if (!rotation_amount) { + op2.shift_reg.extract_size = 1; + op2.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; + + op2.shift_reg.shift_size = 0; + op2.type = Operand::kTypeShiftRegister; + op2.size = 32; + op2.action = Operand::kActionRead; + + op2.shift_reg.reg.name = "C"; + op2.shift_reg.reg.size = 8; + op2.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; + op2.shift_reg.shift_size = 0; + } else { + op2.imm.val = (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u; + op2.size = 32; + op2.imm.is_signed = false; + op2.action = Operand::kActionRead; + op2.type = Operand::kTypeImmediate; + } + + if (!carry_out) { + inst.operands.pop_back(); + } + +} + static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, Operand::Action action) { inst.operands.emplace_back(); @@ -72,6 +160,17 @@ static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, op.reg.name = kIntRegName[index]; } +static void AddImmOp(Instruction &inst, uint64_t value, unsigned size = 32, + bool is_signed = false) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.imm.val = value; + op.size = size; + op.imm.is_signed = is_signed; + op.action = Operand::kActionRead; + op.type = Operand::kTypeImmediate; +} + // Note: Order is significant; extracted bits may be casted to this type. enum Shift : uint32_t { kShiftLSL, kShiftLSR, kShiftASR, kShiftROR }; @@ -98,7 +197,12 @@ static void AddShiftRegOperand(Instruction &inst, if (!shift_size && shift_type == Shift::kShiftROR) { shift_size = 1; is_rrx = true; + } else if (shift_type == Shift::kShiftLSR || shift_type == Shift::kShiftASR) { + if (!shift_size) { + shift_size = 32; + } } + if (!shift_size) { AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); } else { @@ -106,19 +210,42 @@ static void AddShiftRegOperand(Instruction &inst, auto &op = inst.operands.back(); op.shift_reg.reg.name = kIntRegName[reg_num]; op.shift_reg.reg.size = 32; - op.shift_reg.shift_op = GetOperandShift(static_cast(shift_type)); - if (shift_type == Shift::kShiftLSR || shift_type == Shift::kShiftASR) { - if (!shift_size) { - shift_size = 32; - } - } else if (is_rrx) { - LOG_IF(FATAL, !shift_size) - << "Invalid use of AddShiftRegOperand RRX shifts not supported"; + + if (is_rrx) { + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + op.shift_reg.shift_size = 1; + } else { + op.shift_reg.shift_op = GetOperandShift(static_cast(shift_type)); + op.shift_reg.shift_size = shift_size; } - op.shift_reg.shift_size = shift_size; + + op.type = Operand::kTypeShiftRegister; + op.size = 32; + op.action = Operand::kActionRead; + } + + // To handle rrx we need to take two components shift each and OR the results + // together. No single operand type in remill is flexible enough to handle this. + // So we make 2 operands and OR those two operands together. In most cases + // when rrx isn't used we OR something with 0. + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + if (is_rrx) { + op.shift_reg.reg.name = "C"; + op.shift_reg.reg.size = 8; + + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; + op.shift_reg.shift_size = 31; + op.type = Operand::kTypeShiftRegister; op.size = 32; op.action = Operand::kActionRead; + } else { + op.imm.is_signed = false; + op.imm.val = 0; + op.size = 32; + op.action = Operand::kActionRead; + op.type = Operand::kTypeImmediate; } } @@ -130,6 +257,11 @@ static void AddShiftCarryOperand(Instruction &inst, op.shift_reg.extract_size = 1; op.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; + op.shift_reg.shift_size = shift_size; + op.type = Operand::kTypeShiftRegister; + op.size = 32; + op.action = Operand::kActionRead; + auto is_rrx = false; if (!shift_size && shift_type == Shift::kShiftROR) { shift_size = 1; @@ -159,25 +291,18 @@ static void AddShiftCarryOperand(Instruction &inst, break; case Shift::kShiftROR: if (is_rrx) { - + op.shift_reg.shift_size = 0; + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; } else { - op.shift_reg.shift_size = (shift_size + 31) % 32; + op.shift_reg.shift_size = (shift_size + 31u) % 32u; op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; } break; } - - if (shift_type == Shift::kShiftLSR || shift_type == Shift::kShiftASR) { - - } - op.shift_reg.shift_size = shift_size; - op.type = Operand::kTypeShiftRegister; - op.size = 32; - op.action = Operand::kActionRead; } } -// Decode the condition field and fil in the instruction conditions accordingly +// Decode the condition field and fill in the instruction conditions accordingly static void DecodeCondition(Instruction &inst, uint32_t cond) { inst.conditions.emplace_back(); auto &lhs_cond = inst.conditions.back(); @@ -274,22 +399,8 @@ static void DecodeCondition(Instruction &inst, uint32_t cond) { } } -//000 AND, ANDS (register) -//001 EOR, EORS (register) -//010 0 != 1101 SUB, SUBS (register) — SUB -//010 0 1101 SUB, SUBS (SP minus register) — SUB -//010 1 != 1101 SUB, SUBS (register) — SUBS -//010 1 1101 SUB, SUBS (SP minus register) — SUBS -//011 RSB, RSBS (register) -//100 0 != 1101 ADD, ADDS (register) — ADD -//100 0 1101 ADD, ADDS (SP plus register) — ADD -//100 1 != 1101 ADD, ADDS (register) — ADDS -//100 1 1101 ADD, ADDS (SP plus register) — ADDS -//101 ADC, ADCS (register) -//110 SBC, SBCS (register) -//111 RSC, RSCS (register) // High 3 bit opc and low bit s, opc:s -static const char * const kIdpNames[] = { +static const char * const kIdpNamesRRR[] = { [0b0000] = "ANDrr", [0b0001] = "ANDSrr", [0b0010] = "EORrr", @@ -308,20 +419,36 @@ static const char * const kIdpNames[] = { [0b1111] = "RSCSrr" }; -static bool TryDecodeIntegerDataProcessing(Instruction &inst, uint32_t bits) { - const IntDataProcessing enc = {bits}; +//000 AND, ANDS (register) +//001 EOR, EORS (register) +//010 0 != 1101 SUB, SUBS (register) — SUB +//010 0 1101 SUB, SUBS (SP minus register) — SUB +//010 1 != 1101 SUB, SUBS (register) — SUBS +//010 1 1101 SUB, SUBS (SP minus register) — SUBS +//011 RSB, RSBS (register) +//100 0 != 1101 ADD, ADDS (register) — ADD +//100 0 1101 ADD, ADDS (SP plus register) — ADD +//100 1 != 1101 ADD, ADDS (register) — ADDS +//100 1 1101 ADD, ADDS (SP plus register) — ADDS +//101 ADC, ADCS (register) +//110 SBC, SBCS (register) +//111 RSC, RSCS (register) +static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) { + const IntDataProcessingRRR enc = {bits}; if (enc.cond == 0b1111u) { return false; } - if (enc.opc == 0b010u || enc.opc == 0b100u) { - } - inst.function = kIdpNames[ (enc.opc << 1u) | enc.s]; + inst.function = kIdpNamesRRR[ (enc.opc << 1u) | enc.s]; DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); + if (enc.s) { + AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); + } + if (enc.rd == kPCRegNum) { if (enc.s) { // Updates the flags (condition codes) inst.category = Instruction::kCategoryError; @@ -336,15 +463,161 @@ static bool TryDecodeIntegerDataProcessing(Instruction &inst, uint32_t bits) { return true; } +//000 AND, ANDS (immediate) +//001 EOR, EORS (immediate) +//010 0 != 11x1 SUB, SUBS (immediate) — SUB +//010 0 1101 SUB, SUBS (SP minus immediate) — SUB +//010 0 1111 ADR — A2 +//010 1 != 1101 SUB, SUBS (immediate) — SUBS +//010 1 1101 SUB, SUBS (SP minus immediate) — SUBS +//011 RSB, RSBS (immediate) +//100 0 != 11x1 ADD, ADDS (immediate) — ADD +//100 0 1101 ADD, ADDS (SP plus immediate) — ADD +//100 0 1111 ADR — A1 +//100 1 != 1101 ADD, ADDS (immediate) — ADDS +//100 1 1101 ADD, ADDS (SP plus immediate) — ADDS +//101 ADC, ADCS (immediate) +//110 SBC, SBCS (immediate) +//111 RSC, RSCS (immediate) +static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) { + const IntDataProcessingRRI enc = { bits }; + if (enc.cond == 0b1111u) { + return false; + } + + inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s]; + DecodeCondition(inst, enc.cond); + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + + // Raise the program counter to align to a multiple of 4 bytes + if (enc.rn == kPCRegNum && (enc.opc == 0b100u || enc.opc == 0b010u)) { + int64_t diff = static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); + + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.type = Operand::kTypeAddress; + op.size = 32; + op.action = Operand::kActionRead; + op.addr.address_size = 32; + op.addr.base_reg.name = "PC"; + op.addr.base_reg.size = 32; + op.addr.scale = 0; + op.addr.displacement = diff; + + } else { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + } + + DecodeA32ExpandImm(inst, enc.imm12, enc.s); + + if (enc.rd == kPCRegNum) { + + if (enc.s) { // Updates the flags (condition codes) + inst.category = Instruction::kCategoryError; + return false; + } else { + inst.category = Instruction::kCategoryIndirectJump; + } + } else { + inst.category = Instruction::kCategoryNormal; + } + + return true; +} + + +static const char * const kMulAccRRR[] = { + [0b0000] = "MULrr", + [0b0001] = "MULSrr", + [0b0010] = "MLArr", + [0b0011] = "MLASrr", + [0b0100] = "UMAALrr", + [0b0101] = nullptr, + [0b0110] = "MLSrr", + [0b0111] = nullptr, + [0b1000] = "UMULLrr", + [0b1001] = "UMULLSrr", + [0b1010] = "UMLALrr", + [0b1011] = "UMLALSrr", + [0b1100] = "SMULLrr", + [0b1101] = "SMULLSrr", + [0b1110] = "SMLALrr", + [0b1111] = "SMLALSrr" +}; + +//000 MUL, MULS +//001 MLA, MLAS +//010 0 UMAAL +//010 1 UNALLOCATED +//011 0 MLS +//011 1 UNALLOCATED +//100 UMULL, UMULLS +//101 UMLAL, UMLALS +//110 SMULL, SMULLS +//111 SMLAL, SMLALS +static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { + const MultiplyAndAccumulate enc = { bits }; + // if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; + if (enc.cond == 0b1111u || (enc.rdhi == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum)) { + return false; + } + + auto instruction = kMulAccRRR[(enc.opc << 1u) | enc.s]; + if (!instruction) { + return false; + } + inst.function = instruction; + + DecodeCondition(inst, enc.cond); + AddIntRegOp(inst, enc.rdhi, 32, Operand::kActionWrite); + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); + if (enc.opc != 0b000u) { + AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionRead); + } else { + AddImmOp(inst, 0); + } + + return true; + +} + +static bool (*const kBits7_to_4[])(Instruction&, uint32_t) = { + [0b0000] = TryDecodeIntegerDataProcessingRRR, + [0b0001] = nullptr, + [0b0010] = TryDecodeIntegerDataProcessingRRR, + [0b0011] = nullptr, + [0b0100] = TryDecodeIntegerDataProcessingRRR, + [0b0101] = nullptr, + [0b0110] = TryDecodeIntegerDataProcessingRRR, + [0b0111] = nullptr, + [0b1000] = TryDecodeIntegerDataProcessingRRR, + [0b1001] = TryDecodeMultiplyAndAccumulate, + [0b1010] = TryDecodeIntegerDataProcessingRRR, + [0b1011] = nullptr, + [0b1100] = TryDecodeIntegerDataProcessingRRR, + [0b1101] = nullptr, + [0b1110] = TryDecodeIntegerDataProcessingRRR, + [0b1111] = nullptr +}; + +static bool TryDecodeArithmetic(Instruction &inst, uint32_t bits){ + auto decode = kBits7_to_4[(bits >> 4) & 0b1111u]; + if (!decode){ + return false; + } + return decode(inst, bits); +} + static bool (*const kBits27_to_21[])(Instruction&, uint32_t) = { - [0b0000000] = TryDecodeIntegerDataProcessing, - [0b0000001] = TryDecodeIntegerDataProcessing, - [0b0000010] = TryDecodeIntegerDataProcessing, - [0b0000011] = TryDecodeIntegerDataProcessing, - [0b0000100] = TryDecodeIntegerDataProcessing, - [0b0000101] = TryDecodeIntegerDataProcessing, - [0b0000110] = TryDecodeIntegerDataProcessing, - [0b0000111] = TryDecodeIntegerDataProcessing, + [0b0000000] = TryDecodeArithmetic, + [0b0000001] = TryDecodeArithmetic, + [0b0000010] = TryDecodeArithmetic, + [0b0000011] = TryDecodeArithmetic, + [0b0000100] = TryDecodeArithmetic, + [0b0000101] = TryDecodeArithmetic, + [0b0000110] = TryDecodeArithmetic, + [0b0000111] = TryDecodeArithmetic, [0b0001000] = nullptr, [0b0001001] = nullptr, [0b0001010] = nullptr, @@ -353,14 +626,14 @@ static bool (*const kBits27_to_21[])(Instruction&, uint32_t) = { [0b0001101] = nullptr, [0b0001110] = nullptr, [0b0001111] = nullptr, - [0b0010000] = nullptr, - [0b0010001] = nullptr, - [0b0010010] = nullptr, - [0b0010011] = nullptr, - [0b0010100] = nullptr, - [0b0010101] = nullptr, - [0b0010110] = nullptr, - [0b0010111] = nullptr, + [0b0010000] = TryDecodeIntegerDataProcessingRRI, + [0b0010001] = TryDecodeIntegerDataProcessingRRI, + [0b0010010] = TryDecodeIntegerDataProcessingRRI, + [0b0010011] = TryDecodeIntegerDataProcessingRRI, + [0b0010100] = TryDecodeIntegerDataProcessingRRI, + [0b0010101] = TryDecodeIntegerDataProcessingRRI, + [0b0010110] = TryDecodeIntegerDataProcessingRRI, + [0b0010111] = TryDecodeIntegerDataProcessingRRI, [0b0011000] = nullptr, [0b0011001] = nullptr, [0b0011010] = nullptr, @@ -499,6 +772,10 @@ bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_byte inst.bytes = inst_bytes; } + if (address & 0b1u) { + return false; + } + const auto bytes = reinterpret_cast(inst.bytes.data()); const auto bits = BytesToBits(bytes); diff --git a/remill/Arch/AArch32/Runtime/Types.h b/remill/Arch/AArch32/Runtime/Types.h index 20143f50c..c77e899a5 100644 --- a/remill/Arch/AArch32/Runtime/Types.h +++ b/remill/Arch/AArch32/Runtime/Types.h @@ -64,7 +64,6 @@ typedef MVn MV256; typedef In I8; typedef In I16; typedef In I32; -typedef In I64; typedef In F32; typedef In F64; diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index 8cd04318b..9aa2cfb66 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -30,84 +30,181 @@ T AddWithCarryNZCV(State &state, T lhs, T rhs, T carry) { -template -DEF_SEM(AND, D dst, S1 src1, S2 src2) { - Write(dst, UAnd(Read(src1), Read(src2))); +DEF_SEM(AND, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, UAnd(Read(src1), value)); return memory; } -template -DEF_SEM(ANDS, D dst, S1 src1, S2 src2) { - auto res = UAnd(Read(src1), Read(src2)); +DEF_SEM(ANDS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto value = UOr(Read(src2), Read(src2_rrx)); + auto res = UAnd(Read(src1), value); WriteZExt(dst, res); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); - state.sr.c = false; + state.sr.c = Read(carry_out); // PSTATE.V unchanged return memory; } -template -DEF_SEM(EOR, D dst, S1 src1, S2 src2) { - Write(dst, UXor(Read(src1), Read(src2))); + +DEF_SEM(EOR, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, UXor(Read(src1), value)); + return memory; +} + +DEF_SEM(EORS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto value = UOr(Read(src2), Read(src2_rrx)); + auto res = UXor(Read(src1), value); + Write(dst, res); + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(RSB, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, USub(value, Read(src1))); + return memory; +} + +DEF_SEM(RSBS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, UNot(lhs), rhs, uint32_t(1)); + Write(dst, res); return memory; } -template -DEF_SEM(RSB, D dst, S1 src1, S2 src2) { - Write(dst, USub(Read(src2), Read(src1))); +DEF_SEM(SUB, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, USub(Read(src1), value)); return memory; } -template -DEF_SEM(SUB, D dst, S1 src1, S2 src2) { - Write(dst, USub(Read(src1), Read(src2))); +DEF_SEM(SUBS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, lhs, UNot(rhs), uint32_t(1)); + Write(dst, res); return memory; } -template -DEF_SEM(ADD, D dst, S1 src1, S2 src2) { - Write(dst, UAdd(Read(src1), Read(src2))); + +DEF_SEM(ADD, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, UAdd(Read(src1), value)); return memory; } -template -DEF_SEM(ADDS, D dst, S1 src1, S2 src2) { - using T = typename BaseType::BT; +DEF_SEM(ADDS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = AddWithCarryNZCV(state, lhs, rhs, T(0)); + auto res = AddWithCarryNZCV(state, lhs, rhs, uint32_t(0)); Write(dst, res); return memory; } +DEF_SEM(ADC, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, UAdd(UAdd(Read(src1),value), uint32_t(state.sr.c))); + return memory; +} -template -DEF_SEM(ADC, D dst, S1 src1, S2 src2) { - Write(dst, UAdd(UAdd(Read(src1), Read(src2)), ZExtTo(state.sr.c))); +DEF_SEM(ADCS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, lhs, rhs, uint32_t(state.sr.c)); + Write(dst, res); return memory; } -template -DEF_SEM(SBC, D dst, S1 src1, S2 src2) { - Write(dst, UAdd(UAdd(Read(src1), UNot(Read(src2))), ZExtTo(state.sr.c))); +DEF_SEM(SBC, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, UAdd(UAdd(Read(src1), UNot(value)), uint32_t(state.sr.c))); return memory; } -template -DEF_SEM(RSC, D dst, S1 src1, S2 src2) { - Write(dst, UAdd(UAdd(Read(src2), UNot(Read(src1))), ZExtTo(state.sr.c))); +DEF_SEM(SBCS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, lhs, UNot(rhs), uint32_t(state.sr.c)); + Write(dst, res); + return memory; +} + +DEF_SEM(RSC, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, UAdd(UAdd(value, UNot(Read(src1))), uint32_t(state.sr.c))); + return memory; +} + +DEF_SEM(RSCS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, UNot(lhs), rhs, uint32_t(state.sr.c)); + Write(dst, res); return memory; } } // namespace -DEF_ISEL(ANDrr) = AND; -DEF_ISEL(EORrr) = EOR; -DEF_ISEL(ADDrr) = ADD; -DEF_ISEL(ADDSrr) = ADDS; -DEF_ISEL(ADCrr) = ADC; -DEF_ISEL(RSBrr) = RSB; -DEF_ISEL(SUBrr) = SUB; -DEF_ISEL(SBCrr) = SBC; -DEF_ISEL(RSCrr) = RSC; +DEF_ISEL(ANDrr) = AND; +DEF_ISEL(ANDSrr) = ANDS; +DEF_ISEL(EORrr) = EOR; +DEF_ISEL(EORSrr) = EORS; +DEF_ISEL(ADDrr) = ADD; +DEF_ISEL(ADDSrr) = ADDS; +DEF_ISEL(ADCrr) = ADC; +DEF_ISEL(ADCSrr) = ADCS; +DEF_ISEL(RSBrr) = RSB; +DEF_ISEL(RSBSrr) = RSBS; +DEF_ISEL(SUBrr) = SUB; +DEF_ISEL(SUBSrr) = SUBS; +DEF_ISEL(SBCrr) = SBC; +DEF_ISEL(SBCSrr) = SBCS; +DEF_ISEL(RSCrr) = RSC; +DEF_ISEL(RSCSrr) = RSCS; + +namespace { +DEF_SEM(MUL, R32W dst, R32 src1, R32 src2, R32 src3) { + auto rhs = Signed(Read(src2)); + auto lhs = Signed(Read(src1)); + auto acc = Signed(Read(src3)); + auto res = Unsigned(SAdd(SMul(lhs, rhs), acc)); + Write(dst, res); + return memory; +} + +DEF_SEM(MULS, R32W dst, R32 src1, R32 src2, R32 src3) { + auto rhs = Signed(Read(src2)); + auto lhs = Signed(Read(src1)); + auto acc = Signed(Read(src3)); + auto res = Unsigned(SAdd(SMul(lhs, rhs), acc)); + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + // PSTATE.C, PSTATE.V unchanged + Write(dst, res); + return memory; +} + +DEF_SEM(MLS, R32W dst, R32 src1, R32 src2, R32 src3) { + auto rhs = Signed(Read(src2)); + auto lhs = Signed(Read(src1)); + auto acc = Signed(Read(src3)); + auto res = Unsigned(SSub(acc, SMul(lhs, rhs))); + Write(dst, res); + return memory; +} + +} // namespace + +DEF_ISEL(MULrr) = MUL; +DEF_ISEL(MULSrr) = MULS; +DEF_ISEL(MLArr) = MUL; +DEF_ISEL(MLASrr) = MULS; +DEF_ISEL(MLSrr) = MLS; + From 67ba5663d3e5731d6492a9450b5dc4cd62bfca69 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 29 Sep 2020 11:15:27 -0400 Subject: [PATCH 008/130] UMULL, UMULLS, UMLAL, UMLALS --- remill/Arch/AArch32/Decode.cpp | 24 +++++++++++++++----- remill/Arch/AArch32/Semantics/BINARY.cpp | 28 ++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 985a4effa..f6d15b333 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -547,14 +547,14 @@ static const char * const kMulAccRRR[] = { //000 MUL, MULS //001 MLA, MLAS -//010 0 UMAAL +//010 0 UMAAL - writes to RdHi + RdLo, read RdHi //010 1 UNALLOCATED //011 0 MLS //011 1 UNALLOCATED -//100 UMULL, UMULLS -//101 UMLAL, UMLALS -//110 SMULL, SMULLS -//111 SMLAL, SMLALS +//100 UMULL, UMULLS - writes to RdHi + RdLo +//101 UMLAL, UMLALS - writes to RdHi + RdLo, read RdHi +//110 SMULL, SMULLS - writes to RdHi + RdLo +//111 SMLAL, SMLALS - writes to RdHi + RdLo, read RdHi static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { const MultiplyAndAccumulate enc = { bits }; // if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; @@ -567,11 +567,23 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { return false; } inst.function = instruction; - DecodeCondition(inst, enc.cond); + AddIntRegOp(inst, enc.rdhi, 32, Operand::kActionWrite); + // 2nd write reg only needed for instructions with an opc that begins with 1 and UMALL + if (((enc.opc >> 2) & 0b1u) || enc.opc == 0b010u) { + AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionWrite); + } + + // If opc is UMAAL, UMLAL, SMLAL read RdHi, add 0 immediate for UMULL, SMULL + if (enc.opc == 0b111u || enc.opc == 0b101u || enc.opc == 0b010u) { + AddIntRegOp(inst, enc.rdhi, 32, Operand::kActionRead); + } else if ((enc.opc >> 2) & 0b1u) { + AddImmOp(inst, 0); + } AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); + // If instruction is not MUL add a read to RdLo otherwise add an immediate if (enc.opc != 0b000u) { AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionRead); } else { diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index 9aa2cfb66..c626a414a 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -200,6 +200,30 @@ DEF_SEM(MLS, R32W dst, R32 src1, R32 src2, R32 src3) { return memory; } +DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + auto rhs = Read(src3); + auto lhs = Read(src2); + // Question: this may or may not be the way you want me to do the extensions for the 64 bit result?? + auto acc = (uint64_t(Read(src1)) << 32) | uint64_t(Read(src4)); // UInt(R[dHi]:R[dLo]) + auto res = Unsigned(UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc)); + Write(dst_lo, uint32_t(res)); + Write(dst_hi, uint32_t(res >> 32)); + return memory; +} + +DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + auto rhs = Read(src3); + auto lhs = Read(src2); + auto acc = (uint64_t(Read(src1)) << 32) | uint64_t(Read(src4)); // UInt(R[dHi]:R[dLo]) + auto res = Unsigned(UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc)); + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + // PSTATE.C, PSTATE.V unchanged + Write(dst_lo, uint32_t(res)); + Write(dst_hi, uint32_t(res >> 32)); + return memory; +} + } // namespace DEF_ISEL(MULrr) = MUL; @@ -207,4 +231,8 @@ DEF_ISEL(MULSrr) = MULS; DEF_ISEL(MLArr) = MUL; DEF_ISEL(MLASrr) = MULS; DEF_ISEL(MLSrr) = MLS; +DEF_ISEL(UMULLrr) = UMULL; +DEF_ISEL(UMULLSrr) = UMULLS; +DEF_ISEL(UMLALrr) = UMULL; +DEF_ISEL(UMLALSrr) = UMULLS; From 73f0d2a97631321dd7c6a1c790b8f089696c7cfa Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 29 Sep 2020 11:34:08 -0400 Subject: [PATCH 009/130] Corrected condition for addend or 0 immediate for UMULL/UMLAL + SMULL/SMLAL instructions --- remill/Arch/AArch32/Decode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index f6d15b333..02a426e83 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -583,8 +583,8 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { } AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); - // If instruction is not MUL add a read to RdLo otherwise add an immediate - if (enc.opc != 0b000u) { + // If instruction is not MUL, UMULL, SMULL add read to RdLo otherwise add an immediate + if (enc.opc != 0b000u || enc.opc != 0b100u || enc.opc != 0b110u) { AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionRead); } else { AddImmOp(inst, 0); From 8618494218fd1b0e1c6be8f14314d2c542014387 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 29 Sep 2020 11:54:10 -0400 Subject: [PATCH 010/130] Correct ops in Binary.cpp --- remill/Arch/AArch32/Decode.cpp | 7 ++++++- remill/Arch/AArch32/Semantics/BINARY.cpp | 12 ++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 02a426e83..92f66b589 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -557,8 +557,9 @@ static const char * const kMulAccRRR[] = { //111 SMLAL, SMLALS - writes to RdHi + RdLo, read RdHi static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { const MultiplyAndAccumulate enc = { bits }; + // cond != 1111 // if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; - if (enc.cond == 0b1111u || (enc.rdhi == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum)) { + if (enc.cond == 0b1111u || (enc.rdhi == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum) || ) { return false; } @@ -572,6 +573,10 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { AddIntRegOp(inst, enc.rdhi, 32, Operand::kActionWrite); // 2nd write reg only needed for instructions with an opc that begins with 1 and UMALL if (((enc.opc >> 2) & 0b1u) || enc.opc == 0b010u) { + // if dHi == dLo then UNPREDICTABLE; + if (enc.rdlo == enc.rdhi){ + return false; + } AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionWrite); } diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index c626a414a..11f80b6f2 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -204,23 +204,23 @@ DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) auto rhs = Read(src3); auto lhs = Read(src2); // Question: this may or may not be the way you want me to do the extensions for the 64 bit result?? - auto acc = (uint64_t(Read(src1)) << 32) | uint64_t(Read(src4)); // UInt(R[dHi]:R[dLo]) + auto acc = UOr(ZExt(Read(src1)), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = Unsigned(UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc)); - Write(dst_lo, uint32_t(res)); - Write(dst_hi, uint32_t(res >> 32)); + Write(dst_lo, Trunc(res)); + Write(dst_hi, Trunc(UShr(res, 32ul))); return memory; } DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { auto rhs = Read(src3); auto lhs = Read(src2); - auto acc = (uint64_t(Read(src1)) << 32) | uint64_t(Read(src4)); // UInt(R[dHi]:R[dLo]) + auto acc = UOr(ZExt(Read(src1)), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = Unsigned(UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc)); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); // PSTATE.C, PSTATE.V unchanged - Write(dst_lo, uint32_t(res)); - Write(dst_hi, uint32_t(res >> 32)); + Write(dst_lo, Trunc(res)); + Write(dst_hi, Trunc(UShr(res, 32ul))); return memory; } From 4e88cbd9ee6e8be12c027711bfc8f59c11b925f1 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 29 Sep 2020 12:03:23 -0400 Subject: [PATCH 011/130] UMAAL --- remill/Arch/AArch32/Semantics/BINARY.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index 11f80b6f2..b7254aa66 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -191,6 +191,17 @@ DEF_SEM(MULS, R32W dst, R32 src1, R32 src2, R32 src3) { return memory; } +DEF_SEM(UMAAL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + auto rhs = Read(src3); + auto lhs = Read(src2); + auto acc_hi = Read(src1); + auto acc_lo = Read(src4); + auto res = UAdd(UAdd(UMul(lhs, rhs), acc_hi), acc_lo); + Write(dst_lo, Trunc(res)); + Write(dst_hi, Trunc(UShr(res, 32ul))); + return memory; +} + DEF_SEM(MLS, R32W dst, R32 src1, R32 src2, R32 src3) { auto rhs = Signed(Read(src2)); auto lhs = Signed(Read(src1)); @@ -205,7 +216,7 @@ DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) auto lhs = Read(src2); // Question: this may or may not be the way you want me to do the extensions for the 64 bit result?? auto acc = UOr(ZExt(Read(src1)), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) - auto res = Unsigned(UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc)); + auto res = UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc); Write(dst_lo, Trunc(res)); Write(dst_hi, Trunc(UShr(res, 32ul))); return memory; @@ -215,7 +226,7 @@ DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4 auto rhs = Read(src3); auto lhs = Read(src2); auto acc = UOr(ZExt(Read(src1)), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) - auto res = Unsigned(UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc)); + auto res = UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); // PSTATE.C, PSTATE.V unchanged From 4c9abfa84494b77f4798365d9fed6d8f7d55b6d1 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 29 Sep 2020 12:49:32 -0400 Subject: [PATCH 012/130] SMULL, SMULLS, SMLAL, SMLALS + corrected acc was missing shift left in concatination --- remill/Arch/AArch32/Semantics/BINARY.cpp | 38 ++++++++++++++++++++---- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index b7254aa66..130d2a84b 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -214,27 +214,49 @@ DEF_SEM(MLS, R32W dst, R32 src1, R32 src2, R32 src3) { DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { auto rhs = Read(src3); auto lhs = Read(src2); - // Question: this may or may not be the way you want me to do the extensions for the 64 bit result?? - auto acc = UOr(ZExt(Read(src1)), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) - auto res = UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc); - Write(dst_lo, Trunc(res)); + auto acc = UOr(UShl(ZExt(Read(src1))), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto res = UAdd(UMul(lhs, rhs), acc); Write(dst_hi, Trunc(UShr(res, 32ul))); + Write(dst_lo, Trunc(res)); return memory; } DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { auto rhs = Read(src3); auto lhs = Read(src2); - auto acc = UOr(ZExt(Read(src1)), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) - auto res = UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc); + auto acc = UOr(UShl(ZExt(Read(src1))), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto res = UAdd(UMul(lhs, rhs), acc); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); // PSTATE.C, PSTATE.V unchanged + Write(dst_hi, Trunc(UShr(res, 32ul))); Write(dst_lo, Trunc(res)); + return memory; +} + +DEF_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + // Not entirely sure about all the signed ops I have in here + auto rhs = Signed(Read(src3)); + auto lhs = Signed(Read(src2)); + auto acc = SOr(SShl(SExt(Read(src1))), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto res = SAdd(SMul(lhs, rhs), acc); Write(dst_hi, Trunc(UShr(res, 32ul))); + Write(dst_lo, Trunc(res)); return memory; } +DEF_SEM(SMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + auto rhs = Signed(Read(src3)); + auto lhs = Signed(Read(src2)); + auto acc = SOr(SShl(SExt(Read(src1))), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto res = SAdd(SMul(lhs, rhs), acc); + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + // PSTATE.C, PSTATE.V unchanged + Write(dst_hi, Trunc(UShr(res, 32ul))); + Write(dst_lo, Trunc(res)); + return memory; +} } // namespace DEF_ISEL(MULrr) = MUL; @@ -246,4 +268,8 @@ DEF_ISEL(UMULLrr) = UMULL; DEF_ISEL(UMULLSrr) = UMULLS; DEF_ISEL(UMLALrr) = UMULL; DEF_ISEL(UMLALSrr) = UMULLS; +DEF_ISEL(SMULLrr) = SMULL; +DEF_ISEL(SMULLSrr) = SMULLS; +DEF_ISEL(SMLALrr) = SMULL; +DEF_ISEL(SMLALSrr) = SMULLS; From f71420d3140b41e3a4acabb373a4bfa39bc5fae8 Mon Sep 17 00:00:00 2001 From: sschriner Date: Mon, 5 Oct 2020 19:46:09 -0400 Subject: [PATCH 013/130] Updated decoding instructions based on top level encodings --- remill/Arch/AArch32/Decode.cpp | 292 ++++++++++------------- remill/Arch/AArch32/Semantics/BINARY.cpp | 36 +-- 2 files changed, 142 insertions(+), 186 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 92f66b589..cf5cbdd34 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -72,6 +72,36 @@ union MultiplyAndAccumulate { } __attribute__((packed)); static_assert(sizeof(MultiplyAndAccumulate) == 4, " "); +// Top-level encodings for A32 +union TopLevelEncodings { + uint32_t flat; + struct { + uint32_t _3_to_0 : 4; + uint32_t op1 : 1; + uint32_t _24_to_5 : 20; + uint32_t op0 : 3; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(TopLevelEncodings) == 4, " "); + +// Data-processing and miscellaneous instructions +union DataProcessingAndMisc { + uint32_t flat; + struct { + uint32_t _3_to_0 : 4; + uint32_t op4 : 1; + uint32_t op3 : 2; + uint32_t op2 : 1; + uint32_t _19_to_8 : 12; + uint32_t op1 : 5; + uint32_t op0 : 1; + uint32_t _00 : 2; + uint32_t _not1111 : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(DataProcessingAndMisc) == 4, " "); + static constexpr auto kPCRegNum = 15u; static const char * const kIntRegName[] = { @@ -435,9 +465,6 @@ static const char * const kIdpNamesRRR[] = { //111 RSC, RSCS (register) static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) { const IntDataProcessingRRR enc = {bits}; - if (enc.cond == 0b1111u) { - return false; - } inst.function = kIdpNamesRRR[ (enc.opc << 1u) | enc.s]; DecodeCondition(inst, enc.cond); @@ -481,9 +508,6 @@ static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) //111 RSC, RSCS (immediate) static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) { const IntDataProcessingRRI enc = { bits }; - if (enc.cond == 0b1111u) { - return false; - } inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s]; DecodeCondition(inst, enc.cond); @@ -557,9 +581,8 @@ static const char * const kMulAccRRR[] = { //111 SMLAL, SMLALS - writes to RdHi + RdLo, read RdHi static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { const MultiplyAndAccumulate enc = { bits }; - // cond != 1111 // if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; - if (enc.cond == 0b1111u || (enc.rdhi == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum) || ) { + if (enc.rdhi == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum) { return false; } @@ -589,7 +612,7 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); // If instruction is not MUL, UMULL, SMULL add read to RdLo otherwise add an immediate - if (enc.opc != 0b000u || enc.opc != 0b100u || enc.opc != 0b110u) { + if (enc.opc != 0b000u && enc.opc != 0b100u && enc.opc != 0b110u) { AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionRead); } else { AddImmOp(inst, 0); @@ -599,172 +622,105 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { } -static bool (*const kBits7_to_4[])(Instruction&, uint32_t) = { - [0b0000] = TryDecodeIntegerDataProcessingRRR, - [0b0001] = nullptr, - [0b0010] = TryDecodeIntegerDataProcessingRRR, - [0b0011] = nullptr, - [0b0100] = TryDecodeIntegerDataProcessingRRR, - [0b0101] = nullptr, - [0b0110] = TryDecodeIntegerDataProcessingRRR, - [0b0111] = nullptr, - [0b1000] = TryDecodeIntegerDataProcessingRRR, - [0b1001] = TryDecodeMultiplyAndAccumulate, - [0b1010] = TryDecodeIntegerDataProcessingRRR, +static uint32_t BytesToBits(const uint8_t *bytes) { + uint32_t bits = 0; + bits = (bits << 8) | static_cast(bytes[0]); + bits = (bits << 8) | static_cast(bytes[1]); + bits = (bits << 8) | static_cast(bytes[2]); + bits = (bits << 8) | static_cast(bytes[3]); + return bits; +} + +// Corresponds to Data-processing register (immediate shift) +// op0<24 to 23> | op1 <20> +static bool (*const kDataProcessingRI[])(Instruction&, uint32_t) = { + [0b000] = TryDecodeIntegerDataProcessingRRR, + [0b001] = TryDecodeIntegerDataProcessingRRR, + [0b010] = TryDecodeIntegerDataProcessingRRR, + [0b011] = nullptr, + [0b100] = nullptr, + [0b101] = nullptr, + [0b110] = nullptr, + [0b111] = nullptr, +}; + +// Corresponds to Data-processing immediate +// op0<24 to 23> | op1 <21 to 20> +static bool (*const kDataProcessingI[])(Instruction&, uint32_t) = { + [0b0000] = TryDecodeIntegerDataProcessingRRI, + [0b0001] = TryDecodeIntegerDataProcessingRRI, + [0b0010] = TryDecodeIntegerDataProcessingRRI, + [0b0011] = TryDecodeIntegerDataProcessingRRI, + [0b0100] = TryDecodeIntegerDataProcessingRRI, + [0b0101] = TryDecodeIntegerDataProcessingRRI, + [0b0110] = TryDecodeIntegerDataProcessingRRI, + [0b0111] = TryDecodeIntegerDataProcessingRRI, + [0b1000] = nullptr, + [0b1001] = nullptr, + [0b1010] = nullptr, [0b1011] = nullptr, - [0b1100] = TryDecodeIntegerDataProcessingRRR, + [0b1100] = nullptr, [0b1101] = nullptr, - [0b1110] = TryDecodeIntegerDataProcessingRRR, + [0b1110] = nullptr, [0b1111] = nullptr }; -static bool TryDecodeArithmetic(Instruction &inst, uint32_t bits){ - auto decode = kBits7_to_4[(bits >> 4) & 0b1111u]; - if (!decode){ - return false; - } - return decode(inst, bits); -} +typedef bool (*const TryDecode)(Instruction&, uint32_t); -static bool (*const kBits27_to_21[])(Instruction&, uint32_t) = { - [0b0000000] = TryDecodeArithmetic, - [0b0000001] = TryDecodeArithmetic, - [0b0000010] = TryDecodeArithmetic, - [0b0000011] = TryDecodeArithmetic, - [0b0000100] = TryDecodeArithmetic, - [0b0000101] = TryDecodeArithmetic, - [0b0000110] = TryDecodeArithmetic, - [0b0000111] = TryDecodeArithmetic, - [0b0001000] = nullptr, - [0b0001001] = nullptr, - [0b0001010] = nullptr, - [0b0001011] = nullptr, - [0b0001100] = nullptr, - [0b0001101] = nullptr, - [0b0001110] = nullptr, - [0b0001111] = nullptr, - [0b0010000] = TryDecodeIntegerDataProcessingRRI, - [0b0010001] = TryDecodeIntegerDataProcessingRRI, - [0b0010010] = TryDecodeIntegerDataProcessingRRI, - [0b0010011] = TryDecodeIntegerDataProcessingRRI, - [0b0010100] = TryDecodeIntegerDataProcessingRRI, - [0b0010101] = TryDecodeIntegerDataProcessingRRI, - [0b0010110] = TryDecodeIntegerDataProcessingRRI, - [0b0010111] = TryDecodeIntegerDataProcessingRRI, - [0b0011000] = nullptr, - [0b0011001] = nullptr, - [0b0011010] = nullptr, - [0b0011011] = nullptr, - [0b0011100] = nullptr, - [0b0011101] = nullptr, - [0b0011110] = nullptr, - [0b0011111] = nullptr, - [0b0100000] = nullptr, - [0b0100001] = nullptr, - [0b0100010] = nullptr, - [0b0100011] = nullptr, - [0b0100100] = nullptr, - [0b0100101] = nullptr, - [0b0100110] = nullptr, - [0b0100111] = nullptr, - [0b0101000] = nullptr, - [0b0101001] = nullptr, - [0b0101010] = nullptr, - [0b0101011] = nullptr, - [0b0101100] = nullptr, - [0b0101101] = nullptr, - [0b0101110] = nullptr, - [0b0101111] = nullptr, - [0b0110000] = nullptr, - [0b0110001] = nullptr, - [0b0110010] = nullptr, - [0b0110011] = nullptr, - [0b0110100] = nullptr, - [0b0110101] = nullptr, - [0b0110110] = nullptr, - [0b0110111] = nullptr, - [0b0111000] = nullptr, - [0b0111001] = nullptr, - [0b0111010] = nullptr, - [0b0111011] = nullptr, - [0b0111100] = nullptr, - [0b0111101] = nullptr, - [0b0111110] = nullptr, - [0b0111111] = nullptr, - [0b1000000] = nullptr, - [0b1000001] = nullptr, - [0b1000010] = nullptr, - [0b1000011] = nullptr, - [0b1000100] = nullptr, - [0b1000101] = nullptr, - [0b1000110] = nullptr, - [0b1000111] = nullptr, - [0b1001000] = nullptr, - [0b1001001] = nullptr, - [0b1001010] = nullptr, - [0b1001011] = nullptr, - [0b1001100] = nullptr, - [0b1001101] = nullptr, - [0b1001110] = nullptr, - [0b1001111] = nullptr, - [0b1010000] = nullptr, - [0b1010001] = nullptr, - [0b1010010] = nullptr, - [0b1010011] = nullptr, - [0b1010100] = nullptr, - [0b1010101] = nullptr, - [0b1010110] = nullptr, - [0b1010111] = nullptr, - [0b1011000] = nullptr, - [0b1011001] = nullptr, - [0b1011010] = nullptr, - [0b1011011] = nullptr, - [0b1011100] = nullptr, - [0b1011101] = nullptr, - [0b1011110] = nullptr, - [0b1011111] = nullptr, - [0b1100000] = nullptr, - [0b1100001] = nullptr, - [0b1100010] = nullptr, - [0b1100011] = nullptr, - [0b1100100] = nullptr, - [0b1100101] = nullptr, - [0b1100110] = nullptr, - [0b1100111] = nullptr, - [0b1101000] = nullptr, - [0b1101001] = nullptr, - [0b1101010] = nullptr, - [0b1101011] = nullptr, - [0b1101100] = nullptr, - [0b1101101] = nullptr, - [0b1101110] = nullptr, - [0b1101111] = nullptr, - [0b1110000] = nullptr, - [0b1110001] = nullptr, - [0b1110010] = nullptr, - [0b1110011] = nullptr, - [0b1110100] = nullptr, - [0b1110101] = nullptr, - [0b1110110] = nullptr, - [0b1110111] = nullptr, - [0b1111000] = nullptr, - [0b1111001] = nullptr, - [0b1111010] = nullptr, - [0b1111011] = nullptr, - [0b1111100] = nullptr, - [0b1111101] = nullptr, - [0b1111110] = nullptr, - [0b1111111] = nullptr, -}; +static TryDecode TryDataProcessingAndMisc(uint32_t bits) { + const DataProcessingAndMisc enc = { bits }; + if (!enc.op0) { + if ((!(enc.op1 >> 4)) && enc.op2 && (enc.op3 == 0b00u) && enc.op4) { + // Multiply and Accumulate + return TryDecodeMultiplyAndAccumulate; + } else if (!(((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) && !enc.op4) { + // Data-processing register (immediate shift) + return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b00001u)]; + } else { + // TODO(Sonya): Extra load/store + // TODO(Sonya): Synchronization primitives and Load-Acquire/Store-Release + // TODO(Sonya): Miscellaneous + // TODO(Sonya): Halfword Multiply and Accumulate + // TODO(Sonya): Data-processing register (register shift) + return nullptr; + } + } else { + // Data-processing immediate + return kDataProcessingI[(enc.op1 >> 1) | (enc.op1 & 0b00011u)]; + } +} -static uint32_t BytesToBits(const uint8_t *bytes) { - uint32_t bits = 0; - bits = (bits << 8) | static_cast(bytes[0]); - bits = (bits << 8) | static_cast(bytes[1]); - bits = (bits << 8) | static_cast(bytes[2]); - bits = (bits << 8) | static_cast(bytes[3]); - return bits; +// cond op0 op1 +//!= 1111 00x Data-processing and miscellaneous instructions +//!= 1111 010 Load/Store Word, Unsigned Byte (immediate, literal) +//!= 1111 011 0 Load/Store Word, Unsigned Byte (register) +//!= 1111 011 1 Media instructions +// 10x Branch, branch with link, and block data transfer +// 11x System register access, Advanced SIMD, floating-point, and Supervisor call +// 1111 0xx Unconditional instructions +static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { + const TopLevelEncodings enc = { bits }; + if (!(enc.op0 >> 2)) { // op0 == 0xx + if (enc.cond != 0b1111u) { + if (!(enc.op0 >> 1)) { // 00x + // Data-processing and miscellaneous instructions + return TryDataProcessingAndMisc(bits); + } else { + // TODO(Sonya): Load/Store Word, Unsigned Byte (immediate, literal) + // TODO(Sonya): Load/Store Word, Unsigned Byte (register) + // TODO(Sonya): Media instructions + return nullptr; + } + } else { + // TODO(Sonya): Unconditional instructions + return nullptr; + } + } else { // op0 == 1xx + // TODO(Sonya): Branch, branch with link, and block data transfer + // TODO(Sonya): System register access, Advanced SIMD, floating-point, and Supervisor call + return nullptr; + } } } // namespace @@ -796,7 +752,7 @@ bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_byte const auto bytes = reinterpret_cast(inst.bytes.data()); const auto bits = BytesToBits(bytes); - auto decoder = kBits27_to_21[(bits >> 21) & 0b1111111u]; + auto decoder = TryDecodeTopLevelEncodings(bits); if (!decoder) { LOG(ERROR) << "unhandled bits"; return false; diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index 130d2a84b..9dd2bd8e2 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -192,10 +192,10 @@ DEF_SEM(MULS, R32W dst, R32 src1, R32 src2, R32 src3) { } DEF_SEM(UMAAL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { - auto rhs = Read(src3); - auto lhs = Read(src2); - auto acc_hi = Read(src1); - auto acc_lo = Read(src4); + auto rhs = ZExt(Read(src3)); + auto lhs = ZExt(Read(src2)); + auto acc_hi = ZExt(Read(src1)); + auto acc_lo = ZExt(Read(src4)); auto res = UAdd(UAdd(UMul(lhs, rhs), acc_hi), acc_lo); Write(dst_lo, Trunc(res)); Write(dst_hi, Trunc(UShr(res, 32ul))); @@ -212,9 +212,9 @@ DEF_SEM(MLS, R32W dst, R32 src1, R32 src2, R32 src3) { } DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { - auto rhs = Read(src3); - auto lhs = Read(src2); - auto acc = UOr(UShl(ZExt(Read(src1))), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto rhs = ZExt(Read(src3)); + auto lhs = ZExt(Read(src2)); + auto acc = UOr(UShl(ZExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = UAdd(UMul(lhs, rhs), acc); Write(dst_hi, Trunc(UShr(res, 32ul))); Write(dst_lo, Trunc(res)); @@ -222,9 +222,9 @@ DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) } DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { - auto rhs = Read(src3); - auto lhs = Read(src2); - auto acc = UOr(UShl(ZExt(Read(src1))), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto rhs = ZExt(Read(src3)); + auto lhs = ZExt(Read(src2)); + auto acc = UOr(UShl(ZExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = UAdd(UMul(lhs, rhs), acc); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); @@ -236,24 +236,24 @@ DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4 DEF_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { // Not entirely sure about all the signed ops I have in here - auto rhs = Signed(Read(src3)); - auto lhs = Signed(Read(src2)); - auto acc = SOr(SShl(SExt(Read(src1))), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto rhs = SExt(Signed(Read(src3))); + auto lhs = SExt(Signed(Read(src2))); + auto acc = SOr(SShl(SExt(Read(src1)), 32ul), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); - Write(dst_hi, Trunc(UShr(res, 32ul))); + Write(dst_hi, Trunc(SShr(res, 32ul))); Write(dst_lo, Trunc(res)); return memory; } DEF_SEM(SMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { - auto rhs = Signed(Read(src3)); - auto lhs = Signed(Read(src2)); - auto acc = SOr(SShl(SExt(Read(src1))), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto rhs = SExt(Signed(Read(src3))); + auto lhs = SExt(Signed(Read(src2))); + auto acc = SOr(SShl(SExt(Read(src1)), 32ul), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); // PSTATE.C, PSTATE.V unchanged - Write(dst_hi, Trunc(UShr(res, 32ul))); + Write(dst_hi, Trunc(SShr(res, 32ul))); Write(dst_lo, Trunc(res)); return memory; } From f5cb08b57c80201791446b0b509efc81ad0b5c7f Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 6 Oct 2020 09:56:30 -0400 Subject: [PATCH 014/130] Update returns around kDataProcessingRI and kDataProcessingI with comments to explain the correlation to the instruction rep --- remill/Arch/AArch32/Decode.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index cf5cbdd34..f5bca3f53 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -676,7 +676,9 @@ static TryDecode TryDataProcessingAndMisc(uint32_t bits) { } else if (!(((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) && !enc.op4) { // Data-processing register (immediate shift) - return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b00001u)]; + // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 lowest bit + // index is the concatenation of op0 and op1 + return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; } else { // TODO(Sonya): Extra load/store // TODO(Sonya): Synchronization primitives and Load-Acquire/Store-Release @@ -687,7 +689,9 @@ static TryDecode TryDataProcessingAndMisc(uint32_t bits) { } } else { // Data-processing immediate - return kDataProcessingI[(enc.op1 >> 1) | (enc.op1 & 0b00011u)]; + // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 2 lowest bits + // index is the concatenation of op0 and op1 + return kDataProcessingI[(enc.op1 >> 1) | (enc.op1 & 0b11u)]; } } From cdc05879645e62197f4de6d86aef517c5f191df6 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 6 Oct 2020 13:18:02 -0400 Subject: [PATCH 015/130] Added appropriate inst.category flags to Multiply and accumulate --- remill/Arch/AArch32/Decode.cpp | 35 +++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index f5bca3f53..4a02f9b21 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -535,7 +535,6 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) DecodeA32ExpandImm(inst, enc.imm12, enc.s); if (enc.rd == kPCRegNum) { - if (enc.s) { // Updates the flags (condition codes) inst.category = Instruction::kCategoryError; return false; @@ -583,6 +582,7 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { const MultiplyAndAccumulate enc = { bits }; // if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; if (enc.rdhi == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum) { + inst.category = Instruction::kCategoryError; return false; } @@ -594,10 +594,12 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rdhi, 32, Operand::kActionWrite); + // 2nd write reg only needed for instructions with an opc that begins with 1 and UMALL if (((enc.opc >> 2) & 0b1u) || enc.opc == 0b010u) { // if dHi == dLo then UNPREDICTABLE; - if (enc.rdlo == enc.rdhi){ + if (enc.rdlo == enc.rdhi || enc.rdlo == kPCRegNum){ + inst.category = Instruction::kCategoryError; return false; } AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionWrite); @@ -611,6 +613,7 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { } AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); + // If instruction is not MUL, UMULL, SMULL add read to RdLo otherwise add an immediate if (enc.opc != 0b000u && enc.opc != 0b100u && enc.opc != 0b110u) { AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionRead); @@ -618,6 +621,8 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { AddImmOp(inst, 0); } + inst.category = Instruction::kCategoryNormal; + return true; } @@ -637,11 +642,11 @@ static bool (*const kDataProcessingRI[])(Instruction&, uint32_t) = { [0b000] = TryDecodeIntegerDataProcessingRRR, [0b001] = TryDecodeIntegerDataProcessingRRR, [0b010] = TryDecodeIntegerDataProcessingRRR, - [0b011] = nullptr, - [0b100] = nullptr, - [0b101] = nullptr, - [0b110] = nullptr, - [0b111] = nullptr, + [0b011] = TryDecodeIntegerDataProcessingRRR, + [0b100] = nullptr, // op0:op1 != 100 + [0b101] = nullptr, // TODO(Sonya): Integer Test and Compare (two register, immediate shift) + [0b110] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, immediate shift) + [0b111] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, immediate shift) }; // Corresponds to Data-processing immediate @@ -655,14 +660,14 @@ static bool (*const kDataProcessingI[])(Instruction&, uint32_t) = { [0b0101] = TryDecodeIntegerDataProcessingRRI, [0b0110] = TryDecodeIntegerDataProcessingRRI, [0b0111] = TryDecodeIntegerDataProcessingRRI, - [0b1000] = nullptr, - [0b1001] = nullptr, - [0b1010] = nullptr, - [0b1011] = nullptr, - [0b1100] = nullptr, - [0b1101] = nullptr, - [0b1110] = nullptr, - [0b1111] = nullptr + [0b1000] = nullptr, // TODO(Sonya): Move Halfword (immediate) + [0b1001] = nullptr, // TODO(Sonya): Integer Test and Compare (one register and immediate) + [0b1010] = nullptr, // TODO(Sonya): Move Special Register and Hints (immediate) + [0b1011] = nullptr, // TODO(Sonya): Integer Test and Compare (one register and immediate) + [0b1100] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) + [0b1101] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) + [0b1110] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) + [0b1111] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) }; typedef bool (*const TryDecode)(Instruction&, uint32_t); From 86429409fc3533525786f719a3d4b9f860bd1674 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 6 Oct 2020 18:23:22 -0400 Subject: [PATCH 016/130] Load/Store Word, Unsigned Byte (immediate, literal) && start of Logical Arithmetic (three register, immediate shift) --- remill/Arch/AArch32/Decode.cpp | 219 ++++++++++++++++++- remill/Arch/AArch32/Runtime/Instructions.cpp | 1 + remill/Arch/AArch32/Semantics/MEM.cpp | 87 ++++++++ remill/Arch/Runtime/HyperCall.h | 5 +- 4 files changed, 299 insertions(+), 13 deletions(-) create mode 100644 remill/Arch/AArch32/Semantics/MEM.cpp diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 4a02f9b21..270b27923 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -72,6 +72,42 @@ union MultiplyAndAccumulate { } __attribute__((packed)); static_assert(sizeof(MultiplyAndAccumulate) == 4, " "); +// Load/Store Word, Unsigned Byte (immediate, literal) +union LoadStoreWUBIL { + uint32_t flat; + struct { + uint32_t imm12 : 12; + uint32_t rt : 4; + uint32_t rn : 4; + uint32_t o1 : 1; + uint32_t W : 1; + uint32_t o2 : 1; + uint32_t u : 1; + uint32_t P : 1; + uint32_t _010 : 3; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(LoadStoreWUBIL) == 4, " "); + +// Logical Arithmetic (three register, immediate shift) +union LogicalArithRRRI { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _0 : 1; + uint32_t type : 2; + uint32_t imm5 : 5; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 2; + uint32_t _00011 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(LoadStoreWUBIL) == 4, " "); + // Top-level encodings for A32 union TopLevelEncodings { uint32_t flat; @@ -122,6 +158,7 @@ static const char * const kIntRegName[] = { "R14", "R15" }; +typedef bool (*const TryDecode)(Instruction&, uint32_t); static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out) { uint32_t unrotated_value = imm12 & (0b11111111u); @@ -279,6 +316,8 @@ static void AddShiftRegOperand(Instruction &inst, } } + +// (shift_t, shift_n) = DecodeImmShift(type, imm5) static void AddShiftCarryOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_size, const char * carry_reg_name) { @@ -624,16 +663,146 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { inst.category = Instruction::kCategoryNormal; return true; +} + +static const char * const kLoadSWUBIL[] = { + [0b0000] = "STRp", + [0b0001] = "LDRp", + [0b0010] = "STRBp", + [0b0011] = "LDRBp", + [0b0100] = "STRT", + [0b0101] = "LDRT", + [0b0110] = "STRBT", + [0b0111] = "LDRBT", + [0b1000] = "STR", + [0b1001] = "LDR", + [0b1010] = "STRB", + [0b1011] = "LDRB", + [0b1100] = "STRp", + [0b1101] = "LDRp", + [0b1110] = "STRBp", + [0b1111] = "LDRBp", +}; + +// P:W o2 o1 Rn +//!= 01 0 1 1111 LDR (literal) +//!= 01 1 1 1111 LDRB (literal) +// 00 0 0 STR (immediate) — post-indexed +// 00 0 1 != 1111 LDR (immediate) — post-indexed +// 00 1 0 STRB (immediate) — post-indexed +// 00 1 1 != 1111 LDRB (immediate) — post-indexed +// 01 0 0 STRT +// 01 0 1 LDRT +// 01 1 0 STRBT +// 01 1 1 LDRBT +// 10 0 0 STR (immediate) — offset +// 10 0 1 != 1111 LDR (immediate) — offset +// 10 1 0 STRB (immediate) — offset +// 10 1 1 != 1111 LDRB (immediate) — offset +// 11 0 0 STR (immediate) — pre-indexed +// 11 0 1 != 1111 LDR (immediate) — pre-indexed +// 11 1 0 STRB (immediate) — pre-indexed +// 11 1 1 != 1111 LDRB (immediate) — pre-indexed +template +static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { + const LoadStoreWUBIL enc = { bits }; + + auto instruction = kLoadSWUBIL[enc.P << 3u | enc.W << 2u | enc.o2 << 1u | enc.o1]; + if (!instruction) { + return false; + } + inst.function = instruction; + DecodeCondition(inst, enc.cond); + bool write_back = (!enc.P || enc.W); + + if (write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt)) { + inst.category = Instruction::kCategoryError; + return false; + } + + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.type = Operand::kTypeAddress; + op.size = kMemSize; + op.action = kMemAction; + op.addr.address_size = 32; + op.addr.base_reg.name = kIntRegName[enc.rn]; + op.addr.base_reg.size = 32; + op.addr.scale = 0; + op.addr.displacement = 0; + + // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes + int64_t pc_adjust = 0; + if (kAlignPC && enc.rn == kPCRegNum) { + pc_adjust = static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); + } + auto disp = static_cast(enc.imm12); + // Subtract + if (!enc.u) { + disp = -disp; + } + + // Not Indexing + if (!enc.P) { + op.addr.displacement = pc_adjust; + } else { + op.addr.displacement = disp + pc_adjust; + } + + AddIntRegOp(inst, enc.rt, 32, kRegAction); + + // Pre or Post Indexing + if (write_back) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.type = Operand::kTypeAddress; + op.size = 32; + op.action = Operand::kActionRead; + op.addr.address_size = 32; + op.addr.base_reg.name = kIntRegName[enc.rn]; + op.addr.base_reg.size = 32; + op.addr.scale = 0; + op.addr.displacement = disp + pc_adjust; + } + inst.category = Instruction::kCategoryNormal; + return true; } -static uint32_t BytesToBits(const uint8_t *bytes) { - uint32_t bits = 0; - bits = (bits << 8) | static_cast(bytes[0]); - bits = (bits << 8) | static_cast(bytes[1]); - bits = (bits << 8) | static_cast(bytes[2]); - bits = (bits << 8) | static_cast(bytes[3]); - return bits; +//00 ORR, ORRS (register) +//01 MOV, MOVS (register) +//10 BIC, BICS (register) +//11 MVN, MVNS (register) +static const char * const kLogicalArithmeticRRRI[] = { + [0b00] = "ORR", + [0b01] = "MOV", + [0b10] = "BIC", + [0b11] = "MVN", +}; + +// Logical Arithmetic (three register, immediate shift) +static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { + const LogicalArithRRRI enc = { bits }; + + auto instruction = kLogicalArithmeticRRRI[enc.opc]; + if (!instruction) { + return false; + } + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); + + if (enc.rd == kPCRegNum){ + if (enc.s) { + + } else { + + } + } + return true; } // Corresponds to Data-processing register (immediate shift) @@ -645,8 +814,8 @@ static bool (*const kDataProcessingRI[])(Instruction&, uint32_t) = { [0b011] = TryDecodeIntegerDataProcessingRRR, [0b100] = nullptr, // op0:op1 != 100 [0b101] = nullptr, // TODO(Sonya): Integer Test and Compare (two register, immediate shift) - [0b110] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, immediate shift) - [0b111] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, immediate shift) + [0b110] = TryLogicalArithmeticRRRI, + [0b111] = TryLogicalArithmeticRRRI, }; // Corresponds to Data-processing immediate @@ -670,8 +839,25 @@ static bool (*const kDataProcessingI[])(Instruction&, uint32_t) = { [0b1111] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) }; -typedef bool (*const TryDecode)(Instruction&, uint32_t); +// Corresponds to: Load/Store Word, Unsigned Byte (immediate, literal) +// o2<22> | o1<21> +static bool (*const kLoadStoreWordUBIL[])(Instruction&, uint32_t) = { + [0b00] = TryDecodeLoadStoreWordUBIL, + [0b01] = TryDecodeLoadStoreWordUBIL, + [0b10] = TryDecodeLoadStoreWordUBIL, + [0b11] = TryDecodeLoadStoreWordUBIL, +}; +// Corresponds to: Data-processing and miscellaneous instructions +//op0 op1 op2 op3 op4 +//0 1 != 00 1 Extra load/store +//0 0xxxx 1 00 1 Multiply and Accumulate +//0 1xxxx 1 00 1 Synchronization primitives and Load-Acquire/Store-Release +//0 10xx0 0 Miscellaneous +//0 10xx0 1 0 Halfword Multiply and Accumulate +//0 != 10xx0 0 Data-processing register (immediate shift) +//0 != 10xx0 0 1 Data-processing register (register shift) +//1 Data-processing immediate static TryDecode TryDataProcessingAndMisc(uint32_t bits) { const DataProcessingAndMisc enc = { bits }; if (!enc.op0) { @@ -715,8 +901,11 @@ static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { if (!(enc.op0 >> 1)) { // 00x // Data-processing and miscellaneous instructions return TryDataProcessingAndMisc(bits); + } else if (enc.op0 == 0b010u) { + // Load/Store Word, Unsigned Byte (immediate, literal) + const LoadStoreWUBIL enc_ls_word = { bits }; + return kLoadStoreWordUBIL[enc_ls_word.o2 << 1u | enc_ls_word.o1]; } else { - // TODO(Sonya): Load/Store Word, Unsigned Byte (immediate, literal) // TODO(Sonya): Load/Store Word, Unsigned Byte (register) // TODO(Sonya): Media instructions return nullptr; @@ -732,6 +921,14 @@ static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { } } +static uint32_t BytesToBits(const uint8_t *bytes) { + uint32_t bits = 0; + bits = (bits << 8) | static_cast(bytes[3]); + bits = (bits << 8) | static_cast(bytes[2]); + bits = (bits << 8) | static_cast(bytes[1]); + bits = (bits << 8) | static_cast(bytes[0]); + return bits; +} } // namespace // Decode an instuction. diff --git a/remill/Arch/AArch32/Runtime/Instructions.cpp b/remill/Arch/AArch32/Runtime/Instructions.cpp index 58fd30482..517556604 100644 --- a/remill/Arch/AArch32/Runtime/Instructions.cpp +++ b/remill/Arch/AArch32/Runtime/Instructions.cpp @@ -59,6 +59,7 @@ DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; #include "remill/Arch/AArch32/Semantics/FLAGS.cpp" // #include "remill/Arch/AArch32/Semantics/BINARY.cpp" +#include "remill/Arch/AArch32/Semantics/MEM.cpp" //#include "remill/Arch/AArch64/Semantics/BITBYTE.cpp" //#include "remill/Arch/AArch64/Semantics/BRANCH.cpp" //#include "remill/Arch/AArch64/Semantics/CALL_RET.cpp" diff --git a/remill/Arch/AArch32/Semantics/MEM.cpp b/remill/Arch/AArch32/Semantics/MEM.cpp new file mode 100644 index 000000000..ef539cc14 --- /dev/null +++ b/remill/Arch/AArch32/Semantics/MEM.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { +// Offset +template +DEF_SEM(STR, DstType dst, R32 src1) { + auto src = Read(src1); + Write(dst, TruncTo(src)); + return memory; +} + +// Pre + Post +template +DEF_SEM(STRp, DstType dst, R32 src1, R32W dst_reg, R32 src2) { + auto src = Read(src1); + auto new_val = Read(src2); + Write(dst, TruncTo(src)); + Write(dst_reg, new_val); + return memory; +} + +// Offset +template +DEF_SEM(LDR, SrcType src1, R32W dst) { + auto src = Read(src1); + WriteZExt(dst, src); + return memory; +} + +// Pre + Post +template +DEF_SEM(LDRp, SrcType src1, R32W dst, R32W dst_reg, R32 src2) { + auto src = Read(src1); + auto new_val = Read(src2); + WriteZExt(dst, src); + Write(dst_reg, new_val); + return memory; +} + +template +DEF_SEM(STRT, DstType dst, R32 src1, R32W dst_reg, R32 src2) { + memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + auto src = Read(src1); + auto new_val = Read(src2); + Write(dst, TruncTo(src)); + Write(dst_reg, new_val); + return memory; +} + +template +DEF_SEM(LDRT, SrcType src1, R32W dst, R32W dst_reg, R32 src2) { + memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + auto src = Read(src1); + auto new_val = Read(src2); + WriteZExt(dst, src); + Write(dst_reg, new_val); + return memory; +} + +} // namespace + +DEF_ISEL(STR) = STR; +DEF_ISEL(STRB) = STR; +DEF_ISEL(STRp) = STR; +DEF_ISEL(STRBp) = STR; +DEF_ISEL(LDR) = LDR; +DEF_ISEL(LDRB) = LDR; +DEF_ISEL(LDRp) = LDR; +DEF_ISEL(LDRBp) = LDR; +DEF_ISEL(STRT) = STRT; +DEF_ISEL(STRBT) = STRT; +DEF_ISEL(LDRT) = LDRT; +DEF_ISEL(LDRBT) = LDRT; diff --git a/remill/Arch/Runtime/HyperCall.h b/remill/Arch/Runtime/HyperCall.h index 46ad3183f..badd95faf 100644 --- a/remill/Arch/Runtime/HyperCall.h +++ b/remill/Arch/Runtime/HyperCall.h @@ -60,9 +60,10 @@ class SyncHyperCall { // TODO(pag): How to distinguish little- and big-endian? kAArch64EmulateInstruction = 0x200U, kAArch64Breakpoint, - kAArch32EmulateInstruction = 0x300U, + kAArch32EmulateInstruction = 0x300U, + kAArch32CheckNotEL2, }; -} __attribute__((packed)); +}__attribute__((packed)); class AsyncHyperCall { public: From e9e7b411d6a4e886c2566d23b6ffdc86bcad605b Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 7 Oct 2020 10:18:15 -0400 Subject: [PATCH 017/130] Was missing UMAAL DEF_ISEL in Binary.cpp --- remill/Arch/AArch32/Semantics/BINARY.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index 9dd2bd8e2..c78dd6277 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -197,8 +197,8 @@ DEF_SEM(UMAAL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) auto acc_hi = ZExt(Read(src1)); auto acc_lo = ZExt(Read(src4)); auto res = UAdd(UAdd(UMul(lhs, rhs), acc_hi), acc_lo); - Write(dst_lo, Trunc(res)); - Write(dst_hi, Trunc(UShr(res, 32ul))); + Write(dst_lo, TruncTo(res)); + Write(dst_hi, TruncTo(UShr(res, 32ul))); return memory; } @@ -216,8 +216,8 @@ DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) auto lhs = ZExt(Read(src2)); auto acc = UOr(UShl(ZExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = UAdd(UMul(lhs, rhs), acc); - Write(dst_hi, Trunc(UShr(res, 32ul))); - Write(dst_lo, Trunc(res)); + Write(dst_hi, TruncTo(UShr(res, 32ul))); + Write(dst_lo, TruncTo(res)); return memory; } @@ -229,8 +229,8 @@ DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4 state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); // PSTATE.C, PSTATE.V unchanged - Write(dst_hi, Trunc(UShr(res, 32ul))); - Write(dst_lo, Trunc(res)); + Write(dst_hi, TruncTo(UShr(res, 32ul))); + Write(dst_lo, TruncTo(res)); return memory; } @@ -240,8 +240,8 @@ DEF_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) auto lhs = SExt(Signed(Read(src2))); auto acc = SOr(SShl(SExt(Read(src1)), 32ul), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); - Write(dst_hi, Trunc(SShr(res, 32ul))); - Write(dst_lo, Trunc(res)); + Write(dst_hi, TruncTo(SShr(res, 32ul))); + Write(dst_lo, TruncTo(res)); return memory; } @@ -253,8 +253,8 @@ DEF_SEM(SMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4 state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); // PSTATE.C, PSTATE.V unchanged - Write(dst_hi, Trunc(SShr(res, 32ul))); - Write(dst_lo, Trunc(res)); + Write(dst_hi, TruncTo(SShr(res, 32ul))); + Write(dst_lo, TruncTo(res)); return memory; } } // namespace @@ -264,6 +264,7 @@ DEF_ISEL(MULSrr) = MULS; DEF_ISEL(MLArr) = MUL; DEF_ISEL(MLASrr) = MULS; DEF_ISEL(MLSrr) = MLS; +DEF_ISEL(UMAALrr) = UMAAL; DEF_ISEL(UMULLrr) = UMULL; DEF_ISEL(UMULLSrr) = UMULLS; DEF_ISEL(UMLALrr) = UMULL; From 9d48aae95d21db02a0a1b8db32fed8c6b419ee2b Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 8 Oct 2020 12:49:45 -0400 Subject: [PATCH 018/130] AddAddrRegOp --- remill/Arch/AArch32/Decode.cpp | 110 +++++++++++++++++---------------- 1 file changed, 56 insertions(+), 54 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 270b27923..0b29f412e 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -228,16 +228,31 @@ static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, } static void AddImmOp(Instruction &inst, uint64_t value, unsigned size = 32, - bool is_signed = false) { + Operand::Action action = Operand::kActionRead, + bool is_signed = false) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.imm.val = value; op.size = size; op.imm.is_signed = is_signed; - op.action = Operand::kActionRead; + op.action = action; op.type = Operand::kTypeImmediate; } +static void AddAddrRegOp(Instruction &inst, const char * reg_name, unsigned mem_size, + Operand::Action mem_action, unsigned disp, unsigned scale = 0) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.type = Operand::kTypeAddress; + op.size = mem_size; + op.action = mem_action; + op.addr.address_size = 32; + op.addr.base_reg.name = reg_name; + op.addr.base_reg.size = 32; + op.addr.scale = scale; + op.addr.displacement = disp; +} + // Note: Order is significant; extracted bits may be casted to this type. enum Shift : uint32_t { kShiftLSL, kShiftLSR, kShiftASR, kShiftROR }; @@ -556,16 +571,7 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) if (enc.rn == kPCRegNum && (enc.opc == 0b100u || enc.opc == 0b010u)) { int64_t diff = static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.type = Operand::kTypeAddress; - op.size = 32; - op.action = Operand::kActionRead; - op.addr.address_size = 32; - op.addr.base_reg.name = "PC"; - op.addr.base_reg.size = 32; - op.addr.scale = 0; - op.addr.displacement = diff; + AddAddrRegOp(inst, "PC", 32, Operand::kActionRead, diff); } else { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); @@ -686,8 +692,8 @@ static const char * const kLoadSWUBIL[] = { // P:W o2 o1 Rn -//!= 01 0 1 1111 LDR (literal) -//!= 01 1 1 1111 LDRB (literal) +//!= 01 0 1 1111 LDR (literal) +//!= 01 1 1 1111 LDRB (literal) // 00 0 0 STR (immediate) — post-indexed // 00 0 1 != 1111 LDR (immediate) — post-indexed // 00 1 0 STRB (immediate) — post-indexed @@ -721,17 +727,6 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { return false; } - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.type = Operand::kTypeAddress; - op.size = kMemSize; - op.action = kMemAction; - op.addr.address_size = 32; - op.addr.base_reg.name = kIntRegName[enc.rn]; - op.addr.base_reg.size = 32; - op.addr.scale = 0; - op.addr.displacement = 0; - // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes int64_t pc_adjust = 0; if (kAlignPC && enc.rn == kPCRegNum) { @@ -745,9 +740,9 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { // Not Indexing if (!enc.P) { - op.addr.displacement = pc_adjust; + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); } else { - op.addr.displacement = disp + pc_adjust; + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, disp + pc_adjust); } AddIntRegOp(inst, enc.rt, 32, kRegAction); @@ -755,17 +750,9 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { // Pre or Post Indexing if (write_back) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.type = Operand::kTypeAddress; - op.size = 32; - op.action = Operand::kActionRead; - op.addr.address_size = 32; - op.addr.base_reg.name = kIntRegName[enc.rn]; - op.addr.base_reg.size = 32; - op.addr.scale = 0; - op.addr.displacement = disp + pc_adjust; + AddAddrRegOp(inst, kIntRegName[enc.rn], 32, Operand::kActionRead, disp + pc_adjust); } + inst.category = Instruction::kCategoryNormal; return true; } @@ -775,17 +762,21 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { //10 BIC, BICS (register) //11 MVN, MVNS (register) static const char * const kLogicalArithmeticRRRI[] = { - [0b00] = "ORR", - [0b01] = "MOV", - [0b10] = "BIC", - [0b11] = "MVN", + [0b000] = "ORR", + [0b001] = "ORRS", + [0b010] = "MOV", + [0b011] = "MOVS", + [0b100] = "BIC", + [0b101] = "BICS", + [0b110] = "MVN", + [0b111] = "MVNS", }; // Logical Arithmetic (three register, immediate shift) static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { const LogicalArithRRRI enc = { bits }; - auto instruction = kLogicalArithmeticRRRI[enc.opc]; + auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; if (!instruction) { return false; } @@ -860,13 +851,15 @@ static bool (*const kLoadStoreWordUBIL[])(Instruction&, uint32_t) = { //1 Data-processing immediate static TryDecode TryDataProcessingAndMisc(uint32_t bits) { const DataProcessingAndMisc enc = { bits }; + + // op0 == 0 if (!enc.op0) { + // Multiply and Accumulate if ((!(enc.op1 >> 4)) && enc.op2 && (enc.op3 == 0b00u) && enc.op4) { - // Multiply and Accumulate return TryDecodeMultiplyAndAccumulate; - - } else if (!(((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) && !enc.op4) { - // Data-processing register (immediate shift) + } + // Data-processing register (immediate shift) + else if (!(((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) && !enc.op4) { // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 lowest bit // index is the concatenation of op0 and op1 return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; @@ -878,14 +871,19 @@ static TryDecode TryDataProcessingAndMisc(uint32_t bits) { // TODO(Sonya): Data-processing register (register shift) return nullptr; } - } else { - // Data-processing immediate + } + // op0 == 1 + // Data-processing immediate + else { // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 2 lowest bits // index is the concatenation of op0 and op1 return kDataProcessingI[(enc.op1 >> 1) | (enc.op1 & 0b11u)]; } } +// This is the top level of the instruction encoding schema for AArch32. +// Instructions are grouped into subsets based on this the top level and then +// into smaller sets. // cond op0 op1 //!= 1111 00x Data-processing and miscellaneous instructions //!= 1111 010 Load/Store Word, Unsigned Byte (immediate, literal) @@ -896,13 +894,15 @@ static TryDecode TryDataProcessingAndMisc(uint32_t bits) { // 1111 0xx Unconditional instructions static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { const TopLevelEncodings enc = { bits }; - if (!(enc.op0 >> 2)) { // op0 == 0xx + // op0 == 0xx + if (!(enc.op0 >> 2)) { if (enc.cond != 0b1111u) { - if (!(enc.op0 >> 1)) { // 00x - // Data-processing and miscellaneous instructions + // Data-processing and miscellaneous instructions -- op0 == 00x + if (!(enc.op0 >> 1)) { return TryDataProcessingAndMisc(bits); - } else if (enc.op0 == 0b010u) { - // Load/Store Word, Unsigned Byte (immediate, literal) + } + // Load/Store Word, Unsigned Byte (immediate, literal) -- op0 == 010 + else if (enc.op0 == 0b010u) { const LoadStoreWUBIL enc_ls_word = { bits }; return kLoadStoreWordUBIL[enc_ls_word.o2 << 1u | enc_ls_word.o1]; } else { @@ -914,7 +914,9 @@ static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { // TODO(Sonya): Unconditional instructions return nullptr; } - } else { // op0 == 1xx + } + // op0 == 1xx + else { // TODO(Sonya): Branch, branch with link, and block data transfer // TODO(Sonya): System register access, Advanced SIMD, floating-point, and Supervisor call return nullptr; From 5b82b039a731648a5e5372ec6a7faca9a2b402be Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 8 Oct 2020 18:18:51 -0400 Subject: [PATCH 019/130] Logical Arithmetic (three register, immediate shift) without accounting for the possible PC jump --- remill/Arch/AArch32/Decode.cpp | 59 ++++++----- remill/Arch/AArch32/Runtime/Instructions.cpp | 2 +- remill/Arch/AArch32/Semantics/LOGICAL.cpp | 101 +++++++++++++++++++ 3 files changed, 136 insertions(+), 26 deletions(-) create mode 100644 remill/Arch/AArch32/Semantics/LOGICAL.cpp diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 0b29f412e..b4340656a 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -159,6 +159,7 @@ static const char * const kIntRegName[] = { "R15" }; typedef bool (*const TryDecode)(Instruction&, uint32_t); +typedef bool (*const TryDecodeList[])(Instruction&, uint32_t); static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out) { uint32_t unrotated_value = imm12 & (0b11111111u); @@ -272,6 +273,9 @@ static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { return Operand::ShiftRegister::kShiftInvalid; } + +// Used to handle (shift_t, shift_n) = DecodeImmShift(type, imm5) semantics +// See an instruction in Integer Data Processing (three register, immediate shift) set for an example static void AddShiftRegOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_size) { @@ -570,9 +574,7 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) // Raise the program counter to align to a multiple of 4 bytes if (enc.rn == kPCRegNum && (enc.opc == 0b100u || enc.opc == 0b010u)) { int64_t diff = static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); - AddAddrRegOp(inst, "PC", 32, Operand::kActionRead, diff); - } else { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); } @@ -757,19 +759,19 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { return true; } -//00 ORR, ORRS (register) -//01 MOV, MOVS (register) -//10 BIC, BICS (register) -//11 MVN, MVNS (register) +//00 ORR, ORRS (register) -- rd, rn, & rm +//01 MOV, MOVS (register) -- rd, & rm only +//10 BIC, BICS (register) -- rd, rn, & rm +//11 MVN, MVNS (register) -- rd, & rm only static const char * const kLogicalArithmeticRRRI[] = { - [0b000] = "ORR", - [0b001] = "ORRS", - [0b010] = "MOV", - [0b011] = "MOVS", - [0b100] = "BIC", - [0b101] = "BICS", - [0b110] = "MVN", - [0b111] = "MVNS", + [0b000] = "ORRrrri", + [0b001] = "ORRSrrri", + [0b010] = "MOVrrri", + [0b011] = "MOVSrrri", + [0b100] = "BICrrri", + [0b101] = "BICSrrri", + [0b110] = "MVNrrri", + [0b111] = "MVNSrrri", }; // Logical Arithmetic (three register, immediate shift) @@ -784,21 +786,28 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); - AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); - if (enc.rd == kPCRegNum){ - if (enc.s) { + // enc.opc == x0 + if (!(enc.opc & 0b1)) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + } - } else { + AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); + if (enc.s) { + AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); + } - } + if (enc.rd == kPCRegNum){ + // TODO(Sonya): handle the PC destination register case } + + inst.category = Instruction::kCategoryNormal; return true; } // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> -static bool (*const kDataProcessingRI[])(Instruction&, uint32_t) = { +static TryDecodeList kDataProcessingRI = { [0b000] = TryDecodeIntegerDataProcessingRRR, [0b001] = TryDecodeIntegerDataProcessingRRR, [0b010] = TryDecodeIntegerDataProcessingRRR, @@ -811,7 +820,7 @@ static bool (*const kDataProcessingRI[])(Instruction&, uint32_t) = { // Corresponds to Data-processing immediate // op0<24 to 23> | op1 <21 to 20> -static bool (*const kDataProcessingI[])(Instruction&, uint32_t) = { +static TryDecodeList kDataProcessingI = { [0b0000] = TryDecodeIntegerDataProcessingRRI, [0b0001] = TryDecodeIntegerDataProcessingRRI, [0b0010] = TryDecodeIntegerDataProcessingRRI, @@ -832,7 +841,7 @@ static bool (*const kDataProcessingI[])(Instruction&, uint32_t) = { // Corresponds to: Load/Store Word, Unsigned Byte (immediate, literal) // o2<22> | o1<21> -static bool (*const kLoadStoreWordUBIL[])(Instruction&, uint32_t) = { +static TryDecodeList kLoadStoreWordUBIL = { [0b00] = TryDecodeLoadStoreWordUBIL, [0b01] = TryDecodeLoadStoreWordUBIL, [0b10] = TryDecodeLoadStoreWordUBIL, @@ -906,12 +915,12 @@ static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { const LoadStoreWUBIL enc_ls_word = { bits }; return kLoadStoreWordUBIL[enc_ls_word.o2 << 1u | enc_ls_word.o1]; } else { - // TODO(Sonya): Load/Store Word, Unsigned Byte (register) - // TODO(Sonya): Media instructions + // TODO(Sonya): Load/Store Word, Unsigned Byte (register) -- op0 == 011, op1 == 0 + // TODO(Sonya): Media instructions -- op0 == 011, op1 == 1 return nullptr; } } else { - // TODO(Sonya): Unconditional instructions + // TODO(Sonya): Unconditional instructions -- cond == 1111 return nullptr; } } diff --git a/remill/Arch/AArch32/Runtime/Instructions.cpp b/remill/Arch/AArch32/Runtime/Instructions.cpp index 517556604..57a660776 100644 --- a/remill/Arch/AArch32/Runtime/Instructions.cpp +++ b/remill/Arch/AArch32/Runtime/Instructions.cpp @@ -60,13 +60,13 @@ DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; // #include "remill/Arch/AArch32/Semantics/BINARY.cpp" #include "remill/Arch/AArch32/Semantics/MEM.cpp" +#include "remill/Arch/AArch32/Semantics/LOGICAL.cpp" //#include "remill/Arch/AArch64/Semantics/BITBYTE.cpp" //#include "remill/Arch/AArch64/Semantics/BRANCH.cpp" //#include "remill/Arch/AArch64/Semantics/CALL_RET.cpp" //#include "remill/Arch/AArch64/Semantics/COND.cpp" //#include "remill/Arch/AArch64/Semantics/CONVERT.cpp" //#include "remill/Arch/AArch64/Semantics/DATAXFER.cpp" -//#include "remill/Arch/AArch64/Semantics/LOGICAL.cpp" //#include "remill/Arch/AArch64/Semantics/MISC.cpp" //#include "remill/Arch/AArch64/Semantics/SHIFT.cpp" //#include "remill/Arch/AArch64/Semantics/SIMD.cpp" diff --git a/remill/Arch/AArch32/Semantics/LOGICAL.cpp b/remill/Arch/AArch32/Semantics/LOGICAL.cpp new file mode 100644 index 000000000..6df45f74d --- /dev/null +++ b/remill/Arch/AArch32/Semantics/LOGICAL.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { + +DEF_SEM(ORR, R32W dst, R32 src1, I32 src2, I32 src2_rrx){ + auto value = UOr(Read(src2), Read(src2_rrx)); + auto result = UOr(Read(src1), value); + Write(dst, value); + return memory; +} + +DEF_SEM(ORRS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto value = UOr(Read(src2), Read(src2_rrx)); + auto result = UOr(Read(src1), value); + Write(dst, value); + + state.sr.n = SignFlag(value); + state.sr.z = ZeroFlag(value); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(MOV, R32W dst, I32 src, I32 src_rrx){ + auto value = UOr(Read(src), Read(src_rrx)); + Write(dst, value); + return memory; +} + +DEF_SEM(MOVS, R32W dst, I32 src, I32 src_rrx, I8 carry_out) { + auto value = UOr(Read(src), Read(src_rrx)); + Write(dst, value); + + state.sr.n = SignFlag(value); + state.sr.z = ZeroFlag(value); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(BIC, R32W dst, R32 src1, I32 src2, I32 src2_rrx){ + auto value = UNot(UOr(Read(src2), Read(src2_rrx))); + auto result = UAnd(Read(src1), value); + Write(dst, value); + return memory; +} + +DEF_SEM(BICS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto value = UNot(UOr(Read(src2), Read(src2_rrx))); + auto result = UAnd(Read(src1), value); + Write(dst, value); + + state.sr.n = SignFlag(value); + state.sr.z = ZeroFlag(value); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(MVN, R32W dst, I32 src, I32 src_rrx){ + auto value = UNot(UOr(Read(src), Read(src_rrx))); + Write(dst, value); + return memory; +} + +DEF_SEM(MVNS, R32W dst, I32 src, I32 src_rrx, I8 carry_out) { + auto value = UNot(UOr(Read(src), Read(src_rrx))); + Write(dst, value); + + state.sr.n = SignFlag(value); + state.sr.z = ZeroFlag(value); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +} // namespace + +DEF_ISEL(ORRrrri) = ORR; +DEF_ISEL(ORRSrrri) = ORRS; +DEF_ISEL(MOVrrri) = MOV; +DEF_ISEL(MOVSrrri) = MOVS; +DEF_ISEL(BICrrri) = BIC; +DEF_ISEL(BICSrrri) = BICS; +DEF_ISEL(MVNrrri) = MVN; +DEF_ISEL(MVNSrrri) = MVNS; + From 65af9f890caa00908f477a334d2f601bd16ea135 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 8 Oct 2020 18:44:55 -0400 Subject: [PATCH 020/130] Made DecodeA32ExpandImm much much smaller --- remill/Arch/AArch32/Decode.cpp | 103 ++++++++++++++------------------- 1 file changed, 45 insertions(+), 58 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index b4340656a..eaa236644 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -161,62 +161,6 @@ static const char * const kIntRegName[] = { typedef bool (*const TryDecode)(Instruction&, uint32_t); typedef bool (*const TryDecodeList[])(Instruction&, uint32_t); -static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out) { - uint32_t unrotated_value = imm12 & (0b11111111u); - uint32_t rotation_amount = ((imm12 >> 8) & (0b1111u)) *2u; - auto num_ops = inst.operands.size(); - inst.operands.emplace_back(); - inst.operands.emplace_back(); - inst.operands.emplace_back(); - auto &op0 = inst.operands[num_ops]; - auto &op1 = inst.operands[num_ops + 1]; - auto &op2 = inst.operands[num_ops + 2]; - - op0.imm.is_signed = false; - op0.size = 32; - op0.action = Operand::kActionRead; - op0.type = Operand::kTypeImmediate; - - if (!rotation_amount) { - op0.imm.val = unrotated_value; - } else { - op0.imm.val = __builtin_rotateright32(unrotated_value, rotation_amount); - } - - // This is the 2nd part of RRX so we can reuse the same semantics - op1.imm.is_signed = false; - op1.imm.val = 0; - op1.size = 32; - op1.action = Operand::kActionRead; - op1.type = Operand::kTypeImmediate; - - if (!rotation_amount) { - op2.shift_reg.extract_size = 1; - op2.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; - - op2.shift_reg.shift_size = 0; - op2.type = Operand::kTypeShiftRegister; - op2.size = 32; - op2.action = Operand::kActionRead; - - op2.shift_reg.reg.name = "C"; - op2.shift_reg.reg.size = 8; - op2.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; - op2.shift_reg.shift_size = 0; - } else { - op2.imm.val = (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u; - op2.size = 32; - op2.imm.is_signed = false; - op2.action = Operand::kActionRead; - op2.type = Operand::kTypeImmediate; - } - - if (!carry_out) { - inst.operands.pop_back(); - } - -} - static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, Operand::Action action) { inst.operands.emplace_back(); @@ -273,8 +217,49 @@ static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { return Operand::ShiftRegister::kShiftInvalid; } +static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out) { + uint32_t unrotated_value = imm12 & (0b11111111u); + uint32_t rotation_amount = ((imm12 >> 8) & (0b1111u)) *2u; + + if (!rotation_amount) { + AddImmOp(inst, unrotated_value); + } else { + AddImmOp(inst, __builtin_rotateright32(unrotated_value, rotation_amount)); + } + + AddImmOp(inst, 0); + + if (carry_out) { + inst.operands.emplace_back(); + auto &op2 = inst.operands.back(); + if (!rotation_amount) { + op2.shift_reg.extract_size = 1; + op2.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; + + op2.shift_reg.shift_size = 0; + op2.type = Operand::kTypeShiftRegister; + op2.size = 32; + op2.action = Operand::kActionRead; + + op2.shift_reg.reg.name = "C"; + op2.shift_reg.reg.size = 8; + op2.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; + op2.shift_reg.shift_size = 0; + } else { + op2.imm.val = (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u; + op2.size = 32; + op2.imm.is_signed = false; + op2.action = Operand::kActionRead; + op2.type = Operand::kTypeImmediate; + } + } + +} -// Used to handle (shift_t, shift_n) = DecodeImmShift(type, imm5) semantics +// This function should be used with AddShiftCarryOperand to add carry_out operand! +// Used to handle semantics for: +// (shifted, carry) = Shift_C(R[m], shift_t, shift_n, PSTATE.C); +// (shift_t, shift_n) = DecodeImmShift(type, imm5); // See an instruction in Integer Data Processing (three register, immediate shift) set for an example static void AddShiftRegOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, @@ -336,7 +321,9 @@ static void AddShiftRegOperand(Instruction &inst, } -// (shift_t, shift_n) = DecodeImmShift(type, imm5) +// PLEASE SEE AddShiftRegOperand! +// This function extracts the carry_out that from the semantics that +// AddShiftRegOperand handles static void AddShiftCarryOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_size, const char * carry_reg_name) { From 25f4e50bf98b5b1aabfb4f2e881d1d77174483d9 Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 9 Oct 2020 10:17:08 -0400 Subject: [PATCH 021/130] Replaced some imm ops with AddImmOp calls --- remill/Arch/AArch32/Decode.cpp | 48 +++++++++++++++------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index eaa236644..50ba28341 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -158,6 +158,7 @@ static const char * const kIntRegName[] = { "R14", "R15" }; + typedef bool (*const TryDecode)(Instruction&, uint32_t); typedef bool (*const TryDecodeList[])(Instruction&, uint32_t); @@ -230,33 +231,30 @@ static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out AddImmOp(inst, 0); if (carry_out) { - inst.operands.emplace_back(); - auto &op2 = inst.operands.back(); if (!rotation_amount) { - op2.shift_reg.extract_size = 1; - op2.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; - - op2.shift_reg.shift_size = 0; - op2.type = Operand::kTypeShiftRegister; - op2.size = 32; - op2.action = Operand::kActionRead; - - op2.shift_reg.reg.name = "C"; - op2.shift_reg.reg.size = 8; - op2.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; - op2.shift_reg.shift_size = 0; + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.shift_reg.extract_size = 1; + op.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; + op.shift_reg.shift_size = 0; + op.type = Operand::kTypeShiftRegister; + op.size = 32; + op.action = Operand::kActionRead; + op.shift_reg.reg.name = "C"; + op.shift_reg.reg.size = 8; + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; + op.shift_reg.shift_size = 0; } else { - op2.imm.val = (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u; - op2.size = 32; - op2.imm.is_signed = false; - op2.action = Operand::kActionRead; - op2.type = Operand::kTypeImmediate; + AddImmOp(inst, (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u); } } } -// This function should be used with AddShiftCarryOperand to add carry_out operand! +// Note: This function should be used with AddShiftCarryOperand to add carry_out operand! +// This function adds 2 operands in total - an op and an op_rrx which should be +// ORed together when implementing Semantics + // Used to handle semantics for: // (shifted, carry) = Shift_C(R[m], shift_t, shift_n, PSTATE.C); // (shift_t, shift_n) = DecodeImmShift(type, imm5); @@ -299,9 +297,9 @@ static void AddShiftRegOperand(Instruction &inst, // together. No single operand type in remill is flexible enough to handle this. // So we make 2 operands and OR those two operands together. In most cases // when rrx isn't used we OR something with 0. - inst.operands.emplace_back(); - auto &op = inst.operands.back(); if (is_rrx) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); op.shift_reg.reg.name = "C"; op.shift_reg.reg.size = 8; @@ -312,11 +310,7 @@ static void AddShiftRegOperand(Instruction &inst, op.size = 32; op.action = Operand::kActionRead; } else { - op.imm.is_signed = false; - op.imm.val = 0; - op.size = 32; - op.action = Operand::kActionRead; - op.type = Operand::kTypeImmediate; + AddImmOp(inst, 0); } } From 14a7f06f14df59971a1d1ca6e319ef450cf389af Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 9 Oct 2020 17:37:42 -0400 Subject: [PATCH 022/130] Created AddShiftOp --- remill/Arch/AArch32/Decode.cpp | 194 +++++++++++++++++---------------- 1 file changed, 100 insertions(+), 94 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 50ba28341..97dac48bb 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -199,6 +199,25 @@ static void AddAddrRegOp(Instruction &inst, const char * reg_name, unsigned mem_ op.addr.displacement = disp; } +static void AddShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, + Operand::ShiftRegister::Extend extend_op, const char * reg_name, + unsigned reg_size, unsigned shift_size, unsigned extract_size, + Operand::Action action = Operand::kActionRead, unsigned size = 32) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.shift_reg.extract_size = extract_size; + op.shift_reg.extend_op = extend_op; + op.shift_reg.shift_size = shift_size; + op.type = Operand::kTypeShiftRegister; + op.size = size; + op.action = action; + op.shift_reg.reg.name = reg_name; + op.shift_reg.reg.size = reg_size; + op.shift_reg.shift_op = shift_op; + op.shift_reg.shift_size = shift_size; +} + + // Note: Order is significant; extracted bits may be casted to this type. enum Shift : uint32_t { kShiftLSL, kShiftLSR, kShiftASR, kShiftROR }; @@ -232,18 +251,7 @@ static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out if (carry_out) { if (!rotation_amount) { - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.shift_reg.extract_size = 1; - op.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; - op.shift_reg.shift_size = 0; - op.type = Operand::kTypeShiftRegister; - op.size = 32; - op.action = Operand::kActionRead; - op.shift_reg.reg.name = "C"; - op.shift_reg.reg.size = 8; - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; - op.shift_reg.shift_size = 0; + AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, "C", 8, 0, 1); } else { AddImmOp(inst, (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u); } @@ -275,22 +283,11 @@ static void AddShiftRegOperand(Instruction &inst, if (!shift_size) { AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); } else { - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.shift_reg.reg.name = kIntRegName[reg_num]; - op.shift_reg.reg.size = 32; - if (is_rrx) { - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; - op.shift_reg.shift_size = 1; + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendInvalid, kIntRegName[reg_num], 32, 1, 0); } else { - op.shift_reg.shift_op = GetOperandShift(static_cast(shift_type)); - op.shift_reg.shift_size = shift_size; + AddShiftOp(inst, GetOperandShift(static_cast(shift_type)), Operand::ShiftRegister::kExtendInvalid, kIntRegName[reg_num], 32, shift_size, 0); } - - op.type = Operand::kTypeShiftRegister; - op.size = 32; - op.action = Operand::kActionRead; } // To handle rrx we need to take two components shift each and OR the results @@ -298,17 +295,7 @@ static void AddShiftRegOperand(Instruction &inst, // So we make 2 operands and OR those two operands together. In most cases // when rrx isn't used we OR something with 0. if (is_rrx) { - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.shift_reg.reg.name = "C"; - op.shift_reg.reg.size = 8; - - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; - op.shift_reg.shift_size = 31; - - op.type = Operand::kTypeShiftRegister; - op.size = 32; - op.action = Operand::kActionRead; + AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendInvalid, "C", 8, 31, 0); } else { AddImmOp(inst, 0); } @@ -321,15 +308,6 @@ static void AddShiftRegOperand(Instruction &inst, static void AddShiftCarryOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_size, const char * carry_reg_name) { - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.shift_reg.extract_size = 1; - op.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; - - op.shift_reg.shift_size = shift_size; - op.type = Operand::kTypeShiftRegister; - op.size = 32; - op.action = Operand::kActionRead; auto is_rrx = false; if (!shift_size && shift_type == Shift::kShiftROR) { @@ -338,33 +316,23 @@ static void AddShiftCarryOperand(Instruction &inst, } if (!shift_size) { - op.shift_reg.reg.name = carry_reg_name; - op.shift_reg.reg.size = 8; - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; - op.shift_reg.shift_size = 0; + AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, carry_reg_name, 8, 0, 1); } else { - op.shift_reg.reg.name = kIntRegName[reg_num]; - op.shift_reg.reg.size = 32; switch (static_cast(shift_type)) { case Shift::kShiftASR: - op.shift_reg.shift_size = shift_size - 1; - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftSignedRight; + AddShiftOp(inst, Operand::ShiftRegister::kShiftSignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); break; case Shift::kShiftLSL: - op.shift_reg.shift_size = 32 - shift_size; - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 32 - shift_size, 1); break; case Shift::kShiftLSR: - op.shift_reg.shift_size = shift_size - 1; - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); break; case Shift::kShiftROR: if (is_rrx) { - op.shift_reg.shift_size = 0; - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 0, 1); } else { - op.shift_reg.shift_size = (shift_size + 31u) % 32u; - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, (shift_size + 31u) % 32u, 1); } break; } @@ -830,40 +798,63 @@ static TryDecodeList kLoadStoreWordUBIL = { }; // Corresponds to: Data-processing and miscellaneous instructions -//op0 op1 op2 op3 op4 -//0 1 != 00 1 Extra load/store -//0 0xxxx 1 00 1 Multiply and Accumulate -//0 1xxxx 1 00 1 Synchronization primitives and Load-Acquire/Store-Release -//0 10xx0 0 Miscellaneous -//0 10xx0 1 0 Halfword Multiply and Accumulate -//0 != 10xx0 0 Data-processing register (immediate shift) -//0 != 10xx0 0 1 Data-processing register (register shift) -//1 Data-processing immediate +//op0 op1 op2 op3 op4 +// 0 1 != 00 1 Extra load/store +// 0 0xxxx 1 00 1 Multiply and Accumulate +// 0 1xxxx 1 00 1 Synchronization primitives and Load-Acquire/Store-Release +// 0 10xx0 0 Miscellaneous +// 0 10xx0 1 0 Halfword Multiply and Accumulate +// 0 != 10xx0 0 Data-processing register (immediate shift) +// 0 != 10xx0 0 1 Data-processing register (register shift) +// 1 Data-processing immediate static TryDecode TryDataProcessingAndMisc(uint32_t bits) { const DataProcessingAndMisc enc = { bits }; - // op0 == 0 if (!enc.op0) { - // Multiply and Accumulate - if ((!(enc.op1 >> 4)) && enc.op2 && (enc.op3 == 0b00u) && enc.op4) { - return TryDecodeMultiplyAndAccumulate; + // op2 == 1, op4 == 1 + if (enc.op2 && enc.op4) { + // TODO(Sonya): Extra load/store -- op3 != 00 + if (!enc.op3) { + return nullptr; + } + // op3 == 00 + else { + // Multiply and Accumulate -- op1 == 0xxxx + if (!(enc.op1 >> 4)) { + return TryDecodeMultiplyAndAccumulate; + } + // TODO(Sonya): Synchronization primitives and Load-Acquire/Store-Release -- op1 == 1xxxx + else { + return nullptr; + } + } } - // Data-processing register (immediate shift) - else if (!(((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) && !enc.op4) { - // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 lowest bit - // index is the concatenation of op0 and op1 - return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; - } else { - // TODO(Sonya): Extra load/store - // TODO(Sonya): Synchronization primitives and Load-Acquire/Store-Release + // op1 == 10xx0 + else if (((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) { // TODO(Sonya): Miscellaneous + if (!enc.op2) { + return nullptr; + } // TODO(Sonya): Halfword Multiply and Accumulate - // TODO(Sonya): Data-processing register (register shift) - return nullptr; + else { + return nullptr; + } + } + // op1 != 10xx0 + else { + // Data-processing register (immediate shift) -- op4 == 0 + if (!enc.op4) { + // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 lowest bit + // index is the concatenation of op0 and op1 + return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; + } + // TODO(Sonya): Data-processing register (register shift) -- op4 == 1 + else { + return nullptr; + } } } - // op0 == 1 - // Data-processing immediate + // Data-processing immediate -- op0 == 1 else { // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 2 lowest bits // index is the concatenation of op0 and op1 @@ -895,21 +886,36 @@ static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { else if (enc.op0 == 0b010u) { const LoadStoreWUBIL enc_ls_word = { bits }; return kLoadStoreWordUBIL[enc_ls_word.o2 << 1u | enc_ls_word.o1]; - } else { - // TODO(Sonya): Load/Store Word, Unsigned Byte (register) -- op0 == 011, op1 == 0 - // TODO(Sonya): Media instructions -- op0 == 011, op1 == 1 + } + // TODO(Sonya): Load/Store Word, Unsigned Byte (register) -- op0 == 011, op1 == 0 + else if (!enc.op1) { + // This should be returning another table index using a struct like above return nullptr; } - } else { - // TODO(Sonya): Unconditional instructions -- cond == 1111 + // TODO(Sonya): Media instructions -- op0 == 011, op1 == 1 + else { + // return a result from another function for instruction categorizing + return nullptr; + } + } + // TODO(Sonya): Unconditional instructions -- cond == 1111 + else { + // return a result from another function for instruction categorizing return nullptr; } } // op0 == 1xx else { - // TODO(Sonya): Branch, branch with link, and block data transfer - // TODO(Sonya): System register access, Advanced SIMD, floating-point, and Supervisor call - return nullptr; + // TODO(Sonya): Branch, branch with link, and block data transfer -- op0 == 10x + if (enc.op0 >> 1 == 0b10u) { + // return a result from another function for instruction categorizing + return nullptr; + } + // TODO(Sonya): System register access, Advanced SIMD, floating-point, and Supervisor call -- op0 == 11x + else { + // return a result from another function for instruction categorizing + return nullptr; + } } } From 26e6dbc59d63dcf80671c9ba905dd2dc770eaee1 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 13 Oct 2020 17:19:41 -0400 Subject: [PATCH 023/130] Added interpreter for evaluating new PC value at decoding time to handle direct jumps and conditional jumps --- remill/Arch/AArch32/Decode.cpp | 193 ++++++++++++++++++++++++++++++++- remill/Arch/Instruction.cpp | 91 +++++++++++----- remill/Arch/Instruction.h | 5 +- remill/BC/Lifter.cpp | 172 +++++++++++++++-------------- 4 files changed, 348 insertions(+), 113 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 97dac48bb..2f9d3e0ca 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -202,7 +202,8 @@ static void AddAddrRegOp(Instruction &inst, const char * reg_name, unsigned mem_ static void AddShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, Operand::ShiftRegister::Extend extend_op, const char * reg_name, unsigned reg_size, unsigned shift_size, unsigned extract_size, - Operand::Action action = Operand::kActionRead, unsigned size = 32) { + Operand::Action action = Operand::kActionRead, unsigned size = 32, + bool shift_first = false) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.shift_reg.extract_size = extract_size; @@ -215,6 +216,7 @@ static void AddShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op op.shift_reg.reg.size = reg_size; op.shift_reg.shift_op = shift_op; op.shift_reg.shift_size = shift_size; + op.shift_reg.shift_first = shift_first; } @@ -436,6 +438,145 @@ static void DecodeCondition(Instruction &inst, uint32_t cond) { } } +std::optional EvalReg(const Instruction &inst, const Operand::Register &op) { + if (op.name == kIntRegName[kPCRegNum] || op.name == "PC") { + return inst.pc; + } else if (op.name == "NEXT_PC") { + return inst.next_pc; + } else if (op.name.empty()) { + return 0u; + } else { + return std::nullopt; + } +} + +std::optional EvalShift(const Operand::ShiftRegister &op, + std::optional maybe_val) { + if (!maybe_val || !op.shift_size) { + return maybe_val; + } + + if (op.reg.size != 32) { + return std::nullopt; + } + + auto val = static_cast(*maybe_val); + + switch (op.shift_op) { + case Operand::ShiftRegister::kShiftInvalid: + return maybe_val; + case Operand::ShiftRegister::kShiftLeftAround: + return __builtin_rotateleft32(val, static_cast(op.shift_size)); + case Operand::ShiftRegister::kShiftRightAround: + return __builtin_rotateright32(val, static_cast(op.shift_size)); + case Operand::ShiftRegister::kShiftLeftWithOnes: + return (val << op.shift_size) | ~(~0u << op.shift_size); + case Operand::ShiftRegister::kShiftLeftWithZeroes: + return val << op.shift_size; + case Operand::ShiftRegister::kShiftUnsignedRight: + return val >> op.shift_size; + case Operand::ShiftRegister::kShiftSignedRight: + return static_cast(static_cast(val) >> op.shift_size); + } +} + +std::optional EvalExtract(const Operand::ShiftRegister &op, + std::optional maybe_val) { + if (!maybe_val || !op.extract_size) { + return maybe_val; + } + + if (op.reg.size != 32) { + return std::nullopt; + } + + auto val = static_cast(*maybe_val); + + switch (op.extend_op) { + case Operand::ShiftRegister::kExtendInvalid: + return maybe_val; + case Operand::ShiftRegister::kExtendSigned: + { + val &= (1u << (op.extract_size)) - 1u; + auto sign = val >> (op.extract_size - 1u); + + if (sign) { + val |= ~0u << op.extract_size; + } + + return val; + } + case Operand::ShiftRegister::kExtendUnsigned: + return val & ((1u << (op.extract_size)) - 1u); + } + + +} + +std::optional EvalOperand(const Instruction &inst, const Operand &op) { + switch(op.type) { + case Operand::kTypeInvalid: + return std::nullopt; + case Operand::kTypeImmediate: + return op.imm.val; + case Operand::kTypeRegister: + return EvalReg(inst, op.reg); + case Operand::kTypeAddress: + { + auto seg_val = EvalReg(inst, op.addr.segment_base_reg); + auto base_val = EvalReg(inst, op.addr.base_reg); + auto index_val = EvalReg(inst, op.addr.index_reg); + + if (!seg_val || !base_val || !index_val) { + return std::nullopt; + } + + return static_cast( + static_cast(*seg_val) + static_cast(*base_val) + + (static_cast(*index_val) * op.addr.scale) + + op.addr.displacement); + + } + case Operand::kTypeShiftRegister: + if (op.shift_reg.shift_first) { + return EvalExtract(op.shift_reg, EvalShift(op.shift_reg, EvalReg(inst, op.shift_reg.reg))); + } else { + return EvalShift(op.shift_reg, EvalExtract(op.shift_reg, EvalReg(inst, op.shift_reg.reg))); + } + } + +} + +typedef std::optional (InstEval)(uint32_t, uint32_t, uint32_t); + +// High 3 bit opc +static InstEval * kIdpEvaluatorsRRR[] = { + [0b000] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(src1 & (src2 | src2_rrx)); + }, + [0b001] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(src1 ^ (src2 | src2_rrx)); + }, + [0b010] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(src1 - (src2 | src2_rrx)); + }, + [0b011] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional((src2 | src2_rrx) - src1); + }, + [0b100] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional((src2 | src2_rrx) + src1); + }, + [0b101] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(std::nullopt); + }, + [0b110] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(std::nullopt); + }, + [0b111] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(std::nullopt); + }, +}; + // High 3 bit opc and low bit s, opc:s static const char * const kIdpNamesRRR[] = { [0b0000] = "ANDrr", @@ -488,7 +629,26 @@ static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) inst.category = Instruction::kCategoryError; return false; } else { - inst.category = Instruction::kCategoryIndirectJump; + auto src1 = EvalOperand(inst, inst.operands[1]); + auto src2 = EvalOperand(inst, inst.operands[2]); + auto src2_rrx = EvalOperand(inst, inst.operands[3]); + + if (!src1 || !src2 || !src2_rrx) { + inst.category = Instruction::kCategoryIndirectJump; + } else { + auto res = kIdpEvaluatorsRRR[enc.opc](*src1, *src2, *src2_rrx); + + if (!res) { + inst.category = Instruction::kCategoryIndirectJump; + } else if (!inst.conditions.empty()) { + inst.branch_taken_pc = static_cast(*res); + inst.branch_not_taken_pc = inst.next_pc; + inst.category = Instruction::kCategoryConditionalBranch; + } else { + inst.branch_taken_pc = static_cast(*res); + inst.category = Instruction::kCategoryDirectJump; + } + } } } else { inst.category = Instruction::kCategoryNormal; @@ -535,7 +695,34 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) inst.category = Instruction::kCategoryError; return false; } else { - inst.category = Instruction::kCategoryIndirectJump; + auto src1 = EvalOperand(inst, inst.operands[1]); + auto src2 = EvalOperand(inst, inst.operands[2]); + auto src2_rrx = EvalOperand(inst, inst.operands[3]); + + if (!src1 || !src2 || !src2_rrx) { + inst.category = Instruction::kCategoryIndirectJump; + } else { + auto src1 = EvalOperand(inst, inst.operands[1]); + auto src2 = EvalOperand(inst, inst.operands[2]); + auto src2_rrx = EvalOperand(inst, inst.operands[3]); + + if (!src1 || !src2 || !src2_rrx) { + inst.category = Instruction::kCategoryIndirectJump; + } else { + auto res = kIdpEvaluatorsRRR[enc.opc](*src1, *src2, *src2_rrx); + + if (!res) { + inst.category = Instruction::kCategoryIndirectJump; + } else if (!inst.conditions.empty()) { + inst.branch_taken_pc = static_cast(*res); + inst.branch_not_taken_pc = inst.next_pc; + inst.category = Instruction::kCategoryConditionalBranch; + } else { + inst.branch_taken_pc = static_cast(*res); + inst.category = Instruction::kCategoryDirectJump; + } + } + } } } else { inst.category = Instruction::kCategoryNormal; diff --git a/remill/Arch/Instruction.cpp b/remill/Arch/Instruction.cpp index d881365a0..7060c1520 100644 --- a/remill/Arch/Instruction.cpp +++ b/remill/Arch/Instruction.cpp @@ -31,6 +31,7 @@ Operand::Register::Register(void) : size(0) {} Operand::ShiftRegister::ShiftRegister(void) : shift_size(0), extract_size(0), + shift_first(false), shift_op(Operand::ShiftRegister::kShiftInvalid), extend_op(Operand::ShiftRegister::kExtendInvalid) {} @@ -72,49 +73,83 @@ std::string Operand::Serialize(void) const { ss << "(REG_" << reg.size << " " << reg.name << ")"; break; - case Operand::kTypeShiftRegister: + case Operand::kTypeShiftRegister: { + auto shift_begin = [&](void) { + switch (shift_reg.shift_op) { + case Operand::ShiftRegister::kShiftInvalid: break; - switch (shift_reg.shift_op) { - case Operand::ShiftRegister::kShiftInvalid: break; + case Operand::ShiftRegister::kShiftLeftWithZeroes: ss << "(LSL "; break; - case Operand::ShiftRegister::kShiftLeftWithZeroes: ss << "(LSL "; break; + case Operand::ShiftRegister::kShiftLeftWithOnes: ss << "(MSL "; break; - case Operand::ShiftRegister::kShiftLeftWithOnes: ss << "(MSL "; break; + case Operand::ShiftRegister::kShiftUnsignedRight: ss << "(LSR "; break; - case Operand::ShiftRegister::kShiftUnsignedRight: ss << "(LSR "; break; + case Operand::ShiftRegister::kShiftSignedRight: ss << "(ASR "; break; - case Operand::ShiftRegister::kShiftSignedRight: ss << "(ASR "; break; + case Operand::ShiftRegister::kShiftLeftAround: ss << "(ROL "; break; - case Operand::ShiftRegister::kShiftLeftAround: ss << "(ROL "; break; + case Operand::ShiftRegister::kShiftRightAround: ss << "(ROR "; break; + } + }; - case Operand::ShiftRegister::kShiftRightAround: ss << "(ROR "; break; - } + auto shift_end = [&](void) { + if (Operand::ShiftRegister::kShiftInvalid != shift_reg.shift_op) { + ss << " " << shift_reg.shift_size << ")"; + } + }; - switch (shift_reg.extend_op) { - case Operand::ShiftRegister::kExtendInvalid: - ss << "(REG_" << shift_reg.reg.size << " " << shift_reg.reg.name - << ")"; - break; + auto extract_begin = [&](void) { + switch (shift_reg.extend_op) { + case Operand::ShiftRegister::kExtendInvalid: + break; - case Operand::ShiftRegister::kExtendSigned: - ss << "(SEXT (TRUNC (REG_" << shift_reg.reg.size << " " - << shift_reg.reg.name << ") " << shift_reg.extract_size << ") " - << size << ")"; - break; + case Operand::ShiftRegister::kExtendSigned: + ss << "(SEXT (TRUNC "; + break; - case Operand::ShiftRegister::kExtendUnsigned: - ss << "(ZEXT (TRUNC (REG_" << shift_reg.reg.size << " " - << shift_reg.reg.name << ") " << shift_reg.extract_size << ") " - << size << ")"; - break; + case Operand::ShiftRegister::kExtendUnsigned: + ss << "(ZEXT (TRUNC "; + break; + } + }; + + auto extract_end = [&](void) { + switch (shift_reg.extend_op) { + case Operand::ShiftRegister::kExtendInvalid: + break; + + case Operand::ShiftRegister::kExtendSigned: + ss << " " << shift_reg.extract_size << ") " + << size << ")"; + break; + + case Operand::ShiftRegister::kExtendUnsigned: + ss << " " << shift_reg.extract_size << ") " + << size << ")"; + break; + } + }; + + if (shift_reg.shift_first) { + extract_begin(); + shift_begin(); + } else { + shift_begin(); + extract_begin(); } - if (Operand::ShiftRegister::kShiftInvalid != shift_reg.shift_op) { - ss << " " << shift_reg.shift_size << ")"; + ss << "(REG_" << shift_reg.reg.size << " " << shift_reg.reg.name << ")"; + + if (shift_reg.shift_first) { + shift_end(); + extract_end(); + } else { + extract_end(); + shift_end(); } break; - + } case Operand::kTypeImmediate: ss << "("; if (imm.is_signed) { diff --git a/remill/Arch/Instruction.h b/remill/Arch/Instruction.h index 290430d74..30cace255 100644 --- a/remill/Arch/Instruction.h +++ b/remill/Arch/Instruction.h @@ -61,8 +61,9 @@ class Operand { Register reg; uint64_t shift_size; uint64_t extract_size; + bool shift_first; - enum Shift : unsigned { + enum Shift : uint8_t { kShiftInvalid, kShiftLeftWithZeroes, // Shift left, filling low order bits with zero. kShiftLeftWithOnes, // Shift left, filling low order bits with one. @@ -72,7 +73,7 @@ class Operand { kShiftRightAround // Rotate right. } shift_op; - enum Extend : unsigned { + enum Extend : uint8_t { kExtendInvalid, kExtendUnsigned, kExtendSigned, diff --git a/remill/BC/Lifter.cpp b/remill/BC/Lifter.cpp index 34b88fd8f..6ace13c57 100644 --- a/remill/BC/Lifter.cpp +++ b/remill/BC/Lifter.cpp @@ -365,102 +365,114 @@ llvm::Value *InstructionLifter::LiftShiftRegisterOperand( llvm::IRBuilder<> ir(block); auto curr_size = reg_size; - if (Operand::ShiftRegister::kExtendInvalid != op.shift_reg.extend_op) { + auto extract_and_extend = [&](void) { + if (Operand::ShiftRegister::kExtendInvalid != op.shift_reg.extend_op) { + + auto extract_type = + llvm::Type::getIntNTy(context, op.shift_reg.extract_size); + + if (reg_size > op.shift_reg.extract_size) { + curr_size = op.shift_reg.extract_size; + reg = ir.CreateTrunc(reg, extract_type); + + } else { + CHECK(reg_size == op.shift_reg.extract_size) + << "Invalid extraction size. Can't extract " + << op.shift_reg.extract_size << " bits from a " << reg_size + << "-bit value in operand " << op.Serialize() << " of instruction at " + << std::hex << inst.pc; + } - auto extract_type = - llvm::Type::getIntNTy(context, op.shift_reg.extract_size); + if (op.size > op.shift_reg.extract_size) { + switch (op.shift_reg.extend_op) { + case Operand::ShiftRegister::kExtendSigned: + reg = ir.CreateSExt(reg, op_type); + curr_size = op.size; + break; + case Operand::ShiftRegister::kExtendUnsigned: + reg = ir.CreateZExt(reg, op_type); + curr_size = op.size; + break; + default: + LOG(FATAL) << "Invalid extend operation type for instruction at " + << std::hex << inst.pc; + break; + } + } + } - if (reg_size > op.shift_reg.extract_size) { - curr_size = op.shift_reg.extract_size; - reg = ir.CreateTrunc(reg, extract_type); + CHECK(curr_size <= op.size); - } else { - CHECK(reg_size == op.shift_reg.extract_size) - << "Invalid extraction size. Can't extract " - << op.shift_reg.extract_size << " bits from a " << reg_size - << "-bit value in operand " << op.Serialize() << " of instruction at " - << std::hex << inst.pc; + if (curr_size < op.size) { + reg = ir.CreateZExt(reg, op_type); + curr_size = op.size; } + }; - if (op.size > op.shift_reg.extract_size) { - switch (op.shift_reg.extend_op) { - case Operand::ShiftRegister::kExtendSigned: - reg = ir.CreateSExt(reg, op_type); - curr_size = op.size; - break; - case Operand::ShiftRegister::kExtendUnsigned: - reg = ir.CreateZExt(reg, op_type); - curr_size = op.size; - break; - default: - LOG(FATAL) << "Invalid extend operation type for instruction at " - << std::hex << inst.pc; - break; - } - } - } + auto shift = [&](void) { + if (Operand::ShiftRegister::kShiftInvalid != op.shift_reg.shift_op) { - CHECK(curr_size <= op.size); + CHECK(shift_size < op.size) + << "Shift of size " << shift_size + << " is wider than the base register size in shift register in " + << inst.Serialize(); - if (curr_size < op.size) { - reg = ir.CreateZExt(reg, op_type); - curr_size = op.size; - } + switch (op.shift_reg.shift_op) { - if (Operand::ShiftRegister::kShiftInvalid != op.shift_reg.shift_op) { + // Left shift. + case Operand::ShiftRegister::kShiftLeftWithZeroes: + reg = ir.CreateShl(reg, shift_val); + break; - CHECK(shift_size < op.size) - << "Shift of size " << shift_size - << " is wider than the base register size in shift register in " - << inst.Serialize(); + // Masking shift left. + case Operand::ShiftRegister::kShiftLeftWithOnes: { + const auto mask_val = + llvm::ConstantInt::get(reg_type, ~((~zero) << shift_size)); + reg = ir.CreateOr(ir.CreateShl(reg, shift_val), mask_val); + break; + } - switch (op.shift_reg.shift_op) { + // Logical right shift. + case Operand::ShiftRegister::kShiftUnsignedRight: + reg = ir.CreateLShr(reg, shift_val); + break; - // Left shift. - case Operand::ShiftRegister::kShiftLeftWithZeroes: - reg = ir.CreateShl(reg, shift_val); - break; + // Arithmetic right shift. + case Operand::ShiftRegister::kShiftSignedRight: + reg = ir.CreateAShr(reg, shift_val); + break; - // Masking shift left. - case Operand::ShiftRegister::kShiftLeftWithOnes: { - const auto mask_val = - llvm::ConstantInt::get(reg_type, ~((~zero) << shift_size)); - reg = ir.CreateOr(ir.CreateShl(reg, shift_val), mask_val); - break; - } + // Rotate left. + case Operand::ShiftRegister::kShiftLeftAround: { + const uint64_t shr_amount = (~shift_size + one) & (op.size - one); + const auto shr_val = llvm::ConstantInt::get(op_type, shr_amount); + const auto val1 = ir.CreateLShr(reg, shr_val); + const auto val2 = ir.CreateShl(reg, shift_val); + reg = ir.CreateOr(val1, val2); + break; + } - // Logical right shift. - case Operand::ShiftRegister::kShiftUnsignedRight: - reg = ir.CreateLShr(reg, shift_val); - break; - - // Arithmetic right shift. - case Operand::ShiftRegister::kShiftSignedRight: - reg = ir.CreateAShr(reg, shift_val); - break; - - // Rotate left. - case Operand::ShiftRegister::kShiftLeftAround: { - const uint64_t shr_amount = (~shift_size + one) & (op.size - one); - const auto shr_val = llvm::ConstantInt::get(op_type, shr_amount); - const auto val1 = ir.CreateLShr(reg, shr_val); - const auto val2 = ir.CreateShl(reg, shift_val); - reg = ir.CreateOr(val1, val2); - break; - } + // Rotate right. + case Operand::ShiftRegister::kShiftRightAround: { + const uint64_t shl_amount = (~shift_size + one) & (op.size - one); + const auto shl_val = llvm::ConstantInt::get(op_type, shl_amount); + const auto val1 = ir.CreateLShr(reg, shift_val); + const auto val2 = ir.CreateShl(reg, shl_val); + reg = ir.CreateOr(val1, val2); + break; + } - // Rotate right. - case Operand::ShiftRegister::kShiftRightAround: { - const uint64_t shl_amount = (~shift_size + one) & (op.size - one); - const auto shl_val = llvm::ConstantInt::get(op_type, shl_amount); - const auto val1 = ir.CreateLShr(reg, shift_val); - const auto val2 = ir.CreateShl(reg, shl_val); - reg = ir.CreateOr(val1, val2); - break; + case Operand::ShiftRegister::kShiftInvalid: break; } - - case Operand::ShiftRegister::kShiftInvalid: break; } + }; + + if (op.shift_reg.shift_first) { + shift(); + extract_and_extend(); + } else { + extract_and_extend(); + shift(); } if (word_size > op.size) { From 26746074cf68d47d934246172935a9f63fc53f37 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 13 Oct 2020 18:23:39 -0400 Subject: [PATCH 024/130] Created EvalPCDest added PC evaluation to Logical Arithmetic Instructions --- remill/Arch/AArch32/Decode.cpp | 132 +++++++++------------- remill/Arch/AArch32/Semantics/LOGICAL.cpp | 8 +- 2 files changed, 55 insertions(+), 85 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 2f9d3e0ca..c3cd1a8b1 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -550,7 +550,7 @@ std::optional EvalOperand(const Instruction &inst, const Operand &op) typedef std::optional (InstEval)(uint32_t, uint32_t, uint32_t); // High 3 bit opc -static InstEval * kIdpEvaluatorsRRR[] = { +static InstEval * kIdpEvaluators[] = { [0b000] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { return std::optional(src1 & (src2 | src2_rrx)); }, @@ -577,6 +577,38 @@ static InstEval * kIdpEvaluatorsRRR[] = { }, }; +static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, InstEval * evaluator) { + if (rd == kPCRegNum) { + if (s) { // Updates the flags (condition codes) + inst.category = Instruction::kCategoryError; + return false; + } else { + auto src1 = EvalOperand(inst, inst.operands[1]); + auto src2 = EvalOperand(inst, inst.operands[2]); + auto src2_rrx = EvalOperand(inst, inst.operands[3]); + + if (!src1 || !src2 || !src2_rrx) { + inst.category = Instruction::kCategoryIndirectJump; + } else { + auto res = evaluator(*src1, *src2, *src2_rrx); + if (!res) { + inst.category = Instruction::kCategoryIndirectJump; + } else if (!inst.conditions.empty()) { + inst.branch_taken_pc = static_cast(*res); + inst.branch_not_taken_pc = inst.next_pc; + inst.category = Instruction::kCategoryConditionalBranch; + } else { + inst.branch_taken_pc = static_cast(*res); + inst.category = Instruction::kCategoryDirectJump; + } + } + } + } else { + inst.category = Instruction::kCategoryNormal; + } + return true; +} + // High 3 bit opc and low bit s, opc:s static const char * const kIdpNamesRRR[] = { [0b0000] = "ANDrr", @@ -624,37 +656,7 @@ static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - if (enc.rd == kPCRegNum) { - if (enc.s) { // Updates the flags (condition codes) - inst.category = Instruction::kCategoryError; - return false; - } else { - auto src1 = EvalOperand(inst, inst.operands[1]); - auto src2 = EvalOperand(inst, inst.operands[2]); - auto src2_rrx = EvalOperand(inst, inst.operands[3]); - - if (!src1 || !src2 || !src2_rrx) { - inst.category = Instruction::kCategoryIndirectJump; - } else { - auto res = kIdpEvaluatorsRRR[enc.opc](*src1, *src2, *src2_rrx); - - if (!res) { - inst.category = Instruction::kCategoryIndirectJump; - } else if (!inst.conditions.empty()) { - inst.branch_taken_pc = static_cast(*res); - inst.branch_not_taken_pc = inst.next_pc; - inst.category = Instruction::kCategoryConditionalBranch; - } else { - inst.branch_taken_pc = static_cast(*res); - inst.category = Instruction::kCategoryDirectJump; - } - } - } - } else { - inst.category = Instruction::kCategoryNormal; - } - - return true; + return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); } //000 AND, ANDS (immediate) @@ -690,45 +692,8 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) DecodeA32ExpandImm(inst, enc.imm12, enc.s); - if (enc.rd == kPCRegNum) { - if (enc.s) { // Updates the flags (condition codes) - inst.category = Instruction::kCategoryError; - return false; - } else { - auto src1 = EvalOperand(inst, inst.operands[1]); - auto src2 = EvalOperand(inst, inst.operands[2]); - auto src2_rrx = EvalOperand(inst, inst.operands[3]); - - if (!src1 || !src2 || !src2_rrx) { - inst.category = Instruction::kCategoryIndirectJump; - } else { - auto src1 = EvalOperand(inst, inst.operands[1]); - auto src2 = EvalOperand(inst, inst.operands[2]); - auto src2_rrx = EvalOperand(inst, inst.operands[3]); - - if (!src1 || !src2 || !src2_rrx) { - inst.category = Instruction::kCategoryIndirectJump; - } else { - auto res = kIdpEvaluatorsRRR[enc.opc](*src1, *src2, *src2_rrx); + return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); - if (!res) { - inst.category = Instruction::kCategoryIndirectJump; - } else if (!inst.conditions.empty()) { - inst.branch_taken_pc = static_cast(*res); - inst.branch_not_taken_pc = inst.next_pc; - inst.category = Instruction::kCategoryConditionalBranch; - } else { - inst.branch_taken_pc = static_cast(*res); - inst.category = Instruction::kCategoryDirectJump; - } - } - } - } - } else { - inst.category = Instruction::kCategoryNormal; - } - - return true; } @@ -895,6 +860,21 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { return true; } +static InstEval * kLogArithEvaluators[] = { + [0b00] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(src1 | (src2 | src2_rrx)); + }, + [0b01] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(src2 | src2_rrx); + }, + [0b10] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(src1 & ~(src2 | src2_rrx)); + }, + [0b11] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(~(src2 | src2_rrx)); + }, +}; + //00 ORR, ORRS (register) -- rd, rn, & rm //01 MOV, MOVS (register) -- rd, & rm only //10 BIC, BICS (register) -- rd, rn, & rm @@ -923,22 +903,12 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); - // enc.opc == x0 - if (!(enc.opc & 0b1)) { - AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); - } - AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); if (enc.s) { AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - if (enc.rd == kPCRegNum){ - // TODO(Sonya): handle the PC destination register case - } - - inst.category = Instruction::kCategoryNormal; - return true; + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc]); } // Corresponds to Data-processing register (immediate shift) diff --git a/remill/Arch/AArch32/Semantics/LOGICAL.cpp b/remill/Arch/AArch32/Semantics/LOGICAL.cpp index 6df45f74d..1f66224b8 100644 --- a/remill/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/remill/Arch/AArch32/Semantics/LOGICAL.cpp @@ -35,13 +35,13 @@ DEF_SEM(ORRS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { return memory; } -DEF_SEM(MOV, R32W dst, I32 src, I32 src_rrx){ +DEF_SEM(MOV, R32W dst, R32 _, I32 src, I32 src_rrx){ auto value = UOr(Read(src), Read(src_rrx)); Write(dst, value); return memory; } -DEF_SEM(MOVS, R32W dst, I32 src, I32 src_rrx, I8 carry_out) { +DEF_SEM(MOVS, R32W dst, R32 _, I32 src, I32 src_rrx, I8 carry_out) { auto value = UOr(Read(src), Read(src_rrx)); Write(dst, value); @@ -71,13 +71,13 @@ DEF_SEM(BICS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { return memory; } -DEF_SEM(MVN, R32W dst, I32 src, I32 src_rrx){ +DEF_SEM(MVN, R32W dst, R32 _, I32 src, I32 src_rrx){ auto value = UNot(UOr(Read(src), Read(src_rrx))); Write(dst, value); return memory; } -DEF_SEM(MVNS, R32W dst, I32 src, I32 src_rrx, I8 carry_out) { +DEF_SEM(MVNS, R32W dst, R32 _, I32 src, I32 src_rrx, I8 carry_out) { auto value = UNot(UOr(Read(src), Read(src_rrx))); Write(dst, value); From f7b2cd9466313883240113abd6e17284e0294707 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 13 Oct 2020 18:46:10 -0400 Subject: [PATCH 025/130] AddShiftOp -> AddShiftOp, AddShiftThenExtractOp, AddExtractThenShiftOp --- remill/Arch/AArch32/Decode.cpp | 76 ++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 21 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index c3cd1a8b1..1bae82568 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -161,6 +161,7 @@ static const char * const kIntRegName[] = { typedef bool (*const TryDecode)(Instruction&, uint32_t); typedef bool (*const TryDecodeList[])(Instruction&, uint32_t); +typedef std::optional (InstEval)(uint32_t, uint32_t, uint32_t); static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, Operand::Action action) { @@ -200,10 +201,44 @@ static void AddAddrRegOp(Instruction &inst, const char * reg_name, unsigned mem_ } static void AddShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, - Operand::ShiftRegister::Extend extend_op, const char * reg_name, - unsigned reg_size, unsigned shift_size, unsigned extract_size, - Operand::Action action = Operand::kActionRead, unsigned size = 32, - bool shift_first = false) { + const char * reg_name, unsigned reg_size, unsigned shift_size, + Operand::Action action = Operand::kActionRead, unsigned size = 32) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.shift_reg.shift_size = shift_size; + op.type = Operand::kTypeShiftRegister; + op.size = size; + op.action = action; + op.shift_reg.reg.name = reg_name; + op.shift_reg.reg.size = reg_size; + op.shift_reg.shift_op = shift_op; + op.shift_reg.shift_size = shift_size; +} + +static void AddShiftThenExtractOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, + Operand::ShiftRegister::Extend extend_op, const char * reg_name, + unsigned reg_size, unsigned shift_size, unsigned extract_size, + Operand::Action action = Operand::kActionRead, unsigned size = 32) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.shift_reg.extract_size = extract_size; + op.shift_reg.extend_op = extend_op; + op.shift_reg.shift_size = shift_size; + op.type = Operand::kTypeShiftRegister; + op.size = size; + op.action = action; + op.shift_reg.reg.name = reg_name; + op.shift_reg.reg.size = reg_size; + op.shift_reg.shift_op = shift_op; + op.shift_reg.shift_size = shift_size; + op.shift_reg.shift_first = true; + +} + +static void AddExtractThenShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, + Operand::ShiftRegister::Extend extend_op, const char * reg_name, + unsigned reg_size, unsigned shift_size, unsigned extract_size, + Operand::Action action = Operand::kActionRead, unsigned size = 32) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.shift_reg.extract_size = extract_size; @@ -216,7 +251,7 @@ static void AddShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op op.shift_reg.reg.size = reg_size; op.shift_reg.shift_op = shift_op; op.shift_reg.shift_size = shift_size; - op.shift_reg.shift_first = shift_first; + op.shift_reg.shift_first = false; } @@ -253,7 +288,7 @@ static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out if (carry_out) { if (!rotation_amount) { - AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, "C", 8, 0, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, "C", 8, 0, 1); } else { AddImmOp(inst, (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u); } @@ -286,9 +321,9 @@ static void AddShiftRegOperand(Instruction &inst, AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); } else { if (is_rrx) { - AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendInvalid, kIntRegName[reg_num], 32, 1, 0); + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, kIntRegName[reg_num], 32, 1); } else { - AddShiftOp(inst, GetOperandShift(static_cast(shift_type)), Operand::ShiftRegister::kExtendInvalid, kIntRegName[reg_num], 32, shift_size, 0); + AddShiftOp(inst, GetOperandShift(static_cast(shift_type)), kIntRegName[reg_num], 32, shift_size); } } @@ -297,7 +332,7 @@ static void AddShiftRegOperand(Instruction &inst, // So we make 2 operands and OR those two operands together. In most cases // when rrx isn't used we OR something with 0. if (is_rrx) { - AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendInvalid, "C", 8, 31, 0); + AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, "C", 8, 31); } else { AddImmOp(inst, 0); } @@ -318,23 +353,23 @@ static void AddShiftCarryOperand(Instruction &inst, } if (!shift_size) { - AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, carry_reg_name, 8, 0, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, carry_reg_name, 8, 0, 1); } else { switch (static_cast(shift_type)) { case Shift::kShiftASR: - AddShiftOp(inst, Operand::ShiftRegister::kShiftSignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftSignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); break; case Shift::kShiftLSL: - AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 32 - shift_size, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 32 - shift_size, 1); break; case Shift::kShiftLSR: - AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); break; case Shift::kShiftROR: if (is_rrx) { - AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 0, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 0, 1); } else { - AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, (shift_size + 31u) % 32u, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, (shift_size + 31u) % 32u, 1); } break; } @@ -547,8 +582,6 @@ std::optional EvalOperand(const Instruction &inst, const Operand &op) } -typedef std::optional (InstEval)(uint32_t, uint32_t, uint32_t); - // High 3 bit opc static InstEval * kIdpEvaluators[] = { [0b000] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { @@ -577,7 +610,8 @@ static InstEval * kIdpEvaluators[] = { }, }; -static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, InstEval * evaluator) { +template +static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, Evaluator * evaluator) { if (rd == kPCRegNum) { if (s) { // Updates the flags (condition codes) inst.category = Instruction::kCategoryError; @@ -656,7 +690,7 @@ static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); } //000 AND, ANDS (immediate) @@ -692,7 +726,7 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) DecodeA32ExpandImm(inst, enc.imm12, enc.s); - return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); } @@ -908,7 +942,7 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc]); } // Corresponds to Data-processing register (immediate shift) From f46cc4f0bfc1c27e2f5988ea0ffc31e9361b60e1 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 13 Oct 2020 19:16:06 -0400 Subject: [PATCH 026/130] Cleaned up some formatting, Renamed DecodeA32ExpandImm to ExpandTo32AddImmAddCarry and added a clarifying comment --- remill/Arch/AArch32/Decode.cpp | 94 ++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 28 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 1bae82568..5e43eef3b 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -186,8 +186,9 @@ static void AddImmOp(Instruction &inst, uint64_t value, unsigned size = 32, op.type = Operand::kTypeImmediate; } -static void AddAddrRegOp(Instruction &inst, const char * reg_name, unsigned mem_size, - Operand::Action mem_action, unsigned disp, unsigned scale = 0) { +static void AddAddrRegOp(Instruction &inst, const char *reg_name, + unsigned mem_size, Operand::Action mem_action, + unsigned disp, unsigned scale = 0) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.type = Operand::kTypeAddress; @@ -200,9 +201,12 @@ static void AddAddrRegOp(Instruction &inst, const char * reg_name, unsigned mem_ op.addr.displacement = disp; } -static void AddShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, - const char * reg_name, unsigned reg_size, unsigned shift_size, - Operand::Action action = Operand::kActionRead, unsigned size = 32) { +static void AddShiftOp(Instruction &inst, + Operand::ShiftRegister::Shift shift_op, + const char *reg_name, unsigned reg_size, + unsigned shift_size, Operand::Action action = + Operand::kActionRead, + unsigned size = 32) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.shift_reg.shift_size = shift_size; @@ -215,10 +219,13 @@ static void AddShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op op.shift_reg.shift_size = shift_size; } -static void AddShiftThenExtractOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, - Operand::ShiftRegister::Extend extend_op, const char * reg_name, - unsigned reg_size, unsigned shift_size, unsigned extract_size, - Operand::Action action = Operand::kActionRead, unsigned size = 32) { +static void AddShiftThenExtractOp(Instruction &inst, + Operand::ShiftRegister::Shift shift_op, + Operand::ShiftRegister::Extend extend_op, + const char *reg_name, unsigned reg_size, + unsigned shift_size, unsigned extract_size, + Operand::Action action = Operand::kActionRead, + unsigned size = 32) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.shift_reg.extract_size = extract_size; @@ -235,10 +242,13 @@ static void AddShiftThenExtractOp(Instruction &inst, Operand::ShiftRegister::Shi } -static void AddExtractThenShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, - Operand::ShiftRegister::Extend extend_op, const char * reg_name, - unsigned reg_size, unsigned shift_size, unsigned extract_size, - Operand::Action action = Operand::kActionRead, unsigned size = 32) { +static void AddExtractThenShiftOp(Instruction &inst, + Operand::ShiftRegister::Shift shift_op, + Operand::ShiftRegister::Extend extend_op, + const char *reg_name, unsigned reg_size, + unsigned shift_size, unsigned extract_size, + Operand::Action action = Operand::kActionRead, + unsigned size = 32) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.shift_reg.extract_size = extract_size; @@ -274,7 +284,14 @@ static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { return Operand::ShiftRegister::kShiftInvalid; } -static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out) { +// Note: This function adds either 2 or 3 operands in total +// an op and an op_rrx which should be ORed together when adding Semantics, +// and if carry_out an additional carry_out op + +// Used to handle semantics for: +// (shift_t, shift_n) = DecodeImmShift(type, imm5); +// See an instruction in Data-processing register (immediate shift) for example +static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, bool carry_out) { uint32_t unrotated_value = imm12 & (0b11111111u); uint32_t rotation_amount = ((imm12 >> 8) & (0b1111u)) *2u; @@ -288,12 +305,14 @@ static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out if (carry_out) { if (!rotation_amount) { - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, "C", 8, 0, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, + Operand::ShiftRegister::kExtendUnsigned, "C", 8, 0, + 1); } else { - AddImmOp(inst, (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u); + AddImmOp(inst, + (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u); } } - } // Note: This function should be used with AddShiftCarryOperand to add carry_out operand! @@ -321,9 +340,11 @@ static void AddShiftRegOperand(Instruction &inst, AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); } else { if (is_rrx) { - AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, kIntRegName[reg_num], 32, 1); + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, + kIntRegName[reg_num], 32, 1); } else { - AddShiftOp(inst, GetOperandShift(static_cast(shift_type)), kIntRegName[reg_num], 32, shift_size); + AddShiftOp(inst, GetOperandShift(static_cast(shift_type)), + kIntRegName[reg_num], 32, shift_size); } } @@ -353,23 +374,38 @@ static void AddShiftCarryOperand(Instruction &inst, } if (!shift_size) { - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, carry_reg_name, 8, 0, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, + Operand::ShiftRegister::kExtendUnsigned, + carry_reg_name, 8, 0, 1); } else { switch (static_cast(shift_type)) { case Shift::kShiftASR: - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftSignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftSignedRight, + Operand::ShiftRegister::kExtendUnsigned, + kIntRegName[reg_num], 32, shift_size - 1, 1); break; case Shift::kShiftLSL: - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 32 - shift_size, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, + Operand::ShiftRegister::kExtendUnsigned, + kIntRegName[reg_num], 32, 32 - shift_size, 1); break; case Shift::kShiftLSR: - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, + Operand::ShiftRegister::kExtendUnsigned, + kIntRegName[reg_num], 32, shift_size - 1, 1); break; case Shift::kShiftROR: if (is_rrx) { - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 0, 1); + AddShiftThenExtractOp(inst, + Operand::ShiftRegister::kShiftUnsignedRight, + Operand::ShiftRegister::kExtendUnsigned, + kIntRegName[reg_num], 32, 0, 1); } else { - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, (shift_size + 31u) % 32u, 1); + AddShiftThenExtractOp(inst, + Operand::ShiftRegister::kShiftUnsignedRight, + Operand::ShiftRegister::kExtendUnsigned, + kIntRegName[reg_num], 32, + (shift_size + 31u) % 32u, 1); } break; } @@ -611,9 +647,11 @@ static InstEval * kIdpEvaluators[] = { }; template -static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, Evaluator * evaluator) { +static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, + Evaluator *evaluator) { if (rd == kPCRegNum) { - if (s) { // Updates the flags (condition codes) + // Updates the flags (condition codes) + if (s) { inst.category = Instruction::kCategoryError; return false; } else { @@ -724,7 +762,7 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); } - DecodeA32ExpandImm(inst, enc.imm12, enc.s); + ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s); return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); From b3a98d34bdc470f99d965d5f71769f7962454529 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 13 Oct 2020 19:48:19 -0400 Subject: [PATCH 027/130] Added comment to EvalPCDest for clarity --- remill/Arch/AArch32/Decode.cpp | 76 ++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 5e43eef3b..dff4b11f2 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -618,6 +618,47 @@ std::optional EvalOperand(const Instruction &inst, const Operand &op) } +// Handles appropriate branching semantics for: +// if d == 15 then +// if setflags then +// ALUExceptionReturn(result); +// else +// ALUWritePC(result); +template +static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, + Evaluator *evaluator) { + if (rd == kPCRegNum) { + // Updates the flags (condition codes) + if (s) { + inst.category = Instruction::kCategoryError; + return false; + } else { + auto src1 = EvalOperand(inst, inst.operands[1]); + auto src2 = EvalOperand(inst, inst.operands[2]); + auto src2_rrx = EvalOperand(inst, inst.operands[3]); + + if (!src1 || !src2 || !src2_rrx) { + inst.category = Instruction::kCategoryIndirectJump; + } else { + auto res = evaluator(*src1, *src2, *src2_rrx); + if (!res) { + inst.category = Instruction::kCategoryIndirectJump; + } else if (!inst.conditions.empty()) { + inst.branch_taken_pc = static_cast(*res); + inst.branch_not_taken_pc = inst.next_pc; + inst.category = Instruction::kCategoryConditionalBranch; + } else { + inst.branch_taken_pc = static_cast(*res); + inst.category = Instruction::kCategoryDirectJump; + } + } + } + } else { + inst.category = Instruction::kCategoryNormal; + } + return true; +} + // High 3 bit opc static InstEval * kIdpEvaluators[] = { [0b000] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { @@ -646,41 +687,6 @@ static InstEval * kIdpEvaluators[] = { }, }; -template -static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, - Evaluator *evaluator) { - if (rd == kPCRegNum) { - // Updates the flags (condition codes) - if (s) { - inst.category = Instruction::kCategoryError; - return false; - } else { - auto src1 = EvalOperand(inst, inst.operands[1]); - auto src2 = EvalOperand(inst, inst.operands[2]); - auto src2_rrx = EvalOperand(inst, inst.operands[3]); - - if (!src1 || !src2 || !src2_rrx) { - inst.category = Instruction::kCategoryIndirectJump; - } else { - auto res = evaluator(*src1, *src2, *src2_rrx); - if (!res) { - inst.category = Instruction::kCategoryIndirectJump; - } else if (!inst.conditions.empty()) { - inst.branch_taken_pc = static_cast(*res); - inst.branch_not_taken_pc = inst.next_pc; - inst.category = Instruction::kCategoryConditionalBranch; - } else { - inst.branch_taken_pc = static_cast(*res); - inst.category = Instruction::kCategoryDirectJump; - } - } - } - } else { - inst.category = Instruction::kCategoryNormal; - } - return true; -} - // High 3 bit opc and low bit s, opc:s static const char * const kIdpNamesRRR[] = { [0b0000] = "ANDrr", From e17750bd0b4fec8553fb74d8f5f8f420c0d29d11 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 14 Oct 2020 10:51:51 -0400 Subject: [PATCH 028/130] Cleaned up some things, updated the decoding semantics and semantics for the logical instructions --- remill/Arch/AArch32/Decode.cpp | 60 ++++++++++------------- remill/Arch/AArch32/Semantics/LOGICAL.cpp | 42 ++-------------- 2 files changed, 31 insertions(+), 71 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index dff4b11f2..7d9722ce5 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -159,8 +159,7 @@ static const char * const kIntRegName[] = { "R15" }; -typedef bool (*const TryDecode)(Instruction&, uint32_t); -typedef bool (*const TryDecodeList[])(Instruction&, uint32_t); +typedef bool (TryDecode)(Instruction&, uint32_t); typedef std::optional (InstEval)(uint32_t, uint32_t, uint32_t); static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, @@ -209,7 +208,6 @@ static void AddShiftOp(Instruction &inst, unsigned size = 32) { inst.operands.emplace_back(); auto &op = inst.operands.back(); - op.shift_reg.shift_size = shift_size; op.type = Operand::kTypeShiftRegister; op.size = size; op.action = action; @@ -226,18 +224,10 @@ static void AddShiftThenExtractOp(Instruction &inst, unsigned shift_size, unsigned extract_size, Operand::Action action = Operand::kActionRead, unsigned size = 32) { - inst.operands.emplace_back(); + AddShiftOp(inst, shift_op, reg_name, reg_size, shift_size, action, size); auto &op = inst.operands.back(); op.shift_reg.extract_size = extract_size; op.shift_reg.extend_op = extend_op; - op.shift_reg.shift_size = shift_size; - op.type = Operand::kTypeShiftRegister; - op.size = size; - op.action = action; - op.shift_reg.reg.name = reg_name; - op.shift_reg.reg.size = reg_size; - op.shift_reg.shift_op = shift_op; - op.shift_reg.shift_size = shift_size; op.shift_reg.shift_first = true; } @@ -249,18 +239,10 @@ static void AddExtractThenShiftOp(Instruction &inst, unsigned shift_size, unsigned extract_size, Operand::Action action = Operand::kActionRead, unsigned size = 32) { - inst.operands.emplace_back(); + AddShiftOp(inst, shift_op, reg_name, reg_size, shift_size, action, size); auto &op = inst.operands.back(); op.shift_reg.extract_size = extract_size; op.shift_reg.extend_op = extend_op; - op.shift_reg.shift_size = shift_size; - op.type = Operand::kTypeShiftRegister; - op.size = size; - op.action = action; - op.shift_reg.reg.name = reg_name; - op.shift_reg.reg.size = reg_size; - op.shift_reg.shift_op = shift_op; - op.shift_reg.shift_size = shift_size; op.shift_reg.shift_first = false; } @@ -580,8 +562,6 @@ std::optional EvalExtract(const Operand::ShiftRegister &op, case Operand::ShiftRegister::kExtendUnsigned: return val & ((1u << (op.extract_size)) - 1u); } - - } std::optional EvalOperand(const Instruction &inst, const Operand &op) { @@ -624,9 +604,10 @@ std::optional EvalOperand(const Instruction &inst, const Operand &op) // ALUExceptionReturn(result); // else // ALUWritePC(result); -template +// TODO(Sonya): maybe template this and decide on a robust method for handling +// the variable number of arguments to evaluator static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, - Evaluator *evaluator) { + InstEval *evaluator) { if (rd == kPCRegNum) { // Updates the flags (condition codes) if (s) { @@ -734,7 +715,7 @@ static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); } //000 AND, ANDS (immediate) @@ -770,7 +751,7 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s); - return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); } @@ -981,17 +962,30 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + // enc.opc == x0 + if (!(enc.opc & 0b1u)) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + } + // enc.opc == 01 + else if (!(enc.opc & 0b10u)) { + AddImmOp(inst, 0); + } + // enc.opc == 11 + else { + AddImmOp(inst, 1); + } + AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); if (enc.s) { AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc]); } // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> -static TryDecodeList kDataProcessingRI = { +static TryDecode * kDataProcessingRI[] = { [0b000] = TryDecodeIntegerDataProcessingRRR, [0b001] = TryDecodeIntegerDataProcessingRRR, [0b010] = TryDecodeIntegerDataProcessingRRR, @@ -1004,7 +998,7 @@ static TryDecodeList kDataProcessingRI = { // Corresponds to Data-processing immediate // op0<24 to 23> | op1 <21 to 20> -static TryDecodeList kDataProcessingI = { +static TryDecode * kDataProcessingI[] = { [0b0000] = TryDecodeIntegerDataProcessingRRI, [0b0001] = TryDecodeIntegerDataProcessingRRI, [0b0010] = TryDecodeIntegerDataProcessingRRI, @@ -1025,7 +1019,7 @@ static TryDecodeList kDataProcessingI = { // Corresponds to: Load/Store Word, Unsigned Byte (immediate, literal) // o2<22> | o1<21> -static TryDecodeList kLoadStoreWordUBIL = { +static TryDecode * kLoadStoreWordUBIL[] = { [0b00] = TryDecodeLoadStoreWordUBIL, [0b01] = TryDecodeLoadStoreWordUBIL, [0b10] = TryDecodeLoadStoreWordUBIL, @@ -1042,7 +1036,7 @@ static TryDecodeList kLoadStoreWordUBIL = { // 0 != 10xx0 0 Data-processing register (immediate shift) // 0 != 10xx0 0 1 Data-processing register (register shift) // 1 Data-processing immediate -static TryDecode TryDataProcessingAndMisc(uint32_t bits) { +static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { const DataProcessingAndMisc enc = { bits }; // op0 == 0 if (!enc.op0) { @@ -1108,7 +1102,7 @@ static TryDecode TryDataProcessingAndMisc(uint32_t bits) { // 10x Branch, branch with link, and block data transfer // 11x System register access, Advanced SIMD, floating-point, and Supervisor call // 1111 0xx Unconditional instructions -static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { +static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { const TopLevelEncodings enc = { bits }; // op0 == 0xx if (!(enc.op0 >> 2)) { diff --git a/remill/Arch/AArch32/Semantics/LOGICAL.cpp b/remill/Arch/AArch32/Semantics/LOGICAL.cpp index 1f66224b8..721964001 100644 --- a/remill/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/remill/Arch/AArch32/Semantics/LOGICAL.cpp @@ -35,23 +35,6 @@ DEF_SEM(ORRS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { return memory; } -DEF_SEM(MOV, R32W dst, R32 _, I32 src, I32 src_rrx){ - auto value = UOr(Read(src), Read(src_rrx)); - Write(dst, value); - return memory; -} - -DEF_SEM(MOVS, R32W dst, R32 _, I32 src, I32 src_rrx, I8 carry_out) { - auto value = UOr(Read(src), Read(src_rrx)); - Write(dst, value); - - state.sr.n = SignFlag(value); - state.sr.z = ZeroFlag(value); - state.sr.c = Read(carry_out); - // PSTATE.V unchanged - return memory; -} - DEF_SEM(BIC, R32W dst, R32 src1, I32 src2, I32 src2_rrx){ auto value = UNot(UOr(Read(src2), Read(src2_rrx))); auto result = UAnd(Read(src1), value); @@ -71,31 +54,14 @@ DEF_SEM(BICS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { return memory; } -DEF_SEM(MVN, R32W dst, R32 _, I32 src, I32 src_rrx){ - auto value = UNot(UOr(Read(src), Read(src_rrx))); - Write(dst, value); - return memory; -} - -DEF_SEM(MVNS, R32W dst, R32 _, I32 src, I32 src_rrx, I8 carry_out) { - auto value = UNot(UOr(Read(src), Read(src_rrx))); - Write(dst, value); - - state.sr.n = SignFlag(value); - state.sr.z = ZeroFlag(value); - state.sr.c = Read(carry_out); - // PSTATE.V unchanged - return memory; -} - } // namespace DEF_ISEL(ORRrrri) = ORR; DEF_ISEL(ORRSrrri) = ORRS; -DEF_ISEL(MOVrrri) = MOV; -DEF_ISEL(MOVSrrri) = MOVS; +DEF_ISEL(MOVrrri) = ORR; +DEF_ISEL(MOVSrrri) = ORRS; DEF_ISEL(BICrrri) = BIC; DEF_ISEL(BICSrrri) = BICS; -DEF_ISEL(MVNrrri) = MVN; -DEF_ISEL(MVNSrrri) = MVNS; +DEF_ISEL(MVNrrri) = BIC; +DEF_ISEL(MVNSrrri) = BICS; From 9d77145667421df32754d997a49fda16297d4e83 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 14 Oct 2020 12:59:57 -0400 Subject: [PATCH 029/130] Shortened kLogArithEvaluators and fixed a bug --- remill/Arch/AArch32/Decode.cpp | 16 ++++++---------- remill/Arch/AArch32/Semantics/LOGICAL.cpp | 16 ++++++++-------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 7d9722ce5..63961da7f 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -755,7 +755,6 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) } - static const char * const kMulAccRRR[] = { [0b0000] = "MULrr", [0b0001] = "MULSrr", @@ -919,19 +918,16 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { return true; } +// Can package semantics for MOV with ORR and MVN with BIC since src1 will be +// 0 and 1 for MOV and MVN respectively, mirroring the semantics in LOGICAL.cpp static InstEval * kLogArithEvaluators[] = { - [0b00] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + [0b0] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { return std::optional(src1 | (src2 | src2_rrx)); }, - [0b01] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { - return std::optional(src2 | src2_rrx); - }, - [0b10] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + + [0b1] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { return std::optional(src1 & ~(src2 | src2_rrx)); }, - [0b11] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { - return std::optional(~(src2 | src2_rrx)); - }, }; //00 ORR, ORRS (register) -- rd, rn, & rm @@ -980,7 +976,7 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); } // Corresponds to Data-processing register (immediate shift) diff --git a/remill/Arch/AArch32/Semantics/LOGICAL.cpp b/remill/Arch/AArch32/Semantics/LOGICAL.cpp index 721964001..140357998 100644 --- a/remill/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/remill/Arch/AArch32/Semantics/LOGICAL.cpp @@ -19,17 +19,17 @@ namespace { DEF_SEM(ORR, R32W dst, R32 src1, I32 src2, I32 src2_rrx){ auto value = UOr(Read(src2), Read(src2_rrx)); auto result = UOr(Read(src1), value); - Write(dst, value); + Write(dst, result); return memory; } DEF_SEM(ORRS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { auto value = UOr(Read(src2), Read(src2_rrx)); auto result = UOr(Read(src1), value); - Write(dst, value); + Write(dst, result); - state.sr.n = SignFlag(value); - state.sr.z = ZeroFlag(value); + state.sr.n = SignFlag(result); + state.sr.z = ZeroFlag(result); state.sr.c = Read(carry_out); // PSTATE.V unchanged return memory; @@ -38,17 +38,17 @@ DEF_SEM(ORRS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { DEF_SEM(BIC, R32W dst, R32 src1, I32 src2, I32 src2_rrx){ auto value = UNot(UOr(Read(src2), Read(src2_rrx))); auto result = UAnd(Read(src1), value); - Write(dst, value); + Write(dst, result); return memory; } DEF_SEM(BICS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { auto value = UNot(UOr(Read(src2), Read(src2_rrx))); auto result = UAnd(Read(src1), value); - Write(dst, value); + Write(dst, result); - state.sr.n = SignFlag(value); - state.sr.z = ZeroFlag(value); + state.sr.n = SignFlag(result); + state.sr.z = ZeroFlag(result); state.sr.c = Read(carry_out); // PSTATE.V unchanged return memory; From 6c819b239900e59ffb453e9cf1cda5eaf7e3a70e Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 14 Oct 2020 18:20:24 -0400 Subject: [PATCH 030/130] Updates from testing instructions --- remill/Arch/AArch32/Decode.cpp | 24 +++++++++++++---------- remill/Arch/AArch32/Semantics/BINARY.cpp | 4 ---- remill/Arch/AArch32/Semantics/LOGICAL.cpp | 1 - 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 63961da7f..492ee5977 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -530,6 +530,8 @@ std::optional EvalShift(const Operand::ShiftRegister &op, return val >> op.shift_size; case Operand::ShiftRegister::kShiftSignedRight: return static_cast(static_cast(val) >> op.shift_size); + default: + return std::nullopt; } } @@ -561,6 +563,8 @@ std::optional EvalExtract(const Operand::ShiftRegister &op, } case Operand::ShiftRegister::kExtendUnsigned: return val & ((1u << (op.extract_size)) - 1u); + default: + return std::nullopt; } } @@ -594,8 +598,9 @@ std::optional EvalOperand(const Instruction &inst, const Operand &op) } else { return EvalShift(op.shift_reg, EvalExtract(op.shift_reg, EvalReg(inst, op.shift_reg.reg))); } + default: + return std::nullopt; } - } // Handles appropriate branching semantics for: @@ -604,8 +609,6 @@ std::optional EvalOperand(const Instruction &inst, const Operand &op) // ALUExceptionReturn(result); // else // ALUWritePC(result); -// TODO(Sonya): maybe template this and decide on a robust method for handling -// the variable number of arguments to evaluator static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, InstEval *evaluator) { if (rd == kPCRegNum) { @@ -619,6 +622,7 @@ static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, auto src2_rrx = EvalOperand(inst, inst.operands[3]); if (!src1 || !src2 || !src2_rrx) { + LOG(ERROR) << "\n\n\n\n\n\n\n indirect jump \n\n\n\n\n\n\n" << !src1 << !src2 << !src2_rrx; inst.category = Instruction::kCategoryIndirectJump; } else { auto res = evaluator(*src1, *src2, *src2_rrx); @@ -715,7 +719,7 @@ static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc]); } //000 AND, ANDS (immediate) @@ -751,8 +755,7 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s); - return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); - + return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc]); } static const char * const kMulAccRRR[] = { @@ -786,8 +789,10 @@ static const char * const kMulAccRRR[] = { //111 SMLAL, SMLALS - writes to RdHi + RdLo, read RdHi static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { const MultiplyAndAccumulate enc = { bits }; - // if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; - if (enc.rdhi == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum) { + // MUL, MULS only: if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; + // All other instructions: if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; + if (enc.rdhi == kPCRegNum || (enc.rdlo == kPCRegNum && !enc.opc) + || enc.rn == kPCRegNum || enc.rm == kPCRegNum) { inst.category = Instruction::kCategoryError; return false; } @@ -804,7 +809,7 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { // 2nd write reg only needed for instructions with an opc that begins with 1 and UMALL if (((enc.opc >> 2) & 0b1u) || enc.opc == 0b010u) { // if dHi == dLo then UNPREDICTABLE; - if (enc.rdlo == enc.rdhi || enc.rdlo == kPCRegNum){ + if (enc.rdlo == enc.rdhi){ inst.category = Instruction::kCategoryError; return false; } @@ -924,7 +929,6 @@ static InstEval * kLogArithEvaluators[] = { [0b0] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { return std::optional(src1 | (src2 | src2_rrx)); }, - [0b1] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { return std::optional(src1 & ~(src2 | src2_rrx)); }, diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index c78dd6277..7b8b528fe 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -28,8 +28,6 @@ T AddWithCarryNZCV(State &state, T lhs, T rhs, T carry) { return result; } - - DEF_SEM(AND, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { auto value = UOr(Read(src2), Read(src2_rrx)); Write(dst, UAnd(Read(src1), value)); @@ -47,7 +45,6 @@ DEF_SEM(ANDS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { return memory; } - DEF_SEM(EOR, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { auto value = UOr(Read(src2), Read(src2_rrx)); Write(dst, UXor(Read(src1), value)); @@ -93,7 +90,6 @@ DEF_SEM(SUBS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { return memory; } - DEF_SEM(ADD, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { auto value = UOr(Read(src2), Read(src2_rrx)); Write(dst, UAdd(Read(src1), value)); diff --git a/remill/Arch/AArch32/Semantics/LOGICAL.cpp b/remill/Arch/AArch32/Semantics/LOGICAL.cpp index 140357998..071c038fc 100644 --- a/remill/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/remill/Arch/AArch32/Semantics/LOGICAL.cpp @@ -64,4 +64,3 @@ DEF_ISEL(BICrrri) = BIC; DEF_ISEL(BICSrrri) = BICS; DEF_ISEL(MVNrrri) = BIC; DEF_ISEL(MVNSrrri) = BICS; - From a77db18dfdf82d0b09642995e522ea99003ac39f Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 15 Oct 2020 12:17:53 -0400 Subject: [PATCH 031/130] Fixed DEF_ISEL for pre/post index instructions in MEM.cpp --- remill/Arch/AArch32/Semantics/MEM.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/remill/Arch/AArch32/Semantics/MEM.cpp b/remill/Arch/AArch32/Semantics/MEM.cpp index ef539cc14..3c953c5f9 100644 --- a/remill/Arch/AArch32/Semantics/MEM.cpp +++ b/remill/Arch/AArch32/Semantics/MEM.cpp @@ -75,12 +75,12 @@ DEF_SEM(LDRT, SrcType src1, R32W dst, R32W dst_reg, R32 src2) { DEF_ISEL(STR) = STR; DEF_ISEL(STRB) = STR; -DEF_ISEL(STRp) = STR; -DEF_ISEL(STRBp) = STR; +DEF_ISEL(STRp) = STRp; +DEF_ISEL(STRBp) = STRp; DEF_ISEL(LDR) = LDR; DEF_ISEL(LDRB) = LDR; -DEF_ISEL(LDRp) = LDR; -DEF_ISEL(LDRBp) = LDR; +DEF_ISEL(LDRp) = LDRp; +DEF_ISEL(LDRBp) = LDRp; DEF_ISEL(STRT) = STRT; DEF_ISEL(STRBT) = STRT; DEF_ISEL(LDRT) = LDRT; From 6aca67087f7881dc0c8de8c295bb8a8ab9fe7106 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 15 Oct 2020 16:28:14 -0400 Subject: [PATCH 032/130] Integer Test and Compare (two register, immediate shift) --- remill/Arch/AArch32/Decode.cpp | 91 +++++++++++++++----- remill/Arch/AArch32/Runtime/Instructions.cpp | 3 +- remill/Arch/AArch32/Semantics/COND.cpp | 58 +++++++++++++ 3 files changed, 129 insertions(+), 23 deletions(-) create mode 100644 remill/Arch/AArch32/Semantics/COND.cpp diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 492ee5977..4e5699de8 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -90,6 +90,24 @@ union LoadStoreWUBIL { } __attribute__((packed)); static_assert(sizeof(LoadStoreWUBIL) == 4, " "); +// Integer Test and Compare (two register, immediate shift) +union IntTestCompRRI { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _0 : 1; + uint32_t type : 2; + uint32_t imm5 : 5; + uint32_t _0000 : 4; + uint32_t rn : 4; + uint32_t _1 : 1; + uint32_t opc : 2; + uint32_t _00010 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntTestCompRRI) == 4, " "); + // Logical Arithmetic (three register, immediate shift) union LogicalArithRRRI { uint32_t flat; @@ -106,7 +124,7 @@ union LogicalArithRRRI { uint32_t cond : 4; } __attribute__((packed)); } __attribute__((packed)); -static_assert(sizeof(LoadStoreWUBIL) == 4, " "); +static_assert(sizeof(LogicalArithRRRI) == 4, " "); // Top-level encodings for A32 union TopLevelEncodings { @@ -622,7 +640,6 @@ static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, auto src2_rrx = EvalOperand(inst, inst.operands[3]); if (!src1 || !src2 || !src2_rrx) { - LOG(ERROR) << "\n\n\n\n\n\n\n indirect jump \n\n\n\n\n\n\n" << !src1 << !src2 << !src2_rrx; inst.category = Instruction::kCategoryIndirectJump; } else { auto res = evaluator(*src1, *src2, *src2_rrx); @@ -722,22 +739,22 @@ static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc]); } -//000 AND, ANDS (immediate) -//001 EOR, EORS (immediate) +//000 AND, ANDS (immediate) +//001 EOR, EORS (immediate) //010 0 != 11x1 SUB, SUBS (immediate) — SUB -//010 0 1101 SUB, SUBS (SP minus immediate) — SUB -//010 0 1111 ADR — A2 +//010 0 1101 SUB, SUBS (SP minus immediate) — SUB +//010 0 1111 ADR — A2 (alias of subtract) //010 1 != 1101 SUB, SUBS (immediate) — SUBS -//010 1 1101 SUB, SUBS (SP minus immediate) — SUBS -//011 RSB, RSBS (immediate) +//010 1 1101 SUB, SUBS (SP minus immediate) — SUBS +//011 RSB, RSBS (immediate) //100 0 != 11x1 ADD, ADDS (immediate) — ADD -//100 0 1101 ADD, ADDS (SP plus immediate) — ADD -//100 0 1111 ADR — A1 +//100 0 1101 ADD, ADDS (SP plus immediate) — ADD +//100 0 1111 ADR — A1 (alias of add) //100 1 != 1101 ADD, ADDS (immediate) — ADDS -//100 1 1101 ADD, ADDS (SP plus immediate) — ADDS -//101 ADC, ADCS (immediate) -//110 SBC, SBCS (immediate) -//111 RSC, RSCS (immediate) +//100 1 1101 ADD, ADDS (SP plus immediate) — ADDS +//101 ADC, ADCS (immediate) +//110 SBC, SBCS (immediate) +//111 RSC, RSCS (immediate) static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) { const IntDataProcessingRRI enc = { bits }; @@ -880,18 +897,19 @@ template(inst.pc & ~(3u)) - static_cast(inst.pc); } auto disp = static_cast(enc.imm12); + // Subtract if (!enc.u) { disp = -disp; @@ -983,6 +1002,36 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); } +//00 TST (register) +//01 TEQ (register) +//10 CMP (register) +//11 CMN (register) +static const char * const kIntegerTestAndCompareRRI[] = { + [0b00] = "TSTrri", + [0b01] = "TEQrri", + [0b10] = "CMPrri", + [0b11] = "CMNrri", +}; + +// Integer Test and Compare (two register, immediate shift) +static bool TryIntegerTestAndCompareRRI(Instruction &inst, uint32_t bits) { + const IntTestCompRRI enc = { bits }; + + auto instruction = kIntegerTestAndCompareRRI[enc.opc]; + if (!instruction) { + return false; + } + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); + AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); + + inst.category = Instruction::kCategoryNormal; + return true; +} + // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> static TryDecode * kDataProcessingRI[] = { @@ -991,7 +1040,7 @@ static TryDecode * kDataProcessingRI[] = { [0b010] = TryDecodeIntegerDataProcessingRRR, [0b011] = TryDecodeIntegerDataProcessingRRR, [0b100] = nullptr, // op0:op1 != 100 - [0b101] = nullptr, // TODO(Sonya): Integer Test and Compare (two register, immediate shift) + [0b101] = TryIntegerTestAndCompareRRI, [0b110] = TryLogicalArithmeticRRRI, [0b111] = TryLogicalArithmeticRRRI, }; diff --git a/remill/Arch/AArch32/Runtime/Instructions.cpp b/remill/Arch/AArch32/Runtime/Instructions.cpp index 57a660776..00cb7c877 100644 --- a/remill/Arch/AArch32/Runtime/Instructions.cpp +++ b/remill/Arch/AArch32/Runtime/Instructions.cpp @@ -57,14 +57,13 @@ DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; // clang-format off #include "remill/Arch/AArch32/Semantics/FLAGS.cpp" -// #include "remill/Arch/AArch32/Semantics/BINARY.cpp" #include "remill/Arch/AArch32/Semantics/MEM.cpp" #include "remill/Arch/AArch32/Semantics/LOGICAL.cpp" //#include "remill/Arch/AArch64/Semantics/BITBYTE.cpp" //#include "remill/Arch/AArch64/Semantics/BRANCH.cpp" //#include "remill/Arch/AArch64/Semantics/CALL_RET.cpp" -//#include "remill/Arch/AArch64/Semantics/COND.cpp" +#include "remill/Arch/AArch32/Semantics/COND.cpp" //#include "remill/Arch/AArch64/Semantics/CONVERT.cpp" //#include "remill/Arch/AArch64/Semantics/DATAXFER.cpp" //#include "remill/Arch/AArch64/Semantics/MISC.cpp" diff --git a/remill/Arch/AArch32/Semantics/COND.cpp b/remill/Arch/AArch32/Semantics/COND.cpp new file mode 100644 index 000000000..8a7db8d3f --- /dev/null +++ b/remill/Arch/AArch32/Semantics/COND.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { + +DEF_SEM(TST, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto res = UAnd(Read(src1), UOr(Read(src2), Read(src2_rrx))); + + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(TEQ, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto res = UXor(Read(src1), UOr(Read(src2), Read(src2_rrx))); + + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(CMP, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); + auto lhs = Read(src1); + AddWithCarryNZCV(state, lhs, UNot(rhs), uint32_t(1)); + return memory; +} + +DEF_SEM(CMN, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); + auto lhs = Read(src1); + AddWithCarryNZCV(state, lhs, rhs, uint32_t(0)); + return memory; +} + +} // namespace + +DEF_ISEL(TST) = TST; +DEF_ISEL(TEQ) = TEQ; +DEF_ISEL(CMP) = CMP; +DEF_ISEL(CMN) = CMN; From dda77379a508d97cff597d1be2cbcd83824ea7f0 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 15 Oct 2020 17:43:01 -0400 Subject: [PATCH 033/130] Logical Arithmetic (two register and immediate) --- remill/Arch/AArch32/Decode.cpp | 71 ++++++++++++++++++----- remill/Arch/AArch32/Semantics/LOGICAL.cpp | 16 ++--- 2 files changed, 66 insertions(+), 21 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 4e5699de8..c5faf5b26 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -126,6 +126,20 @@ union LogicalArithRRRI { } __attribute__((packed)); static_assert(sizeof(LogicalArithRRRI) == 4, " "); +union LogicalArithmeticRRI { + uint32_t flat; + struct { + uint32_t imm12 : 12; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 2; + uint32_t _00111 : 5; + uint32_t cond : 4; + } __attribute__((packed)); + } __attribute__((packed)); +static_assert(sizeof(LogicalArithmeticRRI) == 4, " "); + // Top-level encodings for A32 union TopLevelEncodings { uint32_t flat; @@ -289,7 +303,7 @@ static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { // and if carry_out an additional carry_out op // Used to handle semantics for: -// (shift_t, shift_n) = DecodeImmShift(type, imm5); +// (imm32, carry) = A32ExpandImm_C(imm12, PSTATE.C); // See an instruction in Data-processing register (immediate shift) for example static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, bool carry_out) { uint32_t unrotated_value = imm12 & (0b11111111u); @@ -958,14 +972,14 @@ static InstEval * kLogArithEvaluators[] = { //10 BIC, BICS (register) -- rd, rn, & rm //11 MVN, MVNS (register) -- rd, & rm only static const char * const kLogicalArithmeticRRRI[] = { - [0b000] = "ORRrrri", - [0b001] = "ORRSrrri", - [0b010] = "MOVrrri", - [0b011] = "MOVSrrri", - [0b100] = "BICrrri", - [0b101] = "BICSrrri", - [0b110] = "MVNrrri", - [0b111] = "MVNSrrri", + [0b000] = "ORRrr", + [0b001] = "ORRSrr", + [0b010] = "MOVrr", + [0b011] = "MOVSrr", + [0b100] = "BICrr", + [0b101] = "BICSrr", + [0b110] = "MVNrr", + [0b111] = "MVNSrr", }; // Logical Arithmetic (three register, immediate shift) @@ -1002,6 +1016,37 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); } +// Logical Arithmetic (two register and immediate) +static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { + const LogicalArithmeticRRI enc = { bits }; + + auto instruction = kLogicalArithmeticRRRI[enc.opc]; + if (!instruction) { + return false; + } + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + + // enc.opc == x0 + if (!(enc.opc & 0b1u)) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + } + // enc.opc == 01 + else if (!(enc.opc & 0b10u)) { + AddImmOp(inst, 0); + } + // enc.opc == 11 + else { + AddImmOp(inst, 1); + } + + ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s); + + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); +} + //00 TST (register) //01 TEQ (register) //10 CMP (register) @@ -1060,10 +1105,10 @@ static TryDecode * kDataProcessingI[] = { [0b1001] = nullptr, // TODO(Sonya): Integer Test and Compare (one register and immediate) [0b1010] = nullptr, // TODO(Sonya): Move Special Register and Hints (immediate) [0b1011] = nullptr, // TODO(Sonya): Integer Test and Compare (one register and immediate) - [0b1100] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) - [0b1101] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) - [0b1110] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) - [0b1111] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) + [0b1100] = TryLogicalArithmeticRRI, + [0b1101] = TryLogicalArithmeticRRI, + [0b1110] = TryLogicalArithmeticRRI, + [0b1111] = TryLogicalArithmeticRRI, }; // Corresponds to: Load/Store Word, Unsigned Byte (immediate, literal) diff --git a/remill/Arch/AArch32/Semantics/LOGICAL.cpp b/remill/Arch/AArch32/Semantics/LOGICAL.cpp index 071c038fc..bb12db036 100644 --- a/remill/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/remill/Arch/AArch32/Semantics/LOGICAL.cpp @@ -56,11 +56,11 @@ DEF_SEM(BICS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { } // namespace -DEF_ISEL(ORRrrri) = ORR; -DEF_ISEL(ORRSrrri) = ORRS; -DEF_ISEL(MOVrrri) = ORR; -DEF_ISEL(MOVSrrri) = ORRS; -DEF_ISEL(BICrrri) = BIC; -DEF_ISEL(BICSrrri) = BICS; -DEF_ISEL(MVNrrri) = BIC; -DEF_ISEL(MVNSrrri) = BICS; +DEF_ISEL(ORRrr) = ORR; +DEF_ISEL(ORRSrr) = ORRS; +DEF_ISEL(MOVrr) = ORR; +DEF_ISEL(MOVSrr) = ORRS; +DEF_ISEL(BICrr) = BIC; +DEF_ISEL(BICSrr) = BICS; +DEF_ISEL(MVNrr) = BIC; +DEF_ISEL(MVNSrr) = BICS; From 803dbfec0bad25db2b24a9b68e8fd8a8cd5e28c9 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 15 Oct 2020 17:58:18 -0400 Subject: [PATCH 034/130] Integer Test and Compare (one register and immediate) --- remill/Arch/AArch32/Decode.cpp | 50 +++++++++++++++++++---- remill/Arch/AArch32/Semantics/COND.cpp | 2 - remill/Arch/AArch32/Semantics/LOGICAL.cpp | 2 - 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index c5faf5b26..5124bccd6 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -108,6 +108,21 @@ union IntTestCompRRI { } __attribute__((packed)); static_assert(sizeof(IntTestCompRRI) == 4, " "); +// Integer Test and Compare (one register and immediate) +union IntTestCompRI { + uint32_t flat; + struct { + uint32_t imm12 : 12; + uint32_t _0000 : 4; + uint32_t rn : 4; + uint32_t _1 : 1; + uint32_t opc : 2; + uint32_t _00110 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntTestCompRI) == 4, " "); + // Logical Arithmetic (three register, immediate shift) union LogicalArithRRRI { uint32_t flat; @@ -1051,18 +1066,18 @@ static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { //01 TEQ (register) //10 CMP (register) //11 CMN (register) -static const char * const kIntegerTestAndCompareRRI[] = { - [0b00] = "TSTrri", - [0b01] = "TEQrri", - [0b10] = "CMPrri", - [0b11] = "CMNrri", +static const char * const kIntegerTestAndCompareR[] = { + [0b00] = "TSTr", + [0b01] = "TEQr", + [0b10] = "CMPr", + [0b11] = "CMNr", }; // Integer Test and Compare (two register, immediate shift) static bool TryIntegerTestAndCompareRRI(Instruction &inst, uint32_t bits) { const IntTestCompRRI enc = { bits }; - auto instruction = kIntegerTestAndCompareRRI[enc.opc]; + auto instruction = kIntegerTestAndCompareR[enc.opc]; if (!instruction) { return false; } @@ -1077,6 +1092,25 @@ static bool TryIntegerTestAndCompareRRI(Instruction &inst, uint32_t bits) { return true; } +// Integer Test and Compare (one register and immediate) +static bool TryIntegerTestAndCompareRI(Instruction &inst, uint32_t bits) { + const IntTestCompRI enc = { bits }; + + auto instruction = kIntegerTestAndCompareR[enc.opc]; + if (!instruction) { + return false; + } + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + ExpandTo32AddImmAddCarry(inst, enc.imm12, 1u); + + inst.category = Instruction::kCategoryNormal; + return true; + +} + // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> static TryDecode * kDataProcessingRI[] = { @@ -1102,9 +1136,9 @@ static TryDecode * kDataProcessingI[] = { [0b0110] = TryDecodeIntegerDataProcessingRRI, [0b0111] = TryDecodeIntegerDataProcessingRRI, [0b1000] = nullptr, // TODO(Sonya): Move Halfword (immediate) - [0b1001] = nullptr, // TODO(Sonya): Integer Test and Compare (one register and immediate) + [0b1001] = TryIntegerTestAndCompareRI, [0b1010] = nullptr, // TODO(Sonya): Move Special Register and Hints (immediate) - [0b1011] = nullptr, // TODO(Sonya): Integer Test and Compare (one register and immediate) + [0b1011] = TryIntegerTestAndCompareRI, [0b1100] = TryLogicalArithmeticRRI, [0b1101] = TryLogicalArithmeticRRI, [0b1110] = TryLogicalArithmeticRRI, diff --git a/remill/Arch/AArch32/Semantics/COND.cpp b/remill/Arch/AArch32/Semantics/COND.cpp index 8a7db8d3f..e69342e01 100644 --- a/remill/Arch/AArch32/Semantics/COND.cpp +++ b/remill/Arch/AArch32/Semantics/COND.cpp @@ -15,7 +15,6 @@ */ namespace { - DEF_SEM(TST, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { auto res = UAnd(Read(src1), UOr(Read(src2), Read(src2_rrx))); @@ -49,7 +48,6 @@ DEF_SEM(CMN, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { AddWithCarryNZCV(state, lhs, rhs, uint32_t(0)); return memory; } - } // namespace DEF_ISEL(TST) = TST; diff --git a/remill/Arch/AArch32/Semantics/LOGICAL.cpp b/remill/Arch/AArch32/Semantics/LOGICAL.cpp index bb12db036..f7a493d2a 100644 --- a/remill/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/remill/Arch/AArch32/Semantics/LOGICAL.cpp @@ -15,7 +15,6 @@ */ namespace { - DEF_SEM(ORR, R32W dst, R32 src1, I32 src2, I32 src2_rrx){ auto value = UOr(Read(src2), Read(src2_rrx)); auto result = UOr(Read(src1), value); @@ -53,7 +52,6 @@ DEF_SEM(BICS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { // PSTATE.V unchanged return memory; } - } // namespace DEF_ISEL(ORRrr) = ORR; From e179f71747e1021965978f0b52dd44269ebb5f74 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 15 Oct 2020 18:39:44 -0400 Subject: [PATCH 035/130] Added to the top level encoding infrastructure to handle the Data-processing register (register shift) set of instructions and 3 corresponding subsets --- remill/Arch/AArch32/Decode.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 5124bccd6..9c1804040 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -1124,6 +1124,19 @@ static TryDecode * kDataProcessingRI[] = { [0b111] = TryLogicalArithmeticRRRI, }; +// Corresponds to Data-processing register (immediate shift) +// op0<24 to 23> | op1 <20> +static TryDecode * kDataProcessingRR[] = { + [0b000] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) + [0b001] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) + [0b010] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) + [0b011] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) + [0b100] = nullptr, // op0:op1 != 100 + [0b101] = nullptr, // TODO(Sonya): Integer Test and Compare (two register, register shift) + [0b110] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, register shift) + [0b111] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, register shift) +}; + // Corresponds to Data-processing immediate // op0<24 to 23> | op1 <21 to 20> static TryDecode * kDataProcessingI[] = { @@ -1207,7 +1220,7 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { } // TODO(Sonya): Data-processing register (register shift) -- op4 == 1 else { - return nullptr; + return kDataProcessingRR[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; } } } From c1d51d490b2c31ea23741149a1cd460f540b1bdf Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 16 Oct 2020 13:37:06 -0400 Subject: [PATCH 036/130] Add structs for the 3 subsets of Data-processing register (register shift) --- remill/Arch/AArch32/Decode.cpp | 75 ++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 9c1804040..c2e391236 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -22,8 +22,27 @@ namespace remill { namespace { +//Integer Data Processing (three register, register shift) +union IntDataProcessingRRRR { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _1 : 1; + uint32_t type : 2; + uint32_t _0 : 1; + uint32_t rs : 4; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 3; + uint32_t _0000 : 4; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntDataProcessingRRRR) == 4, " "); + //Integer Data Processing (three register, immediate shift) -union IntDataProcessingRRR { +union IntDataProcessingRRRI { uint32_t flat; struct { uint32_t rm : 4; @@ -38,7 +57,7 @@ union IntDataProcessingRRR { uint32_t cond : 4; } __attribute__((packed)); } __attribute__((packed)); -static_assert(sizeof(IntDataProcessingRRR) == 4, " "); +static_assert(sizeof(IntDataProcessingRRRI) == 4, " "); //Integer Data Processing (2 register and immediate, immediate shift) union IntDataProcessingRRI { @@ -108,6 +127,25 @@ union IntTestCompRRI { } __attribute__((packed)); static_assert(sizeof(IntTestCompRRI) == 4, " "); +// Integer Test and Compare (two register, register shift) +union IntTestCompRRR { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _1 : 1; + uint32_t type : 2; + uint32_t _0 : 1; + uint32_t rs : 4; + uint32_t _0000 : 4; + uint32_t rn : 4; + uint32_t _1 : 1; + uint32_t opc : 2; + uint32_t _00010 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntTestCompRRR) == 4, " "); + // Integer Test and Compare (one register and immediate) union IntTestCompRI { uint32_t flat; @@ -141,6 +179,25 @@ union LogicalArithRRRI { } __attribute__((packed)); static_assert(sizeof(LogicalArithRRRI) == 4, " "); +// Logical Arithmetic (three register, register shift) +union LogicalArithRRRR { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _1 : 1; + uint32_t type : 2; + uint32_t _0 : 0; + uint32_t rs : 4; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 2; + uint32_t _00011 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(LogicalArithRRRR) == 4, " "); + union LogicalArithmeticRRI { uint32_t flat; struct { @@ -752,8 +809,8 @@ static const char * const kIdpNamesRRR[] = { //101 ADC, ADCS (register) //110 SBC, SBCS (register) //111 RSC, RSCS (register) -static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) { - const IntDataProcessingRRR enc = {bits}; +static bool TryDecodeIntegerDataProcessingRRRI(Instruction &inst, uint32_t bits) { + const IntDataProcessingRRRI enc = {bits}; inst.function = kIdpNamesRRR[ (enc.opc << 1u) | enc.s]; DecodeCondition(inst, enc.cond); @@ -1114,10 +1171,10 @@ static bool TryIntegerTestAndCompareRI(Instruction &inst, uint32_t bits) { // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> static TryDecode * kDataProcessingRI[] = { - [0b000] = TryDecodeIntegerDataProcessingRRR, - [0b001] = TryDecodeIntegerDataProcessingRRR, - [0b010] = TryDecodeIntegerDataProcessingRRR, - [0b011] = TryDecodeIntegerDataProcessingRRR, + [0b000] = TryDecodeIntegerDataProcessingRRRI, + [0b001] = TryDecodeIntegerDataProcessingRRRI, + [0b010] = TryDecodeIntegerDataProcessingRRRI, + [0b011] = TryDecodeIntegerDataProcessingRRRI, [0b100] = nullptr, // op0:op1 != 100 [0b101] = TryIntegerTestAndCompareRRI, [0b110] = TryLogicalArithmeticRRRI, @@ -1218,7 +1275,7 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { // index is the concatenation of op0 and op1 return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; } - // TODO(Sonya): Data-processing register (register shift) -- op4 == 1 + // Data-processing register (register shift) -- op4 == 1 else { return kDataProcessingRR[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; } From 51603203f8879aeee40499c9aa23762f8decb9ca Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 16 Oct 2020 15:44:26 -0400 Subject: [PATCH 037/130] Code status before refactoring operand types --- remill/Arch/AArch32/Decode.cpp | 102 +++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 25 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index c2e391236..fe744710b 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -825,6 +825,21 @@ static bool TryDecodeIntegerDataProcessingRRRI(Instruction &inst, uint32_t bits) return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc]); } +// TODO(Sonya): Integer Data Processing (three register, register shift) +static bool TryDecodeIntegerDataProcessingRRRR(Instruction &inst, uint32_t bits) { + return false; + const IntDataProcessingRRRR enc = { bits }; + + inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s]; + DecodeCondition(inst, enc.cond); + + if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum + || enc.rm == kPCRegNum) { + inst.category = Instruction::kCategoryError; + return false; + } +} + //000 AND, ANDS (immediate) //001 EOR, EORS (immediate) //010 0 != 11x1 SUB, SUBS (immediate) — SUB @@ -990,10 +1005,7 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { } auto instruction = kLoadSWUBIL[enc.P << 3u | enc.W << 2u | enc.o2 << 1u | enc.o1]; - if (!instruction) { - inst.category = Instruction::kCategoryError; - return false; - } + inst.function = instruction; DecodeCondition(inst, enc.cond); @@ -1059,9 +1071,7 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { const LogicalArithRRRI enc = { bits }; auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; - if (!instruction) { - return false; - } + inst.function = instruction; DecodeCondition(inst, enc.cond); @@ -1088,19 +1098,48 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); } +// TODO(Sonya): Logical Arithmetic (three register, register shift) +static bool TryLogicalArithmeticRRRR(Instruction &inst, uint32_t bits) { + return false; + + const LogicalArithRRRR enc = { bits }; + + auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; + + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum + || enc.rm == kPCRegNum) { + inst.category = Instruction::kCategoryError; + return false; + } + + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + // enc.opc == x0 + if (!(enc.opc & 0b1u)) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + } + // enc.opc == 01 + else if (!(enc.opc & 0b10u)) { + AddImmOp(inst, 0); + } + // enc.opc == 11 + else { + AddImmOp(inst, 1); + } +} + // Logical Arithmetic (two register and immediate) static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { const LogicalArithmeticRRI enc = { bits }; - auto instruction = kLogicalArithmeticRRRI[enc.opc]; - if (!instruction) { - return false; - } + auto instruction = kLogicalArithmeticRRRI[enc.opc | enc.s]; + inst.function = instruction; DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); - // enc.opc == x0 if (!(enc.opc & 0b1u)) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); @@ -1135,9 +1174,7 @@ static bool TryIntegerTestAndCompareRRI(Instruction &inst, uint32_t bits) { const IntTestCompRRI enc = { bits }; auto instruction = kIntegerTestAndCompareR[enc.opc]; - if (!instruction) { - return false; - } + inst.function = instruction; DecodeCondition(inst, enc.cond); @@ -1149,14 +1186,29 @@ static bool TryIntegerTestAndCompareRRI(Instruction &inst, uint32_t bits) { return true; } +// TODO(Sonya): Integer Test and Compare (two register, register shift) +static bool TryIntegerTestAndCompareRRR(Instruction &inst, uint32_t bits) { + return false; + + const IntTestCompRRR enc = { bits }; + + auto instruction = kIntegerTestAndCompareR[enc.opc]; + + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + if (enc.rn == kPCRegNum || enc.rs == kPCRegNum || enc.rm == kPCRegNum) { + inst.category = Instruction::kCategoryError; + return false; + } +} + // Integer Test and Compare (one register and immediate) static bool TryIntegerTestAndCompareRI(Instruction &inst, uint32_t bits) { const IntTestCompRI enc = { bits }; auto instruction = kIntegerTestAndCompareR[enc.opc]; - if (!instruction) { - return false; - } + inst.function = instruction; DecodeCondition(inst, enc.cond); @@ -1184,14 +1236,14 @@ static TryDecode * kDataProcessingRI[] = { // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> static TryDecode * kDataProcessingRR[] = { - [0b000] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) - [0b001] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) - [0b010] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) - [0b011] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) + [0b000] = TryDecodeIntegerDataProcessingRRRR, + [0b001] = TryDecodeIntegerDataProcessingRRRR, + [0b010] = TryDecodeIntegerDataProcessingRRRR, + [0b011] = TryDecodeIntegerDataProcessingRRRR, [0b100] = nullptr, // op0:op1 != 100 - [0b101] = nullptr, // TODO(Sonya): Integer Test and Compare (two register, register shift) - [0b110] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, register shift) - [0b111] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, register shift) + [0b101] = TryIntegerTestAndCompareRRR, + [0b110] = TryLogicalArithmeticRRRR, + [0b111] = TryLogicalArithmeticRRRR, }; // Corresponds to Data-processing immediate From 9d745baed6bf78c95ab61e5af2ac4afdf11afa3a Mon Sep 17 00:00:00 2001 From: Peter Goodman Date: Tue, 15 Sep 2020 15:18:19 -0400 Subject: [PATCH 038/130] This branch contains support for new architectures. --- .../remill/Arch/AArch32/Runtime/Operators.h | 32 +++++ include/remill/Arch/AArch32/Runtime/State.h | 113 ++++++++++++++++++ include/remill/Arch/AArch32/Runtime/Types.h | 72 +++++++++++ 3 files changed, 217 insertions(+) create mode 100644 include/remill/Arch/AArch32/Runtime/Operators.h create mode 100644 include/remill/Arch/AArch32/Runtime/State.h create mode 100644 include/remill/Arch/AArch32/Runtime/Types.h diff --git a/include/remill/Arch/AArch32/Runtime/Operators.h b/include/remill/Arch/AArch32/Runtime/Operators.h new file mode 100644 index 000000000..2d3555ee0 --- /dev/null +++ b/include/remill/Arch/AArch32/Runtime/Operators.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace { + +// Read a register directly. Sometimes this is needed for suppressed operands. +ALWAYS_INLINE static addr_t _Read(Memory *, Reg reg) { + return reg.aword; +} + +// Write directly to a register. This is sometimes needed for suppressed +// register operands. +ALWAYS_INLINE static void _Write(Memory *, Reg ®, addr_t val) { + reg.aword = val; +} + +} // namespace diff --git a/include/remill/Arch/AArch32/Runtime/State.h b/include/remill/Arch/AArch32/Runtime/State.h new file mode 100644 index 000000000..bd8558e78 --- /dev/null +++ b/include/remill/Arch/AArch32/Runtime/State.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#pragma clang diagnostic push +#pragma clang diagnostic fatal "-Wpadded" + +#include "remill/Arch/Runtime/State.h" +#include "remill/Arch/Runtime/Types.h" + +struct Reg final { + alignas(4) uint32_t dword; +} __attribute__((packed)); + +static_assert(sizeof(uint32_t) == sizeof(Reg), "Invalid packing of `Reg`."); +static_assert(0 == __builtin_offsetof(Reg, dword), + "Invalid packing of `Reg::dword`."); + +struct alignas(8) GPR final { + + // Prevents LLVM from casting a `GPR` into an `i64` to access `X0`. + volatile uint32_t _0; + Reg r0; + volatile uint32_t _1; + Reg r1; + volatile uint32_t _2; + Reg r2; + volatile uint32_t _3; + Reg r3; + volatile uint32_t _4; + Reg r4; + volatile uint32_t _5; + Reg r5; + volatile uint32_t _6; + Reg r6; + volatile uint32_t _7; + Reg r7; + volatile uint32_t _8; + Reg r8; + volatile uint32_t _9; + Reg r9; + volatile uint32_t _10; + Reg r10; + volatile uint32_t _11; + Reg r11; + volatile uint32_t _12; + Reg r12; + // R13 is SP (stack pointer) + volatile uint32_t _13; + Reg r13; + // R14 is LR (link register) + volatile uint32_t _14; + Reg r14; + // R15 is PC (program counter) + volatile uint32_t _15; + Reg r15; + + +} __attribute__((packed)); + +// System registers affecting control and status of the machine. +struct alignas(8) SR final { + + uint8_t _2; + uint8_t n; // Negative condition flag. + uint8_t _3; + uint8_t z; // Zero condition flag + uint8_t _4; + uint8_t c; // Carry condition flag + uint8_t _5; + uint8_t v; // Overflow condition flag + + uint8_t _6; + uint8_t ixc; // Inexact (cumulative). + uint8_t _7; + uint8_t ofc; // Overflow (cumulative). + uint8_t _8; + uint8_t ufc; // Underflow (cumulative). + uint8_t _9; + uint8_t idc; // Input denormal (cumulative). + uint8_t _10; + uint8_t ioc; // Invalid operation (cumulative). + + uint8_t _padding[6]; +} __attribute__((packed)); + +struct alignas(16) State final : public ArchState { + + + GPR gpr; // 528 bytes. + SR sr; + uint64_t _0; + + +} __attribute__((packed)); + +using AArch32State = State; + +#pragma clang diagnostic pop diff --git a/include/remill/Arch/AArch32/Runtime/Types.h b/include/remill/Arch/AArch32/Runtime/Types.h new file mode 100644 index 000000000..c77e899a5 --- /dev/null +++ b/include/remill/Arch/AArch32/Runtime/Types.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// We need this for boolean conditions, used in branch instructions. +typedef RnW R8W; + +typedef RnW R8W; +typedef RnW R16W; + +// Note: AArch64 zero-extends like x86, but the smallest register size that +// can be accessed is 32 bits. +typedef RnW R32W; + +//typedef Rn R8; +//typedef Rn R16; +typedef Rn R32; + +typedef Vn V8; +typedef Vn V16; +typedef Vn V32; +typedef Vn V64; +typedef Vn V128; +typedef VnW V128W; + +typedef MnW M8W; +typedef MnW M16W; +typedef MnW M32W; +typedef MnW M64W; + +typedef MVnW MV8W; +typedef MVnW MV16W; +typedef MVnW MV32W; +typedef MVnW MV64W; +typedef MVnW MV128W; + +typedef Mn M8; +typedef Mn M16; + +typedef Mn M32; +typedef Mn M64; + +typedef MVn MV8; +typedef MVn MV16; +typedef MVn MV32; +typedef MVn MV64; +typedef MVn MV128; +typedef MVn MV256; + +typedef In I8; +typedef In I16; +typedef In I32; + +typedef In F32; +typedef In F64; + +typedef In PC; +typedef In ADDR; From 0b9eea921e102c0fc82c4a3bcd6ecda5f0b4a3f1 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 15 Sep 2020 17:16:40 -0400 Subject: [PATCH 039/130] Initial start to support for AArch 32 --- CMakeLists.txt | 3 + include/remill/Arch/Arch.h | 5 + include/remill/Arch/Runtime/HyperCall.h | 1 + lib/Arch/Arch.cpp | 11 +- lib/Arch/Instruction.cpp | 1 + lib/Arch/Name.cpp | 6 + remill/Arch/AArch32/Arch.cpp | 233 +++++++++++++++++++ remill/Arch/AArch32/Runtime/BasicBlock.cpp | 36 +++ remill/Arch/AArch32/Runtime/CMakeLists.txt | 57 +++++ remill/Arch/AArch32/Runtime/Instructions.cpp | 74 ++++++ remill/Arch/AArch32/Runtime/State.h | 85 +++++++ 11 files changed, 511 insertions(+), 1 deletion(-) create mode 100644 remill/Arch/AArch32/Arch.cpp create mode 100644 remill/Arch/AArch32/Runtime/BasicBlock.cpp create mode 100644 remill/Arch/AArch32/Runtime/CMakeLists.txt create mode 100644 remill/Arch/AArch32/Runtime/Instructions.cpp create mode 100644 remill/Arch/AArch32/Runtime/State.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e6b4f18f..e46b0e1b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,6 +179,7 @@ else() endif() set(REMILL_BUILD_SEMANTICS_DIR_X86 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/X86/Runtime") +set(REMILL_BUILD_SEMANTICS_DIR_AARCH32 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/AArch32/Runtime") set(REMILL_BUILD_SEMANTICS_DIR_AARCH64 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/AArch64/Runtime") set(REMILL_BUILD_SEMANTICS_DIR_SPARC32 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/SPARC32/Runtime") set(REMILL_BUILD_SEMANTICS_DIR_SPARC64 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/SPARC64/Runtime") @@ -261,6 +262,7 @@ endif() target_compile_definitions(remill_settings INTERFACE "REMILL_INSTALL_SEMANTICS_DIR=\"${REMILL_INSTALL_SEMANTICS_DIR}/\"" "REMILL_BUILD_SEMANTICS_DIR_X86=\"${REMILL_BUILD_SEMANTICS_DIR_X86}\"" + "REMILL_BUILD_SEMANTICS_DIR_AARCH32=\"${REMILL_BUILD_SEMANTICS_DIR_AARCH32}\"" "REMILL_BUILD_SEMANTICS_DIR_AARCH64=\"${REMILL_BUILD_SEMANTICS_DIR_AARCH64}\"" "REMILL_BUILD_SEMANTICS_DIR_SPARC32=\"${REMILL_BUILD_SEMANTICS_DIR_SPARC32}\"" "REMILL_BUILD_SEMANTICS_DIR_SPARC64=\"${REMILL_BUILD_SEMANTICS_DIR_SPARC64}\"" @@ -343,6 +345,7 @@ endif() set(REMILL_BC_LIBRARY_LOCATION "${REMILL_INSTALL_LIB_DIR}/${static_lib_prefix}remill_bc.${static_lib_extension}") set(REMILL_ARCH_LIBRARY_LOCATION "${REMILL_INSTALL_LIB_DIR}/${static_lib_prefix}remill_arch.${static_lib_extension}") set(REMILL_ARCH_X86_LIBRARY_LOCATION "${REMILL_INSTALL_LIB_DIR}/${static_lib_prefix}remill_arch_x86.${static_lib_extension}") +set(REMILL_ARCH_AARCH32_LIBRARY_LOCATION "${REMILL_INSTALL_LIB_DIR}/${static_lib_prefix}remill_arch_aarch32.${static_lib_extension}") set(REMILL_ARCH_AARCH64_LIBRARY_LOCATION "${REMILL_INSTALL_LIB_DIR}/${static_lib_prefix}remill_arch_aarch64.${static_lib_extension}") set(REMILL_ARCH_SPARC32_LIBRARY_LOCATION "${REMILL_INSTALL_LIB_DIR}/${static_lib_prefix}remill_arch_sparc32.${static_lib_extension}") set(REMILL_ARCH_SPARC64_LIBRARY_LOCATION "${REMILL_INSTALL_LIB_DIR}/${static_lib_prefix}remill_arch_sparc64.${static_lib_extension}") diff --git a/include/remill/Arch/Arch.h b/include/remill/Arch/Arch.h index 4440e079c..ecbbb1cbb 100644 --- a/include/remill/Arch/Arch.h +++ b/include/remill/Arch/Arch.h @@ -244,6 +244,7 @@ class Arch { bool IsX86(void) const; bool IsAMD64(void) const; + bool IsAArch32(void) const; bool IsAArch64(void) const; bool IsSPARC32(void) const; bool IsSPARC64(void) const; @@ -285,6 +286,10 @@ class Arch { static ArchPtr GetX86(llvm::LLVMContext *context, OSName os, ArchName arch_name); + // Defined in `lib/Arch/AArch32/Arch.cpp`. + static ArchPtr GetAArch32(llvm::LLVMContext *context, OSName os, + ArchName arch_name); + // Defined in `lib/Arch/AArch64/Arch.cpp`. static ArchPtr GetAArch64(llvm::LLVMContext *context, OSName os, ArchName arch_name); diff --git a/include/remill/Arch/Runtime/HyperCall.h b/include/remill/Arch/Runtime/HyperCall.h index b9c086323..d5058c8de 100644 --- a/include/remill/Arch/Runtime/HyperCall.h +++ b/include/remill/Arch/Runtime/HyperCall.h @@ -60,6 +60,7 @@ class SyncHyperCall { // TODO(pag): How to distinguish little- and big-endian? kAArch64EmulateInstruction = 0x200U, kAArch64Breakpoint, + kAArch32EmulateInstruction = 0x300U, kSPARC32EmulateInstruction = 0x400U, kSPARC64EmulateInstruction, diff --git a/lib/Arch/Arch.cpp b/lib/Arch/Arch.cpp index bcb76740c..0ba5a7031 100644 --- a/lib/Arch/Arch.cpp +++ b/lib/Arch/Arch.cpp @@ -46,7 +46,7 @@ DEFINE_string(arch, REMILL_ARCH, "Architecture of the code being translated. " "Valid architectures: x86, amd64 (with or without " - "`_avx` or `_avx512` appended), aarch64"); + "`_avx` or `_avx512` appended), aarch64, aarch32"); DECLARE_string(os); @@ -81,6 +81,7 @@ static unsigned AddressSize(ArchName arch_name) { case kArchX86: case kArchX86_AVX: case kArchX86_AVX512: + case kArchAArch32LittleEndian: case kArchSparc32: return 32; case kArchAMD64: @@ -173,6 +174,11 @@ auto Arch::Build(llvm::LLVMContext *context_, OSName os_name_, return GetAArch64(context_, os_name_, arch_name_); } + case kArchAArch32LittleEndian: { + DLOG(INFO) << "Using architecture: AArch32, feature set: Little Endian"; + return GetAArch32(context_, os_name_, arch_name_); + } + case kArchX86: { DLOG(INFO) << "Using architecture: X86"; return GetX86(context_, os_name_, arch_name_); @@ -357,6 +363,9 @@ bool Arch::IsAMD64(void) const { } } +bool Arch::IsAArch32(void) const { + return remill::kArchAArch32LittleEndian == arch_name; + bool Arch::IsAArch64(void) const { return remill::kArchAArch64LittleEndian == arch_name; } diff --git a/lib/Arch/Instruction.cpp b/lib/Arch/Instruction.cpp index c2eb72516..de5d9b334 100644 --- a/lib/Arch/Instruction.cpp +++ b/lib/Arch/Instruction.cpp @@ -271,6 +271,7 @@ std::string Instruction::Serialize(void) const { case kArchX86: case kArchX86_AVX: case kArchX86_AVX512: ss << "X86"; break; + case kArchAArch32LittleEndian: ss << "AArch32"; break; case kArchAArch64LittleEndian: ss << "AArch64"; break; case kArchSparc32: ss << "SPARC32"; break; case kArchSparc64: ss << "SPARC64"; break; diff --git a/lib/Arch/Name.cpp b/lib/Arch/Name.cpp index d84dc1fee..4643f5516 100644 --- a/lib/Arch/Name.cpp +++ b/lib/Arch/Name.cpp @@ -25,6 +25,8 @@ ArchName GetArchName(const llvm::Triple &triple) { case llvm::Triple::ArchType::x86: return kArchX86; case llvm::Triple::ArchType::x86_64: return kArchAMD64; case llvm::Triple::ArchType::aarch64: return kArchAArch64LittleEndian; + case llvm::Triple::ArchType::arm: return kArchAArch32LittleEndian; + case llvm::Triple::ArchType::thumb: return kArchAArch32LittleEndian; default: return kArchInvalid; } } @@ -48,6 +50,9 @@ ArchName GetArchName(std::string_view arch_name) { } else if (arch_name == "amd64_avx512") { return kArchAMD64_AVX512; + } else if (arch_name == "aarch32") { + return kArchAArch32LittleEndian; + } else if (arch_name == "aarch64") { return kArchAArch64LittleEndian; @@ -72,6 +77,7 @@ static const std::string_view kArchNames[] = { [kArchAMD64] = "amd64", [kArchAMD64_AVX] = "amd64_avx", [kArchAMD64_AVX512] = "amd64_avx512", + [kArchAArch32LittleEndian] = "aarch32", [kArchAArch64LittleEndian] = "aarch64", [kArchSparc32] = "sparc32", [kArchSparc64] = "sparc64", diff --git a/remill/Arch/AArch32/Arch.cpp b/remill/Arch/AArch32/Arch.cpp new file mode 100644 index 000000000..79a71d157 --- /dev/null +++ b/remill/Arch/AArch32/Arch.cpp @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "remill/Arch/Arch.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "remill/Arch/Instruction.h" +#include "remill/Arch/Name.h" +#include "remill/BC/ABI.h" +#include "remill/BC/Util.h" +#include "remill/BC/Version.h" +#include "remill/OS/OS.h" + +// clang-format off +#define ADDRESS_SIZE 32 +#include "Runtime/State.h" + +// clang-format on + +namespace remill { +namespace { + + + +class AArch32Arch final : public Arch { + public: + AArch32Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_); + + virtual ~AArch32Arch(void); + + // Returns the name of the stack pointer register. + const char *StackPointerRegisterName(void) const override; + + // Returns the name of the program counter register. + const char *ProgramCounterRegisterName(void) const override; + + // Decode an instuction. + bool DecodeInstruction(uint64_t address, std::string_view inst_bytes, + Instruction &inst) const override; + + // Maximum number of bytes in an instruction. + uint64_t MaxInstructionSize(void) const override; + + llvm::Triple Triple(void) const override; + llvm::DataLayout DataLayout(void) const override; + + // Default calling convention for this architecture. + llvm::CallingConv::ID DefaultCallingConv(void) const override; + + // Populate the `__remill_basic_block` function with variables. + void PopulateBasicBlockFunction(llvm::Module *module, + llvm::Function *bb_func) const override; + + private: + // Decode an instuction. + bool DecodeInstruction(uint64_t address, std::string_view inst_bytes, + Instruction &inst, bool is_lazy) const; + + AArch32Arch(void) = delete; +}; + +AArch32Arch::AArch32Arch(llvm::LLVMContext *context_, OSName os_name_, + ArchName arch_name_) + : Arch(context_, os_name_, arch_name_) {} + +AArch32Arch::~AArch32Arch(void) {} + +// Maximum number of bytes in an instruction for this particular architecture. +uint64_t AArch32Arch::MaxInstructionSize(void) const { + return 4; +} + +// Default calling convention for this architecture. +llvm::CallingConv::ID AArch32Arch::DefaultCallingConv(void) const { + return llvm::CallingConv::C; // cdecl. +} + +// Get the LLVM triple for this architecture. +llvm::Triple AArch32Arch::Triple(void) const { + auto triple = BasicTriple(); + switch (arch_name) { + case kArchAArch32LittleEndian: triple.setArch(llvm::Triple::arm); break; + default: + LOG(FATAL) << "Cannot get triple for non-aarch32 architecture " + << GetArchName(arch_name); + } + + return triple; +} + +// Get the LLVM DataLayout for a module. +llvm::DataLayout AArch32Arch::DataLayout(void) const { + std::string dl; + switch (os_name) { + case kOSInvalid: + LOG(FATAL) << "Cannot convert module for an unrecognized OS."; + break; + + case kOSLinux: + case kOSSolaris: + case kOSmacOS: + case kOSWindows: + dl = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"; + break; + } + + return llvm::DataLayout(dl); +} + +// Decode an instuction. +bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes, + Instruction &inst, bool is_lazy) const { + + inst.pc = address; + inst.arch_name = arch_name; + inst.category = Instruction::kCategoryInvalid; + + return false; +} + +// Returns the name of the stack pointer register. +const char *AArch32Arch::StackPointerRegisterName(void) const { + return "SP"; +} + +// Returns the name of the program counter register. +const char *AArch32Arch::ProgramCounterRegisterName(void) const { + return "PC"; +} + +bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes, + Instruction &inst) const { + inst.arch_for_decode = this; + return DecodeInstruction(address, inst_bytes, inst, false); +} + +// Populate the `__remill_basic_block` function with variables. +void AArch32Arch::PopulateBasicBlockFunction(llvm::Module *module, + llvm::Function *bb_func) const { + const auto &dl = module->getDataLayout(); + CHECK_EQ(sizeof(State), dl.getTypeAllocSize(StateStructType())) + << "Mismatch between size of State type for x86/amd64 and what is in " + << "the bitcode module"; + + auto &context = module->getContext(); +// auto u8 = llvm::Type::getInt8Ty(context); +// auto u16 = llvm::Type::getInt16Ty(context); + auto u32 = llvm::Type::getInt32Ty(context); +// auto u64 = llvm::Type::getInt64Ty(context); +// auto f64 = llvm::Type::getDoubleTy(context); +// auto v128 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 128u / 8u); +// auto v256 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 256u / 8u); +// auto v512 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 512u / 8u); + auto addr = llvm::Type::getIntNTy(context, address_size); + //auto zero_addr_val = llvm::Constant::getNullValue(addr); + + const auto entry_block = &bb_func->getEntryBlock(); + llvm::IRBuilder<> ir(entry_block); + +#define OFFSET_OF(type, access) \ + (reinterpret_cast(&reinterpret_cast( \ + static_cast(nullptr)->access))) + +#define REG(name, access, type) \ + AddRegister(#name, type, OFFSET_OF(State, access), nullptr) + +#define SUB_REG(name, access, type, parent_reg_name) \ + AddRegister(#name, type, OFFSET_OF(State, access), #parent_reg_name) + + REG(R0, gpr.r0.dword, u32); + REG(R1, gpr.r1.dword, u32); + REG(R2, gpr.r2.dword, u32); + REG(R3, gpr.r3.dword, u32); + REG(R4, gpr.r4.dword, u32); + REG(R5, gpr.r5.dword, u32); + REG(R6, gpr.r6.dword, u32); + REG(R7, gpr.r7.dword, u32); + REG(R8, gpr.r8.dword, u32); + REG(R9, gpr.r9.dword, u32); + REG(R10, gpr.r10.dword, u32); + REG(R11, gpr.r11.dword, u32); + REG(R12, gpr.r12.dword, u32); + REG(R13, gpr.r13.dword, u32); + REG(R14, gpr.r14.dword, u32); + REG(R15, gpr.r15.dword, u32); + + SUB_REG(SP, gpr.r13.dword, u32, R13); + SUB_REG(LR, gpr.r14.dword, u32, R14); + SUB_REG(PC, gpr.r15.dword, u32, R15); + + const auto pc_arg = NthArgument(bb_func, kPCArgNum); + const auto state_ptr_arg = NthArgument(bb_func, kStatePointerArgNum); + ir.CreateStore(pc_arg, ir.CreateAlloca(addr, nullptr, "NEXT_PC")); + + ir.CreateAlloca(u32, nullptr, "SUPPRESS_WRITEBACK"); + (void) this->RegisterByName("PC")->AddressOf(state_ptr_arg, ir); +} + +} // namespace + +// TODO(pag): We pretend that these are singletons, but they aren't really! +Arch::ArchPtr Arch::GetAArch32(llvm::LLVMContext *context_, OSName os_name_, + ArchName arch_name_) { + return std::make_unique(context_, os_name_, arch_name_); +} + +} // namespace remill diff --git a/remill/Arch/AArch32/Runtime/BasicBlock.cpp b/remill/Arch/AArch32/Runtime/BasicBlock.cpp new file mode 100644 index 000000000..7619fde1f --- /dev/null +++ b/remill/Arch/AArch32/Runtime/BasicBlock.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "remill/Arch/AArch32/Runtime/State.h" +#include "remill/Arch/Float.h" + +extern "C" { + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-variable" + +// Instructions will be lifted into clones of this function. +[[gnu::used]] Memory *__remill_basic_block(State &, addr_t, Memory *); + +#pragma clang diagnostic pop + +} // extern C + +#include "remill/Arch/Runtime/Intrinsics.cpp" diff --git a/remill/Arch/AArch32/Runtime/CMakeLists.txt b/remill/Arch/AArch32/Runtime/CMakeLists.txt new file mode 100644 index 000000000..804315222 --- /dev/null +++ b/remill/Arch/AArch32/Runtime/CMakeLists.txt @@ -0,0 +1,57 @@ +# Copyright (c) 2017 Trail of Bits, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.2) +project(arm_runtime) + +set(ARMRUNTIME_SOURCEFILES + Instructions.cpp + BasicBlock.cpp +) + +set_source_files_properties(Instructions.cpp PROPERTIES COMPILE_FLAGS "-O3 -g0") +set_source_files_properties(BasicBlock.cpp PROPERTIES COMPILE_FLAGS "-O0 -g3") + +if(DEFINED WIN32) + set(install_folder "${CMAKE_INSTALL_PREFIX}/remill/${REMILL_LLVM_VERSION}/semantics") +else() + set(install_folder "${CMAKE_INSTALL_PREFIX}/share/remill/${REMILL_LLVM_VERSION}/semantics") +endif() + +function(add_runtime_helper target_name address_bit_size little_endian) + message(" > Generating runtime target: ${target_name}") + + # Visual C++ requires C++14 + if(WIN32) + set(required_cpp_standard "c++14") + else() + set(required_cpp_standard "c++17") + endif() + + add_runtime(${target_name} + SOURCES ${ARMRUNTIME_SOURCEFILES} + ADDRESS_SIZE ${address_bit_size} + DEFINITIONS "LITTLE_ENDIAN=${little_endian}" + BCFLAGS "-std=${required_cpp_standard}" + INCLUDEDIRECTORIES "${CMAKE_SOURCE_DIR}" + INSTALLDESTINATION "${install_folder}" + + DEPENDENCIES + + ) +endfunction() + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + add_runtime_helper(aarch32 32 1) +endif() diff --git a/remill/Arch/AArch32/Runtime/Instructions.cpp b/remill/Arch/AArch32/Runtime/Instructions.cpp new file mode 100644 index 000000000..cea35d7a9 --- /dev/null +++ b/remill/Arch/AArch32/Runtime/Instructions.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +// clang-format off +#include "remill/Arch/Float.h" +#include "remill/Arch/Runtime/Intrinsics.h" +#include "remill/Arch/Runtime/Operators.h" +#include "remill/Arch/AArch32/Runtime/State.h" +//#include "remill/Arch/AArch32/Runtime/Types.h" +//#include "remill/Arch/AArch32/Runtime/Operators.h" + +// clang-format on + +#define REG_PC state.gpr.r15.dword +#define REG_SP state.gpr.r13.dword + +#define HYPER_CALL state.hyper_call +#define INTERRUPT_VECTOR state.hyper_call_vector +#define HYPER_CALL_VECTOR state.hyper_call_vector + +namespace { + +// Takes the place of an unsupported instruction. +DEF_SEM(HandleUnsupported) { + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kAArch32EmulateInstruction); +} + +// Takes the place of an invalid instruction. +DEF_SEM(HandleInvalidInstruction) { + HYPER_CALL = AsyncHyperCall::kInvalidInstruction; + return memory; +} + +} // namespace + +// Takes the place of an unsupported instruction. +DEF_ISEL(UNSUPPORTED_INSTRUCTION) = HandleUnsupported; +DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; + +// clang-format off +//#include "remill/Arch/AArch64/Semantics/FLAGS.cpp" +// +//#include "remill/Arch/AArch64/Semantics/BINARY.cpp" +//#include "remill/Arch/AArch64/Semantics/BITBYTE.cpp" +//#include "remill/Arch/AArch64/Semantics/BRANCH.cpp" +//#include "remill/Arch/AArch64/Semantics/CALL_RET.cpp" +//#include "remill/Arch/AArch64/Semantics/COND.cpp" +//#include "remill/Arch/AArch64/Semantics/CONVERT.cpp" +//#include "remill/Arch/AArch64/Semantics/DATAXFER.cpp" +//#include "remill/Arch/AArch64/Semantics/LOGICAL.cpp" +//#include "remill/Arch/AArch64/Semantics/MISC.cpp" +//#include "remill/Arch/AArch64/Semantics/SHIFT.cpp" +//#include "remill/Arch/AArch64/Semantics/SIMD.cpp" +//#include "remill/Arch/AArch64/Semantics/SYSTEM.cpp" + +// clang-format on diff --git a/remill/Arch/AArch32/Runtime/State.h b/remill/Arch/AArch32/Runtime/State.h new file mode 100644 index 000000000..92ca82b57 --- /dev/null +++ b/remill/Arch/AArch32/Runtime/State.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#pragma clang diagnostic push +#pragma clang diagnostic fatal "-Wpadded" + +#include "remill/Arch/Runtime/State.h" +#include "remill/Arch/Runtime/Types.h" + +struct Reg final { + alignas(4) uint32_t dword; +} __attribute__((packed)); + +static_assert(sizeof(uint32_t) == sizeof(Reg), "Invalid packing of `Reg`."); +static_assert(0 == __builtin_offsetof(Reg, dword), + "Invalid packing of `Reg::dword`."); + +struct alignas(8) GPR final { + + // Prevents LLVM from casting a `GPR` into an `i64` to access `X0`. + volatile uint32_t _0; + Reg r0; + volatile uint32_t _1; + Reg r1; + volatile uint32_t _2; + Reg r2; + volatile uint32_t _3; + Reg r3; + volatile uint32_t _4; + Reg r4; + volatile uint32_t _5; + Reg r5; + volatile uint32_t _6; + Reg r6; + volatile uint32_t _7; + Reg r7; + volatile uint32_t _8; + Reg r8; + volatile uint32_t _9; + Reg r9; + volatile uint32_t _10; + Reg r10; + volatile uint32_t _11; + Reg r11; + volatile uint32_t _12; + Reg r12; + // R13 is SP (stack pointer) + volatile uint32_t _13; + Reg r13; + // R14 is LR (link register) + volatile uint32_t _14; + Reg r14; + // R15 is PC (program counter) + volatile uint32_t _15; + Reg r15; + + +} __attribute__((packed)); + +struct alignas(16) State final : public ArchState { + + + GPR gpr; // 528 bytes. + + +} __attribute__((packed)); + +using AArch32State = State; + +#pragma clang diagnostic pop From e4c7760016b308f88aa928a1adf7c64e64868c76 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 17 Sep 2020 14:53:19 -0400 Subject: [PATCH 040/130] Progress --- include/remill/Arch/Instruction.h | 21 +++++++++++ lib/Arch/Instruction.cpp | 35 +++++++++++++++++ remill/Arch/AArch32/Arch.cpp | 63 +------------------------------ 3 files changed, 58 insertions(+), 61 deletions(-) diff --git a/include/remill/Arch/Instruction.h b/include/remill/Arch/Instruction.h index 753dfbbba..290430d74 100644 --- a/include/remill/Arch/Instruction.h +++ b/include/remill/Arch/Instruction.h @@ -127,6 +127,22 @@ class Operand { std::string Serialize(void) const; }; +class Condition { + public: + + enum Kind { + kTypeTrue, + kTypeIsOne, + kTypeIsZero, + kTypeIsEqual, + } kind; + + Operand::Register lhs_reg; + Operand::Register rhs_reg; + + std::string Serialize(void) const; +}; + // Generic instruction type. class Instruction { public: @@ -173,6 +189,10 @@ class Instruction { // Is this instruction decoded within the context of a delay slot? bool in_delay_slot; + // If `conditions` is non-empty then this tells us if we should negate the + // result of the condition. + bool negate_conditions; + enum Category { kCategoryInvalid, kCategoryNormal, @@ -189,6 +209,7 @@ class Instruction { } category; std::vector operands; + std::vector conditions; std::string Serialize(void) const; diff --git a/lib/Arch/Instruction.cpp b/lib/Arch/Instruction.cpp index de5d9b334..4890608d0 100644 --- a/lib/Arch/Instruction.cpp +++ b/lib/Arch/Instruction.cpp @@ -216,6 +216,30 @@ std::string Operand::Serialize(void) const { return ss.str(); } +std::string Condition::Serialize(void) const { + std::stringstream ss; + + ss << "("; + switch (kind) { + case Condition::kTypeIsEqual: + ss << "(REG_" << lhs_reg.size << " " << lhs_reg.name << ") = (REG_" + << rhs_reg.size << " " << rhs_reg.name << ")"; + break; + case Condition::kTypeIsOne: + ss << "(REG_" << lhs_reg.size << " " << lhs_reg.name << ") = 1"; + break; + case Condition::kTypeIsZero: + ss << "(REG_" << lhs_reg.size << " " << lhs_reg.name << ") = 0"; + break; + case Condition::kTypeTrue: + ss << "TRUE"; + break; + + } + return ss.str(); +} + + Instruction::Instruction(void) : pc(0), next_pc(0), @@ -228,6 +252,7 @@ Instruction::Instruction(void) has_branch_taken_delay_slot(false), has_branch_not_taken_delay_slot(false), in_delay_slot(false), + negate_conditions(false), category(Instruction::kCategoryInvalid) {} void Instruction::Reset(void) { @@ -241,9 +266,11 @@ void Instruction::Reset(void) { has_branch_taken_delay_slot = false; has_branch_not_taken_delay_slot = false; in_delay_slot = false; + negate_conditions = false; category = Instruction::kCategoryInvalid; arch_for_decode = nullptr; operands.clear(); + conditions.clear(); function.clear(); bytes.clear(); } @@ -355,6 +382,14 @@ std::string Instruction::Serialize(void) const { default: break; } + auto end = ""; + auto sep = " (CONDS "; + for (const auto &cond: conditions) { + ss << sep << cond.Serialize(); + sep = " AND "; + end = ")"; + } + ss << end; ss << ")"; return ss.str(); } diff --git a/remill/Arch/AArch32/Arch.cpp b/remill/Arch/AArch32/Arch.cpp index 79a71d157..1abbeb399 100644 --- a/remill/Arch/AArch32/Arch.cpp +++ b/remill/Arch/AArch32/Arch.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "remill/Arch/Arch.h" +#include "Arch.h" #include #include @@ -44,46 +44,6 @@ // clang-format on namespace remill { -namespace { - - - -class AArch32Arch final : public Arch { - public: - AArch32Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_); - - virtual ~AArch32Arch(void); - - // Returns the name of the stack pointer register. - const char *StackPointerRegisterName(void) const override; - - // Returns the name of the program counter register. - const char *ProgramCounterRegisterName(void) const override; - - // Decode an instuction. - bool DecodeInstruction(uint64_t address, std::string_view inst_bytes, - Instruction &inst) const override; - - // Maximum number of bytes in an instruction. - uint64_t MaxInstructionSize(void) const override; - - llvm::Triple Triple(void) const override; - llvm::DataLayout DataLayout(void) const override; - - // Default calling convention for this architecture. - llvm::CallingConv::ID DefaultCallingConv(void) const override; - - // Populate the `__remill_basic_block` function with variables. - void PopulateBasicBlockFunction(llvm::Module *module, - llvm::Function *bb_func) const override; - - private: - // Decode an instuction. - bool DecodeInstruction(uint64_t address, std::string_view inst_bytes, - Instruction &inst, bool is_lazy) const; - - AArch32Arch(void) = delete; -}; AArch32Arch::AArch32Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_) @@ -133,17 +93,6 @@ llvm::DataLayout AArch32Arch::DataLayout(void) const { return llvm::DataLayout(dl); } -// Decode an instuction. -bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes, - Instruction &inst, bool is_lazy) const { - - inst.pc = address; - inst.arch_name = arch_name; - inst.category = Instruction::kCategoryInvalid; - - return false; -} - // Returns the name of the stack pointer register. const char *AArch32Arch::StackPointerRegisterName(void) const { return "SP"; @@ -154,12 +103,6 @@ const char *AArch32Arch::ProgramCounterRegisterName(void) const { return "PC"; } -bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes, - Instruction &inst) const { - inst.arch_for_decode = this; - return DecodeInstruction(address, inst_bytes, inst, false); -} - // Populate the `__remill_basic_block` function with variables. void AArch32Arch::PopulateBasicBlockFunction(llvm::Module *module, llvm::Function *bb_func) const { @@ -222,8 +165,6 @@ void AArch32Arch::PopulateBasicBlockFunction(llvm::Module *module, (void) this->RegisterByName("PC")->AddressOf(state_ptr_arg, ir); } -} // namespace - // TODO(pag): We pretend that these are singletons, but they aren't really! Arch::ArchPtr Arch::GetAArch32(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_) { From 025255c190e98f621bdb299aac854bd162eb190e Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 17 Sep 2020 14:59:30 -0400 Subject: [PATCH 041/130] Forgot the new files --- remill/Arch/AArch32/Arch.h | 55 +++++ remill/Arch/AArch32/Decode.cpp | 417 +++++++++++++++++++++++++++++++++ 2 files changed, 472 insertions(+) create mode 100644 remill/Arch/AArch32/Arch.h create mode 100644 remill/Arch/AArch32/Decode.cpp diff --git a/remill/Arch/AArch32/Arch.h b/remill/Arch/AArch32/Arch.h new file mode 100644 index 000000000..1f8e8e5be --- /dev/null +++ b/remill/Arch/AArch32/Arch.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "remill/Arch/Arch.h" + +namespace remill { +class AArch32Arch final : public Arch { + public: + AArch32Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_); + + virtual ~AArch32Arch(void); + + // Returns the name of the stack pointer register. + const char *StackPointerRegisterName(void) const override; + + // Returns the name of the program counter register. + const char *ProgramCounterRegisterName(void) const override; + + // Decode an instuction. + bool DecodeInstruction(uint64_t address, std::string_view inst_bytes, + Instruction &inst) const override; + + // Maximum number of bytes in an instruction. + uint64_t MaxInstructionSize(void) const override; + + llvm::Triple Triple(void) const override; + llvm::DataLayout DataLayout(void) const override; + + // Default calling convention for this architecture. + llvm::CallingConv::ID DefaultCallingConv(void) const override; + + // Populate the `__remill_basic_block` function with variables. + void PopulateBasicBlockFunction(llvm::Module *module, + llvm::Function *bb_func) const override; + + private: + AArch32Arch(void) = delete; +}; + +} // namespace remill diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp new file mode 100644 index 000000000..be320ab09 --- /dev/null +++ b/remill/Arch/AArch32/Decode.cpp @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Arch.h" + +#include + +namespace remill { + +namespace { + +//Integer Data Processing (three register, immediate shift) +union IntDataProcessing { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _0 : 1; + uint32_t type : 2; + uint32_t imm5 : 5; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 3; + uint32_t _0000 : 4; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntDataProcessing) == 4, " "); + +static constexpr auto kPCRegNum = 15u; + +static const char * const kIntRegName[] = { + "R0", + "R1", + "R2", + "R3", + "R4", + "R5", + "R6", + "R7", + "R8", + "R9", + "R10", + "R11", + "R12", + "R13", + "R14", + "R15" +}; + +static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, + Operand::Action action) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.type = Operand::kTypeRegister; + op.size = size; + op.action = action; + op.reg.size = size; + op.reg.name = kIntRegName[index]; +} + +// Note: Order is significant; extracted bits may be casted to this type. +enum Shift : uint32_t { kShiftLSL, kShiftLSR, kShiftASR, kShiftROR }; + +// Translate a shift encoding into an operand shift type used by the shift +// register class. +static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { + switch (s) { + case kShiftLSL: + return Operand::ShiftRegister::kShiftLeftWithZeroes; + case kShiftLSR: + return Operand::ShiftRegister::kShiftUnsignedRight; + case kShiftASR: + return Operand::ShiftRegister::kShiftSignedRight; + case kShiftROR: + return Operand::ShiftRegister::kShiftRightAround; + } + return Operand::ShiftRegister::kShiftInvalid; +} + +static void AddShiftRegOperand(Instruction &inst, + uint32_t reg_num, uint32_t shift_type, + uint32_t shift_size) { + if (!shift_size) { + AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); + } else { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.shift_reg.reg.name = kIntRegName[reg_num]; + op.shift_reg.reg.size = 32; + op.shift_reg.shift_op = GetOperandShift(static_cast(shift_type)); + if (shift_type == Shift::kShiftLSR || shift_type == Shift::kShiftASR) { + if (!shift_size) { + shift_size = 32; + } + } else if (shift_type == Shift::kShiftROR) { + LOG_IF(FATAL, !shift_size) + << "Invalid use of AddShiftRegOperand RRX shifts not supported"; + } + op.shift_reg.shift_size = shift_size; + op.type = Operand::kTypeShiftRegister; + op.size = 32; + op.action = Operand::kActionRead; + } +} + +// Decode the condition field and fil in the instruction conditions accordingly +static void DecodeCondition(Instruction &inst, uint32_t cond) { + inst.conditions.emplace_back(); + auto &lhs_cond = inst.conditions.back(); + + switch (cond) { + case 0b0001: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b0000: { + lhs_cond.kind = Condition::kTypeIsOne; + lhs_cond.lhs_reg.name = "Z"; + lhs_cond.lhs_reg.size = 8; + break; + } + case 0b0011: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b0010: { + lhs_cond.kind = Condition::kTypeIsOne; + lhs_cond.lhs_reg.name = "C"; + lhs_cond.lhs_reg.size = 8; + break; + } + case 0b0101: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b0100: { + lhs_cond.kind = Condition::kTypeIsOne; + lhs_cond.lhs_reg.name = "N"; + lhs_cond.lhs_reg.size = 8; + break; + } + case 0b0111: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b0110: { + lhs_cond.kind = Condition::kTypeIsOne; + lhs_cond.lhs_reg.name = "V"; + lhs_cond.lhs_reg.size = 8; + break; + } + case 0b1001: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b1000: { + lhs_cond.kind = Condition::kTypeIsOne; + lhs_cond.lhs_reg.name = "C"; + lhs_cond.lhs_reg.size = 8; + + inst.conditions.emplace_back(); + auto &rhs_cond = inst.conditions.back(); + rhs_cond.kind = Condition::kTypeIsZero; + rhs_cond.rhs_reg.name = "Z"; + rhs_cond.rhs_reg.size = 8; + break; + } + case 0b1011: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b1010: { + lhs_cond.kind = Condition::kTypeIsEqual; + lhs_cond.lhs_reg.name = "N"; + lhs_cond.lhs_reg.size = 8; + + lhs_cond.rhs_reg.name = "V"; + lhs_cond.rhs_reg.size = 8; + break; + } + case 0b1101: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b1100: { + lhs_cond.kind = Condition::kTypeIsEqual; + lhs_cond.lhs_reg.name = "N"; + lhs_cond.lhs_reg.size = 8; + + lhs_cond.rhs_reg.name = "V"; + lhs_cond.rhs_reg.size = 8; + + inst.conditions.emplace_back(); + auto &rhs_cond = inst.conditions.back(); + rhs_cond.kind = Condition::kTypeIsZero; + rhs_cond.rhs_reg.name = "Z"; + rhs_cond.rhs_reg.size = 8; + break; + } + case 0b1111: + case 0b1110: + inst.conditions.pop_back(); + break; + default: + LOG(FATAL) << "Invalid condition bits " << cond << " in " << inst.Serialize(); + break; + } +} + +static bool TryDecodeIntegerDataProcessing(Instruction &inst, uint32_t bits) { + const IntDataProcessing enc = {bits}; + if (enc.cond == 0b1111u) { + return false; + } + if (enc.opc == 0b010u || enc.opc == 0b100u) { + + } + + DecodeCondition(inst, enc.cond); + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); + + if (enc.rd == kPCRegNum) { + inst.category = Instruction::kCategoryIndirectJump; + } else { + inst.category = Instruction::kCategoryNormal; + } + + return true; +} + +static bool (*const kBits27_to_21[])(Instruction&, uint32_t) = { + [0b0000000] = TryDecodeIntegerDataProcessing, + [0b0000001] = TryDecodeIntegerDataProcessing, + [0b0000010] = TryDecodeIntegerDataProcessing, + [0b0000011] = TryDecodeIntegerDataProcessing, + [0b0000100] = TryDecodeIntegerDataProcessing, + [0b0000101] = TryDecodeIntegerDataProcessing, + [0b0000110] = TryDecodeIntegerDataProcessing, + [0b0000111] = TryDecodeIntegerDataProcessing, + [0b0001000] = nullptr, + [0b0001001] = nullptr, + [0b0001010] = nullptr, + [0b0001011] = nullptr, + [0b0001100] = nullptr, + [0b0001101] = nullptr, + [0b0001110] = nullptr, + [0b0001111] = nullptr, + [0b0010000] = nullptr, + [0b0010001] = nullptr, + [0b0010010] = nullptr, + [0b0010011] = nullptr, + [0b0010100] = nullptr, + [0b0010101] = nullptr, + [0b0010110] = nullptr, + [0b0010111] = nullptr, + [0b0011000] = nullptr, + [0b0011001] = nullptr, + [0b0011010] = nullptr, + [0b0011011] = nullptr, + [0b0011100] = nullptr, + [0b0011101] = nullptr, + [0b0011110] = nullptr, + [0b0011111] = nullptr, + [0b0100000] = nullptr, + [0b0100001] = nullptr, + [0b0100010] = nullptr, + [0b0100011] = nullptr, + [0b0100100] = nullptr, + [0b0100101] = nullptr, + [0b0100110] = nullptr, + [0b0100111] = nullptr, + [0b0101000] = nullptr, + [0b0101001] = nullptr, + [0b0101010] = nullptr, + [0b0101011] = nullptr, + [0b0101100] = nullptr, + [0b0101101] = nullptr, + [0b0101110] = nullptr, + [0b0101111] = nullptr, + [0b0110000] = nullptr, + [0b0110001] = nullptr, + [0b0110010] = nullptr, + [0b0110011] = nullptr, + [0b0110100] = nullptr, + [0b0110101] = nullptr, + [0b0110110] = nullptr, + [0b0110111] = nullptr, + [0b0111000] = nullptr, + [0b0111001] = nullptr, + [0b0111010] = nullptr, + [0b0111011] = nullptr, + [0b0111100] = nullptr, + [0b0111101] = nullptr, + [0b0111110] = nullptr, + [0b0111111] = nullptr, + [0b1000000] = nullptr, + [0b1000001] = nullptr, + [0b1000010] = nullptr, + [0b1000011] = nullptr, + [0b1000100] = nullptr, + [0b1000101] = nullptr, + [0b1000110] = nullptr, + [0b1000111] = nullptr, + [0b1001000] = nullptr, + [0b1001001] = nullptr, + [0b1001010] = nullptr, + [0b1001011] = nullptr, + [0b1001100] = nullptr, + [0b1001101] = nullptr, + [0b1001110] = nullptr, + [0b1001111] = nullptr, + [0b1010000] = nullptr, + [0b1010001] = nullptr, + [0b1010010] = nullptr, + [0b1010011] = nullptr, + [0b1010100] = nullptr, + [0b1010101] = nullptr, + [0b1010110] = nullptr, + [0b1010111] = nullptr, + [0b1011000] = nullptr, + [0b1011001] = nullptr, + [0b1011010] = nullptr, + [0b1011011] = nullptr, + [0b1011100] = nullptr, + [0b1011101] = nullptr, + [0b1011110] = nullptr, + [0b1011111] = nullptr, + [0b1100000] = nullptr, + [0b1100001] = nullptr, + [0b1100010] = nullptr, + [0b1100011] = nullptr, + [0b1100100] = nullptr, + [0b1100101] = nullptr, + [0b1100110] = nullptr, + [0b1100111] = nullptr, + [0b1101000] = nullptr, + [0b1101001] = nullptr, + [0b1101010] = nullptr, + [0b1101011] = nullptr, + [0b1101100] = nullptr, + [0b1101101] = nullptr, + [0b1101110] = nullptr, + [0b1101111] = nullptr, + [0b1110000] = nullptr, + [0b1110001] = nullptr, + [0b1110010] = nullptr, + [0b1110011] = nullptr, + [0b1110100] = nullptr, + [0b1110101] = nullptr, + [0b1110110] = nullptr, + [0b1110111] = nullptr, + [0b1111000] = nullptr, + [0b1111001] = nullptr, + [0b1111010] = nullptr, + [0b1111011] = nullptr, + [0b1111100] = nullptr, + [0b1111101] = nullptr, + [0b1111110] = nullptr, + [0b1111111] = nullptr, +}; + + +static uint32_t BytesToBits(const uint8_t *bytes) { + uint32_t bits = 0; + bits = (bits << 8) | static_cast(bytes[0]); + bits = (bits << 8) | static_cast(bytes[1]); + bits = (bits << 8) | static_cast(bytes[2]); + bits = (bits << 8) | static_cast(bytes[3]); + return bits; +} + +} // namespace + +// Decode an instuction. +bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes, + Instruction &inst) const { + + inst.pc = address; + inst.next_pc = address + inst_bytes.size(); // Default fall-through. + inst.branch_taken_pc = 0; + inst.branch_not_taken_pc = 0; + inst.has_branch_taken_delay_slot = false; + inst.has_branch_not_taken_delay_slot = false; + inst.arch_name = arch_name; + inst.arch_for_decode = nullptr; + inst.category = Instruction::kCategoryInvalid; + inst.operands.clear(); + if (!inst.bytes.empty() && inst.bytes.data() == inst_bytes.data()) { + inst.bytes.resize(inst_bytes.size()); + } else { + inst.bytes = inst_bytes; + } + + const auto bytes = reinterpret_cast(inst.bytes.data()); + const auto bits = BytesToBits(bytes); + + auto decoder = kBits27_to_21[(bits >> 21) & 0b1111111u]; + if (!decoder) { + LOG(ERROR) << "unhandled bits"; + return false; + } + + auto ret = decoder(inst, bits); + LOG(ERROR) << inst.Serialize(); + return ret; +} + +} // namespace remill From 4090697109e84cc396e81b438fabfda57e9bc115 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 23 Sep 2020 12:00:09 -0400 Subject: [PATCH 042/130] Added all data Integer processing instructions without S + ADDS and started ANDS --- bin/lift/Lift.cpp | 3 + lib/BC/Util.cpp | 1 + remill/Arch/AArch32/Arch.cpp | 9 +- remill/Arch/AArch32/Decode.cpp | 108 ++++++++++- remill/Arch/AArch32/Runtime/CMakeLists.txt | 3 + remill/Arch/AArch32/Runtime/Instructions.cpp | 8 +- remill/Arch/AArch32/Runtime/Operators.h | 32 ++++ remill/Arch/AArch32/Runtime/State.h | 28 +++ remill/Arch/AArch32/Runtime/Types.h | 73 +++++++ remill/Arch/AArch32/Semantics/BINARY.cpp | 113 +++++++++++ remill/Arch/AArch32/Semantics/FLAGS.cpp | 189 +++++++++++++++++++ 11 files changed, 560 insertions(+), 7 deletions(-) create mode 100644 remill/Arch/AArch32/Runtime/Operators.h create mode 100644 remill/Arch/AArch32/Runtime/Types.h create mode 100644 remill/Arch/AArch32/Semantics/BINARY.cpp create mode 100644 remill/Arch/AArch32/Semantics/FLAGS.cpp diff --git a/bin/lift/Lift.cpp b/bin/lift/Lift.cpp index 0141e6608..7380de988 100644 --- a/bin/lift/Lift.cpp +++ b/bin/lift/Lift.cpp @@ -267,6 +267,9 @@ int main(int argc, char *argv[]) { // `module`. trace_lifter.Lift(FLAGS_entry_address); + for (auto [ea, trace] : manager.traces) { + LOG(ERROR) << remill::LLVMThingToString(trace); + } // Optimize the module, but with a particular focus on only the functions // that we actually lifted. remill::OptimizationGuide guide = {}; diff --git a/lib/BC/Util.cpp b/lib/BC/Util.cpp index a64644705..d82c61c43 100644 --- a/lib/BC/Util.cpp +++ b/lib/BC/Util.cpp @@ -488,6 +488,7 @@ namespace { static const char *gSemanticsSearchPaths[] = { // Derived from the build. REMILL_BUILD_SEMANTICS_DIR_X86 "\0", + REMILL_BUILD_SEMANTICS_DIR_AARCH32 "\0", REMILL_BUILD_SEMANTICS_DIR_AARCH64 "\0", REMILL_BUILD_SEMANTICS_DIR_SPARC32 "\0", REMILL_BUILD_SEMANTICS_DIR_SPARC64 "\0", diff --git a/remill/Arch/AArch32/Arch.cpp b/remill/Arch/AArch32/Arch.cpp index 1abbeb399..2b86f65dc 100644 --- a/remill/Arch/AArch32/Arch.cpp +++ b/remill/Arch/AArch32/Arch.cpp @@ -112,7 +112,7 @@ void AArch32Arch::PopulateBasicBlockFunction(llvm::Module *module, << "the bitcode module"; auto &context = module->getContext(); -// auto u8 = llvm::Type::getInt8Ty(context); + auto u8 = llvm::Type::getInt8Ty(context); // auto u16 = llvm::Type::getInt16Ty(context); auto u32 = llvm::Type::getInt32Ty(context); // auto u64 = llvm::Type::getInt64Ty(context); @@ -157,10 +157,17 @@ void AArch32Arch::PopulateBasicBlockFunction(llvm::Module *module, SUB_REG(LR, gpr.r14.dword, u32, R14); SUB_REG(PC, gpr.r15.dword, u32, R15); + REG(N, sr.n, u8); + REG(C, sr.c, u8); + REG(Z, sr.z, u8); + REG(V, sr.v, u8); + const auto pc_arg = NthArgument(bb_func, kPCArgNum); const auto state_ptr_arg = NthArgument(bb_func, kStatePointerArgNum); ir.CreateStore(pc_arg, ir.CreateAlloca(addr, nullptr, "NEXT_PC")); + auto zero_c = ir.CreateAlloca(u8, nullptr, "ZERO_C"); + ir.CreateStore(llvm::Constant::getNullValue(u8), zero_c); ir.CreateAlloca(u32, nullptr, "SUPPRESS_WRITEBACK"); (void) this->RegisterByName("PC")->AddressOf(state_ptr_arg, ir); } diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index be320ab09..5065d21ab 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -94,6 +94,11 @@ static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { static void AddShiftRegOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_size) { + auto is_rrx = false; + if (!shift_size && shift_type == Shift::kShiftROR) { + shift_size = 1; + is_rrx = true; + } if (!shift_size) { AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); } else { @@ -117,6 +122,66 @@ static void AddShiftRegOperand(Instruction &inst, } } +static void AddShiftCarryOperand(Instruction &inst, + uint32_t reg_num, uint32_t shift_type, + uint32_t shift_size, const char * carry_reg_name) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.shift_reg.extract_size = 1; + op.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; + + auto is_rrx = false; + if (!shift_size && shift_type == Shift::kShiftROR) { + shift_size = 1; + is_rrx = true; + } + + if (!shift_size) { + op.shift_reg.reg.name = carry_reg_name; + op.shift_reg.reg.size = 8; + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; + op.shift_reg.shift_size = 0; + } else { + op.shift_reg.reg.name = kIntRegName[reg_num]; + op.shift_reg.reg.size = 32; + switch (static_cast(shift_type)) { + case Shift::kShiftASR: + op.shift_reg.shift_size = shift_size - 1; + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftSignedRight; + break; + case Shift::kShiftLSL: + op.shift_reg.shift_size = 32 - shift_size; + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + break; + case Shift::kShiftLSR: + op.shift_reg.shift_size = shift_size - 1; + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + break; + case Shift::kShiftROR: + if (is_rrx) { + + } else { + op.shift_reg.shift_size = (shift_size + 31) % 32; + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + } + break; + } + + if (shift_type == Shift::kShiftLSR || shift_type == Shift::kShiftASR) { + if (!shift_size) { + shift_size = 32; + } + } else if (shift_type == Shift::kShiftROR) { + LOG_IF(FATAL, !shift_size) + << "Invalid use of AddShiftRegOperand RRX shifts not supported"; + } + op.shift_reg.shift_size = shift_size; + op.type = Operand::kTypeShiftRegister; + op.size = 32; + op.action = Operand::kActionRead; + } +} + // Decode the condition field and fil in the instruction conditions accordingly static void DecodeCondition(Instruction &inst, uint32_t cond) { inst.conditions.emplace_back(); @@ -214,6 +279,40 @@ static void DecodeCondition(Instruction &inst, uint32_t cond) { } } +//000 AND, ANDS (register) +//001 EOR, EORS (register) +//010 0 != 1101 SUB, SUBS (register) — SUB +//010 0 1101 SUB, SUBS (SP minus register) — SUB +//010 1 != 1101 SUB, SUBS (register) — SUBS +//010 1 1101 SUB, SUBS (SP minus register) — SUBS +//011 RSB, RSBS (register) +//100 0 != 1101 ADD, ADDS (register) — ADD +//100 0 1101 ADD, ADDS (SP plus register) — ADD +//100 1 != 1101 ADD, ADDS (register) — ADDS +//100 1 1101 ADD, ADDS (SP plus register) — ADDS +//101 ADC, ADCS (register) +//110 SBC, SBCS (register) +//111 RSC, RSCS (register) +// High 3 bit opc and low bit s, opc:s +static const char * const kIdpNames[] = { + [0b0000] = "ANDrr", + [0b0001] = "ANDSrr", + [0b0010] = "EORrr", + [0b0011] = "EORSrr", + [0b0100] = "SUBrr", + [0b0101] = "SUBSrr", + [0b0110] = "RSBrr", + [0b0111] = "RSBSrr", + [0b1000] = "ADDrr", + [0b1001] = "ADDSrr", + [0b1010] = "ADCrr", + [0b1011] = "ADCSrr", + [0b1100] = "SBCrr", + [0b1101] = "SBCSrr", + [0b1110] = "RSCrr", + [0b1111] = "RSCSrr" +}; + static bool TryDecodeIntegerDataProcessing(Instruction &inst, uint32_t bits) { const IntDataProcessing enc = {bits}; if (enc.cond == 0b1111u) { @@ -222,14 +321,19 @@ static bool TryDecodeIntegerDataProcessing(Instruction &inst, uint32_t bits) { if (enc.opc == 0b010u || enc.opc == 0b100u) { } - + inst.function = kIdpNames[ (enc.opc << 1u) | enc.s]; DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); if (enc.rd == kPCRegNum) { - inst.category = Instruction::kCategoryIndirectJump; + if (enc.s) { // Updates the flags (condition codes) + inst.category = Instruction::kCategoryError; + return false; + } else { + inst.category = Instruction::kCategoryIndirectJump; + } } else { inst.category = Instruction::kCategoryNormal; } diff --git a/remill/Arch/AArch32/Runtime/CMakeLists.txt b/remill/Arch/AArch32/Runtime/CMakeLists.txt index 804315222..0661e3a0f 100644 --- a/remill/Arch/AArch32/Runtime/CMakeLists.txt +++ b/remill/Arch/AArch32/Runtime/CMakeLists.txt @@ -48,6 +48,9 @@ function(add_runtime_helper target_name address_bit_size little_endian) INSTALLDESTINATION "${install_folder}" DEPENDENCIES + "${CMAKE_SOURCE_DIR}/remill/Arch/AArch32/Semantics/BINARY.cpp" + "${CMAKE_SOURCE_DIR}/remill/Arch/AArch32/Semantics/FLAGS.cpp" + ) endfunction() diff --git a/remill/Arch/AArch32/Runtime/Instructions.cpp b/remill/Arch/AArch32/Runtime/Instructions.cpp index cea35d7a9..58fd30482 100644 --- a/remill/Arch/AArch32/Runtime/Instructions.cpp +++ b/remill/Arch/AArch32/Runtime/Instructions.cpp @@ -23,8 +23,8 @@ #include "remill/Arch/Runtime/Intrinsics.h" #include "remill/Arch/Runtime/Operators.h" #include "remill/Arch/AArch32/Runtime/State.h" -//#include "remill/Arch/AArch32/Runtime/Types.h" -//#include "remill/Arch/AArch32/Runtime/Operators.h" +#include "remill/Arch/AArch32/Runtime/Types.h" +#include "remill/Arch/AArch32/Runtime/Operators.h" // clang-format on @@ -56,9 +56,9 @@ DEF_ISEL(UNSUPPORTED_INSTRUCTION) = HandleUnsupported; DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; // clang-format off -//#include "remill/Arch/AArch64/Semantics/FLAGS.cpp" +#include "remill/Arch/AArch32/Semantics/FLAGS.cpp" // -//#include "remill/Arch/AArch64/Semantics/BINARY.cpp" +#include "remill/Arch/AArch32/Semantics/BINARY.cpp" //#include "remill/Arch/AArch64/Semantics/BITBYTE.cpp" //#include "remill/Arch/AArch64/Semantics/BRANCH.cpp" //#include "remill/Arch/AArch64/Semantics/CALL_RET.cpp" diff --git a/remill/Arch/AArch32/Runtime/Operators.h b/remill/Arch/AArch32/Runtime/Operators.h new file mode 100644 index 000000000..2d3555ee0 --- /dev/null +++ b/remill/Arch/AArch32/Runtime/Operators.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace { + +// Read a register directly. Sometimes this is needed for suppressed operands. +ALWAYS_INLINE static addr_t _Read(Memory *, Reg reg) { + return reg.aword; +} + +// Write directly to a register. This is sometimes needed for suppressed +// register operands. +ALWAYS_INLINE static void _Write(Memory *, Reg ®, addr_t val) { + reg.aword = val; +} + +} // namespace diff --git a/remill/Arch/AArch32/Runtime/State.h b/remill/Arch/AArch32/Runtime/State.h index 92ca82b57..bd8558e78 100644 --- a/remill/Arch/AArch32/Runtime/State.h +++ b/remill/Arch/AArch32/Runtime/State.h @@ -72,10 +72,38 @@ struct alignas(8) GPR final { } __attribute__((packed)); +// System registers affecting control and status of the machine. +struct alignas(8) SR final { + + uint8_t _2; + uint8_t n; // Negative condition flag. + uint8_t _3; + uint8_t z; // Zero condition flag + uint8_t _4; + uint8_t c; // Carry condition flag + uint8_t _5; + uint8_t v; // Overflow condition flag + + uint8_t _6; + uint8_t ixc; // Inexact (cumulative). + uint8_t _7; + uint8_t ofc; // Overflow (cumulative). + uint8_t _8; + uint8_t ufc; // Underflow (cumulative). + uint8_t _9; + uint8_t idc; // Input denormal (cumulative). + uint8_t _10; + uint8_t ioc; // Invalid operation (cumulative). + + uint8_t _padding[6]; +} __attribute__((packed)); + struct alignas(16) State final : public ArchState { GPR gpr; // 528 bytes. + SR sr; + uint64_t _0; } __attribute__((packed)); diff --git a/remill/Arch/AArch32/Runtime/Types.h b/remill/Arch/AArch32/Runtime/Types.h new file mode 100644 index 000000000..20143f50c --- /dev/null +++ b/remill/Arch/AArch32/Runtime/Types.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// We need this for boolean conditions, used in branch instructions. +typedef RnW R8W; + +typedef RnW R8W; +typedef RnW R16W; + +// Note: AArch64 zero-extends like x86, but the smallest register size that +// can be accessed is 32 bits. +typedef RnW R32W; + +//typedef Rn R8; +//typedef Rn R16; +typedef Rn R32; + +typedef Vn V8; +typedef Vn V16; +typedef Vn V32; +typedef Vn V64; +typedef Vn V128; +typedef VnW V128W; + +typedef MnW M8W; +typedef MnW M16W; +typedef MnW M32W; +typedef MnW M64W; + +typedef MVnW MV8W; +typedef MVnW MV16W; +typedef MVnW MV32W; +typedef MVnW MV64W; +typedef MVnW MV128W; + +typedef Mn M8; +typedef Mn M16; + +typedef Mn M32; +typedef Mn M64; + +typedef MVn MV8; +typedef MVn MV16; +typedef MVn MV32; +typedef MVn MV64; +typedef MVn MV128; +typedef MVn MV256; + +typedef In I8; +typedef In I16; +typedef In I32; +typedef In I64; + +typedef In F32; +typedef In F64; + +typedef In PC; +typedef In ADDR; diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp new file mode 100644 index 000000000..8cd04318b --- /dev/null +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { + +template +T AddWithCarryNZCV(State &state, T lhs, T rhs, T carry) { + auto unsigned_result = UAdd(UAdd(ZExt(lhs), ZExt(rhs)), ZExt(carry)); + auto signed_result = SAdd(SAdd(SExt(lhs), SExt(rhs)), Signed(ZExt(carry))); + auto result = TruncTo(unsigned_result); + state.sr.n = SignFlag(result); + state.sr.z = ZeroFlag(result); + state.sr.c = UCmpNeq(ZExt(result), unsigned_result); + state.sr.v = SCmpNeq(SExt(result), signed_result); + return result; +} + + + +template +DEF_SEM(AND, D dst, S1 src1, S2 src2) { + Write(dst, UAnd(Read(src1), Read(src2))); + return memory; +} + +template +DEF_SEM(ANDS, D dst, S1 src1, S2 src2) { + auto res = UAnd(Read(src1), Read(src2)); + WriteZExt(dst, res); + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + state.sr.c = false; + // PSTATE.V unchanged + return memory; +} + +template +DEF_SEM(EOR, D dst, S1 src1, S2 src2) { + Write(dst, UXor(Read(src1), Read(src2))); + return memory; +} + +template +DEF_SEM(RSB, D dst, S1 src1, S2 src2) { + Write(dst, USub(Read(src2), Read(src1))); + return memory; +} + +template +DEF_SEM(SUB, D dst, S1 src1, S2 src2) { + Write(dst, USub(Read(src1), Read(src2))); + return memory; +} + +template +DEF_SEM(ADD, D dst, S1 src1, S2 src2) { + Write(dst, UAdd(Read(src1), Read(src2))); + return memory; +} + +template +DEF_SEM(ADDS, D dst, S1 src1, S2 src2) { + using T = typename BaseType::BT; + auto lhs = Read(src1); + auto rhs = Read(src2); + auto res = AddWithCarryNZCV(state, lhs, rhs, T(0)); + Write(dst, res); + return memory; +} + + +template +DEF_SEM(ADC, D dst, S1 src1, S2 src2) { + Write(dst, UAdd(UAdd(Read(src1), Read(src2)), ZExtTo(state.sr.c))); + return memory; +} + +template +DEF_SEM(SBC, D dst, S1 src1, S2 src2) { + Write(dst, UAdd(UAdd(Read(src1), UNot(Read(src2))), ZExtTo(state.sr.c))); + return memory; +} + +template +DEF_SEM(RSC, D dst, S1 src1, S2 src2) { + Write(dst, UAdd(UAdd(Read(src2), UNot(Read(src1))), ZExtTo(state.sr.c))); + return memory; +} + +} // namespace + +DEF_ISEL(ANDrr) = AND; +DEF_ISEL(EORrr) = EOR; +DEF_ISEL(ADDrr) = ADD; +DEF_ISEL(ADDSrr) = ADDS; +DEF_ISEL(ADCrr) = ADC; +DEF_ISEL(RSBrr) = RSB; +DEF_ISEL(SUBrr) = SUB; +DEF_ISEL(SBCrr) = SBC; +DEF_ISEL(RSCrr) = RSC; diff --git a/remill/Arch/AArch32/Semantics/FLAGS.cpp b/remill/Arch/AArch32/Semantics/FLAGS.cpp new file mode 100644 index 000000000..0432bf56f --- /dev/null +++ b/remill/Arch/AArch32/Semantics/FLAGS.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { + +// Used to select specializations of flags computations based on what operator +// is executed. +enum : uint32_t { kLHS = 2415899639U, kRHS = 70623199U }; + +// Zero flags, tells us whether or not a value is zero. +template +[[gnu::const]] ALWAYS_INLINE static bool ZeroFlag(T res) { + return T(0) == res; +} + +// Zero flags, tells us whether or not a value is zero. +template +[[gnu::const]] ALWAYS_INLINE static bool NotZeroFlag(T res) { + return T(0) != res; +} + +// Sign flag, tells us if a result is signed or unsigned. +template +[[gnu::const]] ALWAYS_INLINE static bool SignFlag(T res) { + return 0 > Signed(res); +} + +// Tests whether there is an even number of bits in the low order byte. +[[gnu::const]] ALWAYS_INLINE static bool ParityFlag(uint8_t r0) { + return !__builtin_parity(static_cast(r0)); + + // auto r1 = r0 >> 1_u8; + // auto r2 = r1 >> 1_u8; + // auto r3 = r2 >> 1_u8; + // auto r4 = r3 >> 1_u8; + // auto r5 = r4 >> 1_u8; + // auto r6 = r5 >> 1_u8; + // auto r7 = r6 >> 1_u8; + // + // return !(1 & (r0 ^ r1 ^ r2 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7)); +} + +struct tag_add {}; +struct tag_sub {}; +struct tag_div {}; +struct tag_mul {}; + +// Generic overflow flag. +template +struct Overflow; + +// Computes an overflow flag when two numbers are added together. +template <> +struct Overflow { + template + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { + static_assert(std::is_unsigned::value, + "Invalid specialization of `Overflow::Flag` for addition."); + enum { kSignShift = sizeof(T) * 8 - 1 }; + + const T sign_lhs = lhs >> kSignShift; + const T sign_rhs = rhs >> kSignShift; + const T sign_res = res >> kSignShift; + return 2 == (sign_lhs ^ sign_res) + (sign_rhs ^ sign_res); + } +}; + +// Computes an overflow flag when one number is subtracted from another. +template <> +struct Overflow { + template + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { + static_assert(std::is_unsigned::value, + "Invalid specialization of `Overflow::Flag` for " + "subtraction."); + enum { kSignShift = sizeof(T) * 8 - 1 }; + + const T sign_lhs = lhs >> kSignShift; + const T sign_rhs = rhs >> kSignShift; + const T sign_res = res >> kSignShift; + return 2 == (sign_lhs ^ sign_rhs) + (sign_lhs ^ sign_res); + } +}; + +// Computes an overflow flag when one number is multiplied with another. +template <> +struct Overflow { + + // Integer multiplication overflow check, where result is twice the width of + // the operands. + template + [[gnu::const]] ALWAYS_INLINE static bool + Flag(T, T, R res, + typename std::enable_if::type = 0) { + + return static_cast(static_cast(res)) != res; + } + + // Signed integer multiplication overflow check, where the result is + // truncated to the size of the operands. + template + [[gnu::const]] ALWAYS_INLINE static bool + Flag(T lhs, T rhs, T, + typename std::enable_if::value, int>::type = 0) { + auto lhs_wide = SExt(lhs); + auto rhs_wide = SExt(rhs); + return Flag(lhs, rhs, lhs_wide * rhs_wide); + } +}; + +// Generic carry flag. +template +struct Carry; + +// Computes an carry flag when two numbers are added together. +template <> +struct Carry { + template + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { + static_assert(std::is_unsigned::value, + "Invalid specialization of `Carry::Flag` for addition."); + return res < lhs || res < rhs; + } +}; + +// Computes an carry flag when one number is subtracted from another. +template <> +struct Carry { + template + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T) { + static_assert(std::is_unsigned::value, + "Invalid specialization of `Carry::Flag` for addition."); + return lhs < rhs; + } +}; + +ALWAYS_INLINE static void SetFPSRStatusFlags(State &state, int mask) { + // TODO(Sonya): Update these flags to work on AArch32 +// state.sr.ixc |= static_cast(0 != (mask & FE_INEXACT)); +// state.sr.ofc |= static_cast(0 != (mask & FE_OVERFLOW)); +// state.sr.ufc |= static_cast(0 != (mask & FE_UNDERFLOW)); +// state.sr.ioc |= static_cast(0 != (mask & FE_INVALID)); +} + +template +ALWAYS_INLINE static auto CheckedFloatUnaryOp(State &state, F func, T arg1) + -> decltype(func(arg1)) { + + //state.sr.idc |= IsDenormal(arg1); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + BarrierReorder(); + auto res = func(arg1); + BarrierReorder(); + auto new_except = __remill_fpu_exception_test_and_clear( + FE_ALL_EXCEPT, old_except /* zero */); + SetFPSRStatusFlags(state, new_except); + return res; +} + +template +ALWAYS_INLINE static auto CheckedFloatBinOp(State &state, F func, T arg1, + T arg2) + -> decltype(func(arg1, arg2)) { + + //state.sr.idc |= IsDenormal(arg1) | IsDenormal(arg2); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + BarrierReorder(); + auto res = func(arg1, arg2); + BarrierReorder(); + auto new_except = __remill_fpu_exception_test_and_clear( + FE_ALL_EXCEPT, old_except /* zero */); + SetFPSRStatusFlags(state, new_except); + return res; +} + +} // namespace From 0d0a7f43d45b54f78a669f1d122e26dbf984d802 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 23 Sep 2020 12:48:56 -0400 Subject: [PATCH 043/130] Updated --- remill/Arch/AArch32/Decode.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 5065d21ab..394e6384a 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -111,7 +111,7 @@ static void AddShiftRegOperand(Instruction &inst, if (!shift_size) { shift_size = 32; } - } else if (shift_type == Shift::kShiftROR) { + } else if (is_rrx) { LOG_IF(FATAL, !shift_size) << "Invalid use of AddShiftRegOperand RRX shifts not supported"; } @@ -168,12 +168,7 @@ static void AddShiftCarryOperand(Instruction &inst, } if (shift_type == Shift::kShiftLSR || shift_type == Shift::kShiftASR) { - if (!shift_size) { - shift_size = 32; - } - } else if (shift_type == Shift::kShiftROR) { - LOG_IF(FATAL, !shift_size) - << "Invalid use of AddShiftRegOperand RRX shifts not supported"; + } op.shift_reg.shift_size = shift_size; op.type = Operand::kTypeShiftRegister; From 488c1f1cd12487530e77732aec2ab736b55db02b Mon Sep 17 00:00:00 2001 From: sschriner Date: Mon, 28 Sep 2020 18:01:32 -0400 Subject: [PATCH 044/130] Finished Integer Data Processing with three registers, added integer data processing with 2 regs + immediate, started MUL instructions --- remill/Arch/AArch32/Decode.cpp | 393 +++++++++++++++++++---- remill/Arch/AArch32/Runtime/Types.h | 1 - remill/Arch/AArch32/Semantics/BINARY.cpp | 181 ++++++++--- 3 files changed, 474 insertions(+), 101 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 394e6384a..985a4effa 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -23,7 +23,7 @@ namespace remill { namespace { //Integer Data Processing (three register, immediate shift) -union IntDataProcessing { +union IntDataProcessingRRR { uint32_t flat; struct { uint32_t rm : 4; @@ -38,7 +38,39 @@ union IntDataProcessing { uint32_t cond : 4; } __attribute__((packed)); } __attribute__((packed)); -static_assert(sizeof(IntDataProcessing) == 4, " "); +static_assert(sizeof(IntDataProcessingRRR) == 4, " "); + +//Integer Data Processing (2 register and immediate, immediate shift) +union IntDataProcessingRRI { + uint32_t flat; + struct { + uint32_t imm12 : 12; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 3; + uint32_t _0010 : 4; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntDataProcessingRRI) == 4, " "); + +// Multiply and Accumulate +union MultiplyAndAccumulate { + uint32_t flat; + struct { + uint32_t rn : 4; + uint32_t _1001 : 4; + uint32_t rm : 4; + uint32_t rdlo : 4; + uint32_t rdhi : 4; + uint32_t s : 1; + uint32_t opc : 3; + uint32_t _0000 : 4; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(MultiplyAndAccumulate) == 4, " "); static constexpr auto kPCRegNum = 15u; @@ -61,6 +93,62 @@ static const char * const kIntRegName[] = { "R15" }; +static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out) { + uint32_t unrotated_value = imm12 & (0b11111111u); + uint32_t rotation_amount = ((imm12 >> 8) & (0b1111u)) *2u; + auto num_ops = inst.operands.size(); + inst.operands.emplace_back(); + inst.operands.emplace_back(); + inst.operands.emplace_back(); + auto &op0 = inst.operands[num_ops]; + auto &op1 = inst.operands[num_ops + 1]; + auto &op2 = inst.operands[num_ops + 2]; + + op0.imm.is_signed = false; + op0.size = 32; + op0.action = Operand::kActionRead; + op0.type = Operand::kTypeImmediate; + + if (!rotation_amount) { + op0.imm.val = unrotated_value; + } else { + op0.imm.val = __builtin_rotateright32(unrotated_value, rotation_amount); + } + + // This is the 2nd part of RRX so we can reuse the same semantics + op1.imm.is_signed = false; + op1.imm.val = 0; + op1.size = 32; + op1.action = Operand::kActionRead; + op1.type = Operand::kTypeImmediate; + + if (!rotation_amount) { + op2.shift_reg.extract_size = 1; + op2.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; + + op2.shift_reg.shift_size = 0; + op2.type = Operand::kTypeShiftRegister; + op2.size = 32; + op2.action = Operand::kActionRead; + + op2.shift_reg.reg.name = "C"; + op2.shift_reg.reg.size = 8; + op2.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; + op2.shift_reg.shift_size = 0; + } else { + op2.imm.val = (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u; + op2.size = 32; + op2.imm.is_signed = false; + op2.action = Operand::kActionRead; + op2.type = Operand::kTypeImmediate; + } + + if (!carry_out) { + inst.operands.pop_back(); + } + +} + static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, Operand::Action action) { inst.operands.emplace_back(); @@ -72,6 +160,17 @@ static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, op.reg.name = kIntRegName[index]; } +static void AddImmOp(Instruction &inst, uint64_t value, unsigned size = 32, + bool is_signed = false) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.imm.val = value; + op.size = size; + op.imm.is_signed = is_signed; + op.action = Operand::kActionRead; + op.type = Operand::kTypeImmediate; +} + // Note: Order is significant; extracted bits may be casted to this type. enum Shift : uint32_t { kShiftLSL, kShiftLSR, kShiftASR, kShiftROR }; @@ -98,7 +197,12 @@ static void AddShiftRegOperand(Instruction &inst, if (!shift_size && shift_type == Shift::kShiftROR) { shift_size = 1; is_rrx = true; + } else if (shift_type == Shift::kShiftLSR || shift_type == Shift::kShiftASR) { + if (!shift_size) { + shift_size = 32; + } } + if (!shift_size) { AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); } else { @@ -106,19 +210,42 @@ static void AddShiftRegOperand(Instruction &inst, auto &op = inst.operands.back(); op.shift_reg.reg.name = kIntRegName[reg_num]; op.shift_reg.reg.size = 32; - op.shift_reg.shift_op = GetOperandShift(static_cast(shift_type)); - if (shift_type == Shift::kShiftLSR || shift_type == Shift::kShiftASR) { - if (!shift_size) { - shift_size = 32; - } - } else if (is_rrx) { - LOG_IF(FATAL, !shift_size) - << "Invalid use of AddShiftRegOperand RRX shifts not supported"; + + if (is_rrx) { + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + op.shift_reg.shift_size = 1; + } else { + op.shift_reg.shift_op = GetOperandShift(static_cast(shift_type)); + op.shift_reg.shift_size = shift_size; } - op.shift_reg.shift_size = shift_size; + + op.type = Operand::kTypeShiftRegister; + op.size = 32; + op.action = Operand::kActionRead; + } + + // To handle rrx we need to take two components shift each and OR the results + // together. No single operand type in remill is flexible enough to handle this. + // So we make 2 operands and OR those two operands together. In most cases + // when rrx isn't used we OR something with 0. + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + if (is_rrx) { + op.shift_reg.reg.name = "C"; + op.shift_reg.reg.size = 8; + + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; + op.shift_reg.shift_size = 31; + op.type = Operand::kTypeShiftRegister; op.size = 32; op.action = Operand::kActionRead; + } else { + op.imm.is_signed = false; + op.imm.val = 0; + op.size = 32; + op.action = Operand::kActionRead; + op.type = Operand::kTypeImmediate; } } @@ -130,6 +257,11 @@ static void AddShiftCarryOperand(Instruction &inst, op.shift_reg.extract_size = 1; op.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; + op.shift_reg.shift_size = shift_size; + op.type = Operand::kTypeShiftRegister; + op.size = 32; + op.action = Operand::kActionRead; + auto is_rrx = false; if (!shift_size && shift_type == Shift::kShiftROR) { shift_size = 1; @@ -159,25 +291,18 @@ static void AddShiftCarryOperand(Instruction &inst, break; case Shift::kShiftROR: if (is_rrx) { - + op.shift_reg.shift_size = 0; + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; } else { - op.shift_reg.shift_size = (shift_size + 31) % 32; + op.shift_reg.shift_size = (shift_size + 31u) % 32u; op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; } break; } - - if (shift_type == Shift::kShiftLSR || shift_type == Shift::kShiftASR) { - - } - op.shift_reg.shift_size = shift_size; - op.type = Operand::kTypeShiftRegister; - op.size = 32; - op.action = Operand::kActionRead; } } -// Decode the condition field and fil in the instruction conditions accordingly +// Decode the condition field and fill in the instruction conditions accordingly static void DecodeCondition(Instruction &inst, uint32_t cond) { inst.conditions.emplace_back(); auto &lhs_cond = inst.conditions.back(); @@ -274,22 +399,8 @@ static void DecodeCondition(Instruction &inst, uint32_t cond) { } } -//000 AND, ANDS (register) -//001 EOR, EORS (register) -//010 0 != 1101 SUB, SUBS (register) — SUB -//010 0 1101 SUB, SUBS (SP minus register) — SUB -//010 1 != 1101 SUB, SUBS (register) — SUBS -//010 1 1101 SUB, SUBS (SP minus register) — SUBS -//011 RSB, RSBS (register) -//100 0 != 1101 ADD, ADDS (register) — ADD -//100 0 1101 ADD, ADDS (SP plus register) — ADD -//100 1 != 1101 ADD, ADDS (register) — ADDS -//100 1 1101 ADD, ADDS (SP plus register) — ADDS -//101 ADC, ADCS (register) -//110 SBC, SBCS (register) -//111 RSC, RSCS (register) // High 3 bit opc and low bit s, opc:s -static const char * const kIdpNames[] = { +static const char * const kIdpNamesRRR[] = { [0b0000] = "ANDrr", [0b0001] = "ANDSrr", [0b0010] = "EORrr", @@ -308,20 +419,36 @@ static const char * const kIdpNames[] = { [0b1111] = "RSCSrr" }; -static bool TryDecodeIntegerDataProcessing(Instruction &inst, uint32_t bits) { - const IntDataProcessing enc = {bits}; +//000 AND, ANDS (register) +//001 EOR, EORS (register) +//010 0 != 1101 SUB, SUBS (register) — SUB +//010 0 1101 SUB, SUBS (SP minus register) — SUB +//010 1 != 1101 SUB, SUBS (register) — SUBS +//010 1 1101 SUB, SUBS (SP minus register) — SUBS +//011 RSB, RSBS (register) +//100 0 != 1101 ADD, ADDS (register) — ADD +//100 0 1101 ADD, ADDS (SP plus register) — ADD +//100 1 != 1101 ADD, ADDS (register) — ADDS +//100 1 1101 ADD, ADDS (SP plus register) — ADDS +//101 ADC, ADCS (register) +//110 SBC, SBCS (register) +//111 RSC, RSCS (register) +static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) { + const IntDataProcessingRRR enc = {bits}; if (enc.cond == 0b1111u) { return false; } - if (enc.opc == 0b010u || enc.opc == 0b100u) { - } - inst.function = kIdpNames[ (enc.opc << 1u) | enc.s]; + inst.function = kIdpNamesRRR[ (enc.opc << 1u) | enc.s]; DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); + if (enc.s) { + AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); + } + if (enc.rd == kPCRegNum) { if (enc.s) { // Updates the flags (condition codes) inst.category = Instruction::kCategoryError; @@ -336,15 +463,161 @@ static bool TryDecodeIntegerDataProcessing(Instruction &inst, uint32_t bits) { return true; } +//000 AND, ANDS (immediate) +//001 EOR, EORS (immediate) +//010 0 != 11x1 SUB, SUBS (immediate) — SUB +//010 0 1101 SUB, SUBS (SP minus immediate) — SUB +//010 0 1111 ADR — A2 +//010 1 != 1101 SUB, SUBS (immediate) — SUBS +//010 1 1101 SUB, SUBS (SP minus immediate) — SUBS +//011 RSB, RSBS (immediate) +//100 0 != 11x1 ADD, ADDS (immediate) — ADD +//100 0 1101 ADD, ADDS (SP plus immediate) — ADD +//100 0 1111 ADR — A1 +//100 1 != 1101 ADD, ADDS (immediate) — ADDS +//100 1 1101 ADD, ADDS (SP plus immediate) — ADDS +//101 ADC, ADCS (immediate) +//110 SBC, SBCS (immediate) +//111 RSC, RSCS (immediate) +static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) { + const IntDataProcessingRRI enc = { bits }; + if (enc.cond == 0b1111u) { + return false; + } + + inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s]; + DecodeCondition(inst, enc.cond); + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + + // Raise the program counter to align to a multiple of 4 bytes + if (enc.rn == kPCRegNum && (enc.opc == 0b100u || enc.opc == 0b010u)) { + int64_t diff = static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); + + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.type = Operand::kTypeAddress; + op.size = 32; + op.action = Operand::kActionRead; + op.addr.address_size = 32; + op.addr.base_reg.name = "PC"; + op.addr.base_reg.size = 32; + op.addr.scale = 0; + op.addr.displacement = diff; + + } else { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + } + + DecodeA32ExpandImm(inst, enc.imm12, enc.s); + + if (enc.rd == kPCRegNum) { + + if (enc.s) { // Updates the flags (condition codes) + inst.category = Instruction::kCategoryError; + return false; + } else { + inst.category = Instruction::kCategoryIndirectJump; + } + } else { + inst.category = Instruction::kCategoryNormal; + } + + return true; +} + + +static const char * const kMulAccRRR[] = { + [0b0000] = "MULrr", + [0b0001] = "MULSrr", + [0b0010] = "MLArr", + [0b0011] = "MLASrr", + [0b0100] = "UMAALrr", + [0b0101] = nullptr, + [0b0110] = "MLSrr", + [0b0111] = nullptr, + [0b1000] = "UMULLrr", + [0b1001] = "UMULLSrr", + [0b1010] = "UMLALrr", + [0b1011] = "UMLALSrr", + [0b1100] = "SMULLrr", + [0b1101] = "SMULLSrr", + [0b1110] = "SMLALrr", + [0b1111] = "SMLALSrr" +}; + +//000 MUL, MULS +//001 MLA, MLAS +//010 0 UMAAL +//010 1 UNALLOCATED +//011 0 MLS +//011 1 UNALLOCATED +//100 UMULL, UMULLS +//101 UMLAL, UMLALS +//110 SMULL, SMULLS +//111 SMLAL, SMLALS +static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { + const MultiplyAndAccumulate enc = { bits }; + // if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; + if (enc.cond == 0b1111u || (enc.rdhi == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum)) { + return false; + } + + auto instruction = kMulAccRRR[(enc.opc << 1u) | enc.s]; + if (!instruction) { + return false; + } + inst.function = instruction; + + DecodeCondition(inst, enc.cond); + AddIntRegOp(inst, enc.rdhi, 32, Operand::kActionWrite); + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); + if (enc.opc != 0b000u) { + AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionRead); + } else { + AddImmOp(inst, 0); + } + + return true; + +} + +static bool (*const kBits7_to_4[])(Instruction&, uint32_t) = { + [0b0000] = TryDecodeIntegerDataProcessingRRR, + [0b0001] = nullptr, + [0b0010] = TryDecodeIntegerDataProcessingRRR, + [0b0011] = nullptr, + [0b0100] = TryDecodeIntegerDataProcessingRRR, + [0b0101] = nullptr, + [0b0110] = TryDecodeIntegerDataProcessingRRR, + [0b0111] = nullptr, + [0b1000] = TryDecodeIntegerDataProcessingRRR, + [0b1001] = TryDecodeMultiplyAndAccumulate, + [0b1010] = TryDecodeIntegerDataProcessingRRR, + [0b1011] = nullptr, + [0b1100] = TryDecodeIntegerDataProcessingRRR, + [0b1101] = nullptr, + [0b1110] = TryDecodeIntegerDataProcessingRRR, + [0b1111] = nullptr +}; + +static bool TryDecodeArithmetic(Instruction &inst, uint32_t bits){ + auto decode = kBits7_to_4[(bits >> 4) & 0b1111u]; + if (!decode){ + return false; + } + return decode(inst, bits); +} + static bool (*const kBits27_to_21[])(Instruction&, uint32_t) = { - [0b0000000] = TryDecodeIntegerDataProcessing, - [0b0000001] = TryDecodeIntegerDataProcessing, - [0b0000010] = TryDecodeIntegerDataProcessing, - [0b0000011] = TryDecodeIntegerDataProcessing, - [0b0000100] = TryDecodeIntegerDataProcessing, - [0b0000101] = TryDecodeIntegerDataProcessing, - [0b0000110] = TryDecodeIntegerDataProcessing, - [0b0000111] = TryDecodeIntegerDataProcessing, + [0b0000000] = TryDecodeArithmetic, + [0b0000001] = TryDecodeArithmetic, + [0b0000010] = TryDecodeArithmetic, + [0b0000011] = TryDecodeArithmetic, + [0b0000100] = TryDecodeArithmetic, + [0b0000101] = TryDecodeArithmetic, + [0b0000110] = TryDecodeArithmetic, + [0b0000111] = TryDecodeArithmetic, [0b0001000] = nullptr, [0b0001001] = nullptr, [0b0001010] = nullptr, @@ -353,14 +626,14 @@ static bool (*const kBits27_to_21[])(Instruction&, uint32_t) = { [0b0001101] = nullptr, [0b0001110] = nullptr, [0b0001111] = nullptr, - [0b0010000] = nullptr, - [0b0010001] = nullptr, - [0b0010010] = nullptr, - [0b0010011] = nullptr, - [0b0010100] = nullptr, - [0b0010101] = nullptr, - [0b0010110] = nullptr, - [0b0010111] = nullptr, + [0b0010000] = TryDecodeIntegerDataProcessingRRI, + [0b0010001] = TryDecodeIntegerDataProcessingRRI, + [0b0010010] = TryDecodeIntegerDataProcessingRRI, + [0b0010011] = TryDecodeIntegerDataProcessingRRI, + [0b0010100] = TryDecodeIntegerDataProcessingRRI, + [0b0010101] = TryDecodeIntegerDataProcessingRRI, + [0b0010110] = TryDecodeIntegerDataProcessingRRI, + [0b0010111] = TryDecodeIntegerDataProcessingRRI, [0b0011000] = nullptr, [0b0011001] = nullptr, [0b0011010] = nullptr, @@ -499,6 +772,10 @@ bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_byte inst.bytes = inst_bytes; } + if (address & 0b1u) { + return false; + } + const auto bytes = reinterpret_cast(inst.bytes.data()); const auto bits = BytesToBits(bytes); diff --git a/remill/Arch/AArch32/Runtime/Types.h b/remill/Arch/AArch32/Runtime/Types.h index 20143f50c..c77e899a5 100644 --- a/remill/Arch/AArch32/Runtime/Types.h +++ b/remill/Arch/AArch32/Runtime/Types.h @@ -64,7 +64,6 @@ typedef MVn MV256; typedef In I8; typedef In I16; typedef In I32; -typedef In I64; typedef In F32; typedef In F64; diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index 8cd04318b..9aa2cfb66 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -30,84 +30,181 @@ T AddWithCarryNZCV(State &state, T lhs, T rhs, T carry) { -template -DEF_SEM(AND, D dst, S1 src1, S2 src2) { - Write(dst, UAnd(Read(src1), Read(src2))); +DEF_SEM(AND, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, UAnd(Read(src1), value)); return memory; } -template -DEF_SEM(ANDS, D dst, S1 src1, S2 src2) { - auto res = UAnd(Read(src1), Read(src2)); +DEF_SEM(ANDS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto value = UOr(Read(src2), Read(src2_rrx)); + auto res = UAnd(Read(src1), value); WriteZExt(dst, res); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); - state.sr.c = false; + state.sr.c = Read(carry_out); // PSTATE.V unchanged return memory; } -template -DEF_SEM(EOR, D dst, S1 src1, S2 src2) { - Write(dst, UXor(Read(src1), Read(src2))); + +DEF_SEM(EOR, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, UXor(Read(src1), value)); + return memory; +} + +DEF_SEM(EORS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto value = UOr(Read(src2), Read(src2_rrx)); + auto res = UXor(Read(src1), value); + Write(dst, res); + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(RSB, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, USub(value, Read(src1))); + return memory; +} + +DEF_SEM(RSBS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, UNot(lhs), rhs, uint32_t(1)); + Write(dst, res); return memory; } -template -DEF_SEM(RSB, D dst, S1 src1, S2 src2) { - Write(dst, USub(Read(src2), Read(src1))); +DEF_SEM(SUB, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, USub(Read(src1), value)); return memory; } -template -DEF_SEM(SUB, D dst, S1 src1, S2 src2) { - Write(dst, USub(Read(src1), Read(src2))); +DEF_SEM(SUBS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, lhs, UNot(rhs), uint32_t(1)); + Write(dst, res); return memory; } -template -DEF_SEM(ADD, D dst, S1 src1, S2 src2) { - Write(dst, UAdd(Read(src1), Read(src2))); + +DEF_SEM(ADD, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, UAdd(Read(src1), value)); return memory; } -template -DEF_SEM(ADDS, D dst, S1 src1, S2 src2) { - using T = typename BaseType::BT; +DEF_SEM(ADDS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = AddWithCarryNZCV(state, lhs, rhs, T(0)); + auto res = AddWithCarryNZCV(state, lhs, rhs, uint32_t(0)); Write(dst, res); return memory; } +DEF_SEM(ADC, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, UAdd(UAdd(Read(src1),value), uint32_t(state.sr.c))); + return memory; +} -template -DEF_SEM(ADC, D dst, S1 src1, S2 src2) { - Write(dst, UAdd(UAdd(Read(src1), Read(src2)), ZExtTo(state.sr.c))); +DEF_SEM(ADCS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, lhs, rhs, uint32_t(state.sr.c)); + Write(dst, res); return memory; } -template -DEF_SEM(SBC, D dst, S1 src1, S2 src2) { - Write(dst, UAdd(UAdd(Read(src1), UNot(Read(src2))), ZExtTo(state.sr.c))); +DEF_SEM(SBC, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, UAdd(UAdd(Read(src1), UNot(value)), uint32_t(state.sr.c))); return memory; } -template -DEF_SEM(RSC, D dst, S1 src1, S2 src2) { - Write(dst, UAdd(UAdd(Read(src2), UNot(Read(src1))), ZExtTo(state.sr.c))); +DEF_SEM(SBCS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, lhs, UNot(rhs), uint32_t(state.sr.c)); + Write(dst, res); + return memory; +} + +DEF_SEM(RSC, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { + auto value = UOr(Read(src2), Read(src2_rrx)); + Write(dst, UAdd(UAdd(value, UNot(Read(src1))), uint32_t(state.sr.c))); + return memory; +} + +DEF_SEM(RSCS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, UNot(lhs), rhs, uint32_t(state.sr.c)); + Write(dst, res); return memory; } } // namespace -DEF_ISEL(ANDrr) = AND; -DEF_ISEL(EORrr) = EOR; -DEF_ISEL(ADDrr) = ADD; -DEF_ISEL(ADDSrr) = ADDS; -DEF_ISEL(ADCrr) = ADC; -DEF_ISEL(RSBrr) = RSB; -DEF_ISEL(SUBrr) = SUB; -DEF_ISEL(SBCrr) = SBC; -DEF_ISEL(RSCrr) = RSC; +DEF_ISEL(ANDrr) = AND; +DEF_ISEL(ANDSrr) = ANDS; +DEF_ISEL(EORrr) = EOR; +DEF_ISEL(EORSrr) = EORS; +DEF_ISEL(ADDrr) = ADD; +DEF_ISEL(ADDSrr) = ADDS; +DEF_ISEL(ADCrr) = ADC; +DEF_ISEL(ADCSrr) = ADCS; +DEF_ISEL(RSBrr) = RSB; +DEF_ISEL(RSBSrr) = RSBS; +DEF_ISEL(SUBrr) = SUB; +DEF_ISEL(SUBSrr) = SUBS; +DEF_ISEL(SBCrr) = SBC; +DEF_ISEL(SBCSrr) = SBCS; +DEF_ISEL(RSCrr) = RSC; +DEF_ISEL(RSCSrr) = RSCS; + +namespace { +DEF_SEM(MUL, R32W dst, R32 src1, R32 src2, R32 src3) { + auto rhs = Signed(Read(src2)); + auto lhs = Signed(Read(src1)); + auto acc = Signed(Read(src3)); + auto res = Unsigned(SAdd(SMul(lhs, rhs), acc)); + Write(dst, res); + return memory; +} + +DEF_SEM(MULS, R32W dst, R32 src1, R32 src2, R32 src3) { + auto rhs = Signed(Read(src2)); + auto lhs = Signed(Read(src1)); + auto acc = Signed(Read(src3)); + auto res = Unsigned(SAdd(SMul(lhs, rhs), acc)); + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + // PSTATE.C, PSTATE.V unchanged + Write(dst, res); + return memory; +} + +DEF_SEM(MLS, R32W dst, R32 src1, R32 src2, R32 src3) { + auto rhs = Signed(Read(src2)); + auto lhs = Signed(Read(src1)); + auto acc = Signed(Read(src3)); + auto res = Unsigned(SSub(acc, SMul(lhs, rhs))); + Write(dst, res); + return memory; +} + +} // namespace + +DEF_ISEL(MULrr) = MUL; +DEF_ISEL(MULSrr) = MULS; +DEF_ISEL(MLArr) = MUL; +DEF_ISEL(MLASrr) = MULS; +DEF_ISEL(MLSrr) = MLS; + From 1020e26884ce6ebffd001acaceb3034066cb4883 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 29 Sep 2020 11:15:27 -0400 Subject: [PATCH 045/130] UMULL, UMULLS, UMLAL, UMLALS --- remill/Arch/AArch32/Decode.cpp | 24 +++++++++++++++----- remill/Arch/AArch32/Semantics/BINARY.cpp | 28 ++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 985a4effa..f6d15b333 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -547,14 +547,14 @@ static const char * const kMulAccRRR[] = { //000 MUL, MULS //001 MLA, MLAS -//010 0 UMAAL +//010 0 UMAAL - writes to RdHi + RdLo, read RdHi //010 1 UNALLOCATED //011 0 MLS //011 1 UNALLOCATED -//100 UMULL, UMULLS -//101 UMLAL, UMLALS -//110 SMULL, SMULLS -//111 SMLAL, SMLALS +//100 UMULL, UMULLS - writes to RdHi + RdLo +//101 UMLAL, UMLALS - writes to RdHi + RdLo, read RdHi +//110 SMULL, SMULLS - writes to RdHi + RdLo +//111 SMLAL, SMLALS - writes to RdHi + RdLo, read RdHi static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { const MultiplyAndAccumulate enc = { bits }; // if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; @@ -567,11 +567,23 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { return false; } inst.function = instruction; - DecodeCondition(inst, enc.cond); + AddIntRegOp(inst, enc.rdhi, 32, Operand::kActionWrite); + // 2nd write reg only needed for instructions with an opc that begins with 1 and UMALL + if (((enc.opc >> 2) & 0b1u) || enc.opc == 0b010u) { + AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionWrite); + } + + // If opc is UMAAL, UMLAL, SMLAL read RdHi, add 0 immediate for UMULL, SMULL + if (enc.opc == 0b111u || enc.opc == 0b101u || enc.opc == 0b010u) { + AddIntRegOp(inst, enc.rdhi, 32, Operand::kActionRead); + } else if ((enc.opc >> 2) & 0b1u) { + AddImmOp(inst, 0); + } AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); + // If instruction is not MUL add a read to RdLo otherwise add an immediate if (enc.opc != 0b000u) { AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionRead); } else { diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index 9aa2cfb66..c626a414a 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -200,6 +200,30 @@ DEF_SEM(MLS, R32W dst, R32 src1, R32 src2, R32 src3) { return memory; } +DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + auto rhs = Read(src3); + auto lhs = Read(src2); + // Question: this may or may not be the way you want me to do the extensions for the 64 bit result?? + auto acc = (uint64_t(Read(src1)) << 32) | uint64_t(Read(src4)); // UInt(R[dHi]:R[dLo]) + auto res = Unsigned(UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc)); + Write(dst_lo, uint32_t(res)); + Write(dst_hi, uint32_t(res >> 32)); + return memory; +} + +DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + auto rhs = Read(src3); + auto lhs = Read(src2); + auto acc = (uint64_t(Read(src1)) << 32) | uint64_t(Read(src4)); // UInt(R[dHi]:R[dLo]) + auto res = Unsigned(UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc)); + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + // PSTATE.C, PSTATE.V unchanged + Write(dst_lo, uint32_t(res)); + Write(dst_hi, uint32_t(res >> 32)); + return memory; +} + } // namespace DEF_ISEL(MULrr) = MUL; @@ -207,4 +231,8 @@ DEF_ISEL(MULSrr) = MULS; DEF_ISEL(MLArr) = MUL; DEF_ISEL(MLASrr) = MULS; DEF_ISEL(MLSrr) = MLS; +DEF_ISEL(UMULLrr) = UMULL; +DEF_ISEL(UMULLSrr) = UMULLS; +DEF_ISEL(UMLALrr) = UMULL; +DEF_ISEL(UMLALSrr) = UMULLS; From b38ecbc245da23f37275f2c050438db65de489ca Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 29 Sep 2020 11:34:08 -0400 Subject: [PATCH 046/130] Corrected condition for addend or 0 immediate for UMULL/UMLAL + SMULL/SMLAL instructions --- remill/Arch/AArch32/Decode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index f6d15b333..02a426e83 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -583,8 +583,8 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { } AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); - // If instruction is not MUL add a read to RdLo otherwise add an immediate - if (enc.opc != 0b000u) { + // If instruction is not MUL, UMULL, SMULL add read to RdLo otherwise add an immediate + if (enc.opc != 0b000u || enc.opc != 0b100u || enc.opc != 0b110u) { AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionRead); } else { AddImmOp(inst, 0); From c77ff3a03063835647f32abe3728633db182f0cc Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 29 Sep 2020 11:54:10 -0400 Subject: [PATCH 047/130] Correct ops in Binary.cpp --- remill/Arch/AArch32/Decode.cpp | 7 ++++++- remill/Arch/AArch32/Semantics/BINARY.cpp | 12 ++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 02a426e83..92f66b589 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -557,8 +557,9 @@ static const char * const kMulAccRRR[] = { //111 SMLAL, SMLALS - writes to RdHi + RdLo, read RdHi static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { const MultiplyAndAccumulate enc = { bits }; + // cond != 1111 // if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; - if (enc.cond == 0b1111u || (enc.rdhi == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum)) { + if (enc.cond == 0b1111u || (enc.rdhi == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum) || ) { return false; } @@ -572,6 +573,10 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { AddIntRegOp(inst, enc.rdhi, 32, Operand::kActionWrite); // 2nd write reg only needed for instructions with an opc that begins with 1 and UMALL if (((enc.opc >> 2) & 0b1u) || enc.opc == 0b010u) { + // if dHi == dLo then UNPREDICTABLE; + if (enc.rdlo == enc.rdhi){ + return false; + } AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionWrite); } diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index c626a414a..11f80b6f2 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -204,23 +204,23 @@ DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) auto rhs = Read(src3); auto lhs = Read(src2); // Question: this may or may not be the way you want me to do the extensions for the 64 bit result?? - auto acc = (uint64_t(Read(src1)) << 32) | uint64_t(Read(src4)); // UInt(R[dHi]:R[dLo]) + auto acc = UOr(ZExt(Read(src1)), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = Unsigned(UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc)); - Write(dst_lo, uint32_t(res)); - Write(dst_hi, uint32_t(res >> 32)); + Write(dst_lo, Trunc(res)); + Write(dst_hi, Trunc(UShr(res, 32ul))); return memory; } DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { auto rhs = Read(src3); auto lhs = Read(src2); - auto acc = (uint64_t(Read(src1)) << 32) | uint64_t(Read(src4)); // UInt(R[dHi]:R[dLo]) + auto acc = UOr(ZExt(Read(src1)), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = Unsigned(UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc)); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); // PSTATE.C, PSTATE.V unchanged - Write(dst_lo, uint32_t(res)); - Write(dst_hi, uint32_t(res >> 32)); + Write(dst_lo, Trunc(res)); + Write(dst_hi, Trunc(UShr(res, 32ul))); return memory; } From 4580916d0598591826d5001b7d44f3fb4972fef0 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 29 Sep 2020 12:03:23 -0400 Subject: [PATCH 048/130] UMAAL --- remill/Arch/AArch32/Semantics/BINARY.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index 11f80b6f2..b7254aa66 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -191,6 +191,17 @@ DEF_SEM(MULS, R32W dst, R32 src1, R32 src2, R32 src3) { return memory; } +DEF_SEM(UMAAL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + auto rhs = Read(src3); + auto lhs = Read(src2); + auto acc_hi = Read(src1); + auto acc_lo = Read(src4); + auto res = UAdd(UAdd(UMul(lhs, rhs), acc_hi), acc_lo); + Write(dst_lo, Trunc(res)); + Write(dst_hi, Trunc(UShr(res, 32ul))); + return memory; +} + DEF_SEM(MLS, R32W dst, R32 src1, R32 src2, R32 src3) { auto rhs = Signed(Read(src2)); auto lhs = Signed(Read(src1)); @@ -205,7 +216,7 @@ DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) auto lhs = Read(src2); // Question: this may or may not be the way you want me to do the extensions for the 64 bit result?? auto acc = UOr(ZExt(Read(src1)), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) - auto res = Unsigned(UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc)); + auto res = UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc); Write(dst_lo, Trunc(res)); Write(dst_hi, Trunc(UShr(res, 32ul))); return memory; @@ -215,7 +226,7 @@ DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4 auto rhs = Read(src3); auto lhs = Read(src2); auto acc = UOr(ZExt(Read(src1)), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) - auto res = Unsigned(UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc)); + auto res = UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); // PSTATE.C, PSTATE.V unchanged From 0e2bc86b8d02c2cc0d862af5261c23dee19d94d7 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 29 Sep 2020 12:49:32 -0400 Subject: [PATCH 049/130] SMULL, SMULLS, SMLAL, SMLALS + corrected acc was missing shift left in concatination --- remill/Arch/AArch32/Semantics/BINARY.cpp | 38 ++++++++++++++++++++---- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index b7254aa66..130d2a84b 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -214,27 +214,49 @@ DEF_SEM(MLS, R32W dst, R32 src1, R32 src2, R32 src3) { DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { auto rhs = Read(src3); auto lhs = Read(src2); - // Question: this may or may not be the way you want me to do the extensions for the 64 bit result?? - auto acc = UOr(ZExt(Read(src1)), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) - auto res = UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc); - Write(dst_lo, Trunc(res)); + auto acc = UOr(UShl(ZExt(Read(src1))), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto res = UAdd(UMul(lhs, rhs), acc); Write(dst_hi, Trunc(UShr(res, 32ul))); + Write(dst_lo, Trunc(res)); return memory; } DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { auto rhs = Read(src3); auto lhs = Read(src2); - auto acc = UOr(ZExt(Read(src1)), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) - auto res = UAdd(UMul(uint64_t(lhs), uint64_t(rhs)), acc); + auto acc = UOr(UShl(ZExt(Read(src1))), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto res = UAdd(UMul(lhs, rhs), acc); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); // PSTATE.C, PSTATE.V unchanged + Write(dst_hi, Trunc(UShr(res, 32ul))); Write(dst_lo, Trunc(res)); + return memory; +} + +DEF_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + // Not entirely sure about all the signed ops I have in here + auto rhs = Signed(Read(src3)); + auto lhs = Signed(Read(src2)); + auto acc = SOr(SShl(SExt(Read(src1))), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto res = SAdd(SMul(lhs, rhs), acc); Write(dst_hi, Trunc(UShr(res, 32ul))); + Write(dst_lo, Trunc(res)); return memory; } +DEF_SEM(SMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + auto rhs = Signed(Read(src3)); + auto lhs = Signed(Read(src2)); + auto acc = SOr(SShl(SExt(Read(src1))), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto res = SAdd(SMul(lhs, rhs), acc); + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + // PSTATE.C, PSTATE.V unchanged + Write(dst_hi, Trunc(UShr(res, 32ul))); + Write(dst_lo, Trunc(res)); + return memory; +} } // namespace DEF_ISEL(MULrr) = MUL; @@ -246,4 +268,8 @@ DEF_ISEL(UMULLrr) = UMULL; DEF_ISEL(UMULLSrr) = UMULLS; DEF_ISEL(UMLALrr) = UMULL; DEF_ISEL(UMLALSrr) = UMULLS; +DEF_ISEL(SMULLrr) = SMULL; +DEF_ISEL(SMULLSrr) = SMULLS; +DEF_ISEL(SMLALrr) = SMULL; +DEF_ISEL(SMLALSrr) = SMULLS; From 038724ce1b15e31bb4ebca2edb1f3ccc893b9178 Mon Sep 17 00:00:00 2001 From: sschriner Date: Mon, 5 Oct 2020 19:46:09 -0400 Subject: [PATCH 050/130] Updated decoding instructions based on top level encodings --- remill/Arch/AArch32/Decode.cpp | 292 ++++++++++------------- remill/Arch/AArch32/Semantics/BINARY.cpp | 36 +-- 2 files changed, 142 insertions(+), 186 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 92f66b589..cf5cbdd34 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -72,6 +72,36 @@ union MultiplyAndAccumulate { } __attribute__((packed)); static_assert(sizeof(MultiplyAndAccumulate) == 4, " "); +// Top-level encodings for A32 +union TopLevelEncodings { + uint32_t flat; + struct { + uint32_t _3_to_0 : 4; + uint32_t op1 : 1; + uint32_t _24_to_5 : 20; + uint32_t op0 : 3; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(TopLevelEncodings) == 4, " "); + +// Data-processing and miscellaneous instructions +union DataProcessingAndMisc { + uint32_t flat; + struct { + uint32_t _3_to_0 : 4; + uint32_t op4 : 1; + uint32_t op3 : 2; + uint32_t op2 : 1; + uint32_t _19_to_8 : 12; + uint32_t op1 : 5; + uint32_t op0 : 1; + uint32_t _00 : 2; + uint32_t _not1111 : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(DataProcessingAndMisc) == 4, " "); + static constexpr auto kPCRegNum = 15u; static const char * const kIntRegName[] = { @@ -435,9 +465,6 @@ static const char * const kIdpNamesRRR[] = { //111 RSC, RSCS (register) static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) { const IntDataProcessingRRR enc = {bits}; - if (enc.cond == 0b1111u) { - return false; - } inst.function = kIdpNamesRRR[ (enc.opc << 1u) | enc.s]; DecodeCondition(inst, enc.cond); @@ -481,9 +508,6 @@ static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) //111 RSC, RSCS (immediate) static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) { const IntDataProcessingRRI enc = { bits }; - if (enc.cond == 0b1111u) { - return false; - } inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s]; DecodeCondition(inst, enc.cond); @@ -557,9 +581,8 @@ static const char * const kMulAccRRR[] = { //111 SMLAL, SMLALS - writes to RdHi + RdLo, read RdHi static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { const MultiplyAndAccumulate enc = { bits }; - // cond != 1111 // if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; - if (enc.cond == 0b1111u || (enc.rdhi == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum) || ) { + if (enc.rdhi == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum) { return false; } @@ -589,7 +612,7 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); // If instruction is not MUL, UMULL, SMULL add read to RdLo otherwise add an immediate - if (enc.opc != 0b000u || enc.opc != 0b100u || enc.opc != 0b110u) { + if (enc.opc != 0b000u && enc.opc != 0b100u && enc.opc != 0b110u) { AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionRead); } else { AddImmOp(inst, 0); @@ -599,172 +622,105 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { } -static bool (*const kBits7_to_4[])(Instruction&, uint32_t) = { - [0b0000] = TryDecodeIntegerDataProcessingRRR, - [0b0001] = nullptr, - [0b0010] = TryDecodeIntegerDataProcessingRRR, - [0b0011] = nullptr, - [0b0100] = TryDecodeIntegerDataProcessingRRR, - [0b0101] = nullptr, - [0b0110] = TryDecodeIntegerDataProcessingRRR, - [0b0111] = nullptr, - [0b1000] = TryDecodeIntegerDataProcessingRRR, - [0b1001] = TryDecodeMultiplyAndAccumulate, - [0b1010] = TryDecodeIntegerDataProcessingRRR, +static uint32_t BytesToBits(const uint8_t *bytes) { + uint32_t bits = 0; + bits = (bits << 8) | static_cast(bytes[0]); + bits = (bits << 8) | static_cast(bytes[1]); + bits = (bits << 8) | static_cast(bytes[2]); + bits = (bits << 8) | static_cast(bytes[3]); + return bits; +} + +// Corresponds to Data-processing register (immediate shift) +// op0<24 to 23> | op1 <20> +static bool (*const kDataProcessingRI[])(Instruction&, uint32_t) = { + [0b000] = TryDecodeIntegerDataProcessingRRR, + [0b001] = TryDecodeIntegerDataProcessingRRR, + [0b010] = TryDecodeIntegerDataProcessingRRR, + [0b011] = nullptr, + [0b100] = nullptr, + [0b101] = nullptr, + [0b110] = nullptr, + [0b111] = nullptr, +}; + +// Corresponds to Data-processing immediate +// op0<24 to 23> | op1 <21 to 20> +static bool (*const kDataProcessingI[])(Instruction&, uint32_t) = { + [0b0000] = TryDecodeIntegerDataProcessingRRI, + [0b0001] = TryDecodeIntegerDataProcessingRRI, + [0b0010] = TryDecodeIntegerDataProcessingRRI, + [0b0011] = TryDecodeIntegerDataProcessingRRI, + [0b0100] = TryDecodeIntegerDataProcessingRRI, + [0b0101] = TryDecodeIntegerDataProcessingRRI, + [0b0110] = TryDecodeIntegerDataProcessingRRI, + [0b0111] = TryDecodeIntegerDataProcessingRRI, + [0b1000] = nullptr, + [0b1001] = nullptr, + [0b1010] = nullptr, [0b1011] = nullptr, - [0b1100] = TryDecodeIntegerDataProcessingRRR, + [0b1100] = nullptr, [0b1101] = nullptr, - [0b1110] = TryDecodeIntegerDataProcessingRRR, + [0b1110] = nullptr, [0b1111] = nullptr }; -static bool TryDecodeArithmetic(Instruction &inst, uint32_t bits){ - auto decode = kBits7_to_4[(bits >> 4) & 0b1111u]; - if (!decode){ - return false; - } - return decode(inst, bits); -} +typedef bool (*const TryDecode)(Instruction&, uint32_t); -static bool (*const kBits27_to_21[])(Instruction&, uint32_t) = { - [0b0000000] = TryDecodeArithmetic, - [0b0000001] = TryDecodeArithmetic, - [0b0000010] = TryDecodeArithmetic, - [0b0000011] = TryDecodeArithmetic, - [0b0000100] = TryDecodeArithmetic, - [0b0000101] = TryDecodeArithmetic, - [0b0000110] = TryDecodeArithmetic, - [0b0000111] = TryDecodeArithmetic, - [0b0001000] = nullptr, - [0b0001001] = nullptr, - [0b0001010] = nullptr, - [0b0001011] = nullptr, - [0b0001100] = nullptr, - [0b0001101] = nullptr, - [0b0001110] = nullptr, - [0b0001111] = nullptr, - [0b0010000] = TryDecodeIntegerDataProcessingRRI, - [0b0010001] = TryDecodeIntegerDataProcessingRRI, - [0b0010010] = TryDecodeIntegerDataProcessingRRI, - [0b0010011] = TryDecodeIntegerDataProcessingRRI, - [0b0010100] = TryDecodeIntegerDataProcessingRRI, - [0b0010101] = TryDecodeIntegerDataProcessingRRI, - [0b0010110] = TryDecodeIntegerDataProcessingRRI, - [0b0010111] = TryDecodeIntegerDataProcessingRRI, - [0b0011000] = nullptr, - [0b0011001] = nullptr, - [0b0011010] = nullptr, - [0b0011011] = nullptr, - [0b0011100] = nullptr, - [0b0011101] = nullptr, - [0b0011110] = nullptr, - [0b0011111] = nullptr, - [0b0100000] = nullptr, - [0b0100001] = nullptr, - [0b0100010] = nullptr, - [0b0100011] = nullptr, - [0b0100100] = nullptr, - [0b0100101] = nullptr, - [0b0100110] = nullptr, - [0b0100111] = nullptr, - [0b0101000] = nullptr, - [0b0101001] = nullptr, - [0b0101010] = nullptr, - [0b0101011] = nullptr, - [0b0101100] = nullptr, - [0b0101101] = nullptr, - [0b0101110] = nullptr, - [0b0101111] = nullptr, - [0b0110000] = nullptr, - [0b0110001] = nullptr, - [0b0110010] = nullptr, - [0b0110011] = nullptr, - [0b0110100] = nullptr, - [0b0110101] = nullptr, - [0b0110110] = nullptr, - [0b0110111] = nullptr, - [0b0111000] = nullptr, - [0b0111001] = nullptr, - [0b0111010] = nullptr, - [0b0111011] = nullptr, - [0b0111100] = nullptr, - [0b0111101] = nullptr, - [0b0111110] = nullptr, - [0b0111111] = nullptr, - [0b1000000] = nullptr, - [0b1000001] = nullptr, - [0b1000010] = nullptr, - [0b1000011] = nullptr, - [0b1000100] = nullptr, - [0b1000101] = nullptr, - [0b1000110] = nullptr, - [0b1000111] = nullptr, - [0b1001000] = nullptr, - [0b1001001] = nullptr, - [0b1001010] = nullptr, - [0b1001011] = nullptr, - [0b1001100] = nullptr, - [0b1001101] = nullptr, - [0b1001110] = nullptr, - [0b1001111] = nullptr, - [0b1010000] = nullptr, - [0b1010001] = nullptr, - [0b1010010] = nullptr, - [0b1010011] = nullptr, - [0b1010100] = nullptr, - [0b1010101] = nullptr, - [0b1010110] = nullptr, - [0b1010111] = nullptr, - [0b1011000] = nullptr, - [0b1011001] = nullptr, - [0b1011010] = nullptr, - [0b1011011] = nullptr, - [0b1011100] = nullptr, - [0b1011101] = nullptr, - [0b1011110] = nullptr, - [0b1011111] = nullptr, - [0b1100000] = nullptr, - [0b1100001] = nullptr, - [0b1100010] = nullptr, - [0b1100011] = nullptr, - [0b1100100] = nullptr, - [0b1100101] = nullptr, - [0b1100110] = nullptr, - [0b1100111] = nullptr, - [0b1101000] = nullptr, - [0b1101001] = nullptr, - [0b1101010] = nullptr, - [0b1101011] = nullptr, - [0b1101100] = nullptr, - [0b1101101] = nullptr, - [0b1101110] = nullptr, - [0b1101111] = nullptr, - [0b1110000] = nullptr, - [0b1110001] = nullptr, - [0b1110010] = nullptr, - [0b1110011] = nullptr, - [0b1110100] = nullptr, - [0b1110101] = nullptr, - [0b1110110] = nullptr, - [0b1110111] = nullptr, - [0b1111000] = nullptr, - [0b1111001] = nullptr, - [0b1111010] = nullptr, - [0b1111011] = nullptr, - [0b1111100] = nullptr, - [0b1111101] = nullptr, - [0b1111110] = nullptr, - [0b1111111] = nullptr, -}; +static TryDecode TryDataProcessingAndMisc(uint32_t bits) { + const DataProcessingAndMisc enc = { bits }; + if (!enc.op0) { + if ((!(enc.op1 >> 4)) && enc.op2 && (enc.op3 == 0b00u) && enc.op4) { + // Multiply and Accumulate + return TryDecodeMultiplyAndAccumulate; + } else if (!(((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) && !enc.op4) { + // Data-processing register (immediate shift) + return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b00001u)]; + } else { + // TODO(Sonya): Extra load/store + // TODO(Sonya): Synchronization primitives and Load-Acquire/Store-Release + // TODO(Sonya): Miscellaneous + // TODO(Sonya): Halfword Multiply and Accumulate + // TODO(Sonya): Data-processing register (register shift) + return nullptr; + } + } else { + // Data-processing immediate + return kDataProcessingI[(enc.op1 >> 1) | (enc.op1 & 0b00011u)]; + } +} -static uint32_t BytesToBits(const uint8_t *bytes) { - uint32_t bits = 0; - bits = (bits << 8) | static_cast(bytes[0]); - bits = (bits << 8) | static_cast(bytes[1]); - bits = (bits << 8) | static_cast(bytes[2]); - bits = (bits << 8) | static_cast(bytes[3]); - return bits; +// cond op0 op1 +//!= 1111 00x Data-processing and miscellaneous instructions +//!= 1111 010 Load/Store Word, Unsigned Byte (immediate, literal) +//!= 1111 011 0 Load/Store Word, Unsigned Byte (register) +//!= 1111 011 1 Media instructions +// 10x Branch, branch with link, and block data transfer +// 11x System register access, Advanced SIMD, floating-point, and Supervisor call +// 1111 0xx Unconditional instructions +static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { + const TopLevelEncodings enc = { bits }; + if (!(enc.op0 >> 2)) { // op0 == 0xx + if (enc.cond != 0b1111u) { + if (!(enc.op0 >> 1)) { // 00x + // Data-processing and miscellaneous instructions + return TryDataProcessingAndMisc(bits); + } else { + // TODO(Sonya): Load/Store Word, Unsigned Byte (immediate, literal) + // TODO(Sonya): Load/Store Word, Unsigned Byte (register) + // TODO(Sonya): Media instructions + return nullptr; + } + } else { + // TODO(Sonya): Unconditional instructions + return nullptr; + } + } else { // op0 == 1xx + // TODO(Sonya): Branch, branch with link, and block data transfer + // TODO(Sonya): System register access, Advanced SIMD, floating-point, and Supervisor call + return nullptr; + } } } // namespace @@ -796,7 +752,7 @@ bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_byte const auto bytes = reinterpret_cast(inst.bytes.data()); const auto bits = BytesToBits(bytes); - auto decoder = kBits27_to_21[(bits >> 21) & 0b1111111u]; + auto decoder = TryDecodeTopLevelEncodings(bits); if (!decoder) { LOG(ERROR) << "unhandled bits"; return false; diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index 130d2a84b..9dd2bd8e2 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -192,10 +192,10 @@ DEF_SEM(MULS, R32W dst, R32 src1, R32 src2, R32 src3) { } DEF_SEM(UMAAL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { - auto rhs = Read(src3); - auto lhs = Read(src2); - auto acc_hi = Read(src1); - auto acc_lo = Read(src4); + auto rhs = ZExt(Read(src3)); + auto lhs = ZExt(Read(src2)); + auto acc_hi = ZExt(Read(src1)); + auto acc_lo = ZExt(Read(src4)); auto res = UAdd(UAdd(UMul(lhs, rhs), acc_hi), acc_lo); Write(dst_lo, Trunc(res)); Write(dst_hi, Trunc(UShr(res, 32ul))); @@ -212,9 +212,9 @@ DEF_SEM(MLS, R32W dst, R32 src1, R32 src2, R32 src3) { } DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { - auto rhs = Read(src3); - auto lhs = Read(src2); - auto acc = UOr(UShl(ZExt(Read(src1))), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto rhs = ZExt(Read(src3)); + auto lhs = ZExt(Read(src2)); + auto acc = UOr(UShl(ZExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = UAdd(UMul(lhs, rhs), acc); Write(dst_hi, Trunc(UShr(res, 32ul))); Write(dst_lo, Trunc(res)); @@ -222,9 +222,9 @@ DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) } DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { - auto rhs = Read(src3); - auto lhs = Read(src2); - auto acc = UOr(UShl(ZExt(Read(src1))), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto rhs = ZExt(Read(src3)); + auto lhs = ZExt(Read(src2)); + auto acc = UOr(UShl(ZExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = UAdd(UMul(lhs, rhs), acc); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); @@ -236,24 +236,24 @@ DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4 DEF_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { // Not entirely sure about all the signed ops I have in here - auto rhs = Signed(Read(src3)); - auto lhs = Signed(Read(src2)); - auto acc = SOr(SShl(SExt(Read(src1))), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto rhs = SExt(Signed(Read(src3))); + auto lhs = SExt(Signed(Read(src2))); + auto acc = SOr(SShl(SExt(Read(src1)), 32ul), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); - Write(dst_hi, Trunc(UShr(res, 32ul))); + Write(dst_hi, Trunc(SShr(res, 32ul))); Write(dst_lo, Trunc(res)); return memory; } DEF_SEM(SMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { - auto rhs = Signed(Read(src3)); - auto lhs = Signed(Read(src2)); - auto acc = SOr(SShl(SExt(Read(src1))), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto rhs = SExt(Signed(Read(src3))); + auto lhs = SExt(Signed(Read(src2))); + auto acc = SOr(SShl(SExt(Read(src1)), 32ul), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); // PSTATE.C, PSTATE.V unchanged - Write(dst_hi, Trunc(UShr(res, 32ul))); + Write(dst_hi, Trunc(SShr(res, 32ul))); Write(dst_lo, Trunc(res)); return memory; } From 8e28749fdea15d88f71c7537b1b5ed6c6cb3693c Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 6 Oct 2020 09:56:30 -0400 Subject: [PATCH 051/130] Update returns around kDataProcessingRI and kDataProcessingI with comments to explain the correlation to the instruction rep --- remill/Arch/AArch32/Decode.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index cf5cbdd34..f5bca3f53 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -676,7 +676,9 @@ static TryDecode TryDataProcessingAndMisc(uint32_t bits) { } else if (!(((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) && !enc.op4) { // Data-processing register (immediate shift) - return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b00001u)]; + // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 lowest bit + // index is the concatenation of op0 and op1 + return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; } else { // TODO(Sonya): Extra load/store // TODO(Sonya): Synchronization primitives and Load-Acquire/Store-Release @@ -687,7 +689,9 @@ static TryDecode TryDataProcessingAndMisc(uint32_t bits) { } } else { // Data-processing immediate - return kDataProcessingI[(enc.op1 >> 1) | (enc.op1 & 0b00011u)]; + // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 2 lowest bits + // index is the concatenation of op0 and op1 + return kDataProcessingI[(enc.op1 >> 1) | (enc.op1 & 0b11u)]; } } From 10e7daa705bf99b66e8e739914d578af977a3ef7 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 6 Oct 2020 13:18:02 -0400 Subject: [PATCH 052/130] Added appropriate inst.category flags to Multiply and accumulate --- remill/Arch/AArch32/Decode.cpp | 35 +++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index f5bca3f53..4a02f9b21 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -535,7 +535,6 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) DecodeA32ExpandImm(inst, enc.imm12, enc.s); if (enc.rd == kPCRegNum) { - if (enc.s) { // Updates the flags (condition codes) inst.category = Instruction::kCategoryError; return false; @@ -583,6 +582,7 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { const MultiplyAndAccumulate enc = { bits }; // if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; if (enc.rdhi == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum) { + inst.category = Instruction::kCategoryError; return false; } @@ -594,10 +594,12 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rdhi, 32, Operand::kActionWrite); + // 2nd write reg only needed for instructions with an opc that begins with 1 and UMALL if (((enc.opc >> 2) & 0b1u) || enc.opc == 0b010u) { // if dHi == dLo then UNPREDICTABLE; - if (enc.rdlo == enc.rdhi){ + if (enc.rdlo == enc.rdhi || enc.rdlo == kPCRegNum){ + inst.category = Instruction::kCategoryError; return false; } AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionWrite); @@ -611,6 +613,7 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { } AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); + // If instruction is not MUL, UMULL, SMULL add read to RdLo otherwise add an immediate if (enc.opc != 0b000u && enc.opc != 0b100u && enc.opc != 0b110u) { AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionRead); @@ -618,6 +621,8 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { AddImmOp(inst, 0); } + inst.category = Instruction::kCategoryNormal; + return true; } @@ -637,11 +642,11 @@ static bool (*const kDataProcessingRI[])(Instruction&, uint32_t) = { [0b000] = TryDecodeIntegerDataProcessingRRR, [0b001] = TryDecodeIntegerDataProcessingRRR, [0b010] = TryDecodeIntegerDataProcessingRRR, - [0b011] = nullptr, - [0b100] = nullptr, - [0b101] = nullptr, - [0b110] = nullptr, - [0b111] = nullptr, + [0b011] = TryDecodeIntegerDataProcessingRRR, + [0b100] = nullptr, // op0:op1 != 100 + [0b101] = nullptr, // TODO(Sonya): Integer Test and Compare (two register, immediate shift) + [0b110] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, immediate shift) + [0b111] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, immediate shift) }; // Corresponds to Data-processing immediate @@ -655,14 +660,14 @@ static bool (*const kDataProcessingI[])(Instruction&, uint32_t) = { [0b0101] = TryDecodeIntegerDataProcessingRRI, [0b0110] = TryDecodeIntegerDataProcessingRRI, [0b0111] = TryDecodeIntegerDataProcessingRRI, - [0b1000] = nullptr, - [0b1001] = nullptr, - [0b1010] = nullptr, - [0b1011] = nullptr, - [0b1100] = nullptr, - [0b1101] = nullptr, - [0b1110] = nullptr, - [0b1111] = nullptr + [0b1000] = nullptr, // TODO(Sonya): Move Halfword (immediate) + [0b1001] = nullptr, // TODO(Sonya): Integer Test and Compare (one register and immediate) + [0b1010] = nullptr, // TODO(Sonya): Move Special Register and Hints (immediate) + [0b1011] = nullptr, // TODO(Sonya): Integer Test and Compare (one register and immediate) + [0b1100] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) + [0b1101] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) + [0b1110] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) + [0b1111] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) }; typedef bool (*const TryDecode)(Instruction&, uint32_t); From 5820e8aaa2678faf0c5a1ef308546d584c3872a9 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 6 Oct 2020 18:23:22 -0400 Subject: [PATCH 053/130] Load/Store Word, Unsigned Byte (immediate, literal) && start of Logical Arithmetic (three register, immediate shift) --- include/remill/Arch/Runtime/HyperCall.h | 2 +- remill/Arch/AArch32/Decode.cpp | 219 ++++++++++++++++++- remill/Arch/AArch32/Runtime/Instructions.cpp | 1 + remill/Arch/AArch32/Semantics/MEM.cpp | 87 ++++++++ 4 files changed, 297 insertions(+), 12 deletions(-) create mode 100644 remill/Arch/AArch32/Semantics/MEM.cpp diff --git a/include/remill/Arch/Runtime/HyperCall.h b/include/remill/Arch/Runtime/HyperCall.h index d5058c8de..6b827511c 100644 --- a/include/remill/Arch/Runtime/HyperCall.h +++ b/include/remill/Arch/Runtime/HyperCall.h @@ -88,7 +88,7 @@ class SyncHyperCall { kSPARCTrapCondVC, kSPARCTrapCondVS, }; -} __attribute__((packed)); +}__attribute__((packed)); class AsyncHyperCall { public: diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 4a02f9b21..270b27923 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -72,6 +72,42 @@ union MultiplyAndAccumulate { } __attribute__((packed)); static_assert(sizeof(MultiplyAndAccumulate) == 4, " "); +// Load/Store Word, Unsigned Byte (immediate, literal) +union LoadStoreWUBIL { + uint32_t flat; + struct { + uint32_t imm12 : 12; + uint32_t rt : 4; + uint32_t rn : 4; + uint32_t o1 : 1; + uint32_t W : 1; + uint32_t o2 : 1; + uint32_t u : 1; + uint32_t P : 1; + uint32_t _010 : 3; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(LoadStoreWUBIL) == 4, " "); + +// Logical Arithmetic (three register, immediate shift) +union LogicalArithRRRI { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _0 : 1; + uint32_t type : 2; + uint32_t imm5 : 5; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 2; + uint32_t _00011 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(LoadStoreWUBIL) == 4, " "); + // Top-level encodings for A32 union TopLevelEncodings { uint32_t flat; @@ -122,6 +158,7 @@ static const char * const kIntRegName[] = { "R14", "R15" }; +typedef bool (*const TryDecode)(Instruction&, uint32_t); static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out) { uint32_t unrotated_value = imm12 & (0b11111111u); @@ -279,6 +316,8 @@ static void AddShiftRegOperand(Instruction &inst, } } + +// (shift_t, shift_n) = DecodeImmShift(type, imm5) static void AddShiftCarryOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_size, const char * carry_reg_name) { @@ -624,16 +663,146 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { inst.category = Instruction::kCategoryNormal; return true; +} + +static const char * const kLoadSWUBIL[] = { + [0b0000] = "STRp", + [0b0001] = "LDRp", + [0b0010] = "STRBp", + [0b0011] = "LDRBp", + [0b0100] = "STRT", + [0b0101] = "LDRT", + [0b0110] = "STRBT", + [0b0111] = "LDRBT", + [0b1000] = "STR", + [0b1001] = "LDR", + [0b1010] = "STRB", + [0b1011] = "LDRB", + [0b1100] = "STRp", + [0b1101] = "LDRp", + [0b1110] = "STRBp", + [0b1111] = "LDRBp", +}; + +// P:W o2 o1 Rn +//!= 01 0 1 1111 LDR (literal) +//!= 01 1 1 1111 LDRB (literal) +// 00 0 0 STR (immediate) — post-indexed +// 00 0 1 != 1111 LDR (immediate) — post-indexed +// 00 1 0 STRB (immediate) — post-indexed +// 00 1 1 != 1111 LDRB (immediate) — post-indexed +// 01 0 0 STRT +// 01 0 1 LDRT +// 01 1 0 STRBT +// 01 1 1 LDRBT +// 10 0 0 STR (immediate) — offset +// 10 0 1 != 1111 LDR (immediate) — offset +// 10 1 0 STRB (immediate) — offset +// 10 1 1 != 1111 LDRB (immediate) — offset +// 11 0 0 STR (immediate) — pre-indexed +// 11 0 1 != 1111 LDR (immediate) — pre-indexed +// 11 1 0 STRB (immediate) — pre-indexed +// 11 1 1 != 1111 LDRB (immediate) — pre-indexed +template +static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { + const LoadStoreWUBIL enc = { bits }; + + auto instruction = kLoadSWUBIL[enc.P << 3u | enc.W << 2u | enc.o2 << 1u | enc.o1]; + if (!instruction) { + return false; + } + inst.function = instruction; + DecodeCondition(inst, enc.cond); + bool write_back = (!enc.P || enc.W); + + if (write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt)) { + inst.category = Instruction::kCategoryError; + return false; + } + + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.type = Operand::kTypeAddress; + op.size = kMemSize; + op.action = kMemAction; + op.addr.address_size = 32; + op.addr.base_reg.name = kIntRegName[enc.rn]; + op.addr.base_reg.size = 32; + op.addr.scale = 0; + op.addr.displacement = 0; + + // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes + int64_t pc_adjust = 0; + if (kAlignPC && enc.rn == kPCRegNum) { + pc_adjust = static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); + } + auto disp = static_cast(enc.imm12); + // Subtract + if (!enc.u) { + disp = -disp; + } + + // Not Indexing + if (!enc.P) { + op.addr.displacement = pc_adjust; + } else { + op.addr.displacement = disp + pc_adjust; + } + + AddIntRegOp(inst, enc.rt, 32, kRegAction); + + // Pre or Post Indexing + if (write_back) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.type = Operand::kTypeAddress; + op.size = 32; + op.action = Operand::kActionRead; + op.addr.address_size = 32; + op.addr.base_reg.name = kIntRegName[enc.rn]; + op.addr.base_reg.size = 32; + op.addr.scale = 0; + op.addr.displacement = disp + pc_adjust; + } + inst.category = Instruction::kCategoryNormal; + return true; } -static uint32_t BytesToBits(const uint8_t *bytes) { - uint32_t bits = 0; - bits = (bits << 8) | static_cast(bytes[0]); - bits = (bits << 8) | static_cast(bytes[1]); - bits = (bits << 8) | static_cast(bytes[2]); - bits = (bits << 8) | static_cast(bytes[3]); - return bits; +//00 ORR, ORRS (register) +//01 MOV, MOVS (register) +//10 BIC, BICS (register) +//11 MVN, MVNS (register) +static const char * const kLogicalArithmeticRRRI[] = { + [0b00] = "ORR", + [0b01] = "MOV", + [0b10] = "BIC", + [0b11] = "MVN", +}; + +// Logical Arithmetic (three register, immediate shift) +static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { + const LogicalArithRRRI enc = { bits }; + + auto instruction = kLogicalArithmeticRRRI[enc.opc]; + if (!instruction) { + return false; + } + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); + + if (enc.rd == kPCRegNum){ + if (enc.s) { + + } else { + + } + } + return true; } // Corresponds to Data-processing register (immediate shift) @@ -645,8 +814,8 @@ static bool (*const kDataProcessingRI[])(Instruction&, uint32_t) = { [0b011] = TryDecodeIntegerDataProcessingRRR, [0b100] = nullptr, // op0:op1 != 100 [0b101] = nullptr, // TODO(Sonya): Integer Test and Compare (two register, immediate shift) - [0b110] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, immediate shift) - [0b111] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, immediate shift) + [0b110] = TryLogicalArithmeticRRRI, + [0b111] = TryLogicalArithmeticRRRI, }; // Corresponds to Data-processing immediate @@ -670,8 +839,25 @@ static bool (*const kDataProcessingI[])(Instruction&, uint32_t) = { [0b1111] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) }; -typedef bool (*const TryDecode)(Instruction&, uint32_t); +// Corresponds to: Load/Store Word, Unsigned Byte (immediate, literal) +// o2<22> | o1<21> +static bool (*const kLoadStoreWordUBIL[])(Instruction&, uint32_t) = { + [0b00] = TryDecodeLoadStoreWordUBIL, + [0b01] = TryDecodeLoadStoreWordUBIL, + [0b10] = TryDecodeLoadStoreWordUBIL, + [0b11] = TryDecodeLoadStoreWordUBIL, +}; +// Corresponds to: Data-processing and miscellaneous instructions +//op0 op1 op2 op3 op4 +//0 1 != 00 1 Extra load/store +//0 0xxxx 1 00 1 Multiply and Accumulate +//0 1xxxx 1 00 1 Synchronization primitives and Load-Acquire/Store-Release +//0 10xx0 0 Miscellaneous +//0 10xx0 1 0 Halfword Multiply and Accumulate +//0 != 10xx0 0 Data-processing register (immediate shift) +//0 != 10xx0 0 1 Data-processing register (register shift) +//1 Data-processing immediate static TryDecode TryDataProcessingAndMisc(uint32_t bits) { const DataProcessingAndMisc enc = { bits }; if (!enc.op0) { @@ -715,8 +901,11 @@ static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { if (!(enc.op0 >> 1)) { // 00x // Data-processing and miscellaneous instructions return TryDataProcessingAndMisc(bits); + } else if (enc.op0 == 0b010u) { + // Load/Store Word, Unsigned Byte (immediate, literal) + const LoadStoreWUBIL enc_ls_word = { bits }; + return kLoadStoreWordUBIL[enc_ls_word.o2 << 1u | enc_ls_word.o1]; } else { - // TODO(Sonya): Load/Store Word, Unsigned Byte (immediate, literal) // TODO(Sonya): Load/Store Word, Unsigned Byte (register) // TODO(Sonya): Media instructions return nullptr; @@ -732,6 +921,14 @@ static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { } } +static uint32_t BytesToBits(const uint8_t *bytes) { + uint32_t bits = 0; + bits = (bits << 8) | static_cast(bytes[3]); + bits = (bits << 8) | static_cast(bytes[2]); + bits = (bits << 8) | static_cast(bytes[1]); + bits = (bits << 8) | static_cast(bytes[0]); + return bits; +} } // namespace // Decode an instuction. diff --git a/remill/Arch/AArch32/Runtime/Instructions.cpp b/remill/Arch/AArch32/Runtime/Instructions.cpp index 58fd30482..517556604 100644 --- a/remill/Arch/AArch32/Runtime/Instructions.cpp +++ b/remill/Arch/AArch32/Runtime/Instructions.cpp @@ -59,6 +59,7 @@ DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; #include "remill/Arch/AArch32/Semantics/FLAGS.cpp" // #include "remill/Arch/AArch32/Semantics/BINARY.cpp" +#include "remill/Arch/AArch32/Semantics/MEM.cpp" //#include "remill/Arch/AArch64/Semantics/BITBYTE.cpp" //#include "remill/Arch/AArch64/Semantics/BRANCH.cpp" //#include "remill/Arch/AArch64/Semantics/CALL_RET.cpp" diff --git a/remill/Arch/AArch32/Semantics/MEM.cpp b/remill/Arch/AArch32/Semantics/MEM.cpp new file mode 100644 index 000000000..ef539cc14 --- /dev/null +++ b/remill/Arch/AArch32/Semantics/MEM.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { +// Offset +template +DEF_SEM(STR, DstType dst, R32 src1) { + auto src = Read(src1); + Write(dst, TruncTo(src)); + return memory; +} + +// Pre + Post +template +DEF_SEM(STRp, DstType dst, R32 src1, R32W dst_reg, R32 src2) { + auto src = Read(src1); + auto new_val = Read(src2); + Write(dst, TruncTo(src)); + Write(dst_reg, new_val); + return memory; +} + +// Offset +template +DEF_SEM(LDR, SrcType src1, R32W dst) { + auto src = Read(src1); + WriteZExt(dst, src); + return memory; +} + +// Pre + Post +template +DEF_SEM(LDRp, SrcType src1, R32W dst, R32W dst_reg, R32 src2) { + auto src = Read(src1); + auto new_val = Read(src2); + WriteZExt(dst, src); + Write(dst_reg, new_val); + return memory; +} + +template +DEF_SEM(STRT, DstType dst, R32 src1, R32W dst_reg, R32 src2) { + memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + auto src = Read(src1); + auto new_val = Read(src2); + Write(dst, TruncTo(src)); + Write(dst_reg, new_val); + return memory; +} + +template +DEF_SEM(LDRT, SrcType src1, R32W dst, R32W dst_reg, R32 src2) { + memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + auto src = Read(src1); + auto new_val = Read(src2); + WriteZExt(dst, src); + Write(dst_reg, new_val); + return memory; +} + +} // namespace + +DEF_ISEL(STR) = STR; +DEF_ISEL(STRB) = STR; +DEF_ISEL(STRp) = STR; +DEF_ISEL(STRBp) = STR; +DEF_ISEL(LDR) = LDR; +DEF_ISEL(LDRB) = LDR; +DEF_ISEL(LDRp) = LDR; +DEF_ISEL(LDRBp) = LDR; +DEF_ISEL(STRT) = STRT; +DEF_ISEL(STRBT) = STRT; +DEF_ISEL(LDRT) = LDRT; +DEF_ISEL(LDRBT) = LDRT; From 14d90c385eb43e858f4acd209c7d19dcf69ec2a6 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 7 Oct 2020 10:18:15 -0400 Subject: [PATCH 054/130] Was missing UMAAL DEF_ISEL in Binary.cpp --- remill/Arch/AArch32/Semantics/BINARY.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index 9dd2bd8e2..c78dd6277 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -197,8 +197,8 @@ DEF_SEM(UMAAL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) auto acc_hi = ZExt(Read(src1)); auto acc_lo = ZExt(Read(src4)); auto res = UAdd(UAdd(UMul(lhs, rhs), acc_hi), acc_lo); - Write(dst_lo, Trunc(res)); - Write(dst_hi, Trunc(UShr(res, 32ul))); + Write(dst_lo, TruncTo(res)); + Write(dst_hi, TruncTo(UShr(res, 32ul))); return memory; } @@ -216,8 +216,8 @@ DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) auto lhs = ZExt(Read(src2)); auto acc = UOr(UShl(ZExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = UAdd(UMul(lhs, rhs), acc); - Write(dst_hi, Trunc(UShr(res, 32ul))); - Write(dst_lo, Trunc(res)); + Write(dst_hi, TruncTo(UShr(res, 32ul))); + Write(dst_lo, TruncTo(res)); return memory; } @@ -229,8 +229,8 @@ DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4 state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); // PSTATE.C, PSTATE.V unchanged - Write(dst_hi, Trunc(UShr(res, 32ul))); - Write(dst_lo, Trunc(res)); + Write(dst_hi, TruncTo(UShr(res, 32ul))); + Write(dst_lo, TruncTo(res)); return memory; } @@ -240,8 +240,8 @@ DEF_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) auto lhs = SExt(Signed(Read(src2))); auto acc = SOr(SShl(SExt(Read(src1)), 32ul), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); - Write(dst_hi, Trunc(SShr(res, 32ul))); - Write(dst_lo, Trunc(res)); + Write(dst_hi, TruncTo(SShr(res, 32ul))); + Write(dst_lo, TruncTo(res)); return memory; } @@ -253,8 +253,8 @@ DEF_SEM(SMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4 state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); // PSTATE.C, PSTATE.V unchanged - Write(dst_hi, Trunc(SShr(res, 32ul))); - Write(dst_lo, Trunc(res)); + Write(dst_hi, TruncTo(SShr(res, 32ul))); + Write(dst_lo, TruncTo(res)); return memory; } } // namespace @@ -264,6 +264,7 @@ DEF_ISEL(MULSrr) = MULS; DEF_ISEL(MLArr) = MUL; DEF_ISEL(MLASrr) = MULS; DEF_ISEL(MLSrr) = MLS; +DEF_ISEL(UMAALrr) = UMAAL; DEF_ISEL(UMULLrr) = UMULL; DEF_ISEL(UMULLSrr) = UMULLS; DEF_ISEL(UMLALrr) = UMULL; From 8aa2dde7a45d7a4f9a508a0511cf3500e6970662 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 8 Oct 2020 12:49:45 -0400 Subject: [PATCH 055/130] AddAddrRegOp --- remill/Arch/AArch32/Decode.cpp | 110 +++++++++++++++++---------------- 1 file changed, 56 insertions(+), 54 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 270b27923..0b29f412e 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -228,16 +228,31 @@ static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, } static void AddImmOp(Instruction &inst, uint64_t value, unsigned size = 32, - bool is_signed = false) { + Operand::Action action = Operand::kActionRead, + bool is_signed = false) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.imm.val = value; op.size = size; op.imm.is_signed = is_signed; - op.action = Operand::kActionRead; + op.action = action; op.type = Operand::kTypeImmediate; } +static void AddAddrRegOp(Instruction &inst, const char * reg_name, unsigned mem_size, + Operand::Action mem_action, unsigned disp, unsigned scale = 0) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.type = Operand::kTypeAddress; + op.size = mem_size; + op.action = mem_action; + op.addr.address_size = 32; + op.addr.base_reg.name = reg_name; + op.addr.base_reg.size = 32; + op.addr.scale = scale; + op.addr.displacement = disp; +} + // Note: Order is significant; extracted bits may be casted to this type. enum Shift : uint32_t { kShiftLSL, kShiftLSR, kShiftASR, kShiftROR }; @@ -556,16 +571,7 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) if (enc.rn == kPCRegNum && (enc.opc == 0b100u || enc.opc == 0b010u)) { int64_t diff = static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.type = Operand::kTypeAddress; - op.size = 32; - op.action = Operand::kActionRead; - op.addr.address_size = 32; - op.addr.base_reg.name = "PC"; - op.addr.base_reg.size = 32; - op.addr.scale = 0; - op.addr.displacement = diff; + AddAddrRegOp(inst, "PC", 32, Operand::kActionRead, diff); } else { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); @@ -686,8 +692,8 @@ static const char * const kLoadSWUBIL[] = { // P:W o2 o1 Rn -//!= 01 0 1 1111 LDR (literal) -//!= 01 1 1 1111 LDRB (literal) +//!= 01 0 1 1111 LDR (literal) +//!= 01 1 1 1111 LDRB (literal) // 00 0 0 STR (immediate) — post-indexed // 00 0 1 != 1111 LDR (immediate) — post-indexed // 00 1 0 STRB (immediate) — post-indexed @@ -721,17 +727,6 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { return false; } - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.type = Operand::kTypeAddress; - op.size = kMemSize; - op.action = kMemAction; - op.addr.address_size = 32; - op.addr.base_reg.name = kIntRegName[enc.rn]; - op.addr.base_reg.size = 32; - op.addr.scale = 0; - op.addr.displacement = 0; - // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes int64_t pc_adjust = 0; if (kAlignPC && enc.rn == kPCRegNum) { @@ -745,9 +740,9 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { // Not Indexing if (!enc.P) { - op.addr.displacement = pc_adjust; + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); } else { - op.addr.displacement = disp + pc_adjust; + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, disp + pc_adjust); } AddIntRegOp(inst, enc.rt, 32, kRegAction); @@ -755,17 +750,9 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { // Pre or Post Indexing if (write_back) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.type = Operand::kTypeAddress; - op.size = 32; - op.action = Operand::kActionRead; - op.addr.address_size = 32; - op.addr.base_reg.name = kIntRegName[enc.rn]; - op.addr.base_reg.size = 32; - op.addr.scale = 0; - op.addr.displacement = disp + pc_adjust; + AddAddrRegOp(inst, kIntRegName[enc.rn], 32, Operand::kActionRead, disp + pc_adjust); } + inst.category = Instruction::kCategoryNormal; return true; } @@ -775,17 +762,21 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { //10 BIC, BICS (register) //11 MVN, MVNS (register) static const char * const kLogicalArithmeticRRRI[] = { - [0b00] = "ORR", - [0b01] = "MOV", - [0b10] = "BIC", - [0b11] = "MVN", + [0b000] = "ORR", + [0b001] = "ORRS", + [0b010] = "MOV", + [0b011] = "MOVS", + [0b100] = "BIC", + [0b101] = "BICS", + [0b110] = "MVN", + [0b111] = "MVNS", }; // Logical Arithmetic (three register, immediate shift) static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { const LogicalArithRRRI enc = { bits }; - auto instruction = kLogicalArithmeticRRRI[enc.opc]; + auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; if (!instruction) { return false; } @@ -860,13 +851,15 @@ static bool (*const kLoadStoreWordUBIL[])(Instruction&, uint32_t) = { //1 Data-processing immediate static TryDecode TryDataProcessingAndMisc(uint32_t bits) { const DataProcessingAndMisc enc = { bits }; + + // op0 == 0 if (!enc.op0) { + // Multiply and Accumulate if ((!(enc.op1 >> 4)) && enc.op2 && (enc.op3 == 0b00u) && enc.op4) { - // Multiply and Accumulate return TryDecodeMultiplyAndAccumulate; - - } else if (!(((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) && !enc.op4) { - // Data-processing register (immediate shift) + } + // Data-processing register (immediate shift) + else if (!(((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) && !enc.op4) { // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 lowest bit // index is the concatenation of op0 and op1 return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; @@ -878,14 +871,19 @@ static TryDecode TryDataProcessingAndMisc(uint32_t bits) { // TODO(Sonya): Data-processing register (register shift) return nullptr; } - } else { - // Data-processing immediate + } + // op0 == 1 + // Data-processing immediate + else { // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 2 lowest bits // index is the concatenation of op0 and op1 return kDataProcessingI[(enc.op1 >> 1) | (enc.op1 & 0b11u)]; } } +// This is the top level of the instruction encoding schema for AArch32. +// Instructions are grouped into subsets based on this the top level and then +// into smaller sets. // cond op0 op1 //!= 1111 00x Data-processing and miscellaneous instructions //!= 1111 010 Load/Store Word, Unsigned Byte (immediate, literal) @@ -896,13 +894,15 @@ static TryDecode TryDataProcessingAndMisc(uint32_t bits) { // 1111 0xx Unconditional instructions static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { const TopLevelEncodings enc = { bits }; - if (!(enc.op0 >> 2)) { // op0 == 0xx + // op0 == 0xx + if (!(enc.op0 >> 2)) { if (enc.cond != 0b1111u) { - if (!(enc.op0 >> 1)) { // 00x - // Data-processing and miscellaneous instructions + // Data-processing and miscellaneous instructions -- op0 == 00x + if (!(enc.op0 >> 1)) { return TryDataProcessingAndMisc(bits); - } else if (enc.op0 == 0b010u) { - // Load/Store Word, Unsigned Byte (immediate, literal) + } + // Load/Store Word, Unsigned Byte (immediate, literal) -- op0 == 010 + else if (enc.op0 == 0b010u) { const LoadStoreWUBIL enc_ls_word = { bits }; return kLoadStoreWordUBIL[enc_ls_word.o2 << 1u | enc_ls_word.o1]; } else { @@ -914,7 +914,9 @@ static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { // TODO(Sonya): Unconditional instructions return nullptr; } - } else { // op0 == 1xx + } + // op0 == 1xx + else { // TODO(Sonya): Branch, branch with link, and block data transfer // TODO(Sonya): System register access, Advanced SIMD, floating-point, and Supervisor call return nullptr; From 6716d3995acbe059f8e7dc520dcbe3c5c1ea1023 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 8 Oct 2020 18:18:51 -0400 Subject: [PATCH 056/130] Logical Arithmetic (three register, immediate shift) without accounting for the possible PC jump --- remill/Arch/AArch32/Decode.cpp | 59 ++++++----- remill/Arch/AArch32/Runtime/Instructions.cpp | 2 +- remill/Arch/AArch32/Semantics/LOGICAL.cpp | 101 +++++++++++++++++++ 3 files changed, 136 insertions(+), 26 deletions(-) create mode 100644 remill/Arch/AArch32/Semantics/LOGICAL.cpp diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 0b29f412e..b4340656a 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -159,6 +159,7 @@ static const char * const kIntRegName[] = { "R15" }; typedef bool (*const TryDecode)(Instruction&, uint32_t); +typedef bool (*const TryDecodeList[])(Instruction&, uint32_t); static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out) { uint32_t unrotated_value = imm12 & (0b11111111u); @@ -272,6 +273,9 @@ static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { return Operand::ShiftRegister::kShiftInvalid; } + +// Used to handle (shift_t, shift_n) = DecodeImmShift(type, imm5) semantics +// See an instruction in Integer Data Processing (three register, immediate shift) set for an example static void AddShiftRegOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_size) { @@ -570,9 +574,7 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) // Raise the program counter to align to a multiple of 4 bytes if (enc.rn == kPCRegNum && (enc.opc == 0b100u || enc.opc == 0b010u)) { int64_t diff = static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); - AddAddrRegOp(inst, "PC", 32, Operand::kActionRead, diff); - } else { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); } @@ -757,19 +759,19 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { return true; } -//00 ORR, ORRS (register) -//01 MOV, MOVS (register) -//10 BIC, BICS (register) -//11 MVN, MVNS (register) +//00 ORR, ORRS (register) -- rd, rn, & rm +//01 MOV, MOVS (register) -- rd, & rm only +//10 BIC, BICS (register) -- rd, rn, & rm +//11 MVN, MVNS (register) -- rd, & rm only static const char * const kLogicalArithmeticRRRI[] = { - [0b000] = "ORR", - [0b001] = "ORRS", - [0b010] = "MOV", - [0b011] = "MOVS", - [0b100] = "BIC", - [0b101] = "BICS", - [0b110] = "MVN", - [0b111] = "MVNS", + [0b000] = "ORRrrri", + [0b001] = "ORRSrrri", + [0b010] = "MOVrrri", + [0b011] = "MOVSrrri", + [0b100] = "BICrrri", + [0b101] = "BICSrrri", + [0b110] = "MVNrrri", + [0b111] = "MVNSrrri", }; // Logical Arithmetic (three register, immediate shift) @@ -784,21 +786,28 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); - AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); - if (enc.rd == kPCRegNum){ - if (enc.s) { + // enc.opc == x0 + if (!(enc.opc & 0b1)) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + } - } else { + AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); + if (enc.s) { + AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); + } - } + if (enc.rd == kPCRegNum){ + // TODO(Sonya): handle the PC destination register case } + + inst.category = Instruction::kCategoryNormal; return true; } // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> -static bool (*const kDataProcessingRI[])(Instruction&, uint32_t) = { +static TryDecodeList kDataProcessingRI = { [0b000] = TryDecodeIntegerDataProcessingRRR, [0b001] = TryDecodeIntegerDataProcessingRRR, [0b010] = TryDecodeIntegerDataProcessingRRR, @@ -811,7 +820,7 @@ static bool (*const kDataProcessingRI[])(Instruction&, uint32_t) = { // Corresponds to Data-processing immediate // op0<24 to 23> | op1 <21 to 20> -static bool (*const kDataProcessingI[])(Instruction&, uint32_t) = { +static TryDecodeList kDataProcessingI = { [0b0000] = TryDecodeIntegerDataProcessingRRI, [0b0001] = TryDecodeIntegerDataProcessingRRI, [0b0010] = TryDecodeIntegerDataProcessingRRI, @@ -832,7 +841,7 @@ static bool (*const kDataProcessingI[])(Instruction&, uint32_t) = { // Corresponds to: Load/Store Word, Unsigned Byte (immediate, literal) // o2<22> | o1<21> -static bool (*const kLoadStoreWordUBIL[])(Instruction&, uint32_t) = { +static TryDecodeList kLoadStoreWordUBIL = { [0b00] = TryDecodeLoadStoreWordUBIL, [0b01] = TryDecodeLoadStoreWordUBIL, [0b10] = TryDecodeLoadStoreWordUBIL, @@ -906,12 +915,12 @@ static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { const LoadStoreWUBIL enc_ls_word = { bits }; return kLoadStoreWordUBIL[enc_ls_word.o2 << 1u | enc_ls_word.o1]; } else { - // TODO(Sonya): Load/Store Word, Unsigned Byte (register) - // TODO(Sonya): Media instructions + // TODO(Sonya): Load/Store Word, Unsigned Byte (register) -- op0 == 011, op1 == 0 + // TODO(Sonya): Media instructions -- op0 == 011, op1 == 1 return nullptr; } } else { - // TODO(Sonya): Unconditional instructions + // TODO(Sonya): Unconditional instructions -- cond == 1111 return nullptr; } } diff --git a/remill/Arch/AArch32/Runtime/Instructions.cpp b/remill/Arch/AArch32/Runtime/Instructions.cpp index 517556604..57a660776 100644 --- a/remill/Arch/AArch32/Runtime/Instructions.cpp +++ b/remill/Arch/AArch32/Runtime/Instructions.cpp @@ -60,13 +60,13 @@ DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; // #include "remill/Arch/AArch32/Semantics/BINARY.cpp" #include "remill/Arch/AArch32/Semantics/MEM.cpp" +#include "remill/Arch/AArch32/Semantics/LOGICAL.cpp" //#include "remill/Arch/AArch64/Semantics/BITBYTE.cpp" //#include "remill/Arch/AArch64/Semantics/BRANCH.cpp" //#include "remill/Arch/AArch64/Semantics/CALL_RET.cpp" //#include "remill/Arch/AArch64/Semantics/COND.cpp" //#include "remill/Arch/AArch64/Semantics/CONVERT.cpp" //#include "remill/Arch/AArch64/Semantics/DATAXFER.cpp" -//#include "remill/Arch/AArch64/Semantics/LOGICAL.cpp" //#include "remill/Arch/AArch64/Semantics/MISC.cpp" //#include "remill/Arch/AArch64/Semantics/SHIFT.cpp" //#include "remill/Arch/AArch64/Semantics/SIMD.cpp" diff --git a/remill/Arch/AArch32/Semantics/LOGICAL.cpp b/remill/Arch/AArch32/Semantics/LOGICAL.cpp new file mode 100644 index 000000000..6df45f74d --- /dev/null +++ b/remill/Arch/AArch32/Semantics/LOGICAL.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { + +DEF_SEM(ORR, R32W dst, R32 src1, I32 src2, I32 src2_rrx){ + auto value = UOr(Read(src2), Read(src2_rrx)); + auto result = UOr(Read(src1), value); + Write(dst, value); + return memory; +} + +DEF_SEM(ORRS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto value = UOr(Read(src2), Read(src2_rrx)); + auto result = UOr(Read(src1), value); + Write(dst, value); + + state.sr.n = SignFlag(value); + state.sr.z = ZeroFlag(value); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(MOV, R32W dst, I32 src, I32 src_rrx){ + auto value = UOr(Read(src), Read(src_rrx)); + Write(dst, value); + return memory; +} + +DEF_SEM(MOVS, R32W dst, I32 src, I32 src_rrx, I8 carry_out) { + auto value = UOr(Read(src), Read(src_rrx)); + Write(dst, value); + + state.sr.n = SignFlag(value); + state.sr.z = ZeroFlag(value); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(BIC, R32W dst, R32 src1, I32 src2, I32 src2_rrx){ + auto value = UNot(UOr(Read(src2), Read(src2_rrx))); + auto result = UAnd(Read(src1), value); + Write(dst, value); + return memory; +} + +DEF_SEM(BICS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto value = UNot(UOr(Read(src2), Read(src2_rrx))); + auto result = UAnd(Read(src1), value); + Write(dst, value); + + state.sr.n = SignFlag(value); + state.sr.z = ZeroFlag(value); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(MVN, R32W dst, I32 src, I32 src_rrx){ + auto value = UNot(UOr(Read(src), Read(src_rrx))); + Write(dst, value); + return memory; +} + +DEF_SEM(MVNS, R32W dst, I32 src, I32 src_rrx, I8 carry_out) { + auto value = UNot(UOr(Read(src), Read(src_rrx))); + Write(dst, value); + + state.sr.n = SignFlag(value); + state.sr.z = ZeroFlag(value); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +} // namespace + +DEF_ISEL(ORRrrri) = ORR; +DEF_ISEL(ORRSrrri) = ORRS; +DEF_ISEL(MOVrrri) = MOV; +DEF_ISEL(MOVSrrri) = MOVS; +DEF_ISEL(BICrrri) = BIC; +DEF_ISEL(BICSrrri) = BICS; +DEF_ISEL(MVNrrri) = MVN; +DEF_ISEL(MVNSrrri) = MVNS; + From 99afe5f06a729bc26db68e9df00847298fd57e91 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 8 Oct 2020 18:44:55 -0400 Subject: [PATCH 057/130] Made DecodeA32ExpandImm much much smaller --- remill/Arch/AArch32/Decode.cpp | 103 ++++++++++++++------------------- 1 file changed, 45 insertions(+), 58 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index b4340656a..eaa236644 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -161,62 +161,6 @@ static const char * const kIntRegName[] = { typedef bool (*const TryDecode)(Instruction&, uint32_t); typedef bool (*const TryDecodeList[])(Instruction&, uint32_t); -static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out) { - uint32_t unrotated_value = imm12 & (0b11111111u); - uint32_t rotation_amount = ((imm12 >> 8) & (0b1111u)) *2u; - auto num_ops = inst.operands.size(); - inst.operands.emplace_back(); - inst.operands.emplace_back(); - inst.operands.emplace_back(); - auto &op0 = inst.operands[num_ops]; - auto &op1 = inst.operands[num_ops + 1]; - auto &op2 = inst.operands[num_ops + 2]; - - op0.imm.is_signed = false; - op0.size = 32; - op0.action = Operand::kActionRead; - op0.type = Operand::kTypeImmediate; - - if (!rotation_amount) { - op0.imm.val = unrotated_value; - } else { - op0.imm.val = __builtin_rotateright32(unrotated_value, rotation_amount); - } - - // This is the 2nd part of RRX so we can reuse the same semantics - op1.imm.is_signed = false; - op1.imm.val = 0; - op1.size = 32; - op1.action = Operand::kActionRead; - op1.type = Operand::kTypeImmediate; - - if (!rotation_amount) { - op2.shift_reg.extract_size = 1; - op2.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; - - op2.shift_reg.shift_size = 0; - op2.type = Operand::kTypeShiftRegister; - op2.size = 32; - op2.action = Operand::kActionRead; - - op2.shift_reg.reg.name = "C"; - op2.shift_reg.reg.size = 8; - op2.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; - op2.shift_reg.shift_size = 0; - } else { - op2.imm.val = (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u; - op2.size = 32; - op2.imm.is_signed = false; - op2.action = Operand::kActionRead; - op2.type = Operand::kTypeImmediate; - } - - if (!carry_out) { - inst.operands.pop_back(); - } - -} - static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, Operand::Action action) { inst.operands.emplace_back(); @@ -273,8 +217,49 @@ static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { return Operand::ShiftRegister::kShiftInvalid; } +static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out) { + uint32_t unrotated_value = imm12 & (0b11111111u); + uint32_t rotation_amount = ((imm12 >> 8) & (0b1111u)) *2u; + + if (!rotation_amount) { + AddImmOp(inst, unrotated_value); + } else { + AddImmOp(inst, __builtin_rotateright32(unrotated_value, rotation_amount)); + } + + AddImmOp(inst, 0); + + if (carry_out) { + inst.operands.emplace_back(); + auto &op2 = inst.operands.back(); + if (!rotation_amount) { + op2.shift_reg.extract_size = 1; + op2.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; + + op2.shift_reg.shift_size = 0; + op2.type = Operand::kTypeShiftRegister; + op2.size = 32; + op2.action = Operand::kActionRead; + + op2.shift_reg.reg.name = "C"; + op2.shift_reg.reg.size = 8; + op2.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; + op2.shift_reg.shift_size = 0; + } else { + op2.imm.val = (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u; + op2.size = 32; + op2.imm.is_signed = false; + op2.action = Operand::kActionRead; + op2.type = Operand::kTypeImmediate; + } + } + +} -// Used to handle (shift_t, shift_n) = DecodeImmShift(type, imm5) semantics +// This function should be used with AddShiftCarryOperand to add carry_out operand! +// Used to handle semantics for: +// (shifted, carry) = Shift_C(R[m], shift_t, shift_n, PSTATE.C); +// (shift_t, shift_n) = DecodeImmShift(type, imm5); // See an instruction in Integer Data Processing (three register, immediate shift) set for an example static void AddShiftRegOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, @@ -336,7 +321,9 @@ static void AddShiftRegOperand(Instruction &inst, } -// (shift_t, shift_n) = DecodeImmShift(type, imm5) +// PLEASE SEE AddShiftRegOperand! +// This function extracts the carry_out that from the semantics that +// AddShiftRegOperand handles static void AddShiftCarryOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_size, const char * carry_reg_name) { From 3dc635648b6f28ec9e829b055a89e62353cd9ec5 Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 9 Oct 2020 10:17:08 -0400 Subject: [PATCH 058/130] Replaced some imm ops with AddImmOp calls --- remill/Arch/AArch32/Decode.cpp | 48 +++++++++++++++------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index eaa236644..50ba28341 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -158,6 +158,7 @@ static const char * const kIntRegName[] = { "R14", "R15" }; + typedef bool (*const TryDecode)(Instruction&, uint32_t); typedef bool (*const TryDecodeList[])(Instruction&, uint32_t); @@ -230,33 +231,30 @@ static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out AddImmOp(inst, 0); if (carry_out) { - inst.operands.emplace_back(); - auto &op2 = inst.operands.back(); if (!rotation_amount) { - op2.shift_reg.extract_size = 1; - op2.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; - - op2.shift_reg.shift_size = 0; - op2.type = Operand::kTypeShiftRegister; - op2.size = 32; - op2.action = Operand::kActionRead; - - op2.shift_reg.reg.name = "C"; - op2.shift_reg.reg.size = 8; - op2.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; - op2.shift_reg.shift_size = 0; + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.shift_reg.extract_size = 1; + op.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; + op.shift_reg.shift_size = 0; + op.type = Operand::kTypeShiftRegister; + op.size = 32; + op.action = Operand::kActionRead; + op.shift_reg.reg.name = "C"; + op.shift_reg.reg.size = 8; + op.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; + op.shift_reg.shift_size = 0; } else { - op2.imm.val = (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u; - op2.size = 32; - op2.imm.is_signed = false; - op2.action = Operand::kActionRead; - op2.type = Operand::kTypeImmediate; + AddImmOp(inst, (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u); } } } -// This function should be used with AddShiftCarryOperand to add carry_out operand! +// Note: This function should be used with AddShiftCarryOperand to add carry_out operand! +// This function adds 2 operands in total - an op and an op_rrx which should be +// ORed together when implementing Semantics + // Used to handle semantics for: // (shifted, carry) = Shift_C(R[m], shift_t, shift_n, PSTATE.C); // (shift_t, shift_n) = DecodeImmShift(type, imm5); @@ -299,9 +297,9 @@ static void AddShiftRegOperand(Instruction &inst, // together. No single operand type in remill is flexible enough to handle this. // So we make 2 operands and OR those two operands together. In most cases // when rrx isn't used we OR something with 0. - inst.operands.emplace_back(); - auto &op = inst.operands.back(); if (is_rrx) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); op.shift_reg.reg.name = "C"; op.shift_reg.reg.size = 8; @@ -312,11 +310,7 @@ static void AddShiftRegOperand(Instruction &inst, op.size = 32; op.action = Operand::kActionRead; } else { - op.imm.is_signed = false; - op.imm.val = 0; - op.size = 32; - op.action = Operand::kActionRead; - op.type = Operand::kTypeImmediate; + AddImmOp(inst, 0); } } From 701d75efada8ff9efc27816c299fb88528c9c3b8 Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 9 Oct 2020 17:37:42 -0400 Subject: [PATCH 059/130] Created AddShiftOp --- remill/Arch/AArch32/Decode.cpp | 194 +++++++++++++++++---------------- 1 file changed, 100 insertions(+), 94 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 50ba28341..97dac48bb 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -199,6 +199,25 @@ static void AddAddrRegOp(Instruction &inst, const char * reg_name, unsigned mem_ op.addr.displacement = disp; } +static void AddShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, + Operand::ShiftRegister::Extend extend_op, const char * reg_name, + unsigned reg_size, unsigned shift_size, unsigned extract_size, + Operand::Action action = Operand::kActionRead, unsigned size = 32) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.shift_reg.extract_size = extract_size; + op.shift_reg.extend_op = extend_op; + op.shift_reg.shift_size = shift_size; + op.type = Operand::kTypeShiftRegister; + op.size = size; + op.action = action; + op.shift_reg.reg.name = reg_name; + op.shift_reg.reg.size = reg_size; + op.shift_reg.shift_op = shift_op; + op.shift_reg.shift_size = shift_size; +} + + // Note: Order is significant; extracted bits may be casted to this type. enum Shift : uint32_t { kShiftLSL, kShiftLSR, kShiftASR, kShiftROR }; @@ -232,18 +251,7 @@ static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out if (carry_out) { if (!rotation_amount) { - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.shift_reg.extract_size = 1; - op.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; - op.shift_reg.shift_size = 0; - op.type = Operand::kTypeShiftRegister; - op.size = 32; - op.action = Operand::kActionRead; - op.shift_reg.reg.name = "C"; - op.shift_reg.reg.size = 8; - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; - op.shift_reg.shift_size = 0; + AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, "C", 8, 0, 1); } else { AddImmOp(inst, (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u); } @@ -275,22 +283,11 @@ static void AddShiftRegOperand(Instruction &inst, if (!shift_size) { AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); } else { - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.shift_reg.reg.name = kIntRegName[reg_num]; - op.shift_reg.reg.size = 32; - if (is_rrx) { - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; - op.shift_reg.shift_size = 1; + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendInvalid, kIntRegName[reg_num], 32, 1, 0); } else { - op.shift_reg.shift_op = GetOperandShift(static_cast(shift_type)); - op.shift_reg.shift_size = shift_size; + AddShiftOp(inst, GetOperandShift(static_cast(shift_type)), Operand::ShiftRegister::kExtendInvalid, kIntRegName[reg_num], 32, shift_size, 0); } - - op.type = Operand::kTypeShiftRegister; - op.size = 32; - op.action = Operand::kActionRead; } // To handle rrx we need to take two components shift each and OR the results @@ -298,17 +295,7 @@ static void AddShiftRegOperand(Instruction &inst, // So we make 2 operands and OR those two operands together. In most cases // when rrx isn't used we OR something with 0. if (is_rrx) { - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.shift_reg.reg.name = "C"; - op.shift_reg.reg.size = 8; - - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; - op.shift_reg.shift_size = 31; - - op.type = Operand::kTypeShiftRegister; - op.size = 32; - op.action = Operand::kActionRead; + AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendInvalid, "C", 8, 31, 0); } else { AddImmOp(inst, 0); } @@ -321,15 +308,6 @@ static void AddShiftRegOperand(Instruction &inst, static void AddShiftCarryOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_size, const char * carry_reg_name) { - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.shift_reg.extract_size = 1; - op.shift_reg.extend_op = Operand::ShiftRegister::kExtendUnsigned; - - op.shift_reg.shift_size = shift_size; - op.type = Operand::kTypeShiftRegister; - op.size = 32; - op.action = Operand::kActionRead; auto is_rrx = false; if (!shift_size && shift_type == Shift::kShiftROR) { @@ -338,33 +316,23 @@ static void AddShiftCarryOperand(Instruction &inst, } if (!shift_size) { - op.shift_reg.reg.name = carry_reg_name; - op.shift_reg.reg.size = 8; - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftLeftWithZeroes; - op.shift_reg.shift_size = 0; + AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, carry_reg_name, 8, 0, 1); } else { - op.shift_reg.reg.name = kIntRegName[reg_num]; - op.shift_reg.reg.size = 32; switch (static_cast(shift_type)) { case Shift::kShiftASR: - op.shift_reg.shift_size = shift_size - 1; - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftSignedRight; + AddShiftOp(inst, Operand::ShiftRegister::kShiftSignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); break; case Shift::kShiftLSL: - op.shift_reg.shift_size = 32 - shift_size; - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 32 - shift_size, 1); break; case Shift::kShiftLSR: - op.shift_reg.shift_size = shift_size - 1; - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); break; case Shift::kShiftROR: if (is_rrx) { - op.shift_reg.shift_size = 0; - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 0, 1); } else { - op.shift_reg.shift_size = (shift_size + 31u) % 32u; - op.shift_reg.shift_op = Operand::ShiftRegister::kShiftUnsignedRight; + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, (shift_size + 31u) % 32u, 1); } break; } @@ -830,40 +798,63 @@ static TryDecodeList kLoadStoreWordUBIL = { }; // Corresponds to: Data-processing and miscellaneous instructions -//op0 op1 op2 op3 op4 -//0 1 != 00 1 Extra load/store -//0 0xxxx 1 00 1 Multiply and Accumulate -//0 1xxxx 1 00 1 Synchronization primitives and Load-Acquire/Store-Release -//0 10xx0 0 Miscellaneous -//0 10xx0 1 0 Halfword Multiply and Accumulate -//0 != 10xx0 0 Data-processing register (immediate shift) -//0 != 10xx0 0 1 Data-processing register (register shift) -//1 Data-processing immediate +//op0 op1 op2 op3 op4 +// 0 1 != 00 1 Extra load/store +// 0 0xxxx 1 00 1 Multiply and Accumulate +// 0 1xxxx 1 00 1 Synchronization primitives and Load-Acquire/Store-Release +// 0 10xx0 0 Miscellaneous +// 0 10xx0 1 0 Halfword Multiply and Accumulate +// 0 != 10xx0 0 Data-processing register (immediate shift) +// 0 != 10xx0 0 1 Data-processing register (register shift) +// 1 Data-processing immediate static TryDecode TryDataProcessingAndMisc(uint32_t bits) { const DataProcessingAndMisc enc = { bits }; - // op0 == 0 if (!enc.op0) { - // Multiply and Accumulate - if ((!(enc.op1 >> 4)) && enc.op2 && (enc.op3 == 0b00u) && enc.op4) { - return TryDecodeMultiplyAndAccumulate; + // op2 == 1, op4 == 1 + if (enc.op2 && enc.op4) { + // TODO(Sonya): Extra load/store -- op3 != 00 + if (!enc.op3) { + return nullptr; + } + // op3 == 00 + else { + // Multiply and Accumulate -- op1 == 0xxxx + if (!(enc.op1 >> 4)) { + return TryDecodeMultiplyAndAccumulate; + } + // TODO(Sonya): Synchronization primitives and Load-Acquire/Store-Release -- op1 == 1xxxx + else { + return nullptr; + } + } } - // Data-processing register (immediate shift) - else if (!(((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) && !enc.op4) { - // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 lowest bit - // index is the concatenation of op0 and op1 - return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; - } else { - // TODO(Sonya): Extra load/store - // TODO(Sonya): Synchronization primitives and Load-Acquire/Store-Release + // op1 == 10xx0 + else if (((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) { // TODO(Sonya): Miscellaneous + if (!enc.op2) { + return nullptr; + } // TODO(Sonya): Halfword Multiply and Accumulate - // TODO(Sonya): Data-processing register (register shift) - return nullptr; + else { + return nullptr; + } + } + // op1 != 10xx0 + else { + // Data-processing register (immediate shift) -- op4 == 0 + if (!enc.op4) { + // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 lowest bit + // index is the concatenation of op0 and op1 + return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; + } + // TODO(Sonya): Data-processing register (register shift) -- op4 == 1 + else { + return nullptr; + } } } - // op0 == 1 - // Data-processing immediate + // Data-processing immediate -- op0 == 1 else { // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 2 lowest bits // index is the concatenation of op0 and op1 @@ -895,21 +886,36 @@ static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { else if (enc.op0 == 0b010u) { const LoadStoreWUBIL enc_ls_word = { bits }; return kLoadStoreWordUBIL[enc_ls_word.o2 << 1u | enc_ls_word.o1]; - } else { - // TODO(Sonya): Load/Store Word, Unsigned Byte (register) -- op0 == 011, op1 == 0 - // TODO(Sonya): Media instructions -- op0 == 011, op1 == 1 + } + // TODO(Sonya): Load/Store Word, Unsigned Byte (register) -- op0 == 011, op1 == 0 + else if (!enc.op1) { + // This should be returning another table index using a struct like above return nullptr; } - } else { - // TODO(Sonya): Unconditional instructions -- cond == 1111 + // TODO(Sonya): Media instructions -- op0 == 011, op1 == 1 + else { + // return a result from another function for instruction categorizing + return nullptr; + } + } + // TODO(Sonya): Unconditional instructions -- cond == 1111 + else { + // return a result from another function for instruction categorizing return nullptr; } } // op0 == 1xx else { - // TODO(Sonya): Branch, branch with link, and block data transfer - // TODO(Sonya): System register access, Advanced SIMD, floating-point, and Supervisor call - return nullptr; + // TODO(Sonya): Branch, branch with link, and block data transfer -- op0 == 10x + if (enc.op0 >> 1 == 0b10u) { + // return a result from another function for instruction categorizing + return nullptr; + } + // TODO(Sonya): System register access, Advanced SIMD, floating-point, and Supervisor call -- op0 == 11x + else { + // return a result from another function for instruction categorizing + return nullptr; + } } } From 84ad0984692222feb80036c2ab0831d476d375e2 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 13 Oct 2020 17:19:41 -0400 Subject: [PATCH 060/130] Added interpreter for evaluating new PC value at decoding time to handle direct jumps and conditional jumps --- include/remill/Arch/Instruction.h | 5 +- lib/Arch/Instruction.cpp | 91 +++++++++----- remill/Arch/AArch32/Decode.cpp | 193 +++++++++++++++++++++++++++++- 3 files changed, 256 insertions(+), 33 deletions(-) diff --git a/include/remill/Arch/Instruction.h b/include/remill/Arch/Instruction.h index 290430d74..30cace255 100644 --- a/include/remill/Arch/Instruction.h +++ b/include/remill/Arch/Instruction.h @@ -61,8 +61,9 @@ class Operand { Register reg; uint64_t shift_size; uint64_t extract_size; + bool shift_first; - enum Shift : unsigned { + enum Shift : uint8_t { kShiftInvalid, kShiftLeftWithZeroes, // Shift left, filling low order bits with zero. kShiftLeftWithOnes, // Shift left, filling low order bits with one. @@ -72,7 +73,7 @@ class Operand { kShiftRightAround // Rotate right. } shift_op; - enum Extend : unsigned { + enum Extend : uint8_t { kExtendInvalid, kExtendUnsigned, kExtendSigned, diff --git a/lib/Arch/Instruction.cpp b/lib/Arch/Instruction.cpp index 4890608d0..88136d369 100644 --- a/lib/Arch/Instruction.cpp +++ b/lib/Arch/Instruction.cpp @@ -31,6 +31,7 @@ Operand::Register::Register(void) : size(0) {} Operand::ShiftRegister::ShiftRegister(void) : shift_size(0), extract_size(0), + shift_first(false), shift_op(Operand::ShiftRegister::kShiftInvalid), extend_op(Operand::ShiftRegister::kExtendInvalid) {} @@ -72,49 +73,83 @@ std::string Operand::Serialize(void) const { ss << "(REG_" << reg.size << " " << reg.name << ")"; break; - case Operand::kTypeShiftRegister: + case Operand::kTypeShiftRegister: { + auto shift_begin = [&](void) { + switch (shift_reg.shift_op) { + case Operand::ShiftRegister::kShiftInvalid: break; - switch (shift_reg.shift_op) { - case Operand::ShiftRegister::kShiftInvalid: break; + case Operand::ShiftRegister::kShiftLeftWithZeroes: ss << "(LSL "; break; - case Operand::ShiftRegister::kShiftLeftWithZeroes: ss << "(LSL "; break; + case Operand::ShiftRegister::kShiftLeftWithOnes: ss << "(MSL "; break; - case Operand::ShiftRegister::kShiftLeftWithOnes: ss << "(MSL "; break; + case Operand::ShiftRegister::kShiftUnsignedRight: ss << "(LSR "; break; - case Operand::ShiftRegister::kShiftUnsignedRight: ss << "(LSR "; break; + case Operand::ShiftRegister::kShiftSignedRight: ss << "(ASR "; break; - case Operand::ShiftRegister::kShiftSignedRight: ss << "(ASR "; break; + case Operand::ShiftRegister::kShiftLeftAround: ss << "(ROL "; break; - case Operand::ShiftRegister::kShiftLeftAround: ss << "(ROL "; break; + case Operand::ShiftRegister::kShiftRightAround: ss << "(ROR "; break; + } + }; - case Operand::ShiftRegister::kShiftRightAround: ss << "(ROR "; break; - } + auto shift_end = [&](void) { + if (Operand::ShiftRegister::kShiftInvalid != shift_reg.shift_op) { + ss << " " << shift_reg.shift_size << ")"; + } + }; - switch (shift_reg.extend_op) { - case Operand::ShiftRegister::kExtendInvalid: - ss << "(REG_" << shift_reg.reg.size << " " << shift_reg.reg.name - << ")"; - break; + auto extract_begin = [&](void) { + switch (shift_reg.extend_op) { + case Operand::ShiftRegister::kExtendInvalid: + break; - case Operand::ShiftRegister::kExtendSigned: - ss << "(SEXT (TRUNC (REG_" << shift_reg.reg.size << " " - << shift_reg.reg.name << ") " << shift_reg.extract_size << ") " - << size << ")"; - break; + case Operand::ShiftRegister::kExtendSigned: + ss << "(SEXT (TRUNC "; + break; - case Operand::ShiftRegister::kExtendUnsigned: - ss << "(ZEXT (TRUNC (REG_" << shift_reg.reg.size << " " - << shift_reg.reg.name << ") " << shift_reg.extract_size << ") " - << size << ")"; - break; + case Operand::ShiftRegister::kExtendUnsigned: + ss << "(ZEXT (TRUNC "; + break; + } + }; + + auto extract_end = [&](void) { + switch (shift_reg.extend_op) { + case Operand::ShiftRegister::kExtendInvalid: + break; + + case Operand::ShiftRegister::kExtendSigned: + ss << " " << shift_reg.extract_size << ") " + << size << ")"; + break; + + case Operand::ShiftRegister::kExtendUnsigned: + ss << " " << shift_reg.extract_size << ") " + << size << ")"; + break; + } + }; + + if (shift_reg.shift_first) { + extract_begin(); + shift_begin(); + } else { + shift_begin(); + extract_begin(); } - if (Operand::ShiftRegister::kShiftInvalid != shift_reg.shift_op) { - ss << " " << shift_reg.shift_size << ")"; + ss << "(REG_" << shift_reg.reg.size << " " << shift_reg.reg.name << ")"; + + if (shift_reg.shift_first) { + shift_end(); + extract_end(); + } else { + extract_end(); + shift_end(); } break; - + } case Operand::kTypeImmediate: ss << "("; if (imm.is_signed) { diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 97dac48bb..2f9d3e0ca 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -202,7 +202,8 @@ static void AddAddrRegOp(Instruction &inst, const char * reg_name, unsigned mem_ static void AddShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, Operand::ShiftRegister::Extend extend_op, const char * reg_name, unsigned reg_size, unsigned shift_size, unsigned extract_size, - Operand::Action action = Operand::kActionRead, unsigned size = 32) { + Operand::Action action = Operand::kActionRead, unsigned size = 32, + bool shift_first = false) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.shift_reg.extract_size = extract_size; @@ -215,6 +216,7 @@ static void AddShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op op.shift_reg.reg.size = reg_size; op.shift_reg.shift_op = shift_op; op.shift_reg.shift_size = shift_size; + op.shift_reg.shift_first = shift_first; } @@ -436,6 +438,145 @@ static void DecodeCondition(Instruction &inst, uint32_t cond) { } } +std::optional EvalReg(const Instruction &inst, const Operand::Register &op) { + if (op.name == kIntRegName[kPCRegNum] || op.name == "PC") { + return inst.pc; + } else if (op.name == "NEXT_PC") { + return inst.next_pc; + } else if (op.name.empty()) { + return 0u; + } else { + return std::nullopt; + } +} + +std::optional EvalShift(const Operand::ShiftRegister &op, + std::optional maybe_val) { + if (!maybe_val || !op.shift_size) { + return maybe_val; + } + + if (op.reg.size != 32) { + return std::nullopt; + } + + auto val = static_cast(*maybe_val); + + switch (op.shift_op) { + case Operand::ShiftRegister::kShiftInvalid: + return maybe_val; + case Operand::ShiftRegister::kShiftLeftAround: + return __builtin_rotateleft32(val, static_cast(op.shift_size)); + case Operand::ShiftRegister::kShiftRightAround: + return __builtin_rotateright32(val, static_cast(op.shift_size)); + case Operand::ShiftRegister::kShiftLeftWithOnes: + return (val << op.shift_size) | ~(~0u << op.shift_size); + case Operand::ShiftRegister::kShiftLeftWithZeroes: + return val << op.shift_size; + case Operand::ShiftRegister::kShiftUnsignedRight: + return val >> op.shift_size; + case Operand::ShiftRegister::kShiftSignedRight: + return static_cast(static_cast(val) >> op.shift_size); + } +} + +std::optional EvalExtract(const Operand::ShiftRegister &op, + std::optional maybe_val) { + if (!maybe_val || !op.extract_size) { + return maybe_val; + } + + if (op.reg.size != 32) { + return std::nullopt; + } + + auto val = static_cast(*maybe_val); + + switch (op.extend_op) { + case Operand::ShiftRegister::kExtendInvalid: + return maybe_val; + case Operand::ShiftRegister::kExtendSigned: + { + val &= (1u << (op.extract_size)) - 1u; + auto sign = val >> (op.extract_size - 1u); + + if (sign) { + val |= ~0u << op.extract_size; + } + + return val; + } + case Operand::ShiftRegister::kExtendUnsigned: + return val & ((1u << (op.extract_size)) - 1u); + } + + +} + +std::optional EvalOperand(const Instruction &inst, const Operand &op) { + switch(op.type) { + case Operand::kTypeInvalid: + return std::nullopt; + case Operand::kTypeImmediate: + return op.imm.val; + case Operand::kTypeRegister: + return EvalReg(inst, op.reg); + case Operand::kTypeAddress: + { + auto seg_val = EvalReg(inst, op.addr.segment_base_reg); + auto base_val = EvalReg(inst, op.addr.base_reg); + auto index_val = EvalReg(inst, op.addr.index_reg); + + if (!seg_val || !base_val || !index_val) { + return std::nullopt; + } + + return static_cast( + static_cast(*seg_val) + static_cast(*base_val) + + (static_cast(*index_val) * op.addr.scale) + + op.addr.displacement); + + } + case Operand::kTypeShiftRegister: + if (op.shift_reg.shift_first) { + return EvalExtract(op.shift_reg, EvalShift(op.shift_reg, EvalReg(inst, op.shift_reg.reg))); + } else { + return EvalShift(op.shift_reg, EvalExtract(op.shift_reg, EvalReg(inst, op.shift_reg.reg))); + } + } + +} + +typedef std::optional (InstEval)(uint32_t, uint32_t, uint32_t); + +// High 3 bit opc +static InstEval * kIdpEvaluatorsRRR[] = { + [0b000] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(src1 & (src2 | src2_rrx)); + }, + [0b001] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(src1 ^ (src2 | src2_rrx)); + }, + [0b010] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(src1 - (src2 | src2_rrx)); + }, + [0b011] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional((src2 | src2_rrx) - src1); + }, + [0b100] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional((src2 | src2_rrx) + src1); + }, + [0b101] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(std::nullopt); + }, + [0b110] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(std::nullopt); + }, + [0b111] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(std::nullopt); + }, +}; + // High 3 bit opc and low bit s, opc:s static const char * const kIdpNamesRRR[] = { [0b0000] = "ANDrr", @@ -488,7 +629,26 @@ static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) inst.category = Instruction::kCategoryError; return false; } else { - inst.category = Instruction::kCategoryIndirectJump; + auto src1 = EvalOperand(inst, inst.operands[1]); + auto src2 = EvalOperand(inst, inst.operands[2]); + auto src2_rrx = EvalOperand(inst, inst.operands[3]); + + if (!src1 || !src2 || !src2_rrx) { + inst.category = Instruction::kCategoryIndirectJump; + } else { + auto res = kIdpEvaluatorsRRR[enc.opc](*src1, *src2, *src2_rrx); + + if (!res) { + inst.category = Instruction::kCategoryIndirectJump; + } else if (!inst.conditions.empty()) { + inst.branch_taken_pc = static_cast(*res); + inst.branch_not_taken_pc = inst.next_pc; + inst.category = Instruction::kCategoryConditionalBranch; + } else { + inst.branch_taken_pc = static_cast(*res); + inst.category = Instruction::kCategoryDirectJump; + } + } } } else { inst.category = Instruction::kCategoryNormal; @@ -535,7 +695,34 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) inst.category = Instruction::kCategoryError; return false; } else { - inst.category = Instruction::kCategoryIndirectJump; + auto src1 = EvalOperand(inst, inst.operands[1]); + auto src2 = EvalOperand(inst, inst.operands[2]); + auto src2_rrx = EvalOperand(inst, inst.operands[3]); + + if (!src1 || !src2 || !src2_rrx) { + inst.category = Instruction::kCategoryIndirectJump; + } else { + auto src1 = EvalOperand(inst, inst.operands[1]); + auto src2 = EvalOperand(inst, inst.operands[2]); + auto src2_rrx = EvalOperand(inst, inst.operands[3]); + + if (!src1 || !src2 || !src2_rrx) { + inst.category = Instruction::kCategoryIndirectJump; + } else { + auto res = kIdpEvaluatorsRRR[enc.opc](*src1, *src2, *src2_rrx); + + if (!res) { + inst.category = Instruction::kCategoryIndirectJump; + } else if (!inst.conditions.empty()) { + inst.branch_taken_pc = static_cast(*res); + inst.branch_not_taken_pc = inst.next_pc; + inst.category = Instruction::kCategoryConditionalBranch; + } else { + inst.branch_taken_pc = static_cast(*res); + inst.category = Instruction::kCategoryDirectJump; + } + } + } } } else { inst.category = Instruction::kCategoryNormal; From 994952c361be2d262d7d880d9031faf36a17e770 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 13 Oct 2020 18:23:39 -0400 Subject: [PATCH 061/130] Created EvalPCDest added PC evaluation to Logical Arithmetic Instructions --- remill/Arch/AArch32/Decode.cpp | 132 +++++++++------------- remill/Arch/AArch32/Semantics/LOGICAL.cpp | 8 +- 2 files changed, 55 insertions(+), 85 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 2f9d3e0ca..c3cd1a8b1 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -550,7 +550,7 @@ std::optional EvalOperand(const Instruction &inst, const Operand &op) typedef std::optional (InstEval)(uint32_t, uint32_t, uint32_t); // High 3 bit opc -static InstEval * kIdpEvaluatorsRRR[] = { +static InstEval * kIdpEvaluators[] = { [0b000] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { return std::optional(src1 & (src2 | src2_rrx)); }, @@ -577,6 +577,38 @@ static InstEval * kIdpEvaluatorsRRR[] = { }, }; +static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, InstEval * evaluator) { + if (rd == kPCRegNum) { + if (s) { // Updates the flags (condition codes) + inst.category = Instruction::kCategoryError; + return false; + } else { + auto src1 = EvalOperand(inst, inst.operands[1]); + auto src2 = EvalOperand(inst, inst.operands[2]); + auto src2_rrx = EvalOperand(inst, inst.operands[3]); + + if (!src1 || !src2 || !src2_rrx) { + inst.category = Instruction::kCategoryIndirectJump; + } else { + auto res = evaluator(*src1, *src2, *src2_rrx); + if (!res) { + inst.category = Instruction::kCategoryIndirectJump; + } else if (!inst.conditions.empty()) { + inst.branch_taken_pc = static_cast(*res); + inst.branch_not_taken_pc = inst.next_pc; + inst.category = Instruction::kCategoryConditionalBranch; + } else { + inst.branch_taken_pc = static_cast(*res); + inst.category = Instruction::kCategoryDirectJump; + } + } + } + } else { + inst.category = Instruction::kCategoryNormal; + } + return true; +} + // High 3 bit opc and low bit s, opc:s static const char * const kIdpNamesRRR[] = { [0b0000] = "ANDrr", @@ -624,37 +656,7 @@ static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - if (enc.rd == kPCRegNum) { - if (enc.s) { // Updates the flags (condition codes) - inst.category = Instruction::kCategoryError; - return false; - } else { - auto src1 = EvalOperand(inst, inst.operands[1]); - auto src2 = EvalOperand(inst, inst.operands[2]); - auto src2_rrx = EvalOperand(inst, inst.operands[3]); - - if (!src1 || !src2 || !src2_rrx) { - inst.category = Instruction::kCategoryIndirectJump; - } else { - auto res = kIdpEvaluatorsRRR[enc.opc](*src1, *src2, *src2_rrx); - - if (!res) { - inst.category = Instruction::kCategoryIndirectJump; - } else if (!inst.conditions.empty()) { - inst.branch_taken_pc = static_cast(*res); - inst.branch_not_taken_pc = inst.next_pc; - inst.category = Instruction::kCategoryConditionalBranch; - } else { - inst.branch_taken_pc = static_cast(*res); - inst.category = Instruction::kCategoryDirectJump; - } - } - } - } else { - inst.category = Instruction::kCategoryNormal; - } - - return true; + return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); } //000 AND, ANDS (immediate) @@ -690,45 +692,8 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) DecodeA32ExpandImm(inst, enc.imm12, enc.s); - if (enc.rd == kPCRegNum) { - if (enc.s) { // Updates the flags (condition codes) - inst.category = Instruction::kCategoryError; - return false; - } else { - auto src1 = EvalOperand(inst, inst.operands[1]); - auto src2 = EvalOperand(inst, inst.operands[2]); - auto src2_rrx = EvalOperand(inst, inst.operands[3]); - - if (!src1 || !src2 || !src2_rrx) { - inst.category = Instruction::kCategoryIndirectJump; - } else { - auto src1 = EvalOperand(inst, inst.operands[1]); - auto src2 = EvalOperand(inst, inst.operands[2]); - auto src2_rrx = EvalOperand(inst, inst.operands[3]); - - if (!src1 || !src2 || !src2_rrx) { - inst.category = Instruction::kCategoryIndirectJump; - } else { - auto res = kIdpEvaluatorsRRR[enc.opc](*src1, *src2, *src2_rrx); + return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); - if (!res) { - inst.category = Instruction::kCategoryIndirectJump; - } else if (!inst.conditions.empty()) { - inst.branch_taken_pc = static_cast(*res); - inst.branch_not_taken_pc = inst.next_pc; - inst.category = Instruction::kCategoryConditionalBranch; - } else { - inst.branch_taken_pc = static_cast(*res); - inst.category = Instruction::kCategoryDirectJump; - } - } - } - } - } else { - inst.category = Instruction::kCategoryNormal; - } - - return true; } @@ -895,6 +860,21 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { return true; } +static InstEval * kLogArithEvaluators[] = { + [0b00] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(src1 | (src2 | src2_rrx)); + }, + [0b01] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(src2 | src2_rrx); + }, + [0b10] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(src1 & ~(src2 | src2_rrx)); + }, + [0b11] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + return std::optional(~(src2 | src2_rrx)); + }, +}; + //00 ORR, ORRS (register) -- rd, rn, & rm //01 MOV, MOVS (register) -- rd, & rm only //10 BIC, BICS (register) -- rd, rn, & rm @@ -923,22 +903,12 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); - // enc.opc == x0 - if (!(enc.opc & 0b1)) { - AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); - } - AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); if (enc.s) { AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - if (enc.rd == kPCRegNum){ - // TODO(Sonya): handle the PC destination register case - } - - inst.category = Instruction::kCategoryNormal; - return true; + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc]); } // Corresponds to Data-processing register (immediate shift) diff --git a/remill/Arch/AArch32/Semantics/LOGICAL.cpp b/remill/Arch/AArch32/Semantics/LOGICAL.cpp index 6df45f74d..1f66224b8 100644 --- a/remill/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/remill/Arch/AArch32/Semantics/LOGICAL.cpp @@ -35,13 +35,13 @@ DEF_SEM(ORRS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { return memory; } -DEF_SEM(MOV, R32W dst, I32 src, I32 src_rrx){ +DEF_SEM(MOV, R32W dst, R32 _, I32 src, I32 src_rrx){ auto value = UOr(Read(src), Read(src_rrx)); Write(dst, value); return memory; } -DEF_SEM(MOVS, R32W dst, I32 src, I32 src_rrx, I8 carry_out) { +DEF_SEM(MOVS, R32W dst, R32 _, I32 src, I32 src_rrx, I8 carry_out) { auto value = UOr(Read(src), Read(src_rrx)); Write(dst, value); @@ -71,13 +71,13 @@ DEF_SEM(BICS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { return memory; } -DEF_SEM(MVN, R32W dst, I32 src, I32 src_rrx){ +DEF_SEM(MVN, R32W dst, R32 _, I32 src, I32 src_rrx){ auto value = UNot(UOr(Read(src), Read(src_rrx))); Write(dst, value); return memory; } -DEF_SEM(MVNS, R32W dst, I32 src, I32 src_rrx, I8 carry_out) { +DEF_SEM(MVNS, R32W dst, R32 _, I32 src, I32 src_rrx, I8 carry_out) { auto value = UNot(UOr(Read(src), Read(src_rrx))); Write(dst, value); From 8302a1db47233dd2ae4a5252328a26bc16760a01 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 13 Oct 2020 18:46:10 -0400 Subject: [PATCH 062/130] AddShiftOp -> AddShiftOp, AddShiftThenExtractOp, AddExtractThenShiftOp --- remill/Arch/AArch32/Decode.cpp | 76 ++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 21 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index c3cd1a8b1..1bae82568 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -161,6 +161,7 @@ static const char * const kIntRegName[] = { typedef bool (*const TryDecode)(Instruction&, uint32_t); typedef bool (*const TryDecodeList[])(Instruction&, uint32_t); +typedef std::optional (InstEval)(uint32_t, uint32_t, uint32_t); static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, Operand::Action action) { @@ -200,10 +201,44 @@ static void AddAddrRegOp(Instruction &inst, const char * reg_name, unsigned mem_ } static void AddShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, - Operand::ShiftRegister::Extend extend_op, const char * reg_name, - unsigned reg_size, unsigned shift_size, unsigned extract_size, - Operand::Action action = Operand::kActionRead, unsigned size = 32, - bool shift_first = false) { + const char * reg_name, unsigned reg_size, unsigned shift_size, + Operand::Action action = Operand::kActionRead, unsigned size = 32) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.shift_reg.shift_size = shift_size; + op.type = Operand::kTypeShiftRegister; + op.size = size; + op.action = action; + op.shift_reg.reg.name = reg_name; + op.shift_reg.reg.size = reg_size; + op.shift_reg.shift_op = shift_op; + op.shift_reg.shift_size = shift_size; +} + +static void AddShiftThenExtractOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, + Operand::ShiftRegister::Extend extend_op, const char * reg_name, + unsigned reg_size, unsigned shift_size, unsigned extract_size, + Operand::Action action = Operand::kActionRead, unsigned size = 32) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.shift_reg.extract_size = extract_size; + op.shift_reg.extend_op = extend_op; + op.shift_reg.shift_size = shift_size; + op.type = Operand::kTypeShiftRegister; + op.size = size; + op.action = action; + op.shift_reg.reg.name = reg_name; + op.shift_reg.reg.size = reg_size; + op.shift_reg.shift_op = shift_op; + op.shift_reg.shift_size = shift_size; + op.shift_reg.shift_first = true; + +} + +static void AddExtractThenShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, + Operand::ShiftRegister::Extend extend_op, const char * reg_name, + unsigned reg_size, unsigned shift_size, unsigned extract_size, + Operand::Action action = Operand::kActionRead, unsigned size = 32) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.shift_reg.extract_size = extract_size; @@ -216,7 +251,7 @@ static void AddShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op op.shift_reg.reg.size = reg_size; op.shift_reg.shift_op = shift_op; op.shift_reg.shift_size = shift_size; - op.shift_reg.shift_first = shift_first; + op.shift_reg.shift_first = false; } @@ -253,7 +288,7 @@ static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out if (carry_out) { if (!rotation_amount) { - AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, "C", 8, 0, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, "C", 8, 0, 1); } else { AddImmOp(inst, (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u); } @@ -286,9 +321,9 @@ static void AddShiftRegOperand(Instruction &inst, AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); } else { if (is_rrx) { - AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendInvalid, kIntRegName[reg_num], 32, 1, 0); + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, kIntRegName[reg_num], 32, 1); } else { - AddShiftOp(inst, GetOperandShift(static_cast(shift_type)), Operand::ShiftRegister::kExtendInvalid, kIntRegName[reg_num], 32, shift_size, 0); + AddShiftOp(inst, GetOperandShift(static_cast(shift_type)), kIntRegName[reg_num], 32, shift_size); } } @@ -297,7 +332,7 @@ static void AddShiftRegOperand(Instruction &inst, // So we make 2 operands and OR those two operands together. In most cases // when rrx isn't used we OR something with 0. if (is_rrx) { - AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendInvalid, "C", 8, 31, 0); + AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, "C", 8, 31); } else { AddImmOp(inst, 0); } @@ -318,23 +353,23 @@ static void AddShiftCarryOperand(Instruction &inst, } if (!shift_size) { - AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, carry_reg_name, 8, 0, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, carry_reg_name, 8, 0, 1); } else { switch (static_cast(shift_type)) { case Shift::kShiftASR: - AddShiftOp(inst, Operand::ShiftRegister::kShiftSignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftSignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); break; case Shift::kShiftLSL: - AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 32 - shift_size, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 32 - shift_size, 1); break; case Shift::kShiftLSR: - AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); break; case Shift::kShiftROR: if (is_rrx) { - AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 0, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 0, 1); } else { - AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, (shift_size + 31u) % 32u, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, (shift_size + 31u) % 32u, 1); } break; } @@ -547,8 +582,6 @@ std::optional EvalOperand(const Instruction &inst, const Operand &op) } -typedef std::optional (InstEval)(uint32_t, uint32_t, uint32_t); - // High 3 bit opc static InstEval * kIdpEvaluators[] = { [0b000] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { @@ -577,7 +610,8 @@ static InstEval * kIdpEvaluators[] = { }, }; -static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, InstEval * evaluator) { +template +static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, Evaluator * evaluator) { if (rd == kPCRegNum) { if (s) { // Updates the flags (condition codes) inst.category = Instruction::kCategoryError; @@ -656,7 +690,7 @@ static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); } //000 AND, ANDS (immediate) @@ -692,7 +726,7 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) DecodeA32ExpandImm(inst, enc.imm12, enc.s); - return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); } @@ -908,7 +942,7 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc]); } // Corresponds to Data-processing register (immediate shift) From b2e05af590175caeef772063a294a4b8f0d10725 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 13 Oct 2020 19:16:06 -0400 Subject: [PATCH 063/130] Cleaned up some formatting, Renamed DecodeA32ExpandImm to ExpandTo32AddImmAddCarry and added a clarifying comment --- remill/Arch/AArch32/Decode.cpp | 94 ++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 28 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 1bae82568..5e43eef3b 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -186,8 +186,9 @@ static void AddImmOp(Instruction &inst, uint64_t value, unsigned size = 32, op.type = Operand::kTypeImmediate; } -static void AddAddrRegOp(Instruction &inst, const char * reg_name, unsigned mem_size, - Operand::Action mem_action, unsigned disp, unsigned scale = 0) { +static void AddAddrRegOp(Instruction &inst, const char *reg_name, + unsigned mem_size, Operand::Action mem_action, + unsigned disp, unsigned scale = 0) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.type = Operand::kTypeAddress; @@ -200,9 +201,12 @@ static void AddAddrRegOp(Instruction &inst, const char * reg_name, unsigned mem_ op.addr.displacement = disp; } -static void AddShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, - const char * reg_name, unsigned reg_size, unsigned shift_size, - Operand::Action action = Operand::kActionRead, unsigned size = 32) { +static void AddShiftOp(Instruction &inst, + Operand::ShiftRegister::Shift shift_op, + const char *reg_name, unsigned reg_size, + unsigned shift_size, Operand::Action action = + Operand::kActionRead, + unsigned size = 32) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.shift_reg.shift_size = shift_size; @@ -215,10 +219,13 @@ static void AddShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op op.shift_reg.shift_size = shift_size; } -static void AddShiftThenExtractOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, - Operand::ShiftRegister::Extend extend_op, const char * reg_name, - unsigned reg_size, unsigned shift_size, unsigned extract_size, - Operand::Action action = Operand::kActionRead, unsigned size = 32) { +static void AddShiftThenExtractOp(Instruction &inst, + Operand::ShiftRegister::Shift shift_op, + Operand::ShiftRegister::Extend extend_op, + const char *reg_name, unsigned reg_size, + unsigned shift_size, unsigned extract_size, + Operand::Action action = Operand::kActionRead, + unsigned size = 32) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.shift_reg.extract_size = extract_size; @@ -235,10 +242,13 @@ static void AddShiftThenExtractOp(Instruction &inst, Operand::ShiftRegister::Shi } -static void AddExtractThenShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, - Operand::ShiftRegister::Extend extend_op, const char * reg_name, - unsigned reg_size, unsigned shift_size, unsigned extract_size, - Operand::Action action = Operand::kActionRead, unsigned size = 32) { +static void AddExtractThenShiftOp(Instruction &inst, + Operand::ShiftRegister::Shift shift_op, + Operand::ShiftRegister::Extend extend_op, + const char *reg_name, unsigned reg_size, + unsigned shift_size, unsigned extract_size, + Operand::Action action = Operand::kActionRead, + unsigned size = 32) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.shift_reg.extract_size = extract_size; @@ -274,7 +284,14 @@ static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { return Operand::ShiftRegister::kShiftInvalid; } -static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out) { +// Note: This function adds either 2 or 3 operands in total +// an op and an op_rrx which should be ORed together when adding Semantics, +// and if carry_out an additional carry_out op + +// Used to handle semantics for: +// (shift_t, shift_n) = DecodeImmShift(type, imm5); +// See an instruction in Data-processing register (immediate shift) for example +static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, bool carry_out) { uint32_t unrotated_value = imm12 & (0b11111111u); uint32_t rotation_amount = ((imm12 >> 8) & (0b1111u)) *2u; @@ -288,12 +305,14 @@ static void DecodeA32ExpandImm(Instruction &inst, uint32_t imm12, bool carry_out if (carry_out) { if (!rotation_amount) { - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, "C", 8, 0, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, + Operand::ShiftRegister::kExtendUnsigned, "C", 8, 0, + 1); } else { - AddImmOp(inst, (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u); + AddImmOp(inst, + (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u); } } - } // Note: This function should be used with AddShiftCarryOperand to add carry_out operand! @@ -321,9 +340,11 @@ static void AddShiftRegOperand(Instruction &inst, AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); } else { if (is_rrx) { - AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, kIntRegName[reg_num], 32, 1); + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, + kIntRegName[reg_num], 32, 1); } else { - AddShiftOp(inst, GetOperandShift(static_cast(shift_type)), kIntRegName[reg_num], 32, shift_size); + AddShiftOp(inst, GetOperandShift(static_cast(shift_type)), + kIntRegName[reg_num], 32, shift_size); } } @@ -353,23 +374,38 @@ static void AddShiftCarryOperand(Instruction &inst, } if (!shift_size) { - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, carry_reg_name, 8, 0, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, + Operand::ShiftRegister::kExtendUnsigned, + carry_reg_name, 8, 0, 1); } else { switch (static_cast(shift_type)) { case Shift::kShiftASR: - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftSignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftSignedRight, + Operand::ShiftRegister::kExtendUnsigned, + kIntRegName[reg_num], 32, shift_size - 1, 1); break; case Shift::kShiftLSL: - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 32 - shift_size, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, + Operand::ShiftRegister::kExtendUnsigned, + kIntRegName[reg_num], 32, 32 - shift_size, 1); break; case Shift::kShiftLSR: - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, shift_size - 1, 1); + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, + Operand::ShiftRegister::kExtendUnsigned, + kIntRegName[reg_num], 32, shift_size - 1, 1); break; case Shift::kShiftROR: if (is_rrx) { - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, 0, 1); + AddShiftThenExtractOp(inst, + Operand::ShiftRegister::kShiftUnsignedRight, + Operand::ShiftRegister::kExtendUnsigned, + kIntRegName[reg_num], 32, 0, 1); } else { - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, (shift_size + 31u) % 32u, 1); + AddShiftThenExtractOp(inst, + Operand::ShiftRegister::kShiftUnsignedRight, + Operand::ShiftRegister::kExtendUnsigned, + kIntRegName[reg_num], 32, + (shift_size + 31u) % 32u, 1); } break; } @@ -611,9 +647,11 @@ static InstEval * kIdpEvaluators[] = { }; template -static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, Evaluator * evaluator) { +static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, + Evaluator *evaluator) { if (rd == kPCRegNum) { - if (s) { // Updates the flags (condition codes) + // Updates the flags (condition codes) + if (s) { inst.category = Instruction::kCategoryError; return false; } else { @@ -724,7 +762,7 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); } - DecodeA32ExpandImm(inst, enc.imm12, enc.s); + ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s); return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); From a3b0d5cede48cae1fc8a42bc83374ac17d0ac54a Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 13 Oct 2020 19:48:19 -0400 Subject: [PATCH 064/130] Added comment to EvalPCDest for clarity --- remill/Arch/AArch32/Decode.cpp | 76 ++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 5e43eef3b..dff4b11f2 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -618,6 +618,47 @@ std::optional EvalOperand(const Instruction &inst, const Operand &op) } +// Handles appropriate branching semantics for: +// if d == 15 then +// if setflags then +// ALUExceptionReturn(result); +// else +// ALUWritePC(result); +template +static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, + Evaluator *evaluator) { + if (rd == kPCRegNum) { + // Updates the flags (condition codes) + if (s) { + inst.category = Instruction::kCategoryError; + return false; + } else { + auto src1 = EvalOperand(inst, inst.operands[1]); + auto src2 = EvalOperand(inst, inst.operands[2]); + auto src2_rrx = EvalOperand(inst, inst.operands[3]); + + if (!src1 || !src2 || !src2_rrx) { + inst.category = Instruction::kCategoryIndirectJump; + } else { + auto res = evaluator(*src1, *src2, *src2_rrx); + if (!res) { + inst.category = Instruction::kCategoryIndirectJump; + } else if (!inst.conditions.empty()) { + inst.branch_taken_pc = static_cast(*res); + inst.branch_not_taken_pc = inst.next_pc; + inst.category = Instruction::kCategoryConditionalBranch; + } else { + inst.branch_taken_pc = static_cast(*res); + inst.category = Instruction::kCategoryDirectJump; + } + } + } + } else { + inst.category = Instruction::kCategoryNormal; + } + return true; +} + // High 3 bit opc static InstEval * kIdpEvaluators[] = { [0b000] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { @@ -646,41 +687,6 @@ static InstEval * kIdpEvaluators[] = { }, }; -template -static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, - Evaluator *evaluator) { - if (rd == kPCRegNum) { - // Updates the flags (condition codes) - if (s) { - inst.category = Instruction::kCategoryError; - return false; - } else { - auto src1 = EvalOperand(inst, inst.operands[1]); - auto src2 = EvalOperand(inst, inst.operands[2]); - auto src2_rrx = EvalOperand(inst, inst.operands[3]); - - if (!src1 || !src2 || !src2_rrx) { - inst.category = Instruction::kCategoryIndirectJump; - } else { - auto res = evaluator(*src1, *src2, *src2_rrx); - if (!res) { - inst.category = Instruction::kCategoryIndirectJump; - } else if (!inst.conditions.empty()) { - inst.branch_taken_pc = static_cast(*res); - inst.branch_not_taken_pc = inst.next_pc; - inst.category = Instruction::kCategoryConditionalBranch; - } else { - inst.branch_taken_pc = static_cast(*res); - inst.category = Instruction::kCategoryDirectJump; - } - } - } - } else { - inst.category = Instruction::kCategoryNormal; - } - return true; -} - // High 3 bit opc and low bit s, opc:s static const char * const kIdpNamesRRR[] = { [0b0000] = "ANDrr", From de1950d75832a84bd95d8e13113452066b7023db Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 14 Oct 2020 10:51:51 -0400 Subject: [PATCH 065/130] Cleaned up some things, updated the decoding semantics and semantics for the logical instructions --- remill/Arch/AArch32/Decode.cpp | 60 ++++++++++------------- remill/Arch/AArch32/Semantics/LOGICAL.cpp | 42 ++-------------- 2 files changed, 31 insertions(+), 71 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index dff4b11f2..7d9722ce5 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -159,8 +159,7 @@ static const char * const kIntRegName[] = { "R15" }; -typedef bool (*const TryDecode)(Instruction&, uint32_t); -typedef bool (*const TryDecodeList[])(Instruction&, uint32_t); +typedef bool (TryDecode)(Instruction&, uint32_t); typedef std::optional (InstEval)(uint32_t, uint32_t, uint32_t); static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, @@ -209,7 +208,6 @@ static void AddShiftOp(Instruction &inst, unsigned size = 32) { inst.operands.emplace_back(); auto &op = inst.operands.back(); - op.shift_reg.shift_size = shift_size; op.type = Operand::kTypeShiftRegister; op.size = size; op.action = action; @@ -226,18 +224,10 @@ static void AddShiftThenExtractOp(Instruction &inst, unsigned shift_size, unsigned extract_size, Operand::Action action = Operand::kActionRead, unsigned size = 32) { - inst.operands.emplace_back(); + AddShiftOp(inst, shift_op, reg_name, reg_size, shift_size, action, size); auto &op = inst.operands.back(); op.shift_reg.extract_size = extract_size; op.shift_reg.extend_op = extend_op; - op.shift_reg.shift_size = shift_size; - op.type = Operand::kTypeShiftRegister; - op.size = size; - op.action = action; - op.shift_reg.reg.name = reg_name; - op.shift_reg.reg.size = reg_size; - op.shift_reg.shift_op = shift_op; - op.shift_reg.shift_size = shift_size; op.shift_reg.shift_first = true; } @@ -249,18 +239,10 @@ static void AddExtractThenShiftOp(Instruction &inst, unsigned shift_size, unsigned extract_size, Operand::Action action = Operand::kActionRead, unsigned size = 32) { - inst.operands.emplace_back(); + AddShiftOp(inst, shift_op, reg_name, reg_size, shift_size, action, size); auto &op = inst.operands.back(); op.shift_reg.extract_size = extract_size; op.shift_reg.extend_op = extend_op; - op.shift_reg.shift_size = shift_size; - op.type = Operand::kTypeShiftRegister; - op.size = size; - op.action = action; - op.shift_reg.reg.name = reg_name; - op.shift_reg.reg.size = reg_size; - op.shift_reg.shift_op = shift_op; - op.shift_reg.shift_size = shift_size; op.shift_reg.shift_first = false; } @@ -580,8 +562,6 @@ std::optional EvalExtract(const Operand::ShiftRegister &op, case Operand::ShiftRegister::kExtendUnsigned: return val & ((1u << (op.extract_size)) - 1u); } - - } std::optional EvalOperand(const Instruction &inst, const Operand &op) { @@ -624,9 +604,10 @@ std::optional EvalOperand(const Instruction &inst, const Operand &op) // ALUExceptionReturn(result); // else // ALUWritePC(result); -template +// TODO(Sonya): maybe template this and decide on a robust method for handling +// the variable number of arguments to evaluator static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, - Evaluator *evaluator) { + InstEval *evaluator) { if (rd == kPCRegNum) { // Updates the flags (condition codes) if (s) { @@ -734,7 +715,7 @@ static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); } //000 AND, ANDS (immediate) @@ -770,7 +751,7 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s); - return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); } @@ -981,17 +962,30 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + // enc.opc == x0 + if (!(enc.opc & 0b1u)) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + } + // enc.opc == 01 + else if (!(enc.opc & 0b10u)) { + AddImmOp(inst, 0); + } + // enc.opc == 11 + else { + AddImmOp(inst, 1); + } + AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); if (enc.s) { AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc]); } // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> -static TryDecodeList kDataProcessingRI = { +static TryDecode * kDataProcessingRI[] = { [0b000] = TryDecodeIntegerDataProcessingRRR, [0b001] = TryDecodeIntegerDataProcessingRRR, [0b010] = TryDecodeIntegerDataProcessingRRR, @@ -1004,7 +998,7 @@ static TryDecodeList kDataProcessingRI = { // Corresponds to Data-processing immediate // op0<24 to 23> | op1 <21 to 20> -static TryDecodeList kDataProcessingI = { +static TryDecode * kDataProcessingI[] = { [0b0000] = TryDecodeIntegerDataProcessingRRI, [0b0001] = TryDecodeIntegerDataProcessingRRI, [0b0010] = TryDecodeIntegerDataProcessingRRI, @@ -1025,7 +1019,7 @@ static TryDecodeList kDataProcessingI = { // Corresponds to: Load/Store Word, Unsigned Byte (immediate, literal) // o2<22> | o1<21> -static TryDecodeList kLoadStoreWordUBIL = { +static TryDecode * kLoadStoreWordUBIL[] = { [0b00] = TryDecodeLoadStoreWordUBIL, [0b01] = TryDecodeLoadStoreWordUBIL, [0b10] = TryDecodeLoadStoreWordUBIL, @@ -1042,7 +1036,7 @@ static TryDecodeList kLoadStoreWordUBIL = { // 0 != 10xx0 0 Data-processing register (immediate shift) // 0 != 10xx0 0 1 Data-processing register (register shift) // 1 Data-processing immediate -static TryDecode TryDataProcessingAndMisc(uint32_t bits) { +static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { const DataProcessingAndMisc enc = { bits }; // op0 == 0 if (!enc.op0) { @@ -1108,7 +1102,7 @@ static TryDecode TryDataProcessingAndMisc(uint32_t bits) { // 10x Branch, branch with link, and block data transfer // 11x System register access, Advanced SIMD, floating-point, and Supervisor call // 1111 0xx Unconditional instructions -static TryDecode TryDecodeTopLevelEncodings(uint32_t bits) { +static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { const TopLevelEncodings enc = { bits }; // op0 == 0xx if (!(enc.op0 >> 2)) { diff --git a/remill/Arch/AArch32/Semantics/LOGICAL.cpp b/remill/Arch/AArch32/Semantics/LOGICAL.cpp index 1f66224b8..721964001 100644 --- a/remill/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/remill/Arch/AArch32/Semantics/LOGICAL.cpp @@ -35,23 +35,6 @@ DEF_SEM(ORRS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { return memory; } -DEF_SEM(MOV, R32W dst, R32 _, I32 src, I32 src_rrx){ - auto value = UOr(Read(src), Read(src_rrx)); - Write(dst, value); - return memory; -} - -DEF_SEM(MOVS, R32W dst, R32 _, I32 src, I32 src_rrx, I8 carry_out) { - auto value = UOr(Read(src), Read(src_rrx)); - Write(dst, value); - - state.sr.n = SignFlag(value); - state.sr.z = ZeroFlag(value); - state.sr.c = Read(carry_out); - // PSTATE.V unchanged - return memory; -} - DEF_SEM(BIC, R32W dst, R32 src1, I32 src2, I32 src2_rrx){ auto value = UNot(UOr(Read(src2), Read(src2_rrx))); auto result = UAnd(Read(src1), value); @@ -71,31 +54,14 @@ DEF_SEM(BICS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { return memory; } -DEF_SEM(MVN, R32W dst, R32 _, I32 src, I32 src_rrx){ - auto value = UNot(UOr(Read(src), Read(src_rrx))); - Write(dst, value); - return memory; -} - -DEF_SEM(MVNS, R32W dst, R32 _, I32 src, I32 src_rrx, I8 carry_out) { - auto value = UNot(UOr(Read(src), Read(src_rrx))); - Write(dst, value); - - state.sr.n = SignFlag(value); - state.sr.z = ZeroFlag(value); - state.sr.c = Read(carry_out); - // PSTATE.V unchanged - return memory; -} - } // namespace DEF_ISEL(ORRrrri) = ORR; DEF_ISEL(ORRSrrri) = ORRS; -DEF_ISEL(MOVrrri) = MOV; -DEF_ISEL(MOVSrrri) = MOVS; +DEF_ISEL(MOVrrri) = ORR; +DEF_ISEL(MOVSrrri) = ORRS; DEF_ISEL(BICrrri) = BIC; DEF_ISEL(BICSrrri) = BICS; -DEF_ISEL(MVNrrri) = MVN; -DEF_ISEL(MVNSrrri) = MVNS; +DEF_ISEL(MVNrrri) = BIC; +DEF_ISEL(MVNSrrri) = BICS; From 2cdf979683f8739727a8c7102d6c09d7cebbce5c Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 14 Oct 2020 12:59:57 -0400 Subject: [PATCH 066/130] Shortened kLogArithEvaluators and fixed a bug --- remill/Arch/AArch32/Decode.cpp | 16 ++++++---------- remill/Arch/AArch32/Semantics/LOGICAL.cpp | 16 ++++++++-------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 7d9722ce5..63961da7f 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -755,7 +755,6 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) } - static const char * const kMulAccRRR[] = { [0b0000] = "MULrr", [0b0001] = "MULSrr", @@ -919,19 +918,16 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { return true; } +// Can package semantics for MOV with ORR and MVN with BIC since src1 will be +// 0 and 1 for MOV and MVN respectively, mirroring the semantics in LOGICAL.cpp static InstEval * kLogArithEvaluators[] = { - [0b00] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + [0b0] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { return std::optional(src1 | (src2 | src2_rrx)); }, - [0b01] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { - return std::optional(src2 | src2_rrx); - }, - [0b10] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { + + [0b1] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { return std::optional(src1 & ~(src2 | src2_rrx)); }, - [0b11] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { - return std::optional(~(src2 | src2_rrx)); - }, }; //00 ORR, ORRS (register) -- rd, rn, & rm @@ -980,7 +976,7 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); } // Corresponds to Data-processing register (immediate shift) diff --git a/remill/Arch/AArch32/Semantics/LOGICAL.cpp b/remill/Arch/AArch32/Semantics/LOGICAL.cpp index 721964001..140357998 100644 --- a/remill/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/remill/Arch/AArch32/Semantics/LOGICAL.cpp @@ -19,17 +19,17 @@ namespace { DEF_SEM(ORR, R32W dst, R32 src1, I32 src2, I32 src2_rrx){ auto value = UOr(Read(src2), Read(src2_rrx)); auto result = UOr(Read(src1), value); - Write(dst, value); + Write(dst, result); return memory; } DEF_SEM(ORRS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { auto value = UOr(Read(src2), Read(src2_rrx)); auto result = UOr(Read(src1), value); - Write(dst, value); + Write(dst, result); - state.sr.n = SignFlag(value); - state.sr.z = ZeroFlag(value); + state.sr.n = SignFlag(result); + state.sr.z = ZeroFlag(result); state.sr.c = Read(carry_out); // PSTATE.V unchanged return memory; @@ -38,17 +38,17 @@ DEF_SEM(ORRS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { DEF_SEM(BIC, R32W dst, R32 src1, I32 src2, I32 src2_rrx){ auto value = UNot(UOr(Read(src2), Read(src2_rrx))); auto result = UAnd(Read(src1), value); - Write(dst, value); + Write(dst, result); return memory; } DEF_SEM(BICS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { auto value = UNot(UOr(Read(src2), Read(src2_rrx))); auto result = UAnd(Read(src1), value); - Write(dst, value); + Write(dst, result); - state.sr.n = SignFlag(value); - state.sr.z = ZeroFlag(value); + state.sr.n = SignFlag(result); + state.sr.z = ZeroFlag(result); state.sr.c = Read(carry_out); // PSTATE.V unchanged return memory; From 896f77c9a175b8401555a85aa0c5c42d3817aee8 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 14 Oct 2020 18:20:24 -0400 Subject: [PATCH 067/130] Updates from testing instructions --- remill/Arch/AArch32/Decode.cpp | 24 +++++++++++++---------- remill/Arch/AArch32/Semantics/BINARY.cpp | 4 ---- remill/Arch/AArch32/Semantics/LOGICAL.cpp | 1 - 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 63961da7f..492ee5977 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -530,6 +530,8 @@ std::optional EvalShift(const Operand::ShiftRegister &op, return val >> op.shift_size; case Operand::ShiftRegister::kShiftSignedRight: return static_cast(static_cast(val) >> op.shift_size); + default: + return std::nullopt; } } @@ -561,6 +563,8 @@ std::optional EvalExtract(const Operand::ShiftRegister &op, } case Operand::ShiftRegister::kExtendUnsigned: return val & ((1u << (op.extract_size)) - 1u); + default: + return std::nullopt; } } @@ -594,8 +598,9 @@ std::optional EvalOperand(const Instruction &inst, const Operand &op) } else { return EvalShift(op.shift_reg, EvalExtract(op.shift_reg, EvalReg(inst, op.shift_reg.reg))); } + default: + return std::nullopt; } - } // Handles appropriate branching semantics for: @@ -604,8 +609,6 @@ std::optional EvalOperand(const Instruction &inst, const Operand &op) // ALUExceptionReturn(result); // else // ALUWritePC(result); -// TODO(Sonya): maybe template this and decide on a robust method for handling -// the variable number of arguments to evaluator static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, InstEval *evaluator) { if (rd == kPCRegNum) { @@ -619,6 +622,7 @@ static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, auto src2_rrx = EvalOperand(inst, inst.operands[3]); if (!src1 || !src2 || !src2_rrx) { + LOG(ERROR) << "\n\n\n\n\n\n\n indirect jump \n\n\n\n\n\n\n" << !src1 << !src2 << !src2_rrx; inst.category = Instruction::kCategoryIndirectJump; } else { auto res = evaluator(*src1, *src2, *src2_rrx); @@ -715,7 +719,7 @@ static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); } - return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc]); } //000 AND, ANDS (immediate) @@ -751,8 +755,7 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s); - return EvalPCDest(inst, enc.s, enc.opc, kIdpEvaluators[enc.opc]); - + return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc]); } static const char * const kMulAccRRR[] = { @@ -786,8 +789,10 @@ static const char * const kMulAccRRR[] = { //111 SMLAL, SMLALS - writes to RdHi + RdLo, read RdHi static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { const MultiplyAndAccumulate enc = { bits }; - // if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; - if (enc.rdhi == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum) { + // MUL, MULS only: if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; + // All other instructions: if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; + if (enc.rdhi == kPCRegNum || (enc.rdlo == kPCRegNum && !enc.opc) + || enc.rn == kPCRegNum || enc.rm == kPCRegNum) { inst.category = Instruction::kCategoryError; return false; } @@ -804,7 +809,7 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { // 2nd write reg only needed for instructions with an opc that begins with 1 and UMALL if (((enc.opc >> 2) & 0b1u) || enc.opc == 0b010u) { // if dHi == dLo then UNPREDICTABLE; - if (enc.rdlo == enc.rdhi || enc.rdlo == kPCRegNum){ + if (enc.rdlo == enc.rdhi){ inst.category = Instruction::kCategoryError; return false; } @@ -924,7 +929,6 @@ static InstEval * kLogArithEvaluators[] = { [0b0] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { return std::optional(src1 | (src2 | src2_rrx)); }, - [0b1] = +[](uint32_t src1, uint32_t src2, uint32_t src2_rrx) { return std::optional(src1 & ~(src2 | src2_rrx)); }, diff --git a/remill/Arch/AArch32/Semantics/BINARY.cpp b/remill/Arch/AArch32/Semantics/BINARY.cpp index c78dd6277..7b8b528fe 100644 --- a/remill/Arch/AArch32/Semantics/BINARY.cpp +++ b/remill/Arch/AArch32/Semantics/BINARY.cpp @@ -28,8 +28,6 @@ T AddWithCarryNZCV(State &state, T lhs, T rhs, T carry) { return result; } - - DEF_SEM(AND, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { auto value = UOr(Read(src2), Read(src2_rrx)); Write(dst, UAnd(Read(src1), value)); @@ -47,7 +45,6 @@ DEF_SEM(ANDS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { return memory; } - DEF_SEM(EOR, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { auto value = UOr(Read(src2), Read(src2_rrx)); Write(dst, UXor(Read(src1), value)); @@ -93,7 +90,6 @@ DEF_SEM(SUBS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { return memory; } - DEF_SEM(ADD, R32W dst, R32 src1, I32 src2, I32 src2_rrx) { auto value = UOr(Read(src2), Read(src2_rrx)); Write(dst, UAdd(Read(src1), value)); diff --git a/remill/Arch/AArch32/Semantics/LOGICAL.cpp b/remill/Arch/AArch32/Semantics/LOGICAL.cpp index 140357998..071c038fc 100644 --- a/remill/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/remill/Arch/AArch32/Semantics/LOGICAL.cpp @@ -64,4 +64,3 @@ DEF_ISEL(BICrrri) = BIC; DEF_ISEL(BICSrrri) = BICS; DEF_ISEL(MVNrrri) = BIC; DEF_ISEL(MVNSrrri) = BICS; - From aee262e12b0781d6f994966905688ec8c5cda0ce Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 15 Oct 2020 12:17:53 -0400 Subject: [PATCH 068/130] Fixed DEF_ISEL for pre/post index instructions in MEM.cpp --- remill/Arch/AArch32/Semantics/MEM.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/remill/Arch/AArch32/Semantics/MEM.cpp b/remill/Arch/AArch32/Semantics/MEM.cpp index ef539cc14..3c953c5f9 100644 --- a/remill/Arch/AArch32/Semantics/MEM.cpp +++ b/remill/Arch/AArch32/Semantics/MEM.cpp @@ -75,12 +75,12 @@ DEF_SEM(LDRT, SrcType src1, R32W dst, R32W dst_reg, R32 src2) { DEF_ISEL(STR) = STR; DEF_ISEL(STRB) = STR; -DEF_ISEL(STRp) = STR; -DEF_ISEL(STRBp) = STR; +DEF_ISEL(STRp) = STRp; +DEF_ISEL(STRBp) = STRp; DEF_ISEL(LDR) = LDR; DEF_ISEL(LDRB) = LDR; -DEF_ISEL(LDRp) = LDR; -DEF_ISEL(LDRBp) = LDR; +DEF_ISEL(LDRp) = LDRp; +DEF_ISEL(LDRBp) = LDRp; DEF_ISEL(STRT) = STRT; DEF_ISEL(STRBT) = STRT; DEF_ISEL(LDRT) = LDRT; From fe855235aaf80be48fe3c66709ab8f2e6435353a Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 15 Oct 2020 16:28:14 -0400 Subject: [PATCH 069/130] Integer Test and Compare (two register, immediate shift) --- remill/Arch/AArch32/Decode.cpp | 91 +++++++++++++++----- remill/Arch/AArch32/Runtime/Instructions.cpp | 3 +- remill/Arch/AArch32/Semantics/COND.cpp | 58 +++++++++++++ 3 files changed, 129 insertions(+), 23 deletions(-) create mode 100644 remill/Arch/AArch32/Semantics/COND.cpp diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 492ee5977..4e5699de8 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -90,6 +90,24 @@ union LoadStoreWUBIL { } __attribute__((packed)); static_assert(sizeof(LoadStoreWUBIL) == 4, " "); +// Integer Test and Compare (two register, immediate shift) +union IntTestCompRRI { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _0 : 1; + uint32_t type : 2; + uint32_t imm5 : 5; + uint32_t _0000 : 4; + uint32_t rn : 4; + uint32_t _1 : 1; + uint32_t opc : 2; + uint32_t _00010 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntTestCompRRI) == 4, " "); + // Logical Arithmetic (three register, immediate shift) union LogicalArithRRRI { uint32_t flat; @@ -106,7 +124,7 @@ union LogicalArithRRRI { uint32_t cond : 4; } __attribute__((packed)); } __attribute__((packed)); -static_assert(sizeof(LoadStoreWUBIL) == 4, " "); +static_assert(sizeof(LogicalArithRRRI) == 4, " "); // Top-level encodings for A32 union TopLevelEncodings { @@ -622,7 +640,6 @@ static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, auto src2_rrx = EvalOperand(inst, inst.operands[3]); if (!src1 || !src2 || !src2_rrx) { - LOG(ERROR) << "\n\n\n\n\n\n\n indirect jump \n\n\n\n\n\n\n" << !src1 << !src2 << !src2_rrx; inst.category = Instruction::kCategoryIndirectJump; } else { auto res = evaluator(*src1, *src2, *src2_rrx); @@ -722,22 +739,22 @@ static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc]); } -//000 AND, ANDS (immediate) -//001 EOR, EORS (immediate) +//000 AND, ANDS (immediate) +//001 EOR, EORS (immediate) //010 0 != 11x1 SUB, SUBS (immediate) — SUB -//010 0 1101 SUB, SUBS (SP minus immediate) — SUB -//010 0 1111 ADR — A2 +//010 0 1101 SUB, SUBS (SP minus immediate) — SUB +//010 0 1111 ADR — A2 (alias of subtract) //010 1 != 1101 SUB, SUBS (immediate) — SUBS -//010 1 1101 SUB, SUBS (SP minus immediate) — SUBS -//011 RSB, RSBS (immediate) +//010 1 1101 SUB, SUBS (SP minus immediate) — SUBS +//011 RSB, RSBS (immediate) //100 0 != 11x1 ADD, ADDS (immediate) — ADD -//100 0 1101 ADD, ADDS (SP plus immediate) — ADD -//100 0 1111 ADR — A1 +//100 0 1101 ADD, ADDS (SP plus immediate) — ADD +//100 0 1111 ADR — A1 (alias of add) //100 1 != 1101 ADD, ADDS (immediate) — ADDS -//100 1 1101 ADD, ADDS (SP plus immediate) — ADDS -//101 ADC, ADCS (immediate) -//110 SBC, SBCS (immediate) -//111 RSC, RSCS (immediate) +//100 1 1101 ADD, ADDS (SP plus immediate) — ADDS +//101 ADC, ADCS (immediate) +//110 SBC, SBCS (immediate) +//111 RSC, RSCS (immediate) static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) { const IntDataProcessingRRI enc = { bits }; @@ -880,18 +897,19 @@ template(inst.pc & ~(3u)) - static_cast(inst.pc); } auto disp = static_cast(enc.imm12); + // Subtract if (!enc.u) { disp = -disp; @@ -983,6 +1002,36 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); } +//00 TST (register) +//01 TEQ (register) +//10 CMP (register) +//11 CMN (register) +static const char * const kIntegerTestAndCompareRRI[] = { + [0b00] = "TSTrri", + [0b01] = "TEQrri", + [0b10] = "CMPrri", + [0b11] = "CMNrri", +}; + +// Integer Test and Compare (two register, immediate shift) +static bool TryIntegerTestAndCompareRRI(Instruction &inst, uint32_t bits) { + const IntTestCompRRI enc = { bits }; + + auto instruction = kIntegerTestAndCompareRRI[enc.opc]; + if (!instruction) { + return false; + } + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); + AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); + + inst.category = Instruction::kCategoryNormal; + return true; +} + // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> static TryDecode * kDataProcessingRI[] = { @@ -991,7 +1040,7 @@ static TryDecode * kDataProcessingRI[] = { [0b010] = TryDecodeIntegerDataProcessingRRR, [0b011] = TryDecodeIntegerDataProcessingRRR, [0b100] = nullptr, // op0:op1 != 100 - [0b101] = nullptr, // TODO(Sonya): Integer Test and Compare (two register, immediate shift) + [0b101] = TryIntegerTestAndCompareRRI, [0b110] = TryLogicalArithmeticRRRI, [0b111] = TryLogicalArithmeticRRRI, }; diff --git a/remill/Arch/AArch32/Runtime/Instructions.cpp b/remill/Arch/AArch32/Runtime/Instructions.cpp index 57a660776..00cb7c877 100644 --- a/remill/Arch/AArch32/Runtime/Instructions.cpp +++ b/remill/Arch/AArch32/Runtime/Instructions.cpp @@ -57,14 +57,13 @@ DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; // clang-format off #include "remill/Arch/AArch32/Semantics/FLAGS.cpp" -// #include "remill/Arch/AArch32/Semantics/BINARY.cpp" #include "remill/Arch/AArch32/Semantics/MEM.cpp" #include "remill/Arch/AArch32/Semantics/LOGICAL.cpp" //#include "remill/Arch/AArch64/Semantics/BITBYTE.cpp" //#include "remill/Arch/AArch64/Semantics/BRANCH.cpp" //#include "remill/Arch/AArch64/Semantics/CALL_RET.cpp" -//#include "remill/Arch/AArch64/Semantics/COND.cpp" +#include "remill/Arch/AArch32/Semantics/COND.cpp" //#include "remill/Arch/AArch64/Semantics/CONVERT.cpp" //#include "remill/Arch/AArch64/Semantics/DATAXFER.cpp" //#include "remill/Arch/AArch64/Semantics/MISC.cpp" diff --git a/remill/Arch/AArch32/Semantics/COND.cpp b/remill/Arch/AArch32/Semantics/COND.cpp new file mode 100644 index 000000000..8a7db8d3f --- /dev/null +++ b/remill/Arch/AArch32/Semantics/COND.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { + +DEF_SEM(TST, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto res = UAnd(Read(src1), UOr(Read(src2), Read(src2_rrx))); + + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(TEQ, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto res = UXor(Read(src1), UOr(Read(src2), Read(src2_rrx))); + + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(CMP, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); + auto lhs = Read(src1); + AddWithCarryNZCV(state, lhs, UNot(rhs), uint32_t(1)); + return memory; +} + +DEF_SEM(CMN, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { + auto rhs = UOr(Read(src2), Read(src2_rrx)); + auto lhs = Read(src1); + AddWithCarryNZCV(state, lhs, rhs, uint32_t(0)); + return memory; +} + +} // namespace + +DEF_ISEL(TST) = TST; +DEF_ISEL(TEQ) = TEQ; +DEF_ISEL(CMP) = CMP; +DEF_ISEL(CMN) = CMN; From d831bdc38dbbc9ad99fba21ba5feb04d49a1f316 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 15 Oct 2020 17:43:01 -0400 Subject: [PATCH 070/130] Logical Arithmetic (two register and immediate) --- remill/Arch/AArch32/Decode.cpp | 71 ++++++++++++++++++----- remill/Arch/AArch32/Semantics/LOGICAL.cpp | 16 ++--- 2 files changed, 66 insertions(+), 21 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 4e5699de8..c5faf5b26 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -126,6 +126,20 @@ union LogicalArithRRRI { } __attribute__((packed)); static_assert(sizeof(LogicalArithRRRI) == 4, " "); +union LogicalArithmeticRRI { + uint32_t flat; + struct { + uint32_t imm12 : 12; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 2; + uint32_t _00111 : 5; + uint32_t cond : 4; + } __attribute__((packed)); + } __attribute__((packed)); +static_assert(sizeof(LogicalArithmeticRRI) == 4, " "); + // Top-level encodings for A32 union TopLevelEncodings { uint32_t flat; @@ -289,7 +303,7 @@ static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { // and if carry_out an additional carry_out op // Used to handle semantics for: -// (shift_t, shift_n) = DecodeImmShift(type, imm5); +// (imm32, carry) = A32ExpandImm_C(imm12, PSTATE.C); // See an instruction in Data-processing register (immediate shift) for example static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, bool carry_out) { uint32_t unrotated_value = imm12 & (0b11111111u); @@ -958,14 +972,14 @@ static InstEval * kLogArithEvaluators[] = { //10 BIC, BICS (register) -- rd, rn, & rm //11 MVN, MVNS (register) -- rd, & rm only static const char * const kLogicalArithmeticRRRI[] = { - [0b000] = "ORRrrri", - [0b001] = "ORRSrrri", - [0b010] = "MOVrrri", - [0b011] = "MOVSrrri", - [0b100] = "BICrrri", - [0b101] = "BICSrrri", - [0b110] = "MVNrrri", - [0b111] = "MVNSrrri", + [0b000] = "ORRrr", + [0b001] = "ORRSrr", + [0b010] = "MOVrr", + [0b011] = "MOVSrr", + [0b100] = "BICrr", + [0b101] = "BICSrr", + [0b110] = "MVNrr", + [0b111] = "MVNSrr", }; // Logical Arithmetic (three register, immediate shift) @@ -1002,6 +1016,37 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); } +// Logical Arithmetic (two register and immediate) +static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { + const LogicalArithmeticRRI enc = { bits }; + + auto instruction = kLogicalArithmeticRRRI[enc.opc]; + if (!instruction) { + return false; + } + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + + // enc.opc == x0 + if (!(enc.opc & 0b1u)) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + } + // enc.opc == 01 + else if (!(enc.opc & 0b10u)) { + AddImmOp(inst, 0); + } + // enc.opc == 11 + else { + AddImmOp(inst, 1); + } + + ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s); + + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); +} + //00 TST (register) //01 TEQ (register) //10 CMP (register) @@ -1060,10 +1105,10 @@ static TryDecode * kDataProcessingI[] = { [0b1001] = nullptr, // TODO(Sonya): Integer Test and Compare (one register and immediate) [0b1010] = nullptr, // TODO(Sonya): Move Special Register and Hints (immediate) [0b1011] = nullptr, // TODO(Sonya): Integer Test and Compare (one register and immediate) - [0b1100] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) - [0b1101] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) - [0b1110] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) - [0b1111] = nullptr, // TODO(Sonya): Logical Arithmetic (two register and immediate) + [0b1100] = TryLogicalArithmeticRRI, + [0b1101] = TryLogicalArithmeticRRI, + [0b1110] = TryLogicalArithmeticRRI, + [0b1111] = TryLogicalArithmeticRRI, }; // Corresponds to: Load/Store Word, Unsigned Byte (immediate, literal) diff --git a/remill/Arch/AArch32/Semantics/LOGICAL.cpp b/remill/Arch/AArch32/Semantics/LOGICAL.cpp index 071c038fc..bb12db036 100644 --- a/remill/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/remill/Arch/AArch32/Semantics/LOGICAL.cpp @@ -56,11 +56,11 @@ DEF_SEM(BICS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { } // namespace -DEF_ISEL(ORRrrri) = ORR; -DEF_ISEL(ORRSrrri) = ORRS; -DEF_ISEL(MOVrrri) = ORR; -DEF_ISEL(MOVSrrri) = ORRS; -DEF_ISEL(BICrrri) = BIC; -DEF_ISEL(BICSrrri) = BICS; -DEF_ISEL(MVNrrri) = BIC; -DEF_ISEL(MVNSrrri) = BICS; +DEF_ISEL(ORRrr) = ORR; +DEF_ISEL(ORRSrr) = ORRS; +DEF_ISEL(MOVrr) = ORR; +DEF_ISEL(MOVSrr) = ORRS; +DEF_ISEL(BICrr) = BIC; +DEF_ISEL(BICSrr) = BICS; +DEF_ISEL(MVNrr) = BIC; +DEF_ISEL(MVNSrr) = BICS; From ae7ae3da762bab543d54fe64d0c3ae6242c7f76b Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 15 Oct 2020 17:58:18 -0400 Subject: [PATCH 071/130] Integer Test and Compare (one register and immediate) --- remill/Arch/AArch32/Decode.cpp | 50 +++++++++++++++++++---- remill/Arch/AArch32/Semantics/COND.cpp | 2 - remill/Arch/AArch32/Semantics/LOGICAL.cpp | 2 - 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index c5faf5b26..5124bccd6 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -108,6 +108,21 @@ union IntTestCompRRI { } __attribute__((packed)); static_assert(sizeof(IntTestCompRRI) == 4, " "); +// Integer Test and Compare (one register and immediate) +union IntTestCompRI { + uint32_t flat; + struct { + uint32_t imm12 : 12; + uint32_t _0000 : 4; + uint32_t rn : 4; + uint32_t _1 : 1; + uint32_t opc : 2; + uint32_t _00110 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntTestCompRI) == 4, " "); + // Logical Arithmetic (three register, immediate shift) union LogicalArithRRRI { uint32_t flat; @@ -1051,18 +1066,18 @@ static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { //01 TEQ (register) //10 CMP (register) //11 CMN (register) -static const char * const kIntegerTestAndCompareRRI[] = { - [0b00] = "TSTrri", - [0b01] = "TEQrri", - [0b10] = "CMPrri", - [0b11] = "CMNrri", +static const char * const kIntegerTestAndCompareR[] = { + [0b00] = "TSTr", + [0b01] = "TEQr", + [0b10] = "CMPr", + [0b11] = "CMNr", }; // Integer Test and Compare (two register, immediate shift) static bool TryIntegerTestAndCompareRRI(Instruction &inst, uint32_t bits) { const IntTestCompRRI enc = { bits }; - auto instruction = kIntegerTestAndCompareRRI[enc.opc]; + auto instruction = kIntegerTestAndCompareR[enc.opc]; if (!instruction) { return false; } @@ -1077,6 +1092,25 @@ static bool TryIntegerTestAndCompareRRI(Instruction &inst, uint32_t bits) { return true; } +// Integer Test and Compare (one register and immediate) +static bool TryIntegerTestAndCompareRI(Instruction &inst, uint32_t bits) { + const IntTestCompRI enc = { bits }; + + auto instruction = kIntegerTestAndCompareR[enc.opc]; + if (!instruction) { + return false; + } + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + ExpandTo32AddImmAddCarry(inst, enc.imm12, 1u); + + inst.category = Instruction::kCategoryNormal; + return true; + +} + // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> static TryDecode * kDataProcessingRI[] = { @@ -1102,9 +1136,9 @@ static TryDecode * kDataProcessingI[] = { [0b0110] = TryDecodeIntegerDataProcessingRRI, [0b0111] = TryDecodeIntegerDataProcessingRRI, [0b1000] = nullptr, // TODO(Sonya): Move Halfword (immediate) - [0b1001] = nullptr, // TODO(Sonya): Integer Test and Compare (one register and immediate) + [0b1001] = TryIntegerTestAndCompareRI, [0b1010] = nullptr, // TODO(Sonya): Move Special Register and Hints (immediate) - [0b1011] = nullptr, // TODO(Sonya): Integer Test and Compare (one register and immediate) + [0b1011] = TryIntegerTestAndCompareRI, [0b1100] = TryLogicalArithmeticRRI, [0b1101] = TryLogicalArithmeticRRI, [0b1110] = TryLogicalArithmeticRRI, diff --git a/remill/Arch/AArch32/Semantics/COND.cpp b/remill/Arch/AArch32/Semantics/COND.cpp index 8a7db8d3f..e69342e01 100644 --- a/remill/Arch/AArch32/Semantics/COND.cpp +++ b/remill/Arch/AArch32/Semantics/COND.cpp @@ -15,7 +15,6 @@ */ namespace { - DEF_SEM(TST, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { auto res = UAnd(Read(src1), UOr(Read(src2), Read(src2_rrx))); @@ -49,7 +48,6 @@ DEF_SEM(CMN, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { AddWithCarryNZCV(state, lhs, rhs, uint32_t(0)); return memory; } - } // namespace DEF_ISEL(TST) = TST; diff --git a/remill/Arch/AArch32/Semantics/LOGICAL.cpp b/remill/Arch/AArch32/Semantics/LOGICAL.cpp index bb12db036..f7a493d2a 100644 --- a/remill/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/remill/Arch/AArch32/Semantics/LOGICAL.cpp @@ -15,7 +15,6 @@ */ namespace { - DEF_SEM(ORR, R32W dst, R32 src1, I32 src2, I32 src2_rrx){ auto value = UOr(Read(src2), Read(src2_rrx)); auto result = UOr(Read(src1), value); @@ -53,7 +52,6 @@ DEF_SEM(BICS, R32W dst, R32 src1, I32 src2, I32 src2_rrx, I8 carry_out) { // PSTATE.V unchanged return memory; } - } // namespace DEF_ISEL(ORRrr) = ORR; From 813b0fba4ea9c3a6c7cb920766efc6842c41d2fe Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 15 Oct 2020 18:39:44 -0400 Subject: [PATCH 072/130] Added to the top level encoding infrastructure to handle the Data-processing register (register shift) set of instructions and 3 corresponding subsets --- remill/Arch/AArch32/Decode.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 5124bccd6..9c1804040 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -1124,6 +1124,19 @@ static TryDecode * kDataProcessingRI[] = { [0b111] = TryLogicalArithmeticRRRI, }; +// Corresponds to Data-processing register (immediate shift) +// op0<24 to 23> | op1 <20> +static TryDecode * kDataProcessingRR[] = { + [0b000] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) + [0b001] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) + [0b010] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) + [0b011] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) + [0b100] = nullptr, // op0:op1 != 100 + [0b101] = nullptr, // TODO(Sonya): Integer Test and Compare (two register, register shift) + [0b110] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, register shift) + [0b111] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, register shift) +}; + // Corresponds to Data-processing immediate // op0<24 to 23> | op1 <21 to 20> static TryDecode * kDataProcessingI[] = { @@ -1207,7 +1220,7 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { } // TODO(Sonya): Data-processing register (register shift) -- op4 == 1 else { - return nullptr; + return kDataProcessingRR[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; } } } From 436fa94adb6606991ebdf29cbcfcc492d52da5e5 Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 16 Oct 2020 13:37:06 -0400 Subject: [PATCH 073/130] Add structs for the 3 subsets of Data-processing register (register shift) --- remill/Arch/AArch32/Decode.cpp | 75 ++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index 9c1804040..c2e391236 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -22,8 +22,27 @@ namespace remill { namespace { +//Integer Data Processing (three register, register shift) +union IntDataProcessingRRRR { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _1 : 1; + uint32_t type : 2; + uint32_t _0 : 1; + uint32_t rs : 4; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 3; + uint32_t _0000 : 4; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntDataProcessingRRRR) == 4, " "); + //Integer Data Processing (three register, immediate shift) -union IntDataProcessingRRR { +union IntDataProcessingRRRI { uint32_t flat; struct { uint32_t rm : 4; @@ -38,7 +57,7 @@ union IntDataProcessingRRR { uint32_t cond : 4; } __attribute__((packed)); } __attribute__((packed)); -static_assert(sizeof(IntDataProcessingRRR) == 4, " "); +static_assert(sizeof(IntDataProcessingRRRI) == 4, " "); //Integer Data Processing (2 register and immediate, immediate shift) union IntDataProcessingRRI { @@ -108,6 +127,25 @@ union IntTestCompRRI { } __attribute__((packed)); static_assert(sizeof(IntTestCompRRI) == 4, " "); +// Integer Test and Compare (two register, register shift) +union IntTestCompRRR { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _1 : 1; + uint32_t type : 2; + uint32_t _0 : 1; + uint32_t rs : 4; + uint32_t _0000 : 4; + uint32_t rn : 4; + uint32_t _1 : 1; + uint32_t opc : 2; + uint32_t _00010 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntTestCompRRR) == 4, " "); + // Integer Test and Compare (one register and immediate) union IntTestCompRI { uint32_t flat; @@ -141,6 +179,25 @@ union LogicalArithRRRI { } __attribute__((packed)); static_assert(sizeof(LogicalArithRRRI) == 4, " "); +// Logical Arithmetic (three register, register shift) +union LogicalArithRRRR { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _1 : 1; + uint32_t type : 2; + uint32_t _0 : 0; + uint32_t rs : 4; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 2; + uint32_t _00011 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(LogicalArithRRRR) == 4, " "); + union LogicalArithmeticRRI { uint32_t flat; struct { @@ -752,8 +809,8 @@ static const char * const kIdpNamesRRR[] = { //101 ADC, ADCS (register) //110 SBC, SBCS (register) //111 RSC, RSCS (register) -static bool TryDecodeIntegerDataProcessingRRR(Instruction &inst, uint32_t bits) { - const IntDataProcessingRRR enc = {bits}; +static bool TryDecodeIntegerDataProcessingRRRI(Instruction &inst, uint32_t bits) { + const IntDataProcessingRRRI enc = {bits}; inst.function = kIdpNamesRRR[ (enc.opc << 1u) | enc.s]; DecodeCondition(inst, enc.cond); @@ -1114,10 +1171,10 @@ static bool TryIntegerTestAndCompareRI(Instruction &inst, uint32_t bits) { // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> static TryDecode * kDataProcessingRI[] = { - [0b000] = TryDecodeIntegerDataProcessingRRR, - [0b001] = TryDecodeIntegerDataProcessingRRR, - [0b010] = TryDecodeIntegerDataProcessingRRR, - [0b011] = TryDecodeIntegerDataProcessingRRR, + [0b000] = TryDecodeIntegerDataProcessingRRRI, + [0b001] = TryDecodeIntegerDataProcessingRRRI, + [0b010] = TryDecodeIntegerDataProcessingRRRI, + [0b011] = TryDecodeIntegerDataProcessingRRRI, [0b100] = nullptr, // op0:op1 != 100 [0b101] = TryIntegerTestAndCompareRRI, [0b110] = TryLogicalArithmeticRRRI, @@ -1218,7 +1275,7 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { // index is the concatenation of op0 and op1 return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; } - // TODO(Sonya): Data-processing register (register shift) -- op4 == 1 + // Data-processing register (register shift) -- op4 == 1 else { return kDataProcessingRR[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; } From c3fa9d6c5377fd23942d75acc43e84878526b5f5 Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 16 Oct 2020 15:44:26 -0400 Subject: [PATCH 074/130] Code status before refactoring operand types --- remill/Arch/AArch32/Decode.cpp | 102 +++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 25 deletions(-) diff --git a/remill/Arch/AArch32/Decode.cpp b/remill/Arch/AArch32/Decode.cpp index c2e391236..fe744710b 100644 --- a/remill/Arch/AArch32/Decode.cpp +++ b/remill/Arch/AArch32/Decode.cpp @@ -825,6 +825,21 @@ static bool TryDecodeIntegerDataProcessingRRRI(Instruction &inst, uint32_t bits) return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc]); } +// TODO(Sonya): Integer Data Processing (three register, register shift) +static bool TryDecodeIntegerDataProcessingRRRR(Instruction &inst, uint32_t bits) { + return false; + const IntDataProcessingRRRR enc = { bits }; + + inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s]; + DecodeCondition(inst, enc.cond); + + if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum + || enc.rm == kPCRegNum) { + inst.category = Instruction::kCategoryError; + return false; + } +} + //000 AND, ANDS (immediate) //001 EOR, EORS (immediate) //010 0 != 11x1 SUB, SUBS (immediate) — SUB @@ -990,10 +1005,7 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { } auto instruction = kLoadSWUBIL[enc.P << 3u | enc.W << 2u | enc.o2 << 1u | enc.o1]; - if (!instruction) { - inst.category = Instruction::kCategoryError; - return false; - } + inst.function = instruction; DecodeCondition(inst, enc.cond); @@ -1059,9 +1071,7 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { const LogicalArithRRRI enc = { bits }; auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; - if (!instruction) { - return false; - } + inst.function = instruction; DecodeCondition(inst, enc.cond); @@ -1088,19 +1098,48 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); } +// TODO(Sonya): Logical Arithmetic (three register, register shift) +static bool TryLogicalArithmeticRRRR(Instruction &inst, uint32_t bits) { + return false; + + const LogicalArithRRRR enc = { bits }; + + auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; + + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum + || enc.rm == kPCRegNum) { + inst.category = Instruction::kCategoryError; + return false; + } + + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + // enc.opc == x0 + if (!(enc.opc & 0b1u)) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + } + // enc.opc == 01 + else if (!(enc.opc & 0b10u)) { + AddImmOp(inst, 0); + } + // enc.opc == 11 + else { + AddImmOp(inst, 1); + } +} + // Logical Arithmetic (two register and immediate) static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { const LogicalArithmeticRRI enc = { bits }; - auto instruction = kLogicalArithmeticRRRI[enc.opc]; - if (!instruction) { - return false; - } + auto instruction = kLogicalArithmeticRRRI[enc.opc | enc.s]; + inst.function = instruction; DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); - // enc.opc == x0 if (!(enc.opc & 0b1u)) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); @@ -1135,9 +1174,7 @@ static bool TryIntegerTestAndCompareRRI(Instruction &inst, uint32_t bits) { const IntTestCompRRI enc = { bits }; auto instruction = kIntegerTestAndCompareR[enc.opc]; - if (!instruction) { - return false; - } + inst.function = instruction; DecodeCondition(inst, enc.cond); @@ -1149,14 +1186,29 @@ static bool TryIntegerTestAndCompareRRI(Instruction &inst, uint32_t bits) { return true; } +// TODO(Sonya): Integer Test and Compare (two register, register shift) +static bool TryIntegerTestAndCompareRRR(Instruction &inst, uint32_t bits) { + return false; + + const IntTestCompRRR enc = { bits }; + + auto instruction = kIntegerTestAndCompareR[enc.opc]; + + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + if (enc.rn == kPCRegNum || enc.rs == kPCRegNum || enc.rm == kPCRegNum) { + inst.category = Instruction::kCategoryError; + return false; + } +} + // Integer Test and Compare (one register and immediate) static bool TryIntegerTestAndCompareRI(Instruction &inst, uint32_t bits) { const IntTestCompRI enc = { bits }; auto instruction = kIntegerTestAndCompareR[enc.opc]; - if (!instruction) { - return false; - } + inst.function = instruction; DecodeCondition(inst, enc.cond); @@ -1184,14 +1236,14 @@ static TryDecode * kDataProcessingRI[] = { // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> static TryDecode * kDataProcessingRR[] = { - [0b000] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) - [0b001] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) - [0b010] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) - [0b011] = nullptr, // TODO(Sonya): Integer Data Processing (three register, register shift) + [0b000] = TryDecodeIntegerDataProcessingRRRR, + [0b001] = TryDecodeIntegerDataProcessingRRRR, + [0b010] = TryDecodeIntegerDataProcessingRRRR, + [0b011] = TryDecodeIntegerDataProcessingRRRR, [0b100] = nullptr, // op0:op1 != 100 - [0b101] = nullptr, // TODO(Sonya): Integer Test and Compare (two register, register shift) - [0b110] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, register shift) - [0b111] = nullptr, // TODO(Sonya): Logical Arithmetic (three register, register shift) + [0b101] = TryIntegerTestAndCompareRRR, + [0b110] = TryLogicalArithmeticRRRR, + [0b111] = TryLogicalArithmeticRRRR, }; // Corresponds to Data-processing immediate From 2cf4366fed979571102d1508a7a96d02fedb7a28 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 4 Nov 2020 15:34:15 -0500 Subject: [PATCH 075/130] Finished updates off master --- cmake/remillConfig.cmake.in | 4 ++++ include/remill/Arch/Name.h | 1 + include/remill/Arch/Runtime/HyperCall.h | 2 ++ lib/Arch/Arch.cpp | 1 + lib/Arch/CMakeLists.txt | 2 ++ 5 files changed, 10 insertions(+) diff --git a/cmake/remillConfig.cmake.in b/cmake/remillConfig.cmake.in index f71380bee..78c26ea05 100644 --- a/cmake/remillConfig.cmake.in +++ b/cmake/remillConfig.cmake.in @@ -65,6 +65,9 @@ if(NOT TARGET remill) add_library(remill_arch_x86 STATIC IMPORTED) set_property(TARGET remill_arch_x86 PROPERTY IMPORTED_LOCATION "@REMILL_ARCH_X86_LIBRARY_LOCATION@") + add_library(remill_arch_aarch32 STATIC IMPORTED) + set_property(TARGET remill_arch_aarch32 PROPERTY IMPORTED_LOCATION "@REMILL_ARCH_AARCH32_LIBRARY_LOCATION@") + add_library(remill_arch_aarch64 STATIC IMPORTED) set_property(TARGET remill_arch_aarch64 PROPERTY IMPORTED_LOCATION "@REMILL_ARCH_AARCH64_LIBRARY_LOCATION@") @@ -84,6 +87,7 @@ if(NOT TARGET remill) remill_os remill_arch remill_arch_x86 + remill_arch_aarch32 remill_arch_aarch64 remill_arch_sparc32 remill_arch_sparc64 diff --git a/include/remill/Arch/Name.h b/include/remill/Arch/Name.h index 226c7f03c..0e919de4c 100644 --- a/include/remill/Arch/Name.h +++ b/include/remill/Arch/Name.h @@ -80,6 +80,7 @@ enum ArchName : uint32_t { kArchAMD64_AVX, kArchAMD64_AVX512, + kArchAArch32LittleEndian, kArchAArch64LittleEndian, kArchSparc32, diff --git a/include/remill/Arch/Runtime/HyperCall.h b/include/remill/Arch/Runtime/HyperCall.h index 6b827511c..3c926e893 100644 --- a/include/remill/Arch/Runtime/HyperCall.h +++ b/include/remill/Arch/Runtime/HyperCall.h @@ -62,6 +62,8 @@ class SyncHyperCall { kAArch64Breakpoint, kAArch32EmulateInstruction = 0x300U, + kAArch32CheckNotEL2, + kSPARC32EmulateInstruction = 0x400U, kSPARC64EmulateInstruction, kSPARCSetAsiRegister, diff --git a/lib/Arch/Arch.cpp b/lib/Arch/Arch.cpp index 0ba5a7031..c40a1b93c 100644 --- a/lib/Arch/Arch.cpp +++ b/lib/Arch/Arch.cpp @@ -365,6 +365,7 @@ bool Arch::IsAMD64(void) const { bool Arch::IsAArch32(void) const { return remill::kArchAArch32LittleEndian == arch_name; +} bool Arch::IsAArch64(void) const { return remill::kArchAArch64LittleEndian == arch_name; diff --git a/lib/Arch/CMakeLists.txt b/lib/Arch/CMakeLists.txt index 25363ad0b..b6fd565d6 100644 --- a/lib/Arch/CMakeLists.txt +++ b/lib/Arch/CMakeLists.txt @@ -22,6 +22,7 @@ add_library(remill_arch STATIC Name.cpp ) +add_subdirectory(AArch32) add_subdirectory(AArch64) add_subdirectory(SPARC32) add_subdirectory(SPARC64) @@ -31,6 +32,7 @@ set_property(TARGET remill_arch PROPERTY POSITION_INDEPENDENT_CODE ON) target_link_libraries(remill_arch LINK_PUBLIC remill_settings + remill_arch_aarch32 remill_arch_aarch64 remill_arch_sparc32 remill_arch_sparc64 From e477f959c195b86729ff1534f55573ffed548abd Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 4 Nov 2020 17:32:44 -0500 Subject: [PATCH 076/130] Start of operand refactor --- include/remill/Arch/Instruction.h | 34 ++++++++++++++- include/remill/BC/InstructionLifter.h | 17 +++++++- lib/Arch/Instruction.cpp | 33 +++++++++++++- lib/BC/InstructionLifter.cpp | 62 +++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 4 deletions(-) diff --git a/include/remill/Arch/Instruction.h b/include/remill/Arch/Instruction.h index 30cace255..f77d51ecd 100644 --- a/include/remill/Arch/Instruction.h +++ b/include/remill/Arch/Instruction.h @@ -18,13 +18,34 @@ #include #include +#include + +namespace llvm { +class Constant; +class Type; +} // namespace llvm namespace remill { class Arch; +class Register; +class OperandExpression; enum ArchName : unsigned; +struct LLVMOpExpr{ + unsigned llvm_opcode {0}; + OperandExpression *op1 {nullptr}; + OperandExpression *op2 {nullptr}; +}; + + +class OperandExpression : public std::variant { + public: + std::string Serialize(void) const; + llvm::Type * type {nullptr}; +}; + // Generic instruction operand. class Operand { public: @@ -36,7 +57,8 @@ class Operand { kTypeRegister, kTypeShiftRegister, kTypeImmediate, - kTypeAddress + kTypeAddress, + kTypeExpression, } type; enum Action { kActionInvalid, kActionRead, kActionWrite } action; @@ -125,6 +147,8 @@ class Operand { } } addr; + OperandExpression * expr; + std::string Serialize(void) const; }; @@ -278,6 +302,14 @@ class Instruction { inline bool IsNoOp(void) const { return kCategoryNoOp == category; } + + // This allocates an OperandExpression + OperandExpression * AllocateExpression(void); + + private: + static constexpr auto kMaxNumExpr = 10u; + OperandExpression exprs[kMaxNumExpr]; + unsigned next_expr_index{0}; }; } // namespace remill diff --git a/include/remill/BC/InstructionLifter.h b/include/remill/BC/InstructionLifter.h index 7303e8b17..6a7a260d6 100644 --- a/include/remill/BC/InstructionLifter.h +++ b/include/remill/BC/InstructionLifter.h @@ -96,16 +96,29 @@ class InstructionLifter { Operand ®); // Lift a register operand to a value. - virtual llvm::Value *LiftRegisterOperand(Instruction &inst, + virtual llvm::Value * LiftRegisterOperand(Instruction &inst, llvm::BasicBlock *block, llvm::Value *state_ptr, llvm::Argument *arg, Operand ®); // Lift an immediate operand. - virtual llvm::Value *LiftImmediateOperand(Instruction &inst, + virtual llvm::Value * LiftImmediateOperand(Instruction &inst, llvm::BasicBlock *block, llvm::Argument *arg, Operand &op); + // Lift an expression operand. + virtual llvm::Value * LiftExpressionOperand(Instruction &inst, + llvm::BasicBlock *block, + llvm::Value *state_ptr, + llvm::Argument *arg, Operand &op); + + // Lift an expression operand. + virtual llvm::Value* LiftExpressionOperand(Instruction &inst, + llvm::BasicBlock *block, + llvm::Value *state_ptr, + llvm::Argument *arg, + const OperandExpression *op); + // Lift an indirect memory operand to a value. virtual llvm::Value * LiftAddressOperand(Instruction &inst, llvm::BasicBlock *block, diff --git a/lib/Arch/Instruction.cpp b/lib/Arch/Instruction.cpp index 88136d369..cded6e9d8 100644 --- a/lib/Arch/Instruction.cpp +++ b/lib/Arch/Instruction.cpp @@ -23,9 +23,30 @@ #include "remill/Arch/Arch.h" #include "remill/Arch/Name.h" +#include "remill/BC/Util.h" +#include namespace remill { +std::string OperandExpression::Serialize(void) const { + std::stringstream ss; + if (auto llvm_op = std::get_if(this)) { + ss << "(" << llvm::Instruction::getOpcodeName(llvm_op->llvm_opcode) << " " + << llvm_op->op1->Serialize(); + if (llvm_op->op2) { + ss << " " << llvm_op->op2->Serialize(); + } + ss << ")"; + } else if (auto reg_op = std::get_if(this)) { + ss << (*reg_op)->name; + } else if (auto ci_op = std::get_if(this)) { + ss << remill::LLVMThingToString(*ci_op); + } else if (auto str_op = std::get_if(this)) { + ss << *str_op; + } + return ss.str(); +} + Operand::Register::Register(void) : size(0) {} Operand::ShiftRegister::ShiftRegister(void) @@ -46,7 +67,8 @@ Operand::Address::Address(void) Operand::Operand(void) : type(Operand::kTypeInvalid), action(Operand::kActionInvalid), - size(0) {} + size(0), + expr(nullptr) {} namespace { static int64_t SignedImmediate(uint64_t val, uint64_t size) { @@ -246,6 +268,9 @@ std::string Operand::Serialize(void) const { } ss << ")"; // End of `(ADDR_`. break; + case Operand::kTypeExpression: + ss << expr->Serialize(); + break; } ss << ")"; return ss.str(); @@ -308,6 +333,12 @@ void Instruction::Reset(void) { conditions.clear(); function.clear(); bytes.clear(); + next_expr_index = 0; +} + +OperandExpression * Instruction::AllocateExpression(void) { + CHECK_LT(next_expr_index, kMaxNumExpr); + return &(exprs[next_expr_index++]); } bool Instruction::FinalizeDecode(void) { diff --git a/lib/BC/InstructionLifter.cpp b/lib/BC/InstructionLifter.cpp index 0be0e1572..ef6b9c039 100644 --- a/lib/BC/InstructionLifter.cpp +++ b/lib/BC/InstructionLifter.cpp @@ -614,6 +614,65 @@ InstructionLifter::LiftImmediateOperand(Instruction &inst, llvm::BasicBlock *, } } +// Lift an expression operand. +llvm::Value *InstructionLifter::LiftExpressionOperand(Instruction &inst, + llvm::BasicBlock *block, + llvm::Value *state_ptr, + llvm::Argument *arg, Operand &op) { + +} + +// Lift an expression operand. +llvm::Value* InstructionLifter::LiftExpressionOperand( + Instruction &inst, llvm::BasicBlock *block, llvm::Value *state_ptr, + llvm::Argument *arg, const OperandExpression *op) { + if (auto llvm_op = std::get_if(op)) { + auto lhs = LiftExpressionOperand(inst, block, state_ptr, nullptr, llvm_op->op1); + llvm::Value * rhs = nullptr; + if (llvm_op->op2) { + rhs = LiftExpressionOperand(inst, block, state_ptr, nullptr, llvm_op->op2); + } + llvm::IRBuilder<> ir(block); + switch (llvm_op->llvm_opcode) { + case llvm::Instruction::Add: + return ir.CreateAdd(lhs, rhs); + case llvm::Instruction::Sub: + return ir.CreateSub(lhs, rhs); + case llvm::Instruction::Mul: + return ir.CreateMul(lhs, rhs); + case llvm::Instruction::Shl: + return ir.CreateShl(lhs, rhs); + case llvm::Instruction::LShr: + return ir.CreateLShr(lhs, rhs); + case llvm::Instruction::AShr: + return ir.CreateAShr(lhs, rhs); + case llvm::Instruction::ZExt: + return ir.CreateZExt(lhs, op->type); + case llvm::Instruction::SExt: + return ir.CreateSExt(lhs, op->type); + case llvm::Instruction::Trunc: + return ir.CreateTrunc(lhs, op->type); + + } + } else if (auto reg_op = std::get_if(op)) { + if (!arg || !llvm::isa(arg->getType())) { + return LoadRegValue(block, state_ptr, (*reg_op)->name); + } else { + return LoadRegAddress(block, state_ptr, (*reg_op)->name); + } + + } else if (auto ci_op = std::get_if(op)) { + return *ci_op; + + } else if (auto str_op = std::get_if(op)) { + if (!arg || !llvm::isa(arg->getType())) { + return LoadRegValue(block, state_ptr, *str_op); + } else { + return LoadRegAddress(block, state_ptr, *str_op); + } + } +} + // Zero-extend a value to be the machine word size. llvm::Value *InstructionLifter::LiftAddressOperand(Instruction &inst, llvm::BasicBlock *block, @@ -718,6 +777,9 @@ InstructionLifter::LiftOperand(Instruction &inst, llvm::BasicBlock *block, } return LiftAddressOperand(inst, block, state_ptr, arg, arch_op); + + case Operand::kTypeExpression: + return LiftExpressionOperand(inst, block, state_ptr, arg, arch_op); } LOG(FATAL) << "Got a unknown operand type of " From 7d5b84c376a1b1ccf896359a377e73692f7203bb Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 5 Nov 2020 18:02:09 -0500 Subject: [PATCH 077/130] Finished Expression Operand Support --- include/remill/Arch/Instruction.h | 22 +- include/remill/BC/InstructionLifter.h | 3 +- lib/Arch/Instruction.cpp | 284 +++++++++++++++++++++++++- lib/BC/InstructionLifter.cpp | 97 ++++++++- 4 files changed, 389 insertions(+), 17 deletions(-) diff --git a/include/remill/Arch/Instruction.h b/include/remill/Arch/Instruction.h index f77d51ecd..09f4a47ee 100644 --- a/include/remill/Arch/Instruction.h +++ b/include/remill/Arch/Instruction.h @@ -28,19 +28,19 @@ class Type; namespace remill { class Arch; -class Register; +struct Register; class OperandExpression; enum ArchName : unsigned; struct LLVMOpExpr{ - unsigned llvm_opcode {0}; - OperandExpression *op1 {nullptr}; - OperandExpression *op2 {nullptr}; + unsigned llvm_opcode; + OperandExpression *op1; + OperandExpression *op2; }; -class OperandExpression : public std::variant { +class OperandExpression : public std::variant { public: std::string Serialize(void) const; llvm::Type * type {nullptr}; @@ -305,9 +305,19 @@ class Instruction { // This allocates an OperandExpression OperandExpression * AllocateExpression(void); + OperandExpression * EmplaceRegister(const Register *); + OperandExpression * EmplaceConstant(llvm::Constant *); + OperandExpression * EmplaceVariable(std::string_view, llvm::Type *); + OperandExpression * EmplaceBinaryOp(unsigned opcode, OperandExpression * op1, OperandExpression * op2); + OperandExpression * EmplaceUnaryOp(unsigned opcode, OperandExpression * op1, llvm::Type *); + + Operand & EmplaceOperand(const Operand::Register &op); + Operand & EmplaceOperand(const Operand::Immediate &op); + Operand & EmplaceOperand(const Operand::ShiftRegister &op); + Operand & EmplaceOperand(const Operand::Address &op); private: - static constexpr auto kMaxNumExpr = 10u; + static constexpr auto kMaxNumExpr = 32u; OperandExpression exprs[kMaxNumExpr]; unsigned next_expr_index{0}; }; diff --git a/include/remill/BC/InstructionLifter.h b/include/remill/BC/InstructionLifter.h index 6a7a260d6..0ca18882f 100644 --- a/include/remill/BC/InstructionLifter.h +++ b/include/remill/BC/InstructionLifter.h @@ -38,6 +38,7 @@ class Arch; class Instruction; class IntrinsicTable; class Operand; +class OperandExpression; class TraceLifter; enum LiftStatus { @@ -113,7 +114,7 @@ class InstructionLifter { llvm::Argument *arg, Operand &op); // Lift an expression operand. - virtual llvm::Value* LiftExpressionOperand(Instruction &inst, + virtual llvm::Value* LiftExpressionOperandRec(Instruction &inst, llvm::BasicBlock *block, llvm::Value *state_ptr, llvm::Argument *arg, diff --git a/lib/Arch/Instruction.cpp b/lib/Arch/Instruction.cpp index cded6e9d8..bb4d905d6 100644 --- a/lib/Arch/Instruction.cpp +++ b/lib/Arch/Instruction.cpp @@ -25,6 +25,7 @@ #include "remill/Arch/Name.h" #include "remill/BC/Util.h" #include +#include namespace remill { @@ -35,13 +36,15 @@ std::string OperandExpression::Serialize(void) const { << llvm_op->op1->Serialize(); if (llvm_op->op2) { ss << " " << llvm_op->op2->Serialize(); + } else { + ss << " to " << remill::LLVMThingToString(type); } ss << ")"; } else if (auto reg_op = std::get_if(this)) { ss << (*reg_op)->name; } else if (auto ci_op = std::get_if(this)) { ss << remill::LLVMThingToString(*ci_op); - } else if (auto str_op = std::get_if(this)) { + } else if (auto str_op = std::get_if(this)) { ss << *str_op; } return ss.str(); @@ -187,7 +190,7 @@ std::string Operand::Serialize(void) const { } break; - case Operand::kTypeAddress: + case Operand::kTypeAddress: { ss << "("; // Nice version of the memory size. @@ -268,6 +271,7 @@ std::string Operand::Serialize(void) const { } ss << ")"; // End of `(ADDR_`. break; + } case Operand::kTypeExpression: ss << expr->Serialize(); break; @@ -341,6 +345,282 @@ OperandExpression * Instruction::AllocateExpression(void) { return &(exprs[next_expr_index++]); } +OperandExpression* Instruction::EmplaceRegister(const Register * reg) { + auto expr = AllocateExpression(); + expr->emplace(reg); + expr->type = reg->type; + return expr; +} + +OperandExpression* Instruction::EmplaceConstant(llvm::Constant * val) { + auto expr = AllocateExpression(); + expr->emplace(val); + expr->type = val->getType(); + return expr; +} + +OperandExpression* Instruction::EmplaceVariable(std::string_view var_name, llvm::Type * type) { + auto expr = AllocateExpression(); + expr->emplace(var_name.data(), var_name.size()); + expr->type = type; + return expr; +} + +OperandExpression* Instruction::EmplaceBinaryOp(unsigned opcode, + OperandExpression *op1, + OperandExpression *op2) { + auto expr = AllocateExpression(); + expr->emplace(LLVMOpExpr{opcode, op1, op2}); + expr->type = op1->type; + return expr; +} + +OperandExpression* Instruction::EmplaceUnaryOp(unsigned opcode, + OperandExpression *op1, + llvm::Type* type) { + auto expr = AllocateExpression(); + expr->emplace(LLVMOpExpr{opcode, op1, nullptr}); + expr->type = type; + return expr; +} + +Operand & Instruction::EmplaceOperand(const Operand::Register ®_op) { + operands.emplace_back(); + auto &op = operands.back(); + op.type = Operand::kTypeExpression; + op.size = reg_op.size; + if (auto reg = arch_for_decode->RegisterByName(reg_op.name)) { + op.expr = EmplaceRegister(reg); + } else { + auto &context = *arch_for_decode->context; + auto ty = llvm::Type::getIntNTy(context, reg_op.size); + op.expr = EmplaceVariable(reg_op.name, ty); + } + return op; +} + +Operand &Instruction::EmplaceOperand(const Operand::Immediate &imm_op) { + operands.emplace_back(); + auto &op = operands.back(); + auto &context = *arch_for_decode->context; + + auto ty = llvm::Type::getIntNTy(context, arch_for_decode->address_size); + op.expr = EmplaceConstant(llvm::ConstantInt::get(ty, imm_op.val, imm_op.is_signed)); + op.size = arch_for_decode->address_size; + op.type = Operand::kTypeExpression; + return op; +} + +Operand &Instruction::EmplaceOperand(const Operand::ShiftRegister &shift_op) { + operands.emplace_back(); + auto &op = operands.back(); + op.type = Operand::kTypeExpression; + op.size = arch_for_decode->address_size; + auto &arch_reg = shift_op.reg; + + auto &context = *arch_for_decode->context; + auto reg = arch_for_decode->RegisterByName(arch_reg.name); + auto reg_type = reg->type; + auto reg_size = reg->size * 8u; + auto op_type = llvm::Type::getIntNTy(context, op.size); + + const uint64_t zero = 0; + const uint64_t one = 1; + const uint64_t shift_size = shift_op.shift_size; + + const auto shift_val = llvm::ConstantInt::get(op_type, shift_size); + + auto expr = EmplaceRegister(reg); + + auto curr_size = reg_size; + + auto do_extract = [&](void) { + if (Operand::ShiftRegister::kExtendInvalid != shift_op.extend_op) { + + auto extract_type = + llvm::Type::getIntNTy(context, shift_op.extract_size); + + if (reg_size > shift_op.extract_size) { + curr_size = shift_op.extract_size; + expr = EmplaceUnaryOp(llvm::Instruction::Trunc, expr, extract_type); + + } else { + CHECK(reg_size == shift_op.extract_size) + << "Invalid extraction size. Can't extract " + << shift_op.extract_size << " bits from a " << reg_size + << "-bit value in operand " << op.Serialize() << " of instruction at " + << std::hex << pc; + } + + if (op.size > shift_op.extract_size) { + switch (shift_op.extend_op) { + case Operand::ShiftRegister::kExtendSigned: + expr = EmplaceUnaryOp(llvm::Instruction::SExt, expr, op_type); + curr_size = op.size; + break; + case Operand::ShiftRegister::kExtendUnsigned: + expr = EmplaceUnaryOp(llvm::Instruction::ZExt, expr, op_type); + curr_size = op.size; + break; + default: + LOG(FATAL) << "Invalid extend operation type for instruction at " + << std::hex << pc; + break; + } + } + } + CHECK(curr_size <= op.size); + + if (curr_size < op.size) { + expr = EmplaceUnaryOp(llvm::Instruction::ZExt, expr, op_type); + curr_size = op.size; + } + }; + + auto do_shift = [&](void) { + if (Operand::ShiftRegister::kShiftInvalid != shift_op.shift_op) { + + CHECK(shift_size < op.size) + << "Shift of size " << shift_size + << " is wider than the base register size in shift register in " + << Serialize(); + + switch (shift_op.shift_op) { + + // Left shift. + case Operand::ShiftRegister::kShiftLeftWithZeroes: + expr = EmplaceBinaryOp(llvm::Instruction::Shl, expr, EmplaceConstant(shift_val)); + break; + + // Masking shift left. + case Operand::ShiftRegister::kShiftLeftWithOnes: { + const auto mask_val = + llvm::ConstantInt::get(reg_type, ~((~zero) << shift_size)); + expr = EmplaceBinaryOp(llvm::Instruction::Shl, expr, EmplaceConstant(shift_val)); + expr = EmplaceBinaryOp(llvm::Instruction::Or, expr, EmplaceConstant(mask_val)); + break; + } + + // Logical right shift. + case Operand::ShiftRegister::kShiftUnsignedRight: + expr = EmplaceBinaryOp(llvm::Instruction::LShr, expr, EmplaceConstant(shift_val)); + break; + + // Arithmetic right shift. + case Operand::ShiftRegister::kShiftSignedRight: + expr = EmplaceBinaryOp(llvm::Instruction::AShr, expr, EmplaceConstant(shift_val)); + break; + + // Rotate left. + case Operand::ShiftRegister::kShiftLeftAround: { + const uint64_t shr_amount = (~shift_size + one) & (op.size - one); + const auto shr_val = llvm::ConstantInt::get(op_type, shr_amount); + auto expr1 = EmplaceBinaryOp(llvm::Instruction::LShr, expr, EmplaceConstant(shr_val)); + auto expr2 = EmplaceBinaryOp(llvm::Instruction::Shl, expr, EmplaceConstant(shift_val)); + expr = EmplaceBinaryOp(llvm::Instruction::Or, expr1, expr2); + break; + } + + // Rotate right. + case Operand::ShiftRegister::kShiftRightAround: { + const uint64_t shl_amount = (~shift_size + one) & (op.size - one); + const auto shl_val = llvm::ConstantInt::get(op_type, shl_amount); + auto expr1 = EmplaceBinaryOp(llvm::Instruction::LShr, expr, EmplaceConstant(shift_val)); + auto expr2 = EmplaceBinaryOp(llvm::Instruction::Shl, expr, EmplaceConstant(shl_val)); + expr = EmplaceBinaryOp(llvm::Instruction::Or, expr1, expr2); + break; + } + + case Operand::ShiftRegister::kShiftInvalid: break; + } + } + if (curr_size < op.size) { + expr = EmplaceUnaryOp(llvm::Instruction::ZExt, expr, op_type); + curr_size = op.size; + } + }; + + if (shift_op.shift_first) { + do_shift(); + do_extract(); + } else { + do_extract(); + do_shift(); + } + op.expr = expr; + return op; +} + +Operand& Instruction::EmplaceOperand(const Operand::Address &addr_op) { + operands.emplace_back(); + auto &op = operands.back(); + + const auto word_type = arch_for_decode->AddressType(); + const auto zero = llvm::ConstantInt::get(word_type, 0, false); + const auto word_size = arch_for_decode->address_size; + + CHECK(word_size >= addr_op.base_reg.size)<< "Memory base register " + << addr_op.base_reg.name << "for instruction at " << std::hex << pc + << " is wider than the machine word size."; + + CHECK(word_size >= addr_op.index_reg.size)<< "Memory index register " + << addr_op.base_reg.name << "for instruction at " << std::hex << pc + << " is wider than the machine word size."; + + auto reg_or_zero = [=](const Operand::Register & reg) { + if (!reg.name.empty()) { + auto reg_pointer = arch_for_decode->RegisterByName(reg.name); + return EmplaceRegister(reg_pointer); + } else { + return EmplaceConstant(zero); + } + }; + + auto addr = reg_or_zero(addr_op.base_reg); + + if (!addr_op.index_reg.name.empty() && addr_op.scale) { + auto index = reg_or_zero(addr_op.index_reg); + if (addr_op.scale != 1) { + auto scale = llvm::ConstantInt::get(word_type, + static_cast(addr_op.scale), + true); + index = EmplaceBinaryOp(llvm::Instruction::Mul, index, EmplaceConstant(scale)); + } + addr = EmplaceBinaryOp(llvm::Instruction::Add, addr, index); + } + + if (addr_op.displacement) { + if (0 < addr_op.displacement) { + auto disp = llvm::ConstantInt::get(word_type, + static_cast(addr_op.displacement)); + addr = EmplaceBinaryOp(llvm::Instruction::Add, addr, EmplaceConstant(disp)); + } else { + auto disp = llvm::ConstantInt::get(word_type, + static_cast(-addr_op.displacement)); + addr = EmplaceBinaryOp(llvm::Instruction::Sub, addr, EmplaceConstant(disp)); + } + } + + // Compute the segmented address. + if (!addr_op.segment_base_reg.name.empty()) { + auto segment = reg_or_zero(addr_op.segment_base_reg); + addr = EmplaceBinaryOp(llvm::Instruction::Add, addr, segment); + } + + // Memory address is smaller than the machine word size (e.g. 32-bit address + // used in 64-bit). + if (addr_op.address_size < word_size) { + auto addr_type = llvm::Type::getIntNTy( + *arch_for_decode->context, static_cast(addr_op.address_size)); + + addr = EmplaceUnaryOp(llvm::Instruction::Trunc, addr, addr_type); + addr = EmplaceUnaryOp(llvm::Instruction::ZExt, addr, word_type); + } + op.expr = addr; + op.type = Operand::kTypeExpression; + return op; +} + bool Instruction::FinalizeDecode(void) { if (!IsValid()) { return false; diff --git a/lib/BC/InstructionLifter.cpp b/lib/BC/InstructionLifter.cpp index ef6b9c039..3f8975216 100644 --- a/lib/BC/InstructionLifter.cpp +++ b/lib/BC/InstructionLifter.cpp @@ -615,22 +615,91 @@ InstructionLifter::LiftImmediateOperand(Instruction &inst, llvm::BasicBlock *, } // Lift an expression operand. -llvm::Value *InstructionLifter::LiftExpressionOperand(Instruction &inst, - llvm::BasicBlock *block, - llvm::Value *state_ptr, - llvm::Argument *arg, Operand &op) { +llvm::Value* InstructionLifter::LiftExpressionOperand(Instruction &inst, + llvm::BasicBlock *block, + llvm::Value *state_ptr, + llvm::Argument *arg, + Operand &op) { + auto val = LiftExpressionOperandRec(inst, block, state_ptr, arg, op.expr); + llvm::Function *func = block->getParent(); + llvm::Module *module = func->getParent(); + const auto real_arg_type = arg->getType(); + + // LLVM on AArch64 and on amd64 Windows converts things like `RnW`, + // which is a struct containing a `uint64_t *`, into a `uintptr_t` when they + // are being passed as arguments. + auto arg_type = IntendedArgumentType(arg); + + if (llvm::isa(arg_type)) { + return ConvertToIntendedType(inst, op, block, val, real_arg_type); + + } else { + CHECK(arg_type->isIntegerTy() || arg_type->isFloatingPointTy()) + << "Expected " << op.Serialize() << " to be an integral or float type " + << "for instruction at " << std::hex << inst.pc; + const llvm::DataLayout data_layout(module); + auto val_type = val->getType(); + auto val_size = data_layout.getTypeAllocSizeInBits(val_type); + auto arg_size = data_layout.getTypeAllocSizeInBits(arg_type); + const auto word_size = impl->arch->address_size; + + if (val_size < arg_size) { + if (arg_type->isIntegerTy()) { + CHECK(val_type->isIntegerTy()) + << "Expected " << op.Serialize() << " to be an integral type " + << "for instruction at " << std::hex << inst.pc; + + CHECK(word_size == arg_size) + << "Expected integer argument to be machine word size (" + << word_size << " bits) but is is " << arg_size << " instead " + << "in instruction at " << std::hex << inst.pc; + + val = new llvm::ZExtInst(val, impl->word_type, "", block); + + } else if (arg_type->isFloatingPointTy()) { + CHECK(val_type->isFloatingPointTy()) + << "Expected " << op.Serialize() << " to be a floating point type " + << "for instruction at " << std::hex << inst.pc; + + val = new llvm::FPExtInst(val, arg_type, "", block); + } + + } else if (val_size > arg_size) { + if (arg_type->isIntegerTy()) { + CHECK(val_type->isIntegerTy()) + << "Expected " << op.Serialize() << " to be an integral type " + << "for instruction at " << std::hex << inst.pc; + + CHECK(word_size == arg_size) + << "Expected integer argument to be machine word size (" + << word_size << " bits) but is is " << arg_size << " instead " + << "in instruction at " << std::hex << inst.pc; + + val = new llvm::TruncInst(val, arg_type, "", block); + + } else if (arg_type->isFloatingPointTy()) { + CHECK(val_type->isFloatingPointTy()) + << "Expected " << op.Serialize() << " to be a floating point type " + << "for instruction at " << std::hex << inst.pc; + + val = new llvm::FPTruncInst(val, arg_type, "", block); + } + } + + return ConvertToIntendedType(inst, op, block, val, real_arg_type); + } } // Lift an expression operand. -llvm::Value* InstructionLifter::LiftExpressionOperand( +llvm::Value *InstructionLifter::LiftExpressionOperandRec( Instruction &inst, llvm::BasicBlock *block, llvm::Value *state_ptr, llvm::Argument *arg, const OperandExpression *op) { if (auto llvm_op = std::get_if(op)) { - auto lhs = LiftExpressionOperand(inst, block, state_ptr, nullptr, llvm_op->op1); + auto lhs = LiftExpressionOperandRec(inst, block, state_ptr, nullptr, llvm_op->op1); llvm::Value * rhs = nullptr; if (llvm_op->op2) { - rhs = LiftExpressionOperand(inst, block, state_ptr, nullptr, llvm_op->op2); + rhs = LiftExpressionOperandRec(inst, block, state_ptr, nullptr, llvm_op->op2); } llvm::IRBuilder<> ir(block); switch (llvm_op->llvm_opcode) { @@ -652,6 +721,15 @@ llvm::Value* InstructionLifter::LiftExpressionOperand( return ir.CreateSExt(lhs, op->type); case llvm::Instruction::Trunc: return ir.CreateTrunc(lhs, op->type); + case llvm::Instruction::And: + return ir.CreateAnd(lhs, rhs); + case llvm::Instruction::Or: + return ir.CreateOr(lhs, rhs); + default: + LOG(FATAL) + << "Invalid Expression " + << llvm::Instruction::getOpcodeName(llvm_op->llvm_opcode) ; + return nullptr; } } else if (auto reg_op = std::get_if(op)) { @@ -664,12 +742,15 @@ llvm::Value* InstructionLifter::LiftExpressionOperand( } else if (auto ci_op = std::get_if(op)) { return *ci_op; - } else if (auto str_op = std::get_if(op)) { + } else if (auto str_op = std::get_if(op)) { if (!arg || !llvm::isa(arg->getType())) { return LoadRegValue(block, state_ptr, *str_op); } else { return LoadRegAddress(block, state_ptr, *str_op); } + } else { + LOG(FATAL) << "Uninitialized Operand Expression"; + return nullptr; } } From 1147d8f60bc379e5f7085b279fc4dc3324bc85b5 Mon Sep 17 00:00:00 2001 From: sschriner Date: Mon, 9 Nov 2020 13:42:34 -0500 Subject: [PATCH 078/130] Fix the .gitignore to add AArch32 to lib/Arch && removed all extra rrx ops from semantics --- .gitignore | 1 - lib/Arch/AArch32/Arch.cpp | 181 +++ lib/Arch/AArch32/Arch.h | 55 + lib/Arch/AArch32/CMakeLists.txt | 46 + lib/Arch/AArch32/Decode.cpp | 1443 +++++++++++++++++++++ lib/Arch/AArch32/Runtime/BasicBlock.cpp | 34 + lib/Arch/AArch32/Runtime/CMakeLists.txt | 63 + lib/Arch/AArch32/Runtime/Instructions.cpp | 74 ++ lib/Arch/AArch32/Semantics/BINARY.cpp | 272 ++++ lib/Arch/AArch32/Semantics/COND.cpp | 56 + lib/Arch/AArch32/Semantics/FLAGS.cpp | 189 +++ lib/Arch/AArch32/Semantics/LOGICAL.cpp | 64 + lib/Arch/AArch32/Semantics/MEM.cpp | 87 ++ 13 files changed, 2564 insertions(+), 1 deletion(-) create mode 100644 lib/Arch/AArch32/Arch.cpp create mode 100644 lib/Arch/AArch32/Arch.h create mode 100644 lib/Arch/AArch32/CMakeLists.txt create mode 100644 lib/Arch/AArch32/Decode.cpp create mode 100644 lib/Arch/AArch32/Runtime/BasicBlock.cpp create mode 100644 lib/Arch/AArch32/Runtime/CMakeLists.txt create mode 100644 lib/Arch/AArch32/Runtime/Instructions.cpp create mode 100644 lib/Arch/AArch32/Semantics/BINARY.cpp create mode 100644 lib/Arch/AArch32/Semantics/COND.cpp create mode 100644 lib/Arch/AArch32/Semantics/FLAGS.cpp create mode 100644 lib/Arch/AArch32/Semantics/LOGICAL.cpp create mode 100644 lib/Arch/AArch32/Semantics/MEM.cpp diff --git a/.gitignore b/.gitignore index 2838a539b..e331c6e90 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,6 @@ cmake-build-release compile_commands.json bin/* -lib/* third_party/* build/* diff --git a/lib/Arch/AArch32/Arch.cpp b/lib/Arch/AArch32/Arch.cpp new file mode 100644 index 000000000..92da9a332 --- /dev/null +++ b/lib/Arch/AArch32/Arch.cpp @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Arch.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "remill/Arch/Instruction.h" +#include "remill/Arch/Name.h" +#include "remill/BC/ABI.h" +#include "remill/BC/Util.h" +#include "remill/BC/Version.h" +#include "remill/OS/OS.h" + +// clang-format off +#define ADDRESS_SIZE 32 +#include "remill/Arch/AArch32/Runtime/State.h" + +// clang-format on + +namespace remill { + +AArch32Arch::AArch32Arch(llvm::LLVMContext *context_, OSName os_name_, + ArchName arch_name_) + : Arch(context_, os_name_, arch_name_) {} + +AArch32Arch::~AArch32Arch(void) {} + +// Maximum number of bytes in an instruction for this particular architecture. +uint64_t AArch32Arch::MaxInstructionSize(void) const { + return 4; +} + +// Default calling convention for this architecture. +llvm::CallingConv::ID AArch32Arch::DefaultCallingConv(void) const { + return llvm::CallingConv::C; // cdecl. +} + +// Get the LLVM triple for this architecture. +llvm::Triple AArch32Arch::Triple(void) const { + auto triple = BasicTriple(); + switch (arch_name) { + case kArchAArch32LittleEndian: triple.setArch(llvm::Triple::arm); break; + default: + LOG(FATAL) << "Cannot get triple for non-aarch32 architecture " + << GetArchName(arch_name); + } + + return triple; +} + +// Get the LLVM DataLayout for a module. +llvm::DataLayout AArch32Arch::DataLayout(void) const { + std::string dl; + switch (os_name) { + case kOSInvalid: + LOG(FATAL) << "Cannot convert module for an unrecognized OS."; + break; + + case kOSLinux: + case kOSSolaris: + case kOSmacOS: + case kOSWindows: + dl = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"; + break; + } + + return llvm::DataLayout(dl); +} + +// Returns the name of the stack pointer register. +std::string_view AArch32Arch::StackPointerRegisterName(void) const { + return "SP"; +} + +// Returns the name of the program counter register. +std::string_view AArch32Arch::ProgramCounterRegisterName(void) const { + return "PC"; +} + +// Populate the `__remill_basic_block` function with variables. +void AArch32Arch::PopulateBasicBlockFunction(llvm::Module *module, + llvm::Function *bb_func) const { + const auto &dl = module->getDataLayout(); + CHECK_EQ(sizeof(State), dl.getTypeAllocSize(StateStructType())) + << "Mismatch between size of State type for x86/amd64 and what is in " + << "the bitcode module"; + + auto &context = module->getContext(); + auto u8 = llvm::Type::getInt8Ty(context); +// auto u16 = llvm::Type::getInt16Ty(context); + auto u32 = llvm::Type::getInt32Ty(context); +// auto u64 = llvm::Type::getInt64Ty(context); +// auto f64 = llvm::Type::getDoubleTy(context); +// auto v128 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 128u / 8u); +// auto v256 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 256u / 8u); +// auto v512 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 512u / 8u); + auto addr = llvm::Type::getIntNTy(context, address_size); + //auto zero_addr_val = llvm::Constant::getNullValue(addr); + + const auto entry_block = &bb_func->getEntryBlock(); + llvm::IRBuilder<> ir(entry_block); + +#define OFFSET_OF(type, access) \ + (reinterpret_cast(&reinterpret_cast( \ + static_cast(nullptr)->access))) + +#define REG(name, access, type) \ + AddRegister(#name, type, OFFSET_OF(State, access), nullptr) + +#define SUB_REG(name, access, type, parent_reg_name) \ + AddRegister(#name, type, OFFSET_OF(State, access), #parent_reg_name) + + REG(R0, gpr.r0.dword, u32); + REG(R1, gpr.r1.dword, u32); + REG(R2, gpr.r2.dword, u32); + REG(R3, gpr.r3.dword, u32); + REG(R4, gpr.r4.dword, u32); + REG(R5, gpr.r5.dword, u32); + REG(R6, gpr.r6.dword, u32); + REG(R7, gpr.r7.dword, u32); + REG(R8, gpr.r8.dword, u32); + REG(R9, gpr.r9.dword, u32); + REG(R10, gpr.r10.dword, u32); + REG(R11, gpr.r11.dword, u32); + REG(R12, gpr.r12.dword, u32); + REG(R13, gpr.r13.dword, u32); + REG(R14, gpr.r14.dword, u32); + REG(R15, gpr.r15.dword, u32); + + SUB_REG(SP, gpr.r13.dword, u32, R13); + SUB_REG(LR, gpr.r14.dword, u32, R14); + SUB_REG(PC, gpr.r15.dword, u32, R15); + + REG(N, sr.n, u8); + REG(C, sr.c, u8); + REG(Z, sr.z, u8); + REG(V, sr.v, u8); + + const auto pc_arg = NthArgument(bb_func, kPCArgNum); + const auto state_ptr_arg = NthArgument(bb_func, kStatePointerArgNum); + ir.CreateStore(pc_arg, ir.CreateAlloca(addr, nullptr, "NEXT_PC")); + + auto zero_c = ir.CreateAlloca(u8, nullptr, "ZERO_C"); + ir.CreateStore(llvm::Constant::getNullValue(u8), zero_c); + ir.CreateAlloca(u32, nullptr, "SUPPRESS_WRITEBACK"); + (void) this->RegisterByName("PC")->AddressOf(state_ptr_arg, ir); +} + +// TODO(pag): We pretend that these are singletons, but they aren't really! +Arch::ArchPtr Arch::GetAArch32(llvm::LLVMContext *context_, OSName os_name_, + ArchName arch_name_) { + return std::make_unique(context_, os_name_, arch_name_); +} + +} // namespace remill diff --git a/lib/Arch/AArch32/Arch.h b/lib/Arch/AArch32/Arch.h new file mode 100644 index 000000000..0f7124aff --- /dev/null +++ b/lib/Arch/AArch32/Arch.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "remill/Arch/Arch.h" + +namespace remill { +class AArch32Arch final : public Arch { + public: + AArch32Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_); + + virtual ~AArch32Arch(void); + + // Returns the name of the stack pointer register. + std::string_view StackPointerRegisterName(void) const override; + + // Returns the name of the program counter register. + std::string_view ProgramCounterRegisterName(void) const override; + + // Decode an instuction. + bool DecodeInstruction(uint64_t address, std::string_view inst_bytes, + Instruction &inst) const override; + + // Maximum number of bytes in an instruction. + uint64_t MaxInstructionSize(void) const override; + + llvm::Triple Triple(void) const override; + llvm::DataLayout DataLayout(void) const override; + + // Default calling convention for this architecture. + llvm::CallingConv::ID DefaultCallingConv(void) const override; + + // Populate the `__remill_basic_block` function with variables. + void PopulateBasicBlockFunction(llvm::Module *module, + llvm::Function *bb_func) const override; + + private: + AArch32Arch(void) = delete; +}; + +} // namespace remill diff --git a/lib/Arch/AArch32/CMakeLists.txt b/lib/Arch/AArch32/CMakeLists.txt new file mode 100644 index 000000000..f76bef4be --- /dev/null +++ b/lib/Arch/AArch32/CMakeLists.txt @@ -0,0 +1,46 @@ +# Copyright (c) 2020 Trail of Bits, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +add_library(remill_arch_aarch32 STATIC + "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Definitions.h" + "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/HyperCall.h" + "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Intrinsics.h" + "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Operators.h" + "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Runtime.h" + "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/State.h" + "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Types.h" + + "${REMILL_INCLUDE_DIR}/remill/Arch/AArch32/Runtime/Operators.h" + "${REMILL_INCLUDE_DIR}/remill/Arch/AArch32/Runtime/State.h" + "${REMILL_INCLUDE_DIR}/remill/Arch/AArch32/Runtime/Types.h" + + Arch.cpp + Decode.cpp +# Decode.h +# Extract.cpp +) + +add_subdirectory(Runtime) + +set_property(TARGET remill_arch_aarch32 PROPERTY POSITION_INDEPENDENT_CODE ON) + +target_link_libraries(remill_arch_aarch32 LINK_PUBLIC + remill_settings +) + +install( + TARGETS remill_arch_aarch32 + ARCHIVE DESTINATION "${REMILL_INSTALL_LIB_DIR}" + PUBLIC_HEADER DESTINATION "${REMILL_INSTALL_INCLUDE_DIR}" +) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp new file mode 100644 index 000000000..18eddae66 --- /dev/null +++ b/lib/Arch/AArch32/Decode.cpp @@ -0,0 +1,1443 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Arch.h" + +#include + +namespace remill { + +namespace { + +//Integer Data Processing (three register, register shift) +//union IntDataProcessingRRRR { +// uint32_t flat; +// struct { +// uint32_t rm : 4; +// uint32_t _1 : 1; +// uint32_t type : 2; +// uint32_t _0 : 1; +// uint32_t rs : 4; +// uint32_t rd : 4; +// uint32_t rn : 4; +// uint32_t s : 1; +// uint32_t opc : 3; +// uint32_t _0000 : 4; +// uint32_t cond : 4; +// } __attribute__((packed)); +//} __attribute__((packed)); +//static_assert(sizeof(IntDataProcessingRRRR) == 4, " "); + +//Integer Data Processing (three register, immediate shift) +union IntDataProcessingRRRI { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _0 : 1; + uint32_t type : 2; + uint32_t imm5 : 5; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 3; + uint32_t _0000 : 4; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntDataProcessingRRRI) == 4, " "); + +//Integer Data Processing (2 register and immediate, immediate shift) +union IntDataProcessingRRI { + uint32_t flat; + struct { + uint32_t imm12 : 12; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 3; + uint32_t _0010 : 4; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntDataProcessingRRI) == 4, " "); + +// Multiply and Accumulate +union MultiplyAndAccumulate { + uint32_t flat; + struct { + uint32_t rn : 4; + uint32_t _1001 : 4; + uint32_t rm : 4; + uint32_t rdlo : 4; + uint32_t rdhi : 4; + uint32_t s : 1; + uint32_t opc : 3; + uint32_t _0000 : 4; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(MultiplyAndAccumulate) == 4, " "); + +// Load/Store Word, Unsigned Byte (immediate, literal) +union LoadStoreWUBIL { + uint32_t flat; + struct { + uint32_t imm12 : 12; + uint32_t rt : 4; + uint32_t rn : 4; + uint32_t o1 : 1; + uint32_t W : 1; + uint32_t o2 : 1; + uint32_t u : 1; + uint32_t P : 1; + uint32_t _010 : 3; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(LoadStoreWUBIL) == 4, " "); + +// Integer Test and Compare (two register, immediate shift) +union IntTestCompRRI { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _0 : 1; + uint32_t type : 2; + uint32_t imm5 : 5; + uint32_t _0000 : 4; + uint32_t rn : 4; + uint32_t _1 : 1; + uint32_t opc : 2; + uint32_t _00010 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntTestCompRRI) == 4, " "); + +// Integer Test and Compare (two register, register shift) +//union IntTestCompRRR { +// uint32_t flat; +// struct { +// uint32_t rm : 4; +// uint32_t _1 : 1; +// uint32_t type : 2; +// uint32_t _0 : 1; +// uint32_t rs : 4; +// uint32_t _0000 : 4; +// uint32_t rn : 4; +// uint32_t _1a : 1; +// uint32_t opc : 2; +// uint32_t _00010 : 5; +// uint32_t cond : 4; +// } __attribute__((packed)); +//} __attribute__((packed)); +//static_assert(sizeof(IntTestCompRRR) == 4, " "); + +// Integer Test and Compare (one register and immediate) +union IntTestCompRI { + uint32_t flat; + struct { + uint32_t imm12 : 12; + uint32_t _0000 : 4; + uint32_t rn : 4; + uint32_t _1 : 1; + uint32_t opc : 2; + uint32_t _00110 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntTestCompRI) == 4, " "); + +// Logical Arithmetic (three register, immediate shift) +union LogicalArithRRRI { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _0 : 1; + uint32_t type : 2; + uint32_t imm5 : 5; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 2; + uint32_t _00011 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(LogicalArithRRRI) == 4, " "); + +// Logical Arithmetic (three register, register shift) +//union LogicalArithRRRR { +// uint32_t flat; +// struct { +// uint32_t rm : 4; +// uint32_t _1 : 1; +// uint32_t type : 2; +// uint32_t _0 : 1; +// uint32_t rs : 4; +// uint32_t rd : 4; +// uint32_t rn : 4; +// uint32_t s : 1; +// uint32_t opc : 2; +// uint32_t _00011 : 5; +// uint32_t cond : 4; +// } __attribute__((packed)); +//} __attribute__((packed)); +//static_assert(sizeof(LogicalArithRRRR) == 4, " "); + +union LogicalArithmeticRRI { + uint32_t flat; + struct { + uint32_t imm12 : 12; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 2; + uint32_t _00111 : 5; + uint32_t cond : 4; + } __attribute__((packed)); + } __attribute__((packed)); +static_assert(sizeof(LogicalArithmeticRRI) == 4, " "); + +// Top-level encodings for A32 +union TopLevelEncodings { + uint32_t flat; + struct { + uint32_t _3_to_0 : 4; + uint32_t op1 : 1; + uint32_t _24_to_5 : 20; + uint32_t op0 : 3; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(TopLevelEncodings) == 4, " "); + +// Data-processing and miscellaneous instructions +union DataProcessingAndMisc { + uint32_t flat; + struct { + uint32_t _3_to_0 : 4; + uint32_t op4 : 1; + uint32_t op3 : 2; + uint32_t op2 : 1; + uint32_t _19_to_8 : 12; + uint32_t op1 : 5; + uint32_t op0 : 1; + uint32_t _00 : 2; + uint32_t _not1111 : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(DataProcessingAndMisc) == 4, " "); + +static constexpr auto kPCRegNum = 15u; + +static const char * const kIntRegName[] = { + "R0", + "R1", + "R2", + "R3", + "R4", + "R5", + "R6", + "R7", + "R8", + "R9", + "R10", + "R11", + "R12", + "R13", + "R14", + "R15" +}; + +typedef bool (TryDecode)(Instruction&, uint32_t); +typedef std::optional (InstEval)(uint32_t, uint32_t); + +static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, + Operand::Action action) { + Operand::Register reg; + reg.size = size; + reg.name = kIntRegName[index]; + auto &op = inst.EmplaceOperand(reg); + op.action = action; +} + +static void AddImmOp(Instruction &inst, uint64_t value, unsigned size = 32, + Operand::Action action = Operand::kActionRead, + bool is_signed = false) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.imm.val = value; + op.size = size; + op.imm.is_signed = is_signed; + op.action = action; + op.type = Operand::kTypeImmediate; +} + +static void AddAddrRegOp(Instruction &inst, const char *reg_name, + unsigned mem_size, Operand::Action mem_action, + unsigned disp, unsigned scale = 0) { + Operand::Address addr; + addr.address_size = 32; + addr.base_reg.name = reg_name; + addr.base_reg.size = 32; + addr.scale = scale; + addr.displacement = disp; + auto &op = inst.EmplaceOperand(addr); + op.size = mem_size; + op.action = mem_action; +} + +static void AddShiftOp(Instruction &inst, + Operand::ShiftRegister::Shift shift_op, + const char *reg_name, unsigned reg_size, + unsigned shift_size) { + Operand::ShiftRegister shift_reg; + shift_reg.reg.name = reg_name; + shift_reg.reg.size = reg_size; + shift_reg.shift_op = shift_op; + shift_reg.shift_size = shift_size; + auto &op = inst.EmplaceOperand(shift_reg); + op.action = Operand::kActionRead; +} + +static void AddShiftThenExtractOp(Instruction &inst, + Operand::ShiftRegister::Shift shift_op, + Operand::ShiftRegister::Extend extend_op, + const char *reg_name, unsigned reg_size, + unsigned shift_size, unsigned extract_size) { + Operand::ShiftRegister shift_reg; + shift_reg.reg.name = reg_name; + shift_reg.reg.size = reg_size; + shift_reg.shift_op = shift_op; + shift_reg.shift_size = shift_size; + shift_reg.extract_size = extract_size; + shift_reg.extend_op = extend_op; + shift_reg.shift_first = true; + auto &op = inst.EmplaceOperand(shift_reg); + op.action = Operand::kActionRead; + +} + +static void AddExtractThenShiftOp(Instruction &inst, + Operand::ShiftRegister::Shift shift_op, + Operand::ShiftRegister::Extend extend_op, + const char *reg_name, unsigned reg_size, + unsigned shift_size, unsigned extract_size) { + Operand::ShiftRegister shift_reg; + shift_reg.reg.name = reg_name; + shift_reg.reg.size = reg_size; + shift_reg.shift_op = shift_op; + shift_reg.shift_size = shift_size; + shift_reg.extract_size = extract_size; + shift_reg.extend_op = extend_op; + shift_reg.shift_first = false; + auto &op = inst.EmplaceOperand(shift_reg); + op.action = Operand::kActionRead; +} + + +// Note: Order is significant; extracted bits may be casted to this type. +enum Shift : uint32_t { kShiftLSL, kShiftLSR, kShiftASR, kShiftROR }; + +// Translate a shift encoding into an operand shift type used by the shift +// register class. +static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { + switch (s) { + case kShiftLSL: + return Operand::ShiftRegister::kShiftLeftWithZeroes; + case kShiftLSR: + return Operand::ShiftRegister::kShiftUnsignedRight; + case kShiftASR: + return Operand::ShiftRegister::kShiftSignedRight; + case kShiftROR: + return Operand::ShiftRegister::kShiftRightAround; + } + return Operand::ShiftRegister::kShiftInvalid; +} + +// Note: This function adds either 1 or 2 operands in total +// an op and an optional additional carry_out op +// Used to handle semantics for: +// (imm32, carry) = A32ExpandImm_C(imm12, PSTATE.C); +// See an instruction in Data-processing register (immediate shift) for example +static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, bool carry_out) { + uint32_t unrotated_value = imm12 & (0b11111111u); + uint32_t rotation_amount = ((imm12 >> 8) & (0b1111u)) *2u; + + if (!rotation_amount) { + AddImmOp(inst, unrotated_value); + } else { + AddImmOp(inst, __builtin_rotateright32(unrotated_value, rotation_amount)); + } + + if (carry_out) { + if (!rotation_amount) { + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, + Operand::ShiftRegister::kExtendUnsigned, "C", 8, 0, + 1); + } else { + AddImmOp(inst, + (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u); + } + } +} + +// Note: This function should be used with AddShiftCarryOperand to add carry_out operand! +// Used to handle semantics for: +// (shifted, carry) = Shift_C(R[m], shift_t, shift_n, PSTATE.C); +// (shift_t, shift_n) = DecodeImmShift(type, imm5); +// See an instruction in Integer Data Processing (three register, immediate shift) set for an example +static void AddShiftRegOperand(Instruction &inst, + uint32_t reg_num, uint32_t shift_type, + uint32_t shift_size) { + auto is_rrx = false; + if (!shift_size && shift_type == Shift::kShiftROR) { + shift_size = 1; + is_rrx = true; + } else if (shift_type == Shift::kShiftLSR || shift_type == Shift::kShiftASR) { + if (!shift_size) { + shift_size = 32; + } + } + + if (!shift_size) { + AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); + } else { + if (is_rrx) { + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, + kIntRegName[reg_num], 32, 1); + } else { + AddShiftOp(inst, GetOperandShift(static_cast(shift_type)), + kIntRegName[reg_num], 32, shift_size); + } + } + + // To handle rrx we need to take two components shift each and OR the results + // together. We create this functionality by creating a new shift operand, + // removing it from the instruction operand list, and adding a binary op to + // the register operand that ORs the expressions together. + if (is_rrx) { + AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, "C", 8, 31); + auto rrx_op = inst.operands.back().expr; + inst.operands.pop_back(); + inst.operands.back().expr = inst.EmplaceBinaryOp(llvm::Instruction::Or, + inst.operands.back().expr, + rrx_op); + } +} + + +// PLEASE SEE AddShiftRegOperand! +// This function extracts the carry_out that from the semantics that +// AddShiftRegOperand handles +static void AddShiftCarryOperand(Instruction &inst, + uint32_t reg_num, uint32_t shift_type, + uint32_t shift_size, const char * carry_reg_name) { + + auto is_rrx = false; + if (!shift_size && shift_type == Shift::kShiftROR) { + shift_size = 1; + is_rrx = true; + } + + if (!shift_size) { + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, + Operand::ShiftRegister::kExtendUnsigned, + carry_reg_name, 8, 0, 1); + } else { + switch (static_cast(shift_type)) { + case Shift::kShiftASR: + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftSignedRight, + Operand::ShiftRegister::kExtendUnsigned, + kIntRegName[reg_num], 32, shift_size - 1, 1); + break; + case Shift::kShiftLSL: + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, + Operand::ShiftRegister::kExtendUnsigned, + kIntRegName[reg_num], 32, 32 - shift_size, 1); + break; + case Shift::kShiftLSR: + AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, + Operand::ShiftRegister::kExtendUnsigned, + kIntRegName[reg_num], 32, shift_size - 1, 1); + break; + case Shift::kShiftROR: + if (is_rrx) { + AddShiftThenExtractOp(inst, + Operand::ShiftRegister::kShiftUnsignedRight, + Operand::ShiftRegister::kExtendUnsigned, + kIntRegName[reg_num], 32, 0, 1); + } else { + AddShiftThenExtractOp(inst, + Operand::ShiftRegister::kShiftUnsignedRight, + Operand::ShiftRegister::kExtendUnsigned, + kIntRegName[reg_num], 32, + (shift_size + 31u) % 32u, 1); + } + break; + } + } +} + +// Decode the condition field and fill in the instruction conditions accordingly +static void DecodeCondition(Instruction &inst, uint32_t cond) { + inst.conditions.emplace_back(); + auto &lhs_cond = inst.conditions.back(); + + switch (cond) { + case 0b0001: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b0000: { + lhs_cond.kind = Condition::kTypeIsOne; + lhs_cond.lhs_reg.name = "Z"; + lhs_cond.lhs_reg.size = 8; + break; + } + case 0b0011: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b0010: { + lhs_cond.kind = Condition::kTypeIsOne; + lhs_cond.lhs_reg.name = "C"; + lhs_cond.lhs_reg.size = 8; + break; + } + case 0b0101: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b0100: { + lhs_cond.kind = Condition::kTypeIsOne; + lhs_cond.lhs_reg.name = "N"; + lhs_cond.lhs_reg.size = 8; + break; + } + case 0b0111: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b0110: { + lhs_cond.kind = Condition::kTypeIsOne; + lhs_cond.lhs_reg.name = "V"; + lhs_cond.lhs_reg.size = 8; + break; + } + case 0b1001: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b1000: { + lhs_cond.kind = Condition::kTypeIsOne; + lhs_cond.lhs_reg.name = "C"; + lhs_cond.lhs_reg.size = 8; + + inst.conditions.emplace_back(); + auto &rhs_cond = inst.conditions.back(); + rhs_cond.kind = Condition::kTypeIsZero; + rhs_cond.rhs_reg.name = "Z"; + rhs_cond.rhs_reg.size = 8; + break; + } + case 0b1011: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b1010: { + lhs_cond.kind = Condition::kTypeIsEqual; + lhs_cond.lhs_reg.name = "N"; + lhs_cond.lhs_reg.size = 8; + + lhs_cond.rhs_reg.name = "V"; + lhs_cond.rhs_reg.size = 8; + break; + } + case 0b1101: + inst.negate_conditions = true; + [[clang::fallthrough]]; + case 0b1100: { + lhs_cond.kind = Condition::kTypeIsEqual; + lhs_cond.lhs_reg.name = "N"; + lhs_cond.lhs_reg.size = 8; + + lhs_cond.rhs_reg.name = "V"; + lhs_cond.rhs_reg.size = 8; + + inst.conditions.emplace_back(); + auto &rhs_cond = inst.conditions.back(); + rhs_cond.kind = Condition::kTypeIsZero; + rhs_cond.rhs_reg.name = "Z"; + rhs_cond.rhs_reg.size = 8; + break; + } + case 0b1111: + case 0b1110: + inst.conditions.pop_back(); + break; + default: + LOG(FATAL) << "Invalid condition bits " << cond << " in " << inst.Serialize(); + break; + } +} + +std::optional EvalReg(const Instruction &inst, const Operand::Register &op) { + if (op.name == kIntRegName[kPCRegNum] || op.name == "PC") { + return inst.pc; + } else if (op.name == "NEXT_PC") { + return inst.next_pc; + } else if (op.name.empty()) { + return 0u; + } else { + return std::nullopt; + } +} + +std::optional EvalShift(const Operand::ShiftRegister &op, + std::optional maybe_val) { + if (!maybe_val || !op.shift_size) { + return maybe_val; + } + + if (op.reg.size != 32) { + return std::nullopt; + } + + auto val = static_cast(*maybe_val); + + switch (op.shift_op) { + case Operand::ShiftRegister::kShiftInvalid: + return maybe_val; + case Operand::ShiftRegister::kShiftLeftAround: + return __builtin_rotateleft32(val, static_cast(op.shift_size)); + case Operand::ShiftRegister::kShiftRightAround: + return __builtin_rotateright32(val, static_cast(op.shift_size)); + case Operand::ShiftRegister::kShiftLeftWithOnes: + return (val << op.shift_size) | ~(~0u << op.shift_size); + case Operand::ShiftRegister::kShiftLeftWithZeroes: + return val << op.shift_size; + case Operand::ShiftRegister::kShiftUnsignedRight: + return val >> op.shift_size; + case Operand::ShiftRegister::kShiftSignedRight: + return static_cast(static_cast(val) >> op.shift_size); + default: + return std::nullopt; + } +} + +std::optional EvalExtract(const Operand::ShiftRegister &op, + std::optional maybe_val) { + if (!maybe_val || !op.extract_size) { + return maybe_val; + } + + if (op.reg.size != 32) { + return std::nullopt; + } + + auto val = static_cast(*maybe_val); + + switch (op.extend_op) { + case Operand::ShiftRegister::kExtendInvalid: + return maybe_val; + case Operand::ShiftRegister::kExtendSigned: + { + val &= (1u << (op.extract_size)) - 1u; + auto sign = val >> (op.extract_size - 1u); + + if (sign) { + val |= ~0u << op.extract_size; + } + + return val; + } + case Operand::ShiftRegister::kExtendUnsigned: + return val & ((1u << (op.extract_size)) - 1u); + default: + return std::nullopt; + } +} + +std::optional EvalOperand(const Instruction &inst, const Operand &op) { + switch(op.type) { + case Operand::kTypeInvalid: + return std::nullopt; + case Operand::kTypeImmediate: + return op.imm.val; + case Operand::kTypeRegister: + return EvalReg(inst, op.reg); + case Operand::kTypeAddress: + { + auto seg_val = EvalReg(inst, op.addr.segment_base_reg); + auto base_val = EvalReg(inst, op.addr.base_reg); + auto index_val = EvalReg(inst, op.addr.index_reg); + + if (!seg_val || !base_val || !index_val) { + return std::nullopt; + } + + return static_cast( + static_cast(*seg_val) + static_cast(*base_val) + + (static_cast(*index_val) * op.addr.scale) + + op.addr.displacement); + + } + case Operand::kTypeShiftRegister: + if (op.shift_reg.shift_first) { + return EvalExtract(op.shift_reg, EvalShift(op.shift_reg, EvalReg(inst, op.shift_reg.reg))); + } else { + return EvalShift(op.shift_reg, EvalExtract(op.shift_reg, EvalReg(inst, op.shift_reg.reg))); + } + default: + return std::nullopt; + } +} + +// Handles appropriate branching semantics for: +// if d == 15 then +// if setflags then +// ALUExceptionReturn(result); +// else +// ALUWritePC(result); +static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, + InstEval *evaluator) { + if (rd == kPCRegNum) { + // Updates the flags (condition codes) + if (s) { + inst.category = Instruction::kCategoryError; + return false; + } else { + auto src1 = EvalOperand(inst, inst.operands[1]); + auto src2 = EvalOperand(inst, inst.operands[2]); + + if (!src1 || !src2) { + inst.category = Instruction::kCategoryIndirectJump; + } else { + auto res = evaluator(*src1, *src2); + if (!res) { + inst.category = Instruction::kCategoryIndirectJump; + } else if (!inst.conditions.empty()) { + inst.branch_taken_pc = static_cast(*res); + inst.branch_not_taken_pc = inst.next_pc; + inst.category = Instruction::kCategoryConditionalBranch; + } else { + inst.branch_taken_pc = static_cast(*res); + inst.category = Instruction::kCategoryDirectJump; + } + } + } + } else { + inst.category = Instruction::kCategoryNormal; + } + return true; +} + +// High 3 bit opc +static InstEval * kIdpEvaluators[] = { + [0b000] = +[](uint32_t src1, uint32_t src2) { + return std::optional(src1 & src2); + }, + [0b001] = +[](uint32_t src1, uint32_t src2) { + return std::optional(src1 ^ src2); + }, + [0b010] = +[](uint32_t src1, uint32_t src2) { + return std::optional(src1 - src2); + }, + [0b011] = +[](uint32_t src1, uint32_t src2) { + return std::optional(src2 - src1); + }, + [0b100] = +[](uint32_t src1, uint32_t src2) { + return std::optional(src2 + src1); + }, + [0b101] = +[](uint32_t src1, uint32_t src2) { + return std::optional(std::nullopt); + }, + [0b110] = +[](uint32_t src1, uint32_t src2) { + return std::optional(std::nullopt); + }, + [0b111] = +[](uint32_t src1, uint32_t src2) { + return std::optional(std::nullopt); + }, +}; + +// High 3 bit opc and low bit s, opc:s +static const char * const kIdpNamesRRR[] = { + [0b0000] = "ANDrr", + [0b0001] = "ANDSrr", + [0b0010] = "EORrr", + [0b0011] = "EORSrr", + [0b0100] = "SUBrr", + [0b0101] = "SUBSrr", + [0b0110] = "RSBrr", + [0b0111] = "RSBSrr", + [0b1000] = "ADDrr", + [0b1001] = "ADDSrr", + [0b1010] = "ADCrr", + [0b1011] = "ADCSrr", + [0b1100] = "SBCrr", + [0b1101] = "SBCSrr", + [0b1110] = "RSCrr", + [0b1111] = "RSCSrr" +}; + +//000 AND, ANDS (register) +//001 EOR, EORS (register) +//010 0 != 1101 SUB, SUBS (register) — SUB +//010 0 1101 SUB, SUBS (SP minus register) — SUB +//010 1 != 1101 SUB, SUBS (register) — SUBS +//010 1 1101 SUB, SUBS (SP minus register) — SUBS +//011 RSB, RSBS (register) +//100 0 != 1101 ADD, ADDS (register) — ADD +//100 0 1101 ADD, ADDS (SP plus register) — ADD +//100 1 != 1101 ADD, ADDS (register) — ADDS +//100 1 1101 ADD, ADDS (SP plus register) — ADDS +//101 ADC, ADCS (register) +//110 SBC, SBCS (register) +//111 RSC, RSCS (register) +static bool TryDecodeIntegerDataProcessingRRRI(Instruction &inst, uint32_t bits) { + const IntDataProcessingRRRI enc = {bits}; + + inst.function = kIdpNamesRRR[ (enc.opc << 1u) | enc.s]; + DecodeCondition(inst, enc.cond); + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); + + if (enc.s) { + AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); + } + + return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc]); +} + +// TODO(Sonya): Integer Data Processing (three register, register shift) +//static bool TryDecodeIntegerDataProcessingRRRR(Instruction &inst, uint32_t bits) { +// return false; +// const IntDataProcessingRRRR enc = { bits }; +// +// inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s]; +// DecodeCondition(inst, enc.cond); +// +// if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum +// || enc.rm == kPCRegNum) { +// inst.category = Instruction::kCategoryError; +// return false; +// } +//} + +//000 AND, ANDS (immediate) +//001 EOR, EORS (immediate) +//010 0 != 11x1 SUB, SUBS (immediate) — SUB +//010 0 1101 SUB, SUBS (SP minus immediate) — SUB +//010 0 1111 ADR — A2 (alias of subtract) +//010 1 != 1101 SUB, SUBS (immediate) — SUBS +//010 1 1101 SUB, SUBS (SP minus immediate) — SUBS +//011 RSB, RSBS (immediate) +//100 0 != 11x1 ADD, ADDS (immediate) — ADD +//100 0 1101 ADD, ADDS (SP plus immediate) — ADD +//100 0 1111 ADR — A1 (alias of add) +//100 1 != 1101 ADD, ADDS (immediate) — ADDS +//100 1 1101 ADD, ADDS (SP plus immediate) — ADDS +//101 ADC, ADCS (immediate) +//110 SBC, SBCS (immediate) +//111 RSC, RSCS (immediate) +static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) { + const IntDataProcessingRRI enc = { bits }; + + inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s]; + DecodeCondition(inst, enc.cond); + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + + // Raise the program counter to align to a multiple of 4 bytes + if (enc.rn == kPCRegNum && (enc.opc == 0b100u || enc.opc == 0b010u)) { + int64_t diff = static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); + AddAddrRegOp(inst, "PC", 32, Operand::kActionRead, diff); + } else { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + } + + ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s); + + return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc]); +} + +static const char * const kMulAccRRR[] = { + [0b0000] = "MULrr", + [0b0001] = "MULSrr", + [0b0010] = "MLArr", + [0b0011] = "MLASrr", + [0b0100] = "UMAALrr", + [0b0101] = nullptr, + [0b0110] = "MLSrr", + [0b0111] = nullptr, + [0b1000] = "UMULLrr", + [0b1001] = "UMULLSrr", + [0b1010] = "UMLALrr", + [0b1011] = "UMLALSrr", + [0b1100] = "SMULLrr", + [0b1101] = "SMULLSrr", + [0b1110] = "SMLALrr", + [0b1111] = "SMLALSrr" +}; + +//000 MUL, MULS +//001 MLA, MLAS +//010 0 UMAAL - writes to RdHi + RdLo, read RdHi +//010 1 UNALLOCATED +//011 0 MLS +//011 1 UNALLOCATED +//100 UMULL, UMULLS - writes to RdHi + RdLo +//101 UMLAL, UMLALS - writes to RdHi + RdLo, read RdHi +//110 SMULL, SMULLS - writes to RdHi + RdLo +//111 SMLAL, SMLALS - writes to RdHi + RdLo, read RdHi +static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { + const MultiplyAndAccumulate enc = { bits }; + // MUL, MULS only: if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; + // All other instructions: if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; + if (enc.rdhi == kPCRegNum || (enc.rdlo == kPCRegNum && !enc.opc) + || enc.rn == kPCRegNum || enc.rm == kPCRegNum) { + inst.category = Instruction::kCategoryError; + return false; + } + + auto instruction = kMulAccRRR[(enc.opc << 1u) | enc.s]; + if (!instruction) { + return false; + } + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.rdhi, 32, Operand::kActionWrite); + + // 2nd write reg only needed for instructions with an opc that begins with 1 and UMALL + if (((enc.opc >> 2) & 0b1u) || enc.opc == 0b010u) { + // if dHi == dLo then UNPREDICTABLE; + if (enc.rdlo == enc.rdhi){ + inst.category = Instruction::kCategoryError; + return false; + } + AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionWrite); + } + + // If opc is UMAAL, UMLAL, SMLAL read RdHi, add 0 immediate for UMULL, SMULL + if (enc.opc == 0b111u || enc.opc == 0b101u || enc.opc == 0b010u) { + AddIntRegOp(inst, enc.rdhi, 32, Operand::kActionRead); + } else if ((enc.opc >> 2) & 0b1u) { + AddImmOp(inst, 0); + } + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); + + // If instruction is not MUL, UMULL, SMULL add read to RdLo otherwise add an immediate + if (enc.opc != 0b000u && enc.opc != 0b100u && enc.opc != 0b110u) { + AddIntRegOp(inst, enc.rdlo, 32, Operand::kActionRead); + } else { + AddImmOp(inst, 0); + } + + inst.category = Instruction::kCategoryNormal; + + return true; +} + +static const char * const kLoadSWUBIL[] = { + [0b0000] = "STRp", + [0b0001] = "LDRp", + [0b0010] = "STRBp", + [0b0011] = "LDRBp", + [0b0100] = "STRT", + [0b0101] = "LDRT", + [0b0110] = "STRBT", + [0b0111] = "LDRBT", + [0b1000] = "STR", + [0b1001] = "LDR", + [0b1010] = "STRB", + [0b1011] = "LDRB", + [0b1100] = "STRp", + [0b1101] = "LDRp", + [0b1110] = "STRBp", + [0b1111] = "LDRBp", +}; + + +// P:W o2 o1 Rn +//!= 01 0 1 1111 LDR (literal) +//!= 01 1 1 1111 LDRB (literal) +// 00 0 0 STR (immediate) — post-indexed +// 00 0 1 != 1111 LDR (immediate) — post-indexed +// 00 1 0 STRB (immediate) — post-indexed +// 00 1 1 != 1111 LDRB (immediate) — post-indexed +// 01 0 0 STRT +// 01 0 1 LDRT +// 01 1 0 STRBT +// 01 1 1 LDRBT +// 10 0 0 STR (immediate) — offset +// 10 0 1 != 1111 LDR (immediate) — offset +// 10 1 0 STRB (immediate) — offset +// 10 1 1 != 1111 LDRB (immediate) — offset +// 11 0 0 STR (immediate) — pre-indexed +// 11 0 1 != 1111 LDR (immediate) — pre-indexed +// 11 1 0 STRB (immediate) — pre-indexed +// 11 1 1 != 1111 LDRB (immediate) — pre-indexed +template +static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { + const LoadStoreWUBIL enc = { bits }; + + bool write_back = (!enc.P || enc.W); + if (write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt)) { + inst.category = Instruction::kCategoryError; + return false; + } + + auto instruction = kLoadSWUBIL[enc.P << 3u | enc.W << 2u | enc.o2 << 1u | enc.o1]; + + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes + int64_t pc_adjust = 0; + if (kAlignPC && enc.rn == kPCRegNum) { + pc_adjust = static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); + } + auto disp = static_cast(enc.imm12); + + // Subtract + if (!enc.u) { + disp = -disp; + } + + // Not Indexing + if (!enc.P) { + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); + } else { + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, disp + pc_adjust); + } + + AddIntRegOp(inst, enc.rt, 32, kRegAction); + + // Pre or Post Indexing + if (write_back) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); + AddAddrRegOp(inst, kIntRegName[enc.rn], 32, Operand::kActionRead, disp + pc_adjust); + } + + inst.category = Instruction::kCategoryNormal; + return true; +} + +// Can package semantics for MOV with ORR and MVN with BIC since src1 will be +// 0 and 1 for MOV and MVN respectively, mirroring the semantics in LOGICAL.cpp +static InstEval * kLogArithEvaluators[] = { + [0b0] = +[](uint32_t src1, uint32_t src2) { + return std::optional(src1 | src2); + }, + [0b1] = +[](uint32_t src1, uint32_t src2) { + return std::optional(src1 & ~src2); + }, +}; + +//00 ORR, ORRS (register) -- rd, rn, & rm +//01 MOV, MOVS (register) -- rd, & rm only +//10 BIC, BICS (register) -- rd, rn, & rm +//11 MVN, MVNS (register) -- rd, & rm only +static const char * const kLogicalArithmeticRRRI[] = { + [0b000] = "ORRrr", + [0b001] = "ORRSrr", + [0b010] = "MOVrr", + [0b011] = "MOVSrr", + [0b100] = "BICrr", + [0b101] = "BICSrr", + [0b110] = "MVNrr", + [0b111] = "MVNSrr", +}; + +// Logical Arithmetic (three register, immediate shift) +static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { + const LogicalArithRRRI enc = { bits }; + + auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; + + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + + // enc.opc == x0 + if (!(enc.opc & 0b1u)) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + } + // enc.opc == 01 + else if (!(enc.opc & 0b10u)) { + AddImmOp(inst, 0); + } + // enc.opc == 11 + else { + AddImmOp(inst, 1); + } + + AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); + if (enc.s) { + AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); + } + + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); +} + +// TODO(Sonya): Logical Arithmetic (three register, register shift) +//static bool TryLogicalArithmeticRRRR(Instruction &inst, uint32_t bits) { +// return false; +// +// const LogicalArithRRRR enc = { bits }; +// +// auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; +// +// inst.function = instruction; +// DecodeCondition(inst, enc.cond); +// +// if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum +// || enc.rm == kPCRegNum) { +// inst.category = Instruction::kCategoryError; +// return false; +// } +// +// AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); +// // enc.opc == x0 +// if (!(enc.opc & 0b1u)) { +// AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); +// } +// // enc.opc == 01 +// else if (!(enc.opc & 0b10u)) { +// AddImmOp(inst, 0); +// } +// // enc.opc == 11 +// else { +// AddImmOp(inst, 1); +// } +//} + +// Logical Arithmetic (two register and immediate) +static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { + const LogicalArithmeticRRI enc = { bits }; + + auto instruction = kLogicalArithmeticRRRI[enc.opc | enc.s]; + + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + // enc.opc == x0 + if (!(enc.opc & 0b1u)) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + } + // enc.opc == 01 + else if (!(enc.opc & 0b10u)) { + AddImmOp(inst, 0); + } + // enc.opc == 11 + else { + AddImmOp(inst, 1); + } + + ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s); + + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); +} + +//00 TST (register) +//01 TEQ (register) +//10 CMP (register) +//11 CMN (register) +static const char * const kIntegerTestAndCompareR[] = { + [0b00] = "TSTr", + [0b01] = "TEQr", + [0b10] = "CMPr", + [0b11] = "CMNr", +}; + +// Integer Test and Compare (two register, immediate shift) +static bool TryIntegerTestAndCompareRRI(Instruction &inst, uint32_t bits) { + const IntTestCompRRI enc = { bits }; + + auto instruction = kIntegerTestAndCompareR[enc.opc]; + + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); + AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); + + inst.category = Instruction::kCategoryNormal; + return true; +} + +// TODO(Sonya): Integer Test and Compare (two register, register shift) +//static bool TryIntegerTestAndCompareRRR(Instruction &inst, uint32_t bits) { +// return false; +// +// const IntTestCompRRR enc = { bits }; +// +// auto instruction = kIntegerTestAndCompareR[enc.opc]; +// +// inst.function = instruction; +// DecodeCondition(inst, enc.cond); +// +// if (enc.rn == kPCRegNum || enc.rs == kPCRegNum || enc.rm == kPCRegNum) { +// inst.category = Instruction::kCategoryError; +// return false; +// } +//} +// +//// Integer Test and Compare (one register and immediate) +//static bool TryIntegerTestAndCompareRI(Instruction &inst, uint32_t bits) { +// const IntTestCompRI enc = { bits }; +// +// auto instruction = kIntegerTestAndCompareR[enc.opc]; +// +// inst.function = instruction; +// DecodeCondition(inst, enc.cond); +// +// AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); +// ExpandTo32AddImmAddCarry(inst, enc.imm12, 1u); +// +// inst.category = Instruction::kCategoryNormal; +// return true; +// +//} + +// Corresponds to Data-processing register (immediate shift) +// op0<24 to 23> | op1 <20> +static TryDecode * kDataProcessingRI[] = { + [0b000] = TryDecodeIntegerDataProcessingRRRI, + [0b001] = TryDecodeIntegerDataProcessingRRRI, + [0b010] = TryDecodeIntegerDataProcessingRRRI, + [0b011] = TryDecodeIntegerDataProcessingRRRI, + [0b100] = nullptr, // op0:op1 != 100 + [0b101] = TryIntegerTestAndCompareRRI, + [0b110] = TryLogicalArithmeticRRRI, + [0b111] = TryLogicalArithmeticRRRI, +}; + +// Corresponds to Data-processing register (immediate shift) +// op0<24 to 23> | op1 <20> +static TryDecode * kDataProcessingRR[] = { + [0b000] = nullptr, //TryDecodeIntegerDataProcessingRRRR, + [0b001] = nullptr, //TryDecodeIntegerDataProcessingRRRR, + [0b010] = nullptr, //TryDecodeIntegerDataProcessingRRRR, + [0b011] = nullptr, //TryDecodeIntegerDataProcessingRRRR, + [0b100] = nullptr, // op0:op1 != 100 + [0b101] = nullptr, //TryIntegerTestAndCompareRRR, + [0b110] = nullptr, //TryLogicalArithmeticRRRR, + [0b111] = nullptr, //TryLogicalArithmeticRRRR, +}; + +// Corresponds to Data-processing immediate +// op0<24 to 23> | op1 <21 to 20> +static TryDecode * kDataProcessingI[] = { + [0b0000] = TryDecodeIntegerDataProcessingRRI, + [0b0001] = TryDecodeIntegerDataProcessingRRI, + [0b0010] = TryDecodeIntegerDataProcessingRRI, + [0b0011] = TryDecodeIntegerDataProcessingRRI, + [0b0100] = TryDecodeIntegerDataProcessingRRI, + [0b0101] = TryDecodeIntegerDataProcessingRRI, + [0b0110] = TryDecodeIntegerDataProcessingRRI, + [0b0111] = TryDecodeIntegerDataProcessingRRI, + [0b1000] = nullptr, // TODO(Sonya): Move Halfword (immediate) + [0b1001] = nullptr, //TryIntegerTestAndCompareRI, + [0b1010] = nullptr, // TODO(Sonya): Move Special Register and Hints (immediate) + [0b1011] = nullptr, // TryIntegerTestAndCompareRI, + [0b1100] = TryLogicalArithmeticRRI, + [0b1101] = TryLogicalArithmeticRRI, + [0b1110] = TryLogicalArithmeticRRI, + [0b1111] = TryLogicalArithmeticRRI, +}; + +// Corresponds to: Load/Store Word, Unsigned Byte (immediate, literal) +// o2<22> | o1<21> +static TryDecode * kLoadStoreWordUBIL[] = { + [0b00] = TryDecodeLoadStoreWordUBIL, + [0b01] = TryDecodeLoadStoreWordUBIL, + [0b10] = TryDecodeLoadStoreWordUBIL, + [0b11] = TryDecodeLoadStoreWordUBIL, +}; + +// Corresponds to: Data-processing and miscellaneous instructions +//op0 op1 op2 op3 op4 +// 0 1 != 00 1 Extra load/store +// 0 0xxxx 1 00 1 Multiply and Accumulate +// 0 1xxxx 1 00 1 Synchronization primitives and Load-Acquire/Store-Release +// 0 10xx0 0 Miscellaneous +// 0 10xx0 1 0 Halfword Multiply and Accumulate +// 0 != 10xx0 0 Data-processing register (immediate shift) +// 0 != 10xx0 0 1 Data-processing register (register shift) +// 1 Data-processing immediate +static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { + const DataProcessingAndMisc enc = { bits }; + // op0 == 0 + if (!enc.op0) { + // op2 == 1, op4 == 1 + if (enc.op2 && enc.op4) { + // TODO(Sonya): Extra load/store -- op3 != 00 + if (!enc.op3) { + return nullptr; + } + // op3 == 00 + else { + // Multiply and Accumulate -- op1 == 0xxxx + if (!(enc.op1 >> 4)) { + return TryDecodeMultiplyAndAccumulate; + } + // TODO(Sonya): Synchronization primitives and Load-Acquire/Store-Release -- op1 == 1xxxx + else { + return nullptr; + } + } + } + // op1 == 10xx0 + else if (((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) { + // TODO(Sonya): Miscellaneous + if (!enc.op2) { + return nullptr; + } + // TODO(Sonya): Halfword Multiply and Accumulate + else { + return nullptr; + } + } + // op1 != 10xx0 + else { + // Data-processing register (immediate shift) -- op4 == 0 + if (!enc.op4) { + // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 lowest bit + // index is the concatenation of op0 and op1 + return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; + } + // Data-processing register (register shift) -- op4 == 1 + else { + return kDataProcessingRR[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; + } + } + } + // Data-processing immediate -- op0 == 1 + else { + // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 2 lowest bits + // index is the concatenation of op0 and op1 + return kDataProcessingI[(enc.op1 >> 1) | (enc.op1 & 0b11u)]; + } +} + +// This is the top level of the instruction encoding schema for AArch32. +// Instructions are grouped into subsets based on this the top level and then +// into smaller sets. +// cond op0 op1 +//!= 1111 00x Data-processing and miscellaneous instructions +//!= 1111 010 Load/Store Word, Unsigned Byte (immediate, literal) +//!= 1111 011 0 Load/Store Word, Unsigned Byte (register) +//!= 1111 011 1 Media instructions +// 10x Branch, branch with link, and block data transfer +// 11x System register access, Advanced SIMD, floating-point, and Supervisor call +// 1111 0xx Unconditional instructions +static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { + const TopLevelEncodings enc = { bits }; + // op0 == 0xx + if (!(enc.op0 >> 2)) { + if (enc.cond != 0b1111u) { + // Data-processing and miscellaneous instructions -- op0 == 00x + if (!(enc.op0 >> 1)) { + return TryDataProcessingAndMisc(bits); + } + // Load/Store Word, Unsigned Byte (immediate, literal) -- op0 == 010 + else if (enc.op0 == 0b010u) { + const LoadStoreWUBIL enc_ls_word = { bits }; + return kLoadStoreWordUBIL[enc_ls_word.o2 << 1u | enc_ls_word.o1]; + } + // TODO(Sonya): Load/Store Word, Unsigned Byte (register) -- op0 == 011, op1 == 0 + else if (!enc.op1) { + // This should be returning another table index using a struct like above + return nullptr; + } + // TODO(Sonya): Media instructions -- op0 == 011, op1 == 1 + else { + // return a result from another function for instruction categorizing + return nullptr; + } + } + // TODO(Sonya): Unconditional instructions -- cond == 1111 + else { + // return a result from another function for instruction categorizing + return nullptr; + } + } + // op0 == 1xx + else { + // TODO(Sonya): Branch, branch with link, and block data transfer -- op0 == 10x + if (enc.op0 >> 1 == 0b10u) { + // return a result from another function for instruction categorizing + return nullptr; + } + // TODO(Sonya): System register access, Advanced SIMD, floating-point, and Supervisor call -- op0 == 11x + else { + // return a result from another function for instruction categorizing + return nullptr; + } + } +} + +static uint32_t BytesToBits(const uint8_t *bytes) { + uint32_t bits = 0; + bits = (bits << 8) | static_cast(bytes[3]); + bits = (bits << 8) | static_cast(bytes[2]); + bits = (bits << 8) | static_cast(bytes[1]); + bits = (bits << 8) | static_cast(bytes[0]); + return bits; +} +} // namespace + +// Decode an instuction. +bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes, + Instruction &inst) const { + + inst.pc = address; + inst.next_pc = address + inst_bytes.size(); // Default fall-through. + inst.branch_taken_pc = 0; + inst.branch_not_taken_pc = 0; + inst.has_branch_taken_delay_slot = false; + inst.has_branch_not_taken_delay_slot = false; + inst.arch_name = arch_name; + inst.arch_for_decode = this; + inst.category = Instruction::kCategoryInvalid; + inst.operands.clear(); + if (!inst.bytes.empty() && inst.bytes.data() == inst_bytes.data()) { + inst.bytes.resize(inst_bytes.size()); + } else { + inst.bytes = inst_bytes; + } + + if (address & 0b1u) { + return false; + } + + const auto bytes = reinterpret_cast(inst.bytes.data()); + const auto bits = BytesToBits(bytes); + + auto decoder = TryDecodeTopLevelEncodings(bits); + if (!decoder) { + LOG(ERROR) << "unhandled bits"; + return false; + } + + auto ret = decoder(inst, bits); + LOG(ERROR) << inst.Serialize(); + return ret; +} + +} // namespace remill diff --git a/lib/Arch/AArch32/Runtime/BasicBlock.cpp b/lib/Arch/AArch32/Runtime/BasicBlock.cpp new file mode 100644 index 000000000..159d79bd7 --- /dev/null +++ b/lib/Arch/AArch32/Runtime/BasicBlock.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "remill/Arch/AArch32/Runtime/State.h" +#include "remill/Arch/Runtime/Float.h" + +extern "C" { + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-variable" + +// Instructions will be lifted into clones of this function. +[[gnu::used]] Memory *__remill_basic_block(State &, addr_t, Memory *); + +#pragma clang diagnostic pop + +} // extern C diff --git a/lib/Arch/AArch32/Runtime/CMakeLists.txt b/lib/Arch/AArch32/Runtime/CMakeLists.txt new file mode 100644 index 000000000..d1201dd79 --- /dev/null +++ b/lib/Arch/AArch32/Runtime/CMakeLists.txt @@ -0,0 +1,63 @@ +# Copyright (c) 2017 Trail of Bits, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.2) +project(arm_runtime) + +set(ARMRUNTIME_SOURCEFILES + Instructions.cpp + BasicBlock.cpp + + "${REMILL_LIB_DIR}/Arch/Runtime/Intrinsics.cpp" +) + +set_source_files_properties(Instructions.cpp PROPERTIES COMPILE_FLAGS "-O3 -g0") +set_source_files_properties(BasicBlock.cpp PROPERTIES COMPILE_FLAGS "-O0 -g3") + +function(add_runtime_helper target_name little_endian) + message(" > Generating runtime target: ${target_name}") + + # Visual C++ requires C++14 + if(WIN32) + set(required_cpp_standard "c++14") + else() + set(required_cpp_standard "c++17") + endif() + + # necessary to build code as 32-bit + # on aarch64 + if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*|arm64.*|ARM64.*)") + set(arch_flags "--target=arm-linux-gnueabihf") + else() + set(arch_flags "-m32") + endif() + + add_runtime(${target_name} + SOURCES ${ARMRUNTIME_SOURCEFILES} + ADDRESS_SIZE 32 + DEFINITIONS "LITTLE_ENDIAN=${little_endian}" + BCFLAGS "${arch_flags}" "-std=${required_cpp_standard}" + INCLUDEDIRECTORIES "${REMILL_INCLUDE_DIR}" "${REMILL_SOURCE_DIR}" + INSTALLDESTINATION "${REMILL_INSTALL_SEMANTICS_DIR}" + + DEPENDENCIES + "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/BINARY.cpp" + "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/FLAGS.cpp" + "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/COND.cpp" + "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/LOGICAL.cpp" + "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/MEM.cpp" + ) +endfunction() + +add_runtime_helper(aarch32 1) diff --git a/lib/Arch/AArch32/Runtime/Instructions.cpp b/lib/Arch/AArch32/Runtime/Instructions.cpp new file mode 100644 index 000000000..468ef64dd --- /dev/null +++ b/lib/Arch/AArch32/Runtime/Instructions.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +// clang-format off +#include "remill/Arch/Runtime/Float.h" +#include "remill/Arch/Runtime/Intrinsics.h" +#include "remill/Arch/Runtime/Operators.h" +#include "remill/Arch/AArch32/Runtime/State.h" +#include "remill/Arch/AArch32/Runtime/Types.h" +#include "remill/Arch/AArch32/Runtime/Operators.h" + +// clang-format on + +#define REG_PC state.gpr.r15.dword +#define REG_SP state.gpr.r13.dword + +#define HYPER_CALL state.hyper_call +#define INTERRUPT_VECTOR state.hyper_call_vector +#define HYPER_CALL_VECTOR state.hyper_call_vector + +namespace { + +// Takes the place of an unsupported instruction. +DEF_SEM(HandleUnsupported) { + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kAArch32EmulateInstruction); +} + +// Takes the place of an invalid instruction. +DEF_SEM(HandleInvalidInstruction) { + HYPER_CALL = AsyncHyperCall::kInvalidInstruction; + return memory; +} + +} // namespace + +// Takes the place of an unsupported instruction. +DEF_ISEL(UNSUPPORTED_INSTRUCTION) = HandleUnsupported; +DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; + +// clang-format off +#include "lib/Arch/AArch32/Semantics/FLAGS.cpp" +#include "lib/Arch/AArch32/Semantics/BINARY.cpp" +#include "lib/Arch/AArch32/Semantics/MEM.cpp" +#include "lib/Arch/AArch32/Semantics/LOGICAL.cpp" +//#include "lib/Arch/AArch64/Semantics/BITBYTE.cpp" +//#include "lib/Arch/AArch64/Semantics/BRANCH.cpp" +//#include "lib/Arch/AArch64/Semantics/CALL_RET.cpp" +#include "lib/Arch/AArch32/Semantics/COND.cpp" +//#include "lib/Arch/AArch64/Semantics/CONVERT.cpp" +//#include "lib/Arch/AArch64/Semantics/DATAXFER.cpp" +//#include "lib/Arch/AArch64/Semantics/MISC.cpp" +//#include "lib/Arch/AArch64/Semantics/SHIFT.cpp" +//#include "lib/Arch/AArch64/Semantics/SIMD.cpp" +//#include "lib/Arch/AArch64/Semantics/SYSTEM.cpp" + +// clang-format on diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp new file mode 100644 index 000000000..9f7e6383e --- /dev/null +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { + +template +T AddWithCarryNZCV(State &state, T lhs, T rhs, T carry) { + auto unsigned_result = UAdd(UAdd(ZExt(lhs), ZExt(rhs)), ZExt(carry)); + auto signed_result = SAdd(SAdd(SExt(lhs), SExt(rhs)), Signed(ZExt(carry))); + auto result = TruncTo(unsigned_result); + state.sr.n = SignFlag(result); + state.sr.z = ZeroFlag(result); + state.sr.c = UCmpNeq(ZExt(result), unsigned_result); + state.sr.v = SCmpNeq(SExt(result), signed_result); + return result; +} + +DEF_SEM(AND, R32W dst, R32 src1, I32 src2) { + auto value = Read(src2); + Write(dst, UAnd(Read(src1), value)); + return memory; +} + +DEF_SEM(ANDS, R32W dst, R32 src1, I32 src2, I8 carry_out) { + auto value = Read(src2); + auto res = UAnd(Read(src1), value); + WriteZExt(dst, res); + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(EOR, R32W dst, R32 src1, I32 src2) { + auto value = Read(src2); + Write(dst, UXor(Read(src1), value)); + return memory; +} + +DEF_SEM(EORS, R32W dst, R32 src1, I32 src2, I8 carry_out) { + auto value = Read(src2); + auto res = UXor(Read(src1), value); + Write(dst, res); + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(RSB, R32W dst, R32 src1, I32 src2) { + auto value = Read(src2); + Write(dst, USub(value, Read(src1))); + return memory; +} + +DEF_SEM(RSBS, R32W dst, R32 src1, I32 src2, I8 carry_out) { + auto rhs = Read(src2); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, UNot(lhs), rhs, uint32_t(1)); + Write(dst, res); + return memory; +} + +DEF_SEM(SUB, R32W dst, R32 src1, I32 src2) { + auto value = Read(src2); + Write(dst, USub(Read(src1), value)); + return memory; +} + +DEF_SEM(SUBS, R32W dst, R32 src1, I32 src2, I8 carry_out) { + auto rhs = Read(src2); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, lhs, UNot(rhs), uint32_t(1)); + Write(dst, res); + return memory; +} + +DEF_SEM(ADD, R32W dst, R32 src1, I32 src2) { + auto value = Read(src2); + Write(dst, UAdd(Read(src1), value)); + return memory; +} + +DEF_SEM(ADDS, R32W dst, R32 src1, I32 src2, I8 carry_out) { + auto rhs = Read(src2); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, lhs, rhs, uint32_t(0)); + Write(dst, res); + return memory; +} + +DEF_SEM(ADC, R32W dst, R32 src1, I32 src2) { + auto value = Read(src2); + Write(dst, UAdd(UAdd(Read(src1),value), uint32_t(state.sr.c))); + return memory; +} + +DEF_SEM(ADCS, R32W dst, R32 src1, I32 src2, I8 carry_out) { + auto rhs = Read(src2); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, lhs, rhs, uint32_t(state.sr.c)); + Write(dst, res); + return memory; +} + +DEF_SEM(SBC, R32W dst, R32 src1, I32 src2) { + auto value = Read(src2); + Write(dst, UAdd(UAdd(Read(src1), UNot(value)), uint32_t(state.sr.c))); + return memory; +} + +DEF_SEM(SBCS, R32W dst, R32 src1, I32 src2, I8 carry_out) { + auto rhs = Read(src2); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, lhs, UNot(rhs), uint32_t(state.sr.c)); + Write(dst, res); + return memory; +} + +DEF_SEM(RSC, R32W dst, R32 src1, I32 src2) { + auto value = Read(src2); + Write(dst, UAdd(UAdd(value, UNot(Read(src1))), uint32_t(state.sr.c))); + return memory; +} + +DEF_SEM(RSCS, R32W dst, R32 src1, I32 src2, I8 carry_out) { + auto rhs = Read(src2); + auto lhs = Read(src1); + auto res = AddWithCarryNZCV(state, UNot(lhs), rhs, uint32_t(state.sr.c)); + Write(dst, res); + return memory; +} + +} // namespace + +DEF_ISEL(ANDrr) = AND; +DEF_ISEL(ANDSrr) = ANDS; +DEF_ISEL(EORrr) = EOR; +DEF_ISEL(EORSrr) = EORS; +DEF_ISEL(ADDrr) = ADD; +DEF_ISEL(ADDSrr) = ADDS; +DEF_ISEL(ADCrr) = ADC; +DEF_ISEL(ADCSrr) = ADCS; +DEF_ISEL(RSBrr) = RSB; +DEF_ISEL(RSBSrr) = RSBS; +DEF_ISEL(SUBrr) = SUB; +DEF_ISEL(SUBSrr) = SUBS; +DEF_ISEL(SBCrr) = SBC; +DEF_ISEL(SBCSrr) = SBCS; +DEF_ISEL(RSCrr) = RSC; +DEF_ISEL(RSCSrr) = RSCS; + +namespace { +DEF_SEM(MUL, R32W dst, R32 src1, R32 src2, R32 src3) { + auto rhs = Signed(Read(src2)); + auto lhs = Signed(Read(src1)); + auto acc = Signed(Read(src3)); + auto res = Unsigned(SAdd(SMul(lhs, rhs), acc)); + Write(dst, res); + return memory; +} + +DEF_SEM(MULS, R32W dst, R32 src1, R32 src2, R32 src3) { + auto rhs = Signed(Read(src2)); + auto lhs = Signed(Read(src1)); + auto acc = Signed(Read(src3)); + auto res = Unsigned(SAdd(SMul(lhs, rhs), acc)); + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + // PSTATE.C, PSTATE.V unchanged + Write(dst, res); + return memory; +} + +DEF_SEM(UMAAL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + auto rhs = ZExt(Read(src3)); + auto lhs = ZExt(Read(src2)); + auto acc_hi = ZExt(Read(src1)); + auto acc_lo = ZExt(Read(src4)); + auto res = UAdd(UAdd(UMul(lhs, rhs), acc_hi), acc_lo); + Write(dst_lo, TruncTo(res)); + Write(dst_hi, TruncTo(UShr(res, 32ul))); + return memory; +} + +DEF_SEM(MLS, R32W dst, R32 src1, R32 src2, R32 src3) { + auto rhs = Signed(Read(src2)); + auto lhs = Signed(Read(src1)); + auto acc = Signed(Read(src3)); + auto res = Unsigned(SSub(acc, SMul(lhs, rhs))); + Write(dst, res); + return memory; +} + +DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + auto rhs = ZExt(Read(src3)); + auto lhs = ZExt(Read(src2)); + auto acc = UOr(UShl(ZExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto res = UAdd(UMul(lhs, rhs), acc); + Write(dst_hi, TruncTo(UShr(res, 32ul))); + Write(dst_lo, TruncTo(res)); + return memory; +} + +DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + auto rhs = ZExt(Read(src3)); + auto lhs = ZExt(Read(src2)); + auto acc = UOr(UShl(ZExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto res = UAdd(UMul(lhs, rhs), acc); + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + // PSTATE.C, PSTATE.V unchanged + Write(dst_hi, TruncTo(UShr(res, 32ul))); + Write(dst_lo, TruncTo(res)); + return memory; +} + +DEF_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + // Not entirely sure about all the signed ops I have in here + auto rhs = SExt(Signed(Read(src3))); + auto lhs = SExt(Signed(Read(src2))); + auto acc = SOr(SShl(SExt(Read(src1)), 32ul), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto res = SAdd(SMul(lhs, rhs), acc); + Write(dst_hi, TruncTo(SShr(res, 32ul))); + Write(dst_lo, TruncTo(res)); + return memory; +} + +DEF_SEM(SMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + auto rhs = SExt(Signed(Read(src3))); + auto lhs = SExt(Signed(Read(src2))); + auto acc = SOr(SShl(SExt(Read(src1)), 32ul), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto res = SAdd(SMul(lhs, rhs), acc); + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + // PSTATE.C, PSTATE.V unchanged + Write(dst_hi, TruncTo(SShr(res, 32ul))); + Write(dst_lo, TruncTo(res)); + return memory; +} +} // namespace + +DEF_ISEL(MULrr) = MUL; +DEF_ISEL(MULSrr) = MULS; +DEF_ISEL(MLArr) = MUL; +DEF_ISEL(MLASrr) = MULS; +DEF_ISEL(MLSrr) = MLS; +DEF_ISEL(UMAALrr) = UMAAL; +DEF_ISEL(UMULLrr) = UMULL; +DEF_ISEL(UMULLSrr) = UMULLS; +DEF_ISEL(UMLALrr) = UMULL; +DEF_ISEL(UMLALSrr) = UMULLS; +DEF_ISEL(SMULLrr) = SMULL; +DEF_ISEL(SMULLSrr) = SMULLS; +DEF_ISEL(SMLALrr) = SMULL; +DEF_ISEL(SMLALSrr) = SMULLS; + diff --git a/lib/Arch/AArch32/Semantics/COND.cpp b/lib/Arch/AArch32/Semantics/COND.cpp new file mode 100644 index 000000000..8bc4b3075 --- /dev/null +++ b/lib/Arch/AArch32/Semantics/COND.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { +DEF_SEM(TST, R32 src1, I32 src2, I8 carry_out) { + auto res = UAnd(Read(src1), Read(src2)); + + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(TEQ, R32 src1, I32 src2, I8 carry_out) { + auto res = UXor(Read(src1), Read(src2)); + + state.sr.n = SignFlag(res); + state.sr.z = ZeroFlag(res); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(CMP, R32 src1, I32 src2, I8 carry_out) { + auto rhs = Read(src2); + auto lhs = Read(src1); + AddWithCarryNZCV(state, lhs, UNot(rhs), uint32_t(1)); + return memory; +} + +DEF_SEM(CMN, R32 src1, I32 src2, I8 carry_out) { + auto rhs = Read(src2); + auto lhs = Read(src1); + AddWithCarryNZCV(state, lhs, rhs, uint32_t(0)); + return memory; +} +} // namespace + +DEF_ISEL(TST) = TST; +DEF_ISEL(TEQ) = TEQ; +DEF_ISEL(CMP) = CMP; +DEF_ISEL(CMN) = CMN; diff --git a/lib/Arch/AArch32/Semantics/FLAGS.cpp b/lib/Arch/AArch32/Semantics/FLAGS.cpp new file mode 100644 index 000000000..0432bf56f --- /dev/null +++ b/lib/Arch/AArch32/Semantics/FLAGS.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { + +// Used to select specializations of flags computations based on what operator +// is executed. +enum : uint32_t { kLHS = 2415899639U, kRHS = 70623199U }; + +// Zero flags, tells us whether or not a value is zero. +template +[[gnu::const]] ALWAYS_INLINE static bool ZeroFlag(T res) { + return T(0) == res; +} + +// Zero flags, tells us whether or not a value is zero. +template +[[gnu::const]] ALWAYS_INLINE static bool NotZeroFlag(T res) { + return T(0) != res; +} + +// Sign flag, tells us if a result is signed or unsigned. +template +[[gnu::const]] ALWAYS_INLINE static bool SignFlag(T res) { + return 0 > Signed(res); +} + +// Tests whether there is an even number of bits in the low order byte. +[[gnu::const]] ALWAYS_INLINE static bool ParityFlag(uint8_t r0) { + return !__builtin_parity(static_cast(r0)); + + // auto r1 = r0 >> 1_u8; + // auto r2 = r1 >> 1_u8; + // auto r3 = r2 >> 1_u8; + // auto r4 = r3 >> 1_u8; + // auto r5 = r4 >> 1_u8; + // auto r6 = r5 >> 1_u8; + // auto r7 = r6 >> 1_u8; + // + // return !(1 & (r0 ^ r1 ^ r2 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7)); +} + +struct tag_add {}; +struct tag_sub {}; +struct tag_div {}; +struct tag_mul {}; + +// Generic overflow flag. +template +struct Overflow; + +// Computes an overflow flag when two numbers are added together. +template <> +struct Overflow { + template + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { + static_assert(std::is_unsigned::value, + "Invalid specialization of `Overflow::Flag` for addition."); + enum { kSignShift = sizeof(T) * 8 - 1 }; + + const T sign_lhs = lhs >> kSignShift; + const T sign_rhs = rhs >> kSignShift; + const T sign_res = res >> kSignShift; + return 2 == (sign_lhs ^ sign_res) + (sign_rhs ^ sign_res); + } +}; + +// Computes an overflow flag when one number is subtracted from another. +template <> +struct Overflow { + template + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { + static_assert(std::is_unsigned::value, + "Invalid specialization of `Overflow::Flag` for " + "subtraction."); + enum { kSignShift = sizeof(T) * 8 - 1 }; + + const T sign_lhs = lhs >> kSignShift; + const T sign_rhs = rhs >> kSignShift; + const T sign_res = res >> kSignShift; + return 2 == (sign_lhs ^ sign_rhs) + (sign_lhs ^ sign_res); + } +}; + +// Computes an overflow flag when one number is multiplied with another. +template <> +struct Overflow { + + // Integer multiplication overflow check, where result is twice the width of + // the operands. + template + [[gnu::const]] ALWAYS_INLINE static bool + Flag(T, T, R res, + typename std::enable_if::type = 0) { + + return static_cast(static_cast(res)) != res; + } + + // Signed integer multiplication overflow check, where the result is + // truncated to the size of the operands. + template + [[gnu::const]] ALWAYS_INLINE static bool + Flag(T lhs, T rhs, T, + typename std::enable_if::value, int>::type = 0) { + auto lhs_wide = SExt(lhs); + auto rhs_wide = SExt(rhs); + return Flag(lhs, rhs, lhs_wide * rhs_wide); + } +}; + +// Generic carry flag. +template +struct Carry; + +// Computes an carry flag when two numbers are added together. +template <> +struct Carry { + template + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { + static_assert(std::is_unsigned::value, + "Invalid specialization of `Carry::Flag` for addition."); + return res < lhs || res < rhs; + } +}; + +// Computes an carry flag when one number is subtracted from another. +template <> +struct Carry { + template + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T) { + static_assert(std::is_unsigned::value, + "Invalid specialization of `Carry::Flag` for addition."); + return lhs < rhs; + } +}; + +ALWAYS_INLINE static void SetFPSRStatusFlags(State &state, int mask) { + // TODO(Sonya): Update these flags to work on AArch32 +// state.sr.ixc |= static_cast(0 != (mask & FE_INEXACT)); +// state.sr.ofc |= static_cast(0 != (mask & FE_OVERFLOW)); +// state.sr.ufc |= static_cast(0 != (mask & FE_UNDERFLOW)); +// state.sr.ioc |= static_cast(0 != (mask & FE_INVALID)); +} + +template +ALWAYS_INLINE static auto CheckedFloatUnaryOp(State &state, F func, T arg1) + -> decltype(func(arg1)) { + + //state.sr.idc |= IsDenormal(arg1); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + BarrierReorder(); + auto res = func(arg1); + BarrierReorder(); + auto new_except = __remill_fpu_exception_test_and_clear( + FE_ALL_EXCEPT, old_except /* zero */); + SetFPSRStatusFlags(state, new_except); + return res; +} + +template +ALWAYS_INLINE static auto CheckedFloatBinOp(State &state, F func, T arg1, + T arg2) + -> decltype(func(arg1, arg2)) { + + //state.sr.idc |= IsDenormal(arg1) | IsDenormal(arg2); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + BarrierReorder(); + auto res = func(arg1, arg2); + BarrierReorder(); + auto new_except = __remill_fpu_exception_test_and_clear( + FE_ALL_EXCEPT, old_except /* zero */); + SetFPSRStatusFlags(state, new_except); + return res; +} + +} // namespace diff --git a/lib/Arch/AArch32/Semantics/LOGICAL.cpp b/lib/Arch/AArch32/Semantics/LOGICAL.cpp new file mode 100644 index 000000000..7c7b2dcab --- /dev/null +++ b/lib/Arch/AArch32/Semantics/LOGICAL.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { +DEF_SEM(ORR, R32W dst, R32 src1, I32 src2){ + auto value = Read(src2); + auto result = UOr(Read(src1), value); + Write(dst, result); + return memory; +} + +DEF_SEM(ORRS, R32W dst, R32 src1, I32 src2, I8 carry_out) { + auto value = Read(src2); + auto result = UOr(Read(src1), value); + Write(dst, result); + + state.sr.n = SignFlag(result); + state.sr.z = ZeroFlag(result); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} + +DEF_SEM(BIC, R32W dst, R32 src1, I32 src2){ + auto value = UNot(Read(src2)); + auto result = UAnd(Read(src1), value); + Write(dst, result); + return memory; +} + +DEF_SEM(BICS, R32W dst, R32 src1, I32 src2, I8 carry_out) { + auto value = UNot(Read(src2)); + auto result = UAnd(Read(src1), value); + Write(dst, result); + + state.sr.n = SignFlag(result); + state.sr.z = ZeroFlag(result); + state.sr.c = Read(carry_out); + // PSTATE.V unchanged + return memory; +} +} // namespace + +DEF_ISEL(ORRrr) = ORR; +DEF_ISEL(ORRSrr) = ORRS; +DEF_ISEL(MOVrr) = ORR; +DEF_ISEL(MOVSrr) = ORRS; +DEF_ISEL(BICrr) = BIC; +DEF_ISEL(BICSrr) = BICS; +DEF_ISEL(MVNrr) = BIC; +DEF_ISEL(MVNSrr) = BICS; diff --git a/lib/Arch/AArch32/Semantics/MEM.cpp b/lib/Arch/AArch32/Semantics/MEM.cpp new file mode 100644 index 000000000..3c953c5f9 --- /dev/null +++ b/lib/Arch/AArch32/Semantics/MEM.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { +// Offset +template +DEF_SEM(STR, DstType dst, R32 src1) { + auto src = Read(src1); + Write(dst, TruncTo(src)); + return memory; +} + +// Pre + Post +template +DEF_SEM(STRp, DstType dst, R32 src1, R32W dst_reg, R32 src2) { + auto src = Read(src1); + auto new_val = Read(src2); + Write(dst, TruncTo(src)); + Write(dst_reg, new_val); + return memory; +} + +// Offset +template +DEF_SEM(LDR, SrcType src1, R32W dst) { + auto src = Read(src1); + WriteZExt(dst, src); + return memory; +} + +// Pre + Post +template +DEF_SEM(LDRp, SrcType src1, R32W dst, R32W dst_reg, R32 src2) { + auto src = Read(src1); + auto new_val = Read(src2); + WriteZExt(dst, src); + Write(dst_reg, new_val); + return memory; +} + +template +DEF_SEM(STRT, DstType dst, R32 src1, R32W dst_reg, R32 src2) { + memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + auto src = Read(src1); + auto new_val = Read(src2); + Write(dst, TruncTo(src)); + Write(dst_reg, new_val); + return memory; +} + +template +DEF_SEM(LDRT, SrcType src1, R32W dst, R32W dst_reg, R32 src2) { + memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + auto src = Read(src1); + auto new_val = Read(src2); + WriteZExt(dst, src); + Write(dst_reg, new_val); + return memory; +} + +} // namespace + +DEF_ISEL(STR) = STR; +DEF_ISEL(STRB) = STR; +DEF_ISEL(STRp) = STRp; +DEF_ISEL(STRBp) = STRp; +DEF_ISEL(LDR) = LDR; +DEF_ISEL(LDRB) = LDR; +DEF_ISEL(LDRp) = LDRp; +DEF_ISEL(LDRBp) = LDRp; +DEF_ISEL(STRT) = STRT; +DEF_ISEL(STRBT) = STRT; +DEF_ISEL(LDRT) = LDRT; +DEF_ISEL(LDRBT) = LDRT; From 91023a9c73c51efa435af6279db33b510ab538b1 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 10 Nov 2020 15:03:35 -0500 Subject: [PATCH 079/130] Updated .gitignore again, Added AddShiftRegRegOperand, Updated AddShiftRegImmOperand, Finished Register shift instructions for Integer Test and Compare, Logical Arithmetic, Integer Data Processing --- .gitignore | 2 - include/remill/Arch/Instruction.h | 2 +- lib/Arch/AArch32/Decode.cpp | 487 +++++++++++++++++------------- 3 files changed, 286 insertions(+), 205 deletions(-) diff --git a/.gitignore b/.gitignore index e331c6e90..247433bee 100644 --- a/.gitignore +++ b/.gitignore @@ -26,8 +26,6 @@ cmake-build-debug cmake-build-release compile_commands.json -bin/* - third_party/* build/* remill-build/* diff --git a/include/remill/Arch/Instruction.h b/include/remill/Arch/Instruction.h index 09f4a47ee..63dcb297d 100644 --- a/include/remill/Arch/Instruction.h +++ b/include/remill/Arch/Instruction.h @@ -317,7 +317,7 @@ class Instruction { Operand & EmplaceOperand(const Operand::Address &op); private: - static constexpr auto kMaxNumExpr = 32u; + static constexpr auto kMaxNumExpr = 64u; OperandExpression exprs[kMaxNumExpr]; unsigned next_expr_index{0}; }; diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 18eddae66..d469bd77d 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -23,23 +23,23 @@ namespace remill { namespace { //Integer Data Processing (three register, register shift) -//union IntDataProcessingRRRR { -// uint32_t flat; -// struct { -// uint32_t rm : 4; -// uint32_t _1 : 1; -// uint32_t type : 2; -// uint32_t _0 : 1; -// uint32_t rs : 4; -// uint32_t rd : 4; -// uint32_t rn : 4; -// uint32_t s : 1; -// uint32_t opc : 3; -// uint32_t _0000 : 4; -// uint32_t cond : 4; -// } __attribute__((packed)); -//} __attribute__((packed)); -//static_assert(sizeof(IntDataProcessingRRRR) == 4, " "); +union IntDataProcessingRRRR { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _1 : 1; + uint32_t type : 2; + uint32_t _0 : 1; + uint32_t rs : 4; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 3; + uint32_t _0000 : 4; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntDataProcessingRRRR) == 4, " "); //Integer Data Processing (three register, immediate shift) union IntDataProcessingRRRI { @@ -128,23 +128,23 @@ union IntTestCompRRI { static_assert(sizeof(IntTestCompRRI) == 4, " "); // Integer Test and Compare (two register, register shift) -//union IntTestCompRRR { -// uint32_t flat; -// struct { -// uint32_t rm : 4; -// uint32_t _1 : 1; -// uint32_t type : 2; -// uint32_t _0 : 1; -// uint32_t rs : 4; -// uint32_t _0000 : 4; -// uint32_t rn : 4; -// uint32_t _1a : 1; -// uint32_t opc : 2; -// uint32_t _00010 : 5; -// uint32_t cond : 4; -// } __attribute__((packed)); -//} __attribute__((packed)); -//static_assert(sizeof(IntTestCompRRR) == 4, " "); +union IntTestCompRRR { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _1_b4 : 1; + uint32_t type : 2; + uint32_t _0 : 1; + uint32_t rs : 4; + uint32_t _0000 : 4; + uint32_t rn : 4; + uint32_t _1_b20 : 1; + uint32_t opc : 2; + uint32_t _00010 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntTestCompRRR) == 4, " "); // Integer Test and Compare (one register and immediate) union IntTestCompRI { @@ -180,23 +180,23 @@ union LogicalArithRRRI { static_assert(sizeof(LogicalArithRRRI) == 4, " "); // Logical Arithmetic (three register, register shift) -//union LogicalArithRRRR { -// uint32_t flat; -// struct { -// uint32_t rm : 4; -// uint32_t _1 : 1; -// uint32_t type : 2; -// uint32_t _0 : 1; -// uint32_t rs : 4; -// uint32_t rd : 4; -// uint32_t rn : 4; -// uint32_t s : 1; -// uint32_t opc : 2; -// uint32_t _00011 : 5; -// uint32_t cond : 4; -// } __attribute__((packed)); -//} __attribute__((packed)); -//static_assert(sizeof(LogicalArithRRRR) == 4, " "); +union LogicalArithRRRR { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _1 : 1; + uint32_t type : 2; + uint32_t _0 : 1; + uint32_t rs : 4; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 2; + uint32_t _00011 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(LogicalArithRRRR) == 4, " "); union LogicalArithmeticRRI { uint32_t flat; @@ -278,13 +278,12 @@ static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, static void AddImmOp(Instruction &inst, uint64_t value, unsigned size = 32, Operand::Action action = Operand::kActionRead, bool is_signed = false) { - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.imm.val = value; - op.size = size; - op.imm.is_signed = is_signed; + Operand::Immediate imm; + imm.val = value; + imm.is_signed = is_signed; + auto &op = inst.EmplaceOperand(imm); op.action = action; - op.type = Operand::kTypeImmediate; + op.size = size; } static void AddAddrRegOp(Instruction &inst, const char *reg_name, @@ -374,9 +373,10 @@ static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { // Used to handle semantics for: // (imm32, carry) = A32ExpandImm_C(imm12, PSTATE.C); // See an instruction in Data-processing register (immediate shift) for example -static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, bool carry_out) { +static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, + bool carry_out) { uint32_t unrotated_value = imm12 & (0b11111111u); - uint32_t rotation_amount = ((imm12 >> 8) & (0b1111u)) *2u; + uint32_t rotation_amount = ((imm12 >> 8) & (0b1111u)) * 2u; if (!rotation_amount) { AddImmOp(inst, unrotated_value); @@ -396,54 +396,91 @@ static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, bool car } } -// Note: This function should be used with AddShiftCarryOperand to add carry_out operand! -// Used to handle semantics for: -// (shifted, carry) = Shift_C(R[m], shift_t, shift_n, PSTATE.C); -// (shift_t, shift_n) = DecodeImmShift(type, imm5); -// See an instruction in Integer Data Processing (three register, immediate shift) set for an example -static void AddShiftRegOperand(Instruction &inst, - uint32_t reg_num, uint32_t shift_type, - uint32_t shift_size) { - auto is_rrx = false; - if (!shift_size && shift_type == Shift::kShiftROR) { - shift_size = 1; - is_rrx = true; - } else if (shift_type == Shift::kShiftLSR || shift_type == Shift::kShiftASR) { - if (!shift_size) { - shift_size = 32; - } - } - - if (!shift_size) { - AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); - } else { - if (is_rrx) { - AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, - kIntRegName[reg_num], 32, 1); - } else { - AddShiftOp(inst, GetOperandShift(static_cast(shift_type)), - kIntRegName[reg_num], 32, shift_size); - } +// Note: this has no RRX shift operation +static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, + uint32_t shift_type, uint32_t shift_reg_num, + bool carry_out) { + auto _32_type = llvm::Type::getInt32Ty(*(inst.arch_for_decode->context)); + auto _8_type = llvm::Type::getInt8Ty(*(inst.arch_for_decode->context)); + auto _1_type = llvm::Type::getInt1Ty(*(inst.arch_for_decode->context)); + + AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); + AddIntRegOp(inst, shift_reg_num, 32, Operand::kActionRead); + + // Extract the low 8 bits + inst.operands.back().expr = inst.EmplaceUnaryOp(llvm::Instruction::Trunc, + inst.operands.back().expr, + _8_type); + inst.operands.back().expr = inst.EmplaceUnaryOp(llvm::Instruction::ZExt, + inst.operands.back().expr, + _32_type); + + auto shift_val_expr = inst.operands.back().expr; + inst.operands.pop_back(); + + switch (static_cast(shift_type)) { + case Shift::kShiftASR: + inst.operands.back().expr = inst.EmplaceBinaryOp( + llvm::Instruction::AShr, inst.operands.back().expr, shift_val_expr); + + if (carry_out) { + AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); + inst.operands.back().expr = inst.EmplaceBinaryOp( + llvm::Instruction::AShr, inst.operands.back().expr, shift_val_expr); + } + break; + case Shift::kShiftLSL: + inst.operands.back().expr = inst.EmplaceBinaryOp( + llvm::Instruction::Shl, inst.operands.back().expr, shift_val_expr); + + if (carry_out) { + AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); + inst.operands.back().expr = inst.EmplaceBinaryOp( + llvm::Instruction::Shl, inst.operands.back().expr, shift_val_expr); + } + break; + case Shift::kShiftLSR: + inst.operands.back().expr = inst.EmplaceBinaryOp( + llvm::Instruction::LShr, inst.operands.back().expr, shift_val_expr); + + if (carry_out) { + AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); + inst.operands.back().expr = inst.EmplaceBinaryOp( + llvm::Instruction::LShr, inst.operands.back().expr, shift_val_expr); + } + break; + case Shift::kShiftROR: + if (carry_out) { + AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); + const auto word_type = inst.arch_for_decode->AddressType(); + const auto _31 = llvm::ConstantInt::get(word_type, 31, false); + const auto _32 = llvm::ConstantInt::get(word_type, 32, false); + shift_val_expr = inst.EmplaceBinaryOp(llvm::Instruction::Add, + shift_val_expr, + inst.EmplaceConstant(_31)); + shift_val_expr = inst.EmplaceBinaryOp(llvm::Instruction::URem, + shift_val_expr, + inst.EmplaceConstant(_32)); + inst.operands.back().expr = inst.EmplaceBinaryOp( + llvm::Instruction::LShr, inst.operands.back().expr, shift_val_expr); + } + break; } - - // To handle rrx we need to take two components shift each and OR the results - // together. We create this functionality by creating a new shift operand, - // removing it from the instruction operand list, and adding a binary op to - // the register operand that ORs the expressions together. - if (is_rrx) { - AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, "C", 8, 31); - auto rrx_op = inst.operands.back().expr; - inst.operands.pop_back(); - inst.operands.back().expr = inst.EmplaceBinaryOp(llvm::Instruction::Or, - inst.operands.back().expr, - rrx_op); + if (carry_out) { + // Extract sign bit + inst.operands.back().expr = inst.EmplaceUnaryOp(llvm::Instruction::Trunc, + inst.operands.back().expr, + _1_type); + // ZExtend operand back to I8 + inst.operands.back().expr = inst.EmplaceUnaryOp(llvm::Instruction::ZExt, + inst.operands.back().expr, + _8_type); } } - -// PLEASE SEE AddShiftRegOperand! +// PLEASE SEE AddShiftRegImmOperand! // This function extracts the carry_out that from the semantics that -// AddShiftRegOperand handles +// AddShiftRegImmOperand handles static void AddShiftCarryOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_size, const char * carry_reg_name) { @@ -493,6 +530,53 @@ static void AddShiftCarryOperand(Instruction &inst, } } +// Adds a shift operand and optionally carry out operand +// Used to handle semantics for: +// (shift_t, shift_n) = DecodeImmShift(type, imm5); +// (shifted, carry) = Shift_C(R[m], shift_t, shift_n, PSTATE.C); +// See an instruction in Integer Data Processing (three register, immediate shift) set for an example +static void AddShiftRegImmOperand(Instruction &inst, uint32_t reg_num, + uint32_t shift_type, uint32_t shift_size, + bool carry_out) { + auto is_rrx = false; + if (!shift_size && shift_type == Shift::kShiftROR) { + shift_size = 1; + is_rrx = true; + } else if (shift_type == Shift::kShiftLSR || shift_type == Shift::kShiftASR) { + if (!shift_size) { + shift_size = 32; + } + } + + if (!shift_size) { + AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); + } else { + if (is_rrx) { + AddShiftOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, + kIntRegName[reg_num], 32, 1); + } else { + AddShiftOp(inst, GetOperandShift(static_cast(shift_type)), + kIntRegName[reg_num], 32, shift_size); + } + } + + // To handle rrx we need to take two components shift each and OR the results + // together. We create this functionality by creating a new shift operand, + // removing it from the instruction operand list, and adding a binary op to + // the register operand that ORs the expressions together. + if (is_rrx) { + AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, "C", 8, 31); + auto rrx_op = inst.operands.back().expr; + inst.operands.pop_back(); + inst.operands.back().expr = inst.EmplaceBinaryOp(llvm::Instruction::Or, + inst.operands.back().expr, + rrx_op); + } + if (carry_out) { + AddShiftCarryOperand(inst, reg_num, shift_type, shift_size, "C"); + } +} + // Decode the condition field and fill in the instruction conditions accordingly static void DecodeCondition(Instruction &inst, uint32_t cond) { inst.conditions.emplace_back(); @@ -810,30 +894,30 @@ static bool TryDecodeIntegerDataProcessingRRRI(Instruction &inst, uint32_t bits) DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); - AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); + AddShiftRegImmOperand(inst, enc.rm, enc.type, enc.imm5, enc.s); + return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc]); +} - if (enc.s) { - AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); +// Integer Data Processing (three register, register shift) +static bool TryDecodeIntegerDataProcessingRRRR(Instruction &inst, uint32_t bits) { + const IntDataProcessingRRRR enc = { bits }; + + inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s]; + DecodeCondition(inst, enc.cond); + + if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum + || enc.rm == kPCRegNum) { + inst.category = Instruction::kCategoryError; + return false; } + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + AddShiftRegRegOperand(inst, enc.rm, enc.type, enc.rs, enc.s); - return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc]); + inst.category = Instruction::kCategoryNormal; + return true; } -// TODO(Sonya): Integer Data Processing (three register, register shift) -//static bool TryDecodeIntegerDataProcessingRRRR(Instruction &inst, uint32_t bits) { -// return false; -// const IntDataProcessingRRRR enc = { bits }; -// -// inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s]; -// DecodeCondition(inst, enc.cond); -// -// if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum -// || enc.rm == kPCRegNum) { -// inst.category = Instruction::kCategoryError; -// return false; -// } -//} - //000 AND, ANDS (immediate) //001 EOR, EORS (immediate) //010 0 != 11x1 SUB, SUBS (immediate) — SUB @@ -1084,45 +1168,42 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { AddImmOp(inst, 1); } - AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); - if (enc.s) { - AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); - } - + AddShiftRegImmOperand(inst, enc.rm, enc.type, enc.imm5, enc.s); return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); } -// TODO(Sonya): Logical Arithmetic (three register, register shift) -//static bool TryLogicalArithmeticRRRR(Instruction &inst, uint32_t bits) { -// return false; -// -// const LogicalArithRRRR enc = { bits }; -// -// auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; -// -// inst.function = instruction; -// DecodeCondition(inst, enc.cond); -// -// if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum -// || enc.rm == kPCRegNum) { -// inst.category = Instruction::kCategoryError; -// return false; -// } -// -// AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); -// // enc.opc == x0 -// if (!(enc.opc & 0b1u)) { -// AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); -// } -// // enc.opc == 01 -// else if (!(enc.opc & 0b10u)) { -// AddImmOp(inst, 0); -// } -// // enc.opc == 11 -// else { -// AddImmOp(inst, 1); -// } -//} +// Logical Arithmetic (three register, register shift) +static bool TryLogicalArithmeticRRRR(Instruction &inst, uint32_t bits) { + const LogicalArithRRRR enc = { bits }; + + auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; + + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum + || enc.rm == kPCRegNum) { + inst.category = Instruction::kCategoryError; + return false; + } + + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + // enc.opc == x0 + if (!(enc.opc & 0b1u)) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + } + // enc.opc == 01 + else if (!(enc.opc & 0b10u)) { + AddImmOp(inst, 0); + } + // enc.opc == 11 + else { + AddImmOp(inst, 1); + } + AddShiftRegRegOperand(inst, enc.rm, enc.type, enc.rs, enc.s); + inst.category = Instruction::kCategoryNormal; + return true; +} // Logical Arithmetic (two register and immediate) static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { @@ -1173,46 +1254,48 @@ static bool TryIntegerTestAndCompareRRI(Instruction &inst, uint32_t bits) { DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); - AddShiftRegOperand(inst, enc.rm, enc.type, enc.imm5); - AddShiftCarryOperand(inst, enc.rm, enc.type, enc.imm5, "C"); + AddShiftRegImmOperand(inst, enc.rm, enc.type, enc.imm5, 1u); + + inst.category = Instruction::kCategoryNormal; + return true; +} + +// Integer Test and Compare (two register, register shift) +static bool TryIntegerTestAndCompareRRR(Instruction &inst, uint32_t bits) { + const IntTestCompRRR enc = { bits }; + + auto instruction = kIntegerTestAndCompareR[enc.opc]; + + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + if (enc.rn == kPCRegNum || enc.rs == kPCRegNum || enc.rm == kPCRegNum) { + inst.category = Instruction::kCategoryError; + return false; + } + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + AddShiftRegRegOperand(inst, enc.rm, enc.type, enc.rs, 1u); inst.category = Instruction::kCategoryNormal; return true; } -// TODO(Sonya): Integer Test and Compare (two register, register shift) -//static bool TryIntegerTestAndCompareRRR(Instruction &inst, uint32_t bits) { -// return false; -// -// const IntTestCompRRR enc = { bits }; -// -// auto instruction = kIntegerTestAndCompareR[enc.opc]; -// -// inst.function = instruction; -// DecodeCondition(inst, enc.cond); -// -// if (enc.rn == kPCRegNum || enc.rs == kPCRegNum || enc.rm == kPCRegNum) { -// inst.category = Instruction::kCategoryError; -// return false; -// } -//} -// -//// Integer Test and Compare (one register and immediate) -//static bool TryIntegerTestAndCompareRI(Instruction &inst, uint32_t bits) { -// const IntTestCompRI enc = { bits }; -// -// auto instruction = kIntegerTestAndCompareR[enc.opc]; -// -// inst.function = instruction; -// DecodeCondition(inst, enc.cond); -// -// AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); -// ExpandTo32AddImmAddCarry(inst, enc.imm12, 1u); -// -// inst.category = Instruction::kCategoryNormal; -// return true; -// -//} +// Integer Test and Compare (one register and immediate) +static bool TryIntegerTestAndCompareRI(Instruction &inst, uint32_t bits) { + const IntTestCompRI enc = { bits }; + + auto instruction = kIntegerTestAndCompareR[enc.opc]; + + inst.function = instruction; + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + ExpandTo32AddImmAddCarry(inst, enc.imm12, 1u); + + inst.category = Instruction::kCategoryNormal; + return true; + +} // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> @@ -1227,17 +1310,17 @@ static TryDecode * kDataProcessingRI[] = { [0b111] = TryLogicalArithmeticRRRI, }; -// Corresponds to Data-processing register (immediate shift) +// Corresponds to Data-processing register (register shift) // op0<24 to 23> | op1 <20> static TryDecode * kDataProcessingRR[] = { - [0b000] = nullptr, //TryDecodeIntegerDataProcessingRRRR, - [0b001] = nullptr, //TryDecodeIntegerDataProcessingRRRR, - [0b010] = nullptr, //TryDecodeIntegerDataProcessingRRRR, - [0b011] = nullptr, //TryDecodeIntegerDataProcessingRRRR, + [0b000] = TryDecodeIntegerDataProcessingRRRR, + [0b001] = TryDecodeIntegerDataProcessingRRRR, + [0b010] = TryDecodeIntegerDataProcessingRRRR, + [0b011] = TryDecodeIntegerDataProcessingRRRR, [0b100] = nullptr, // op0:op1 != 100 - [0b101] = nullptr, //TryIntegerTestAndCompareRRR, - [0b110] = nullptr, //TryLogicalArithmeticRRRR, - [0b111] = nullptr, //TryLogicalArithmeticRRRR, + [0b101] = TryIntegerTestAndCompareRRR, + [0b110] = TryLogicalArithmeticRRRR, + [0b111] = TryLogicalArithmeticRRRR, }; // Corresponds to Data-processing immediate @@ -1252,9 +1335,9 @@ static TryDecode * kDataProcessingI[] = { [0b0110] = TryDecodeIntegerDataProcessingRRI, [0b0111] = TryDecodeIntegerDataProcessingRRI, [0b1000] = nullptr, // TODO(Sonya): Move Halfword (immediate) - [0b1001] = nullptr, //TryIntegerTestAndCompareRI, + [0b1001] = TryIntegerTestAndCompareRI, [0b1010] = nullptr, // TODO(Sonya): Move Special Register and Hints (immediate) - [0b1011] = nullptr, // TryIntegerTestAndCompareRI, + [0b1011] = TryIntegerTestAndCompareRI, [0b1100] = TryLogicalArithmeticRRI, [0b1101] = TryLogicalArithmeticRRI, [0b1110] = TryLogicalArithmeticRRI, From 3608a8f10b2714d24d24e7d50aceca21e6f29376 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 10 Nov 2020 15:55:47 -0500 Subject: [PATCH 080/130] Updated ROR in AddShiftRegRegOperand --- lib/Arch/AArch32/Decode.cpp | 31 +++++++++++++++++++++---------- lib/BC/InstructionLifter.cpp | 2 ++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index d469bd77d..977ece937 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -404,25 +404,24 @@ static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, auto _8_type = llvm::Type::getInt8Ty(*(inst.arch_for_decode->context)); auto _1_type = llvm::Type::getInt1Ty(*(inst.arch_for_decode->context)); - AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); - AddIntRegOp(inst, shift_reg_num, 32, Operand::kActionRead); + AddIntRegOp(inst, reg_num, 32u, Operand::kActionRead); - // Extract the low 8 bits + // Create expression for the low 8 bits of the shift register + AddIntRegOp(inst, shift_reg_num, 32u, Operand::kActionRead); inst.operands.back().expr = inst.EmplaceUnaryOp(llvm::Instruction::Trunc, inst.operands.back().expr, _8_type); inst.operands.back().expr = inst.EmplaceUnaryOp(llvm::Instruction::ZExt, inst.operands.back().expr, _32_type); - auto shift_val_expr = inst.operands.back().expr; inst.operands.pop_back(); + // Create the shift and carry expressions operations switch (static_cast(shift_type)) { case Shift::kShiftASR: inst.operands.back().expr = inst.EmplaceBinaryOp( llvm::Instruction::AShr, inst.operands.back().expr, shift_val_expr); - if (carry_out) { AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); inst.operands.back().expr = inst.EmplaceBinaryOp( @@ -432,7 +431,6 @@ static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, case Shift::kShiftLSL: inst.operands.back().expr = inst.EmplaceBinaryOp( llvm::Instruction::Shl, inst.operands.back().expr, shift_val_expr); - if (carry_out) { AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); inst.operands.back().expr = inst.EmplaceBinaryOp( @@ -442,7 +440,6 @@ static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, case Shift::kShiftLSR: inst.operands.back().expr = inst.EmplaceBinaryOp( llvm::Instruction::LShr, inst.operands.back().expr, shift_val_expr); - if (carry_out) { AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); inst.operands.back().expr = inst.EmplaceBinaryOp( @@ -450,11 +447,25 @@ static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, } break; case Shift::kShiftROR: + const auto word_type = inst.arch_for_decode->AddressType(); + const auto _31 = llvm::ConstantInt::get(word_type, 31u, false); + const auto _32 = llvm::ConstantInt::get(word_type, 32u, false); + auto shift_amount = inst.EmplaceBinaryOp(llvm::Instruction::URem, + shift_val_expr, + inst.EmplaceConstant(_32)); + auto lhs_expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, + inst.operands.back().expr, + shift_amount); + auto rhs_expr = inst.EmplaceBinaryOp(llvm::Instruction::Shl, + inst.operands.back().expr, + inst.EmplaceBinaryOp( + llvm::Instruction::Sub, + inst.EmplaceConstant(_32), + shift_amount)); + inst.operands.back().expr = inst.EmplaceBinaryOp(llvm::Instruction::Or, + lhs_expr, rhs_expr); if (carry_out) { AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); - const auto word_type = inst.arch_for_decode->AddressType(); - const auto _31 = llvm::ConstantInt::get(word_type, 31, false); - const auto _32 = llvm::ConstantInt::get(word_type, 32, false); shift_val_expr = inst.EmplaceBinaryOp(llvm::Instruction::Add, shift_val_expr, inst.EmplaceConstant(_31)); diff --git a/lib/BC/InstructionLifter.cpp b/lib/BC/InstructionLifter.cpp index 3f8975216..9741b2781 100644 --- a/lib/BC/InstructionLifter.cpp +++ b/lib/BC/InstructionLifter.cpp @@ -725,6 +725,8 @@ llvm::Value *InstructionLifter::LiftExpressionOperandRec( return ir.CreateAnd(lhs, rhs); case llvm::Instruction::Or: return ir.CreateOr(lhs, rhs); + case llvm::Instruction::URem: + return ir.CreateURem(lhs, rhs); default: LOG(FATAL) << "Invalid Expression " From 3333f88a1adefc753ba14bbb30c463ca8255fd42 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 10 Nov 2020 16:10:01 -0500 Subject: [PATCH 081/130] Created ExtractAndZExtExpr --- lib/Arch/AArch32/Decode.cpp | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 977ece937..46ea7cf6b 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -396,24 +396,37 @@ static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, } } + +// Do an extraction and zero extension on an expression +static void ExtractAndZExtExpr(Instruction &inst, Operand &op, + unsigned int extract_size, + unsigned int extend_size) { + auto extract_type = llvm::Type::getIntNTy(*(inst.arch_for_decode->context), + extract_size); + auto extend_type = llvm::Type::getIntNTy(*(inst.arch_for_decode->context), + extend_size); + // Extract bits + inst.operands.back().expr = inst.EmplaceUnaryOp(llvm::Instruction::Trunc, + op.expr, + extract_type); + // ZExtend operand back to I8 + inst.operands.back().expr = inst.EmplaceUnaryOp(llvm::Instruction::ZExt, + op.expr, + extend_type); +} + // Note: this has no RRX shift operation static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_reg_num, bool carry_out) { auto _32_type = llvm::Type::getInt32Ty(*(inst.arch_for_decode->context)); auto _8_type = llvm::Type::getInt8Ty(*(inst.arch_for_decode->context)); - auto _1_type = llvm::Type::getInt1Ty(*(inst.arch_for_decode->context)); AddIntRegOp(inst, reg_num, 32u, Operand::kActionRead); // Create expression for the low 8 bits of the shift register AddIntRegOp(inst, shift_reg_num, 32u, Operand::kActionRead); - inst.operands.back().expr = inst.EmplaceUnaryOp(llvm::Instruction::Trunc, - inst.operands.back().expr, - _8_type); - inst.operands.back().expr = inst.EmplaceUnaryOp(llvm::Instruction::ZExt, - inst.operands.back().expr, - _32_type); + ExtractAndZExtExpr(inst, inst.operands.back(), 8u, 32u); auto shift_val_expr = inst.operands.back().expr; inst.operands.pop_back(); @@ -478,14 +491,8 @@ static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, break; } if (carry_out) { - // Extract sign bit - inst.operands.back().expr = inst.EmplaceUnaryOp(llvm::Instruction::Trunc, - inst.operands.back().expr, - _1_type); - // ZExtend operand back to I8 - inst.operands.back().expr = inst.EmplaceUnaryOp(llvm::Instruction::ZExt, - inst.operands.back().expr, - _8_type); + // Extract the sign bit and extend back to I8 + ExtractAndZExtExpr(inst, inst.operands.back(), 1u, 8u); } } From 8dd8e70920e5ddc99d9fbb0709858a2b6a84571c Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 10 Nov 2020 16:27:41 -0500 Subject: [PATCH 082/130] Fixed comment formatting in if else statements --- lib/Arch/AArch32/Decode.cpp | 55 ++++++++++++------------------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 46ea7cf6b..4ea7538f4 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -419,11 +419,7 @@ static void ExtractAndZExtExpr(Instruction &inst, Operand &op, static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_reg_num, bool carry_out) { - auto _32_type = llvm::Type::getInt32Ty(*(inst.arch_for_decode->context)); - auto _8_type = llvm::Type::getInt8Ty(*(inst.arch_for_decode->context)); - AddIntRegOp(inst, reg_num, 32u, Operand::kActionRead); - // Create expression for the low 8 bits of the shift register AddIntRegOp(inst, shift_reg_num, 32u, Operand::kActionRead); ExtractAndZExtExpr(inst, inst.operands.back(), 8u, 32u); @@ -1176,13 +1172,11 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { // enc.opc == x0 if (!(enc.opc & 0b1u)) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); - } // enc.opc == 01 - else if (!(enc.opc & 0b10u)) { + } else if (!(enc.opc & 0b10u)) { AddImmOp(inst, 0); - } // enc.opc == 11 - else { + } else { AddImmOp(inst, 1); } @@ -1209,13 +1203,11 @@ static bool TryLogicalArithmeticRRRR(Instruction &inst, uint32_t bits) { // enc.opc == x0 if (!(enc.opc & 0b1u)) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); - } // enc.opc == 01 - else if (!(enc.opc & 0b10u)) { + } else if (!(enc.opc & 0b10u)) { AddImmOp(inst, 0); - } // enc.opc == 11 - else { + } else { AddImmOp(inst, 1); } AddShiftRegRegOperand(inst, enc.rm, enc.type, enc.rs, enc.s); @@ -1236,13 +1228,11 @@ static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { // enc.opc == x0 if (!(enc.opc & 0b1u)) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); - } // enc.opc == 01 - else if (!(enc.opc & 0b10u)) { + } else if (!(enc.opc & 0b10u)) { AddImmOp(inst, 0); - } // enc.opc == 11 - else { + } else { AddImmOp(inst, 1); } @@ -1390,27 +1380,23 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { // TODO(Sonya): Extra load/store -- op3 != 00 if (!enc.op3) { return nullptr; - } // op3 == 00 - else { + } else { // Multiply and Accumulate -- op1 == 0xxxx if (!(enc.op1 >> 4)) { return TryDecodeMultiplyAndAccumulate; - } // TODO(Sonya): Synchronization primitives and Load-Acquire/Store-Release -- op1 == 1xxxx - else { + } else { return nullptr; } } - } // op1 == 10xx0 - else if (((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) { + } else if (((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) { // TODO(Sonya): Miscellaneous if (!enc.op2) { return nullptr; - } // TODO(Sonya): Halfword Multiply and Accumulate - else { + } else { return nullptr; } } @@ -1421,15 +1407,13 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 lowest bit // index is the concatenation of op0 and op1 return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; - } // Data-processing register (register shift) -- op4 == 1 - else { + } else { return kDataProcessingRR[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; } } - } // Data-processing immediate -- op0 == 1 - else { + } else { // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 2 lowest bits // index is the concatenation of op0 and op1 return kDataProcessingI[(enc.op1 >> 1) | (enc.op1 & 0b11u)]; @@ -1455,25 +1439,21 @@ static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { // Data-processing and miscellaneous instructions -- op0 == 00x if (!(enc.op0 >> 1)) { return TryDataProcessingAndMisc(bits); - } // Load/Store Word, Unsigned Byte (immediate, literal) -- op0 == 010 - else if (enc.op0 == 0b010u) { + } else if (enc.op0 == 0b010u) { const LoadStoreWUBIL enc_ls_word = { bits }; return kLoadStoreWordUBIL[enc_ls_word.o2 << 1u | enc_ls_word.o1]; - } // TODO(Sonya): Load/Store Word, Unsigned Byte (register) -- op0 == 011, op1 == 0 - else if (!enc.op1) { + } else if (!enc.op1) { // This should be returning another table index using a struct like above return nullptr; - } // TODO(Sonya): Media instructions -- op0 == 011, op1 == 1 - else { + } else { // return a result from another function for instruction categorizing return nullptr; } - } // TODO(Sonya): Unconditional instructions -- cond == 1111 - else { + } else { // return a result from another function for instruction categorizing return nullptr; } @@ -1484,9 +1464,8 @@ static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { if (enc.op0 >> 1 == 0b10u) { // return a result from another function for instruction categorizing return nullptr; - } // TODO(Sonya): System register access, Advanced SIMD, floating-point, and Supervisor call -- op0 == 11x - else { + } else { // return a result from another function for instruction categorizing return nullptr; } From d0e1c5bacc75ee4cfc736b9e407f66d3bd33c42d Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 10 Nov 2020 17:17:42 -0500 Subject: [PATCH 083/130] Created RORExpr --- lib/Arch/AArch32/Decode.cpp | 120 +++++++++++++++++------------------- 1 file changed, 56 insertions(+), 64 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 4ea7538f4..f1db31563 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -396,23 +396,35 @@ static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, } } - // Do an extraction and zero extension on an expression static void ExtractAndZExtExpr(Instruction &inst, Operand &op, - unsigned int extract_size, - unsigned int extend_size) { + unsigned int extract_size, + unsigned int extend_size) { auto extract_type = llvm::Type::getIntNTy(*(inst.arch_for_decode->context), extract_size); auto extend_type = llvm::Type::getIntNTy(*(inst.arch_for_decode->context), extend_size); // Extract bits - inst.operands.back().expr = inst.EmplaceUnaryOp(llvm::Instruction::Trunc, - op.expr, - extract_type); + op.expr = inst.EmplaceUnaryOp(llvm::Instruction::Trunc, op.expr, + extract_type); // ZExtend operand back to I8 - inst.operands.back().expr = inst.EmplaceUnaryOp(llvm::Instruction::ZExt, - op.expr, - extend_type); + op.expr = inst.EmplaceUnaryOp(llvm::Instruction::ZExt, op.expr, extend_type); +} + +static void RORExpr(Instruction &inst, Operand &op, + OperandExpression *shift_amount) { + const auto word_type = inst.arch_for_decode->AddressType(); + const auto _31 = llvm::ConstantInt::get(word_type, 31u, false); + const auto _32 = llvm::ConstantInt::get(word_type, 32u, false); + shift_amount = inst.EmplaceBinaryOp(llvm::Instruction::URem, shift_amount, + inst.EmplaceConstant(_32)); + auto lhs_expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, op.expr, + shift_amount); + auto rhs_expr = inst.EmplaceBinaryOp(llvm::Instruction::Shl, op.expr, + inst.EmplaceBinaryOp(llvm::Instruction::Sub, + inst.EmplaceConstant(_32), + shift_amount)); + op.expr = inst.EmplaceBinaryOp(llvm::Instruction::Or, lhs_expr, rhs_expr); } // Note: this has no RRX shift operation @@ -420,6 +432,7 @@ static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_reg_num, bool carry_out) { AddIntRegOp(inst, reg_num, 32u, Operand::kActionRead); + // Create expression for the low 8 bits of the shift register AddIntRegOp(inst, shift_reg_num, 32u, Operand::kActionRead); ExtractAndZExtExpr(inst, inst.operands.back(), 8u, 32u); @@ -427,65 +440,44 @@ static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, inst.operands.pop_back(); // Create the shift and carry expressions operations - switch (static_cast(shift_type)) { - case Shift::kShiftASR: - inst.operands.back().expr = inst.EmplaceBinaryOp( - llvm::Instruction::AShr, inst.operands.back().expr, shift_val_expr); - if (carry_out) { - AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); - inst.operands.back().expr = inst.EmplaceBinaryOp( - llvm::Instruction::AShr, inst.operands.back().expr, shift_val_expr); - } - break; - case Shift::kShiftLSL: - inst.operands.back().expr = inst.EmplaceBinaryOp( - llvm::Instruction::Shl, inst.operands.back().expr, shift_val_expr); - if (carry_out) { - AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); - inst.operands.back().expr = inst.EmplaceBinaryOp( - llvm::Instruction::Shl, inst.operands.back().expr, shift_val_expr); - } - break; - case Shift::kShiftLSR: + if (static_cast(shift_type) != Shift::kShiftROR) { + unsigned opcode; + switch (static_cast(shift_type)) { + case Shift::kShiftASR: + opcode = llvm::Instruction::AShr; + break; + case Shift::kShiftLSL: + opcode = llvm::Instruction::Shl; + break; + case Shift::kShiftLSR: + opcode = llvm::Instruction::LShr; + break; + } + inst.operands.back().expr = inst.EmplaceBinaryOp(opcode, + inst.operands.back().expr, + shift_val_expr); + if (carry_out) { + AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); inst.operands.back().expr = inst.EmplaceBinaryOp( - llvm::Instruction::LShr, inst.operands.back().expr, shift_val_expr); - if (carry_out) { - AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); - inst.operands.back().expr = inst.EmplaceBinaryOp( - llvm::Instruction::LShr, inst.operands.back().expr, shift_val_expr); - } - break; - case Shift::kShiftROR: - const auto word_type = inst.arch_for_decode->AddressType(); + opcode, inst.operands.back().expr, shift_val_expr); + } + } else { + RORExpr(inst, inst.operands.back(), shift_val_expr); + if (carry_out) { const auto _31 = llvm::ConstantInt::get(word_type, 31u, false); const auto _32 = llvm::ConstantInt::get(word_type, 32u, false); - auto shift_amount = inst.EmplaceBinaryOp(llvm::Instruction::URem, - shift_val_expr, - inst.EmplaceConstant(_32)); - auto lhs_expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, - inst.operands.back().expr, - shift_amount); - auto rhs_expr = inst.EmplaceBinaryOp(llvm::Instruction::Shl, - inst.operands.back().expr, - inst.EmplaceBinaryOp( - llvm::Instruction::Sub, - inst.EmplaceConstant(_32), - shift_amount)); - inst.operands.back().expr = inst.EmplaceBinaryOp(llvm::Instruction::Or, - lhs_expr, rhs_expr); - if (carry_out) { - AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); - shift_val_expr = inst.EmplaceBinaryOp(llvm::Instruction::Add, - shift_val_expr, - inst.EmplaceConstant(_31)); - shift_val_expr = inst.EmplaceBinaryOp(llvm::Instruction::URem, - shift_val_expr, - inst.EmplaceConstant(_32)); - inst.operands.back().expr = inst.EmplaceBinaryOp( - llvm::Instruction::LShr, inst.operands.back().expr, shift_val_expr); - } - break; + AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); + shift_val_expr = inst.EmplaceBinaryOp(llvm::Instruction::Add, + shift_val_expr, + inst.EmplaceConstant(_31)); + shift_val_expr = inst.EmplaceBinaryOp(llvm::Instruction::URem, + shift_val_expr, + inst.EmplaceConstant(_32)); + inst.operands.back().expr = inst.EmplaceBinaryOp( + llvm::Instruction::LShr, inst.operands.back().expr, shift_val_expr); + } } + if (carry_out) { // Extract the sign bit and extend back to I8 ExtractAndZExtExpr(inst, inst.operands.back(), 1u, 8u); From 72101550670b68145002d584a88d8c0313eb8322 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 12 Nov 2020 15:06:22 -0500 Subject: [PATCH 084/130] Small fixes --- lib/Arch/AArch32/Decode.cpp | 34 ++++++++++++++++++++--------- lib/Arch/AArch32/Semantics/COND.cpp | 8 +++---- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index f1db31563..f13200433 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -458,23 +458,38 @@ static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, shift_val_expr); if (carry_out) { AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); + + // Create expression for the low 8 bits of the shift register + AddIntRegOp(inst, shift_reg_num, 32u, Operand::kActionRead); + ExtractAndZExtExpr(inst, inst.operands.back(), 8u, 32u); + auto shift_val_expr_c = inst.operands.back().expr; + inst.operands.pop_back(); + inst.operands.back().expr = inst.EmplaceBinaryOp( - opcode, inst.operands.back().expr, shift_val_expr); + opcode, inst.operands.back().expr, shift_val_expr_c); } } else { RORExpr(inst, inst.operands.back(), shift_val_expr); if (carry_out) { + const auto word_type = inst.arch_for_decode->AddressType(); const auto _31 = llvm::ConstantInt::get(word_type, 31u, false); const auto _32 = llvm::ConstantInt::get(word_type, 32u, false); - AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); - shift_val_expr = inst.EmplaceBinaryOp(llvm::Instruction::Add, - shift_val_expr, + AddIntRegOp(inst, reg_num, 32u, Operand::kActionRead); + + // Create expression for the low 8 bits of the shift register + AddIntRegOp(inst, shift_reg_num, 32u, Operand::kActionRead); + ExtractAndZExtExpr(inst, inst.operands.back(), 8u, 32u); + auto shift_val_expr_c = inst.operands.back().expr; + inst.operands.pop_back(); + + shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Add, + shift_val_expr_c, inst.EmplaceConstant(_31)); - shift_val_expr = inst.EmplaceBinaryOp(llvm::Instruction::URem, - shift_val_expr, + shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::URem, + shift_val_expr_c, inst.EmplaceConstant(_32)); inst.operands.back().expr = inst.EmplaceBinaryOp( - llvm::Instruction::LShr, inst.operands.back().expr, shift_val_expr); + llvm::Instruction::LShr, inst.operands.back().expr, shift_val_expr_c); } } @@ -1383,7 +1398,7 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { } } // op1 == 10xx0 - } else if (((enc.op1 >> 3) == 0b10u) && (enc.op1 & 0b00001u)) { + } else if (((enc.op1 >> 3) == 0b10u) && !(enc.op1 & 0b00001u)) { // TODO(Sonya): Miscellaneous if (!enc.op2) { return nullptr; @@ -1391,9 +1406,8 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { } else { return nullptr; } - } // op1 != 10xx0 - else { + } else { // Data-processing register (immediate shift) -- op4 == 0 if (!enc.op4) { // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 lowest bit diff --git a/lib/Arch/AArch32/Semantics/COND.cpp b/lib/Arch/AArch32/Semantics/COND.cpp index 8bc4b3075..a85781a43 100644 --- a/lib/Arch/AArch32/Semantics/COND.cpp +++ b/lib/Arch/AArch32/Semantics/COND.cpp @@ -50,7 +50,7 @@ DEF_SEM(CMN, R32 src1, I32 src2, I8 carry_out) { } } // namespace -DEF_ISEL(TST) = TST; -DEF_ISEL(TEQ) = TEQ; -DEF_ISEL(CMP) = CMP; -DEF_ISEL(CMN) = CMN; +DEF_ISEL(TSTr) = TST; +DEF_ISEL(TEQr) = TEQ; +DEF_ISEL(CMPr) = CMP; +DEF_ISEL(CMNr) = CMN; From 405b62607c10bc6d9ffc533e5de8a189f96b1b20 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 12 Nov 2020 16:49:31 -0500 Subject: [PATCH 085/130] Small fix in Logical Arithmetic (two register and immediate) --- lib/Arch/AArch32/Decode.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index f13200433..c3ff94847 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -276,13 +276,12 @@ static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, } static void AddImmOp(Instruction &inst, uint64_t value, unsigned size = 32, - Operand::Action action = Operand::kActionRead, bool is_signed = false) { Operand::Immediate imm; imm.val = value; imm.is_signed = is_signed; auto &op = inst.EmplaceOperand(imm); - op.action = action; + op.action = Operand::kActionRead; op.size = size; } @@ -386,6 +385,7 @@ static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, if (carry_out) { if (!rotation_amount) { + // TODO(Sonya): remove the ShiftThenExtractOp op && do an extract only AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, "C", 8, 0, 1); @@ -1226,7 +1226,7 @@ static bool TryLogicalArithmeticRRRR(Instruction &inst, uint32_t bits) { static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { const LogicalArithmeticRRI enc = { bits }; - auto instruction = kLogicalArithmeticRRRI[enc.opc | enc.s]; + auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; inst.function = instruction; DecodeCondition(inst, enc.cond); @@ -1237,14 +1237,13 @@ static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); // enc.opc == 01 } else if (!(enc.opc & 0b10u)) { - AddImmOp(inst, 0); + AddImmOp(inst, 0u); // enc.opc == 11 } else { - AddImmOp(inst, 1); + AddImmOp(inst, 1u); } ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s); - return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); } From 5234e3e110a9557997b30d390d4f724c1a050deb Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 13 Nov 2020 18:53:16 -0500 Subject: [PATCH 086/130] Corrected AddShiftRegRegOperand and cleaned it up. Split the carry op into a separate function. --- lib/Arch/AArch32/Decode.cpp | 124 +++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 53 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index c3ff94847..d6f2451f9 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -427,6 +427,59 @@ static void RORExpr(Instruction &inst, Operand &op, op.expr = inst.EmplaceBinaryOp(llvm::Instruction::Or, lhs_expr, rhs_expr); } +static void AddShiftRegCarryOperand(Instruction &inst, uint32_t reg_num, + uint32_t shift_type, + uint32_t shift_reg_num) { + // Create expression for the low 8 bits of the shift register + AddIntRegOp(inst, shift_reg_num, 32u, Operand::kActionRead); + ExtractAndZExtExpr(inst, inst.operands.back(), 8u, 32u); + auto shift_val_expr_c = inst.operands.back().expr; + inst.operands.pop_back(); + + const auto word_type = inst.arch_for_decode->AddressType(); + const auto _1 = llvm::ConstantInt::get(word_type, 1u, false); + const auto _31 = llvm::ConstantInt::get(word_type, 31u, false); + const auto _32 = llvm::ConstantInt::get(word_type, 32u, false); + + unsigned opcode; + switch (static_cast(shift_type)) { + case Shift::kShiftASR: // shift_size - 1 + opcode = llvm::Instruction::AShr; + shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Sub, + shift_val_expr_c, + inst.EmplaceConstant(_1)); + break; + case Shift::kShiftLSL: // 32 - shift_size + opcode = llvm::Instruction::Shl; + shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Sub, + inst.EmplaceConstant(_32), + shift_val_expr_c); + break; + case Shift::kShiftLSR: // shift_size - 1 + opcode = llvm::Instruction::LShr; + shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Sub, + shift_val_expr_c, + inst.EmplaceConstant(_1)); + break; + case Shift::kShiftROR: + shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Add, + shift_val_expr_c, + inst.EmplaceConstant(_31)); + shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::URem, + shift_val_expr_c, + inst.EmplaceConstant(_32)); + break; + } + + AddIntRegOp(inst, reg_num, 32u, Operand::kActionRead); + inst.operands.back().expr = inst.EmplaceBinaryOp(opcode, + inst.operands.back().expr, + shift_val_expr_c); + + // Extract the sign bit and extend back to I8 + ExtractAndZExtExpr(inst, inst.operands.back(), 1u, 8u); +} + // Note: this has no RRX shift operation static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_reg_num, @@ -440,69 +493,34 @@ static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, inst.operands.pop_back(); // Create the shift and carry expressions operations - if (static_cast(shift_type) != Shift::kShiftROR) { - unsigned opcode; - switch (static_cast(shift_type)) { - case Shift::kShiftASR: - opcode = llvm::Instruction::AShr; - break; - case Shift::kShiftLSL: - opcode = llvm::Instruction::Shl; - break; - case Shift::kShiftLSR: - opcode = llvm::Instruction::LShr; - break; - } - inst.operands.back().expr = inst.EmplaceBinaryOp(opcode, - inst.operands.back().expr, - shift_val_expr); - if (carry_out) { - AddIntRegOp(inst, reg_num, 32, Operand::kActionRead); - - // Create expression for the low 8 bits of the shift register - AddIntRegOp(inst, shift_reg_num, 32u, Operand::kActionRead); - ExtractAndZExtExpr(inst, inst.operands.back(), 8u, 32u); - auto shift_val_expr_c = inst.operands.back().expr; - inst.operands.pop_back(); - + switch (static_cast(shift_type)) { + case Shift::kShiftASR: inst.operands.back().expr = inst.EmplaceBinaryOp( - opcode, inst.operands.back().expr, shift_val_expr_c); - } - } else { - RORExpr(inst, inst.operands.back(), shift_val_expr); - if (carry_out) { - const auto word_type = inst.arch_for_decode->AddressType(); - const auto _31 = llvm::ConstantInt::get(word_type, 31u, false); - const auto _32 = llvm::ConstantInt::get(word_type, 32u, false); - AddIntRegOp(inst, reg_num, 32u, Operand::kActionRead); - - // Create expression for the low 8 bits of the shift register - AddIntRegOp(inst, shift_reg_num, 32u, Operand::kActionRead); - ExtractAndZExtExpr(inst, inst.operands.back(), 8u, 32u); - auto shift_val_expr_c = inst.operands.back().expr; - inst.operands.pop_back(); - - shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Add, - shift_val_expr_c, - inst.EmplaceConstant(_31)); - shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::URem, - shift_val_expr_c, - inst.EmplaceConstant(_32)); + llvm::Instruction::AShr, inst.operands.back().expr, shift_val_expr); + break; + case Shift::kShiftLSL: inst.operands.back().expr = inst.EmplaceBinaryOp( - llvm::Instruction::LShr, inst.operands.back().expr, shift_val_expr_c); - } + llvm::Instruction::Shl, inst.operands.back().expr, shift_val_expr); + break; + case Shift::kShiftLSR: + inst.operands.back().expr = inst.EmplaceBinaryOp( + llvm::Instruction::LShr, inst.operands.back().expr, shift_val_expr); + break; + case Shift::kShiftROR: + RORExpr(inst, inst.operands.back(), shift_val_expr); + break; } if (carry_out) { - // Extract the sign bit and extend back to I8 - ExtractAndZExtExpr(inst, inst.operands.back(), 1u, 8u); + AddShiftRegCarryOperand(inst, reg_num, shift_type, shift_reg_num); } } + // PLEASE SEE AddShiftRegImmOperand! // This function extracts the carry_out that from the semantics that // AddShiftRegImmOperand handles -static void AddShiftCarryOperand(Instruction &inst, +static void AddShiftImmCarryOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_size, const char * carry_reg_name) { @@ -594,7 +612,7 @@ static void AddShiftRegImmOperand(Instruction &inst, uint32_t reg_num, rrx_op); } if (carry_out) { - AddShiftCarryOperand(inst, reg_num, shift_type, shift_size, "C"); + AddShiftImmCarryOperand(inst, reg_num, shift_type, shift_size, "C"); } } From 534b023b6dbdc433cc09e7077ac1b8fec3493413 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 17 Nov 2020 17:56:38 -0500 Subject: [PATCH 087/130] conditional support + Start of Branch instructions --- include/remill/Arch/AArch32/Runtime/Types.h | 2 +- include/remill/Arch/Instruction.h | 12 +- include/remill/Arch/Runtime/Definitions.h | 26 ++ lib/Arch/AArch32/Decode.cpp | 283 ++++++++++++++------ lib/Arch/AArch32/Runtime/CMakeLists.txt | 3 +- lib/Arch/AArch32/Runtime/Instructions.cpp | 2 +- lib/Arch/AArch32/Semantics/BINARY.cpp | 50 ++-- lib/Arch/AArch32/Semantics/BRANCH.cpp | 43 +++ lib/Arch/AArch32/Semantics/COND.cpp | 8 +- lib/Arch/AArch32/Semantics/LOGICAL.cpp | 8 +- lib/Arch/AArch32/Semantics/MEM.cpp | 97 +++++-- lib/Arch/Instruction.cpp | 27 +- lib/BC/InstructionLifter.cpp | 4 +- lib/BC/TraceLifter.cpp | 28 ++ 14 files changed, 427 insertions(+), 166 deletions(-) create mode 100644 lib/Arch/AArch32/Semantics/BRANCH.cpp diff --git a/include/remill/Arch/AArch32/Runtime/Types.h b/include/remill/Arch/AArch32/Runtime/Types.h index c77e899a5..550b13911 100644 --- a/include/remill/Arch/AArch32/Runtime/Types.h +++ b/include/remill/Arch/AArch32/Runtime/Types.h @@ -26,7 +26,7 @@ typedef RnW R16W; // can be accessed is 32 bits. typedef RnW R32W; -//typedef Rn R8; +typedef Rn R8; //typedef Rn R16; typedef Rn R32; diff --git a/include/remill/Arch/Instruction.h b/include/remill/Arch/Instruction.h index 63dcb297d..d5efd2e39 100644 --- a/include/remill/Arch/Instruction.h +++ b/include/remill/Arch/Instruction.h @@ -214,10 +214,6 @@ class Instruction { // Is this instruction decoded within the context of a delay slot? bool in_delay_slot; - // If `conditions` is non-empty then this tells us if we should negate the - // result of the condition. - bool negate_conditions; - enum Category { kCategoryInvalid, kCategoryNormal, @@ -225,6 +221,7 @@ class Instruction { kCategoryError, kCategoryDirectJump, kCategoryIndirectJump, + kCategoryConditionalIndirectJump, kCategoryDirectFunctionCall, kCategoryIndirectFunctionCall, kCategoryFunctionReturn, @@ -234,7 +231,6 @@ class Instruction { } category; std::vector operands; - std::vector conditions; std::string Serialize(void) const; @@ -260,7 +256,7 @@ class Instruction { switch (category) { case kCategoryIndirectFunctionCall: case kCategoryIndirectJump: - case kCategoryConditionalBranch: + case kCategoryConditionalIndirectJump: case kCategoryAsyncHyperCall: case kCategoryConditionalAsyncHyperCall: case kCategoryFunctionReturn: return true; @@ -269,7 +265,8 @@ class Instruction { } inline bool IsConditionalBranch(void) const { - return kCategoryConditionalBranch == category; + return kCategoryConditionalBranch == category || + kCategoryConditionalIndirectJump == category; } inline bool IsFunctionCall(void) const { @@ -306,6 +303,7 @@ class Instruction { // This allocates an OperandExpression OperandExpression * AllocateExpression(void); OperandExpression * EmplaceRegister(const Register *); + OperandExpression * EmplaceRegister(std::string_view reg_name); OperandExpression * EmplaceConstant(llvm::Constant *); OperandExpression * EmplaceVariable(std::string_view, llvm::Type *); OperandExpression * EmplaceBinaryOp(unsigned opcode, OperandExpression * op1, OperandExpression * op2); diff --git a/include/remill/Arch/Runtime/Definitions.h b/include/remill/Arch/Runtime/Definitions.h index 2c2e42778..d2d4d0dfc 100644 --- a/include/remill/Arch/Runtime/Definitions.h +++ b/include/remill/Arch/Runtime/Definitions.h @@ -58,6 +58,32 @@ ALWAYS_INLINE __attribute__((flatten)) static Memory *name( \ Memory *memory, State &state, ##__VA_ARGS__) +template +inline static constexpr auto Specialize(R (*)(Args...), R (*b)(Args...)) -> R (*)(Args...) { + return b; +} + +// Define a semantics implementing function. +#define DEF_COND_SEM(name, ...) \ + ALWAYS_INLINE __attribute__((flatten)) static Memory *name ##_impl( \ + Memory *memory, State &state, ##__VA_ARGS__); \ + static Memory *name ##_spec( \ + Memory *memory, State &state, R8 __cond, R8W __branch_taken, ##__VA_ARGS__) { return nullptr; } \ + template \ + ALWAYS_INLINE __attribute__((flatten)) static Memory *name ##_wrapped( \ + Memory *memory, State &state, R8 __cond, R8W __branch_taken, Args... args) { \ + if (Read(__cond)) { \ + Write(__branch_taken, true); \ + return name##_impl(memory, state, args...); \ + } else { \ + Write(__branch_taken, false); \ + return memory; \ + } \ + } \ + static constexpr auto name = Specialize(name ##_spec, name ##_wrapped); \ + ALWAYS_INLINE __attribute__((flatten)) static Memory *name ##_impl( \ + Memory *memory, State &state, ##__VA_ARGS__) + // Define a semantics implementing function. #define DEF_HELPER(name, ...) \ ALWAYS_INLINE __attribute__((flatten)) static auto name( \ diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index d6f2451f9..93b37d2da 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -15,6 +15,7 @@ */ #include "Arch.h" +#include "remill/BC/ABI.h" #include @@ -242,6 +243,18 @@ union DataProcessingAndMisc { } __attribute__((packed)); static_assert(sizeof(DataProcessingAndMisc) == 4, " "); +// Branch (Immediate) +union BranchI { + uint32_t flat; + struct { + int32_t imm24 : 24; + uint32_t H : 1; + uint32_t _101 : 3; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(BranchI) == 4, " "); + static constexpr auto kPCRegNum = 15u; static const char * const kIntRegName[] = { @@ -275,6 +288,16 @@ static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, op.action = action; } +//static void AddIntRegOp(Instruction &inst, const char *reg_name, unsigned size, +// Operand::Action action) { +// Operand::Register reg; +// reg.size = size; +// reg.name = reg_name; +// auto &op = inst.EmplaceOperand(reg); +// op.action = action; +//} + + static void AddImmOp(Instruction &inst, uint64_t value, unsigned size = 32, bool is_signed = false) { Operand::Immediate imm; @@ -330,22 +353,22 @@ static void AddShiftThenExtractOp(Instruction &inst, } -static void AddExtractThenShiftOp(Instruction &inst, - Operand::ShiftRegister::Shift shift_op, - Operand::ShiftRegister::Extend extend_op, - const char *reg_name, unsigned reg_size, - unsigned shift_size, unsigned extract_size) { - Operand::ShiftRegister shift_reg; - shift_reg.reg.name = reg_name; - shift_reg.reg.size = reg_size; - shift_reg.shift_op = shift_op; - shift_reg.shift_size = shift_size; - shift_reg.extract_size = extract_size; - shift_reg.extend_op = extend_op; - shift_reg.shift_first = false; - auto &op = inst.EmplaceOperand(shift_reg); - op.action = Operand::kActionRead; -} +//static void AddExtractThenShiftOp(Instruction &inst, +// Operand::ShiftRegister::Shift shift_op, +// Operand::ShiftRegister::Extend extend_op, +// const char *reg_name, unsigned reg_size, +// unsigned shift_size, unsigned extract_size) { +// Operand::ShiftRegister shift_reg; +// shift_reg.reg.name = reg_name; +// shift_reg.reg.size = reg_size; +// shift_reg.shift_op = shift_op; +// shift_reg.shift_size = shift_size; +// shift_reg.extract_size = extract_size; +// shift_reg.extend_op = extend_op; +// shift_reg.shift_first = false; +// auto &op = inst.EmplaceOperand(shift_reg); +// op.action = Operand::kActionRead; +//} // Note: Order is significant; extracted bits may be casted to this type. @@ -385,7 +408,6 @@ static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, if (carry_out) { if (!rotation_amount) { - // TODO(Sonya): remove the ShiftThenExtractOp op && do an extract only AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, Operand::ShiftRegister::kExtendUnsigned, "C", 8, 0, 1); @@ -414,7 +436,6 @@ static void ExtractAndZExtExpr(Instruction &inst, Operand &op, static void RORExpr(Instruction &inst, Operand &op, OperandExpression *shift_amount) { const auto word_type = inst.arch_for_decode->AddressType(); - const auto _31 = llvm::ConstantInt::get(word_type, 31u, false); const auto _32 = llvm::ConstantInt::get(word_type, 32u, false); shift_amount = inst.EmplaceBinaryOp(llvm::Instruction::URem, shift_amount, inst.EmplaceConstant(_32)); @@ -431,6 +452,7 @@ static void AddShiftRegCarryOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_reg_num) { // Create expression for the low 8 bits of the shift register + // TODO(Sonya): Replace with Emplace operands then emplace op manually at end AddIntRegOp(inst, shift_reg_num, 32u, Operand::kActionRead); ExtractAndZExtExpr(inst, inst.operands.back(), 8u, 32u); auto shift_val_expr_c = inst.operands.back().expr; @@ -441,7 +463,7 @@ static void AddShiftRegCarryOperand(Instruction &inst, uint32_t reg_num, const auto _31 = llvm::ConstantInt::get(word_type, 31u, false); const auto _32 = llvm::ConstantInt::get(word_type, 32u, false); - unsigned opcode; + unsigned opcode = 0; switch (static_cast(shift_type)) { case Shift::kShiftASR: // shift_size - 1 opcode = llvm::Instruction::AShr; @@ -469,6 +491,8 @@ static void AddShiftRegCarryOperand(Instruction &inst, uint32_t reg_num, shift_val_expr_c, inst.EmplaceConstant(_32)); break; + // TODO(Sonya): Add default with some LOG Error for incorrect shift type + } AddIntRegOp(inst, reg_num, 32u, Operand::kActionRead); @@ -617,100 +641,119 @@ static void AddShiftRegImmOperand(Instruction &inst, uint32_t reg_num, } // Decode the condition field and fill in the instruction conditions accordingly -static void DecodeCondition(Instruction &inst, uint32_t cond) { - inst.conditions.emplace_back(); - auto &lhs_cond = inst.conditions.back(); +static bool DecodeCondition(Instruction &inst, uint32_t cond) { + + auto _8_type = llvm::Type::getInt8Ty(*inst.arch_for_decode->context); + const auto _1 = llvm::ConstantInt::get(_8_type, 1u, false); + bool negate_conditions = false; + bool is_cond = true; + OperandExpression * op_expr = nullptr; switch (cond) { case 0b0001: - inst.negate_conditions = true; + negate_conditions = true; [[clang::fallthrough]]; case 0b0000: { - lhs_cond.kind = Condition::kTypeIsOne; - lhs_cond.lhs_reg.name = "Z"; - lhs_cond.lhs_reg.size = 8; + op_expr = inst.EmplaceRegister("Z"); break; } case 0b0011: - inst.negate_conditions = true; + negate_conditions = true; [[clang::fallthrough]]; case 0b0010: { - lhs_cond.kind = Condition::kTypeIsOne; - lhs_cond.lhs_reg.name = "C"; - lhs_cond.lhs_reg.size = 8; + op_expr = inst.EmplaceRegister("C"); break; } case 0b0101: - inst.negate_conditions = true; + negate_conditions = true; [[clang::fallthrough]]; case 0b0100: { - lhs_cond.kind = Condition::kTypeIsOne; - lhs_cond.lhs_reg.name = "N"; - lhs_cond.lhs_reg.size = 8; + op_expr = inst.EmplaceRegister("N"); break; } case 0b0111: - inst.negate_conditions = true; + negate_conditions = true; [[clang::fallthrough]]; case 0b0110: { - lhs_cond.kind = Condition::kTypeIsOne; - lhs_cond.lhs_reg.name = "V"; - lhs_cond.lhs_reg.size = 8; + op_expr = inst.EmplaceRegister("V"); break; } case 0b1001: - inst.negate_conditions = true; + negate_conditions = true; [[clang::fallthrough]]; case 0b1000: { - lhs_cond.kind = Condition::kTypeIsOne; - lhs_cond.lhs_reg.name = "C"; - lhs_cond.lhs_reg.size = 8; - - inst.conditions.emplace_back(); - auto &rhs_cond = inst.conditions.back(); - rhs_cond.kind = Condition::kTypeIsZero; - rhs_cond.rhs_reg.name = "Z"; - rhs_cond.rhs_reg.size = 8; + //lhs_cond.kind = Condition::kTypeIsOne; + auto c_expr = inst.EmplaceRegister("C"); + + //rhs_cond.kind = Condition::kTypeIsZero; + auto z_expr = inst.EmplaceRegister("Z"); + z_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, z_expr, + inst.EmplaceConstant(_1)); + op_expr = inst.EmplaceBinaryOp(llvm::Instruction::And, z_expr, c_expr); break; } case 0b1011: - inst.negate_conditions = true; + negate_conditions = true; [[clang::fallthrough]]; case 0b1010: { - lhs_cond.kind = Condition::kTypeIsEqual; - lhs_cond.lhs_reg.name = "N"; - lhs_cond.lhs_reg.size = 8; + //lhs_cond.kind = Condition::kTypeIsEqual; + auto n_expr = inst.EmplaceRegister("N"); - lhs_cond.rhs_reg.name = "V"; - lhs_cond.rhs_reg.size = 8; + auto v_expr = inst.EmplaceRegister("V"); + op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, n_expr, v_expr); + op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, op_expr, + inst.EmplaceConstant(_1)); break; } case 0b1101: - inst.negate_conditions = true; + negate_conditions = true; [[clang::fallthrough]]; case 0b1100: { - lhs_cond.kind = Condition::kTypeIsEqual; - lhs_cond.lhs_reg.name = "N"; - lhs_cond.lhs_reg.size = 8; - - lhs_cond.rhs_reg.name = "V"; - lhs_cond.rhs_reg.size = 8; - - inst.conditions.emplace_back(); - auto &rhs_cond = inst.conditions.back(); - rhs_cond.kind = Condition::kTypeIsZero; - rhs_cond.rhs_reg.name = "Z"; - rhs_cond.rhs_reg.size = 8; + //lhs_cond.kind = Condition::kTypeIsEqual; + auto n_expr = inst.EmplaceRegister("N"); + + auto v_expr = inst.EmplaceRegister("V"); + op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, n_expr, v_expr); + op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, op_expr, + inst.EmplaceConstant(_1)); + + //rhs_cond.kind = Condition::kTypeIsZero; + auto z_expr = inst.EmplaceRegister("Z"); + z_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, z_expr, + inst.EmplaceConstant(_1)); + op_expr = inst.EmplaceBinaryOp(llvm::Instruction::And, z_expr, op_expr); break; } case 0b1111: case 0b1110: - inst.conditions.pop_back(); + op_expr = inst.EmplaceConstant(_1); + is_cond = false; break; default: LOG(FATAL) << "Invalid condition bits " << cond << " in " << inst.Serialize(); break; } + + if (negate_conditions) { + op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, + op_expr, + inst.EmplaceConstant(_1)); + } + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.expr = op_expr; + op.type = Operand::kTypeExpression; + op.size = 8u; + op.action = Operand::kActionRead; + + inst.operands.emplace_back(); + auto &branch_taken = inst.operands.back(); + branch_taken.expr = inst.EmplaceVariable(kBranchTakenVariableName, _8_type); + branch_taken.type = Operand::kTypeExpression; + branch_taken.size = 8u; + branch_taken.action = Operand::kActionWrite; + + return is_cond; } std::optional EvalReg(const Instruction &inst, const Operand::Register &op) { @@ -832,7 +875,7 @@ std::optional EvalOperand(const Instruction &inst, const Operand &op) // else // ALUWritePC(result); static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, - InstEval *evaluator) { + InstEval *evaluator, bool is_cond) { if (rd == kPCRegNum) { // Updates the flags (condition codes) if (s) { @@ -847,8 +890,13 @@ static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, } else { auto res = evaluator(*src1, *src2); if (!res) { - inst.category = Instruction::kCategoryIndirectJump; - } else if (!inst.conditions.empty()) { + if (is_cond) { + inst.branch_not_taken_pc = inst.next_pc; + inst.category = Instruction::kCategoryConditionalIndirectJump; + } else { + inst.category = Instruction::kCategoryIndirectJump; + } + } else if (is_cond) { inst.branch_taken_pc = static_cast(*res); inst.branch_not_taken_pc = inst.next_pc; inst.category = Instruction::kCategoryConditionalBranch; @@ -930,11 +978,11 @@ static bool TryDecodeIntegerDataProcessingRRRI(Instruction &inst, uint32_t bits) const IntDataProcessingRRRI enc = {bits}; inst.function = kIdpNamesRRR[ (enc.opc << 1u) | enc.s]; - DecodeCondition(inst, enc.cond); + auto is_cond = DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); AddShiftRegImmOperand(inst, enc.rm, enc.type, enc.imm5, enc.s); - return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc], is_cond); } // Integer Data Processing (three register, register shift) @@ -977,7 +1025,7 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) const IntDataProcessingRRI enc = { bits }; inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s]; - DecodeCondition(inst, enc.cond); + auto is_cond = DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); // Raise the program counter to align to a multiple of 4 bytes @@ -990,7 +1038,7 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s); - return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc]); + return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc], is_cond); } static const char * const kMulAccRRR[] = { @@ -1111,6 +1159,9 @@ static const char * const kLoadSWUBIL[] = { // 11 0 1 != 1111 LDR (immediate) — pre-indexed // 11 1 0 STRB (immediate) — pre-indexed // 11 1 1 != 1111 LDRB (immediate) — pre-indexed +// LDR{}{} , [ {, #{+/-}}] +// LDR{}{} , [], #{+/-} +// LDR{}{} , [, #{+/-}]! template static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { const LoadStoreWUBIL enc = { bits }; @@ -1124,7 +1175,7 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { auto instruction = kLoadSWUBIL[enc.P << 3u | enc.W << 2u | enc.o2 << 1u | enc.o1]; inst.function = instruction; - DecodeCondition(inst, enc.cond); + auto is_cond = DecodeCondition(inst, enc.cond); // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes int64_t pc_adjust = 0; @@ -1153,7 +1204,16 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { AddAddrRegOp(inst, kIntRegName[enc.rn], 32, Operand::kActionRead, disp + pc_adjust); } - inst.category = Instruction::kCategoryNormal; + if (enc.rt == kPCRegNum) { + if (is_cond) { + inst.branch_not_taken_pc = inst.next_pc; + inst.category = Instruction::kCategoryConditionalIndirectJump; + } else { + inst.category = Instruction::kCategoryIndirectJump; + } + } else { + inst.category = Instruction::kCategoryNormal; + } return true; } @@ -1190,7 +1250,7 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; inst.function = instruction; - DecodeCondition(inst, enc.cond); + auto is_cond = DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); @@ -1206,7 +1266,7 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { } AddShiftRegImmOperand(inst, enc.rm, enc.type, enc.imm5, enc.s); - return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u], is_cond); } // Logical Arithmetic (three register, register shift) @@ -1247,7 +1307,7 @@ static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; inst.function = instruction; - DecodeCondition(inst, enc.cond); + auto is_cond = DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); // enc.opc == x0 @@ -1262,7 +1322,7 @@ static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { } ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s); - return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u]); + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u], is_cond); } //00 TST (register) @@ -1329,6 +1389,59 @@ static bool TryIntegerTestAndCompareRI(Instruction &inst, uint32_t bits) { } +// cond H +//!= 1111 0 B +//!= 1111 1 BL, BLX (immediate) — A1 +//1111 BL, BLX (immediate) — A2 +// Branch (immediate) +static bool TryBranchImm(Instruction &inst, uint32_t bits) { + const BranchI enc = { bits }; + auto is_cond = DecodeCondition(inst, enc.cond); + + auto is_func = false; + // PC used by the branch instruction is actually the address of the next instruction + auto target_pc = static_cast(inst.pc + 4 + static_cast(enc.imm24 << 2)); + if (enc.cond != 0b1111) { + if (!enc.H) { + target_pc = target_pc & ~0b11u; + if (is_cond) { + inst.function = "BCOND"; + } else { + inst.function = "B"; + } + } else { + target_pc = target_pc & ~0b11u; + inst.function = "BL"; + is_func = true; + } + } else { + inst.function = "BLX"; + target_pc = target_pc & ~0b11u; + target_pc = target_pc | (enc.H << 1); + is_func = true; + } + auto offset = static_cast(target_pc - inst.pc); + + AddAddrRegOp(inst, "PC", 32u, Operand::kActionRead, offset); + + inst.branch_taken_pc = target_pc; + inst.branch_not_taken_pc = inst.pc + 4; + if (is_cond) { + inst.category = Instruction::kCategoryConditionalBranch; + AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0); + } else if (is_func) { + LOG_IF(FATAL, is_cond) << "TODO: Conditional function calls"; + } else { + inst.category = Instruction::kCategoryDirectJump; + } + Operand::Register reg; + reg.size = 32u; + reg.name = remill::kNextPCVariableName; + auto &next_pc = inst.EmplaceOperand(reg); + next_pc.action = Operand::kActionWrite; + return true; +} + // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> static TryDecode * kDataProcessingRI[] = { @@ -1485,8 +1598,12 @@ static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { else { // TODO(Sonya): Branch, branch with link, and block data transfer -- op0 == 10x if (enc.op0 >> 1 == 0b10u) { - // return a result from another function for instruction categorizing - return nullptr; + // Branch (immediate) bit 25 == 1 + if (enc.op0 == 0b101u) { + return TryBranchImm; + } else { + return nullptr; + } // TODO(Sonya): System register access, Advanced SIMD, floating-point, and Supervisor call -- op0 == 11x } else { // return a result from another function for instruction categorizing diff --git a/lib/Arch/AArch32/Runtime/CMakeLists.txt b/lib/Arch/AArch32/Runtime/CMakeLists.txt index d1201dd79..278554cc0 100644 --- a/lib/Arch/AArch32/Runtime/CMakeLists.txt +++ b/lib/Arch/AArch32/Runtime/CMakeLists.txt @@ -56,7 +56,8 @@ function(add_runtime_helper target_name little_endian) "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/FLAGS.cpp" "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/COND.cpp" "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/LOGICAL.cpp" - "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/MEM.cpp" + "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/MEM.cpp" + "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/BRANCH.cpp" ) endfunction() diff --git a/lib/Arch/AArch32/Runtime/Instructions.cpp b/lib/Arch/AArch32/Runtime/Instructions.cpp index 468ef64dd..318efb649 100644 --- a/lib/Arch/AArch32/Runtime/Instructions.cpp +++ b/lib/Arch/AArch32/Runtime/Instructions.cpp @@ -61,7 +61,7 @@ DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; #include "lib/Arch/AArch32/Semantics/MEM.cpp" #include "lib/Arch/AArch32/Semantics/LOGICAL.cpp" //#include "lib/Arch/AArch64/Semantics/BITBYTE.cpp" -//#include "lib/Arch/AArch64/Semantics/BRANCH.cpp" +#include "lib/Arch/AArch32/Semantics/BRANCH.cpp" //#include "lib/Arch/AArch64/Semantics/CALL_RET.cpp" #include "lib/Arch/AArch32/Semantics/COND.cpp" //#include "lib/Arch/AArch64/Semantics/CONVERT.cpp" diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index 9f7e6383e..b5a2e6d7a 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -28,13 +28,15 @@ T AddWithCarryNZCV(State &state, T lhs, T rhs, T carry) { return result; } -DEF_SEM(AND, R32W dst, R32 src1, I32 src2) { + + +DEF_COND_SEM(AND, R32W dst, R32 src1, I32 src2) { auto value = Read(src2); Write(dst, UAnd(Read(src1), value)); return memory; } -DEF_SEM(ANDS, R32W dst, R32 src1, I32 src2, I8 carry_out) { +DEF_COND_SEM(ANDS, R32W dst, R32 src1, I32 src2, I8 carry_out) { auto value = Read(src2); auto res = UAnd(Read(src1), value); WriteZExt(dst, res); @@ -45,13 +47,13 @@ DEF_SEM(ANDS, R32W dst, R32 src1, I32 src2, I8 carry_out) { return memory; } -DEF_SEM(EOR, R32W dst, R32 src1, I32 src2) { +DEF_COND_SEM(EOR, R32W dst, R32 src1, I32 src2) { auto value = Read(src2); Write(dst, UXor(Read(src1), value)); return memory; } -DEF_SEM(EORS, R32W dst, R32 src1, I32 src2, I8 carry_out) { +DEF_COND_SEM(EORS, R32W dst, R32 src1, I32 src2, I8 carry_out) { auto value = Read(src2); auto res = UXor(Read(src1), value); Write(dst, res); @@ -62,13 +64,13 @@ DEF_SEM(EORS, R32W dst, R32 src1, I32 src2, I8 carry_out) { return memory; } -DEF_SEM(RSB, R32W dst, R32 src1, I32 src2) { +DEF_COND_SEM(RSB, R32W dst, R32 src1, I32 src2) { auto value = Read(src2); Write(dst, USub(value, Read(src1))); return memory; } -DEF_SEM(RSBS, R32W dst, R32 src1, I32 src2, I8 carry_out) { +DEF_COND_SEM(RSBS, R32W dst, R32 src1, I32 src2, I8 carry_out) { auto rhs = Read(src2); auto lhs = Read(src1); auto res = AddWithCarryNZCV(state, UNot(lhs), rhs, uint32_t(1)); @@ -76,13 +78,13 @@ DEF_SEM(RSBS, R32W dst, R32 src1, I32 src2, I8 carry_out) { return memory; } -DEF_SEM(SUB, R32W dst, R32 src1, I32 src2) { +DEF_COND_SEM(SUB, R32W dst, R32 src1, I32 src2) { auto value = Read(src2); Write(dst, USub(Read(src1), value)); return memory; } -DEF_SEM(SUBS, R32W dst, R32 src1, I32 src2, I8 carry_out) { +DEF_COND_SEM(SUBS, R32W dst, R32 src1, I32 src2, I8 carry_out) { auto rhs = Read(src2); auto lhs = Read(src1); auto res = AddWithCarryNZCV(state, lhs, UNot(rhs), uint32_t(1)); @@ -90,13 +92,13 @@ DEF_SEM(SUBS, R32W dst, R32 src1, I32 src2, I8 carry_out) { return memory; } -DEF_SEM(ADD, R32W dst, R32 src1, I32 src2) { +DEF_COND_SEM(ADD, R32W dst, R32 src1, I32 src2) { auto value = Read(src2); Write(dst, UAdd(Read(src1), value)); return memory; } -DEF_SEM(ADDS, R32W dst, R32 src1, I32 src2, I8 carry_out) { +DEF_COND_SEM(ADDS, R32W dst, R32 src1, I32 src2, I8 carry_out) { auto rhs = Read(src2); auto lhs = Read(src1); auto res = AddWithCarryNZCV(state, lhs, rhs, uint32_t(0)); @@ -104,13 +106,13 @@ DEF_SEM(ADDS, R32W dst, R32 src1, I32 src2, I8 carry_out) { return memory; } -DEF_SEM(ADC, R32W dst, R32 src1, I32 src2) { +DEF_COND_SEM(ADC, R32W dst, R32 src1, I32 src2) { auto value = Read(src2); Write(dst, UAdd(UAdd(Read(src1),value), uint32_t(state.sr.c))); return memory; } -DEF_SEM(ADCS, R32W dst, R32 src1, I32 src2, I8 carry_out) { +DEF_COND_SEM(ADCS, R32W dst, R32 src1, I32 src2, I8 carry_out) { auto rhs = Read(src2); auto lhs = Read(src1); auto res = AddWithCarryNZCV(state, lhs, rhs, uint32_t(state.sr.c)); @@ -118,13 +120,13 @@ DEF_SEM(ADCS, R32W dst, R32 src1, I32 src2, I8 carry_out) { return memory; } -DEF_SEM(SBC, R32W dst, R32 src1, I32 src2) { +DEF_COND_SEM(SBC, R32W dst, R32 src1, I32 src2) { auto value = Read(src2); Write(dst, UAdd(UAdd(Read(src1), UNot(value)), uint32_t(state.sr.c))); return memory; } -DEF_SEM(SBCS, R32W dst, R32 src1, I32 src2, I8 carry_out) { +DEF_COND_SEM(SBCS, R32W dst, R32 src1, I32 src2, I8 carry_out) { auto rhs = Read(src2); auto lhs = Read(src1); auto res = AddWithCarryNZCV(state, lhs, UNot(rhs), uint32_t(state.sr.c)); @@ -132,13 +134,13 @@ DEF_SEM(SBCS, R32W dst, R32 src1, I32 src2, I8 carry_out) { return memory; } -DEF_SEM(RSC, R32W dst, R32 src1, I32 src2) { +DEF_COND_SEM(RSC, R32W dst, R32 src1, I32 src2) { auto value = Read(src2); Write(dst, UAdd(UAdd(value, UNot(Read(src1))), uint32_t(state.sr.c))); return memory; } -DEF_SEM(RSCS, R32W dst, R32 src1, I32 src2, I8 carry_out) { +DEF_COND_SEM(RSCS, R32W dst, R32 src1, I32 src2, I8 carry_out) { auto rhs = Read(src2); auto lhs = Read(src1); auto res = AddWithCarryNZCV(state, UNot(lhs), rhs, uint32_t(state.sr.c)); @@ -166,7 +168,7 @@ DEF_ISEL(RSCrr) = RSC; DEF_ISEL(RSCSrr) = RSCS; namespace { -DEF_SEM(MUL, R32W dst, R32 src1, R32 src2, R32 src3) { +DEF_COND_SEM(MUL, R32W dst, R32 src1, R32 src2, R32 src3) { auto rhs = Signed(Read(src2)); auto lhs = Signed(Read(src1)); auto acc = Signed(Read(src3)); @@ -175,7 +177,7 @@ DEF_SEM(MUL, R32W dst, R32 src1, R32 src2, R32 src3) { return memory; } -DEF_SEM(MULS, R32W dst, R32 src1, R32 src2, R32 src3) { +DEF_COND_SEM(MULS, R32W dst, R32 src1, R32 src2, R32 src3) { auto rhs = Signed(Read(src2)); auto lhs = Signed(Read(src1)); auto acc = Signed(Read(src3)); @@ -187,7 +189,7 @@ DEF_SEM(MULS, R32W dst, R32 src1, R32 src2, R32 src3) { return memory; } -DEF_SEM(UMAAL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { +DEF_COND_SEM(UMAAL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { auto rhs = ZExt(Read(src3)); auto lhs = ZExt(Read(src2)); auto acc_hi = ZExt(Read(src1)); @@ -198,7 +200,7 @@ DEF_SEM(UMAAL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) return memory; } -DEF_SEM(MLS, R32W dst, R32 src1, R32 src2, R32 src3) { +DEF_COND_SEM(MLS, R32W dst, R32 src1, R32 src2, R32 src3) { auto rhs = Signed(Read(src2)); auto lhs = Signed(Read(src1)); auto acc = Signed(Read(src3)); @@ -207,7 +209,7 @@ DEF_SEM(MLS, R32W dst, R32 src1, R32 src2, R32 src3) { return memory; } -DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { +DEF_COND_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { auto rhs = ZExt(Read(src3)); auto lhs = ZExt(Read(src2)); auto acc = UOr(UShl(ZExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) @@ -217,7 +219,7 @@ DEF_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) return memory; } -DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { +DEF_COND_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { auto rhs = ZExt(Read(src3)); auto lhs = ZExt(Read(src2)); auto acc = UOr(UShl(ZExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) @@ -230,7 +232,7 @@ DEF_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4 return memory; } -DEF_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { +DEF_COND_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { // Not entirely sure about all the signed ops I have in here auto rhs = SExt(Signed(Read(src3))); auto lhs = SExt(Signed(Read(src2))); @@ -241,7 +243,7 @@ DEF_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) return memory; } -DEF_SEM(SMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { +DEF_COND_SEM(SMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { auto rhs = SExt(Signed(Read(src3))); auto lhs = SExt(Signed(Read(src2))); auto acc = SOr(SShl(SExt(Read(src1)), 32ul), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) diff --git a/lib/Arch/AArch32/Semantics/BRANCH.cpp b/lib/Arch/AArch32/Semantics/BRANCH.cpp new file mode 100644 index 000000000..6b987db01 --- /dev/null +++ b/lib/Arch/AArch32/Semantics/BRANCH.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + + + +namespace { + +DEF_SEM(B, R8, R8W, I32 taken_pc, R32W next_pc_dst) { + auto new_pc = Read(taken_pc); + Write(state.gpr.r15.dword, new_pc); + Write(next_pc_dst, new_pc); + return memory; +} + +DEF_SEM(BCOND, R8 cond, R8W branch_taken, I32 taken_pc, I32 not_taken_pc, + R32W next_pc_dst) { + auto c = Read(cond); + auto new_pc = Select(c, Read(taken_pc), Read(not_taken_pc)); + Write(state.gpr.r15.dword, new_pc); + Write(next_pc_dst, new_pc); + Write(branch_taken, c); + return memory; +} + +} //namespace + +DEF_ISEL(B) = B; +DEF_ISEL(BCOND) = BCOND; diff --git a/lib/Arch/AArch32/Semantics/COND.cpp b/lib/Arch/AArch32/Semantics/COND.cpp index a85781a43..b0a6e7adb 100644 --- a/lib/Arch/AArch32/Semantics/COND.cpp +++ b/lib/Arch/AArch32/Semantics/COND.cpp @@ -15,7 +15,7 @@ */ namespace { -DEF_SEM(TST, R32 src1, I32 src2, I8 carry_out) { +DEF_COND_SEM(TST, R32 src1, I32 src2, I8 carry_out) { auto res = UAnd(Read(src1), Read(src2)); state.sr.n = SignFlag(res); @@ -25,7 +25,7 @@ DEF_SEM(TST, R32 src1, I32 src2, I8 carry_out) { return memory; } -DEF_SEM(TEQ, R32 src1, I32 src2, I8 carry_out) { +DEF_COND_SEM(TEQ, R32 src1, I32 src2, I8 carry_out) { auto res = UXor(Read(src1), Read(src2)); state.sr.n = SignFlag(res); @@ -35,14 +35,14 @@ DEF_SEM(TEQ, R32 src1, I32 src2, I8 carry_out) { return memory; } -DEF_SEM(CMP, R32 src1, I32 src2, I8 carry_out) { +DEF_COND_SEM(CMP, R32 src1, I32 src2, I8 carry_out) { auto rhs = Read(src2); auto lhs = Read(src1); AddWithCarryNZCV(state, lhs, UNot(rhs), uint32_t(1)); return memory; } -DEF_SEM(CMN, R32 src1, I32 src2, I8 carry_out) { +DEF_COND_SEM(CMN, R32 src1, I32 src2, I8 carry_out) { auto rhs = Read(src2); auto lhs = Read(src1); AddWithCarryNZCV(state, lhs, rhs, uint32_t(0)); diff --git a/lib/Arch/AArch32/Semantics/LOGICAL.cpp b/lib/Arch/AArch32/Semantics/LOGICAL.cpp index 7c7b2dcab..d81c75f71 100644 --- a/lib/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/lib/Arch/AArch32/Semantics/LOGICAL.cpp @@ -15,14 +15,14 @@ */ namespace { -DEF_SEM(ORR, R32W dst, R32 src1, I32 src2){ +DEF_COND_SEM(ORR, R32W dst, R32 src1, I32 src2){ auto value = Read(src2); auto result = UOr(Read(src1), value); Write(dst, result); return memory; } -DEF_SEM(ORRS, R32W dst, R32 src1, I32 src2, I8 carry_out) { +DEF_COND_SEM(ORRS, R32W dst, R32 src1, I32 src2, I8 carry_out) { auto value = Read(src2); auto result = UOr(Read(src1), value); Write(dst, result); @@ -34,14 +34,14 @@ DEF_SEM(ORRS, R32W dst, R32 src1, I32 src2, I8 carry_out) { return memory; } -DEF_SEM(BIC, R32W dst, R32 src1, I32 src2){ +DEF_COND_SEM(BIC, R32W dst, R32 src1, I32 src2){ auto value = UNot(Read(src2)); auto result = UAnd(Read(src1), value); Write(dst, result); return memory; } -DEF_SEM(BICS, R32W dst, R32 src1, I32 src2, I8 carry_out) { +DEF_COND_SEM(BICS, R32W dst, R32 src1, I32 src2, I8 carry_out) { auto value = UNot(Read(src2)); auto result = UAnd(Read(src1), value); Write(dst, result); diff --git a/lib/Arch/AArch32/Semantics/MEM.cpp b/lib/Arch/AArch32/Semantics/MEM.cpp index 3c953c5f9..9db2703a2 100644 --- a/lib/Arch/AArch32/Semantics/MEM.cpp +++ b/lib/Arch/AArch32/Semantics/MEM.cpp @@ -16,34 +16,61 @@ namespace { // Offset -template -DEF_SEM(STR, DstType dst, R32 src1) { +DEF_COND_SEM(STR, M32W dst, R32 src1) { auto src = Read(src1); - Write(dst, TruncTo(src)); + Write(dst, TruncTo(src)); + return memory; +} + +DEF_COND_SEM(STRB, M8W dst, R32 src1) { + auto src = Read(src1); + Write(dst, TruncTo(src)); + return memory; +} + +// Pre + Post +DEF_COND_SEM(STRp, M32W dst, R32 src1, R32W dst_reg, R32 src2) { + auto src = Read(src1); + auto new_val = Read(src2); + Write(dst, TruncTo(src)); + Write(dst_reg, new_val); return memory; } // Pre + Post -template -DEF_SEM(STRp, DstType dst, R32 src1, R32W dst_reg, R32 src2) { +DEF_COND_SEM(STRBp, M8W dst, R32 src1, R32W dst_reg, R32 src2) { auto src = Read(src1); auto new_val = Read(src2); - Write(dst, TruncTo(src)); + Write(dst, TruncTo(src)); Write(dst_reg, new_val); return memory; } // Offset -template -DEF_SEM(LDR, SrcType src1, R32W dst) { +DEF_COND_SEM(LDR, M32 src1, R32W dst) { + auto src = Read(src1); + WriteZExt(dst, src); + return memory; +} + +// Offset +DEF_COND_SEM(LDRB, M8 src1, R32W dst) { + auto src = Read(src1); + WriteZExt(dst, src); + return memory; +} + +// Pre + Post +DEF_COND_SEM(LDRp, M32 src1, R32W dst, R32W dst_reg, R32 src2) { auto src = Read(src1); + auto new_val = Read(src2); WriteZExt(dst, src); + Write(dst_reg, new_val); return memory; } // Pre + Post -template -DEF_SEM(LDRp, SrcType src1, R32W dst, R32W dst_reg, R32 src2) { +DEF_COND_SEM(LDRBp, M8 src1, R32W dst, R32W dst_reg, R32 src2) { auto src = Read(src1); auto new_val = Read(src2); WriteZExt(dst, src); @@ -51,18 +78,34 @@ DEF_SEM(LDRp, SrcType src1, R32W dst, R32W dst_reg, R32 src2) { return memory; } -template -DEF_SEM(STRT, DstType dst, R32 src1, R32W dst_reg, R32 src2) { +DEF_COND_SEM(STRT, M32W dst, R32 src1, R32W dst_reg, R32 src2) { + memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + auto src = Read(src1); + auto new_val = Read(src2); + Write(dst, TruncTo(src)); + Write(dst_reg, new_val); + return memory; +} + +DEF_COND_SEM(STRTB, M8W dst, R32 src1, R32W dst_reg, R32 src2) { + memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + auto src = Read(src1); + auto new_val = Read(src2); + Write(dst, TruncTo(src)); + Write(dst_reg, new_val); + return memory; +} + +DEF_COND_SEM(LDRT, M32 src1, R32W dst, R32W dst_reg, R32 src2) { memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); auto src = Read(src1); auto new_val = Read(src2); - Write(dst, TruncTo(src)); + WriteZExt(dst, src); Write(dst_reg, new_val); return memory; } -template -DEF_SEM(LDRT, SrcType src1, R32W dst, R32W dst_reg, R32 src2) { +DEF_COND_SEM(LDRTB, M8 src1, R32W dst, R32W dst_reg, R32 src2) { memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); auto src = Read(src1); auto new_val = Read(src2); @@ -73,15 +116,15 @@ DEF_SEM(LDRT, SrcType src1, R32W dst, R32W dst_reg, R32 src2) { } // namespace -DEF_ISEL(STR) = STR; -DEF_ISEL(STRB) = STR; -DEF_ISEL(STRp) = STRp; -DEF_ISEL(STRBp) = STRp; -DEF_ISEL(LDR) = LDR; -DEF_ISEL(LDRB) = LDR; -DEF_ISEL(LDRp) = LDRp; -DEF_ISEL(LDRBp) = LDRp; -DEF_ISEL(STRT) = STRT; -DEF_ISEL(STRBT) = STRT; -DEF_ISEL(LDRT) = LDRT; -DEF_ISEL(LDRBT) = LDRT; +DEF_ISEL(STR) = STR; +DEF_ISEL(STRB) = STRB; +DEF_ISEL(STRp) = STRp; +DEF_ISEL(STRBp) = STRBp; +DEF_ISEL(LDR) = LDR; +DEF_ISEL(LDRB) = LDRB; +DEF_ISEL(LDRp) = LDRp; +DEF_ISEL(LDRBp) = LDRBp; +DEF_ISEL(STRT) = STRT; +DEF_ISEL(STRBT) = STRTB; +DEF_ISEL(LDRT) = LDRT; +DEF_ISEL(LDRBT) = LDRTB; diff --git a/lib/Arch/Instruction.cpp b/lib/Arch/Instruction.cpp index bb4d905d6..fb893ed59 100644 --- a/lib/Arch/Instruction.cpp +++ b/lib/Arch/Instruction.cpp @@ -316,7 +316,6 @@ Instruction::Instruction(void) has_branch_taken_delay_slot(false), has_branch_not_taken_delay_slot(false), in_delay_slot(false), - negate_conditions(false), category(Instruction::kCategoryInvalid) {} void Instruction::Reset(void) { @@ -330,11 +329,9 @@ void Instruction::Reset(void) { has_branch_taken_delay_slot = false; has_branch_not_taken_delay_slot = false; in_delay_slot = false; - negate_conditions = false; category = Instruction::kCategoryInvalid; arch_for_decode = nullptr; operands.clear(); - conditions.clear(); function.clear(); bytes.clear(); next_expr_index = 0; @@ -352,6 +349,10 @@ OperandExpression* Instruction::EmplaceRegister(const Register * reg) { return expr; } +OperandExpression * Instruction::EmplaceRegister(std::string_view reg_name) { + return EmplaceRegister(arch_for_decode->RegisterByName(reg_name)); +} + OperandExpression* Instruction::EmplaceConstant(llvm::Constant * val) { auto expr = AllocateExpression(); expr->emplace(val); @@ -569,8 +570,13 @@ Operand& Instruction::EmplaceOperand(const Operand::Address &addr_op) { auto reg_or_zero = [=](const Operand::Register & reg) { if (!reg.name.empty()) { - auto reg_pointer = arch_for_decode->RegisterByName(reg.name); - return EmplaceRegister(reg_pointer); + if (auto reg_pointer = arch_for_decode->RegisterByName(reg.name)) { + return EmplaceRegister(reg_pointer); + } else { + return EmplaceVariable( + reg.name, + llvm::Type::getIntNTy(*arch_for_decode->context, reg.size)); + } } else { return EmplaceConstant(zero); } @@ -725,17 +731,12 @@ std::string Instruction::Serialize(void) const { ss << " (COND_BRANCH (TAKEN " << std::hex << branch_taken_pc << ")" << " (NOT_TAKEN " << branch_not_taken_pc << std::dec << "))"; break; + case kCategoryConditionalIndirectJump: + ss << " (COND_BRANCH (TAKEN )" + << " (NOT_TAKEN " << branch_not_taken_pc << std::dec << "))"; default: break; } - auto end = ""; - auto sep = " (CONDS "; - for (const auto &cond: conditions) { - ss << sep << cond.Serialize(); - sep = " AND "; - end = ")"; - } - ss << end; ss << ")"; return ss.str(); } diff --git a/lib/BC/InstructionLifter.cpp b/lib/BC/InstructionLifter.cpp index 9741b2781..1c7606092 100644 --- a/lib/BC/InstructionLifter.cpp +++ b/lib/BC/InstructionLifter.cpp @@ -726,7 +726,9 @@ llvm::Value *InstructionLifter::LiftExpressionOperandRec( case llvm::Instruction::Or: return ir.CreateOr(lhs, rhs); case llvm::Instruction::URem: - return ir.CreateURem(lhs, rhs); + return ir.CreateURem(lhs, rhs); + case llvm::Instruction::Xor: + return ir.CreateXor(lhs, rhs); default: LOG(FATAL) << "Invalid Expression " diff --git a/lib/BC/TraceLifter.cpp b/lib/BC/TraceLifter.cpp index 6c1607508..f7ee591b4 100644 --- a/lib/BC/TraceLifter.cpp +++ b/lib/BC/TraceLifter.cpp @@ -603,6 +603,34 @@ bool TraceLifter::Impl::Lift( not_taken_block = new_not_taken_block; } + llvm::BranchInst::Create(taken_block, not_taken_block, + LoadBranchTaken(block), block); + break; + } + case Instruction::kCategoryConditionalIndirectJump: { + auto taken_block = llvm::BasicBlock::Create(context, "", func); + AddTerminatingTailCall(taken_block, intrinsics->jump); + auto not_taken_block = GetOrCreateBranchNotTakenBlock(); + + // If we might need to add delay slots, then try to lift the delayed + // instruction on each side of the conditional branch, injecting in + // new blocks (for the delayed instruction) between the branch + // and its original targets. + if (try_delay) { + auto new_taken_block = llvm::BasicBlock::Create(context, "", func); + auto new_not_taken_block = llvm::BasicBlock::Create(context, "", + func); + + try_add_delay_slot(true, new_taken_block); + try_add_delay_slot(false, new_not_taken_block); + + llvm::BranchInst::Create(taken_block, new_taken_block); + llvm::BranchInst::Create(not_taken_block, new_not_taken_block); + + taken_block = new_taken_block; + not_taken_block = new_not_taken_block; + } + llvm::BranchInst::Create(taken_block, not_taken_block, LoadBranchTaken(block), block); break; From fc7920e8abefc063a78e3ad65ba9493d6a9e9401 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 18 Nov 2020 11:27:32 -0500 Subject: [PATCH 088/130] Created AddExprOp, cleaned up some expressions in reg shifted reg, and updated some occurances of ShiftThenExtractOp with ExtractAndZExtExpr --- lib/Arch/AArch32/Decode.cpp | 144 ++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 70 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 93b37d2da..a333f0ba9 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -288,15 +288,25 @@ static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, op.action = action; } -//static void AddIntRegOp(Instruction &inst, const char *reg_name, unsigned size, -// Operand::Action action) { -// Operand::Register reg; -// reg.size = size; -// reg.name = reg_name; -// auto &op = inst.EmplaceOperand(reg); -// op.action = action; -//} +static void AddIntRegOp(Instruction &inst, const char *reg_name, unsigned size, + Operand::Action action) { + Operand::Register reg; + reg.size = size; + reg.name = reg_name; + auto &op = inst.EmplaceOperand(reg); + op.action = action; +} +static void AddExprOp(Instruction &inst, OperandExpression *op_expr, + uint64_t size = 32, Operand::Action action = + Operand::kActionRead) { + inst.operands.emplace_back(); + auto &op = inst.operands.back(); + op.expr = op_expr; + op.type = Operand::kTypeExpression; + op.size = size; + op.action = action; +} static void AddImmOp(Instruction &inst, uint64_t value, unsigned size = 32, bool is_signed = false) { @@ -390,6 +400,25 @@ static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { return Operand::ShiftRegister::kShiftInvalid; } +// Do an extraction and zero extension on an expression +static void ExtractAndZExtExpr(Instruction &inst, OperandExpression *&op_expr, + unsigned int extract_size, + unsigned int extend_size) { + auto extract_type = llvm::Type::getIntNTy(*(inst.arch_for_decode->context), + extract_size); + auto extend_type = llvm::Type::getIntNTy(*(inst.arch_for_decode->context), + extract_size); + + // Extract bits + op_expr = inst.EmplaceUnaryOp(llvm::Instruction::Trunc, op_expr, + extract_type); + // ZExtend operand to extend_size + if (extend_size > extract_size) { + op_expr = inst.EmplaceUnaryOp(llvm::Instruction::ZExt, op_expr, + extend_type); + } +} + // Note: This function adds either 1 or 2 operands in total // an op and an optional additional carry_out op // Used to handle semantics for: @@ -408,9 +437,8 @@ static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, if (carry_out) { if (!rotation_amount) { - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, - Operand::ShiftRegister::kExtendUnsigned, "C", 8, 0, - 1); + AddIntRegOp(inst, "C", 8u, Operand::kActionRead); + ExtractAndZExtExpr(inst, inst.operands.back().expr, 1u, 8u); } else { AddImmOp(inst, (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u); @@ -418,45 +446,28 @@ static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, } } -// Do an extraction and zero extension on an expression -static void ExtractAndZExtExpr(Instruction &inst, Operand &op, - unsigned int extract_size, - unsigned int extend_size) { - auto extract_type = llvm::Type::getIntNTy(*(inst.arch_for_decode->context), - extract_size); - auto extend_type = llvm::Type::getIntNTy(*(inst.arch_for_decode->context), - extend_size); - // Extract bits - op.expr = inst.EmplaceUnaryOp(llvm::Instruction::Trunc, op.expr, - extract_type); - // ZExtend operand back to I8 - op.expr = inst.EmplaceUnaryOp(llvm::Instruction::ZExt, op.expr, extend_type); -} - -static void RORExpr(Instruction &inst, Operand &op, +static void RORExpr(Instruction &inst, OperandExpression * &op_expr, OperandExpression *shift_amount) { const auto word_type = inst.arch_for_decode->AddressType(); const auto _32 = llvm::ConstantInt::get(word_type, 32u, false); + shift_amount = inst.EmplaceBinaryOp(llvm::Instruction::URem, shift_amount, inst.EmplaceConstant(_32)); - auto lhs_expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, op.expr, + auto lhs_expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, op_expr, shift_amount); - auto rhs_expr = inst.EmplaceBinaryOp(llvm::Instruction::Shl, op.expr, + auto rhs_expr = inst.EmplaceBinaryOp(llvm::Instruction::Shl, op_expr, inst.EmplaceBinaryOp(llvm::Instruction::Sub, inst.EmplaceConstant(_32), shift_amount)); - op.expr = inst.EmplaceBinaryOp(llvm::Instruction::Or, lhs_expr, rhs_expr); + op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Or, lhs_expr, rhs_expr); } static void AddShiftRegCarryOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_reg_num) { // Create expression for the low 8 bits of the shift register - // TODO(Sonya): Replace with Emplace operands then emplace op manually at end - AddIntRegOp(inst, shift_reg_num, 32u, Operand::kActionRead); - ExtractAndZExtExpr(inst, inst.operands.back(), 8u, 32u); - auto shift_val_expr_c = inst.operands.back().expr; - inst.operands.pop_back(); + auto shift_val_expr_c = inst.EmplaceRegister(kIntRegName[shift_reg_num]); + ExtractAndZExtExpr(inst, shift_val_expr_c, 8u, 32u); const auto word_type = inst.arch_for_decode->AddressType(); const auto _1 = llvm::ConstantInt::get(word_type, 1u, false); @@ -491,50 +502,55 @@ static void AddShiftRegCarryOperand(Instruction &inst, uint32_t reg_num, shift_val_expr_c, inst.EmplaceConstant(_32)); break; - // TODO(Sonya): Add default with some LOG Error for incorrect shift type + default: + LOG(FATAL) << "Invalid shift bits " << shift_type << " in " + << inst.Serialize(); } - AddIntRegOp(inst, reg_num, 32u, Operand::kActionRead); - inst.operands.back().expr = inst.EmplaceBinaryOp(opcode, - inst.operands.back().expr, - shift_val_expr_c); + auto carry_expr = inst.EmplaceRegister(kIntRegName[reg_num]); + carry_expr = inst.EmplaceBinaryOp(opcode, carry_expr, shift_val_expr_c); // Extract the sign bit and extend back to I8 - ExtractAndZExtExpr(inst, inst.operands.back(), 1u, 8u); + ExtractAndZExtExpr(inst, carry_expr, 1u, 8u); + + AddExprOp(inst, carry_expr); } // Note: this has no RRX shift operation static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_reg_num, bool carry_out) { - AddIntRegOp(inst, reg_num, 32u, Operand::kActionRead); + auto op_expr = inst.EmplaceRegister(kIntRegName[reg_num]); // Create expression for the low 8 bits of the shift register - AddIntRegOp(inst, shift_reg_num, 32u, Operand::kActionRead); - ExtractAndZExtExpr(inst, inst.operands.back(), 8u, 32u); - auto shift_val_expr = inst.operands.back().expr; - inst.operands.pop_back(); + auto shift_val_expr = inst.EmplaceRegister(kIntRegName[shift_reg_num]); + ExtractAndZExtExpr(inst, shift_val_expr, 8u, 32u); // Create the shift and carry expressions operations switch (static_cast(shift_type)) { case Shift::kShiftASR: - inst.operands.back().expr = inst.EmplaceBinaryOp( - llvm::Instruction::AShr, inst.operands.back().expr, shift_val_expr); + op_expr = inst.EmplaceBinaryOp(llvm::Instruction::AShr, op_expr, + shift_val_expr); break; case Shift::kShiftLSL: - inst.operands.back().expr = inst.EmplaceBinaryOp( - llvm::Instruction::Shl, inst.operands.back().expr, shift_val_expr); + op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Shl, op_expr, + shift_val_expr); break; case Shift::kShiftLSR: - inst.operands.back().expr = inst.EmplaceBinaryOp( - llvm::Instruction::LShr, inst.operands.back().expr, shift_val_expr); + op_expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, op_expr, + shift_val_expr); break; case Shift::kShiftROR: - RORExpr(inst, inst.operands.back(), shift_val_expr); + RORExpr(inst, op_expr, shift_val_expr); break; + default: + LOG(FATAL) << "Invalid shift bits " << shift_type << " in " + << inst.Serialize(); } + AddExprOp(inst, op_expr); + if (carry_out) { AddShiftRegCarryOperand(inst, reg_num, shift_type, shift_reg_num); } @@ -547,7 +563,6 @@ static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, static void AddShiftImmCarryOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_size, const char * carry_reg_name) { - auto is_rrx = false; if (!shift_size && shift_type == Shift::kShiftROR) { shift_size = 1; @@ -555,9 +570,8 @@ static void AddShiftImmCarryOperand(Instruction &inst, } if (!shift_size) { - AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, - Operand::ShiftRegister::kExtendUnsigned, - carry_reg_name, 8, 0, 1); + AddIntRegOp(inst, carry_reg_name, 8u, Operand::kActionRead); + ExtractAndZExtExpr(inst, inst.operands.back().expr, 1u, 8u); } else { switch (static_cast(shift_type)) { case Shift::kShiftASR: @@ -577,10 +591,8 @@ static void AddShiftImmCarryOperand(Instruction &inst, break; case Shift::kShiftROR: if (is_rrx) { - AddShiftThenExtractOp(inst, - Operand::ShiftRegister::kShiftUnsignedRight, - Operand::ShiftRegister::kExtendUnsigned, - kIntRegName[reg_num], 32, 0, 1); + AddIntRegOp(inst, reg_num, 32u, Operand::kActionRead); + ExtractAndZExtExpr(inst, inst.operands.back().expr, 1u, 32u); } else { AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, @@ -682,10 +694,7 @@ static bool DecodeCondition(Instruction &inst, uint32_t cond) { negate_conditions = true; [[clang::fallthrough]]; case 0b1000: { - //lhs_cond.kind = Condition::kTypeIsOne; auto c_expr = inst.EmplaceRegister("C"); - - //rhs_cond.kind = Condition::kTypeIsZero; auto z_expr = inst.EmplaceRegister("Z"); z_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, z_expr, inst.EmplaceConstant(_1)); @@ -696,9 +705,7 @@ static bool DecodeCondition(Instruction &inst, uint32_t cond) { negate_conditions = true; [[clang::fallthrough]]; case 0b1010: { - //lhs_cond.kind = Condition::kTypeIsEqual; auto n_expr = inst.EmplaceRegister("N"); - auto v_expr = inst.EmplaceRegister("V"); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, n_expr, v_expr); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, op_expr, @@ -709,15 +716,11 @@ static bool DecodeCondition(Instruction &inst, uint32_t cond) { negate_conditions = true; [[clang::fallthrough]]; case 0b1100: { - //lhs_cond.kind = Condition::kTypeIsEqual; auto n_expr = inst.EmplaceRegister("N"); - auto v_expr = inst.EmplaceRegister("V"); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, n_expr, v_expr); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, op_expr, inst.EmplaceConstant(_1)); - - //rhs_cond.kind = Condition::kTypeIsZero; auto z_expr = inst.EmplaceRegister("Z"); z_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, z_expr, inst.EmplaceConstant(_1)); @@ -739,6 +742,7 @@ static bool DecodeCondition(Instruction &inst, uint32_t cond) { op_expr, inst.EmplaceConstant(_1)); } + inst.operands.emplace_back(); auto &op = inst.operands.back(); op.expr = op_expr; From 2c5bee6c298225518d6b0d3340814208eaa20a52 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 18 Nov 2020 18:09:40 -0500 Subject: [PATCH 089/130] Updates from testing register shifted by register value inst --- lib/Arch/AArch32/Decode.cpp | 115 ++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index a333f0ba9..1c7ba05ab 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -401,13 +401,13 @@ static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { } // Do an extraction and zero extension on an expression -static void ExtractAndZExtExpr(Instruction &inst, OperandExpression *&op_expr, +static OperandExpression * ExtractAndZExtExpr(Instruction &inst, OperandExpression * op_expr, unsigned int extract_size, unsigned int extend_size) { auto extract_type = llvm::Type::getIntNTy(*(inst.arch_for_decode->context), extract_size); auto extend_type = llvm::Type::getIntNTy(*(inst.arch_for_decode->context), - extract_size); + extend_size); // Extract bits op_expr = inst.EmplaceUnaryOp(llvm::Instruction::Trunc, op_expr, @@ -417,6 +417,7 @@ static void ExtractAndZExtExpr(Instruction &inst, OperandExpression *&op_expr, op_expr = inst.EmplaceUnaryOp(llvm::Instruction::ZExt, op_expr, extend_type); } + return op_expr; } // Note: This function adds either 1 or 2 operands in total @@ -438,7 +439,9 @@ static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, if (carry_out) { if (!rotation_amount) { AddIntRegOp(inst, "C", 8u, Operand::kActionRead); - ExtractAndZExtExpr(inst, inst.operands.back().expr, 1u, 8u); + inst.operands.back().expr = ExtractAndZExtExpr(inst, + inst.operands.back().expr, + 1u, 8u); } else { AddImmOp(inst, (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u); @@ -446,8 +449,9 @@ static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, } } -static void RORExpr(Instruction &inst, OperandExpression * &op_expr, - OperandExpression *shift_amount) { +static OperandExpression * RORExpr(Instruction &inst, + OperandExpression * op_expr, + OperandExpression * shift_amount) { const auto word_type = inst.arch_for_decode->AddressType(); const auto _32 = llvm::ConstantInt::get(word_type, 32u, false); @@ -460,41 +464,50 @@ static void RORExpr(Instruction &inst, OperandExpression * &op_expr, inst.EmplaceConstant(_32), shift_amount)); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Or, lhs_expr, rhs_expr); + return op_expr; } static void AddShiftRegCarryOperand(Instruction &inst, uint32_t reg_num, uint32_t shift_type, uint32_t shift_reg_num) { + auto carry_expr = inst.EmplaceRegister(kIntRegName[reg_num]); + // Create expression for the low 8 bits of the shift register auto shift_val_expr_c = inst.EmplaceRegister(kIntRegName[shift_reg_num]); - ExtractAndZExtExpr(inst, shift_val_expr_c, 8u, 32u); + shift_val_expr_c = ExtractAndZExtExpr(inst, shift_val_expr_c, 8u, 32u); const auto word_type = inst.arch_for_decode->AddressType(); const auto _1 = llvm::ConstantInt::get(word_type, 1u, false); const auto _31 = llvm::ConstantInt::get(word_type, 31u, false); const auto _32 = llvm::ConstantInt::get(word_type, 32u, false); - unsigned opcode = 0; switch (static_cast(shift_type)) { - case Shift::kShiftASR: // shift_size - 1 - opcode = llvm::Instruction::AShr; + case Shift::kShiftASR: + // shift_size - 1u shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Sub, shift_val_expr_c, inst.EmplaceConstant(_1)); + carry_expr = inst.EmplaceBinaryOp(llvm::Instruction::AShr, carry_expr, + shift_val_expr_c); break; - case Shift::kShiftLSL: // 32 - shift_size - opcode = llvm::Instruction::Shl; + case Shift::kShiftLSL: + // 32u - shift_size shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Sub, inst.EmplaceConstant(_32), shift_val_expr_c); + carry_expr = inst.EmplaceBinaryOp(llvm::Instruction::Shl, carry_expr, + shift_val_expr_c); break; - case Shift::kShiftLSR: // shift_size - 1 - opcode = llvm::Instruction::LShr; + case Shift::kShiftLSR: + // shift_size - 1u shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Sub, shift_val_expr_c, inst.EmplaceConstant(_1)); + carry_expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, carry_expr, + shift_val_expr_c); break; case Shift::kShiftROR: + // (shift_size + 31u) % 32u shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Add, shift_val_expr_c, inst.EmplaceConstant(_31)); @@ -508,11 +521,8 @@ static void AddShiftRegCarryOperand(Instruction &inst, uint32_t reg_num, } - auto carry_expr = inst.EmplaceRegister(kIntRegName[reg_num]); - carry_expr = inst.EmplaceBinaryOp(opcode, carry_expr, shift_val_expr_c); - // Extract the sign bit and extend back to I8 - ExtractAndZExtExpr(inst, carry_expr, 1u, 8u); + carry_expr = ExtractAndZExtExpr(inst, carry_expr, 1u, 8u); AddExprOp(inst, carry_expr); } @@ -525,7 +535,7 @@ static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, // Create expression for the low 8 bits of the shift register auto shift_val_expr = inst.EmplaceRegister(kIntRegName[shift_reg_num]); - ExtractAndZExtExpr(inst, shift_val_expr, 8u, 32u); + shift_val_expr = ExtractAndZExtExpr(inst, shift_val_expr, 8u, 32u); // Create the shift and carry expressions operations switch (static_cast(shift_type)) { @@ -542,7 +552,7 @@ static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, shift_val_expr); break; case Shift::kShiftROR: - RORExpr(inst, op_expr, shift_val_expr); + op_expr = RORExpr(inst, op_expr, shift_val_expr); break; default: LOG(FATAL) << "Invalid shift bits " << shift_type << " in " @@ -571,7 +581,9 @@ static void AddShiftImmCarryOperand(Instruction &inst, if (!shift_size) { AddIntRegOp(inst, carry_reg_name, 8u, Operand::kActionRead); - ExtractAndZExtExpr(inst, inst.operands.back().expr, 1u, 8u); + inst.operands.back().expr = ExtractAndZExtExpr(inst, + inst.operands.back().expr, + 1u, 8u); } else { switch (static_cast(shift_type)) { case Shift::kShiftASR: @@ -592,7 +604,7 @@ static void AddShiftImmCarryOperand(Instruction &inst, case Shift::kShiftROR: if (is_rrx) { AddIntRegOp(inst, reg_num, 32u, Operand::kActionRead); - ExtractAndZExtExpr(inst, inst.operands.back().expr, 1u, 32u); + inst.operands.back().expr = ExtractAndZExtExpr(inst, inst.operands.back().expr, 1u, 32u); } else { AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, @@ -743,19 +755,9 @@ static bool DecodeCondition(Instruction &inst, uint32_t cond) { inst.EmplaceConstant(_1)); } - inst.operands.emplace_back(); - auto &op = inst.operands.back(); - op.expr = op_expr; - op.type = Operand::kTypeExpression; - op.size = 8u; - op.action = Operand::kActionRead; - - inst.operands.emplace_back(); - auto &branch_taken = inst.operands.back(); - branch_taken.expr = inst.EmplaceVariable(kBranchTakenVariableName, _8_type); - branch_taken.type = Operand::kTypeExpression; - branch_taken.size = 8u; - branch_taken.action = Operand::kActionWrite; + AddExprOp(inst, op_expr, 8u); + AddExprOp(inst, inst.EmplaceVariable(kBranchTakenVariableName, _8_type), 8u, + Operand::kActionWrite); return is_cond; } @@ -993,14 +995,15 @@ static bool TryDecodeIntegerDataProcessingRRRI(Instruction &inst, uint32_t bits) static bool TryDecodeIntegerDataProcessingRRRR(Instruction &inst, uint32_t bits) { const IntDataProcessingRRRR enc = { bits }; - inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s]; - DecodeCondition(inst, enc.cond); - if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum || enc.rm == kPCRegNum) { inst.category = Instruction::kCategoryError; return false; } + + inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s]; + DecodeCondition(inst, enc.cond); + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); AddShiftRegRegOperand(inst, enc.rm, enc.type, enc.rs, enc.s); @@ -1266,7 +1269,7 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { AddImmOp(inst, 0); // enc.opc == 11 } else { - AddImmOp(inst, 1); + AddImmOp(inst, ~0u); } AddShiftRegImmOperand(inst, enc.rm, enc.type, enc.imm5, enc.s); @@ -1277,17 +1280,16 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { static bool TryLogicalArithmeticRRRR(Instruction &inst, uint32_t bits) { const LogicalArithRRRR enc = { bits }; - auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; - - inst.function = instruction; - DecodeCondition(inst, enc.cond); - if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum || enc.rm == kPCRegNum) { inst.category = Instruction::kCategoryError; return false; } + inst.function = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); // enc.opc == x0 if (!(enc.opc & 0b1u)) { @@ -1297,7 +1299,7 @@ static bool TryLogicalArithmeticRRRR(Instruction &inst, uint32_t bits) { AddImmOp(inst, 0); // enc.opc == 11 } else { - AddImmOp(inst, 1); + AddImmOp(inst, ~0u); } AddShiftRegRegOperand(inst, enc.rm, enc.type, enc.rs, enc.s); inst.category = Instruction::kCategoryNormal; @@ -1308,9 +1310,7 @@ static bool TryLogicalArithmeticRRRR(Instruction &inst, uint32_t bits) { static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { const LogicalArithmeticRRI enc = { bits }; - auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; - - inst.function = instruction; + inst.function = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; auto is_cond = DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); @@ -1322,7 +1322,7 @@ static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { AddImmOp(inst, 0u); // enc.opc == 11 } else { - AddImmOp(inst, 1u); + AddImmOp(inst, ~0u); } ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s); @@ -1360,15 +1360,14 @@ static bool TryIntegerTestAndCompareRRI(Instruction &inst, uint32_t bits) { static bool TryIntegerTestAndCompareRRR(Instruction &inst, uint32_t bits) { const IntTestCompRRR enc = { bits }; - auto instruction = kIntegerTestAndCompareR[enc.opc]; + if (enc.rn == kPCRegNum || enc.rs == kPCRegNum || enc.rm == kPCRegNum) { + inst.category = Instruction::kCategoryError; + return false; + } - inst.function = instruction; + inst.function = kIntegerTestAndCompareR[enc.opc]; DecodeCondition(inst, enc.cond); - if (enc.rn == kPCRegNum || enc.rs == kPCRegNum || enc.rm == kPCRegNum) { - inst.category = Instruction::kCategoryError; - return false; - } AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); AddShiftRegRegOperand(inst, enc.rm, enc.type, enc.rs, 1u); @@ -1600,11 +1599,15 @@ static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { } // op0 == 1xx else { - // TODO(Sonya): Branch, branch with link, and block data transfer -- op0 == 10x + // Branch, branch with link, and block data transfer -- op0 == 10x if (enc.op0 >> 1 == 0b10u) { - // Branch (immediate) bit 25 == 1 + // Branch (immediate) op0 == 101 if (enc.op0 == 0b101u) { return TryBranchImm; + // TODO(Sonya): Exception Save/Restore -- cond == 1111, op0 == 100 + } else if (enc.cond == 0b1111u) { + return nullptr; + // TODO(Sonya): Load/Store Multiple -- cond != 1111, op0 == 100 } else { return nullptr; } From 98104dc69a7562b7e1409c352dc6a39a89134b94 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 18 Nov 2020 18:15:10 -0500 Subject: [PATCH 090/130] Fix to ROR in AddShiftRegCarryOperand --- lib/Arch/AArch32/Decode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 1c7ba05ab..08561f94c 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -511,7 +511,7 @@ static void AddShiftRegCarryOperand(Instruction &inst, uint32_t reg_num, shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Add, shift_val_expr_c, inst.EmplaceConstant(_31)); - shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::URem, + carry_expr = inst.EmplaceBinaryOp(llvm::Instruction::URem, shift_val_expr_c, inst.EmplaceConstant(_32)); break; From 2ff5cdd4559359e130b32ac3b47c7ea88ae676b1 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 19 Nov 2020 09:24:43 -0500 Subject: [PATCH 091/130] Corrected negation in DecodeCondition --- lib/Arch/AArch32/Decode.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 08561f94c..13a8ba2ab 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -668,7 +668,8 @@ static void AddShiftRegImmOperand(Instruction &inst, uint32_t reg_num, static bool DecodeCondition(Instruction &inst, uint32_t cond) { auto _8_type = llvm::Type::getInt8Ty(*inst.arch_for_decode->context); - const auto _1 = llvm::ConstantInt::get(_8_type, 1u, false); + // Use ~0 -> 11111111 with XOR op for negation + const auto _1 = llvm::ConstantInt::get(_8_type, ~0u, false); bool negate_conditions = false; bool is_cond = true; From 9c0ea88043d66fc272ce58fa1d2d42bc76cf7662 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 19 Nov 2020 09:29:51 -0500 Subject: [PATCH 092/130] DecodeCondition edit --- lib/Arch/AArch32/Decode.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 13a8ba2ab..a2082bc73 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -668,8 +668,9 @@ static void AddShiftRegImmOperand(Instruction &inst, uint32_t reg_num, static bool DecodeCondition(Instruction &inst, uint32_t cond) { auto _8_type = llvm::Type::getInt8Ty(*inst.arch_for_decode->context); + const auto _1 = llvm::ConstantInt::get(_8_type, 1u, false); // Use ~0 -> 11111111 with XOR op for negation - const auto _1 = llvm::ConstantInt::get(_8_type, ~0u, false); + const auto negate = llvm::ConstantInt::get(_8_type, ~0u, false); bool negate_conditions = false; bool is_cond = true; @@ -710,7 +711,7 @@ static bool DecodeCondition(Instruction &inst, uint32_t cond) { auto c_expr = inst.EmplaceRegister("C"); auto z_expr = inst.EmplaceRegister("Z"); z_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, z_expr, - inst.EmplaceConstant(_1)); + inst.EmplaceConstant(negate)); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::And, z_expr, c_expr); break; } @@ -722,7 +723,7 @@ static bool DecodeCondition(Instruction &inst, uint32_t cond) { auto v_expr = inst.EmplaceRegister("V"); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, n_expr, v_expr); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, op_expr, - inst.EmplaceConstant(_1)); + inst.EmplaceConstant(negate)); break; } case 0b1101: @@ -733,10 +734,10 @@ static bool DecodeCondition(Instruction &inst, uint32_t cond) { auto v_expr = inst.EmplaceRegister("V"); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, n_expr, v_expr); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, op_expr, - inst.EmplaceConstant(_1)); + inst.EmplaceConstant(negate)); auto z_expr = inst.EmplaceRegister("Z"); z_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, z_expr, - inst.EmplaceConstant(_1)); + inst.EmplaceConstant(negate)); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::And, z_expr, op_expr); break; } From 2a6398c6a280bea937eef9db0e244b6339b58ea2 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 19 Nov 2020 11:14:28 -0500 Subject: [PATCH 093/130] DecodeCondition and AddShiftRegCarryOperand edits --- lib/Arch/AArch32/Decode.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index a2082bc73..baac6b9c8 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -495,7 +495,7 @@ static void AddShiftRegCarryOperand(Instruction &inst, uint32_t reg_num, shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Sub, inst.EmplaceConstant(_32), shift_val_expr_c); - carry_expr = inst.EmplaceBinaryOp(llvm::Instruction::Shl, carry_expr, + carry_expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, carry_expr, shift_val_expr_c); break; case Shift::kShiftLSR: @@ -511,9 +511,11 @@ static void AddShiftRegCarryOperand(Instruction &inst, uint32_t reg_num, shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Add, shift_val_expr_c, inst.EmplaceConstant(_31)); - carry_expr = inst.EmplaceBinaryOp(llvm::Instruction::URem, + shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::URem, shift_val_expr_c, inst.EmplaceConstant(_32)); + carry_expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, carry_expr, + shift_val_expr_c); break; default: LOG(FATAL) << "Invalid shift bits " << shift_type << " in " @@ -752,9 +754,8 @@ static bool DecodeCondition(Instruction &inst, uint32_t cond) { } if (negate_conditions) { - op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, - op_expr, - inst.EmplaceConstant(_1)); + op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, op_expr, + inst.EmplaceConstant(negate)); } AddExprOp(inst, op_expr, 8u); @@ -1598,9 +1599,8 @@ static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { // return a result from another function for instruction categorizing return nullptr; } - } // op0 == 1xx - else { + } else { // Branch, branch with link, and block data transfer -- op0 == 10x if (enc.op0 >> 1 == 0b10u) { // Branch (immediate) op0 == 101 From 84f9efa139912e67f4376c1924c269f659813328 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 19 Nov 2020 11:24:06 -0500 Subject: [PATCH 094/130] Updated arch_for_decode to arch --- lib/Arch/AArch32/Decode.cpp | 12 ++++++------ lib/Arch/Instruction.cpp | 28 ++++++++++++++-------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index baac6b9c8..cc90b09d5 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -404,9 +404,9 @@ static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { static OperandExpression * ExtractAndZExtExpr(Instruction &inst, OperandExpression * op_expr, unsigned int extract_size, unsigned int extend_size) { - auto extract_type = llvm::Type::getIntNTy(*(inst.arch_for_decode->context), + auto extract_type = llvm::Type::getIntNTy(*(inst.arch->context), extract_size); - auto extend_type = llvm::Type::getIntNTy(*(inst.arch_for_decode->context), + auto extend_type = llvm::Type::getIntNTy(*(inst.arch->context), extend_size); // Extract bits @@ -452,7 +452,7 @@ static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, static OperandExpression * RORExpr(Instruction &inst, OperandExpression * op_expr, OperandExpression * shift_amount) { - const auto word_type = inst.arch_for_decode->AddressType(); + const auto word_type = inst.arch->AddressType(); const auto _32 = llvm::ConstantInt::get(word_type, 32u, false); shift_amount = inst.EmplaceBinaryOp(llvm::Instruction::URem, shift_amount, @@ -476,7 +476,7 @@ static void AddShiftRegCarryOperand(Instruction &inst, uint32_t reg_num, auto shift_val_expr_c = inst.EmplaceRegister(kIntRegName[shift_reg_num]); shift_val_expr_c = ExtractAndZExtExpr(inst, shift_val_expr_c, 8u, 32u); - const auto word_type = inst.arch_for_decode->AddressType(); + const auto word_type = inst.arch->AddressType(); const auto _1 = llvm::ConstantInt::get(word_type, 1u, false); const auto _31 = llvm::ConstantInt::get(word_type, 31u, false); const auto _32 = llvm::ConstantInt::get(word_type, 32u, false); @@ -669,7 +669,7 @@ static void AddShiftRegImmOperand(Instruction &inst, uint32_t reg_num, // Decode the condition field and fill in the instruction conditions accordingly static bool DecodeCondition(Instruction &inst, uint32_t cond) { - auto _8_type = llvm::Type::getInt8Ty(*inst.arch_for_decode->context); + auto _8_type = llvm::Type::getInt8Ty(*inst.arch->context); const auto _1 = llvm::ConstantInt::get(_8_type, 1u, false); // Use ~0 -> 11111111 with XOR op for negation const auto negate = llvm::ConstantInt::get(_8_type, ~0u, false); @@ -1642,7 +1642,7 @@ bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_byte inst.has_branch_taken_delay_slot = false; inst.has_branch_not_taken_delay_slot = false; inst.arch_name = arch_name; - inst.arch_for_decode = this; + inst.arch = this; inst.category = Instruction::kCategoryInvalid; inst.operands.clear(); if (!inst.bytes.empty() && inst.bytes.data() == inst_bytes.data()) { diff --git a/lib/Arch/Instruction.cpp b/lib/Arch/Instruction.cpp index ed38face9..959fa35f2 100644 --- a/lib/Arch/Instruction.cpp +++ b/lib/Arch/Instruction.cpp @@ -350,7 +350,7 @@ OperandExpression* Instruction::EmplaceRegister(const Register * reg) { } OperandExpression * Instruction::EmplaceRegister(std::string_view reg_name) { - return EmplaceRegister(arch_for_decode->RegisterByName(reg_name)); + return EmplaceRegister(arch->RegisterByName(reg_name)); } OperandExpression* Instruction::EmplaceConstant(llvm::Constant * val) { @@ -390,10 +390,10 @@ Operand & Instruction::EmplaceOperand(const Operand::Register ®_op) { auto &op = operands.back(); op.type = Operand::kTypeExpression; op.size = reg_op.size; - if (auto reg = arch_for_decode->RegisterByName(reg_op.name)) { + if (auto reg = arch->RegisterByName(reg_op.name)) { op.expr = EmplaceRegister(reg); } else { - auto &context = *arch_for_decode->context; + auto &context = *arch->context; auto ty = llvm::Type::getIntNTy(context, reg_op.size); op.expr = EmplaceVariable(reg_op.name, ty); } @@ -403,11 +403,11 @@ Operand & Instruction::EmplaceOperand(const Operand::Register ®_op) { Operand &Instruction::EmplaceOperand(const Operand::Immediate &imm_op) { operands.emplace_back(); auto &op = operands.back(); - auto &context = *arch_for_decode->context; + auto &context = *arch->context; - auto ty = llvm::Type::getIntNTy(context, arch_for_decode->address_size); + auto ty = llvm::Type::getIntNTy(context, arch->address_size); op.expr = EmplaceConstant(llvm::ConstantInt::get(ty, imm_op.val, imm_op.is_signed)); - op.size = arch_for_decode->address_size; + op.size = arch->address_size; op.type = Operand::kTypeExpression; return op; } @@ -416,11 +416,11 @@ Operand &Instruction::EmplaceOperand(const Operand::ShiftRegister &shift_op) { operands.emplace_back(); auto &op = operands.back(); op.type = Operand::kTypeExpression; - op.size = arch_for_decode->address_size; + op.size = arch->address_size; auto &arch_reg = shift_op.reg; - auto &context = *arch_for_decode->context; - auto reg = arch_for_decode->RegisterByName(arch_reg.name); + auto &context = *arch->context; + auto reg = arch->RegisterByName(arch_reg.name); auto reg_type = reg->type; auto reg_size = reg->size * 8u; auto op_type = llvm::Type::getIntNTy(context, op.size); @@ -556,9 +556,9 @@ Operand& Instruction::EmplaceOperand(const Operand::Address &addr_op) { operands.emplace_back(); auto &op = operands.back(); - const auto word_type = arch_for_decode->AddressType(); + const auto word_type = arch->AddressType(); const auto zero = llvm::ConstantInt::get(word_type, 0, false); - const auto word_size = arch_for_decode->address_size; + const auto word_size = arch->address_size; CHECK(word_size >= addr_op.base_reg.size)<< "Memory base register " << addr_op.base_reg.name << "for instruction at " << std::hex << pc @@ -570,12 +570,12 @@ Operand& Instruction::EmplaceOperand(const Operand::Address &addr_op) { auto reg_or_zero = [=](const Operand::Register & reg) { if (!reg.name.empty()) { - if (auto reg_pointer = arch_for_decode->RegisterByName(reg.name)) { + if (auto reg_pointer = arch->RegisterByName(reg.name)) { return EmplaceRegister(reg_pointer); } else { return EmplaceVariable( reg.name, - llvm::Type::getIntNTy(*arch_for_decode->context, reg.size)); + llvm::Type::getIntNTy(*arch->context, reg.size)); } } else { return EmplaceConstant(zero); @@ -617,7 +617,7 @@ Operand& Instruction::EmplaceOperand(const Operand::Address &addr_op) { // used in 64-bit). if (addr_op.address_size < word_size) { auto addr_type = llvm::Type::getIntNTy( - *arch_for_decode->context, static_cast(addr_op.address_size)); + *arch->context, static_cast(addr_op.address_size)); addr = EmplaceUnaryOp(llvm::Instruction::Trunc, addr, addr_type); addr = EmplaceUnaryOp(llvm::Instruction::ZExt, addr, word_type); From ddf993c65e28450e7968105749e04210b97a1ff5 Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 20 Nov 2020 16:02:06 -0500 Subject: [PATCH 095/130] Halfword Multiply and Accumulate --- include/remill/Arch/AArch32/Runtime/State.h | 4 +- lib/Arch/AArch32/Decode.cpp | 155 ++++++++++++++++---- lib/Arch/AArch32/Semantics/BINARY.cpp | 93 +++++++++--- 3 files changed, 209 insertions(+), 43 deletions(-) diff --git a/include/remill/Arch/AArch32/Runtime/State.h b/include/remill/Arch/AArch32/Runtime/State.h index bd8558e78..ebeb0668a 100644 --- a/include/remill/Arch/AArch32/Runtime/State.h +++ b/include/remill/Arch/AArch32/Runtime/State.h @@ -94,8 +94,10 @@ struct alignas(8) SR final { uint8_t idc; // Input denormal (cumulative). uint8_t _10; uint8_t ioc; // Invalid operation (cumulative). + uint8_t _11; + uint8_t q; // Sticky overflow bit. - uint8_t _padding[6]; + uint8_t _padding[4]; } __attribute__((packed)); struct alignas(16) State final : public ArchState { diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index cc90b09d5..940e9cb73 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -92,6 +92,26 @@ union MultiplyAndAccumulate { } __attribute__((packed)); static_assert(sizeof(MultiplyAndAccumulate) == 4, " "); +// Halfword Multiply and Accumulate +union HMultiplyAndAccumulate { + uint32_t flat; + struct { + uint32_t rn : 4; + uint32_t _0_b4 : 1; + uint32_t N : 1; + uint32_t M : 1; + uint32_t _1 : 1; + uint32_t rm : 4; + uint32_t ra : 4; + uint32_t rd : 4; + uint32_t _0_b20 : 1; + uint32_t opc : 2; + uint32_t _00010 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(HMultiplyAndAccumulate) == 4, " "); + // Load/Store Word, Unsigned Byte (immediate, literal) union LoadStoreWUBIL { uint32_t flat; @@ -401,7 +421,8 @@ static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { } // Do an extraction and zero extension on an expression -static OperandExpression * ExtractAndZExtExpr(Instruction &inst, OperandExpression * op_expr, +template +static OperandExpression * ExtractAndExtExpr(Instruction &inst, OperandExpression * op_expr, unsigned int extract_size, unsigned int extend_size) { auto extract_type = llvm::Type::getIntNTy(*(inst.arch->context), @@ -414,8 +435,7 @@ static OperandExpression * ExtractAndZExtExpr(Instruction &inst, OperandExpressi extract_type); // ZExtend operand to extend_size if (extend_size > extract_size) { - op_expr = inst.EmplaceUnaryOp(llvm::Instruction::ZExt, op_expr, - extend_type); + op_expr = inst.EmplaceUnaryOp(ext, op_expr, extend_type); } return op_expr; } @@ -439,7 +459,7 @@ static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, if (carry_out) { if (!rotation_amount) { AddIntRegOp(inst, "C", 8u, Operand::kActionRead); - inst.operands.back().expr = ExtractAndZExtExpr(inst, + inst.operands.back().expr = ExtractAndExtExpr(inst, inst.operands.back().expr, 1u, 8u); } else { @@ -474,7 +494,7 @@ static void AddShiftRegCarryOperand(Instruction &inst, uint32_t reg_num, // Create expression for the low 8 bits of the shift register auto shift_val_expr_c = inst.EmplaceRegister(kIntRegName[shift_reg_num]); - shift_val_expr_c = ExtractAndZExtExpr(inst, shift_val_expr_c, 8u, 32u); + shift_val_expr_c = ExtractAndExtExpr(inst, shift_val_expr_c, 8u, 32u); const auto word_type = inst.arch->AddressType(); const auto _1 = llvm::ConstantInt::get(word_type, 1u, false); @@ -524,7 +544,7 @@ static void AddShiftRegCarryOperand(Instruction &inst, uint32_t reg_num, } // Extract the sign bit and extend back to I8 - carry_expr = ExtractAndZExtExpr(inst, carry_expr, 1u, 8u); + carry_expr = ExtractAndExtExpr(inst, carry_expr, 1u, 8u); AddExprOp(inst, carry_expr); } @@ -537,7 +557,7 @@ static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, // Create expression for the low 8 bits of the shift register auto shift_val_expr = inst.EmplaceRegister(kIntRegName[shift_reg_num]); - shift_val_expr = ExtractAndZExtExpr(inst, shift_val_expr, 8u, 32u); + shift_val_expr = ExtractAndExtExpr(inst, shift_val_expr, 8u, 32u); // Create the shift and carry expressions operations switch (static_cast(shift_type)) { @@ -583,7 +603,7 @@ static void AddShiftImmCarryOperand(Instruction &inst, if (!shift_size) { AddIntRegOp(inst, carry_reg_name, 8u, Operand::kActionRead); - inst.operands.back().expr = ExtractAndZExtExpr(inst, + inst.operands.back().expr = ExtractAndExtExpr(inst, inst.operands.back().expr, 1u, 8u); } else { @@ -606,7 +626,7 @@ static void AddShiftImmCarryOperand(Instruction &inst, case Shift::kShiftROR: if (is_rrx) { AddIntRegOp(inst, reg_num, 32u, Operand::kActionRead); - inst.operands.back().expr = ExtractAndZExtExpr(inst, inst.operands.back().expr, 1u, 32u); + inst.operands.back().expr = ExtractAndExtExpr(inst, inst.operands.back().expr, 1u, 32u); } else { AddShiftThenExtractOp(inst, Operand::ShiftRegister::kShiftUnsignedRight, @@ -1052,22 +1072,22 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) } static const char * const kMulAccRRR[] = { - [0b0000] = "MULrr", - [0b0001] = "MULSrr", - [0b0010] = "MLArr", - [0b0011] = "MLASrr", - [0b0100] = "UMAALrr", + [0b0000] = "MUL", + [0b0001] = "MULS", + [0b0010] = "MLA", + [0b0011] = "MLAS", + [0b0100] = "UMAAL", [0b0101] = nullptr, - [0b0110] = "MLSrr", + [0b0110] = "MLS", [0b0111] = nullptr, - [0b1000] = "UMULLrr", - [0b1001] = "UMULLSrr", - [0b1010] = "UMLALrr", - [0b1011] = "UMLALSrr", - [0b1100] = "SMULLrr", - [0b1101] = "SMULLSrr", - [0b1110] = "SMLALrr", - [0b1111] = "SMLALSrr" + [0b1000] = "UMULL", + [0b1001] = "UMULLS", + [0b1010] = "UMLAL", + [0b1011] = "UMLALS", + [0b1100] = "SMULL", + [0b1101] = "SMULLS", + [0b1110] = "SMLAL", + [0b1111] = "SMLALS" }; //000 MUL, MULS @@ -1130,6 +1150,91 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { return true; } +static const char * const kHMulAccRRR[] = { + [0b000] = "SMLAh", + [0b001] = "SMLAh", + [0b010] = "SMLAWh", + [0b011] = "SMULWh", + [0b100] = "SMLALh", + [0b101] = "SMLALh", + [0b110] = "SMULh", + [0b111] = "SMULh", +}; + +//opc M N +//00 SMLABB, SMLABT, SMLATB, SMLATT — writes to Rd, read Ra, Rm, Rn +//01 0 0 SMLAWB, SMLAWT — SMLAWB — writes to Rd, read Ra, Rm, Rn +//01 0 1 SMULWB, SMULWT — SMULWB — writes to Rd, read Rm, Rn +//01 1 0 SMLAWB, SMLAWT — SMLAWT — writes to Rd, read Ra, Rm, Rn +//01 1 1 SMULWB, SMULWT — SMULWT — writes to Rd, read Rm, Rn +//10 SMLALBB, SMLALBT, SMLALTB, SMLALTT — writes to Rd, Ra, read Rd, Ra, Rm, Rn +//11 SMULBB, SMULBT, SMULTB, SMULTT — writes to Rd, read Rm, Rn +// Halfword Multiply and Accumulate +// - under Data-processing and miscellaneous instructions +static bool TryHalfwordDecodeMultiplyAndAccumulate(Instruction &inst, + uint32_t bits) { + + const HMultiplyAndAccumulate enc = { bits }; + // if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; + // if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; + if (enc.rd == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum) { + inst.category = Instruction::kCategoryError; + } + + inst.function = kHMulAccRRR[(enc.opc << 1) | enc.N]; + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + + // SMLALBB, SMLALBT, SMLALTB, SMLALTT add write ra and read rd + if (enc.opc == 0b10u) { + AddIntRegOp(inst, enc.ra, 32, Operand::kActionWrite); + AddIntRegOp(inst, enc.rd, 32, Operand::kActionRead); + } + + + // Ra + if (enc.opc == 0b10u || (enc.opc == 0b1u && !enc.N) || !enc.opc) { + AddIntRegOp(inst, enc.ra, 32, Operand::kActionRead); + } else if (enc.opc != 0b11u) { + AddImmOp(inst, 0); + } + + const auto word_type = inst.arch->AddressType(); + const auto _16 = llvm::ConstantInt::get(word_type, 16u, false); + + // Rm + AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); + if (enc.M) { + inst.operands.back().expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, + inst.operands.back().expr, + inst.EmplaceConstant(_16)); + inst.operands.back().expr = ExtractAndExtExpr( + inst, inst.operands.back().expr, 16u, 32u); + } else { + inst.operands.back().expr = ExtractAndExtExpr( + inst, inst.operands.back().expr, 16u, 32u); + } + + // Rn + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + if (enc.opc != 0b1u) { + if (enc.N) { + inst.operands.back().expr = inst.EmplaceBinaryOp( + llvm::Instruction::LShr, inst.operands.back().expr, + inst.EmplaceConstant(_16)); + inst.operands.back().expr = ExtractAndExtExpr( + inst, inst.operands.back().expr, 16u, 32u); + } else { + inst.operands.back().expr = ExtractAndExtExpr( + inst, inst.operands.back().expr, 16u, 32u); + } + } + + inst.category = Instruction::kCategoryNormal; + return true; +} + static const char * const kLoadSWUBIL[] = { [0b0000] = "STRp", [0b0001] = "LDRp", @@ -1538,9 +1643,9 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { // TODO(Sonya): Miscellaneous if (!enc.op2) { return nullptr; - // TODO(Sonya): Halfword Multiply and Accumulate + // Halfword Multiply and Accumulate } else { - return nullptr; + return TryHalfwordDecodeMultiplyAndAccumulate; } // op1 != 10xx0 } else { diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index b5a2e6d7a..7d24374f4 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -167,6 +167,8 @@ DEF_ISEL(SBCSrr) = SBCS; DEF_ISEL(RSCrr) = RSC; DEF_ISEL(RSCSrr) = RSCS; + +// Multiply and Accumulate namespace { DEF_COND_SEM(MUL, R32W dst, R32 src1, R32 src2, R32 src3) { auto rhs = Signed(Read(src2)); @@ -233,10 +235,9 @@ DEF_COND_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 } DEF_COND_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { - // Not entirely sure about all the signed ops I have in here auto rhs = SExt(Signed(Read(src3))); auto lhs = SExt(Signed(Read(src2))); - auto acc = SOr(SShl(SExt(Read(src1)), 32ul), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto acc = SOr(SShl(SExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); Write(dst_hi, TruncTo(SShr(res, 32ul))); Write(dst_lo, TruncTo(res)); @@ -246,7 +247,7 @@ DEF_COND_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 DEF_COND_SEM(SMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { auto rhs = SExt(Signed(Read(src3))); auto lhs = SExt(Signed(Read(src2))); - auto acc = SOr(SShl(SExt(Read(src1)), 32ul), SExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto acc = SOr(SShl(SExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); @@ -257,18 +258,76 @@ DEF_COND_SEM(SMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 } } // namespace -DEF_ISEL(MULrr) = MUL; -DEF_ISEL(MULSrr) = MULS; -DEF_ISEL(MLArr) = MUL; -DEF_ISEL(MLASrr) = MULS; -DEF_ISEL(MLSrr) = MLS; -DEF_ISEL(UMAALrr) = UMAAL; -DEF_ISEL(UMULLrr) = UMULL; -DEF_ISEL(UMULLSrr) = UMULLS; -DEF_ISEL(UMLALrr) = UMULL; -DEF_ISEL(UMLALSrr) = UMULLS; -DEF_ISEL(SMULLrr) = SMULL; -DEF_ISEL(SMULLSrr) = SMULLS; -DEF_ISEL(SMLALrr) = SMULL; -DEF_ISEL(SMLALSrr) = SMULLS; +DEF_ISEL(MUL) = MUL; +DEF_ISEL(MULS) = MULS; +DEF_ISEL(MLA) = MUL; +DEF_ISEL(MLAS) = MULS; +DEF_ISEL(MLS) = MLS; +DEF_ISEL(UMAAL) = UMAAL; +DEF_ISEL(UMULL) = UMULL; +DEF_ISEL(UMULLS) = UMULLS; +DEF_ISEL(UMLAL) = UMULL; +DEF_ISEL(UMLALS) = UMULLS; +DEF_ISEL(SMULL) = SMULL; +DEF_ISEL(SMULLS) = SMULLS; +DEF_ISEL(SMLAL) = SMULL; +DEF_ISEL(SMLALS) = SMULLS; + + +// Halfword Multiply and Accumulate +namespace { +DEF_COND_SEM(SMLAh, R32W dst, R32 src1, R32 src2, R32 src3) { + auto rhs = SExt(Read(src3)); + auto lhs = SExt(Read(src2)); + auto acc = SExt(Read(src1)); + auto res = SAdd(SMul(lhs, rhs), acc); + auto trun_res = TruncTo(res); + Write(dst, trun_res); + + // if result != SInt(result<31:0>) then // Signed overflow + // PSTATE.Q = '1'; + state.sr.q = UOr(state.sr.q, SCmpNeq(res, SExt(trun_res))); + return memory; +} + +DEF_COND_SEM(SMLAWh, R32W dst, R32 src1, R32 src2, R32 src3) { + auto rhs = SExt(Read(src3)); + auto lhs = SExt(Read(src2)); + auto acc = SShl(SExt(Read(src1)), 16ul); // SInt(R[a]) << 16 + auto res = SShr(SAdd(SMul(lhs, rhs), acc), 16ul); // R[d] = result<47:16> + auto trun_res = TruncTo(res); + Write(dst, trun_res); + + // if (result >> 16) != SInt(R[d]) then // Signed overflow + // PSTATE.Q = '1'; + state.sr.q = UOr(state.sr.q, SCmpNeq(res, SExt(trun_res))); + return memory; +} + +DEF_COND_SEM(SMULh, R32W dst, R32 src1, R32 src2) { + auto rhs = Signed(Read(src2)); + auto lhs = Signed(Read(src1)); + auto res = SMul(lhs, rhs); + Write(dst, TruncTo(res)); + return memory; + // Signed overflow cannot occur +} + +DEF_COND_SEM(SMLALh, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { + auto rhs = SExt(Read(src4)); + auto lhs = SExt(Read(src3)); + auto acc = SOr(SShl(SExt(Read(src1)), 32ul), Signed(ZExt(Read(src2)))); // UInt(R[dHi]:R[dLo]) + auto res = SAdd(SMul(lhs, rhs), acc); + Write(dst_hi, TruncTo(SShr(res, 32ul))); + Write(dst_lo, TruncTo(res)); + return memory; +} + +}// namespace + +DEF_ISEL(SMULh) = SMULh; +DEF_ISEL(SMLAh) = SMLAh; +DEF_ISEL(SMLALh) = SMLALh; +DEF_ISEL(SMULWh) = SMLAWh; +DEF_ISEL(SMLAWh) = SMLAWh; From df2e779e5da7b7e9b56460257cf306945272c774 Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 20 Nov 2020 18:04:03 -0500 Subject: [PATCH 096/130] Edits from testing Halfword Multiply and Accumulate --- lib/Arch/AArch32/Decode.cpp | 44 ++++++++++++++++----------- lib/Arch/AArch32/Semantics/BINARY.cpp | 23 ++++++++++---- lib/BC/Util.cpp | 2 +- 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 940e9cb73..9c624537e 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -1151,24 +1151,32 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { } static const char * const kHMulAccRRR[] = { - [0b000] = "SMLAh", - [0b001] = "SMLAh", - [0b010] = "SMLAWh", - [0b011] = "SMULWh", - [0b100] = "SMLALh", - [0b101] = "SMLALh", - [0b110] = "SMULh", - [0b111] = "SMULh", + [0b0000] = "SMLABB", // (M == 0 && N == 0) + [0b0010] = "SMLABT", // (M == 1 && N == 0) + [0b0001] = "SMLATB", // (M == 0 && N == 1) + [0b0011] = "SMLATT", // (M == 1 && N == 1) + [0b0100] = "SMLAWB", + [0b0101] = "SMULWB", + [0b0110] = "SMLAWT", + [0b0111] = "SMULWT", + [0b1000] = "SMLALBB", // (M == 0 && N == 0) + [0b1010] = "SMLALBT", // (M == 1 && N == 0) + [0b1001] = "SMLALTB", // (M == 0 && N == 1) + [0b1011] = "SMLALTT", // (M == 1 && N == 1) + [0b1100] = "SMULBB", // (M == 0 && N == 0) + [0b1110] = "SMULBT", // (M == 1 && N == 0) + [0b1101] = "SMULTB", // (M == 0 && N == 1) + [0b1111] = "SMULTT", // (M == 1 && N == 1) }; -//opc M N -//00 SMLABB, SMLABT, SMLATB, SMLATT — writes to Rd, read Ra, Rm, Rn -//01 0 0 SMLAWB, SMLAWT — SMLAWB — writes to Rd, read Ra, Rm, Rn -//01 0 1 SMULWB, SMULWT — SMULWB — writes to Rd, read Rm, Rn -//01 1 0 SMLAWB, SMLAWT — SMLAWT — writes to Rd, read Ra, Rm, Rn -//01 1 1 SMULWB, SMULWT — SMULWT — writes to Rd, read Rm, Rn -//10 SMLALBB, SMLALBT, SMLALTB, SMLALTT — writes to Rd, Ra, read Rd, Ra, Rm, Rn -//11 SMULBB, SMULBT, SMULTB, SMULTT — writes to Rd, read Rm, Rn +// opc M N +// 00 SMLABB, SMLABT, SMLATB, SMLATT — writes to Rd, read Ra, Rm, Rn +// 01 0 0 SMLAWB, SMLAWT — SMLAWB — writes to Rd, read Ra, Rm, Rn +// 01 0 1 SMULWB, SMULWT — SMULWB — writes to Rd, read Rm, Rn +// 01 1 0 SMLAWB, SMLAWT — SMLAWT — writes to Rd, read Ra, Rm, Rn +// 01 1 1 SMULWB, SMULWT — SMULWT — writes to Rd, read Rm, Rn +// 10 SMLALBB, SMLALBT, SMLALTB, SMLALTT — writes to Rd, Ra, read Rd, Ra, Rm, Rn +// 11 SMULBB, SMULBT, SMULTB, SMULTT — writes to Rd, read Rm, Rn // Halfword Multiply and Accumulate // - under Data-processing and miscellaneous instructions static bool TryHalfwordDecodeMultiplyAndAccumulate(Instruction &inst, @@ -1181,7 +1189,7 @@ static bool TryHalfwordDecodeMultiplyAndAccumulate(Instruction &inst, inst.category = Instruction::kCategoryError; } - inst.function = kHMulAccRRR[(enc.opc << 1) | enc.N]; + inst.function = kHMulAccRRR[(enc.opc << 2u) | (enc.M << 1u) | enc.N]; DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); @@ -1736,7 +1744,7 @@ static uint32_t BytesToBits(const uint8_t *bytes) { } } // namespace -// Decode an instuction. +// Decode an instruction bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes, Instruction &inst) const { diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index 7d24374f4..ccfc5d520 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -316,7 +316,7 @@ DEF_COND_SEM(SMULh, R32W dst, R32 src1, R32 src2) { DEF_COND_SEM(SMLALh, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { auto rhs = SExt(Read(src4)); auto lhs = SExt(Read(src3)); - auto acc = SOr(SShl(SExt(Read(src1)), 32ul), Signed(ZExt(Read(src2)))); // UInt(R[dHi]:R[dLo]) + auto acc = SOr(SShl(SExt(Read(src1)), 32ul), ZExt(Read(src2))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); Write(dst_hi, TruncTo(SShr(res, 32ul))); Write(dst_lo, TruncTo(res)); @@ -325,9 +325,20 @@ DEF_COND_SEM(SMLALh, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 }// namespace -DEF_ISEL(SMULh) = SMULh; -DEF_ISEL(SMLAh) = SMLAh; -DEF_ISEL(SMLALh) = SMLALh; -DEF_ISEL(SMULWh) = SMLAWh; -DEF_ISEL(SMLAWh) = SMLAWh; +DEF_ISEL(SMLABB) = SMLAh; +DEF_ISEL(SMLABT) = SMLAh; +DEF_ISEL(SMLATB) = SMLAh; +DEF_ISEL(SMLATT) = SMLAh; +DEF_ISEL(SMLAWB) = SMLAWh; +DEF_ISEL(SMULWB) = SMLAWh; +DEF_ISEL(SMLAWT) = SMLAWh; +DEF_ISEL(SMULWT) = SMLAWh; +DEF_ISEL(SMULBB) = SMULh; +DEF_ISEL(SMULBT) = SMULh; +DEF_ISEL(SMULTB) = SMULh; +DEF_ISEL(SMULTT) = SMULh; +DEF_ISEL(SMLALBB) = SMLALh; +DEF_ISEL(SMLALBT) = SMLALh; +DEF_ISEL(SMLALTB) = SMLALh; +DEF_ISEL(SMLALTT) = SMLALh; diff --git a/lib/BC/Util.cpp b/lib/BC/Util.cpp index 300fe2d25..adbc14dbd 100644 --- a/lib/BC/Util.cpp +++ b/lib/BC/Util.cpp @@ -822,7 +822,7 @@ static llvm::Constant *MoveConstantIntoModule(llvm::Constant *c, !llvm::isa(c) && !llvm::isa(c) && !c->needsRelocation()) { - LOG(ERROR) << "Not moving: " << LLVMThingToString(c); + //LOG(ERROR) << "Not moving: " << LLVMThingToString(c); return c; } #endif From 9e275b2fdab330158524c5f2b23187daf44f463a Mon Sep 17 00:00:00 2001 From: sschriner Date: Mon, 23 Nov 2020 13:20:41 -0500 Subject: [PATCH 097/130] Changed order of operands in Halfword Multiply and Accumulate to better reflect inst format + updated inst errors --- lib/Arch/AArch32/Decode.cpp | 50 +++++++++++++-------------- lib/Arch/AArch32/Semantics/BINARY.cpp | 18 +++++----- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 9c624537e..e458045b7 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -1183,9 +1183,13 @@ static bool TryHalfwordDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { const HMultiplyAndAccumulate enc = { bits }; + bool add_ra = enc.opc == 0b10u || (enc.opc == 0b1u && !enc.N) || !enc.opc; // if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; // if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; - if (enc.rd == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum) { + // if dHi == dLo then UNPREDICTABLE; + if (enc.rd == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum + || ((enc.ra == kPCRegNum) && add_ra) + || ((enc.opc == 0b10u) && (enc.rd == enc.ra))) { inst.category = Instruction::kCategoryError; } @@ -1200,47 +1204,43 @@ static bool TryHalfwordDecodeMultiplyAndAccumulate(Instruction &inst, AddIntRegOp(inst, enc.rd, 32, Operand::kActionRead); } - - // Ra - if (enc.opc == 0b10u || (enc.opc == 0b1u && !enc.N) || !enc.opc) { - AddIntRegOp(inst, enc.ra, 32, Operand::kActionRead); - } else if (enc.opc != 0b11u) { - AddImmOp(inst, 0); - } - const auto word_type = inst.arch->AddressType(); const auto _16 = llvm::ConstantInt::get(word_type, 16u, false); - // Rm - AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); - if (enc.M) { - inst.operands.back().expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, - inst.operands.back().expr, - inst.EmplaceConstant(_16)); - inst.operands.back().expr = ExtractAndExtExpr( - inst, inst.operands.back().expr, 16u, 32u); - } else { - inst.operands.back().expr = ExtractAndExtExpr( - inst, inst.operands.back().expr, 16u, 32u); - } - // Rn AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); if (enc.opc != 0b1u) { if (enc.N) { inst.operands.back().expr = inst.EmplaceBinaryOp( - llvm::Instruction::LShr, inst.operands.back().expr, + llvm::Instruction::AShr, inst.operands.back().expr, inst.EmplaceConstant(_16)); - inst.operands.back().expr = ExtractAndExtExpr( - inst, inst.operands.back().expr, 16u, 32u); } else { inst.operands.back().expr = ExtractAndExtExpr( inst, inst.operands.back().expr, 16u, 32u); } } + // Rm + AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); + if (enc.M) { + inst.operands.back().expr = inst.EmplaceBinaryOp(llvm::Instruction::AShr, + inst.operands.back().expr, + inst.EmplaceConstant(_16)); + } else { + inst.operands.back().expr = ExtractAndExtExpr( + inst, inst.operands.back().expr, 16u, 32u); + } + + // Ra + if (add_ra) { + AddIntRegOp(inst, enc.ra, 32, Operand::kActionRead); + } else if (enc.opc != 0b11u) { + AddImmOp(inst, 0); + } + inst.category = Instruction::kCategoryNormal; return true; + } static const char * const kLoadSWUBIL[] = { diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index ccfc5d520..4a53da7a4 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -277,9 +277,9 @@ DEF_ISEL(SMLALS) = SMULLS; // Halfword Multiply and Accumulate namespace { DEF_COND_SEM(SMLAh, R32W dst, R32 src1, R32 src2, R32 src3) { - auto rhs = SExt(Read(src3)); - auto lhs = SExt(Read(src2)); - auto acc = SExt(Read(src1)); + auto rhs = SExt(Read(src2)); + auto lhs = SExt(Read(src1)); + auto acc = SExt(Read(src3)); auto res = SAdd(SMul(lhs, rhs), acc); auto trun_res = TruncTo(res); Write(dst, trun_res); @@ -291,9 +291,9 @@ DEF_COND_SEM(SMLAh, R32W dst, R32 src1, R32 src2, R32 src3) { } DEF_COND_SEM(SMLAWh, R32W dst, R32 src1, R32 src2, R32 src3) { - auto rhs = SExt(Read(src3)); - auto lhs = SExt(Read(src2)); - auto acc = SShl(SExt(Read(src1)), 16ul); // SInt(R[a]) << 16 + auto rhs = SExt(Read(src2)); + auto lhs = SExt(Read(src1)); + auto acc = SShl(SExt(Read(src3)), 16ul); // SInt(R[a]) << 16 auto res = SShr(SAdd(SMul(lhs, rhs), acc), 16ul); // R[d] = result<47:16> auto trun_res = TruncTo(res); Write(dst, trun_res); @@ -314,9 +314,9 @@ DEF_COND_SEM(SMULh, R32W dst, R32 src1, R32 src2) { } DEF_COND_SEM(SMLALh, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { - auto rhs = SExt(Read(src4)); - auto lhs = SExt(Read(src3)); - auto acc = SOr(SShl(SExt(Read(src1)), 32ul), ZExt(Read(src2))); // UInt(R[dHi]:R[dLo]) + auto rhs = SExt(Read(src3)); + auto lhs = SExt(Read(src2)); + auto acc = SOr(SShl(SExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); Write(dst_hi, TruncTo(SShr(res, 32ul))); Write(dst_lo, TruncTo(res)); From d0897bb6ce6fdd55b6096272fe65428fa2da1f44 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 15 Dec 2020 23:08:39 -0500 Subject: [PATCH 098/130] Branch (Imm) & BX/BXL --- include/remill/Arch/Instruction.h | 22 ++- lib/Arch/AArch32/Decode.cpp | 155 ++++++++++++++++++++-- lib/Arch/AArch32/Runtime/Instructions.cpp | 1 + lib/Arch/AArch32/Semantics/BRANCH.cpp | 45 +++++-- lib/BC/TraceLifter.cpp | 60 ++++++++- 5 files changed, 258 insertions(+), 25 deletions(-) diff --git a/include/remill/Arch/Instruction.h b/include/remill/Arch/Instruction.h index 1be4ce083..c34e9a512 100644 --- a/include/remill/Arch/Instruction.h +++ b/include/remill/Arch/Instruction.h @@ -221,8 +221,11 @@ class Instruction { kCategoryIndirectJump, kCategoryConditionalIndirectJump, kCategoryDirectFunctionCall, + kCategoryConditionalDirectFunctionCall, kCategoryIndirectFunctionCall, + kCategoryConditionalIndirectFunctionCall, kCategoryFunctionReturn, + kCategoryConditionalFunctionReturn, kCategoryConditionalBranch, kCategoryAsyncHyperCall, kCategoryConditionalAsyncHyperCall, @@ -253,30 +256,41 @@ class Instruction { inline bool IsIndirectControlFlow(void) const { switch (category) { case kCategoryIndirectFunctionCall: + case kCategoryConditionalIndirectFunctionCall: case kCategoryIndirectJump: case kCategoryConditionalIndirectJump: case kCategoryAsyncHyperCall: case kCategoryConditionalAsyncHyperCall: - case kCategoryFunctionReturn: return true; + case kCategoryFunctionReturn: + case kCategoryConditionalFunctionReturn: return true; default: return false; } } inline bool IsConditionalBranch(void) const { - return kCategoryConditionalBranch == category || - kCategoryConditionalIndirectJump == category; + switch (category) { + case kCategoryConditionalDirectFunctionCall: + case kCategoryConditionalBranch: + case kCategoryConditionalIndirectJump: + case kCategoryConditionalAsyncHyperCall: + case kCategoryConditionalFunctionReturn: return true; + default: return false; + } } inline bool IsFunctionCall(void) const { switch (category) { case kCategoryDirectFunctionCall: + case kCategoryConditionalDirectFunctionCall: + case kCategoryConditionalIndirectFunctionCall: case kCategoryIndirectFunctionCall: return true; default: return false; } } inline bool IsFunctionReturn(void) const { - return kCategoryFunctionReturn == category; + return kCategoryFunctionReturn == category || + kCategoryConditionalFunctionReturn == category; } inline bool IsValid(void) const { diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index e458045b7..b9c33c875 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -275,7 +275,26 @@ union BranchI { } __attribute__((packed)); static_assert(sizeof(BranchI) == 4, " "); +// Miscellaneous +union Misc { + uint32_t flat; + struct { + uint32_t Rm : 4; + uint32_t op1 : 3; + uint32_t _0_b7 : 1; + uint32_t _11_to_8 : 4; + uint32_t Rd : 4; + uint32_t _19_to_16 : 4; + uint32_t _0_b20 : 1; + uint32_t op0 : 2; + uint32_t _00010: 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(BranchI) == 4, " "); + static constexpr auto kPCRegNum = 15u; +static constexpr auto kLRRegNum = 14u; static const char * const kIntRegName[] = { "R0", @@ -1519,15 +1538,11 @@ static bool TryBranchImm(Instruction &inst, uint32_t bits) { auto is_func = false; // PC used by the branch instruction is actually the address of the next instruction - auto target_pc = static_cast(inst.pc + 4 + static_cast(enc.imm24 << 2)); + auto target_pc = static_cast(inst.pc + 8 + static_cast(enc.imm24 << 2)); if (enc.cond != 0b1111) { if (!enc.H) { target_pc = target_pc & ~0b11u; - if (is_cond) { - inst.function = "BCOND"; - } else { - inst.function = "B"; - } + inst.function = "B"; } else { target_pc = target_pc & ~0b11u; inst.function = "BL"; @@ -1539,28 +1554,148 @@ static bool TryBranchImm(Instruction &inst, uint32_t bits) { target_pc = target_pc | (enc.H << 1); is_func = true; } + if (is_cond) { + inst.function += "COND"; + } auto offset = static_cast(target_pc - inst.pc); AddAddrRegOp(inst, "PC", 32u, Operand::kActionRead, offset); inst.branch_taken_pc = target_pc; inst.branch_not_taken_pc = inst.pc + 4; - if (is_cond) { + if (is_cond && is_func) { + inst.category = Instruction::kCategoryConditionalDirectFunctionCall; + AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0); + } else if (is_cond) { inst.category = Instruction::kCategoryConditionalBranch; AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0); } else if (is_func) { - LOG_IF(FATAL, is_cond) << "TODO: Conditional function calls"; + inst.category = Instruction::kCategoryDirectFunctionCall; + AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0); } else { inst.category = Instruction::kCategoryDirectJump; } + + Operand::Register reg; + reg.size = 32u; + reg.name = remill::kNextPCVariableName; + auto &next_pc = inst.EmplaceOperand(reg); + next_pc.action = Operand::kActionWrite; + + if (is_func) { + Operand::Register reg; + reg.size = 32u; + reg.name = remill::kReturnPCVariableName; + auto &next_pc = inst.EmplaceOperand(reg); + next_pc.action = Operand::kActionWrite; + } + + return true; +} + +static const char * const kBX[] = { + [0b01] = "BX", + [0b10] = "BXJ", // unsupported + [0b11] = "BLX", +}; + +static bool TryDecodeBX(Instruction &inst, uint32_t bits) { + const Misc enc = { bits }; + + if (enc.op1 == 0b10) { // BJX unsupported + LOG(ERROR) << "BJX unsupported"; + return false; + } else if (enc.op1 == 0b11 && enc.Rm == kPCRegNum) { + // if m == 15 then UNPREDICTABLE; + return false; + } + + auto is_cond = DecodeCondition(inst, enc.cond); + inst.function = kBX[enc.op1]; + if (is_cond) { + inst.function += "COND"; + } + + AddAddrRegOp(inst, kIntRegName[enc.Rm], 32u, Operand::kActionRead, 0); + if (enc.op1 == 0b01) { + if (is_cond && (enc.Rm == kLRRegNum)) { + inst.category = Instruction::kCategoryConditionalFunctionReturn; + AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0); + } else if (enc.Rm == kLRRegNum) { + inst.category = Instruction::kCategoryFunctionReturn; + } else if (is_cond) { + inst.category = Instruction::kCategoryConditionalIndirectJump; + AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0); + } else if (enc.op1 == 0b01) { + inst.category = Instruction::kCategoryIndirectJump; + } + } else if (is_cond) { + inst.category = Instruction::kCategoryConditionalDirectFunctionCall; + AddAddrRegOp(inst, "NEXT_PC", 32u, Operand::kActionRead, 0); + } else { + inst.category = Instruction::kCategoryDirectFunctionCall; + } + Operand::Register reg; reg.size = 32u; reg.name = remill::kNextPCVariableName; auto &next_pc = inst.EmplaceOperand(reg); next_pc.action = Operand::kActionWrite; + + if (enc.op1 == 0b11) { + Operand::Register reg; + reg.size = 32u; + reg.name = remill::kReturnPCVariableName; + auto &next_pc = inst.EmplaceOperand(reg); + next_pc.action = Operand::kActionWrite; + } + return true; } +//00 001 UNALLOCATED +//00 010 UNALLOCATED +//00 011 UNALLOCATED +//00 110 UNALLOCATED +//01 001 BX +//01 010 BXJ +//01 011 BLX (register) +//01 110 UNALLOCATED +//10 001 UNALLOCATED +//10 010 UNALLOCATED +//10 011 UNALLOCATED +//10 110 UNALLOCATED +//11 001 CLZ +//11 010 UNALLOCATED +//11 011 UNALLOCATED +//11 110 ERET +// 111 Exception Generation +// 000 Move special register (register) +// 100 Cyclic Redundancy Check +// 101 Integer Saturating Arithmetic +static TryDecode * TryMiscellaneous(uint32_t bits) { + const Misc enc = { bits }; + // op0 | op1 + switch (enc.op0 << 3 | enc.op1) { + case 0b01001: + case 0b01010: + case 0b01011: + return TryDecodeBX; + // TODO(Sonya) + case 0b11001: // CLZ + case 0b11110: // ERET + return nullptr; + } + // TODO(Sonya) + switch (enc.op1) { + case 0b111: // Exception Generation + case 0b000: // Move special register (register) + case 0b100: // Cyclic Redundancy Check + case 0b101: // Integer Saturating Arithmetic + default: return nullptr; + } +} + // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> static TryDecode * kDataProcessingRI[] = { @@ -1648,9 +1783,9 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { } // op1 == 10xx0 } else if (((enc.op1 >> 3) == 0b10u) && !(enc.op1 & 0b00001u)) { - // TODO(Sonya): Miscellaneous + // Miscellaneous if (!enc.op2) { - return nullptr; + return TryMiscellaneous(bits); // Halfword Multiply and Accumulate } else { return TryHalfwordDecodeMultiplyAndAccumulate; diff --git a/lib/Arch/AArch32/Runtime/Instructions.cpp b/lib/Arch/AArch32/Runtime/Instructions.cpp index 318efb649..517aa5535 100644 --- a/lib/Arch/AArch32/Runtime/Instructions.cpp +++ b/lib/Arch/AArch32/Runtime/Instructions.cpp @@ -29,6 +29,7 @@ // clang-format on #define REG_PC state.gpr.r15.dword +#define REG_LR state.gpr.r14.dword #define REG_SP state.gpr.r13.dword #define HYPER_CALL state.hyper_call diff --git a/lib/Arch/AArch32/Semantics/BRANCH.cpp b/lib/Arch/AArch32/Semantics/BRANCH.cpp index 6b987db01..d62834a92 100644 --- a/lib/Arch/AArch32/Semantics/BRANCH.cpp +++ b/lib/Arch/AArch32/Semantics/BRANCH.cpp @@ -14,15 +14,10 @@ * limitations under the License. */ - - - - namespace { - DEF_SEM(B, R8, R8W, I32 taken_pc, R32W next_pc_dst) { auto new_pc = Read(taken_pc); - Write(state.gpr.r15.dword, new_pc); + Write(REG_PC, new_pc); Write(next_pc_dst, new_pc); return memory; } @@ -31,13 +26,47 @@ DEF_SEM(BCOND, R8 cond, R8W branch_taken, I32 taken_pc, I32 not_taken_pc, R32W next_pc_dst) { auto c = Read(cond); auto new_pc = Select(c, Read(taken_pc), Read(not_taken_pc)); - Write(state.gpr.r15.dword, new_pc); + Write(REG_PC, new_pc); Write(next_pc_dst, new_pc); Write(branch_taken, c); return memory; } -} //namespace +DEF_SEM(BL, R8, R8W, PC target_addr, PC ret_addr, R32W next_pc_dst, + R32W return_pc_dst) { + const auto return_pc = Read(ret_addr); + const auto new_pc = Read(target_addr); + Write(REG_LR, return_pc); + Write(REG_PC, new_pc); + Write(next_pc_dst, new_pc); + Write(return_pc_dst, return_pc); + return memory; +} + +DEF_SEM(BLCOND, R8 cond, R8W branch_taken, PC target_addr, PC ret_addr, + R32W next_pc_dst, R32W return_pc_dst) { + auto c = Read(cond); + const auto return_pc = Read(ret_addr); + if (c) { + const auto target_pc = Read(target_addr); + Write(REG_LR, return_pc); + Write(REG_PC, target_pc); + Write(next_pc_dst, target_pc); + } else { + Write(REG_PC, return_pc); + Write(next_pc_dst, return_pc); + } + Write(return_pc_dst, return_pc); + Write(branch_taken, c); + return memory; +} +} // namespace DEF_ISEL(B) = B; DEF_ISEL(BCOND) = BCOND; +DEF_ISEL(BL) = BL; +DEF_ISEL(BLCOND) = BLCOND; +DEF_ISEL(BLX) = BL; +DEF_ISEL(BLXCOND) = BLCOND; +DEF_ISEL(BX) = B; +DEF_ISEL(BXCOND) = BCOND; diff --git a/lib/BC/TraceLifter.cpp b/lib/BC/TraceLifter.cpp index f7ee591b4..26a2a1bf0 100644 --- a/lib/BC/TraceLifter.cpp +++ b/lib/BC/TraceLifter.cpp @@ -102,6 +102,7 @@ class TraceLifter::Impl { } llvm::BasicBlock *GetOrCreateBranchNotTakenBlock(void) { + CHECK(inst.branch_not_taken_pc != 0); inst_work_list.insert(inst.branch_not_taken_pc); return GetOrCreateBlock(inst.branch_not_taken_pc); } @@ -467,7 +468,7 @@ bool TraceLifter::Impl::Lift( LoadNextProgramCounterRef(fall_through_block); llvm::IRBuilder<> ir(fall_through_block); ir.CreateStore(ir.CreateLoad(ret_pc_ref), next_pc_ref); - ir.CreateBr(GetOrCreateNextBlock()); + ir.CreateBr(GetOrCreateBranchNotTakenBlock()); // The trace manager might know about the targets of things like // virtual tables, so we will let it tell us about those possibilities. @@ -519,6 +520,27 @@ bool TraceLifter::Impl::Lift( continue; } + case Instruction::kCategoryConditionalIndirectFunctionCall: { + if (inst.branch_not_taken_pc == inst.branch_taken_pc) { + goto direct_func_call; + } + try_add_delay_slot(true, block); + trace_work_list.insert(inst.branch_taken_pc); + auto do_cond_call = llvm::BasicBlock::Create(context, "", func); + auto next_block = GetOrCreateBranchNotTakenBlock(); + llvm::BranchInst::Create(do_cond_call, next_block, + LoadBranchTaken(block), block); + AddCall(do_cond_call, intrinsics->function_call); + + const auto ret_pc_ref = LoadReturnProgramCounterRef(block); + const auto next_pc_ref = LoadNextProgramCounterRef(block); + llvm::IRBuilder<> ir(do_cond_call); + ir.CreateStore(ir.CreateLoad(ret_pc_ref), next_pc_ref); + ir.CreateBr(next_block); + + continue; + } + // In the case of a direct function call, we try to handle the // pattern of a call to the next PC as a way of getting access to // an instruction pointer. It is the case where a call to the next @@ -528,8 +550,9 @@ bool TraceLifter::Impl::Lift( // that up when trying to lift it), or we'll just have a really big // trace for this function without sacrificing correctness. case Instruction::kCategoryDirectFunctionCall: { + direct_func_call: try_add_delay_slot(true, block); - if (inst.next_pc != inst.branch_taken_pc) { + if (inst.branch_not_taken_pc != inst.branch_taken_pc) { trace_work_list.insert(inst.branch_taken_pc); auto target_trace = get_trace_decl(inst.branch_taken_pc); AddCall(block, target_trace); @@ -539,7 +562,29 @@ bool TraceLifter::Impl::Lift( const auto next_pc_ref = LoadNextProgramCounterRef(block); llvm::IRBuilder<> ir(block); ir.CreateStore(ir.CreateLoad(ret_pc_ref), next_pc_ref); - ir.CreateBr(GetOrCreateNextBlock()); + ir.CreateBr(GetOrCreateBranchNotTakenBlock()); + + continue; + } + + case Instruction::kCategoryConditionalDirectFunctionCall: { + if (inst.branch_not_taken_pc == inst.branch_taken_pc) { + goto direct_func_call; + } + try_add_delay_slot(true, block); + trace_work_list.insert(inst.branch_taken_pc); + auto target_trace = get_trace_decl(inst.branch_taken_pc); + auto do_cond_call = llvm::BasicBlock::Create(context, "", func); + auto next_block = GetOrCreateBranchNotTakenBlock(); + llvm::BranchInst::Create(do_cond_call, next_block, + LoadBranchTaken(block), block); + AddCall(do_cond_call, target_trace); + + const auto ret_pc_ref = LoadReturnProgramCounterRef(block); + const auto next_pc_ref = LoadNextProgramCounterRef(block); + llvm::IRBuilder<> ir(do_cond_call); + ir.CreateStore(ir.CreateLoad(ret_pc_ref), next_pc_ref); + ir.CreateBr(next_block); continue; } @@ -580,6 +625,15 @@ bool TraceLifter::Impl::Lift( AddTerminatingTailCall(block, intrinsics->function_return); break; + case Instruction::kCategoryConditionalFunctionReturn: { + auto taken_block = llvm::BasicBlock::Create(context, "", func); + AddTerminatingTailCall(taken_block, intrinsics->function_return); + auto not_taken_block = GetOrCreateBranchNotTakenBlock(); + llvm::BranchInst::Create(taken_block, not_taken_block, + LoadBranchTaken(block), block); + break; + } + case Instruction::kCategoryConditionalBranch: { auto taken_block = GetOrCreateBranchTakenBlock(); auto not_taken_block = GetOrCreateBranchNotTakenBlock(); From 76552247b1c1ca68f4cb57cc5c4925a73ae416d4 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 16 Dec 2020 11:38:23 -0500 Subject: [PATCH 099/130] Update aarch32 cmake --- lib/Arch/AArch32/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Arch/AArch32/CMakeLists.txt b/lib/Arch/AArch32/CMakeLists.txt index f76bef4be..e6f20c2f1 100644 --- a/lib/Arch/AArch32/CMakeLists.txt +++ b/lib/Arch/AArch32/CMakeLists.txt @@ -41,6 +41,5 @@ target_link_libraries(remill_arch_aarch32 LINK_PUBLIC install( TARGETS remill_arch_aarch32 - ARCHIVE DESTINATION "${REMILL_INSTALL_LIB_DIR}" - PUBLIC_HEADER DESTINATION "${REMILL_INSTALL_INCLUDE_DIR}" + EXPORT remillTargets ) From 09b74e1a4bcf7fc41d99d4c885c11749c9ed40c5 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 16 Dec 2020 11:47:49 -0500 Subject: [PATCH 100/130] cmake update --- CMakeLists_vcpkg.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists_vcpkg.txt b/CMakeLists_vcpkg.txt index fbf7b6194..c908f9df1 100644 --- a/CMakeLists_vcpkg.txt +++ b/CMakeLists_vcpkg.txt @@ -144,6 +144,7 @@ math(EXPR REMILL_LLVM_VERSION_NUMBER "${LLVM_MAJOR_VERSION} * 100 + ${LLVM_MINOR set(REMILL_INSTALL_SEMANTICS_DIR "${CMAKE_INSTALL_PREFIX}/${REMILL_INSTALL_SHARE_DIR}/remill/${REMILL_LLVM_VERSION}/semantics" CACHE PATH "Directory into which semantics are installed") set(REMILL_BUILD_SEMANTICS_DIR_X86 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/X86/Runtime") +set(REMILL_BUILD_SEMANTICS_DIR_AARCH32 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/AArch32/Runtime") set(REMILL_BUILD_SEMANTICS_DIR_AARCH64 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/AArch64/Runtime") set(REMILL_BUILD_SEMANTICS_DIR_SPARC32 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/SPARC32/Runtime") set(REMILL_BUILD_SEMANTICS_DIR_SPARC64 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/SPARC64/Runtime") @@ -229,6 +230,7 @@ endif() target_compile_definitions(remill_settings INTERFACE "REMILL_INSTALL_SEMANTICS_DIR=\"${REMILL_INSTALL_SEMANTICS_DIR}\"" "REMILL_BUILD_SEMANTICS_DIR_X86=\"${REMILL_BUILD_SEMANTICS_DIR_X86}\"" + "REMILL_BUILD_SEMANTICS_DIR_AARCH32=\"${REMILL_BUILD_SEMANTICS_DIR_AARCH32}\"" "REMILL_BUILD_SEMANTICS_DIR_AARCH64=\"${REMILL_BUILD_SEMANTICS_DIR_AARCH64}\"" "REMILL_BUILD_SEMANTICS_DIR_SPARC32=\"${REMILL_BUILD_SEMANTICS_DIR_SPARC32}\"" "REMILL_BUILD_SEMANTICS_DIR_SPARC64=\"${REMILL_BUILD_SEMANTICS_DIR_SPARC64}\"" From 29eb9a660b31986f5c4c9f3b231190710490f1bb Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 16 Dec 2020 16:38:51 -0500 Subject: [PATCH 101/130] CLZ --- lib/Arch/AArch32/Decode.cpp | 23 ++++++++++++++++++++--- lib/Arch/AArch32/Runtime/CMakeLists.txt | 1 + lib/Arch/AArch32/Runtime/Instructions.cpp | 16 ++++++++-------- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index b9c33c875..61ec43611 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -1653,6 +1653,23 @@ static bool TryDecodeBX(Instruction &inst, uint32_t bits) { return true; } +static bool TryDecodeCLZ(Instruction &inst, uint32_t bits) { + const Misc enc = { bits }; + if (enc.Rd == kPCRegNum || enc.Rm == kPCRegNum) { + // if d == 15 || m == 15 then UNPREDICTABLE; + return false; + } + DecodeCondition(inst, enc.cond); + + AddIntRegOp(inst, enc.Rd, 32u, Operand::kActionWrite); + AddIntRegOp(inst, enc.Rm, 32u, Operand::kActionRead); + + inst.function = "CLZ"; + inst.category = Instruction::kCategoryNormal; + return true; +} + + //00 001 UNALLOCATED //00 010 UNALLOCATED //00 011 UNALLOCATED @@ -1681,9 +1698,9 @@ static TryDecode * TryMiscellaneous(uint32_t bits) { case 0b01010: case 0b01011: return TryDecodeBX; - // TODO(Sonya) - case 0b11001: // CLZ - case 0b11110: // ERET + case 0b11001: + return TryDecodeCLZ; + case 0b11110: // TODO(Sonya): ERET return nullptr; } // TODO(Sonya) diff --git a/lib/Arch/AArch32/Runtime/CMakeLists.txt b/lib/Arch/AArch32/Runtime/CMakeLists.txt index 278554cc0..a2736cfee 100644 --- a/lib/Arch/AArch32/Runtime/CMakeLists.txt +++ b/lib/Arch/AArch32/Runtime/CMakeLists.txt @@ -58,6 +58,7 @@ function(add_runtime_helper target_name little_endian) "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/LOGICAL.cpp" "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/MEM.cpp" "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/BRANCH.cpp" + "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/BITBYTE.cpp" ) endfunction() diff --git a/lib/Arch/AArch32/Runtime/Instructions.cpp b/lib/Arch/AArch32/Runtime/Instructions.cpp index 517aa5535..55a9c3cea 100644 --- a/lib/Arch/AArch32/Runtime/Instructions.cpp +++ b/lib/Arch/AArch32/Runtime/Instructions.cpp @@ -61,15 +61,15 @@ DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; #include "lib/Arch/AArch32/Semantics/BINARY.cpp" #include "lib/Arch/AArch32/Semantics/MEM.cpp" #include "lib/Arch/AArch32/Semantics/LOGICAL.cpp" -//#include "lib/Arch/AArch64/Semantics/BITBYTE.cpp" +#include "lib/Arch/AArch32/Semantics/BITBYTE.cpp" #include "lib/Arch/AArch32/Semantics/BRANCH.cpp" -//#include "lib/Arch/AArch64/Semantics/CALL_RET.cpp" +//#include "lib/Arch/AArch32/Semantics/CALL_RET.cpp" #include "lib/Arch/AArch32/Semantics/COND.cpp" -//#include "lib/Arch/AArch64/Semantics/CONVERT.cpp" -//#include "lib/Arch/AArch64/Semantics/DATAXFER.cpp" -//#include "lib/Arch/AArch64/Semantics/MISC.cpp" -//#include "lib/Arch/AArch64/Semantics/SHIFT.cpp" -//#include "lib/Arch/AArch64/Semantics/SIMD.cpp" -//#include "lib/Arch/AArch64/Semantics/SYSTEM.cpp" +//#include "lib/Arch/AArch32/Semantics/CONVERT.cpp" +//#include "lib/Arch/AArch32/Semantics/DATAXFER.cpp" +//#include "lib/Arch/AArch32/Semantics/MISC.cpp" +//#include "lib/Arch/AArch32/Semantics/SHIFT.cpp" +//#include "lib/Arch/AArch32/Semantics/SIMD.cpp" +//#include "lib/Arch/AArch32/Semantics/SYSTEM.cpp" // clang-format on From 94b1e081f90e8727b24207abed410872977f1173 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 16 Dec 2020 16:58:27 -0500 Subject: [PATCH 102/130] Forgot BITBYTE.cpp --- lib/Arch/AArch32/Semantics/BITBYTE.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 lib/Arch/AArch32/Semantics/BITBYTE.cpp diff --git a/lib/Arch/AArch32/Semantics/BITBYTE.cpp b/lib/Arch/AArch32/Semantics/BITBYTE.cpp new file mode 100644 index 000000000..78983749e --- /dev/null +++ b/lib/Arch/AArch32/Semantics/BITBYTE.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { +DEF_COND_SEM(CLZ, R32W dst, R32 src) { + auto count = CountLeadingZeros(Read(src)); + WriteZExt(dst, count); + return memory; +} +} // namespace + +DEF_ISEL(CLZ) = CLZ; From 350af45eb2f248483ed050d3539a7cc8aedf2b0c Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 18 Dec 2020 10:30:52 -0500 Subject: [PATCH 103/130] MOVT --- lib/Arch/AArch32/Decode.cpp | 42 +++++++++++++++++++++++--- lib/Arch/AArch32/Semantics/BINARY.cpp | 13 ++++++-- lib/Arch/AArch32/Semantics/LOGICAL.cpp | 12 ++++++++ 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 61ec43611..43a42c92b 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -233,6 +233,21 @@ union LogicalArithmeticRRI { } __attribute__((packed)); static_assert(sizeof(LogicalArithmeticRRI) == 4, " "); +union MoveHW { + uint32_t flat; + struct { + uint32_t imm12 : 12; + uint32_t rd : 4; + uint32_t imm4 : 4; + uint32_t _00 : 2; + uint32_t H : 1; + uint32_t _00110 : 5; + uint32_t cond : 4; + } __attribute__((packed)); + } __attribute__((packed)); +static_assert(sizeof(MoveHW) == 4, " "); + + // Top-level encodings for A32 union TopLevelEncodings { uint32_t flat; @@ -1253,8 +1268,6 @@ static bool TryHalfwordDecodeMultiplyAndAccumulate(Instruction &inst, // Ra if (add_ra) { AddIntRegOp(inst, enc.ra, 32, Operand::kActionRead); - } else if (enc.opc != 0b11u) { - AddImmOp(inst, 0); } inst.category = Instruction::kCategoryNormal; @@ -1464,6 +1477,27 @@ static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u], is_cond); } +// Move Halfword (immediate) +static bool TryDecodeMoveHalfword(Instruction &inst, uint32_t bits) { + const MoveHW enc = { bits }; + + // if d == 15 then UNPREDICTABLE; + if (enc.rd == kPCRegNum) { + return false; + } else if (!enc.H) { + // (Sonya) This doesn't look like it should be reachable + return false; + } + + inst.function = "MOVT"; + DecodeCondition(inst, enc.cond); + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + AddIntRegOp(inst, enc.rd, 32, Operand::kActionRead); + AddImmOp(inst, enc.imm4 << 12 | enc.imm12); + inst.category = Instruction::kCategoryNormal; + return true; +} + //00 TST (register) //01 TEQ (register) //10 CMP (register) @@ -1750,7 +1784,7 @@ static TryDecode * kDataProcessingI[] = { [0b0101] = TryDecodeIntegerDataProcessingRRI, [0b0110] = TryDecodeIntegerDataProcessingRRI, [0b0111] = TryDecodeIntegerDataProcessingRRI, - [0b1000] = nullptr, // TODO(Sonya): Move Halfword (immediate) + [0b1000] = TryDecodeMoveHalfword, // Move Halfword (immediate) [0b1001] = TryIntegerTestAndCompareRI, [0b1010] = nullptr, // TODO(Sonya): Move Special Register and Hints (immediate) [0b1011] = TryIntegerTestAndCompareRI, @@ -1823,7 +1857,7 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { } else { // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 2 lowest bits // index is the concatenation of op0 and op1 - return kDataProcessingI[(enc.op1 >> 1) | (enc.op1 & 0b11u)]; + return kDataProcessingI[((enc.op1 >> 1) & 0b1100u) | (enc.op1 & 0b11u)]; } } diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index 4a53da7a4..45f8b09d6 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -290,6 +290,15 @@ DEF_COND_SEM(SMLAh, R32W dst, R32 src1, R32 src2, R32 src3) { return memory; } +DEF_COND_SEM(SMULWh, R32W dst, R32 src1, R32 src2) { + auto rhs = SExt(Read(src2)); + auto lhs = SExt(Read(src1)); + auto res = SShr(SMul(lhs, rhs), 16ul); // R[d] = result<47:16> + auto trun_res = TruncTo(res); + Write(dst, trun_res); + return memory; +} + DEF_COND_SEM(SMLAWh, R32W dst, R32 src1, R32 src2, R32 src3) { auto rhs = SExt(Read(src2)); auto lhs = SExt(Read(src1)); @@ -330,9 +339,9 @@ DEF_ISEL(SMLABT) = SMLAh; DEF_ISEL(SMLATB) = SMLAh; DEF_ISEL(SMLATT) = SMLAh; DEF_ISEL(SMLAWB) = SMLAWh; -DEF_ISEL(SMULWB) = SMLAWh; +DEF_ISEL(SMULWB) = SMULWh; DEF_ISEL(SMLAWT) = SMLAWh; -DEF_ISEL(SMULWT) = SMLAWh; +DEF_ISEL(SMULWT) = SMULWh; DEF_ISEL(SMULBB) = SMULh; DEF_ISEL(SMULBT) = SMULh; DEF_ISEL(SMULTB) = SMULh; diff --git a/lib/Arch/AArch32/Semantics/LOGICAL.cpp b/lib/Arch/AArch32/Semantics/LOGICAL.cpp index d81c75f71..ff2101e6e 100644 --- a/lib/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/lib/Arch/AArch32/Semantics/LOGICAL.cpp @@ -52,6 +52,7 @@ DEF_COND_SEM(BICS, R32W dst, R32 src1, I32 src2, I8 carry_out) { // PSTATE.V unchanged return memory; } + } // namespace DEF_ISEL(ORRrr) = ORR; @@ -62,3 +63,14 @@ DEF_ISEL(BICrr) = BIC; DEF_ISEL(BICSrr) = BICS; DEF_ISEL(MVNrr) = BIC; DEF_ISEL(MVNSrr) = BICS; + +namespace { +DEF_COND_SEM(MOVT, R32W dst, R32 src1, R32 src2){ + auto value = ZExt(Trunc(Read(src1))); + auto result = UOr(UShl(Read(src2), 16), value); + Write(dst, result); + return memory; +} +} // namespace + +DEF_ISEL(MOVT) = MOVT; From f4fcaaf461e3a525aa6c434606b70b6725f49740 Mon Sep 17 00:00:00 2001 From: sschriner Date: Mon, 21 Dec 2020 15:22:02 -0500 Subject: [PATCH 104/130] Integer Saturating Arithmetic --- lib/Arch/AArch32/Decode.cpp | 57 ++++++++++++++++++++++++-- lib/Arch/AArch32/Semantics/BINARY.cpp | 58 ++++++++++++++++++++++++++- 2 files changed, 110 insertions(+), 5 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 43a42c92b..00108de76 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -306,7 +306,24 @@ union Misc { uint32_t cond : 4; } __attribute__((packed)); } __attribute__((packed)); -static_assert(sizeof(BranchI) == 4, " "); +static_assert(sizeof(Misc) == 4, " "); + +// Integer Saturating Arithmetic +union IntSatArith { + uint32_t flat; + struct { + uint32_t Rm : 4; + uint32_t _11_to_4 : 8; + uint32_t Rd : 4; + uint32_t Rn : 4; + uint32_t _0_b20 : 1; + uint32_t opc : 2; + uint32_t _00010: 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(IntSatArith) == 4, " "); + static constexpr auto kPCRegNum = 15u; static constexpr auto kLRRegNum = 14u; @@ -1146,6 +1163,7 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { auto instruction = kMulAccRRR[(enc.opc << 1u) | enc.s]; if (!instruction) { + inst.category = Instruction::kCategoryError; return false; } inst.function = instruction; @@ -1483,9 +1501,11 @@ static bool TryDecodeMoveHalfword(Instruction &inst, uint32_t bits) { // if d == 15 then UNPREDICTABLE; if (enc.rd == kPCRegNum) { + inst.category = Instruction::kCategoryError; return false; } else if (!enc.H) { // (Sonya) This doesn't look like it should be reachable + inst.category = Instruction::kCategoryError; return false; } @@ -1638,9 +1658,11 @@ static bool TryDecodeBX(Instruction &inst, uint32_t bits) { if (enc.op1 == 0b10) { // BJX unsupported LOG(ERROR) << "BJX unsupported"; + inst.category = Instruction::kCategoryError; return false; } else if (enc.op1 == 0b11 && enc.Rm == kPCRegNum) { // if m == 15 then UNPREDICTABLE; + inst.category = Instruction::kCategoryError; return false; } @@ -1687,10 +1709,12 @@ static bool TryDecodeBX(Instruction &inst, uint32_t bits) { return true; } +// Count Leading Zeros static bool TryDecodeCLZ(Instruction &inst, uint32_t bits) { const Misc enc = { bits }; if (enc.Rd == kPCRegNum || enc.Rm == kPCRegNum) { // if d == 15 || m == 15 then UNPREDICTABLE; + inst.category = Instruction::kCategoryError; return false; } DecodeCondition(inst, enc.cond); @@ -1703,6 +1727,31 @@ static bool TryDecodeCLZ(Instruction &inst, uint32_t bits) { return true; } +static const char * const kSatArith[] = { + [0b00] = "QADD", + [0b01] = "QSUB", + [0b10] = "QDADD", + [0b11] = "QDSUB", +}; + +// Integer Saturating Arithmetic +static bool TryDecodeIntegerSaturatingArithmetic(Instruction &inst, + uint32_t bits) { + const IntSatArith enc = { bits }; + // if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; + if (enc.Rd == kPCRegNum || enc.Rm == kPCRegNum || enc.Rn == kPCRegNum) { + inst.category = Instruction::kCategoryError; + return false; + } + DecodeCondition(inst, enc.cond); + AddIntRegOp(inst, enc.Rd, 32u, Operand::kActionWrite); + AddIntRegOp(inst, enc.Rm, 32u, Operand::kActionRead); + AddIntRegOp(inst, enc.Rn, 32u, Operand::kActionRead); + + inst.function = kSatArith[enc.opc]; + inst.category = Instruction::kCategoryNormal; + return true; +} //00 001 UNALLOCATED //00 010 UNALLOCATED @@ -1742,7 +1791,9 @@ static TryDecode * TryMiscellaneous(uint32_t bits) { case 0b111: // Exception Generation case 0b000: // Move special register (register) case 0b100: // Cyclic Redundancy Check - case 0b101: // Integer Saturating Arithmetic + return nullptr; + case 0b101: + return TryDecodeIntegerSaturatingArithmetic; default: return nullptr; } } @@ -1784,7 +1835,7 @@ static TryDecode * kDataProcessingI[] = { [0b0101] = TryDecodeIntegerDataProcessingRRI, [0b0110] = TryDecodeIntegerDataProcessingRRI, [0b0111] = TryDecodeIntegerDataProcessingRRI, - [0b1000] = TryDecodeMoveHalfword, // Move Halfword (immediate) + [0b1000] = TryDecodeMoveHalfword, [0b1001] = TryIntegerTestAndCompareRI, [0b1010] = nullptr, // TODO(Sonya): Move Special Register and Hints (immediate) [0b1011] = TryIntegerTestAndCompareRI, diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index 45f8b09d6..06bdf792a 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -28,8 +28,6 @@ T AddWithCarryNZCV(State &state, T lhs, T rhs, T carry) { return result; } - - DEF_COND_SEM(AND, R32W dst, R32 src1, I32 src2) { auto value = Read(src2); Write(dst, UAnd(Read(src1), value)); @@ -351,3 +349,59 @@ DEF_ISEL(SMLALBT) = SMLALh; DEF_ISEL(SMLALTB) = SMLALh; DEF_ISEL(SMLALTT) = SMLALh; +namespace { +template +T SignedSatQ(State &state, T res, int32_t nbits) { + nbits--; + auto upper_bound = T((1 << nbits) - 1); + auto lower_bound = T(-(1 << nbits)); + state.sr.q = Select(SOr(SCmpGt(res, upper_bound), SCmpLt(res, lower_bound)), + uint8_t(1), state.sr.q); + res = Select(SCmpGt(res, upper_bound), upper_bound, res); + res = Select(SCmpLt(res, lower_bound), lower_bound, res); + return res; +} + +DEF_COND_SEM(QADD, R32W dst, R32 src1, R32 src2) { + auto rhs = SExt(Signed(Read(src2))); + auto lhs = SExt(Signed(Read(src1))); + auto res = SAdd(lhs, rhs); + res = SignedSatQ(state, res, 32u); + Write(dst, TruncTo(res)); + return memory; +} + +DEF_COND_SEM(QDADD, R32W dst, R32 src1, R32 src2) { + auto rhs = SExt(Signed(Read(src2))); + auto lhs = SExt(Signed(Read(src1))); + rhs = SignedSatQ(state, SShl(rhs, 1u), 32u); + auto res = SAdd(lhs, rhs); + res = SignedSatQ(state, res, 32u); + Write(dst, TruncTo(res)); + return memory; +} + +DEF_COND_SEM(QSUB, R32W dst, R32 src1, R32 src2) { + auto rhs = SExt(Signed(Read(src2))); + auto lhs = SExt(Signed(Read(src1))); + auto res = SSub(lhs, rhs); + res = SignedSatQ(state, res, 32u); + Write(dst, TruncTo(res)); + return memory; +} + +DEF_COND_SEM(QDSUB, R32W dst, R32 src1, R32 src2) { + auto rhs = SExt(Signed(Read(src2))); + auto lhs = SExt(Signed(Read(src1))); + rhs = SignedSatQ(state, SShl(rhs, 1u), 32u); + auto res = SSub(lhs, rhs); + res = SignedSatQ(state, res, 32u); + Write(dst, TruncTo(res)); + return memory; +} +} // namespace + +DEF_ISEL(QADD) = QADD; +DEF_ISEL(QDADD) = QDADD; +DEF_ISEL(QSUB) = QSUB; +DEF_ISEL(QDSUB) = QDSUB; From f8f9a60ac0efb161bc7706990bb33f57386fe59a Mon Sep 17 00:00:00 2001 From: sschriner Date: Mon, 21 Dec 2020 15:43:04 -0500 Subject: [PATCH 105/130] updated semantics in SMLAWh & SMLAh to use Select for setting PSTATE.Q --- lib/Arch/AArch32/Semantics/BINARY.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index 06bdf792a..54db69f34 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -284,7 +284,8 @@ DEF_COND_SEM(SMLAh, R32W dst, R32 src1, R32 src2, R32 src3) { // if result != SInt(result<31:0>) then // Signed overflow // PSTATE.Q = '1'; - state.sr.q = UOr(state.sr.q, SCmpNeq(res, SExt(trun_res))); + state.sr.q = Select(SCmpNeq(res, SExt(trun_res)), + uint8_t(1), state.sr.q); return memory; } @@ -307,7 +308,8 @@ DEF_COND_SEM(SMLAWh, R32W dst, R32 src1, R32 src2, R32 src3) { // if (result >> 16) != SInt(R[d]) then // Signed overflow // PSTATE.Q = '1'; - state.sr.q = UOr(state.sr.q, SCmpNeq(res, SExt(trun_res))); + state.sr.q = Select(SCmpNeq(res, SExt(trun_res)), + uint8_t(1), state.sr.q); return memory; } @@ -356,7 +358,7 @@ T SignedSatQ(State &state, T res, int32_t nbits) { auto upper_bound = T((1 << nbits) - 1); auto lower_bound = T(-(1 << nbits)); state.sr.q = Select(SOr(SCmpGt(res, upper_bound), SCmpLt(res, lower_bound)), - uint8_t(1), state.sr.q); + uint8_t(1u), state.sr.q); res = Select(SCmpGt(res, upper_bound), upper_bound, res); res = Select(SCmpLt(res, lower_bound), lower_bound, res); return res; From d9bc627540fec4cfb5580492dc79aaeae257eb61 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 29 Dec 2020 10:09:47 -0500 Subject: [PATCH 106/130] Started Load/Store Word, Unsigned Byte (register) & fixed MOV halfword --- lib/Arch/AArch32/Decode.cpp | 217 +++++++++++++++++++++++++++++++++--- 1 file changed, 201 insertions(+), 16 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 00108de76..5bf3cdf6a 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -130,6 +130,72 @@ union LoadStoreWUBIL { } __attribute__((packed)); static_assert(sizeof(LoadStoreWUBIL) == 4, " "); +// Load/Store Word, Unsigned Byte (register) +union LoadStoreWUBR { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _0 : 1; + uint32_t type : 2; + uint32_t imm5 : 5; + uint32_t rt : 4; + uint32_t rn : 4; + uint32_t o1 : 1; + uint32_t W : 1; + uint32_t o2 : 1; + uint32_t u : 1; + uint32_t P : 1; + uint32_t _011 : 3; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(LoadStoreWUBR) == 4, " "); + +// Load/Store Dual, Half, Signed Byte (immediate, literal) +union LoadStoreDualHSBIL { + uint32_t flat; + struct { + uint32_t imm4L : 4; + uint32_t _1_b4 : 1; + uint32_t op2 : 2; + uint32_t _1_b7 : 1; + uint32_t imm4H : 4; + uint32_t rt : 4; + uint32_t rn : 4; + uint32_t o1 : 1; + uint32_t W : 1; + uint32_t _1_b22 : 1; + uint32_t U : 1; + uint32_t P : 1; + uint32_t _000 : 3; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(LoadStoreDualHSBIL) == 4, " "); + +// Load/Store Dual, Half, Signed Byte (register) +union LoadStoreDualHSBR { + uint32_t flat; + struct { + uint32_t rm : 4; + uint32_t _1_b4 : 1; + uint32_t op2 : 2; + uint32_t _1_b7 : 1; + uint32_t _0000 : 4; + uint32_t rt : 4; + uint32_t rn : 4; + uint32_t o1 : 1; + uint32_t W : 1; + uint32_t _0 : 1; + uint32_t U : 1; + uint32_t P : 1; + uint32_t _000 : 3; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(LoadStoreDualHSBR) == 4, " "); + + // Integer Test and Compare (two register, immediate shift) union IntTestCompRRI { uint32_t flat; @@ -1312,7 +1378,6 @@ static const char * const kLoadSWUBIL[] = { [0b1111] = "LDRBp", }; - // P:W o2 o1 Rn //!= 01 0 1 1111 LDR (literal) //!= 01 1 1 1111 LDRB (literal) @@ -1345,9 +1410,7 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { return false; } - auto instruction = kLoadSWUBIL[enc.P << 3u | enc.W << 2u | enc.o2 << 1u | enc.o1]; - - inst.function = instruction; + inst.function = kLoadSWUBIL[enc.P << 3u | enc.W << 2u | enc.o2 << 1u | enc.o1]; auto is_cond = DecodeCondition(inst, enc.cond); // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes @@ -1374,7 +1437,109 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { // Pre or Post Indexing if (write_back) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); - AddAddrRegOp(inst, kIntRegName[enc.rn], 32, Operand::kActionRead, disp + pc_adjust); + AddAddrRegOp(inst, kIntRegName[enc.rn], 32, Operand::kActionRead, + disp + pc_adjust); + } + + if (enc.rt == kPCRegNum) { + if (is_cond) { + inst.branch_not_taken_pc = inst.next_pc; + inst.category = Instruction::kCategoryConditionalIndirectJump; + } else { + inst.category = Instruction::kCategoryIndirectJump; + } + } else { + inst.category = Instruction::kCategoryNormal; + } + return true; +} + +static const char * const kLoadSWUBR[] = { + [0b0000] = "STRp", + [0b0001] = "LDRp", + [0b0010] = "STRT", + [0b0011] = "LDRT", + [0b0100] = "STRB", + [0b0101] = "LDRB", + [0b0110] = "STRBT", + [0b0111] = "LDRBT", + [0b1000] = "STRp", + [0b1001] = "LDRp", + [0b1010] = "STRp", + [0b1011] = "LDRp", + [0b1100] = "STRBp", + [0b1101] = "LDRBp", + [0b1110] = "STRBp", + [0b1111] = "LDRBp", +}; + +// P o2 W o1 +// 0 0 0 0 STR (register) — post-indexed +// 0 0 0 1 LDR (register) — post-indexed +// 0 0 1 0 STRT +// 0 0 1 1 LDRT +// 0 1 0 0 STRB (register) — post-indexed +// 0 1 0 1 LDRB (register) — post-indexed +// 0 1 1 0 STRBT +// 0 1 1 1 LDRBT +// 1 0 0 STR (register) — pre-indexed +// 1 0 1 LDR (register) — pre-indexed +// 1 1 0 STRB (register) — pre-indexed +// 1 1 1 LDRB (register) — pre-indexed +// Offset (P == 1 && W == 0): LDR{}{} , [, {+/-}{, }] +// Post-indexed (P == 0 && W == 0): LDR{}{} , [], {+/-}{, } +// Pre-indexed (P == 1 && W == 1): LDR{}{} , [, {+/-}{, }]! +// Load/Store Word, Unsigned Byte (register) +template +static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { + const LoadStoreWUBR enc = { bits }; + bool write_back = (!enc.P || enc.W); + + // if wback && (n == 15 || n == t) then UNPREDICTABLE; + // if m == 15 then UNPREDICTABLE; + if ((write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt)) + || (enc.rm == kPCRegNum)) { + inst.category = Instruction::kCategoryError; + return false; + } + + inst.function = kLoadSWUBR[enc.P << 3u | enc.o2 << 2u | enc.W << 1u | enc.o1]; + return false; + + auto is_cond = DecodeCondition(inst, enc.cond); + + // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes + int64_t pc_adjust = 0; + if (kAlignPC && enc.rn == kPCRegNum) { + pc_adjust = static_cast(inst.pc & ~(3u)) + - static_cast(inst.pc); + } + + AddShiftRegImmOperand(inst, enc.rm, enc.type, enc.imm5, 0u); + + auto disp = 0;//static_cast(enc.imm12); + + // Subtract + if (!enc.u) { + disp = -disp; + } + + // Not Indexing + if (!enc.P) { + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); + } else { + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, + disp + pc_adjust); + } + + AddIntRegOp(inst, enc.rt, 32, kRegAction); + + // Pre or Post Indexing + if (write_back) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); + AddAddrRegOp(inst, kIntRegName[enc.rn], 32, Operand::kActionRead, + disp + pc_adjust); } if (enc.rt == kPCRegNum) { @@ -1503,17 +1668,21 @@ static bool TryDecodeMoveHalfword(Instruction &inst, uint32_t bits) { if (enc.rd == kPCRegNum) { inst.category = Instruction::kCategoryError; return false; - } else if (!enc.H) { - // (Sonya) This doesn't look like it should be reachable - inst.category = Instruction::kCategoryError; - return false; + } else if (enc.H) { + inst.function = "MOVT"; + } else { + inst.function = "MOVrr"; } - inst.function = "MOVT"; DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); - AddIntRegOp(inst, enc.rd, 32, Operand::kActionRead); + if (enc.H) { + AddIntRegOp(inst, enc.rd, 32, Operand::kActionRead); + } AddImmOp(inst, enc.imm4 << 12 | enc.imm12); + if (!enc.H) { + AddImmOp(inst, 0); + } inst.category = Instruction::kCategoryNormal; return true; } @@ -1854,6 +2023,21 @@ static TryDecode * kLoadStoreWordUBIL[] = { [0b11] = TryDecodeLoadStoreWordUBIL, }; +// Corresponds to: Load/Store Word, Unsigned Byte (register) +// o2<22> | o1<21> +static TryDecode * kLoadStoreWordUBR[] = { + [0b00] = TryDecodeLoadStoreWordUBReg, + [0b01] = TryDecodeLoadStoreWordUBReg, + [0b10] = TryDecodeLoadStoreWordUBReg, + [0b11] = TryDecodeLoadStoreWordUBReg, +}; + +// Extra load/store +static TryDecode * kExtraLoadStore[] = { + [0b0] = nullptr, // TryDecodeLoadStoreDualHalfSignedBReg, + [0b1] = nullptr, // TryDecodeLoadStoreDualHalfSignedBImm, +}; + // Corresponds to: Data-processing and miscellaneous instructions //op0 op1 op2 op3 op4 // 0 1 != 00 1 Extra load/store @@ -1870,9 +2054,10 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { if (!enc.op0) { // op2 == 1, op4 == 1 if (enc.op2 && enc.op4) { - // TODO(Sonya): Extra load/store -- op3 != 00 + // Extra load/store -- op3 != 00 if (!enc.op3) { - return nullptr; + // Index with bit 22 + return kExtraLoadStore[(enc.op1 >> 2) & 0b1]; // op3 == 00 } else { // Multiply and Accumulate -- op1 == 0xxxx @@ -1935,10 +2120,10 @@ static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { } else if (enc.op0 == 0b010u) { const LoadStoreWUBIL enc_ls_word = { bits }; return kLoadStoreWordUBIL[enc_ls_word.o2 << 1u | enc_ls_word.o1]; - // TODO(Sonya): Load/Store Word, Unsigned Byte (register) -- op0 == 011, op1 == 0 + // Load/Store Word, Unsigned Byte (register) -- op0 == 011, op1 == 0 } else if (!enc.op1) { - // This should be returning another table index using a struct like above - return nullptr; + const LoadStoreWUBR enc_ls_word = { bits }; + return kLoadStoreWordUBR[enc_ls_word.o2 << 1u | enc_ls_word.o1]; // TODO(Sonya): Media instructions -- op0 == 011, op1 == 1 } else { // return a result from another function for instruction categorizing From caaa47ffd142b5f85a6197254064e9f64937cd83 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 30 Dec 2020 11:01:10 -0500 Subject: [PATCH 107/130] Load/Store Word, Unsigned Byte (register) --- lib/Arch/AArch32/Decode.cpp | 64 +++++++++++--------------- lib/Arch/AArch32/Semantics/LOGICAL.cpp | 2 + 2 files changed, 28 insertions(+), 38 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 5bf3cdf6a..488265f7a 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -1359,7 +1359,7 @@ static bool TryHalfwordDecodeMultiplyAndAccumulate(Instruction &inst, } -static const char * const kLoadSWUBIL[] = { +static const char * const kLoadSWUB[] = { [0b0000] = "STRp", [0b0001] = "LDRp", [0b0010] = "STRBp", @@ -1410,7 +1410,7 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { return false; } - inst.function = kLoadSWUBIL[enc.P << 3u | enc.W << 2u | enc.o2 << 1u | enc.o1]; + inst.function = kLoadSWUB[enc.P << 3u | enc.W << 2u | enc.o2 << 1u | enc.o1]; auto is_cond = DecodeCondition(inst, enc.cond); // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes @@ -1454,37 +1454,18 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { return true; } -static const char * const kLoadSWUBR[] = { - [0b0000] = "STRp", - [0b0001] = "LDRp", - [0b0010] = "STRT", - [0b0011] = "LDRT", - [0b0100] = "STRB", - [0b0101] = "LDRB", - [0b0110] = "STRBT", - [0b0111] = "LDRBT", - [0b1000] = "STRp", - [0b1001] = "LDRp", - [0b1010] = "STRp", - [0b1011] = "LDRp", - [0b1100] = "STRBp", - [0b1101] = "LDRBp", - [0b1110] = "STRBp", - [0b1111] = "LDRBp", -}; - // P o2 W o1 -// 0 0 0 0 STR (register) — post-indexed +// 0 0 0 0 STR (register) — post-indexed if m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; // 0 0 0 1 LDR (register) — post-indexed -// 0 0 1 0 STRT +// 0 0 1 0 STRT if n == 15 || n == t || m == 15 then UNPREDICTABLE; // 0 0 1 1 LDRT -// 0 1 0 0 STRB (register) — post-indexed +// 0 1 0 0 STRB (register) — post-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; // 0 1 0 1 LDRB (register) — post-indexed -// 0 1 1 0 STRBT +// 0 1 1 0 STRBT if t == 15 || n == 15 || n == t then UNPREDICTABLE; // 0 1 1 1 LDRBT -// 1 0 0 STR (register) — pre-indexed +// 1 0 0 STR (register) — pre-indexed if m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; // 1 0 1 LDR (register) — pre-indexed -// 1 1 0 STRB (register) — pre-indexed +// 1 1 0 STRB (register) — pre-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; // 1 1 1 LDRB (register) — pre-indexed // Offset (P == 1 && W == 0): LDR{}{} , [, {+/-}{, }] // Post-indexed (P == 0 && W == 0): LDR{}{} , [], {+/-}{, } @@ -1497,16 +1478,14 @@ static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { bool write_back = (!enc.P || enc.W); // if wback && (n == 15 || n == t) then UNPREDICTABLE; - // if m == 15 then UNPREDICTABLE; if ((write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt)) - || (enc.rm == kPCRegNum)) { + || (enc.rm == kPCRegNum && (enc.P || !enc.o2 || !enc.W)) + || (enc.rt == kPCRegNum && enc.o2)) { inst.category = Instruction::kCategoryError; return false; } - inst.function = kLoadSWUBR[enc.P << 3u | enc.o2 << 2u | enc.W << 1u | enc.o1]; - return false; - + inst.function = kLoadSWUB[enc.P << 3u | enc.W << 2u | enc.o2 << 1u | enc.o1]; auto is_cond = DecodeCondition(inst, enc.cond); // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes @@ -1517,12 +1496,15 @@ static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { } AddShiftRegImmOperand(inst, enc.rm, enc.type, enc.imm5, 0u); - - auto disp = 0;//static_cast(enc.imm12); + auto disp_expr = inst.operands.back().expr; + inst.operands.pop_back(); // Subtract if (!enc.u) { - disp = -disp; + const auto word_type = inst.arch->AddressType(); + const auto _0 = llvm::ConstantInt::get(word_type, 0, true); + disp_expr = inst.EmplaceBinaryOp(llvm::Instruction::Sub, + inst.EmplaceConstant(_0), disp_expr); } // Not Indexing @@ -1530,7 +1512,10 @@ static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); } else { AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, - disp + pc_adjust); + pc_adjust); + inst.operands.back().expr = inst.EmplaceBinaryOp(llvm::Instruction::Add, + inst.operands.back().expr, + disp_expr); } AddIntRegOp(inst, enc.rt, 32, kRegAction); @@ -1539,7 +1524,10 @@ static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { if (write_back) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); AddAddrRegOp(inst, kIntRegName[enc.rn], 32, Operand::kActionRead, - disp + pc_adjust); + pc_adjust); + inst.operands.back().expr = inst.EmplaceBinaryOp(llvm::Instruction::Add, + inst.operands.back().expr, + disp_expr); } if (enc.rt == kPCRegNum) { @@ -1671,7 +1659,7 @@ static bool TryDecodeMoveHalfword(Instruction &inst, uint32_t bits) { } else if (enc.H) { inst.function = "MOVT"; } else { - inst.function = "MOVrr"; + inst.function = "MOVW"; } DecodeCondition(inst, enc.cond); diff --git a/lib/Arch/AArch32/Semantics/LOGICAL.cpp b/lib/Arch/AArch32/Semantics/LOGICAL.cpp index ff2101e6e..4229442c0 100644 --- a/lib/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/lib/Arch/AArch32/Semantics/LOGICAL.cpp @@ -64,6 +64,8 @@ DEF_ISEL(BICSrr) = BICS; DEF_ISEL(MVNrr) = BIC; DEF_ISEL(MVNSrr) = BICS; +DEF_ISEL(MOVW) = ORR; + namespace { DEF_COND_SEM(MOVT, R32W dst, R32 src1, R32 src2){ auto value = ZExt(Trunc(Read(src1))); From 03d3306bdab7fb6b25f4cbb8af626a0535a6a69e Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 30 Dec 2020 14:45:04 -0500 Subject: [PATCH 108/130] Finished testing load/Store Word, Unsigned Byte (register) --- lib/Arch/AArch32/Decode.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 488265f7a..a93bce8be 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -1497,14 +1497,10 @@ static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { AddShiftRegImmOperand(inst, enc.rm, enc.type, enc.imm5, 0u); auto disp_expr = inst.operands.back().expr; + auto disp_op = llvm::Instruction::Add; inst.operands.pop_back(); - - // Subtract if (!enc.u) { - const auto word_type = inst.arch->AddressType(); - const auto _0 = llvm::ConstantInt::get(word_type, 0, true); - disp_expr = inst.EmplaceBinaryOp(llvm::Instruction::Sub, - inst.EmplaceConstant(_0), disp_expr); + disp_op = llvm::Instruction::Sub; } // Not Indexing @@ -1513,7 +1509,7 @@ static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { } else { AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); - inst.operands.back().expr = inst.EmplaceBinaryOp(llvm::Instruction::Add, + inst.operands.back().expr = inst.EmplaceBinaryOp(disp_op, inst.operands.back().expr, disp_expr); } @@ -1525,7 +1521,7 @@ static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); AddAddrRegOp(inst, kIntRegName[enc.rn], 32, Operand::kActionRead, pc_adjust); - inst.operands.back().expr = inst.EmplaceBinaryOp(llvm::Instruction::Add, + inst.operands.back().expr = inst.EmplaceBinaryOp(disp_op, inst.operands.back().expr, disp_expr); } From 9de9323c37d5ea0c4a3cd5263e19b9d1a1b1834e Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 5 Jan 2021 22:40:29 -0500 Subject: [PATCH 109/130] Load/Store Dual, Half, Signed Byte (register) --- lib/Arch/AArch32/Decode.cpp | 244 ++++++++++++++++++++++++++++- lib/Arch/AArch32/Semantics/MEM.cpp | 162 ++++++++++++++++++- 2 files changed, 396 insertions(+), 10 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index a93bce8be..57b8634da 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -1487,6 +1487,8 @@ static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { inst.function = kLoadSWUB[enc.P << 3u | enc.W << 2u | enc.o2 << 1u | enc.o1]; auto is_cond = DecodeCondition(inst, enc.cond); + bool is_add = enc.u; + bool is_index = enc.P; // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes int64_t pc_adjust = 0; @@ -1499,12 +1501,184 @@ static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { auto disp_expr = inst.operands.back().expr; auto disp_op = llvm::Instruction::Add; inst.operands.pop_back(); - if (!enc.u) { + if (!is_add) { + disp_op = llvm::Instruction::Sub; + } + + // Indexing + if (!is_index) { + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); + } else { + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, + pc_adjust); + inst.operands.back().expr = inst.EmplaceBinaryOp(disp_op, + inst.operands.back().expr, + disp_expr); + } + + AddIntRegOp(inst, enc.rt, 32, kRegAction); + + // Pre or Post Indexing + if (write_back) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); + AddAddrRegOp(inst, kIntRegName[enc.rn], 32, Operand::kActionRead, + pc_adjust); + inst.operands.back().expr = inst.EmplaceBinaryOp(disp_op, + inst.operands.back().expr, + disp_expr); + } + + if (enc.rt == kPCRegNum) { + if (is_cond) { + inst.branch_not_taken_pc = inst.next_pc; + inst.category = Instruction::kCategoryConditionalIndirectJump; + } else { + inst.category = Instruction::kCategoryIndirectJump; + } + } else { + inst.category = Instruction::kCategoryNormal; + } + return true; +} + +// op2 != 00 for extra load store instructions +// (see: Data-processing and miscellaneous instructions & Extra load/store) +static const char * const kLoadStoreDHSB[] = { + [0b00010] = "LDRDp", + [0b00001] = "STRHp", + [0b00011] = "STRDp", + [0b00101] = "LDRHp", + [0b00110] = "LDRSBp", + [0b00111] = "LDRSHp", + [0b01010] = nullptr, + [0b01001] = "STRHT", + [0b01011] = nullptr, + [0b01101] = "LDRHT", + [0b01110] = "LDRSBT", + [0b01111] = "LDRSHT", + [0b10010] = "LDRD", + [0b10001] = "STRH", + [0b10011] = "STRD", + [0b10101] = "LDRH", + [0b10110] = "LDRSB", + [0b10111] = "LDRSH", + [0b11010] = "LDRDp", + [0b11001] = "STRHp", + [0b11011] = "STRDp", + [0b11101] = "LDRHp", + [0b11110] = "LDRSBp", + [0b11111] = "LDRSHp", +}; + +//P:W o1 Rn op2 +// 0 1111 10 LDRD (literal) +//!= 01 1 1111 01 LDRH (literal) +//!= 01 1 1111 10 LDRSB (literal) +//!= 01 1 1111 11 LDRSH (literal) +// 00 0 != 1111 10 LDRD (immediate) — post-indexed +// 00 0 01 STRH (immediate) — post-indexed +// 00 0 11 STRD (immediate) — post-indexed +// 00 1 != 1111 01 LDRH (immediate) — post-indexed +// 00 1 != 1111 10 LDRSB (immediate) — post-indexed +// 00 1 != 1111 11 LDRSH (immediate) — post-indexed +// 01 0 != 1111 10 UNALLOCATED +// 01 0 01 STRHT +// 01 0 11 UNALLOCATED +// 01 1 01 LDRHT +// 01 1 10 LDRSBT +// 01 1 11 LDRSHT +// 10 0 != 1111 10 LDRD (immediate) — offset +// 10 0 01 STRH (immediate) — offset +// 10 0 11 STRD (immediate) — offset +// 10 1 != 1111 01 LDRH (immediate) — offset +// 10 1 != 1111 10 LDRSB (immediate) — offset +// 10 1 != 1111 11 LDRSH (immediate) — offset +// 11 0 != 1111 10 LDRD (immediate) — pre-indexed +// 11 0 01 STRH (immediate) — pre-indexed +// 11 0 11 STRD (immediate) — pre-indexed +// 11 1 != 1111 01 LDRH (immediate) — pre-indexed +// 11 1 != 1111 10 LDRSB (immediate) — pre-indexed +// 11 1 != 1111 11 LDRSH (immediate) — pre-indexed +// Load/Store Dual, Half, Signed Byte (immediate, literal) +template +static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst, + uint32_t bits) { + const LoadStoreDualHSBIL enc = { bits }; + auto instruction = + kLoadStoreDHSB[enc.P << 4 | enc.W << 3 | enc.o1 << 2 | enc.op2]; + if (enc.rn == kPCRegNum && !instruction && enc.op2 == 0b10) { + inst.function = "LDRDp"; + } else if (instruction) { + inst.function = instruction; + } else { + inst.category = Instruction::kCategoryError; + return false; + } + + return false; +} + +// P W o1 op2 +// 0 0 0 01 STRH (register) — post-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 0 0 0 10 LDRD (register) — post-indexed +// if t2 == 15 || m == 15 || m == t || m == t2 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; +// 0 0 0 11 STRD (register) — post-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 0 0 1 01 LDRH (register) — post-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 0 0 1 10 LDRSB (register) — post-indexed +// 0 0 1 11 LDRSH (register) — post-indexed +// 0 1 0 01 STRHT if t == 15 || n == 15 || n == t then UNPREDICTABLE; +// 0 1 0 10 UNALLOCATED +// 0 1 0 11 UNALLOCATED +// 0 1 1 01 LDRHT if t == 15 || n == 15 || n == t then UNPREDICTABLE; +// 0 1 1 10 LDRSBT if t == 15 || n == 15 || n == t then UNPREDICTABLE; +// 0 1 1 11 LDRSHT if t == 15 || n == 15 || n == t then UNPREDICTABLE; +// 1 0 01 STRH (register) — pre-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 1 0 10 LDRD (register) — pre-indexed +// 1 0 11 STRD (register) — pre-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 1 1 01 LDRH (register) — pre-indexed +// 1 1 10 LDRSB (register) — pre-indexed +// 1 1 11 LDRSH (register) — pre-indexed +// TODO: Load/Store Dual, Half, Signed Byte (register) +template +static bool TryDecodeLoadStoreDualHalfSignedBReg(Instruction &inst, + uint32_t bits) { + const LoadStoreDualHSBR enc = { bits }; + inst.function = + kLoadStoreDHSB[enc.P << 4 | enc.W << 3 | enc.o1 << 2 | enc.op2]; + + bool write_back = (!enc.P || enc.W); + bool is_add = enc.U; + bool is_index = enc.P; + + // TODO(Sonya): FIXME! Finish this complicated error condition + if (write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt)) { + inst.category = Instruction::kCategoryError; + return false; + } + auto is_cond = DecodeCondition(inst, enc.cond); + + // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes + int64_t pc_adjust = 0; + if (kAlignPC && enc.rn == kPCRegNum) { + pc_adjust = static_cast(inst.pc & ~(3u)) + - static_cast(inst.pc); + } + + // Note: AArch32 has shift_size = 0 and type = LSL so disp is an unshifted reg + // Thumb instructions have shift + AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); + auto disp_expr = inst.operands.back().expr; + auto disp_op = llvm::Instruction::Add; + inst.operands.pop_back(); + + if (!is_add) { disp_op = llvm::Instruction::Sub; } // Not Indexing - if (!enc.P) { + if (!is_index) { AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); } else { AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, @@ -1515,6 +1689,10 @@ static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { } AddIntRegOp(inst, enc.rt, 32, kRegAction); + // Add t2 = t + 1 reg for dual instructions + if (kMemSize == 64u) { + AddIntRegOp(inst, enc.rt + 1, 32, kRegAction); + } // Pre or Post Indexing if (write_back) { @@ -2018,8 +2196,54 @@ static TryDecode * kLoadStoreWordUBR[] = { // Extra load/store static TryDecode * kExtraLoadStore[] = { - [0b0] = nullptr, // TryDecodeLoadStoreDualHalfSignedBReg, - [0b1] = nullptr, // TryDecodeLoadStoreDualHalfSignedBImm, + [0b000001] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b000010] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b000011] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b000101] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b000110] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b000111] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b001001] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b001010] = nullptr, + [0b001011] = nullptr, + [0b001101] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b001110] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b001111] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b010001] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b010010] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b010011] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b010101] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b010110] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b010111] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b011001] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b011010] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b011011] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b011101] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b011110] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b011111] = TryDecodeLoadStoreDualHalfSignedBReg, + [0b100001] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b100010] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b100011] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b100101] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b100110] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b100111] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b101001] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b101010] = TryDecodeLoadStoreDualHalfSignedBIL, // only valid for Rn == 15 (PC) + [0b101011] = nullptr, + [0b101101] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b101110] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b101111] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b110001] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b110010] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b110011] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b110101] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b110110] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b110111] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b111001] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b111010] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b111011] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b111101] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b111110] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b111111] = TryDecodeLoadStoreDualHalfSignedBIL, }; // Corresponds to: Data-processing and miscellaneous instructions @@ -2039,9 +2263,13 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { // op2 == 1, op4 == 1 if (enc.op2 && enc.op4) { // Extra load/store -- op3 != 00 - if (!enc.op3) { - // Index with bit 22 - return kExtraLoadStore[(enc.op1 >> 2) & 0b1]; + if (enc.op3) { + // Index with <22> | P <24> | W <21> | o1 <20> | op2 != 00 <6:5> + return kExtraLoadStore[(((enc.op1 >> 2) & 0b1) << 5) + | ((enc.op1 >> 4) << 4) + | (((enc.op1 >> 1) & 0b1) << 3) + | ((enc.op1 & 0b1) << 2) + | enc.op3 ]; // op3 == 00 } else { // Multiply and Accumulate -- op1 == 0xxxx @@ -2098,7 +2326,7 @@ static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { if (!(enc.op0 >> 2)) { if (enc.cond != 0b1111u) { // Data-processing and miscellaneous instructions -- op0 == 00x - if (!(enc.op0 >> 1)) { + if (~(enc.op0 >> 1)) { return TryDataProcessingAndMisc(bits); // Load/Store Word, Unsigned Byte (immediate, literal) -- op0 == 010 } else if (enc.op0 == 0b010u) { diff --git a/lib/Arch/AArch32/Semantics/MEM.cpp b/lib/Arch/AArch32/Semantics/MEM.cpp index 9db2703a2..161c70a08 100644 --- a/lib/Arch/AArch32/Semantics/MEM.cpp +++ b/lib/Arch/AArch32/Semantics/MEM.cpp @@ -18,7 +18,7 @@ namespace { // Offset DEF_COND_SEM(STR, M32W dst, R32 src1) { auto src = Read(src1); - Write(dst, TruncTo(src)); + Write(dst, src); return memory; } @@ -32,7 +32,7 @@ DEF_COND_SEM(STRB, M8W dst, R32 src1) { DEF_COND_SEM(STRp, M32W dst, R32 src1, R32W dst_reg, R32 src2) { auto src = Read(src1); auto new_val = Read(src2); - Write(dst, TruncTo(src)); + Write(dst, src); Write(dst_reg, new_val); return memory; } @@ -128,3 +128,161 @@ DEF_ISEL(STRT) = STRT; DEF_ISEL(STRBT) = STRTB; DEF_ISEL(LDRT) = LDRT; DEF_ISEL(LDRBT) = LDRTB; + +namespace { +// Offset +DEF_COND_SEM(STRH, M16W dst, R32 src1) { + auto src = Read(src1); + Write(dst, TruncTo(src)); + return memory; +} + +// Pre + Post +DEF_COND_SEM(STRHp, M16W dst, R32 src1, R32W dst_reg, R32 src2) { + auto src = Read(src1); + auto new_val = Read(src2); + Write(dst, TruncTo(src)); + Write(dst_reg, new_val); + return memory; +} + +// Offset +DEF_COND_SEM(LDRH, M16 src1, R32W dst) { + auto src = Read(src1); + WriteZExt(dst, src); + return memory; +} + +// Pre + Post +DEF_COND_SEM(LDRHp, M16 src1, R32W dst, R32W dst_reg, R32 src2) { + auto src = Read(src1); + auto new_val = Read(src2); + WriteZExt(dst, src); + Write(dst_reg, new_val); + return memory; +} + +// Offset +DEF_COND_SEM(STRD, M64W dst, R32 src1, R32 src2) { + auto lhs = UShl(ZExt(Read(src2)), 32ul); + auto rhs = ZExt(Read(src1)); + auto src = UOr(lhs, rhs); + WriteTrunc(dst, src); + return memory; +} + +// Pre + Post +DEF_COND_SEM(STRDp, M64W dst, R32 src1, R32 src2, R32W dst_reg, R32 src_new) { + auto lhs = UShl(ZExt(Read(src2)), 32ul); + auto rhs = ZExt(Read(src1)); + auto src = UOr(lhs, rhs); + auto new_val = Read(src_new); + WriteTrunc(dst, src); + Write(dst_reg, new_val); + return memory; +} + +// Offset +DEF_COND_SEM(LDRD, M64 src1, R32W dst1, R32W dst2) { + auto src = Read(src1); + Write(dst1, TruncTo(src)); + Write(dst2, TruncTo(UShr(src, 32ul))); + return memory; +} + +// Pre + Post +DEF_COND_SEM(LDRDp, M64 src1, R32W dst1, R32W dst2, R32W dst_reg, R32 src2) { + auto src = Read(src1); + auto new_val = Read(src2); + Write(dst1, TruncTo(src)); + Write(dst2, TruncTo(UShr(src, 32ul))); + Write(dst_reg, new_val); + return memory; +} + +// Offset +DEF_COND_SEM(LDRSB, M8 src1, R32W dst) { + auto src = Read(src1); + WriteSExt(dst, src); + return memory; +} + +// Pre + Post +DEF_COND_SEM(LDRSBp, M8 src1, R32W dst, R32W dst_reg, R32 src2) { + auto src = Read(src1); + auto new_val = Read(src2); + WriteSExt(dst, src); + Write(dst_reg, new_val); + return memory; +} + +// Offset +DEF_COND_SEM(LDRSH, M16 src1, R32W dst) { + auto src = Read(src1); + WriteSExt(dst, src); + return memory; +} + +// Pre + Post +DEF_COND_SEM(LDRSHp, M16 src1, R32W dst, R32W dst_reg, R32 src2) { + auto src = Read(src1); + auto new_val = Read(src2); + WriteSExt(dst, src); + Write(dst_reg, new_val); + return memory; +} + +DEF_COND_SEM(STRHT, M16W dst, R32 src1, R32W dst_reg, R32 src2) { + memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + auto src = Read(src1); + auto new_val = Read(src2); + WriteTrunc(dst, src); + Write(dst_reg, new_val); + return memory; +} + +DEF_COND_SEM(LDRHT, M16 src1, R32W dst, R32W dst_reg, R32 src2) { + memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + auto src = Read(src1); + auto new_val = Read(src2); + WriteZExt(dst, src); + Write(dst_reg, new_val); + return memory; +} + +DEF_COND_SEM(LDRSBT, M8 src1, R32W dst, R32W dst_reg, R32 src2) { + memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + auto src = Read(src1); + auto new_val = Read(src2); + WriteSExt(dst, src); + Write(dst_reg, new_val); + return memory; +} + +DEF_COND_SEM(LDRSHT, M16 src1, R32W dst, R32W dst_reg, R32 src2) { + memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + auto src = Read(src1); + auto new_val = Read(src2); + WriteSExt(dst, src); + Write(dst_reg, new_val); + return memory; +} + +} // namespace + +DEF_ISEL(STRH) = STRH; +DEF_ISEL(STRHp) = STRHp; +DEF_ISEL(LDRH) = LDRH; +DEF_ISEL(LDRHp) = LDRHp; +DEF_ISEL(STRD) = STRD; +DEF_ISEL(STRDp) = STRDp; +DEF_ISEL(LDRD) = LDRD; +DEF_ISEL(LDRDp) = LDRDp; +DEF_ISEL(LDRSB) = LDRSB; +DEF_ISEL(LDRSBp) = LDRSBp; +DEF_ISEL(LDRSH) = LDRSH; +DEF_ISEL(LDRSHp) = LDRSHp; +DEF_ISEL(STRHT) = STRHT; +DEF_ISEL(LDRHT) = LDRHT; +DEF_ISEL(LDRSBT) = LDRSBT; +DEF_ISEL(LDRSHT) = LDRSHT; From 0b9e8412f497343c41e07bba13289dfcd211bc01 Mon Sep 17 00:00:00 2001 From: sschriner Date: Tue, 5 Jan 2021 22:57:21 -0500 Subject: [PATCH 110/130] Rest of Extra load store: Load/Store Dual, Half, Signed Byte (immediate, literal) --- lib/Arch/AArch32/Decode.cpp | 57 ++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 57b8634da..0fb4d882c 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -1616,7 +1616,62 @@ static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst, return false; } - return false; + bool write_back = (!enc.P || enc.W); + bool is_add = enc.U; + bool is_index = enc.P; + + // TODO(Sonya): FIXME! Finish this complicated error condition + if (write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt)) { + inst.category = Instruction::kCategoryError; + return false; + } + auto is_cond = DecodeCondition(inst, enc.cond); + + // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes + int64_t pc_adjust = 0; + if (kAlignPC && enc.rn == kPCRegNum) { + pc_adjust = static_cast(inst.pc & ~(3u)) + - static_cast(inst.pc); + } + + auto disp = static_cast(enc.imm4H << 4 | enc.imm4L); + + // Subtract + if (!is_add) { + disp = -disp; + } + + // Not Indexing + if (!is_index) { + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); + } else { + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, disp + pc_adjust); + } + + AddIntRegOp(inst, enc.rt, 32, kRegAction); + // Add t2 = t + 1 reg for dual instructions + if (kMemSize == 64u) { + AddIntRegOp(inst, enc.rt + 1, 32, kRegAction); + } + + // Pre or Post Indexing + if (write_back) { + AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); + AddAddrRegOp(inst, kIntRegName[enc.rn], 32, Operand::kActionRead, + disp + pc_adjust); + } + + if (enc.rt == kPCRegNum) { + if (is_cond) { + inst.branch_not_taken_pc = inst.next_pc; + inst.category = Instruction::kCategoryConditionalIndirectJump; + } else { + inst.category = Instruction::kCategoryIndirectJump; + } + } else { + inst.category = Instruction::kCategoryNormal; + } + return true; } // P W o1 op2 From 4138ac4e6e408678128bc18e1228f518484d9a48 Mon Sep 17 00:00:00 2001 From: sschriner Date: Mon, 11 Jan 2021 17:36:39 -0500 Subject: [PATCH 111/130] Finished testing all the Load/store additions --- lib/Arch/AArch32/Decode.cpp | 135 ++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 59 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 0fb4d882c..d05d43bc3 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -1405,6 +1405,8 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { const LoadStoreWUBIL enc = { bits }; bool write_back = (!enc.P || enc.W); + bool is_add = enc.u; + bool is_index = enc.P; if (write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt)) { inst.category = Instruction::kCategoryError; return false; @@ -1421,12 +1423,12 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { auto disp = static_cast(enc.imm12); // Subtract - if (!enc.u) { + if (!is_add) { disp = -disp; } // Not Indexing - if (!enc.P) { + if (!is_index) { AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); } else { AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, disp + pc_adjust); @@ -1571,34 +1573,34 @@ static const char * const kLoadStoreDHSB[] = { }; //P:W o1 Rn op2 -// 0 1111 10 LDRD (literal) -//!= 01 1 1111 01 LDRH (literal) -//!= 01 1 1111 10 LDRSB (literal) -//!= 01 1 1111 11 LDRSH (literal) -// 00 0 != 1111 10 LDRD (immediate) — post-indexed -// 00 0 01 STRH (immediate) — post-indexed -// 00 0 11 STRD (immediate) — post-indexed -// 00 1 != 1111 01 LDRH (immediate) — post-indexed -// 00 1 != 1111 10 LDRSB (immediate) — post-indexed -// 00 1 != 1111 11 LDRSH (immediate) — post-indexed +// 0 1111 10 LDRD (literal) if Rt<0> == '1' t2 == 15 || wback then UNPREDICTABLE; +//!= 01 1 1111 01 LDRH (literal) if t == 15 || wback then UNPREDICTABLE; +//!= 01 1 1111 10 LDRSB (literal) if t == 15 || wback then UNPREDICTABLE; +//!= 01 1 1111 11 LDRSH (literal) if t == 15 || wback then UNPREDICTABLE; +// 00 0 != 1111 10 LDRD (immediate) — post-indexed if t2 == 15 wback && (n == t || n == t2) then UNPREDICTABLE; +// 00 0 01 STRH (immediate) — post-indexed if t == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 00 0 11 STRD (immediate) — post-indexed if t2 == 15 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; +// 00 1 != 1111 01 LDRH (immediate) — post-indexed if t == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 00 1 != 1111 10 LDRSB (immediate) — post-indexed if t == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 00 1 != 1111 11 LDRSH (immediate) — post-indexed if t == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; // 01 0 != 1111 10 UNALLOCATED -// 01 0 01 STRHT +// 01 0 01 STRHT if t == 15 || n == 15 || n == t then UNPREDICTABLE; // 01 0 11 UNALLOCATED -// 01 1 01 LDRHT -// 01 1 10 LDRSBT -// 01 1 11 LDRSHT -// 10 0 != 1111 10 LDRD (immediate) — offset -// 10 0 01 STRH (immediate) — offset -// 10 0 11 STRD (immediate) — offset -// 10 1 != 1111 01 LDRH (immediate) — offset -// 10 1 != 1111 10 LDRSB (immediate) — offset -// 10 1 != 1111 11 LDRSH (immediate) — offset -// 11 0 != 1111 10 LDRD (immediate) — pre-indexed -// 11 0 01 STRH (immediate) — pre-indexed -// 11 0 11 STRD (immediate) — pre-indexed -// 11 1 != 1111 01 LDRH (immediate) — pre-indexed -// 11 1 != 1111 10 LDRSB (immediate) — pre-indexed -// 11 1 != 1111 11 LDRSH (immediate) — pre-indexed +// 01 1 01 LDRHT if t == 15 || n == 15 || n == t then UNPREDICTABLE; +// 01 1 10 LDRSBT if t == 15 || n == 15 || n == t then UNPREDICTABLE; +// 01 1 11 LDRSHT if t == 15 || n == 15 || n == t then UNPREDICTABLE; +// 10 0 != 1111 10 LDRD (immediate) — offset if t2 == 15 wback && (n == t || n == t2) then UNPREDICTABLE; +// 10 0 01 STRH (immediate) — offset if t == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 10 0 11 STRD (immediate) — offset if t2 == 15 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; +// 10 1 != 1111 01 LDRH (immediate) — offset if t == 15 wback && n == t then UNPREDICTABLE; +// 10 1 != 1111 10 LDRSB (immediate) — offset if t == 15 wback && n == t then UNPREDICTABLE; +// 10 1 != 1111 11 LDRSH (immediate) — offset if t == 15 wback && n == t then UNPREDICTABLE; +// 11 0 != 1111 10 LDRD (immediate) — pre-indexed if t2 == 15 wback && (n == t || n == t2) then UNPREDICTABLE; +// 11 0 01 STRH (immediate) — pre-indexed if t == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 11 0 11 STRD (immediate) — pre-indexed if t2 == 15 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; +// 11 1 != 1111 01 LDRH (immediate) — pre-indexed if t == 15 wback && n == t then UNPREDICTABLE; +// 11 1 != 1111 10 LDRSB (immediate) — pre-indexed if t == 15 wback && n == t then UNPREDICTABLE; +// 11 1 != 1111 11 LDRSH (immediate) — pre-indexed if t == 15 wback && n == t then UNPREDICTABLE; // Load/Store Dual, Half, Signed Byte (immediate, literal) template @@ -1608,6 +1610,10 @@ static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst, auto instruction = kLoadStoreDHSB[enc.P << 4 | enc.W << 3 | enc.o1 << 2 | enc.op2]; if (enc.rn == kPCRegNum && !instruction && enc.op2 == 0b10) { + if (enc.rt &0b1) { + inst.category = Instruction::kCategoryError; + return false; + } inst.function = "LDRDp"; } else if (instruction) { inst.function = instruction; @@ -1619,9 +1625,13 @@ static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst, bool write_back = (!enc.P || enc.W); bool is_add = enc.U; bool is_index = enc.P; + bool is_dual = !enc.o1 && enc.op2 >> 1; + uint32_t rt2 = enc.rt + 1; - // TODO(Sonya): FIXME! Finish this complicated error condition - if (write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt)) { + if ((!is_dual && enc.rt == kPCRegNum) || (is_dual && rt2 == kPCRegNum) + || (write_back + && (enc.rn == kPCRegNum || enc.rn == enc.rt + || (is_dual && enc.rn == rt2)))) { inst.category = Instruction::kCategoryError; return false; } @@ -1650,7 +1660,7 @@ static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst, AddIntRegOp(inst, enc.rt, 32, kRegAction); // Add t2 = t + 1 reg for dual instructions - if (kMemSize == 64u) { + if (is_dual) { AddIntRegOp(inst, enc.rt + 1, 32, kRegAction); } @@ -1675,42 +1685,52 @@ static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst, } // P W o1 op2 -// 0 0 0 01 STRH (register) — post-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; -// 0 0 0 10 LDRD (register) — post-indexed -// if t2 == 15 || m == 15 || m == t || m == t2 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; -// 0 0 0 11 STRD (register) — post-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; -// 0 0 1 01 LDRH (register) — post-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; -// 0 0 1 10 LDRSB (register) — post-indexed -// 0 0 1 11 LDRSH (register) — post-indexed -// 0 1 0 01 STRHT if t == 15 || n == 15 || n == t then UNPREDICTABLE; +// 0 0 0 01 STRH (register) — post-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 0 0 0 10 LDRD (register) — post-indexed if t2 == 15 || m == 15 || m == t || m == t2 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; +// 0 0 0 11 STRD (register) — post-indexed if t2 == 15 || m == 15 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; +// 0 0 1 01 LDRH (register) — post-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 0 0 1 10 LDRSB (register) — post-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 0 0 1 11 LDRSH (register) — post-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE +// 0 1 0 01 STRHT if t == 15 || n == 15 || n == t || m == 15 then UNPREDICTABLE; // 0 1 0 10 UNALLOCATED // 0 1 0 11 UNALLOCATED -// 0 1 1 01 LDRHT if t == 15 || n == 15 || n == t then UNPREDICTABLE; -// 0 1 1 10 LDRSBT if t == 15 || n == 15 || n == t then UNPREDICTABLE; -// 0 1 1 11 LDRSHT if t == 15 || n == 15 || n == t then UNPREDICTABLE; -// 1 0 01 STRH (register) — pre-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; -// 1 0 10 LDRD (register) — pre-indexed -// 1 0 11 STRD (register) — pre-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; -// 1 1 01 LDRH (register) — pre-indexed -// 1 1 10 LDRSB (register) — pre-indexed -// 1 1 11 LDRSH (register) — pre-indexed -// TODO: Load/Store Dual, Half, Signed Byte (register) +// 0 1 1 01 LDRHT if t == 15 || n == 15 || n == t || m == 15 then UNPREDICTABLE; +// 0 1 1 10 LDRSBT if t == 15 || n == 15 || n == t || m == 15 then UNPREDICTABLE; +// 0 1 1 11 LDRSHT if t == 15 || n == 15 || n == t || m == 15 then UNPREDICTABLE; +// 1 0 01 STRH (register) — pre-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 1 0 10 LDRD (register) — pre-indexed if t2 == 15 || m == 15 || m == t || m == t2 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; +// 1 0 11 STRD (register) — pre-indexed if t2 == 15 || m == 15 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; +// 1 1 01 LDRH (register) — pre-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 1 1 10 LDRSB (register) — pre-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; +// 1 1 11 LDRSH (register) — pre-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE +// Load/Store Dual, Half, Signed Byte (register) template static bool TryDecodeLoadStoreDualHalfSignedBReg(Instruction &inst, uint32_t bits) { const LoadStoreDualHSBR enc = { bits }; - inst.function = + auto instruction = kLoadStoreDHSB[enc.P << 4 | enc.W << 3 | enc.o1 << 2 | enc.op2]; bool write_back = (!enc.P || enc.W); bool is_add = enc.U; bool is_index = enc.P; - - // TODO(Sonya): FIXME! Finish this complicated error condition - if (write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt)) { + bool is_dual = !enc.o1 && enc.op2 >> 1; + bool is_unpriv = enc.W && !enc.P; + uint32_t rt2 = enc.rt + 1; + + if (!instruction + || (write_back + && (enc.rn == kPCRegNum || enc.rn == enc.rt + || (is_dual && enc.rn == rt2) + || (is_unpriv && (enc.rt == kPCRegNum || enc.rm == kPCRegNum)))) + || (is_dual + && (enc.rt == kLRRegNum || enc.rm == kPCRegNum + || (enc.op2 == 0b10 && (enc.rm == enc.rt || enc.rm == rt2))))) { inst.category = Instruction::kCategoryError; return false; + } else { + inst.function = instruction; } auto is_cond = DecodeCondition(inst, enc.cond); @@ -1744,9 +1764,9 @@ static bool TryDecodeLoadStoreDualHalfSignedBReg(Instruction &inst, } AddIntRegOp(inst, enc.rt, 32, kRegAction); - // Add t2 = t + 1 reg for dual instructions - if (kMemSize == 64u) { - AddIntRegOp(inst, enc.rt + 1, 32, kRegAction); + + if (is_dual) { + AddIntRegOp(inst, rt2, 32, kRegAction); } // Pre or Post Indexing @@ -2393,12 +2413,10 @@ static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { return kLoadStoreWordUBR[enc_ls_word.o2 << 1u | enc_ls_word.o1]; // TODO(Sonya): Media instructions -- op0 == 011, op1 == 1 } else { - // return a result from another function for instruction categorizing return nullptr; } // TODO(Sonya): Unconditional instructions -- cond == 1111 } else { - // return a result from another function for instruction categorizing return nullptr; } // op0 == 1xx @@ -2417,7 +2435,6 @@ static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { } // TODO(Sonya): System register access, Advanced SIMD, floating-point, and Supervisor call -- op0 == 11x } else { - // return a result from another function for instruction categorizing return nullptr; } } From b9699c7911e6dd42ad37a319076d4c8ef8d2efb0 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 13 Jan 2021 23:25:59 -0500 Subject: [PATCH 112/130] Signed multiply, Divide --- lib/Arch/AArch32/Decode.cpp | 258 +++++++++++++++++++++++++- lib/Arch/AArch32/Semantics/BINARY.cpp | 147 ++++++++++++++- 2 files changed, 394 insertions(+), 11 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index d05d43bc3..7863362c9 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -112,6 +112,24 @@ union HMultiplyAndAccumulate { } __attribute__((packed)); static_assert(sizeof(HMultiplyAndAccumulate) == 4, " "); +// Signed multiply, Divide +union SignedMulDiv { + uint32_t flat; + struct { + uint32_t rn : 4; + uint32_t _1 : 1; + uint32_t op2 : 3; + uint32_t rm : 4; + uint32_t ra : 4; + uint32_t rd : 4; + uint32_t op1 : 3; + uint32_t _01110 : 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(SignedMulDiv) == 4, " "); + + // Load/Store Word, Unsigned Byte (immediate, literal) union LoadStoreWUBIL { uint32_t flat; @@ -374,6 +392,21 @@ union Misc { } __attribute__((packed)); static_assert(sizeof(Misc) == 4, " "); +// Media +union Media { + uint32_t flat; + struct { + uint32_t _3_to_0 : 4; + uint32_t _1: 1; + uint32_t op1 : 3; + uint32_t _19_to_8 : 12; + uint32_t op0 : 5; + uint32_t _011: 3; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(Media) == 4, " "); + // Integer Saturating Arithmetic union IntSatArith { uint32_t flat; @@ -1359,6 +1392,142 @@ static bool TryHalfwordDecodeMultiplyAndAccumulate(Instruction &inst, } +// Index from: op1 | Ra == 15 | op2 +static const char * kSMulDiv(uint32_t index) { + switch(index) { + case 0b0000000: + return "SMLAD"; + case 0b0000001: + return "SMLADX"; + case 0b0000010: + return "SMLSD"; + case 0b0000011: + return "SMLSDX"; + case 0b0001000: + return "SMUAD"; + case 0b0001001: + return "SMUADX"; + case 0b0001010: + return "SMUSD"; + case 0b0001011: + return "SMUSDX"; + // case 0b0010000: - Note(Sonya): a != 15 is constrained UNPREDICTABLE + case 0b0011000: + return "SDIV"; + // case 0b0110000: - Note(Sonya): a != 15 is constrained UNPREDICTABLE + case 0b0111000: + return "UDIV"; + case 0b1000000: + case 0b1001000: + return "SMLALD"; + case 0b1000001: + case 0b1001001: + return "SMLALDX"; + case 0b1000010: + case 0b1001010: + return "SMLSLD"; + case 0b1000011: + case 0b1001011: + return "SMLSLDX"; + case 0b1010000: + return "SMMLA"; + case 0b1010001: + return "SMMLAR"; + case 0b1010110: + // case 0b1011110: - Note(Sonya): a == 15 is constrained UNPREDICTABLE + return "SMMLS"; + case 0b1010111: + // case 0b1011111: - Note(Sonya): a == 15 is constrained UNPREDICTABLE + return "SMMLSR"; + case 0b1011000: + return "SMMUL"; + case 0b1011001: + return "SMMULR"; + default: + return nullptr; // UNALLOCATED + } +} + +// op1 Ra op2 +// 000 != 1111 000 SMLAD, SMLADX — SMLAD if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; +// 000 != 1111 001 SMLAD, SMLADX — SMLADX if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; +// 000 != 1111 010 SMLSD, SMLSDX — SMLSD if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; +// 000 != 1111 011 SMLSD, SMLSDX — SMLSDX if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; +// 000 1xx UNALLOCATED +// 000 1111 000 SMUAD, SMUADX — SMUAD if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; // add 0 TODO +// 000 1111 001 SMUAD, SMUADX — SMUADX if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; +// 000 1111 010 SMUSD, SMUSDX — SMUSD if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; // add 0 TODO +// 000 1111 011 SMUSD, SMUSDX — SMUSDX if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; +// 001 000 SDIV if d == 15 || n == 15 || m == 15 || a != 15 then UNPREDICTABLE; +// 001 != 000 UNALLOCATED +// 010 UNALLOCATED +// 011 000 UDIV if d == 15 || n == 15 || m == 15 || a != 15 then UNPREDICTABLE; +// 011 != 000 UNALLOCATED +// 100 000 SMLALD, SMLALDX — SMLALD if dLo == 15 || dHi == 15 || n == 15 || m == 15 || dHi == dLo then UNPREDICTABLE; +// 100 001 SMLALD, SMLALDX — SMLALDX if dLo == 15 || dHi == 15 || n == 15 || m == 15 || dHi == dLo then UNPREDICTABLE; +// 100 010 SMLSLD, SMLSLDX — SMLSLD if dLo == 15 || dHi == 15 || n == 15 || m == 15 || dHi == dLo then UNPREDICTABLE; +// 100 011 SMLSLD, SMLSLDX — SMLSLDX if dLo == 15 || dHi == 15 || n == 15 || m == 15 || dHi == dLo then UNPREDICTABLE; +// 100 1xx UNALLOCATED +// 101 != 1111 000 SMMLA, SMMLAR — SMMLA if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; // add 0x0 +// 101 != 1111 001 SMMLA, SMMLAR — SMMLAR if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; // add 0x80000000 +// 101 01x UNALLOCATED +// 101 10x UNALLOCATED +// 101 110 SMMLS, SMMLSR — SMMLS if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; // add 0x0 +// 101 111 SMMLS, SMMLSR — SMMLSR if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; // add 0x80000000 +// 101 1111 000 SMMUL, SMMULR — SMMUL if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; // add 0 add 0x0 +// 101 1111 001 SMMUL, SMMULR — SMMULR if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; // add 0 add 0x80000000 +// 11x UNALLOCATED +// Signed multiply, Divide +static bool TryDecodeSignedMultiplyDivide(Instruction &inst, uint32_t bits) { + const SignedMulDiv enc = { bits }; + + auto instruction = kSMulDiv(enc.op1 << 4 | (enc.ra == kPCRegNum) << 3 | enc.op2); + if (!instruction || enc.rd == kPCRegNum || enc.rn == kPCRegNum + || enc.rm == kPCRegNum + || (enc.op1 == 0b100 && (enc.ra == kPCRegNum || enc.ra == enc.rd))) { + inst.category = Instruction::kCategoryError; + return false; + } + inst.function = instruction; + DecodeCondition(inst, enc.cond); + auto div = enc.op1 == 0b001 || enc.op1 == 0b011; + + if (enc.op1 == 0b100) { + AddIntRegOp(inst, enc.ra, 32, Operand::kActionWrite); + } + AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); + + // MSwap + if ((enc.op1 == 0b100 || !enc.op1) && (enc.op2 & 0b1)) { + const auto word_type = inst.arch->AddressType(); + const auto _16 = llvm::ConstantInt::get(word_type, 16u, false); + inst.operands.back().expr = RORExpr(inst, inst.operands.back().expr, + inst.EmplaceConstant(_16)); + } + + if (!div && enc.ra != kPCRegNum) { + AddIntRegOp(inst, enc.ra, 32, Operand::kActionRead); + } else if (!div) { + AddImmOp(inst, 0, 32u, true); + } + + if (enc.op1 == 0b100) { + AddIntRegOp(inst, enc.rd, 32, Operand::kActionRead); + } + + // Round + if (enc.op1 == 0b101 && (enc.op2 & 0b1)) { + AddImmOp(inst, 0x80000000, 32u, false); + } else if (enc.op1 == 0b101) { + AddImmOp(inst, 0, 32u, true); + } + + inst.category = Instruction::kCategoryNormal; + return true; +} + static const char * const kLoadSWUB[] = { [0b0000] = "STRp", [0b0001] = "LDRp", @@ -2159,6 +2328,89 @@ static bool TryDecodeIntegerSaturatingArithmetic(Instruction &inst, return true; } +// op0 op1 +//00xxx Parallel Arithmetic +//01000 101 SEL +//01000 001 UNALLOCATED +//01000 xx0 PKHBT, PKHTB +//01001 x01 UNALLOCATED +//01001 xx0 UNALLOCATED +//0110x x01 UNALLOCATED +//0110x xx0 UNALLOCATED +//01x10 001 Saturate 16-bit +//01x10 101 UNALLOCATED +//01x11 x01 Reverse Bit/Byte +//01x1x xx0 Saturate 32-bit +//01xxx 111 UNALLOCATED +//01xxx 011 Extend and Add +//10xxx Signed multiply, Divide +//11000 000 Unsigned Sum of Absolute Differences +//11000 100 UNALLOCATED +//11001 x00 UNALLOCATED +//1101x x00 UNALLOCATED +//110xx 111 UNALLOCATED +//1110x 111 UNALLOCATED +//1110x x00 Bitfield Insert +//11110 111 UNALLOCATED +//11111 111 Permanently UNDEFINED +//1111x x00 UNALLOCATED +//11x0x x10 UNALLOCATED +//11x1x x10 Bitfield Extract +//11xxx 011 UNALLOCATED +//11xxx x01 UNALLOCATED +static TryDecode * TryMedia(uint32_t bits) { + const Media enc = { bits }; + // op0 | op1 + switch (enc.op0 >> 3) { + case 0b00: // TODO(Sonya): Parallel Arithmetic + return nullptr; + case 0b10: + return TryDecodeSignedMultiplyDivide; + } + // TODO(Sonya) + switch (enc.op0 << 3 | enc.op1) { + case 0b01000101: + // SEL + case 0b01000000: + case 0b01000010: + case 0b01000100: + case 0b01000110: + // PKHBT, PKHTB + case 0b01010001: + case 0b01110001: + // Saturate 16-bit + case 0b01000011: + case 0b01001011: + case 0b01010011: + case 0b01011011: + case 0b01100011: + case 0b01101011: + case 0b01110011: + case 0b01111011: + // Extend and Add + case 0b11000000: + // Unsigned Sum of Absolute Differences + case 0b11100000: + case 0b11100100: + case 0b11101000: + case 0b11101100: + // Bitfield Insert + case 0b11111111: + // Permanently UNDEFINED + case 0b11010010: + case 0b11010110: + case 0b11011010: + case 0b11011110: + case 0b11110010: + case 0b11110110: + case 0b11111010: + case 0b11111110: + // Bitfield Extract + default: + return nullptr; + } +} + //00 001 UNALLOCATED //00 010 UNALLOCATED //00 011 UNALLOCATED @@ -2401,7 +2653,7 @@ static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { if (!(enc.op0 >> 2)) { if (enc.cond != 0b1111u) { // Data-processing and miscellaneous instructions -- op0 == 00x - if (~(enc.op0 >> 1)) { + if (!(enc.op0 >> 1)) { return TryDataProcessingAndMisc(bits); // Load/Store Word, Unsigned Byte (immediate, literal) -- op0 == 010 } else if (enc.op0 == 0b010u) { @@ -2411,9 +2663,9 @@ static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { } else if (!enc.op1) { const LoadStoreWUBR enc_ls_word = { bits }; return kLoadStoreWordUBR[enc_ls_word.o2 << 1u | enc_ls_word.o1]; - // TODO(Sonya): Media instructions -- op0 == 011, op1 == 1 + // Media instructions -- op0 == 011, op1 == 1 } else { - return nullptr; + return TryMedia(bits); } // TODO(Sonya): Unconditional instructions -- cond == 1111 } else { diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index 54db69f34..0d5308e2b 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -145,7 +145,6 @@ DEF_COND_SEM(RSCS, R32W dst, R32 src1, I32 src2, I8 carry_out) { Write(dst, res); return memory; } - } // namespace DEF_ISEL(ANDrr) = AND; @@ -165,7 +164,6 @@ DEF_ISEL(SBCSrr) = SBCS; DEF_ISEL(RSCrr) = RSC; DEF_ISEL(RSCSrr) = RSCS; - // Multiply and Accumulate namespace { DEF_COND_SEM(MUL, R32W dst, R32 src1, R32 src2, R32 src3) { @@ -235,7 +233,7 @@ DEF_COND_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 DEF_COND_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { auto rhs = SExt(Signed(Read(src3))); auto lhs = SExt(Signed(Read(src2))); - auto acc = SOr(SShl(SExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto acc = SOr(SShl(SExt(Read(src1)), 32ul), Signed(ZExt(Read(src4)))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); Write(dst_hi, TruncTo(SShr(res, 32ul))); Write(dst_lo, TruncTo(res)); @@ -245,7 +243,7 @@ DEF_COND_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 DEF_COND_SEM(SMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { auto rhs = SExt(Signed(Read(src3))); auto lhs = SExt(Signed(Read(src2))); - auto acc = SOr(SShl(SExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto acc = SOr(SShl(SExt(Read(src1)), 32ul), Signed(ZExt(Read(src4)))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); @@ -271,7 +269,6 @@ DEF_ISEL(SMULLS) = SMULLS; DEF_ISEL(SMLAL) = SMULL; DEF_ISEL(SMLALS) = SMULLS; - // Halfword Multiply and Accumulate namespace { DEF_COND_SEM(SMLAh, R32W dst, R32 src1, R32 src2, R32 src3) { @@ -325,7 +322,7 @@ DEF_COND_SEM(SMULh, R32W dst, R32 src1, R32 src2) { DEF_COND_SEM(SMLALh, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { auto rhs = SExt(Read(src3)); auto lhs = SExt(Read(src2)); - auto acc = SOr(SShl(SExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto acc = SOr(SShl(SExt(Signed(Read(src1))), 32ul), Signed(ZExt(Read(src4)))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); Write(dst_hi, TruncTo(SShr(res, 32ul))); Write(dst_lo, TruncTo(res)); @@ -351,6 +348,7 @@ DEF_ISEL(SMLALBT) = SMLALh; DEF_ISEL(SMLALTB) = SMLALh; DEF_ISEL(SMLALTT) = SMLALh; +// Integer Saturating Arithmetic namespace { template T SignedSatQ(State &state, T res, int32_t nbits) { @@ -379,7 +377,7 @@ DEF_COND_SEM(QDADD, R32W dst, R32 src1, R32 src2) { rhs = SignedSatQ(state, SShl(rhs, 1u), 32u); auto res = SAdd(lhs, rhs); res = SignedSatQ(state, res, 32u); - Write(dst, TruncTo(res)); + Write(dst, TruncTo(res)); return memory; } @@ -398,7 +396,7 @@ DEF_COND_SEM(QDSUB, R32W dst, R32 src1, R32 src2) { rhs = SignedSatQ(state, SShl(rhs, 1u), 32u); auto res = SSub(lhs, rhs); res = SignedSatQ(state, res, 32u); - Write(dst, TruncTo(res)); + Write(dst, TruncTo(res)); return memory; } } // namespace @@ -407,3 +405,136 @@ DEF_ISEL(QADD) = QADD; DEF_ISEL(QDADD) = QDADD; DEF_ISEL(QSUB) = QSUB; DEF_ISEL(QDSUB) = QDSUB; + +// Signed multiply, Divide +namespace { +DEF_COND_SEM(SMLAD, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm ra + auto rn = Read(src1); + auto rm = Read(src2); + auto ra = Signed(Read(src3)); + auto prod1 = SMul(SExt(Trunc(rn)), + SExt(Trunc(rm))); + auto prod2 = SMul(SExt(SShr(Signed(rn), 16u)), + SExt(SShr(Signed(rm), 16u))); + auto res = SAdd(SAdd(prod1, prod2), SExt(ra)); + WriteTrunc(dst, Unsigned(res)); + + // if result != SInt(result<31:0>) then // Signed overflow + // PSTATE.Q = '1'; + state.sr.q = Select(SCmpNeq(res, SExt(Trunc(res))), + uint8_t(1), state.sr.q); + return memory; +} + +DEF_COND_SEM(SMLSD, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm ra + auto rn = Read(src1); + auto rm = Read(src2); + auto ra = Read(src3); + auto prod1 = SMul(SExt(Signed(Trunc(rn))), + SExt(Signed(Trunc(rm)))); + auto prod2 = SMul(SExt(SShr(Signed(rn), 16u)), + SExt(SShr(Signed(rm), 16u))); + auto res = SAdd(SSub(prod1, prod2), SExt(ra)); + WriteTrunc(dst, Unsigned(res)); + + // if result != SInt(result<31:0>) then // Signed overflow + // PSTATE.Q = '1'; + state.sr.q = Select(SCmpNeq(res, SExt(Trunc(res))), + uint8_t(1), state.sr.q); + return memory; +} + +DEF_COND_SEM(SDIV, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm + auto rn = Signed(Read(src1)); + auto rm = Signed(Read(src2)); + if (!rm) { + WriteZExt(dst, uint32_t(0)); + } else { + WriteZExt(dst, Unsigned(SDiv(rn, rm))); + } + return memory; +} + +DEF_COND_SEM(UDIV, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm + auto rn = Read(src1); + auto rm = Read(src2); + if (!rm) { + WriteZExt(dst, uint32_t(0)); + } else { + WriteZExt(dst, UDiv(rn, rm)); + } + return memory; +} + +DEF_COND_SEM(SMLALD, R32W dst_lo, R32W dst_hi, R32 src1, R32 src2, R32 src3, R32 src4) { // ra - lo rd - hi rn rm ra - lo rd - hi + auto rn = Read(src1); + auto rm = Read(src2); + auto lo = SExt(Signed(Read(src3))); + auto hi = SExt(Signed(Read(src4))); + auto prod1 = SMul(SExt(Trunc(rn)), + SExt(Trunc(rm))); + auto prod2 = SMul(SExt(SShr(Signed(rn), 16u)), + SExt(SShr(Signed(rm), 16u))); + auto res = SAdd(SAdd(prod1, prod2), SOr(lo, SShl(hi, 32u))); + WriteTrunc(dst_lo, Unsigned(res)); + WriteTrunc(dst_hi, Unsigned(SShr(res, 32u))); + return memory; +} + +DEF_COND_SEM(SMLSLD, R32W dst_lo, R32W dst_hi, R32 src1, R32 src2, R32 src3, R32 src4) { // ra - lo rd - hi rn rm ra - lo rd - hi + auto rn = Read(src1); + auto rm = Read(src2); + auto lo = SExt(Signed(Read(src3))); + auto hi = SExt(Signed(Read(src4))); + auto prod1 = SMul(SExt(Trunc(rn)), + SExt(Trunc(rm))); + auto prod2 = SMul(SExt(SShr(Signed(rn), 16u)), + SExt(SShr(Signed(rm), 16u))); + auto res = SAdd(SSub(prod1, prod2), SOr(lo, SShl(hi, 32u))); + WriteTrunc(dst_lo, Unsigned(res)); + WriteTrunc(dst_hi, Unsigned(SShr(res, 32u))); + return memory; +} + +DEF_COND_SEM(SMMLA, R32W dst, R32 src1, R32 src2, R32 src3, I32 src4) { + auto rhs = SExt(Signed(Read(src2))); + auto lhs = SExt(Signed(Read(src1))); + auto acc = SShl(SExt(Signed(Read(src3))), 32u); + auto round = Signed(ZExt(Read(src4))); + auto res = SShr(SAdd(SAdd(acc, SMul(lhs, rhs)), round), 32u); + WriteTrunc(dst, Unsigned(res)); + return memory; +} + +DEF_COND_SEM(SMMLS, R32W dst, R32 src1, R32 src2, R32 src3, I32 src4) { + auto rhs = SExt(Signed(Read(src2))); + auto lhs = SExt(Signed(Read(src1))); + auto acc = SShl(SExt(Signed(Read(src3))), 32u); + auto round = Signed(ZExt(Read(src4))); + auto res = SShr(SAdd(SSub(acc, SMul(lhs, rhs)), round), 32u); + WriteTrunc(dst, Unsigned(res)); + return memory; +} +} // namespace + +DEF_ISEL(SMLAD) = SMLAD; +DEF_ISEL(SMLADX) = SMLAD; +DEF_ISEL(SMLSD) = SMLSD; +DEF_ISEL(SMLSDX) = SMLSD; +DEF_ISEL(SMUAD) = SMLAD; +DEF_ISEL(SMUADX) = SMLAD; +DEF_ISEL(SMUSD) = SMLSD; +DEF_ISEL(SMUSDX) = SMLSD; +DEF_ISEL(SDIV) = SDIV; +DEF_ISEL(UDIV) = UDIV; +DEF_ISEL(SMLALD) = SMLALD; +DEF_ISEL(SMLALDX) = SMLALD; +DEF_ISEL(SMLSLD) = SMLSLD; +DEF_ISEL(SMLSLDX) = SMLSLD; +DEF_ISEL(SMMLA) = SMMLA; +DEF_ISEL(SMMLAR) = SMMLA; +DEF_ISEL(SMMLS) = SMMLS; +DEF_ISEL(SMMLSR) = SMMLS; +DEF_ISEL(SMMUL) = SMMLA; +DEF_ISEL(SMMULR) = SMMLA; + From eccc55b7a77d800d51e414cd26e32eb53576d43b Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 14 Jan 2021 12:10:26 -0500 Subject: [PATCH 113/130] Cleaned up SExt some --- lib/Arch/AArch32/Semantics/BINARY.cpp | 60 +++++++++++++-------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index 0d5308e2b..94433e405 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -272,23 +272,23 @@ DEF_ISEL(SMLALS) = SMULLS; // Halfword Multiply and Accumulate namespace { DEF_COND_SEM(SMLAh, R32W dst, R32 src1, R32 src2, R32 src3) { - auto rhs = SExt(Read(src2)); - auto lhs = SExt(Read(src1)); - auto acc = SExt(Read(src3)); + auto rhs = SExt(Signed(Read(src2))); + auto lhs = SExt(Signed(Read(src1))); + auto acc = SExt(Signed(Read(src3))); auto res = SAdd(SMul(lhs, rhs), acc); auto trun_res = TruncTo(res); Write(dst, trun_res); // if result != SInt(result<31:0>) then // Signed overflow // PSTATE.Q = '1'; - state.sr.q = Select(SCmpNeq(res, SExt(trun_res)), + state.sr.q = Select(SCmpNeq(res, SExt(trun_res)), uint8_t(1), state.sr.q); return memory; } DEF_COND_SEM(SMULWh, R32W dst, R32 src1, R32 src2) { - auto rhs = SExt(Read(src2)); - auto lhs = SExt(Read(src1)); + auto rhs = SExt(Signed(Read(src2))); + auto lhs = SExt(Signed(Read(src1))); auto res = SShr(SMul(lhs, rhs), 16ul); // R[d] = result<47:16> auto trun_res = TruncTo(res); Write(dst, trun_res); @@ -296,16 +296,16 @@ DEF_COND_SEM(SMULWh, R32W dst, R32 src1, R32 src2) { } DEF_COND_SEM(SMLAWh, R32W dst, R32 src1, R32 src2, R32 src3) { - auto rhs = SExt(Read(src2)); - auto lhs = SExt(Read(src1)); - auto acc = SShl(SExt(Read(src3)), 16ul); // SInt(R[a]) << 16 + auto rhs = SExt(Signed(Read(src2))); + auto lhs = SExt(Signed(Read(src1))); + auto acc = SShl(SExt(Signed(Read(src3))), 16ul); // SInt(R[a]) << 16 auto res = SShr(SAdd(SMul(lhs, rhs), acc), 16ul); // R[d] = result<47:16> auto trun_res = TruncTo(res); Write(dst, trun_res); // if (result >> 16) != SInt(R[d]) then // Signed overflow // PSTATE.Q = '1'; - state.sr.q = Select(SCmpNeq(res, SExt(trun_res)), + state.sr.q = Select(SCmpNeq(res, SExt(trun_res)), uint8_t(1), state.sr.q); return memory; } @@ -320,9 +320,9 @@ DEF_COND_SEM(SMULh, R32W dst, R32 src1, R32 src2) { } DEF_COND_SEM(SMLALh, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { - auto rhs = SExt(Read(src3)); - auto lhs = SExt(Read(src2)); - auto acc = SOr(SShl(SExt(Signed(Read(src1))), 32ul), Signed(ZExt(Read(src4)))); // UInt(R[dHi]:R[dLo]) + auto rhs = SExt(Signed(Read(src3))); + auto lhs = SExt(Signed(Read(src2))); + auto acc = SOr(SShl(SExt(Signed(Read(src1))), 32ul), Signed(ZExt(Read(src4)))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); Write(dst_hi, TruncTo(SShr(res, 32ul))); Write(dst_lo, TruncTo(res)); @@ -409,13 +409,13 @@ DEF_ISEL(QDSUB) = QDSUB; // Signed multiply, Divide namespace { DEF_COND_SEM(SMLAD, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm ra - auto rn = Read(src1); - auto rm = Read(src2); + auto rn = Signed(Read(src1)); + auto rm = Signed(Read(src2)); auto ra = Signed(Read(src3)); auto prod1 = SMul(SExt(Trunc(rn)), SExt(Trunc(rm))); - auto prod2 = SMul(SExt(SShr(Signed(rn), 16u)), - SExt(SShr(Signed(rm), 16u))); + auto prod2 = SMul(SExt(SShr(rn, 16u)), + SExt(SShr(rm, 16u))); auto res = SAdd(SAdd(prod1, prod2), SExt(ra)); WriteTrunc(dst, Unsigned(res)); @@ -427,13 +427,13 @@ DEF_COND_SEM(SMLAD, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm ra } DEF_COND_SEM(SMLSD, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm ra - auto rn = Read(src1); - auto rm = Read(src2); - auto ra = Read(src3); + auto rn = Signed(Read(src1)); + auto rm = Signed(Read(src2)); + auto ra = Signed(Read(src3)); auto prod1 = SMul(SExt(Signed(Trunc(rn))), SExt(Signed(Trunc(rm)))); - auto prod2 = SMul(SExt(SShr(Signed(rn), 16u)), - SExt(SShr(Signed(rm), 16u))); + auto prod2 = SMul(SExt(SShr(rn, 16u)), + SExt(SShr(rm, 16u))); auto res = SAdd(SSub(prod1, prod2), SExt(ra)); WriteTrunc(dst, Unsigned(res)); @@ -467,14 +467,14 @@ DEF_COND_SEM(UDIV, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm } DEF_COND_SEM(SMLALD, R32W dst_lo, R32W dst_hi, R32 src1, R32 src2, R32 src3, R32 src4) { // ra - lo rd - hi rn rm ra - lo rd - hi - auto rn = Read(src1); - auto rm = Read(src2); + auto rn = Signed(Read(src1)); + auto rm = Signed(Read(src2)); auto lo = SExt(Signed(Read(src3))); auto hi = SExt(Signed(Read(src4))); auto prod1 = SMul(SExt(Trunc(rn)), SExt(Trunc(rm))); - auto prod2 = SMul(SExt(SShr(Signed(rn), 16u)), - SExt(SShr(Signed(rm), 16u))); + auto prod2 = SMul(SExt(SShr(rn, 16u)), + SExt(SShr(rm, 16u))); auto res = SAdd(SAdd(prod1, prod2), SOr(lo, SShl(hi, 32u))); WriteTrunc(dst_lo, Unsigned(res)); WriteTrunc(dst_hi, Unsigned(SShr(res, 32u))); @@ -482,14 +482,14 @@ DEF_COND_SEM(SMLALD, R32W dst_lo, R32W dst_hi, R32 src1, R32 src2, R32 src3, R32 } DEF_COND_SEM(SMLSLD, R32W dst_lo, R32W dst_hi, R32 src1, R32 src2, R32 src3, R32 src4) { // ra - lo rd - hi rn rm ra - lo rd - hi - auto rn = Read(src1); - auto rm = Read(src2); + auto rn = Signed(Read(src1)); + auto rm = Signed(Read(src2)); auto lo = SExt(Signed(Read(src3))); auto hi = SExt(Signed(Read(src4))); auto prod1 = SMul(SExt(Trunc(rn)), SExt(Trunc(rm))); - auto prod2 = SMul(SExt(SShr(Signed(rn), 16u)), - SExt(SShr(Signed(rm), 16u))); + auto prod2 = SMul(SExt(SShr(rn, 16u)), + SExt(SShr(rm, 16u))); auto res = SAdd(SSub(prod1, prod2), SOr(lo, SShl(hi, 32u))); WriteTrunc(dst_lo, Unsigned(res)); WriteTrunc(dst_hi, Unsigned(SShr(res, 32u))); From 43784a639e85ae5159661fd47630b4da3ecf19d9 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 20 Jan 2021 14:22:54 -0500 Subject: [PATCH 114/130] Saturate Insts and Start of Load Store Multiple - STMDB and LDM (aliases which support PUSH and POP of multiple regs) --- include/remill/Arch/Instruction.h | 2 +- lib/Arch/AArch32/Decode.cpp | 272 +++++++++++++++++++++++++- lib/Arch/AArch32/Semantics/BINARY.cpp | 67 ++++++- lib/Arch/AArch32/Semantics/MEM.cpp | 137 +++++++++++++ 4 files changed, 466 insertions(+), 12 deletions(-) diff --git a/include/remill/Arch/Instruction.h b/include/remill/Arch/Instruction.h index c34e9a512..aba64cb7a 100644 --- a/include/remill/Arch/Instruction.h +++ b/include/remill/Arch/Instruction.h @@ -327,7 +327,7 @@ class Instruction { Operand & EmplaceOperand(const Operand::Address &op); private: - static constexpr auto kMaxNumExpr = 64u; + static constexpr auto kMaxNumExpr = 128u; OperandExpression exprs[kMaxNumExpr]; unsigned next_expr_index{0}; }; diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 7863362c9..84eac8b65 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -213,6 +213,23 @@ union LoadStoreDualHSBR { } __attribute__((packed)); static_assert(sizeof(LoadStoreDualHSBR) == 4, " "); +// Load/Store Multiple +union LoadStoreM { + uint32_t flat; + struct { + uint32_t register_list : 16; + uint32_t rn : 4; + uint32_t L : 1; + uint32_t W : 1; + uint32_t op : 1; + uint32_t U : 1; + uint32_t P : 1; + uint32_t _100 : 3; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(LoadStoreM) == 4, " "); + // Integer Test and Compare (two register, immediate shift) union IntTestCompRRI { @@ -423,6 +440,42 @@ union IntSatArith { } __attribute__((packed)); static_assert(sizeof(IntSatArith) == 4, " "); +// Saturate 16-bit +union Sat16 { + uint32_t flat; + struct { + uint32_t Rn : 4; + uint32_t _0011 : 4; + uint32_t _1111 : 4; + uint32_t Rd : 4; + uint32_t sat_imm : 4; + uint32_t _10 : 2; + uint32_t U : 1; + uint32_t _01101: 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(Sat16) == 4, " "); + +// Saturate 32-bit +union Sat32 { + uint32_t flat; + struct { + uint32_t Rn : 4; + uint32_t _01 : 2; + uint32_t sh : 1; + uint32_t imm5 : 5; + uint32_t Rd : 4; + uint32_t sat_imm : 5; + uint32_t _1 : 1; + uint32_t U : 1; + uint32_t _01101: 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(Sat32) == 4, " "); + + static constexpr auto kPCRegNum = 15u; static constexpr auto kLRRegNum = 14u; @@ -1961,6 +2014,122 @@ static bool TryDecodeLoadStoreDualHalfSignedBReg(Instruction &inst, return true; } +// P U op L register_list +// 0 0 0 0 STMDA, STMED if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; +// 0 0 0 1 LDMDA, LDMFA if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if wback && registers == '1' then UNPREDICTABLE; +// 0 1 0 0 STM, STMIA, STMEA if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; +// 0 1 0 1 LDM, LDMIA, LDMFD if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if wback && registers == '1' then UNPREDICTABLE; +// 1 0 STM (User registers) if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; +// 1 0 0 0 STMDB, STMFD if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; +// 1 0 0 1 LDMDB, LDMEA if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if wback && registers == '1' then UNPREDICTABLE; +// 1 1 0xxxxxxxxxxxxxxx LDM (User registers) if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; +// 1 1 0 0 STMIB, STMFA if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; +// 1 1 0 1 LDMIB, LDMED if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if wback && registers == '1' then UNPREDICTABLE; +// 1 1 1xxxxxxxxxxxxxxx LDM (exception return) if n == 15 then UNPREDICTABLE; if wback && registers == '1' then UNPREDICTABLE; +static const char * const kLoadStoreM[] = { + [0b0000] = "STMDA", + [0b0001] = "LDMDA", + [0b0010] = "STMu", // (User registers) + [0b0011] = "LDM", // (User registers) || (exception return) + [0b0100] = "STM", + [0b0101] = "LDM", + [0b0110] = "STMu", // (User registers) + [0b0111] = "LDM", // (User registers) || (exception return) + [0b1000] = "STMDB", + [0b1001] = "LDMDB", + [0b1010] = "STMu", // (User registers) + [0b1011] = "LDM", // (User registers) || (exception return) + [0b1100] = "STMIB", + [0b1101] = "LDMIB", + [0b1110] = "STMu", // (User registers) + [0b1111] = "LDM", // (User registers) || (exception return) +}; + +// Load/Store Multiple +// Note that: +// LDM{}{} SP!, is an alias for POP{}{} +// STMDB{}{} SP!, is an alias for PUSH{}{} +template +static bool TryDecodeLoadStoreMultiple(Instruction &inst, uint32_t bits) { + const LoadStoreM enc = { bits }; + inst.function = kLoadStoreM[enc.P << 3 | enc.U << 2 | enc.op << 1 | enc.L]; + + if (enc.op && enc.L && (enc.register_list >> 15)) { + // Exception Return + inst.function += "e"; + } else if (enc.op && enc.L) { + // User registers + inst.function += "u"; + } + + auto wback = enc.W; + uint32_t reg_cnt = 0; + for (uint32_t i = 0; 16u > i; i++) { + if ((0b1 << i) & enc.register_list) { + if (wback && i == enc.rn && ((!reg_cnt && !enc.L) || enc.L)) { + // if i == n && wback && i != LowestSetBit(registers) then bits(32) UNKNOWN; + inst.category = Instruction::kCategoryError; + return false; + } + reg_cnt++; + } + } + + if (enc.rn == 15 || (reg_cnt < 1u)) { + inst.category = Instruction::kCategoryError; + return false; + } + + auto is_cond = DecodeCondition(inst, enc.cond); + + AddImmOp(inst, enc.register_list, 16u, false); + + // Write Back + AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); + if (wback) { + if (enc.L) { + // LDM + AddAddrRegOp(inst, kIntRegName[enc.rn], 32u, Operand::kActionRead, + 4 * reg_cnt); + } else { + // STMDB + AddAddrRegOp(inst, kIntRegName[enc.rn], 32u, Operand::kActionRead, + -4 * reg_cnt); + } + } else { + AddAddrRegOp(inst, kIntRegName[enc.rn], 32u, Operand::kActionRead, 0); + } + + // Add mem and reg ops + if (enc.L){ + reg_cnt = 0; + } else { + reg_cnt = - reg_cnt; + } + for (uint32_t i = 0u; 16u > i; i++) { + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, 4 * reg_cnt); + AddIntRegOp(inst, i, 32, kRegAction); + if ((0b1 << i) & enc.register_list) { + + reg_cnt++; + + } + } + + if (enc.register_list & (0b1 << 15u)) { + if (is_cond) { + inst.branch_not_taken_pc = inst.next_pc; + inst.category = Instruction::kCategoryConditionalIndirectJump; + } else { + inst.category = Instruction::kCategoryIndirectJump; + } + } else { + inst.category = Instruction::kCategoryNormal; + } + return true; +} + // Can package semantics for MOV with ORR and MVN with BIC since src1 will be // 0 and 1 for MOV and MVN respectively, mirroring the semantics in LOGICAL.cpp static InstEval * kLogArithEvaluators[] = { @@ -2328,6 +2497,57 @@ static bool TryDecodeIntegerSaturatingArithmetic(Instruction &inst, return true; } +// Saturate 16-bit +static bool TryDecodeSat16(Instruction &inst, uint32_t bits) { + const Sat16 enc = { bits }; + DecodeCondition(inst, enc.cond); + + // if d == 15 || n == 15 then UNPREDICTABLE; + if (enc.Rd == kPCRegNum || enc.Rn == kPCRegNum) { + inst.category = Instruction::kCategoryError; + return false; + } + + AddIntRegOp(inst, enc.Rd, 32u, Operand::kActionWrite); + if (enc.U) { + inst.function = "USAT16"; + AddImmOp(inst, enc.sat_imm); + } else { + inst.function = "SSAT16"; + AddImmOp(inst, enc.sat_imm + 1); + } + AddIntRegOp(inst, enc.Rn, 32u, Operand::kActionRead); + + inst.category = Instruction::kCategoryNormal; + return true; +} + +// Saturate 32-bit +static bool TryDecodeSat32(Instruction &inst, uint32_t bits) { + const Sat32 enc = { bits }; + DecodeCondition(inst, enc.cond); + + // if d == 15 || n == 15 then UNPREDICTABLE; + if (enc.Rd == kPCRegNum || enc.Rn == kPCRegNum) { + inst.category = Instruction::kCategoryError; + return false; + } + + AddIntRegOp(inst, enc.Rd, 32u, Operand::kActionWrite); + if (enc.U) { + inst.function = "USAT"; + AddImmOp(inst, enc.sat_imm); + } else { + inst.function = "SSAT"; + AddImmOp(inst, enc.sat_imm + 1); + } + // (shift_t, shift_n) = DecodeImmShift(sh:'0', imm5); + AddShiftRegImmOperand(inst, enc.Rn, enc.sh << 1, enc.imm5, 0u); + + inst.category = Instruction::kCategoryNormal; + return true; +} + // op0 op1 //00xxx Parallel Arithmetic //01000 101 SEL @@ -2376,9 +2596,33 @@ static TryDecode * TryMedia(uint32_t bits) { case 0b01000100: case 0b01000110: // PKHBT, PKHTB + return nullptr; case 0b01010001: case 0b01110001: - // Saturate 16-bit + return TryDecodeSat16; + case 0b01011001: + case 0b01011101: + case 0b01111001: + case 0b01111101: + // Reverse Bit/Byte + return nullptr; + case 0b01010000: + case 0b01010010: + case 0b01010100: + case 0b01010110: + case 0b01011000: + case 0b01011010: + case 0b01011100: + case 0b01011110: + case 0b01110000: + case 0b01110010: + case 0b01110100: + case 0b01110110: + case 0b01111000: + case 0b01111010: + case 0b01111100: + case 0b01111110: + return TryDecodeSat32; case 0b01000011: case 0b01001011: case 0b01010011: @@ -2573,6 +2817,26 @@ static TryDecode * kExtraLoadStore[] = { [0b111111] = TryDecodeLoadStoreDualHalfSignedBIL, }; +// Load Store Multiple +static TryDecode * kMLoadStore[] = { + [0b0000] = nullptr, //"STMDA", + [0b0001] = nullptr, //"LDMDA", + [0b0010] = nullptr, //"STMu", // (User registers) + [0b0011] = nullptr, //"LDM", // (User registers) || (exception return) + [0b0100] = nullptr, //"STM", + [0b0101] = TryDecodeLoadStoreMultiple, + [0b0110] = nullptr, //"STMu", // (User registers) + [0b0111] = nullptr, //"LDM", // (User registers) || (exception return) + [0b1000] = TryDecodeLoadStoreMultiple, + [0b1001] = nullptr, //"LDMDB", + [0b1010] = nullptr, //"STMu", // (User registers) + [0b1011] = nullptr, //"LDM", // (User registers) || (exception return) + [0b1100] = nullptr, //"STMIB", + [0b1101] = nullptr, //"LDMIB", + [0b1110] = nullptr, //"STMu", // (User registers) + [0b1111] = nullptr, //"LDM", // (User registers) || (exception return) +}; + // Corresponds to: Data-processing and miscellaneous instructions //op0 op1 op2 op3 op4 // 0 1 != 00 1 Extra load/store @@ -2681,9 +2945,11 @@ static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { // TODO(Sonya): Exception Save/Restore -- cond == 1111, op0 == 100 } else if (enc.cond == 0b1111u) { return nullptr; - // TODO(Sonya): Load/Store Multiple -- cond != 1111, op0 == 100 + // Load/Store Multiple -- cond != 1111, op0 == 100 } else { - return nullptr; + const LoadStoreM enc_ls_word = { bits }; + return kMLoadStore[enc_ls_word.P << 3 | enc_ls_word.U << 2 + | enc_ls_word.op << 1 | enc_ls_word.L]; } // TODO(Sonya): System register access, Advanced SIMD, floating-point, and Supervisor call -- op0 == 11x } else { diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index 94433e405..866c64b7a 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -348,25 +348,76 @@ DEF_ISEL(SMLALBT) = SMLALh; DEF_ISEL(SMLALTB) = SMLALh; DEF_ISEL(SMLALTT) = SMLALh; -// Integer Saturating Arithmetic +// Saturate 16-bit && Saturate 32-bit namespace { +template +T UnsignedSatQ(State &state, T res, uint32_t nbits) { + auto upper_bound = T((1 << nbits) - 1); + auto lower_bound = T(0); + state.sr.q = Select(BOr(UCmpGt(res, upper_bound), UCmpLt(res, lower_bound)), + uint8_t(1u), state.sr.q); + res = Select(UCmpGt(res, upper_bound), upper_bound, res); + res = Select(UCmpLt(res, lower_bound), lower_bound, res); + return res; +} + template T SignedSatQ(State &state, T res, int32_t nbits) { nbits--; auto upper_bound = T((1 << nbits) - 1); auto lower_bound = T(-(1 << nbits)); - state.sr.q = Select(SOr(SCmpGt(res, upper_bound), SCmpLt(res, lower_bound)), + state.sr.q = Select(BOr(SCmpGt(res, upper_bound), SCmpLt(res, lower_bound)), uint8_t(1u), state.sr.q); res = Select(SCmpGt(res, upper_bound), upper_bound, res); res = Select(SCmpLt(res, lower_bound), lower_bound, res); return res; } +DEF_COND_SEM(USAT, R32W dst, I32 imm, R32 src) { + auto res = UnsignedSatQ(state, Read(src), Read(imm)); + Write(dst, res); + return memory; +} + +DEF_COND_SEM(SSAT, R32W dst, I32 imm, R32 src) { + auto res = SignedSatQ(state, Signed(Read(src)), Signed(Read(imm))); + Write(dst, Unsigned(res)); + return memory; +} + +DEF_COND_SEM(USAT16, R32W dst, I32 imm1, R32 src1) { + auto src = Read(src1); + auto imm = Read(imm1); + auto high = UnsignedSatQ(state, Trunc(UShr(src, 16u)), imm); + auto low = UnsignedSatQ(state, Trunc(src), imm); + auto res = UOr(UShl(ZExt(high), 16u), ZExt(low)); + Write(dst, res); + return memory; +} + +DEF_COND_SEM(SSAT16, R32W dst, I32 imm1, R32 src1) { + auto src = Signed(Read(src1)); + auto imm = Signed(Read(imm1)); + auto high = SignedSatQ(state, Trunc(SShr(src, 16u)), imm); + auto low = SignedSatQ(state, Trunc(src), imm); + auto res = SOr(SShl(SExt(high), 16u), Signed(ZExt(low))); + Write(dst, Unsigned(res)); + return memory; +} +} // namespace + +DEF_ISEL(USAT) = USAT; +DEF_ISEL(SSAT) = SSAT; +DEF_ISEL(USAT16) = USAT16; +DEF_ISEL(SSAT16) = SSAT16; + +// Integer Saturating Arithmetic +namespace { DEF_COND_SEM(QADD, R32W dst, R32 src1, R32 src2) { auto rhs = SExt(Signed(Read(src2))); auto lhs = SExt(Signed(Read(src1))); auto res = SAdd(lhs, rhs); - res = SignedSatQ(state, res, 32u); + res = SignedSatQ(state, res, 32); Write(dst, TruncTo(res)); return memory; } @@ -374,9 +425,9 @@ DEF_COND_SEM(QADD, R32W dst, R32 src1, R32 src2) { DEF_COND_SEM(QDADD, R32W dst, R32 src1, R32 src2) { auto rhs = SExt(Signed(Read(src2))); auto lhs = SExt(Signed(Read(src1))); - rhs = SignedSatQ(state, SShl(rhs, 1u), 32u); + rhs = SignedSatQ(state, SShl(rhs, 1u), 32); auto res = SAdd(lhs, rhs); - res = SignedSatQ(state, res, 32u); + res = SignedSatQ(state, res, 32); Write(dst, TruncTo(res)); return memory; } @@ -385,7 +436,7 @@ DEF_COND_SEM(QSUB, R32W dst, R32 src1, R32 src2) { auto rhs = SExt(Signed(Read(src2))); auto lhs = SExt(Signed(Read(src1))); auto res = SSub(lhs, rhs); - res = SignedSatQ(state, res, 32u); + res = SignedSatQ(state, res, 32); Write(dst, TruncTo(res)); return memory; } @@ -393,9 +444,9 @@ DEF_COND_SEM(QSUB, R32W dst, R32 src1, R32 src2) { DEF_COND_SEM(QDSUB, R32W dst, R32 src1, R32 src2) { auto rhs = SExt(Signed(Read(src2))); auto lhs = SExt(Signed(Read(src1))); - rhs = SignedSatQ(state, SShl(rhs, 1u), 32u); + rhs = SignedSatQ(state, SShl(rhs, 1u), 32); auto res = SSub(lhs, rhs); - res = SignedSatQ(state, res, 32u); + res = SignedSatQ(state, res, 32); Write(dst, TruncTo(res)); return memory; } diff --git a/lib/Arch/AArch32/Semantics/MEM.cpp b/lib/Arch/AArch32/Semantics/MEM.cpp index 161c70a08..6c6d36984 100644 --- a/lib/Arch/AArch32/Semantics/MEM.cpp +++ b/lib/Arch/AArch32/Semantics/MEM.cpp @@ -286,3 +286,140 @@ DEF_ISEL(STRHT) = STRHT; DEF_ISEL(LDRHT) = LDRHT; DEF_ISEL(LDRSBT) = LDRSBT; DEF_ISEL(LDRSHT) = LDRSHT; + +// Load/Store Multiple +namespace { +DEF_COND_SEM(LDM, I16 reg_list, R32W dst, R32 dst_new, M32 src0, R32W dst0, + M32 src1, R32W dst1, M32 src2, R32W dst2, M32 src3, R32W dst3, + M32 src4, R32W dst4, M32 src5, R32W dst5, M32 src6, R32W dst6, + M32 src7, R32W dst7, M32 src8, R32W dst8, M32 src9, R32W dst9, + M32 src10, R32W dst10, M32 src11, R32W dst11, M32 src12, + R32W dst12, M32 src13, R32W dst13, M32 src14, R32W dst14, + M32W src15, R32W dst15) { + auto regs = Read(reg_list); + if (UAnd(regs, uint16_t(0b1u))) { + Write(dst0, Read(src0)); + } + if (UAnd(regs, uint16_t(0b10u))) { + Write(dst1, Read(src1)); + } + if (UAnd(regs, uint16_t(0b100u))) { + Write(dst2, Read(src2)); + } + if (UAnd(regs, uint16_t(0b1000u))) { + Write(dst3, Read(src3)); + } + if (UAnd(regs, uint16_t(0b10000u))) { + Write(dst4, Read(src4)); + } + if (UAnd(regs, uint16_t(0b100000u))) { + Write(dst5, Read(src5)); + } + if (UAnd(regs, uint16_t(0b1000000u))) { + Write(dst6, Read(src6)); + } + if (UAnd(regs, uint16_t(0b10000000u))) { + Write(dst7, Read(src7)); + } + if (UAnd(regs, uint16_t(0b100000000u))) { + Write(dst8, Read(src8)); + } + if (UAnd(regs, uint16_t(0b1000000000u))) { + Write(dst9, Read(src9)); + } + if (UAnd(regs, uint16_t(0b10000000000u))) { + Write(dst10, Read(src10)); + } + if (UAnd(regs, uint16_t(0b100000000000u))) { + Write(dst11, Read(src11)); + } + if (UAnd(regs, uint16_t(0b1000000000000u))) { + Write(dst12, Read(src12)); + } + if (UAnd(regs, uint16_t(0b10000000000000u))) { + Write(dst13, Read(src13)); + } + if (UAnd(regs, uint16_t(0b100000000000000u))) { + Write(dst14, Read(src14)); + } + if (UAnd(regs, uint16_t(0b1000000000000000u))) { + Write(dst15, Read(src15)); + } + Write(dst, Read(dst_new)); + return memory; +} + +DEF_COND_SEM(STMDB, I16 reg_list, R32W dst, R32 dst_new, M32W dst0, R32 src0, + M32W dst1, R32 src1, M32W dst2, R32 src2, M32W dst3, R32 src3, + M32W dst4, R32 src4, M32W dst5, R32 src5, M32W dst6, R32 src6, + M32W dst7, R32 src7, M32W dst8, R32 src8, M32W dst9, R32 src9, + M32W dst10, R32 src10, M32W dst11, R32 src11, M32W dst12, + R32 src12, M32W dst13, R32 src13, M32W dst14, R32 src14, + M32W dst15, R32 src15) { + + auto regs = Read(reg_list); + if (UAnd(regs, uint16_t(0b1u))) { + Write(dst0, Read(src0)); + } + if (UAnd(regs, uint16_t(0b10u))) { + Write(dst1, Read(src1)); + } + if (UAnd(regs, uint16_t(0b100u))) { + Write(dst2, Read(src2)); + } + if (UAnd(regs, uint16_t(0b1000u))) { + Write(dst3, Read(src3)); + } + if (UAnd(regs, uint16_t(0b10000u))) { + Write(dst4, Read(src4)); + } + if (UAnd(regs, uint16_t(0b100000u))) { + Write(dst5, Read(src5)); + } + if (UAnd(regs, uint16_t(0b1000000u))) { + Write(dst6, Read(src6)); + } + if (UAnd(regs, uint16_t(0b10000000u))) { + Write(dst7, Read(src7)); + } + if (UAnd(regs, uint16_t(0b100000000u))) { + Write(dst8, Read(src8)); + } + if (UAnd(regs, uint16_t(0b1000000000u))) { + Write(dst9, Read(src9)); + } + if (UAnd(regs, uint16_t(0b10000000000u))) { + Write(dst10, Read(src10)); + } + if (UAnd(regs, uint16_t(0b100000000000u))) { + Write(dst11, Read(src11)); + } + if (UAnd(regs, uint16_t(0b1000000000000u))) { + Write(dst12, Read(src12)); + } + if (UAnd(regs, uint16_t(0b10000000000000u))) { + Write(dst13, Read(src13)); + } + if (UAnd(regs, uint16_t(0b100000000000000u))) { + Write(dst14, Read(src14)); + } + if (UAnd(regs, uint16_t(0b1000000000000000u))) { + Write(dst15, Read(src15)); + } + Write(dst, Read(dst_new)); + return memory; +} +} // namespace + +//DEF_ISEL(STMDA) = STMDA; +//DEF_ISEL(LDMDA) = LDMDA; +//DEF_ISEL(STM) = STM; +DEF_ISEL(LDM) = LDM; +//DEF_ISEL(STMu) = STMu; +DEF_ISEL(STMDB) = STMDB; +//DEF_ISEL(LDMDB) = LDMDB; +//DEF_ISEL(LDMu) = LDMu; +//DEF_ISEL(STMIB) = STMIB; +//DEF_ISEL(LDMIB) = LDMIB; +//DEF_ISEL(LDMe) = LDMe; + From 8de19a30f18591a21bf2dac7cbe389dbf9f0d472 Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 20 Jan 2021 23:33:44 -0500 Subject: [PATCH 115/130] Condensed args in STMDB and LDM semantics --- include/remill/Arch/Instruction.h | 2 +- lib/Arch/AArch32/Decode.cpp | 10 +- lib/Arch/AArch32/Semantics/MEM.cpp | 149 ++++++++++++++--------------- 3 files changed, 75 insertions(+), 86 deletions(-) diff --git a/include/remill/Arch/Instruction.h b/include/remill/Arch/Instruction.h index aba64cb7a..c34e9a512 100644 --- a/include/remill/Arch/Instruction.h +++ b/include/remill/Arch/Instruction.h @@ -327,7 +327,7 @@ class Instruction { Operand & EmplaceOperand(const Operand::Address &op); private: - static constexpr auto kMaxNumExpr = 128u; + static constexpr auto kMaxNumExpr = 64u; OperandExpression exprs[kMaxNumExpr]; unsigned next_expr_index{0}; }; diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 84eac8b65..60998fec6 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -2103,18 +2103,12 @@ static bool TryDecodeLoadStoreMultiple(Instruction &inst, uint32_t bits) { // Add mem and reg ops if (enc.L){ - reg_cnt = 0; + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, 0); } else { - reg_cnt = - reg_cnt; + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, -4 * reg_cnt); } for (uint32_t i = 0u; 16u > i; i++) { - AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, 4 * reg_cnt); AddIntRegOp(inst, i, 32, kRegAction); - if ((0b1 << i) & enc.register_list) { - - reg_cnt++; - - } } if (enc.register_list & (0b1 << 15u)) { diff --git a/lib/Arch/AArch32/Semantics/MEM.cpp b/lib/Arch/AArch32/Semantics/MEM.cpp index 6c6d36984..7b4e20a55 100644 --- a/lib/Arch/AArch32/Semantics/MEM.cpp +++ b/lib/Arch/AArch32/Semantics/MEM.cpp @@ -289,122 +289,117 @@ DEF_ISEL(LDRSHT) = LDRSHT; // Load/Store Multiple namespace { -DEF_COND_SEM(LDM, I16 reg_list, R32W dst, R32 dst_new, M32 src0, R32W dst0, - M32 src1, R32W dst1, M32 src2, R32W dst2, M32 src3, R32W dst3, - M32 src4, R32W dst4, M32 src5, R32W dst5, M32 src6, R32W dst6, - M32 src7, R32W dst7, M32 src8, R32W dst8, M32 src9, R32W dst9, - M32 src10, R32W dst10, M32 src11, R32W dst11, M32 src12, - R32W dst12, M32 src13, R32W dst13, M32 src14, R32W dst14, - M32W src15, R32W dst15) { +DEF_COND_SEM(LDM, I16 reg_list, R32W dst, R32 dst_new, M32 src_mem, R32W dst0, + R32W dst1, R32W dst2, R32W dst3, R32W dst4, R32W dst5, R32W dst6, + R32W dst7, R32W dst8, R32W dst9, R32W dst10, R32W dst11, + R32W dst12, R32W dst13, R32W dst14, R32W dst15) { auto regs = Read(reg_list); + uint32_t index = 0; if (UAnd(regs, uint16_t(0b1u))) { - Write(dst0, Read(src0)); + Write(dst0, Read(GetElementPtr(src_mem, index++))); } - if (UAnd(regs, uint16_t(0b10u))) { - Write(dst1, Read(src1)); + if (UAnd(regs, uint16_t(0b1u << 1))) { + Write(dst1, Read(GetElementPtr(src_mem, index++))); } - if (UAnd(regs, uint16_t(0b100u))) { - Write(dst2, Read(src2)); + if (UAnd(regs, uint16_t(0b1u << 2))) { + Write(dst2, Read(GetElementPtr(src_mem, index++))); } - if (UAnd(regs, uint16_t(0b1000u))) { - Write(dst3, Read(src3)); + if (UAnd(regs, uint16_t(0b1u << 3))) { + Write(dst3, Read(GetElementPtr(src_mem, index++))); } - if (UAnd(regs, uint16_t(0b10000u))) { - Write(dst4, Read(src4)); + if (UAnd(regs, uint16_t(0b1u << 4))) { + Write(dst4, Read(GetElementPtr(src_mem, index++))); } - if (UAnd(regs, uint16_t(0b100000u))) { - Write(dst5, Read(src5)); + if (UAnd(regs, uint16_t(0b1u << 5))) { + Write(dst5, Read(GetElementPtr(src_mem, index++))); } - if (UAnd(regs, uint16_t(0b1000000u))) { - Write(dst6, Read(src6)); + if (UAnd(regs, uint16_t(0b1u << 6))) { + Write(dst6, Read(GetElementPtr(src_mem, index++))); } - if (UAnd(regs, uint16_t(0b10000000u))) { - Write(dst7, Read(src7)); + if (UAnd(regs, uint16_t(0b1u << 7))) { + Write(dst7, Read(GetElementPtr(src_mem, index++))); } - if (UAnd(regs, uint16_t(0b100000000u))) { - Write(dst8, Read(src8)); + if (UAnd(regs, uint16_t(0b1u << 8))) { + Write(dst8, Read(GetElementPtr(src_mem, index++))); } - if (UAnd(regs, uint16_t(0b1000000000u))) { - Write(dst9, Read(src9)); + if (UAnd(regs, uint16_t(0b1u << 9))) { + Write(dst9, Read(GetElementPtr(src_mem, index++))); } - if (UAnd(regs, uint16_t(0b10000000000u))) { - Write(dst10, Read(src10)); + if (UAnd(regs, uint16_t(0b1u << 10))) { + Write(dst10, Read(GetElementPtr(src_mem, index++))); } - if (UAnd(regs, uint16_t(0b100000000000u))) { - Write(dst11, Read(src11)); + if (UAnd(regs, uint16_t(0b1u << 11))) { + Write(dst11, Read(GetElementPtr(src_mem, index++))); } - if (UAnd(regs, uint16_t(0b1000000000000u))) { - Write(dst12, Read(src12)); + if (UAnd(regs, uint16_t(0b1u << 12))) { + Write(dst12, Read(GetElementPtr(src_mem, index++))); } - if (UAnd(regs, uint16_t(0b10000000000000u))) { - Write(dst13, Read(src13)); + if (UAnd(regs, uint16_t(0b1u << 13))) { + Write(dst13, Read(GetElementPtr(src_mem, index++))); } - if (UAnd(regs, uint16_t(0b100000000000000u))) { - Write(dst14, Read(src14)); + if (UAnd(regs, uint16_t(0b1u << 14))) { + Write(dst14, Read(GetElementPtr(src_mem, index++))); } - if (UAnd(regs, uint16_t(0b1000000000000000u))) { - Write(dst15, Read(src15)); + if (UAnd(regs, uint16_t(0b1u << 15))) { + Write(dst15, Read(GetElementPtr(src_mem, index++))); } Write(dst, Read(dst_new)); return memory; } -DEF_COND_SEM(STMDB, I16 reg_list, R32W dst, R32 dst_new, M32W dst0, R32 src0, - M32W dst1, R32 src1, M32W dst2, R32 src2, M32W dst3, R32 src3, - M32W dst4, R32 src4, M32W dst5, R32 src5, M32W dst6, R32 src6, - M32W dst7, R32 src7, M32W dst8, R32 src8, M32W dst9, R32 src9, - M32W dst10, R32 src10, M32W dst11, R32 src11, M32W dst12, - R32 src12, M32W dst13, R32 src13, M32W dst14, R32 src14, - M32W dst15, R32 src15) { - +DEF_COND_SEM(STMDB, I16 reg_list, R32W dst, R32 dst_new, M32W dst_mem, R32 src0, + R32 src1, R32 src2, R32 src3, R32 src4, R32 src5, R32 src6, + R32 src7, R32 src8, R32 src9, R32 src10, R32 src11, R32 src12, + R32 src13,R32 src14, R32 src15) { auto regs = Read(reg_list); + uint32_t index = 0; if (UAnd(regs, uint16_t(0b1u))) { - Write(dst0, Read(src0)); + Write(GetElementPtr(dst_mem, index++), Read(src0)); } - if (UAnd(regs, uint16_t(0b10u))) { - Write(dst1, Read(src1)); + if (UAnd(regs, uint16_t(0b1u << 1))) { + Write(GetElementPtr(dst_mem, index++), Read(src1)); } - if (UAnd(regs, uint16_t(0b100u))) { - Write(dst2, Read(src2)); + if (UAnd(regs, uint16_t(0b1u << 2))) { + Write(GetElementPtr(dst_mem, index++), Read(src2)); } - if (UAnd(regs, uint16_t(0b1000u))) { - Write(dst3, Read(src3)); + if (UAnd(regs, uint16_t(0b1u << 3))) { + Write(GetElementPtr(dst_mem, index++), Read(src3)); } - if (UAnd(regs, uint16_t(0b10000u))) { - Write(dst4, Read(src4)); + if (UAnd(regs, uint16_t(0b1u << 4))) { + Write(GetElementPtr(dst_mem, index++), Read(src4)); } - if (UAnd(regs, uint16_t(0b100000u))) { - Write(dst5, Read(src5)); + if (UAnd(regs, uint16_t(0b1u << 5))) { + Write(GetElementPtr(dst_mem, index++), Read(src5)); } - if (UAnd(regs, uint16_t(0b1000000u))) { - Write(dst6, Read(src6)); + if (UAnd(regs, uint16_t(0b1u << 6))) { + Write(GetElementPtr(dst_mem, index++), Read(src6)); } - if (UAnd(regs, uint16_t(0b10000000u))) { - Write(dst7, Read(src7)); + if (UAnd(regs, uint16_t(0b1u << 7))) { + Write(GetElementPtr(dst_mem, index++), Read(src7)); } - if (UAnd(regs, uint16_t(0b100000000u))) { - Write(dst8, Read(src8)); + if (UAnd(regs, uint16_t(0b1u << 8))) { + Write(GetElementPtr(dst_mem, index++), Read(src8)); } - if (UAnd(regs, uint16_t(0b1000000000u))) { - Write(dst9, Read(src9)); + if (UAnd(regs, uint16_t(0b1u << 9))) { + Write(GetElementPtr(dst_mem, index++), Read(src9)); } - if (UAnd(regs, uint16_t(0b10000000000u))) { - Write(dst10, Read(src10)); + if (UAnd(regs, uint16_t(0b1u << 10))) { + Write(GetElementPtr(dst_mem, index++), Read(src10)); } - if (UAnd(regs, uint16_t(0b100000000000u))) { - Write(dst11, Read(src11)); + if (UAnd(regs, uint16_t(0b1u << 11))) { + Write(GetElementPtr(dst_mem, index++), Read(src11)); } - if (UAnd(regs, uint16_t(0b1000000000000u))) { - Write(dst12, Read(src12)); + if (UAnd(regs, uint16_t(0b1u << 12))) { + Write(GetElementPtr(dst_mem, index++), Read(src12)); } - if (UAnd(regs, uint16_t(0b10000000000000u))) { - Write(dst13, Read(src13)); + if (UAnd(regs, uint16_t(0b1u << 13))) { + Write(GetElementPtr(dst_mem, index++), Read(src13)); } - if (UAnd(regs, uint16_t(0b100000000000000u))) { - Write(dst14, Read(src14)); + if (UAnd(regs, uint16_t(0b1u << 14))) { + Write(GetElementPtr(dst_mem, index++), Read(src14)); } - if (UAnd(regs, uint16_t(0b1000000000000000u))) { - Write(dst15, Read(src15)); + if (UAnd(regs, uint16_t(0b1u << 15))) { + Write(GetElementPtr(dst_mem, index++), Read(src15)); } Write(dst, Read(dst_new)); return memory; From c5ca741c9e8ca32202a62acb21b6f883dc49f47a Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 21 Jan 2021 13:45:26 -0500 Subject: [PATCH 116/130] Rest of Multiple Load/Store that do not execute in a different mode --- lib/Arch/AArch32/Decode.cpp | 84 +++++++++++++++++------------- lib/Arch/AArch32/Semantics/MEM.cpp | 12 ++--- 2 files changed, 53 insertions(+), 43 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 60998fec6..0523a49e4 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -2015,15 +2015,15 @@ static bool TryDecodeLoadStoreDualHalfSignedBReg(Instruction &inst, } // P U op L register_list -// 0 0 0 0 STMDA, STMED if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; +// 0 0 0 0 STMDA, STMED if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if i == n && wback && i != LowestSetBit(registers) then bits(32) UNKNOWN; // 0 0 0 1 LDMDA, LDMFA if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if wback && registers == '1' then UNPREDICTABLE; -// 0 1 0 0 STM, STMIA, STMEA if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; +// 0 1 0 0 STM, STMIA, STMEA if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if i == n && wback && i != LowestSetBit(registers) then bits(32) UNKNOWN; // 0 1 0 1 LDM, LDMIA, LDMFD if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if wback && registers == '1' then UNPREDICTABLE; // 1 0 STM (User registers) if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; -// 1 0 0 0 STMDB, STMFD if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; +// 1 0 0 0 STMDB, STMFD if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if i == n && wback && i != LowestSetBit(registers) then bits(32) UNKNOWN; // 1 0 0 1 LDMDB, LDMEA if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if wback && registers == '1' then UNPREDICTABLE; // 1 1 0xxxxxxxxxxxxxxx LDM (User registers) if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; -// 1 1 0 0 STMIB, STMFA if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; +// 1 1 0 0 STMIB, STMFA if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if i == n && wback && i != LowestSetBit(registers) then bits(32) UNKNOWN; // 1 1 0 1 LDMIB, LDMED if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if wback && registers == '1' then UNPREDICTABLE; // 1 1 1xxxxxxxxxxxxxxx LDM (exception return) if n == 15 then UNPREDICTABLE; if wback && registers == '1' then UNPREDICTABLE; static const char * const kLoadStoreM[] = { @@ -2050,7 +2050,7 @@ static const char * const kLoadStoreM[] = { // LDM{}{} SP!, is an alias for POP{}{} // STMDB{}{} SP!, is an alias for PUSH{}{} template + bool kAlignPC = false> static bool TryDecodeLoadStoreMultiple(Instruction &inst, uint32_t bits) { const LoadStoreM enc = { bits }; inst.function = kLoadStoreM[enc.P << 3 | enc.U << 2 | enc.op << 1 | enc.L]; @@ -2083,32 +2083,42 @@ static bool TryDecodeLoadStoreMultiple(Instruction &inst, uint32_t bits) { auto is_cond = DecodeCondition(inst, enc.cond); - AddImmOp(inst, enc.register_list, 16u, false); - - // Write Back - AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); - if (wback) { - if (enc.L) { - // LDM - AddAddrRegOp(inst, kIntRegName[enc.rn], 32u, Operand::kActionRead, - 4 * reg_cnt); - } else { - // STMDB - AddAddrRegOp(inst, kIntRegName[enc.rn], 32u, Operand::kActionRead, - -4 * reg_cnt); - } - } else { - AddAddrRegOp(inst, kIntRegName[enc.rn], 32u, Operand::kActionRead, 0); + uint32_t wback_disp = 0; + uint32_t disp = 0; + switch (enc.P << 2 | enc.U << 1 | enc.op) { + case 0b000: + if (wback) { + wback_disp = -4 * reg_cnt; + } + disp = -4 * reg_cnt + 4; + break; + case 0b010: + if (wback) { + wback_disp = 4 * reg_cnt; + } + // disp remains 0 + break; + case 0b100: + if (wback) { + wback_disp = -4 * reg_cnt; + } + disp = -4 * reg_cnt; + break; + case 0b110: + if (wback) { + wback_disp = 4 * reg_cnt; + } + disp = 4; + break; + // TODO(Sonya): STM (User registers), LDM (User registers), LDM (exception return) } - // Add mem and reg ops - if (enc.L){ - AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, 0); - } else { - AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, -4 * reg_cnt); - } + AddImmOp(inst, enc.register_list, 16u, false); + AddIntRegOp(inst, enc.rn, 32u, Operand::kActionWrite); + AddAddrRegOp(inst, kIntRegName[enc.rn], 32u, kMemAction, wback_disp); + AddAddrRegOp(inst, kIntRegName[enc.rn], 32u, kMemAction, disp); for (uint32_t i = 0u; 16u > i; i++) { - AddIntRegOp(inst, i, 32, kRegAction); + AddIntRegOp(inst, i, 32u, kRegAction); } if (enc.register_list & (0b1 << 15u)) { @@ -2811,22 +2821,22 @@ static TryDecode * kExtraLoadStore[] = { [0b111111] = TryDecodeLoadStoreDualHalfSignedBIL, }; -// Load Store Multiple +// Load Store Multiple

| | | static TryDecode * kMLoadStore[] = { - [0b0000] = nullptr, //"STMDA", - [0b0001] = nullptr, //"LDMDA", + [0b0000] = TryDecodeLoadStoreMultiple, //"STMDA", + [0b0001] = TryDecodeLoadStoreMultiple, //"LDMDA", [0b0010] = nullptr, //"STMu", // (User registers) [0b0011] = nullptr, //"LDM", // (User registers) || (exception return) - [0b0100] = nullptr, //"STM", - [0b0101] = TryDecodeLoadStoreMultiple, + [0b0100] = TryDecodeLoadStoreMultiple, //"STM", + [0b0101] = TryDecodeLoadStoreMultiple, [0b0110] = nullptr, //"STMu", // (User registers) [0b0111] = nullptr, //"LDM", // (User registers) || (exception return) - [0b1000] = TryDecodeLoadStoreMultiple, - [0b1001] = nullptr, //"LDMDB", + [0b1000] = TryDecodeLoadStoreMultiple, + [0b1001] = TryDecodeLoadStoreMultiple, //"LDMDB", [0b1010] = nullptr, //"STMu", // (User registers) [0b1011] = nullptr, //"LDM", // (User registers) || (exception return) - [0b1100] = nullptr, //"STMIB", - [0b1101] = nullptr, //"LDMIB", + [0b1100] = TryDecodeLoadStoreMultiple, //"STMIB", + [0b1101] = TryDecodeLoadStoreMultiple, //"LDMIB", [0b1110] = nullptr, //"STMu", // (User registers) [0b1111] = nullptr, //"LDM", // (User registers) || (exception return) }; diff --git a/lib/Arch/AArch32/Semantics/MEM.cpp b/lib/Arch/AArch32/Semantics/MEM.cpp index 7b4e20a55..3fa7e5675 100644 --- a/lib/Arch/AArch32/Semantics/MEM.cpp +++ b/lib/Arch/AArch32/Semantics/MEM.cpp @@ -406,15 +406,15 @@ DEF_COND_SEM(STMDB, I16 reg_list, R32W dst, R32 dst_new, M32W dst_mem, R32 src0, } } // namespace -//DEF_ISEL(STMDA) = STMDA; -//DEF_ISEL(LDMDA) = LDMDA; -//DEF_ISEL(STM) = STM; +DEF_ISEL(STMDA) = STMDB; +DEF_ISEL(LDMDA) = LDM; +DEF_ISEL(STM) = STMDB; DEF_ISEL(LDM) = LDM; //DEF_ISEL(STMu) = STMu; DEF_ISEL(STMDB) = STMDB; -//DEF_ISEL(LDMDB) = LDMDB; +DEF_ISEL(LDMDB) = LDM; //DEF_ISEL(LDMu) = LDMu; -//DEF_ISEL(STMIB) = STMIB; -//DEF_ISEL(LDMIB) = LDMIB; +DEF_ISEL(STMIB) = STMDB; +DEF_ISEL(LDMIB) = LDM; //DEF_ISEL(LDMe) = LDMe; From d69619b1136c7a294e6168b5795387b60db9ad10 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 4 Feb 2021 12:30:31 -0500 Subject: [PATCH 117/130] Bitfield Extract --- lib/Arch/AArch32/Decode.cpp | 55 ++++++++++++++++++++++++++- lib/Arch/AArch32/Semantics/BINARY.cpp | 32 ++++++++++++++++ 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 0523a49e4..3e9ddfeab 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -475,6 +475,22 @@ union Sat32 { } __attribute__((packed)); static_assert(sizeof(Sat32) == 4, " "); +// Bitfield Extract +union BitExt { + uint32_t flat; + struct { + uint32_t Rn : 4; + uint32_t _101 : 3; + uint32_t lsb : 5; + uint32_t Rd : 4; + uint32_t widthm1 : 5; + uint32_t _1 : 1; + uint32_t U : 1; + uint32_t _01111: 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(BitExt) == 4, " "); static constexpr auto kPCRegNum = 15u; @@ -2552,6 +2568,40 @@ static bool TryDecodeSat32(Instruction &inst, uint32_t bits) { return true; } +// U +// 0 SBFX +// 1 UBFX +static const char * const kBitExt[] = { + [0b0] = "SBFX", + [0b1] = "UBFX", +}; + +// Bitfield Extract +static bool TryBitExtract(Instruction &inst, uint32_t bits) { + const BitExt enc = { bits }; + DecodeCondition(inst, enc.cond); + + inst.function = kBitExt[enc.U]; + + // if d == 15 || n == 15 then UNPREDICTABLE; + // msbit = lsbit + widthminus1; + // if msbit > 31 then UNPREDICTABLE; + if (enc.Rd == kPCRegNum + || enc.Rn == kPCRegNum + || (enc.lsb + enc.widthm1) > 31) { + inst.category = Instruction::kCategoryError; + return false; + } + + AddIntRegOp(inst, enc.Rd, 32u, Operand::kActionWrite); + AddIntRegOp(inst, enc.Rn, 32u, Operand::kActionRead); + AddImmOp(inst, enc.lsb); + AddImmOp(inst, enc.widthm1); + + inst.category = Instruction::kCategoryNormal; + return true; +} + // op0 op1 //00xxx Parallel Arithmetic //01000 101 SEL @@ -2635,7 +2685,7 @@ static TryDecode * TryMedia(uint32_t bits) { case 0b01101011: case 0b01110011: case 0b01111011: - // Extend and Add + //return TryExtAdd; case 0b11000000: // Unsigned Sum of Absolute Differences case 0b11100000: @@ -2645,6 +2695,7 @@ static TryDecode * TryMedia(uint32_t bits) { // Bitfield Insert case 0b11111111: // Permanently UNDEFINED + return nullptr; case 0b11010010: case 0b11010110: case 0b11011010: @@ -2653,7 +2704,7 @@ static TryDecode * TryMedia(uint32_t bits) { case 0b11110110: case 0b11111010: case 0b11111110: - // Bitfield Extract + return TryBitExtract; default: return nullptr; } diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index 866c64b7a..5bcc6e289 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -589,3 +589,35 @@ DEF_ISEL(SMMLSR) = SMMLS; DEF_ISEL(SMMUL) = SMMLA; DEF_ISEL(SMMULR) = SMMLA; + +// Bitfield Extract +namespace { +DEF_COND_SEM(SBFX, R32W dst, R32 src1, I32 src2, I32 src3) { + auto src = Signed(Read(src1)); + auto lsbit = Read(src2); + auto widthminus1 = Read(src3); + auto msbit = Signed(lsbit + widthminus1); + // Extract and retain high bit sign of msbit + // Shift lift to remove the high bits, then shift right to remove the low bits + auto res = SShr(SShl(src, int32_t(31) - Signed(msbit)), + int32_t(31) - Signed(widthminus1)); + Write(dst, Unsigned(res)); + return memory; +} + +DEF_COND_SEM(UBFX, R32W dst, R32 src1, I32 src2, I32 src3) { + auto src = Read(src1); + auto lsbit = Read(src2); + auto widthminus1 = Read(src3); + auto msbit = lsbit + widthminus1; + // Extract unsigned + // Shift lift to remove the high bits, then shift right to remove the low bits + auto res = UShr(UShl(src, uint32_t(31) - msbit), uint32_t(31) - widthminus1); + Write(dst, res); + return memory; +} +} + +DEF_ISEL(SBFX) = SBFX; +DEF_ISEL(UBFX) = UBFX; + From 8c62bf0da99ec9c9340ab6c06654a3a37dd413cf Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 4 Feb 2021 14:42:31 -0500 Subject: [PATCH 118/130] Extend and Add --- lib/Arch/AArch32/Decode.cpp | 90 +++++++++++++++++++- lib/Arch/AArch32/Semantics/BINARY.cpp | 115 ++++++++++++++++++++++++++ 2 files changed, 204 insertions(+), 1 deletion(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 3e9ddfeab..1dce7ba82 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -475,6 +475,23 @@ union Sat32 { } __attribute__((packed)); static_assert(sizeof(Sat32) == 4, " "); +// Extend and Add +union ExtAdd { + uint32_t flat; + struct { + uint32_t Rm : 4; + uint32_t _000111 : 6; + uint32_t rot : 2; + uint32_t Rd : 4; + uint32_t Rn : 4; + uint32_t op : 2; + uint32_t U : 1; + uint32_t _01101: 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(ExtAdd) == 4, " "); + // Bitfield Extract union BitExt { uint32_t flat; @@ -2568,6 +2585,77 @@ static bool TryDecodeSat32(Instruction &inst, uint32_t bits) { return true; } +// U op Rn == 15 +// 0 00 != 1111 SXTAB16 +// 0 00 1111 SXTB16 +// 0 10 != 1111 SXTAB +// 0 10 1111 SXTB +// 0 11 != 1111 SXTAH +// 0 11 1111 SXTH +// 1 00 != 1111 UXTAB16 +// 1 00 1111 UXTB16 +// 1 10 != 1111 UXTAB +// 1 10 1111 UXTB +// 1 11 != 1111 UXTAH +// 1 11 1111 UXTH +static const char * kExtAdd(uint32_t index) { + switch(index) { + case 0b0000: + return "SXTAB16"; + case 0b0001: + return "SXTB16"; + case 0b0100: + return "SXTAB"; + case 0b0101: + return "SXTB"; + case 0b0110: + return "SXTAH"; + case 0b0111: + return "SXTH"; + case 0b1000: + return "UXTAB16"; + case 0b1001: + return "UXTB16"; + case 0b1100: + return "UXTAB"; + case 0b1101: + return "UXTB"; + case 0b1110: + return "UXTAH"; + case 0b1111: + return "UXTH"; + default: + return nullptr; + } +} + +// Extend and Add +static bool TryExtAdd(Instruction &inst, uint32_t bits) { + const ExtAdd enc = { bits }; + DecodeCondition(inst, enc.cond); + + auto instruction = kExtAdd(enc.U << 3 | enc.op | (enc.Rn == kPCRegNum)); + + // if d == 15 || m == 15 then UNPREDICTABLE; + if (!instruction || enc.Rd == kPCRegNum || enc.Rm == kPCRegNum) { + inst.category = Instruction::kCategoryError; + return false; + } + inst.function = instruction; + + AddIntRegOp(inst, enc.Rd, 32u, Operand::kActionWrite); + if (enc.Rn != kPCRegNum) { + AddIntRegOp(inst, enc.Rn, 32u, Operand::kActionRead); + } else { + AddImmOp(inst, 0u); + } + AddIntRegOp(inst, enc.Rm, 32u, Operand::kActionRead); + AddImmOp(inst, enc.rot << 3); + + inst.category = Instruction::kCategoryNormal; + return true; +} + // U // 0 SBFX // 1 UBFX @@ -2685,7 +2773,7 @@ static TryDecode * TryMedia(uint32_t bits) { case 0b01101011: case 0b01110011: case 0b01111011: - //return TryExtAdd; + return TryExtAdd; case 0b11000000: // Unsigned Sum of Absolute Differences case 0b11100000: diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index 5bcc6e289..06248581d 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -590,6 +590,121 @@ DEF_ISEL(SMMUL) = SMMLA; DEF_ISEL(SMMULR) = SMMLA; +// Extend and Add +namespace { +template +T ROR_C(T val, T shift) { + if (shift == 0) { + return val; + } + + auto m = URem(shift, sizeof(T)); + auto shr = UShr(val, m); + auto shl = UShl(val, sizeof(T) - m); + auto res = UOr(shr, shl); + return res; +} + +DEF_COND_SEM(SXTAB16, R32W dst, R32 src1, R32 src2, I32 src3) { + auto src = Read(src2); + auto src_add = Read(src1); + auto rot = Read(src3); + + src = ROR_C(src, rot); + // low/high 16 bits of rn + the low byte sign extended of the low/high 16 bits of rm + auto low = ZExt(UAdd(Trunc(src_add), Unsigned(SExtTo(Signed(TruncTo(src)))))); + auto high = ZExt(UAdd(Trunc(UShr(src_add, 16u)), + Unsigned(SExtTo(Signed(TruncTo(UShr(src, 16u))))))); + auto res = UOr(low, UShl(high, 16u)); + + Write(dst, res); + return memory; +} + +DEF_COND_SEM(SXTAB, R32W dst, R32 src1, R32 src2, I32 src3) { + auto src = Read(src2); + auto src_add = Read(src1); + auto rot = Read(src3); + + src = ROR_C(src, rot); + // Extract low byte + auto res = UAdd(Unsigned(SExtTo(Signed(TruncTo(src)))), + src_add); + + Write(dst, res); + return memory; +} + +DEF_COND_SEM(SXTAH, R32W dst, R32 src1, R32 src2, I32 src3) { + auto src = Read(src2); + auto src_add = Read(src1); + auto rot = Read(src3); + + src = ROR_C(src, rot); + // Extract low 2 bytes and sign extend + auto res = UAdd(Unsigned(SExt(Signed(Trunc(src)))) , src_add); + + Write(dst, res); + return memory; +} + +DEF_COND_SEM(UXTAB16, R32W dst, R32 src1, R32 src2, I32 src3) { + auto src = Read(src2); + auto src_add = Read(src1); + auto rot = Read(src3); + + src = ROR_C(src, rot); + // low/high 16 bits of rn + the low byte of the low/high 16 bits of rm + auto low = ZExt(UAdd(Trunc(src_add), UAnd(Trunc(src), uint16_t(255u)))); + auto high = ZExt(UAdd(Trunc(UShr(src_add, 16u)), + UAnd(Trunc(UShr(src, 16u)), uint16_t(255u)))); + auto res = UOr(low, UShl(high, 16u)); + + Write(dst, res); + return memory; +} + +DEF_COND_SEM(UXTAB, R32W dst, R32 src1, R32 src2, I32 src3) { + auto src = Read(src2); + auto src_add = Read(src1); + auto rot = Read(src3); + + src = ROR_C(src, rot); + // Extract low byte i.e. 0b11111111 = 255 + auto res = UAdd(UAnd(src, uint32_t(255u)), src_add); + + Write(dst, res); + return memory; +} + +DEF_COND_SEM(UXTAH, R32W dst, R32 src1, R32 src2, I32 src3) { + auto src = Read(src2); + auto src_add = Read(src1); + auto rot = Read(src3); + + src = ROR_C(src, rot); + // Extract low 2 bytes i.e. 0b1111111111111111 = 65535 + auto res = UAdd(UAnd(src, uint32_t(65535u)), src_add); + + Write(dst, res); + return memory; +} +} + +DEF_ISEL(SXTAB16) = SXTAB16; +DEF_ISEL(SXTB16) = SXTAB16; +DEF_ISEL(SXTAB) = SXTAB; +DEF_ISEL(SXTB) = SXTAB; +DEF_ISEL(SXTAH) = SXTAH; +DEF_ISEL(SXTH) = SXTAH; +DEF_ISEL(UXTAB16) = UXTAB16; +DEF_ISEL(UXTB16) = UXTAB16; +DEF_ISEL(UXTAB) = UXTAB; +DEF_ISEL(UXTB) = UXTAB; +DEF_ISEL(UXTAH) = UXTAH; +DEF_ISEL(UXTH) = UXTAH; + + // Bitfield Extract namespace { DEF_COND_SEM(SBFX, R32W dst, R32 src1, I32 src2, I32 src3) { From f81b2511fb72f9e113825e703ae5f9b6e197c93a Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 4 Feb 2021 15:24:36 -0500 Subject: [PATCH 119/130] fix --- lib/Arch/AArch32/Decode.cpp | 2 +- lib/Arch/AArch32/Semantics/BINARY.cpp | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 1dce7ba82..2f217cabc 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -2634,7 +2634,7 @@ static bool TryExtAdd(Instruction &inst, uint32_t bits) { const ExtAdd enc = { bits }; DecodeCondition(inst, enc.cond); - auto instruction = kExtAdd(enc.U << 3 | enc.op | (enc.Rn == kPCRegNum)); + auto instruction = kExtAdd(enc.U << 3 | enc.op << 1 | (enc.Rn == kPCRegNum)); // if d == 15 || m == 15 then UNPREDICTABLE; if (!instruction || enc.Rd == kPCRegNum || enc.Rm == kPCRegNum) { diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index 06248581d..4f0b893f0 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -593,14 +593,14 @@ DEF_ISEL(SMMULR) = SMMLA; // Extend and Add namespace { template -T ROR_C(T val, T shift) { +T ROR_C(T val, T shift, T nbits) { if (shift == 0) { return val; } - auto m = URem(shift, sizeof(T)); + auto m = URem(shift, nbits); auto shr = UShr(val, m); - auto shl = UShl(val, sizeof(T) - m); + auto shl = UShl(val, nbits - m); auto res = UOr(shr, shl); return res; } @@ -610,7 +610,7 @@ DEF_COND_SEM(SXTAB16, R32W dst, R32 src1, R32 src2, I32 src3) { auto src_add = Read(src1); auto rot = Read(src3); - src = ROR_C(src, rot); + src = ROR_C(src, rot, 32u); // low/high 16 bits of rn + the low byte sign extended of the low/high 16 bits of rm auto low = ZExt(UAdd(Trunc(src_add), Unsigned(SExtTo(Signed(TruncTo(src)))))); auto high = ZExt(UAdd(Trunc(UShr(src_add, 16u)), @@ -626,7 +626,7 @@ DEF_COND_SEM(SXTAB, R32W dst, R32 src1, R32 src2, I32 src3) { auto src_add = Read(src1); auto rot = Read(src3); - src = ROR_C(src, rot); + src = ROR_C(src, rot, 32u); // Extract low byte auto res = UAdd(Unsigned(SExtTo(Signed(TruncTo(src)))), src_add); @@ -640,7 +640,7 @@ DEF_COND_SEM(SXTAH, R32W dst, R32 src1, R32 src2, I32 src3) { auto src_add = Read(src1); auto rot = Read(src3); - src = ROR_C(src, rot); + src = ROR_C(src, rot, 32u); // Extract low 2 bytes and sign extend auto res = UAdd(Unsigned(SExt(Signed(Trunc(src)))) , src_add); @@ -653,7 +653,7 @@ DEF_COND_SEM(UXTAB16, R32W dst, R32 src1, R32 src2, I32 src3) { auto src_add = Read(src1); auto rot = Read(src3); - src = ROR_C(src, rot); + src = ROR_C(src, rot, 32u); // low/high 16 bits of rn + the low byte of the low/high 16 bits of rm auto low = ZExt(UAdd(Trunc(src_add), UAnd(Trunc(src), uint16_t(255u)))); auto high = ZExt(UAdd(Trunc(UShr(src_add, 16u)), @@ -669,7 +669,7 @@ DEF_COND_SEM(UXTAB, R32W dst, R32 src1, R32 src2, I32 src3) { auto src_add = Read(src1); auto rot = Read(src3); - src = ROR_C(src, rot); + src = ROR_C(src, rot, 32u); // Extract low byte i.e. 0b11111111 = 255 auto res = UAdd(UAnd(src, uint32_t(255u)), src_add); @@ -682,7 +682,7 @@ DEF_COND_SEM(UXTAH, R32W dst, R32 src1, R32 src2, I32 src3) { auto src_add = Read(src1); auto rot = Read(src3); - src = ROR_C(src, rot); + src = ROR_C(src, rot, 32u); // Extract low 2 bytes i.e. 0b1111111111111111 = 65535 auto res = UAdd(UAnd(src, uint32_t(65535u)), src_add); From f3b0f638b6314fd44b1b5985bbee0f10a8291127 Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 4 Feb 2021 16:26:01 -0500 Subject: [PATCH 120/130] NOP --- lib/Arch/AArch32/Decode.cpp | 147 +++++++++++++++++++++- lib/Arch/AArch32/Runtime/CMakeLists.txt | 1 + lib/Arch/AArch32/Runtime/Instructions.cpp | 2 +- lib/Arch/AArch32/Semantics/MISC.cpp | 36 ++++++ 4 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 lib/Arch/AArch32/Semantics/MISC.cpp diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 2f217cabc..58d127e1e 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -509,6 +509,21 @@ union BitExt { } __attribute__((packed)); static_assert(sizeof(BitExt) == 4, " "); +// Move Special Register and Hints (immediate) +union SpecialRegsAndHints { + uint32_t flat; + struct { + uint32_t imm12 : 12; + uint32_t _1111 : 4; + uint32_t imm4 : 4; + uint32_t _10 : 2; + uint32_t R : 1; + uint32_t _00110: 5; + uint32_t cond : 4; + } __attribute__((packed)); +} __attribute__((packed)); +static_assert(sizeof(SpecialRegsAndHints) == 4, " "); + static constexpr auto kPCRegNum = 15u; static constexpr auto kLRRegNum = 14u; @@ -2167,6 +2182,132 @@ static bool TryDecodeLoadStoreMultiple(Instruction &inst, uint32_t bits) { return true; } + +// Index from: op1 | Ra == 15 | op2 +static const char* kSpecial(uint32_t index) { + switch (index) { + case 0b0000000000000: + return "NOP"; + case 0b0000000000001: + // TODO(Sonya) return "YIELD"; + case 0b0000000000010: + // TODO(Sonya) return "WFE"; + case 0b0000000000011: + // TODO(Sonya) return "WFI"; + case 0b0000000000100: + // TODO(Sonya) return "SEV"; + case 0b0000000000101: + // TODO(Sonya) return "SEVL"; + return nullptr; + case 0b0000000000110: + case 0b0000000000111: + return "HINT_1"; // Reserved hint, behaves as NOP + case 0b0000000001000: + case 0b0000000001001: + case 0b0000000001010: + case 0b0000000001011: + case 0b0000000001100: + case 0b0000000001101: + case 0b0000000001110: + case 0b0000000001111: + return "HINT_2"; // Reserved hint, behaves as NOP + // case 0b0000000010000: ESB ARMv8.2 + case 0b0000000010001: + return "HINT_3"; // Reserved hint, behaves as NOP + case 0b0000000010010: + case 0b0000000010011: + return "HINT_4"; // Reserved hint, behaves as NOP + case 0b0000000010100: + case 0b0000000010101: + case 0b0000000010110: + case 0b0000000010111: + return "HINT_5"; // Reserved hint, behaves as NOP + case 0b0000000011000: + case 0b0000000011001: + case 0b0000000011010: + case 0b0000000011011: + case 0b0000000011100: + case 0b0000000011101: + case 0b0000000011110: + case 0b0000000011111: + return "HINT_6"; // Reserved hint, behaves as NOP + case 0b0000011100000: + case 0b0000011100001: + case 0b0000011100010: + case 0b0000011100011: + case 0b0000011100100: + case 0b0000011100101: + case 0b0000011100110: + case 0b0000011100111: + case 0b0000011101000: + case 0b0000011101001: + case 0b0000011101010: + case 0b0000011101011: + case 0b0000011101100: + case 0b0000011101101: + case 0b0000011101110: + case 0b0000011101111: + return "HINT_11"; // Reserved hint, behaves as NOP + } + switch (index >> 5) { + case 0b00000001: + return "HINT_7"; // Reserved hint, behaves as NOP + case 0b00000010: + case 0b00000011: + return "HINT_8"; // Reserved hint, behaves as NOP + case 0b00000100: + case 0b00000101: + return "HINT_9"; // Reserved hint, behaves as NOP + case 0b00000110: + return "HINT_10"; // Reserved hint, behaves as NOP + default: + return nullptr; + } +} + +// R:imm4 imm12 +// != 00000 MSR (immediate) +// 00000 xxxx00000000 NOP +// 00000 xxxx00000001 YIELD +// 00000 xxxx00000010 WFE +// 00000 xxxx00000011 WFI +// 00000 xxxx00000100 SEV +// 00000 xxxx00000101 SEVL +// 00000 xxxx0000011x Reserved hint, behaves as NOP +// 00000 xxxx00001xxx Reserved hint, behaves as NOP +// 00000 xxxx00010000 ESB ARMv8.2 +// 00000 xxxx00010001 Reserved hint, behaves as NOP +// 00000 xxxx0001001x Reserved hint, behaves as NOP +// 00000 xxxx000101xx Reserved hint, behaves as NOP +// 00000 xxxx00011xxx Reserved hint, behaves as NOP +// 00000 xxxx001xxxxx Reserved hint, behaves as NOP +// 00000 xxxx01xxxxxx Reserved hint, behaves as NOP +// 00000 xxxx10xxxxxx Reserved hint, behaves as NOP +// 00000 xxxx110xxxxx Reserved hint, behaves as NOP +// 00000 xxxx1110xxxx Reserved hint, behaves as NOP +// 00000 xxxx1111xxxx DBG +// Move Special Register and Hints (immediate) +// TODO(Sonya): This literally only has functionality for NOP and "behaves as NOP" +static bool TryMoveSpecialRegisterAndHintsI(Instruction &inst, uint32_t bits) { + const SpecialRegsAndHints enc = { bits }; + + // R:imm4:imm12 + auto instruction = kSpecial(enc.R << 12 | enc.imm4 | (enc.imm12 & 255u)); + if (!instruction) { + inst.category = Instruction::kCategoryError; + return false; + } + + // A NOP is still conditional: + // if ConditionPassed() then + // EncodingSpecificOperations(); + // // Do nothing + inst.function = instruction; + DecodeCondition(inst, enc.cond); + inst.category = Instruction::kCategoryNormal; + return true; +} + // Can package semantics for MOV with ORR and MVN with BIC since src1 will be // 0 and 1 for MOV and MVN respectively, mirroring the semantics in LOGICAL.cpp static InstEval * kLogArithEvaluators[] = { @@ -2197,9 +2338,7 @@ static const char * const kLogicalArithmeticRRRI[] = { static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { const LogicalArithRRRI enc = { bits }; - auto instruction = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; - - inst.function = instruction; + inst.function = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; auto is_cond = DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); @@ -2882,7 +3021,7 @@ static TryDecode * kDataProcessingI[] = { [0b0111] = TryDecodeIntegerDataProcessingRRI, [0b1000] = TryDecodeMoveHalfword, [0b1001] = TryIntegerTestAndCompareRI, - [0b1010] = nullptr, // TODO(Sonya): Move Special Register and Hints (immediate) + [0b1010] = TryMoveSpecialRegisterAndHintsI, [0b1011] = TryIntegerTestAndCompareRI, [0b1100] = TryLogicalArithmeticRRI, [0b1101] = TryLogicalArithmeticRRI, diff --git a/lib/Arch/AArch32/Runtime/CMakeLists.txt b/lib/Arch/AArch32/Runtime/CMakeLists.txt index a2736cfee..1b8bb2b42 100644 --- a/lib/Arch/AArch32/Runtime/CMakeLists.txt +++ b/lib/Arch/AArch32/Runtime/CMakeLists.txt @@ -59,6 +59,7 @@ function(add_runtime_helper target_name little_endian) "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/MEM.cpp" "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/BRANCH.cpp" "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/BITBYTE.cpp" + "${REMILL_LIB_DIR}/Arch/AArch32/Semantics/MISC.cpp" ) endfunction() diff --git a/lib/Arch/AArch32/Runtime/Instructions.cpp b/lib/Arch/AArch32/Runtime/Instructions.cpp index 55a9c3cea..b64847023 100644 --- a/lib/Arch/AArch32/Runtime/Instructions.cpp +++ b/lib/Arch/AArch32/Runtime/Instructions.cpp @@ -67,7 +67,7 @@ DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; #include "lib/Arch/AArch32/Semantics/COND.cpp" //#include "lib/Arch/AArch32/Semantics/CONVERT.cpp" //#include "lib/Arch/AArch32/Semantics/DATAXFER.cpp" -//#include "lib/Arch/AArch32/Semantics/MISC.cpp" +#include "lib/Arch/AArch32/Semantics/MISC.cpp" //#include "lib/Arch/AArch32/Semantics/SHIFT.cpp" //#include "lib/Arch/AArch32/Semantics/SIMD.cpp" //#include "lib/Arch/AArch32/Semantics/SYSTEM.cpp" diff --git a/lib/Arch/AArch32/Semantics/MISC.cpp b/lib/Arch/AArch32/Semantics/MISC.cpp new file mode 100644 index 000000000..02fe25cb9 --- /dev/null +++ b/lib/Arch/AArch32/Semantics/MISC.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace { + +DEF_COND_SEM(DoNOP) { + return memory; +} + +} // namespace + +DEF_ISEL(NOP) = DoNOP; +DEF_ISEL(HINT_1) = DoNOP; +DEF_ISEL(HINT_2) = DoNOP; +DEF_ISEL(HINT_3) = DoNOP; +DEF_ISEL(HINT_4) = DoNOP; +DEF_ISEL(HINT_5) = DoNOP; +DEF_ISEL(HINT_6) = DoNOP; +DEF_ISEL(HINT_7) = DoNOP; +DEF_ISEL(HINT_8) = DoNOP; +DEF_ISEL(HINT_9) = DoNOP; +DEF_ISEL(HINT_10) = DoNOP; +DEF_ISEL(HINT_11) = DoNOP; From 127c41111e8112d875030e1d88d30c3fa890c36d Mon Sep 17 00:00:00 2001 From: sschriner Date: Thu, 4 Feb 2021 16:51:45 -0500 Subject: [PATCH 121/130] Small fix --- lib/Arch/AArch32/Semantics/BINARY.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index 4f0b893f0..5544188a5 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -613,9 +613,9 @@ DEF_COND_SEM(SXTAB16, R32W dst, R32 src1, R32 src2, I32 src3) { src = ROR_C(src, rot, 32u); // low/high 16 bits of rn + the low byte sign extended of the low/high 16 bits of rm auto low = ZExt(UAdd(Trunc(src_add), Unsigned(SExtTo(Signed(TruncTo(src)))))); - auto high = ZExt(UAdd(Trunc(UShr(src_add, 16u)), + auto high = SExt(UAdd(Trunc(UShr(src_add, 16u)), Unsigned(SExtTo(Signed(TruncTo(UShr(src, 16u))))))); - auto res = UOr(low, UShl(high, 16u)); + auto res = UOr(low, UShl(Unsigned(high), 16u)); Write(dst, res); return memory; From 4246c791aad64461e901b65088364c0b08ea8a70 Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 5 Feb 2021 10:08:35 -0500 Subject: [PATCH 122/130] Simplified the bit reps in TryMoveSpecialRegisterAndHintsI --- lib/Arch/AArch32/Decode.cpp | 113 ++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 55 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index 58d127e1e..cc6551f6f 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -2185,80 +2185,83 @@ static bool TryDecodeLoadStoreMultiple(Instruction &inst, uint32_t bits) { // Index from: op1 | Ra == 15 | op2 static const char* kSpecial(uint32_t index) { + if (index >> 8) { + return nullptr; // TODO(Sonya) MSR (immediate) + } switch (index) { - case 0b0000000000000: + case 0b000000000: return "NOP"; - case 0b0000000000001: + case 0b000000001: // TODO(Sonya) return "YIELD"; - case 0b0000000000010: + case 0b000000010: // TODO(Sonya) return "WFE"; - case 0b0000000000011: + case 0b000000011: // TODO(Sonya) return "WFI"; - case 0b0000000000100: + case 0b000000100: // TODO(Sonya) return "SEV"; - case 0b0000000000101: + case 0b000000101: // TODO(Sonya) return "SEVL"; return nullptr; - case 0b0000000000110: - case 0b0000000000111: + case 0b000000110: + case 0b000000111: return "HINT_1"; // Reserved hint, behaves as NOP - case 0b0000000001000: - case 0b0000000001001: - case 0b0000000001010: - case 0b0000000001011: - case 0b0000000001100: - case 0b0000000001101: - case 0b0000000001110: - case 0b0000000001111: + case 0b000001000: + case 0b000001001: + case 0b000001010: + case 0b000001011: + case 0b000001100: + case 0b000001101: + case 0b000001110: + case 0b000001111: return "HINT_2"; // Reserved hint, behaves as NOP // case 0b0000000010000: ESB ARMv8.2 - case 0b0000000010001: + case 0b000010001: return "HINT_3"; // Reserved hint, behaves as NOP - case 0b0000000010010: - case 0b0000000010011: + case 0b000010010: + case 0b000010011: return "HINT_4"; // Reserved hint, behaves as NOP - case 0b0000000010100: - case 0b0000000010101: - case 0b0000000010110: - case 0b0000000010111: + case 0b000010100: + case 0b000010101: + case 0b000010110: + case 0b000010111: return "HINT_5"; // Reserved hint, behaves as NOP - case 0b0000000011000: - case 0b0000000011001: - case 0b0000000011010: - case 0b0000000011011: - case 0b0000000011100: - case 0b0000000011101: - case 0b0000000011110: - case 0b0000000011111: + case 0b000011000: + case 0b000011001: + case 0b000011010: + case 0b000011011: + case 0b000011100: + case 0b000011101: + case 0b000011110: + case 0b000011111: return "HINT_6"; // Reserved hint, behaves as NOP - case 0b0000011100000: - case 0b0000011100001: - case 0b0000011100010: - case 0b0000011100011: - case 0b0000011100100: - case 0b0000011100101: - case 0b0000011100110: - case 0b0000011100111: - case 0b0000011101000: - case 0b0000011101001: - case 0b0000011101010: - case 0b0000011101011: - case 0b0000011101100: - case 0b0000011101101: - case 0b0000011101110: - case 0b0000011101111: + case 0b011100000: + case 0b011100001: + case 0b011100010: + case 0b011100011: + case 0b011100100: + case 0b011100101: + case 0b011100110: + case 0b011100111: + case 0b011101000: + case 0b011101001: + case 0b011101010: + case 0b011101011: + case 0b011101100: + case 0b011101101: + case 0b011101110: + case 0b011101111: return "HINT_11"; // Reserved hint, behaves as NOP } switch (index >> 5) { - case 0b00000001: + case 0b0001: return "HINT_7"; // Reserved hint, behaves as NOP - case 0b00000010: - case 0b00000011: + case 0b0010: + case 0b0011: return "HINT_8"; // Reserved hint, behaves as NOP - case 0b00000100: - case 0b00000101: + case 0b0100: + case 0b0101: return "HINT_9"; // Reserved hint, behaves as NOP - case 0b00000110: + case 0b0110: return "HINT_10"; // Reserved hint, behaves as NOP default: return nullptr; @@ -2291,8 +2294,8 @@ static const char* kSpecial(uint32_t index) { static bool TryMoveSpecialRegisterAndHintsI(Instruction &inst, uint32_t bits) { const SpecialRegsAndHints enc = { bits }; - // R:imm4:imm12 - auto instruction = kSpecial(enc.R << 12 | enc.imm4 | (enc.imm12 & 255u)); + // (R:imm4 != 00000):imm12 + auto instruction = kSpecial(((enc.R << 4 | enc.imm4) != 0b0u) << 8 | (enc.imm12 & 255u)); if (!instruction) { inst.category = Instruction::kCategoryError; return false; From 2bb350c390dcf6ada096d9cb5c6e6c2641a49ae9 Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 5 Feb 2021 10:58:47 -0500 Subject: [PATCH 123/130] Moved Bitfield extract semantics out of BINARY and into BITBYTE --- lib/Arch/AArch32/Decode.cpp | 4 ++-- lib/Arch/AArch32/Semantics/BINARY.cpp | 32 -------------------------- lib/Arch/AArch32/Semantics/BITBYTE.cpp | 31 +++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index cc6551f6f..bff499ad8 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -2214,7 +2214,7 @@ static const char* kSpecial(uint32_t index) { case 0b000001110: case 0b000001111: return "HINT_2"; // Reserved hint, behaves as NOP - // case 0b0000000010000: ESB ARMv8.2 + // case 0b000010000: return "ESB"; // ARMv8.2 case 0b000010001: return "HINT_3"; // Reserved hint, behaves as NOP case 0b000010010: @@ -2294,7 +2294,7 @@ static const char* kSpecial(uint32_t index) { static bool TryMoveSpecialRegisterAndHintsI(Instruction &inst, uint32_t bits) { const SpecialRegsAndHints enc = { bits }; - // (R:imm4 != 00000):imm12 + // (R:imm4 != 00000)<1 bit>:imm12 auto instruction = kSpecial(((enc.R << 4 | enc.imm4) != 0b0u) << 8 | (enc.imm12 & 255u)); if (!instruction) { inst.category = Instruction::kCategoryError; diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index 5544188a5..4a6e511dc 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -704,35 +704,3 @@ DEF_ISEL(UXTB) = UXTAB; DEF_ISEL(UXTAH) = UXTAH; DEF_ISEL(UXTH) = UXTAH; - -// Bitfield Extract -namespace { -DEF_COND_SEM(SBFX, R32W dst, R32 src1, I32 src2, I32 src3) { - auto src = Signed(Read(src1)); - auto lsbit = Read(src2); - auto widthminus1 = Read(src3); - auto msbit = Signed(lsbit + widthminus1); - // Extract and retain high bit sign of msbit - // Shift lift to remove the high bits, then shift right to remove the low bits - auto res = SShr(SShl(src, int32_t(31) - Signed(msbit)), - int32_t(31) - Signed(widthminus1)); - Write(dst, Unsigned(res)); - return memory; -} - -DEF_COND_SEM(UBFX, R32W dst, R32 src1, I32 src2, I32 src3) { - auto src = Read(src1); - auto lsbit = Read(src2); - auto widthminus1 = Read(src3); - auto msbit = lsbit + widthminus1; - // Extract unsigned - // Shift lift to remove the high bits, then shift right to remove the low bits - auto res = UShr(UShl(src, uint32_t(31) - msbit), uint32_t(31) - widthminus1); - Write(dst, res); - return memory; -} -} - -DEF_ISEL(SBFX) = SBFX; -DEF_ISEL(UBFX) = UBFX; - diff --git a/lib/Arch/AArch32/Semantics/BITBYTE.cpp b/lib/Arch/AArch32/Semantics/BITBYTE.cpp index 78983749e..3ad698b60 100644 --- a/lib/Arch/AArch32/Semantics/BITBYTE.cpp +++ b/lib/Arch/AArch32/Semantics/BITBYTE.cpp @@ -23,3 +23,34 @@ DEF_COND_SEM(CLZ, R32W dst, R32 src) { } // namespace DEF_ISEL(CLZ) = CLZ; + +// Bitfield Extract +namespace { +DEF_COND_SEM(SBFX, R32W dst, R32 src1, I32 src2, I32 src3) { + auto src = Signed(Read(src1)); + auto lsbit = Read(src2); + auto widthminus1 = Read(src3); + auto msbit = Signed(lsbit + widthminus1); + // Extract and retain high bit sign of msbit + // Shift lift to remove the high bits, then shift right to remove the low bits + auto res = SShr(SShl(src, int32_t(31) - Signed(msbit)), + int32_t(31) - Signed(widthminus1)); + Write(dst, Unsigned(res)); + return memory; +} + +DEF_COND_SEM(UBFX, R32W dst, R32 src1, I32 src2, I32 src3) { + auto src = Read(src1); + auto lsbit = Read(src2); + auto widthminus1 = Read(src3); + auto msbit = lsbit + widthminus1; + // Extract unsigned + // Shift lift to remove the high bits, then shift right to remove the low bits + auto res = UShr(UShl(src, uint32_t(31) - msbit), uint32_t(31) - widthminus1); + Write(dst, res); + return memory; +} +} + +DEF_ISEL(SBFX) = SBFX; +DEF_ISEL(UBFX) = UBFX; From 17faa18c2cbdd6cd13605a8bf8996e3b80f7aeb4 Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 5 Feb 2021 14:48:56 -0500 Subject: [PATCH 124/130] Finished correcting S/ZExt and Trunc use --- lib/Arch/AArch32/Semantics/BINARY.cpp | 74 +++++++++++++-------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index 4a6e511dc..0cd6ad97c 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -414,40 +414,40 @@ DEF_ISEL(SSAT16) = SSAT16; // Integer Saturating Arithmetic namespace { DEF_COND_SEM(QADD, R32W dst, R32 src1, R32 src2) { - auto rhs = SExt(Signed(Read(src2))); - auto lhs = SExt(Signed(Read(src1))); + auto rhs = SExt(Signed(Read(src2))); + auto lhs = SExt(Signed(Read(src1))); auto res = SAdd(lhs, rhs); res = SignedSatQ(state, res, 32); - Write(dst, TruncTo(res)); + Write(dst, Trunc(Unsigned(res))); return memory; } DEF_COND_SEM(QDADD, R32W dst, R32 src1, R32 src2) { - auto rhs = SExt(Signed(Read(src2))); - auto lhs = SExt(Signed(Read(src1))); + auto rhs = SExt(Signed(Read(src2))); + auto lhs = SExt(Signed(Read(src1))); rhs = SignedSatQ(state, SShl(rhs, 1u), 32); auto res = SAdd(lhs, rhs); res = SignedSatQ(state, res, 32); - Write(dst, TruncTo(res)); + Write(dst, Trunc(Unsigned(res))); return memory; } DEF_COND_SEM(QSUB, R32W dst, R32 src1, R32 src2) { - auto rhs = SExt(Signed(Read(src2))); - auto lhs = SExt(Signed(Read(src1))); + auto rhs = SExt(Signed(Read(src2))); + auto lhs = SExt(Signed(Read(src1))); auto res = SSub(lhs, rhs); res = SignedSatQ(state, res, 32); - Write(dst, TruncTo(res)); + Write(dst, Trunc(Unsigned(res))); return memory; } DEF_COND_SEM(QDSUB, R32W dst, R32 src1, R32 src2) { - auto rhs = SExt(Signed(Read(src2))); - auto lhs = SExt(Signed(Read(src1))); + auto rhs = SExt(Signed(Read(src2))); + auto lhs = SExt(Signed(Read(src1))); rhs = SignedSatQ(state, SShl(rhs, 1u), 32); auto res = SSub(lhs, rhs); res = SignedSatQ(state, res, 32); - Write(dst, TruncTo(res)); + Write(dst, Trunc(Unsigned(res))); return memory; } } // namespace @@ -457,22 +457,22 @@ DEF_ISEL(QDADD) = QDADD; DEF_ISEL(QSUB) = QSUB; DEF_ISEL(QDSUB) = QDSUB; -// Signed multiply, Divide +// TODO Signed multiply, Divide namespace { DEF_COND_SEM(SMLAD, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm ra auto rn = Signed(Read(src1)); auto rm = Signed(Read(src2)); auto ra = Signed(Read(src3)); - auto prod1 = SMul(SExt(Trunc(rn)), - SExt(Trunc(rm))); - auto prod2 = SMul(SExt(SShr(rn, 16u)), - SExt(SShr(rm, 16u))); - auto res = SAdd(SAdd(prod1, prod2), SExt(ra)); + auto prod1 = SMul(SExtTo(Trunc(rn)), + SExtTo(Trunc(rm))); + auto prod2 = SMul(SExtTo(SShr(rn, 16u)), + SExtTo(SShr(rm, 16u))); + auto res = SAdd(SAdd(prod1, prod2), SExt(ra)); WriteTrunc(dst, Unsigned(res)); // if result != SInt(result<31:0>) then // Signed overflow // PSTATE.Q = '1'; - state.sr.q = Select(SCmpNeq(res, SExt(Trunc(res))), + state.sr.q = Select(SCmpNeq(res, SExtTo(Trunc(res))), uint8_t(1), state.sr.q); return memory; } @@ -481,16 +481,16 @@ DEF_COND_SEM(SMLSD, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm ra auto rn = Signed(Read(src1)); auto rm = Signed(Read(src2)); auto ra = Signed(Read(src3)); - auto prod1 = SMul(SExt(Signed(Trunc(rn))), - SExt(Signed(Trunc(rm)))); - auto prod2 = SMul(SExt(SShr(rn, 16u)), - SExt(SShr(rm, 16u))); - auto res = SAdd(SSub(prod1, prod2), SExt(ra)); + auto prod1 = SMul(SExtTo(Signed(Trunc(rn))), + SExtTo(Signed(Trunc(rm)))); + auto prod2 = SMul(SExtTo(SShr(rn, 16u)), + SExtTo(SShr(rm, 16u))); + auto res = SAdd(SSub(prod1, prod2), SExt(ra)); WriteTrunc(dst, Unsigned(res)); // if result != SInt(result<31:0>) then // Signed overflow // PSTATE.Q = '1'; - state.sr.q = Select(SCmpNeq(res, SExt(Trunc(res))), + state.sr.q = Select(SCmpNeq(res, SExtTo(Trunc(res))), uint8_t(1), state.sr.q); return memory; } @@ -520,12 +520,12 @@ DEF_COND_SEM(UDIV, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm DEF_COND_SEM(SMLALD, R32W dst_lo, R32W dst_hi, R32 src1, R32 src2, R32 src3, R32 src4) { // ra - lo rd - hi rn rm ra - lo rd - hi auto rn = Signed(Read(src1)); auto rm = Signed(Read(src2)); - auto lo = SExt(Signed(Read(src3))); - auto hi = SExt(Signed(Read(src4))); - auto prod1 = SMul(SExt(Trunc(rn)), - SExt(Trunc(rm))); - auto prod2 = SMul(SExt(SShr(rn, 16u)), - SExt(SShr(rm, 16u))); + auto lo = SExt(Signed(Read(src3))); + auto hi = SExt(Signed(Read(src4))); + auto prod1 = SMul(SExtTo(Trunc(rn)), + SExtTo(Trunc(rm))); + auto prod2 = SMul(SExtTo(SShr(rn, 16u)), + SExtTo(SShr(rm, 16u))); auto res = SAdd(SAdd(prod1, prod2), SOr(lo, SShl(hi, 32u))); WriteTrunc(dst_lo, Unsigned(res)); WriteTrunc(dst_hi, Unsigned(SShr(res, 32u))); @@ -535,12 +535,12 @@ DEF_COND_SEM(SMLALD, R32W dst_lo, R32W dst_hi, R32 src1, R32 src2, R32 src3, R32 DEF_COND_SEM(SMLSLD, R32W dst_lo, R32W dst_hi, R32 src1, R32 src2, R32 src3, R32 src4) { // ra - lo rd - hi rn rm ra - lo rd - hi auto rn = Signed(Read(src1)); auto rm = Signed(Read(src2)); - auto lo = SExt(Signed(Read(src3))); - auto hi = SExt(Signed(Read(src4))); - auto prod1 = SMul(SExt(Trunc(rn)), - SExt(Trunc(rm))); - auto prod2 = SMul(SExt(SShr(rn, 16u)), - SExt(SShr(rm, 16u))); + auto lo = SExt(Signed(Read(src3))); + auto hi = SExt(Signed(Read(src4))); + auto prod1 = SMul(SExtTo(Trunc(rn)), + SExtTo(Trunc(rm))); + auto prod2 = SMul(SExtTo(SShr(rn, 16u)), + SExtTo(SShr(rm, 16u))); auto res = SAdd(SSub(prod1, prod2), SOr(lo, SShl(hi, 32u))); WriteTrunc(dst_lo, Unsigned(res)); WriteTrunc(dst_hi, Unsigned(SShr(res, 32u))); From af548fe7cc8230283a00fbb99eadfdaca34aeacd Mon Sep 17 00:00:00 2001 From: sschriner Date: Mon, 8 Feb 2021 10:54:01 -0500 Subject: [PATCH 125/130] Ran scripts/format-files to format --- include/remill/Arch/AArch32/Runtime/State.h | 3 + include/remill/Arch/AArch32/Runtime/Types.h | 1 + include/remill/Arch/Arch.h | 20 +- include/remill/Arch/Instruction.h | 42 +- include/remill/Arch/Name.h | 87 +- include/remill/Arch/Runtime/Definitions.h | 22 +- include/remill/Arch/Runtime/HyperCall.h | 2 +- include/remill/Arch/Runtime/Operators.h | 3 +- include/remill/Arch/Runtime/Types.h | 3 +- include/remill/Arch/SPARC32/Runtime/State.h | 130 +- include/remill/Arch/SPARC64/Runtime/State.h | 144 +- include/remill/BC/Compat/CTypes.h | 3 +- include/remill/BC/Compat/CallSite.h | 94 +- include/remill/BC/InstructionLifter.h | 15 +- include/remill/BC/TraceLifter.h | 4 +- include/remill/BC/Util.h | 4 +- lib/Arch/AArch32/Arch.cpp | 21 +- lib/Arch/AArch32/Arch.h | 5 +- lib/Arch/AArch32/Decode.cpp | 1408 +++++++-------- lib/Arch/AArch32/Runtime/Instructions.cpp | 3 + lib/Arch/AArch32/Semantics/BINARY.cpp | 136 +- lib/Arch/AArch32/Semantics/BITBYTE.cpp | 6 +- lib/Arch/AArch32/Semantics/BRANCH.cpp | 4 +- lib/Arch/AArch32/Semantics/COND.cpp | 4 +- lib/Arch/AArch32/Semantics/FLAGS.cpp | 9 +- lib/Arch/AArch32/Semantics/LOGICAL.cpp | 12 +- lib/Arch/AArch32/Semantics/MEM.cpp | 38 +- lib/Arch/AArch64/Arch.cpp | 10 +- lib/Arch/AArch64/Semantics/BRANCH.cpp | 3 +- lib/Arch/Arch.cpp | 27 +- lib/Arch/Instruction.cpp | 136 +- lib/Arch/SPARC32/Arch.cpp | 171 +- lib/Arch/SPARC32/Decode.h | 289 +-- lib/Arch/SPARC32/Extract.cpp | 1290 ++++++-------- lib/Arch/SPARC32/Runtime/Instructions.cpp | 229 +-- lib/Arch/SPARC32/Semantics/BINARY.cpp | 41 +- lib/Arch/SPARC32/Semantics/BRANCH.cpp | 71 +- lib/Arch/SPARC32/Semantics/COND.cpp | 398 ++--- lib/Arch/SPARC32/Semantics/DATAXFER.cpp | 110 +- lib/Arch/SPARC32/Semantics/FLAGS.cpp | 128 +- lib/Arch/SPARC32/Semantics/FOP.cpp | 182 +- lib/Arch/SPARC32/Semantics/MISC.cpp | 39 +- lib/Arch/SPARC32/Semantics/TRAP.cpp | 41 +- lib/Arch/SPARC32/Semantics/WINDOW.cpp | 3 +- lib/Arch/SPARC64/Arch.cpp | 54 +- lib/Arch/SPARC64/Decode.h | 5 +- lib/Arch/SPARC64/Extract.cpp | 1786 ++++++++----------- lib/Arch/SPARC64/Runtime/Instructions.cpp | 240 +-- lib/Arch/SPARC64/Semantics/ADDRESS.cpp | 21 +- lib/Arch/SPARC64/Semantics/BINARY.cpp | 102 +- lib/Arch/SPARC64/Semantics/BITBYTE.cpp | 19 +- lib/Arch/SPARC64/Semantics/BRANCH.cpp | 53 +- lib/Arch/SPARC64/Semantics/DATAXFER.cpp | 151 +- lib/Arch/SPARC64/Semantics/FOP.cpp | 125 +- lib/Arch/SPARC64/Semantics/LOGICAL.cpp | 19 +- lib/Arch/SPARC64/Semantics/MISC.cpp | 7 +- lib/Arch/SPARC64/Semantics/TRAP.cpp | 38 +- lib/Arch/SPARC64/Semantics/VIS.cpp | 25 +- lib/Arch/SPARC64/Semantics/WRASR.cpp | 32 +- lib/Arch/X86/Arch.cpp | 8 +- lib/Arch/X86/Runtime/Instructions.cpp | 4 +- lib/Arch/X86/Semantics/AVX.cpp | 4 +- lib/Arch/X86/Semantics/MISC.cpp | 9 +- lib/Arch/X86/Semantics/MMX.cpp | 21 +- lib/Arch/X86/Semantics/SEMAPHORE.cpp | 28 +- lib/Arch/X86/Semantics/SSE.cpp | 5 +- lib/BC/ABI.cpp | 3 +- lib/BC/DeadStoreEliminator.cpp | 11 +- lib/BC/InstructionLifter.cpp | 139 +- lib/BC/InstructionLifter.h | 12 +- lib/BC/TraceLifter.cpp | 25 +- lib/BC/Util.cpp | 58 +- tests/AArch64/Lift.cpp | 4 +- tests/X86/Lift.cpp | 4 +- 74 files changed, 3971 insertions(+), 4432 deletions(-) diff --git a/include/remill/Arch/AArch32/Runtime/State.h b/include/remill/Arch/AArch32/Runtime/State.h index ebeb0668a..d527a5f98 100644 --- a/include/remill/Arch/AArch32/Runtime/State.h +++ b/include/remill/Arch/AArch32/Runtime/State.h @@ -59,12 +59,15 @@ struct alignas(8) GPR final { Reg r11; volatile uint32_t _12; Reg r12; + // R13 is SP (stack pointer) volatile uint32_t _13; Reg r13; + // R14 is LR (link register) volatile uint32_t _14; Reg r14; + // R15 is PC (program counter) volatile uint32_t _15; Reg r15; diff --git a/include/remill/Arch/AArch32/Runtime/Types.h b/include/remill/Arch/AArch32/Runtime/Types.h index 550b13911..9a8fc33b5 100644 --- a/include/remill/Arch/AArch32/Runtime/Types.h +++ b/include/remill/Arch/AArch32/Runtime/Types.h @@ -27,6 +27,7 @@ typedef RnW R16W; typedef RnW R32W; typedef Rn R8; + //typedef Rn R16; typedef Rn R32; diff --git a/include/remill/Arch/Arch.h b/include/remill/Arch/Arch.h index fe2eb2395..f9b23904a 100644 --- a/include/remill/Arch/Arch.h +++ b/include/remill/Arch/Arch.h @@ -31,6 +31,7 @@ #include #include #pragma clang diagnostic pop + // clang-format on #include @@ -134,12 +135,12 @@ class Arch { // Factory method for loading the correct architecture class for a given // operating system and architecture class. static auto Get(llvm::LLVMContext &context, std::string_view os, - std::string_view arch_name) -> ArchPtr; + std::string_view arch_name) -> ArchPtr; // Factory method for loading the correct architecture class for a given // operating system and architecture class. - static auto Get(llvm::LLVMContext &context, OSName os, - ArchName arch_name) -> ArchPtr; + static auto Get(llvm::LLVMContext &context, OSName os, ArchName arch_name) + -> ArchPtr; // Return the type of the state structure. llvm::StructType *StateStructType(void) const; @@ -279,9 +280,8 @@ class Arch { llvm::Triple BasicTriple(void) const; // Add a register into this - const Register *AddRegister(const char *reg_name, - llvm::Type *val_type, size_t offset, - const char *parent_reg_name) const; + const Register *AddRegister(const char *reg_name, llvm::Type *val_type, + size_t offset, const char *parent_reg_name) const; private: // Defined in `lib/Arch/X86/Arch.cpp`. @@ -297,12 +297,12 @@ class Arch { ArchName arch_name); // Defined in `lib/Arch/SPARC32/Arch.cpp`. - static ArchPtr GetSPARC( - llvm::LLVMContext *context, OSName os, ArchName arch_name); + static ArchPtr GetSPARC(llvm::LLVMContext *context, OSName os, + ArchName arch_name); // Defined in `lib/Arch/SPARC64/Arch.cpp`. - static ArchPtr GetSPARC64( - llvm::LLVMContext *context, OSName os, ArchName arch_name); + static ArchPtr GetSPARC64(llvm::LLVMContext *context, OSName os, + ArchName arch_name); mutable std::unique_ptr impl; diff --git a/include/remill/Arch/Instruction.h b/include/remill/Arch/Instruction.h index c34e9a512..f70ae0119 100644 --- a/include/remill/Arch/Instruction.h +++ b/include/remill/Arch/Instruction.h @@ -17,13 +17,13 @@ #pragma once #include -#include #include +#include namespace llvm { class Constant; class Type; -} // namespace llvm +} // namespace llvm namespace remill { @@ -33,17 +33,18 @@ class OperandExpression; enum ArchName : unsigned; -struct LLVMOpExpr{ +struct LLVMOpExpr { unsigned llvm_opcode; OperandExpression *op1; OperandExpression *op2; }; -class OperandExpression : public std::variant { +class OperandExpression : public std::variant { public: std::string Serialize(void) const; - llvm::Type * type {nullptr}; + llvm::Type *type{nullptr}; }; // Generic instruction operand. @@ -147,14 +148,13 @@ class Operand { } } addr; - OperandExpression * expr; + OperandExpression *expr; std::string Serialize(void) const; }; class Condition { public: - enum Kind { kTypeTrue, kTypeIsOne, @@ -290,7 +290,7 @@ class Instruction { inline bool IsFunctionReturn(void) const { return kCategoryFunctionReturn == category || - kCategoryConditionalFunctionReturn == category; + kCategoryConditionalFunctionReturn == category; } inline bool IsValid(void) const { @@ -313,18 +313,20 @@ class Instruction { } // This allocates an OperandExpression - OperandExpression * AllocateExpression(void); - OperandExpression * EmplaceRegister(const Register *); - OperandExpression * EmplaceRegister(std::string_view reg_name); - OperandExpression * EmplaceConstant(llvm::Constant *); - OperandExpression * EmplaceVariable(std::string_view, llvm::Type *); - OperandExpression * EmplaceBinaryOp(unsigned opcode, OperandExpression * op1, OperandExpression * op2); - OperandExpression * EmplaceUnaryOp(unsigned opcode, OperandExpression * op1, llvm::Type *); - - Operand & EmplaceOperand(const Operand::Register &op); - Operand & EmplaceOperand(const Operand::Immediate &op); - Operand & EmplaceOperand(const Operand::ShiftRegister &op); - Operand & EmplaceOperand(const Operand::Address &op); + OperandExpression *AllocateExpression(void); + OperandExpression *EmplaceRegister(const Register *); + OperandExpression *EmplaceRegister(std::string_view reg_name); + OperandExpression *EmplaceConstant(llvm::Constant *); + OperandExpression *EmplaceVariable(std::string_view, llvm::Type *); + OperandExpression *EmplaceBinaryOp(unsigned opcode, OperandExpression *op1, + OperandExpression *op2); + OperandExpression *EmplaceUnaryOp(unsigned opcode, OperandExpression *op1, + llvm::Type *); + + Operand &EmplaceOperand(const Operand::Register &op); + Operand &EmplaceOperand(const Operand::Immediate &op); + Operand &EmplaceOperand(const Operand::ShiftRegister &op); + Operand &EmplaceOperand(const Operand::Address &op); private: static constexpr auto kMaxNumExpr = 64u; diff --git a/include/remill/Arch/Name.h b/include/remill/Arch/Name.h index 0e919de4c..3df3ebe5e 100644 --- a/include/remill/Arch/Name.h +++ b/include/remill/Arch/Name.h @@ -17,49 +17,50 @@ #pragma once #ifndef REMILL_ARCH -# if defined(__x86_64__) -# define REMILL_ARCH "amd64_avx" -# define REMILL_ON_AMD64 1 -# define REMILL_ON_X86 0 -# define REMILL_ON_AARCH64 0 -# define REMILL_ON_SPARC64 0 -# define REMILL_ON_SPARC32 0 -# elif defined(__i386__) || defined(_M_X86) -# define REMILL_ARCH "x86" -# define REMILL_ON_AMD64 0 -# define REMILL_ON_X86 1 -# define REMILL_ON_AARCH64 0 -# define REMILL_ON_SPARC64 0 -# define REMILL_ON_SPARC32 0 -# elif defined(__aarch64__) -# define REMILL_ARCH "aarch64" -# define REMILL_ON_AMD64 0 -# define REMILL_ON_X86 0 -# define REMILL_ON_AARCH64 1 -# define REMILL_ON_SPARC64 0 -# define REMILL_ON_SPARC32 0 -# elif defined(__sparc__) || defined(__sparc) || defined(__sparc_v8__) || defined(__sparc_v9__) || defined(__sparcv8) || defined(__sparcv9) -# define REMILL_ON_AMD64 0 -# define REMILL_ON_X86 0 -# define REMILL_ON_AARCH64 0 -# if (defined(__LP64__) && __LP64__) || (defined(_LP64) && _LP64) -# define REMILL_ARCH "sparc64" -# define REMILL_ON_SPARC64 1 -# define REMILL_ON_SPARC32 0 -# else -# define REMILL_ARCH "sparc32" -# define REMILL_ON_SPARC64 0 -# define REMILL_ON_SPARC32 1 -# endif -# else -# error "Cannot infer current architecture." -# define REMILL_ARCH "invalid" -# define REMILL_ON_AMD64 0 -# define REMILL_ON_X86 0 -# define REMILL_ON_AARCH64 0 -# define REMILL_ON_SPARC64 0 -# define REMILL_ON_SPARC32 0 -# endif +# if defined(__x86_64__) +# define REMILL_ARCH "amd64_avx" +# define REMILL_ON_AMD64 1 +# define REMILL_ON_X86 0 +# define REMILL_ON_AARCH64 0 +# define REMILL_ON_SPARC64 0 +# define REMILL_ON_SPARC32 0 +# elif defined(__i386__) || defined(_M_X86) +# define REMILL_ARCH "x86" +# define REMILL_ON_AMD64 0 +# define REMILL_ON_X86 1 +# define REMILL_ON_AARCH64 0 +# define REMILL_ON_SPARC64 0 +# define REMILL_ON_SPARC32 0 +# elif defined(__aarch64__) +# define REMILL_ARCH "aarch64" +# define REMILL_ON_AMD64 0 +# define REMILL_ON_X86 0 +# define REMILL_ON_AARCH64 1 +# define REMILL_ON_SPARC64 0 +# define REMILL_ON_SPARC32 0 +# elif defined(__sparc__) || defined(__sparc) || defined(__sparc_v8__) || \ + defined(__sparc_v9__) || defined(__sparcv8) || defined(__sparcv9) +# define REMILL_ON_AMD64 0 +# define REMILL_ON_X86 0 +# define REMILL_ON_AARCH64 0 +# if (defined(__LP64__) && __LP64__) || (defined(_LP64) && _LP64) +# define REMILL_ARCH "sparc64" +# define REMILL_ON_SPARC64 1 +# define REMILL_ON_SPARC32 0 +# else +# define REMILL_ARCH "sparc32" +# define REMILL_ON_SPARC64 0 +# define REMILL_ON_SPARC32 1 +# endif +# else +# error "Cannot infer current architecture." +# define REMILL_ARCH "invalid" +# define REMILL_ON_AMD64 0 +# define REMILL_ON_X86 0 +# define REMILL_ON_AARCH64 0 +# define REMILL_ON_SPARC64 0 +# define REMILL_ON_SPARC32 0 +# endif #endif #include diff --git a/include/remill/Arch/Runtime/Definitions.h b/include/remill/Arch/Runtime/Definitions.h index d2d4d0dfc..3b183a31c 100644 --- a/include/remill/Arch/Runtime/Definitions.h +++ b/include/remill/Arch/Runtime/Definitions.h @@ -59,19 +59,23 @@ Memory *memory, State &state, ##__VA_ARGS__) template -inline static constexpr auto Specialize(R (*)(Args...), R (*b)(Args...)) -> R (*)(Args...) { +inline static constexpr auto Specialize(R (*)(Args...), R (*b)(Args...)) + -> R (*)(Args...) { return b; } // Define a semantics implementing function. #define DEF_COND_SEM(name, ...) \ - ALWAYS_INLINE __attribute__((flatten)) static Memory *name ##_impl( \ + ALWAYS_INLINE __attribute__((flatten)) static Memory *name##_impl( \ Memory *memory, State &state, ##__VA_ARGS__); \ - static Memory *name ##_spec( \ - Memory *memory, State &state, R8 __cond, R8W __branch_taken, ##__VA_ARGS__) { return nullptr; } \ - template \ - ALWAYS_INLINE __attribute__((flatten)) static Memory *name ##_wrapped( \ - Memory *memory, State &state, R8 __cond, R8W __branch_taken, Args... args) { \ + static Memory *name##_spec(Memory *memory, State &state, R8 __cond, \ + R8W __branch_taken, ##__VA_ARGS__) { \ + return nullptr; \ + } \ + template \ + ALWAYS_INLINE __attribute__((flatten)) static Memory *name##_wrapped( \ + Memory *memory, State &state, R8 __cond, R8W __branch_taken, \ + Args... args) { \ if (Read(__cond)) { \ Write(__branch_taken, true); \ return name##_impl(memory, state, args...); \ @@ -80,8 +84,8 @@ inline static constexpr auto Specialize(R (*)(Args...), R (*b)(Args...)) -> R (* return memory; \ } \ } \ - static constexpr auto name = Specialize(name ##_spec, name ##_wrapped); \ - ALWAYS_INLINE __attribute__((flatten)) static Memory *name ##_impl( \ + static constexpr auto name = Specialize(name##_spec, name##_wrapped); \ + ALWAYS_INLINE __attribute__((flatten)) static Memory *name##_impl( \ Memory *memory, State &state, ##__VA_ARGS__) // Define a semantics implementing function. diff --git a/include/remill/Arch/Runtime/HyperCall.h b/include/remill/Arch/Runtime/HyperCall.h index 3c926e893..e0970d0cc 100644 --- a/include/remill/Arch/Runtime/HyperCall.h +++ b/include/remill/Arch/Runtime/HyperCall.h @@ -90,7 +90,7 @@ class SyncHyperCall { kSPARCTrapCondVC, kSPARCTrapCondVS, }; -}__attribute__((packed)); +} __attribute__((packed)); class AsyncHyperCall { public: diff --git a/include/remill/Arch/Runtime/Operators.h b/include/remill/Arch/Runtime/Operators.h index 5dc4f3ec6..ba399bd49 100644 --- a/include/remill/Arch/Runtime/Operators.h +++ b/include/remill/Arch/Runtime/Operators.h @@ -1465,7 +1465,8 @@ ALWAYS_INLINE static Memory *__remill_write_memory_128(Memory *mem, addr_t addr, ALWAYS_INLINE static uint##size##_t name(uint##size##_t val) { \ const auto in_val = static_cast(val); \ return in_val ? (static_cast(builtin(in_val)) - \ - static_cast(disp)) : size; \ + static_cast(disp)) \ + : size; \ } MAKE_BUILTIN(CountLeadingZeros, 8, 32, __builtin_clz, 24) diff --git a/include/remill/Arch/Runtime/Types.h b/include/remill/Arch/Runtime/Types.h index 6d130096c..e5b5951a4 100644 --- a/include/remill/Arch/Runtime/Types.h +++ b/include/remill/Arch/Runtime/Types.h @@ -41,7 +41,8 @@ typedef uint64_t addr64_t; typedef IF_64BIT_ELSE(addr64_t, addr32_t) addr_t; typedef IF_64BIT_ELSE(int64_t, int32_t) addr_diff_t; -#if defined(__x86_64__) || defined(__i386__) || defined(_M_X86) || defined (__arm__) +#if defined(__x86_64__) || defined(__i386__) || defined(_M_X86) || \ + defined(__arm__) typedef unsigned uint128_t __attribute__((mode(TI))); typedef int int128_t __attribute__((mode(TI))); #elif defined(__aarch64__) diff --git a/include/remill/Arch/SPARC32/Runtime/State.h b/include/remill/Arch/SPARC32/Runtime/State.h index df9f5a066..ebccea28b 100644 --- a/include/remill/Arch/SPARC32/Runtime/State.h +++ b/include/remill/Arch/SPARC32/Runtime/State.h @@ -34,6 +34,7 @@ union PtrReg final { static_assert(sizeof(PtrReg) == 4); struct GPR { + // Prevents LLVM from casting a `GPR` into an `i64` to access `I0`. volatile addr_t _0; Reg i0; @@ -126,7 +127,8 @@ struct alignas(8) FPURegs final { vec128_t v[8]; } __attribute__((packed)); -static_assert(128 == sizeof(struct FPURegs), "Invalid packing of `struct FPURegs`."); +static_assert(128 == sizeof(struct FPURegs), + "Invalid packing of `struct FPURegs`."); struct FSRReg final { volatile uint8_t _0; @@ -153,9 +155,10 @@ struct FSRReg final { uint8_t fcc2; volatile uint8_t _11; uint8_t fcc3; -}__attribute__((packed)); +} __attribute__((packed)); -static_assert(24 == sizeof(struct FSRReg), "Invalid packing of `struct FSRReg`."); +static_assert(24 == sizeof(struct FSRReg), + "Invalid packing of `struct FSRReg`."); // Integer condition code register flags struct ICCRFlags final { @@ -174,52 +177,52 @@ struct ICCRFlags final { union GSRFlags final { uint64_t flat; struct { - uint64_t align:3; - uint64_t scale:5; - uint64_t reserved_0:17; - uint64_t irnd:2; - uint64_t im:1; - uint64_t reserved_1:4; - uint64_t mask:32; + uint64_t align : 3; + uint64_t scale : 5; + uint64_t reserved_0 : 17; + uint64_t irnd : 2; + uint64_t im : 1; + uint64_t reserved_1 : 4; + uint64_t mask : 32; } __attribute__((packed)); } __attribute__((packed)); struct ASR final { - Reg yreg; // ASR 0 + Reg yreg; // ASR 0 volatile uint32_t _0; - ICCRFlags ccr; // ASR 2 + ICCRFlags ccr; // ASR 2 volatile addr_t _1; union { uint32_t asi_flat; struct { - uint32_t asi:8; // ASR 3 - uint32_t padding_1:24; + uint32_t asi : 8; // ASR 3 + uint32_t padding_1 : 24; } __attribute__((packed)); } __attribute__((packed)); volatile uint64_t _2; - uint64_t tick; // ASR 4 + uint64_t tick; // ASR 4 volatile uint64_t _3; union { uint32_t fprs_flat; struct { - uint32_t fprs:3; // ASR 6 - uint32_t padding_2:29; + uint32_t fprs : 3; // ASR 6 + uint32_t padding_2 : 29; } __attribute__((packed)); } __attribute__((packed)); volatile uint32_t _4; GSRFlags gsr; volatile uint64_t _5; - addr64_t softint; // ASR 20 + addr64_t softint; // ASR 20 volatile uint64_t _6; - addr64_t stick; // ASR 24 + addr64_t stick; // ASR 24 volatile uint64_t _7; - addr64_t stick_cmpr; // ASR 25 + addr64_t stick_cmpr; // ASR 25 volatile uint64_t _8; - addr64_t cfr; // ASR 26 + addr64_t cfr; // ASR 26 volatile uint64_t _9; - addr64_t pause; // ASR 27 + addr64_t pause; // ASR 27 volatile uint64_t _10; - addr64_t mwait; // ASR 28 + addr64_t mwait; // ASR 28 } __attribute__((packed)); struct CSR { @@ -232,47 +235,47 @@ struct CSR { static_assert(8 == sizeof(struct CSR), "Invalid packing of `struct CSR`."); struct PSR { - uint64_t tpc; - uint64_t tnpc; - uint64_t tstate; - uint64_t tick; - uint64_t tba; - volatile uint8_t _0; //padding - uint8_t tt; - uint8_t tl; + uint64_t tpc; + uint64_t tnpc; + uint64_t tstate; + uint64_t tick; + uint64_t tba; + volatile uint8_t _0; //padding + uint8_t tt; + uint8_t tl; union { - uint16_t pstate; + uint16_t pstate; struct { - uint16_t res1:1; - uint16_t ie:1; - uint16_t priv:1; - uint16_t am:1; - uint16_t pef:1; - uint16_t res2:1; - uint16_t mm:1; - uint16_t tle:1; - uint16_t cle:1; - uint16_t res3:1; - uint16_t res4:1; - uint16_t tct:1; - uint16_t padding:4; + uint16_t res1 : 1; + uint16_t ie : 1; + uint16_t priv : 1; + uint16_t am : 1; + uint16_t pef : 1; + uint16_t res2 : 1; + uint16_t mm : 1; + uint16_t tle : 1; + uint16_t cle : 1; + uint16_t res3 : 1; + uint16_t res4 : 1; + uint16_t tct : 1; + uint16_t padding : 4; } __attribute__((packed)) ps; } __attribute__((packed)); volatile uint8_t _1; - uint8_t pil; - uint8_t cwp; - uint8_t cansave; + uint8_t pil; + uint8_t cwp; + uint8_t cansave; volatile uint8_t _2; - uint8_t canrestore; - uint8_t cleanwin; - uint8_t otherwin; + uint8_t canrestore; + uint8_t cleanwin; + uint8_t otherwin; volatile uint8_t _3; union { - uint8_t wstate; + uint8_t wstate; struct { - uint8_t normal:2; - uint8_t other:3; - uint8_t padding:3; + uint8_t normal : 2; + uint8_t other : 3; + uint8_t padding : 3; } __attribute__((packed)) ws; } __attribute__((packed)); uint8_t gl; @@ -319,19 +322,19 @@ struct RegisterWindow { struct alignas(16) State : public ArchState { FPURegs fpreg; // 512 bytes volatile uint64_t _0; - GPR gpr; // 256 bytes + GPR gpr; // 256 bytes volatile uint64_t _1; - ASR asr; // 176 bytes + ASR asr; // 176 bytes volatile uint64_t _2; - PSR psr; // 56 bytes + PSR psr; // 56 bytes volatile uint64_t _3; - FSRReg fsr; // 24 bytes + FSRReg fsr; // 24 bytes volatile uint64_t _4; - CSR csr; // 8 bytes + CSR csr; // 8 bytes volatile uint32_t _5; - Reg pc; // 4 bytes + Reg pc; // 4 bytes volatile uint32_t _6; - Reg next_pc; // 4 bytes + Reg next_pc; // 4 bytes volatile uint32_t _7; // NOTE(pag): This *must* go at the end, as if we change the target arch/data @@ -341,7 +344,8 @@ struct alignas(16) State : public ArchState { uint32_t window; #else RegisterWindow *window; // smuggled. - static_assert(sizeof(RegisterWindow *) == 4, "Invalid size of `RegisterWindow`"); + static_assert(sizeof(RegisterWindow *) == 4, + "Invalid size of `RegisterWindow`"); #endif }; diff --git a/include/remill/Arch/SPARC64/Runtime/State.h b/include/remill/Arch/SPARC64/Runtime/State.h index 9ef957e57..ea36af7d1 100644 --- a/include/remill/Arch/SPARC64/Runtime/State.h +++ b/include/remill/Arch/SPARC64/Runtime/State.h @@ -26,17 +26,16 @@ struct Reg final { addr_t qword; } __attribute__((packed)); -static_assert(sizeof(Reg) == 8, - "Invalid size of `Reg`."); +static_assert(sizeof(Reg) == 8, "Invalid size of `Reg`."); union PtrReg final { addr_t qword; } __attribute__((packed)); -static_assert(sizeof(PtrReg) == 8, - "Invalid size of `PtrReg`."); +static_assert(sizeof(PtrReg) == 8, "Invalid size of `PtrReg`."); struct GPR { + // Prevents LLVM from casting a `GPR` into an `i64` to access `I0`. volatile addr_t _0; Reg i0; @@ -107,8 +106,7 @@ struct GPR { Reg g7; }; -static_assert(512 == sizeof(GPR), - "Invalid packing of `struct GPR`."); +static_assert(512 == sizeof(GPR), "Invalid packing of `struct GPR`."); enum AlternativeSpaceIdentifier : uint32_t { ASI_PST8_PRIMARY = 0xc0, @@ -132,7 +130,8 @@ struct FPURegs final { vec128_t v[16]; } __attribute__((packed)); -static_assert(((128 * 16) / 8) == sizeof(struct FPURegs), "Invalid packing of `struct FPURegs`."); +static_assert(((128 * 16) / 8) == sizeof(struct FPURegs), + "Invalid packing of `struct FPURegs`."); struct FSRReg final { volatile uint8_t _0; @@ -159,9 +158,10 @@ struct FSRReg final { uint8_t fcc2; volatile uint8_t _11; uint8_t fcc3; -}__attribute__((packed)); +} __attribute__((packed)); -static_assert(24 == sizeof(struct FSRReg), "Invalid packing of `struct FSRReg`."); +static_assert(24 == sizeof(struct FSRReg), + "Invalid packing of `struct FSRReg`."); // Integer condition code register flags struct ICCRFlags final { @@ -177,57 +177,58 @@ struct ICCRFlags final { } __attribute__((packed)) icc, xcc; } __attribute__((packed)); -static_assert(16 == sizeof(struct ICCRFlags), "Invalid packing of `struct ICCRFlags`."); +static_assert(16 == sizeof(struct ICCRFlags), + "Invalid packing of `struct ICCRFlags`."); union GSRFlags final { uint64_t flat; struct { - uint64_t align:3; - uint64_t scale:5; - uint64_t reserved_0:17; - uint64_t irnd:2; - uint64_t im:1; - uint64_t reserved_1:4; - uint64_t mask:32; + uint64_t align : 3; + uint64_t scale : 5; + uint64_t reserved_0 : 17; + uint64_t irnd : 2; + uint64_t im : 1; + uint64_t reserved_1 : 4; + uint64_t mask : 32; } __attribute__((packed)); } __attribute__((packed)); struct ASR final { - Reg yreg; // ASR 0 + Reg yreg; // ASR 0 volatile uint64_t _0; - ICCRFlags ccr; // ASR 2 + ICCRFlags ccr; // ASR 2 volatile uint64_t _1; union { uint64_t asi_flat; struct { - uint64_t asi:8; // ASR 3 - uint64_t padding_1:56; + uint64_t asi : 8; // ASR 3 + uint64_t padding_1 : 56; } __attribute__((packed)); } __attribute__((packed)); volatile uint64_t _2; - uint64_t tick; // ASR 4 + uint64_t tick; // ASR 4 volatile uint64_t _3; union { uint64_t fprs_flat; struct { - uint64_t fprs:3; // ASR 6 - uint64_t padding_2:61; + uint64_t fprs : 3; // ASR 6 + uint64_t padding_2 : 61; } __attribute__((packed)); } __attribute__((packed)); volatile uint64_t _4; GSRFlags gsr; volatile uint64_t _5; - uint64_t softint; // ASR 20 + uint64_t softint; // ASR 20 volatile uint64_t _6; - uint64_t stick; // ASR 24 + uint64_t stick; // ASR 24 volatile uint64_t _7; - uint64_t stick_cmpr; // ASR 25 + uint64_t stick_cmpr; // ASR 25 volatile uint64_t _8; - uint64_t cfr; // ASR 26 + uint64_t cfr; // ASR 26 volatile uint64_t _9; - uint64_t pause; // ASR 27 + uint64_t pause; // ASR 27 volatile uint64_t _10; - uint64_t mwait; // ASR 28 + uint64_t mwait; // ASR 28 }; static_assert(192 == sizeof(struct ASR), "Invalid packing of `struct ASR`."); @@ -242,50 +243,50 @@ struct CSR { static_assert(8 == sizeof(struct CSR), "Invalid packing of `struct CSR`."); struct PSR { - uint64_t tpc; - uint64_t tnpc; - uint64_t tstate; - uint64_t tick; - uint64_t tba; - volatile uint8_t _0; //padding - uint8_t tt; - uint8_t tl; + uint64_t tpc; + uint64_t tnpc; + uint64_t tstate; + uint64_t tick; + uint64_t tba; + volatile uint8_t _0; //padding + uint8_t tt; + uint8_t tl; union { - uint16_t pstate; + uint16_t pstate; struct { - uint16_t res1:1; - uint16_t ie:1; - uint16_t priv:1; - uint16_t am:1; - uint16_t pef:1; - uint16_t res2:1; - uint16_t mm:1; - uint16_t tle:1; - uint16_t cle:1; - uint16_t res3:1; - uint16_t res4:1; - uint16_t tct:1; - uint16_t padding:4; + uint16_t res1 : 1; + uint16_t ie : 1; + uint16_t priv : 1; + uint16_t am : 1; + uint16_t pef : 1; + uint16_t res2 : 1; + uint16_t mm : 1; + uint16_t tle : 1; + uint16_t cle : 1; + uint16_t res3 : 1; + uint16_t res4 : 1; + uint16_t tct : 1; + uint16_t padding : 4; } __attribute__((packed)) ps; } __attribute__((packed)); volatile uint8_t _1; - uint8_t pil; - uint8_t cwp; - uint8_t cansave; + uint8_t pil; + uint8_t cwp; + uint8_t cansave; volatile uint8_t _2; - uint8_t canrestore; - uint8_t cleanwin; - uint8_t otherwin; + uint8_t canrestore; + uint8_t cleanwin; + uint8_t otherwin; volatile uint8_t _3; union { - uint8_t wstate; + uint8_t wstate; struct { - uint8_t normal:2; - uint8_t other:3; - uint8_t padding:3; + uint8_t normal : 2; + uint8_t other : 3; + uint8_t padding : 3; } __attribute__((packed)) ws; } __attribute__((packed)); - uint8_t gl; + uint8_t gl; } __attribute__((packed)); struct RegisterWindow { @@ -330,19 +331,19 @@ struct RegisterWindow { struct alignas(16) State : public ArchState { FPURegs fpreg; // 512 bytes volatile uint64_t _0; - GPR gpr; // 512 bytes + GPR gpr; // 512 bytes volatile uint64_t _1; - ASR asr; // 176 bytes + ASR asr; // 176 bytes volatile uint64_t _2; - PSR psr; // 56 bytes + PSR psr; // 56 bytes volatile uint64_t _3; - FSRReg fsr; // 24 bytes + FSRReg fsr; // 24 bytes volatile uint64_t _4; - CSR csr; // 8 bytes + CSR csr; // 8 bytes volatile uint64_t _5; - Reg pc; // 8 bytes + Reg pc; // 8 bytes volatile uint64_t _6; - Reg next_pc; // 8 bytes + Reg next_pc; // 8 bytes volatile uint64_t _7; // NOTE(pag): This *must* go at the end, as if we change the target arch/data @@ -352,7 +353,8 @@ struct alignas(16) State : public ArchState { uint64_t window; #else RegisterWindow *window; // smuggled. - static_assert(sizeof(RegisterWindow *) == 8, "Invalid size of `RegisterWindow`"); + static_assert(sizeof(RegisterWindow *) == 8, + "Invalid size of `RegisterWindow`"); #endif }; diff --git a/include/remill/BC/Compat/CTypes.h b/include/remill/BC/Compat/CTypes.h index 47c23b094..d497ad387 100644 --- a/include/remill/BC/Compat/CTypes.h +++ b/include/remill/BC/Compat/CTypes.h @@ -17,9 +17,10 @@ #pragma once #if __has_include() -#include +# include namespace llvm { + // TODO(pag): This is a rather ugly hack; had some issues with anvill not // compiling on macOS due to these C types. struct LLVMOpaqueNamedMDNode; diff --git a/include/remill/BC/Compat/CallSite.h b/include/remill/BC/Compat/CallSite.h index d8a7b2324..d47e3b03c 100644 --- a/include/remill/BC/Compat/CallSite.h +++ b/include/remill/BC/Compat/CallSite.h @@ -15,10 +15,10 @@ */ #pragma once -#include "remill/BC/Version.h" - #include +#include "remill/BC/Version.h" + /* In llvm-11 llvm::CallSite got partially replace by llvm::AbstractCallSite * for read-only operations and llvm::CallBase was made public (was considered @@ -29,76 +29,74 @@ #if LLVM_VERSION_NUMBER < LLVM_VERSION(11, 0) -#include +# include namespace remill::compat::llvm { - struct CallSite : private ::llvm::CallSite { - using parent = ::llvm::CallSite; +struct CallSite : private ::llvm::CallSite { + using parent = ::llvm::CallSite; - /* List of "allowed" methods (thanks to private inheritance) + /* List of "allowed" methods (thanks to private inheritance) * that prevent user from accidentally using functionality that * would break other llvm version. * If you want to add method here, make sure other versions have it * as well. */ - using parent::parent; - using parent::isInvoke; - using parent::isCall; - using parent::operator bool; - using parent::getCalledValue; - using parent::getCalledFunction; - using parent::setCalledFunction; - }; + using parent::isCall; + using parent::isInvoke; + using parent::parent; + using parent::operator bool; + using parent::getCalledFunction; + using parent::getCalledValue; + using parent::setCalledFunction; +}; -} // namespace remill::compat::llvm +} // namespace remill::compat::llvm #else -#include +# include namespace remill::compat::llvm { - struct CallSite { - ::llvm::CallBase *cb; +struct CallSite { + ::llvm::CallBase *cb; - CallSite(::llvm::Instruction *inst) - : cb(::llvm::dyn_cast<::llvm::CallBase>(inst)) - {} + CallSite(::llvm::Instruction *inst) + : cb(::llvm::dyn_cast<::llvm::CallBase>(inst)) {} - CallSite(::llvm::User *user) - : CallSite(::llvm::dyn_cast<::llvm::Instruction>(user)) - {} + CallSite(::llvm::User *user) + : CallSite(::llvm::dyn_cast<::llvm::Instruction>(user)) {} - bool isInvoke() const { - return ::llvm::isa<::llvm::InvokeInst>(cb); - } + bool isInvoke() const { + return ::llvm::isa<::llvm::InvokeInst>(cb); + } - bool isCall() const { - return ::llvm::isa<::llvm::CallInst>(cb); - } + bool isCall() const { + return ::llvm::isa<::llvm::CallInst>(cb); + } - ::llvm::Value *getCalledValue() { - if (!static_cast(*this)) { - return nullptr; - } - return cb->getCalledOperand(); + ::llvm::Value *getCalledValue() { + if (!static_cast(*this)) { + return nullptr; } + return cb->getCalledOperand(); + } - ::llvm::Function *getCalledFunction() { - if ( !*this) { - return nullptr; - } - return cb->getCalledFunction(); + ::llvm::Function *getCalledFunction() { + if (!*this) { + return nullptr; } + return cb->getCalledFunction(); + } - void setCalledFunction(::llvm::Function *fn) { - return cb->setCalledFunction(fn); - } + void setCalledFunction(::llvm::Function *fn) { + return cb->setCalledFunction(fn); + } - operator bool() const { - return cb; - } - }; + operator bool() const { + return cb; + } +}; -} // namespace remill::compat::llvm +} // namespace remill::compat::llvm #endif diff --git a/include/remill/BC/InstructionLifter.h b/include/remill/BC/InstructionLifter.h index f9ffa569c..2e670f7ba 100644 --- a/include/remill/BC/InstructionLifter.h +++ b/include/remill/BC/InstructionLifter.h @@ -103,28 +103,27 @@ class InstructionLifter { Operand ®); // Lift a register operand to a value. - virtual llvm::Value * LiftRegisterOperand(Instruction &inst, + virtual llvm::Value *LiftRegisterOperand(Instruction &inst, llvm::BasicBlock *block, llvm::Value *state_ptr, llvm::Argument *arg, Operand ®); // Lift an immediate operand. - virtual llvm::Value * LiftImmediateOperand(Instruction &inst, + virtual llvm::Value *LiftImmediateOperand(Instruction &inst, llvm::BasicBlock *block, llvm::Argument *arg, Operand &op); // Lift an expression operand. - virtual llvm::Value * LiftExpressionOperand(Instruction &inst, + virtual llvm::Value *LiftExpressionOperand(Instruction &inst, llvm::BasicBlock *block, llvm::Value *state_ptr, llvm::Argument *arg, Operand &op); // Lift an expression operand. - virtual llvm::Value* LiftExpressionOperandRec(Instruction &inst, - llvm::BasicBlock *block, - llvm::Value *state_ptr, - llvm::Argument *arg, - const OperandExpression *op); + virtual llvm::Value * + LiftExpressionOperandRec(Instruction &inst, llvm::BasicBlock *block, + llvm::Value *state_ptr, llvm::Argument *arg, + const OperandExpression *op); // Lift an indirect memory operand to a value. virtual llvm::Value * diff --git a/include/remill/BC/TraceLifter.h b/include/remill/BC/TraceLifter.h index 3d2d8710c..2dd0c6b31 100644 --- a/include/remill/BC/TraceLifter.h +++ b/include/remill/BC/TraceLifter.h @@ -16,11 +16,11 @@ #pragma once +#include + #include #include -#include - namespace remill { using TraceMap = std::unordered_map; diff --git a/include/remill/BC/Util.h b/include/remill/BC/Util.h index 2127da727..8de55b958 100644 --- a/include/remill/BC/Util.h +++ b/include/remill/BC/Util.h @@ -28,6 +28,7 @@ #include #include #pragma clang diagnostic pop + // clang-format on #include @@ -134,8 +135,7 @@ llvm::Value *LoadBranchTakenRef(llvm::BasicBlock *block); llvm::Function *FindFunction(llvm::Module *M, std::string_view name); // Find a global variable with name `name` in the module `M`. -llvm::GlobalVariable *FindGlobaVariable(llvm::Module *M, - std::string_view name); +llvm::GlobalVariable *FindGlobaVariable(llvm::Module *M, std::string_view name); // Try to verify a module. bool VerifyModule(llvm::Module *module); diff --git a/lib/Arch/AArch32/Arch.cpp b/lib/Arch/AArch32/Arch.cpp index 92da9a332..2b290a930 100644 --- a/lib/Arch/AArch32/Arch.cpp +++ b/lib/Arch/AArch32/Arch.cpp @@ -46,7 +46,7 @@ namespace remill { AArch32Arch::AArch32Arch(llvm::LLVMContext *context_, OSName os_name_, - ArchName arch_name_) + ArchName arch_name_) : Arch(context_, os_name_, arch_name_) {} AArch32Arch::~AArch32Arch(void) {} @@ -105,7 +105,7 @@ std::string_view AArch32Arch::ProgramCounterRegisterName(void) const { // Populate the `__remill_basic_block` function with variables. void AArch32Arch::PopulateBasicBlockFunction(llvm::Module *module, - llvm::Function *bb_func) const { + llvm::Function *bb_func) const { const auto &dl = module->getDataLayout(); CHECK_EQ(sizeof(State), dl.getTypeAllocSize(StateStructType())) << "Mismatch between size of State type for x86/amd64 and what is in " @@ -113,14 +113,17 @@ void AArch32Arch::PopulateBasicBlockFunction(llvm::Module *module, auto &context = module->getContext(); auto u8 = llvm::Type::getInt8Ty(context); -// auto u16 = llvm::Type::getInt16Ty(context); + + // auto u16 = llvm::Type::getInt16Ty(context); auto u32 = llvm::Type::getInt32Ty(context); -// auto u64 = llvm::Type::getInt64Ty(context); -// auto f64 = llvm::Type::getDoubleTy(context); -// auto v128 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 128u / 8u); -// auto v256 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 256u / 8u); -// auto v512 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 512u / 8u); + + // auto u64 = llvm::Type::getInt64Ty(context); + // auto f64 = llvm::Type::getDoubleTy(context); + // auto v128 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 128u / 8u); + // auto v256 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 256u / 8u); + // auto v512 = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), 512u / 8u); auto addr = llvm::Type::getIntNTy(context, address_size); + //auto zero_addr_val = llvm::Constant::getNullValue(addr); const auto entry_block = &bb_func->getEntryBlock(); @@ -174,7 +177,7 @@ void AArch32Arch::PopulateBasicBlockFunction(llvm::Module *module, // TODO(pag): We pretend that these are singletons, but they aren't really! Arch::ArchPtr Arch::GetAArch32(llvm::LLVMContext *context_, OSName os_name_, - ArchName arch_name_) { + ArchName arch_name_) { return std::make_unique(context_, os_name_, arch_name_); } diff --git a/lib/Arch/AArch32/Arch.h b/lib/Arch/AArch32/Arch.h index 0f7124aff..291c94577 100644 --- a/lib/Arch/AArch32/Arch.h +++ b/lib/Arch/AArch32/Arch.h @@ -21,7 +21,8 @@ namespace remill { class AArch32Arch final : public Arch { public: - AArch32Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_); + AArch32Arch(llvm::LLVMContext *context_, OSName os_name_, + ArchName arch_name_); virtual ~AArch32Arch(void); @@ -52,4 +53,4 @@ class AArch32Arch final : public Arch { AArch32Arch(void) = delete; }; -} // namespace remill +} // namespace remill diff --git a/lib/Arch/AArch32/Decode.cpp b/lib/Arch/AArch32/Decode.cpp index bff499ad8..19ca9de6f 100644 --- a/lib/Arch/AArch32/Decode.cpp +++ b/lib/Arch/AArch32/Decode.cpp @@ -14,11 +14,11 @@ * limitations under the License. */ +#include + #include "Arch.h" #include "remill/BC/ABI.h" -#include - namespace remill { namespace { @@ -80,7 +80,7 @@ union MultiplyAndAccumulate { uint32_t flat; struct { uint32_t rn : 4; - uint32_t _1001 : 4; + uint32_t _1001 : 4; uint32_t rm : 4; uint32_t rdlo : 4; uint32_t rdhi : 4; @@ -98,9 +98,9 @@ union HMultiplyAndAccumulate { struct { uint32_t rn : 4; uint32_t _0_b4 : 1; - uint32_t N : 1; - uint32_t M : 1; - uint32_t _1 : 1; + uint32_t N : 1; + uint32_t M : 1; + uint32_t _1 : 1; uint32_t rm : 4; uint32_t ra : 4; uint32_t rd : 4; @@ -118,7 +118,7 @@ union SignedMulDiv { struct { uint32_t rn : 4; uint32_t _1 : 1; - uint32_t op2 : 3; + uint32_t op2 : 3; uint32_t rm : 4; uint32_t ra : 4; uint32_t rd : 4; @@ -136,7 +136,7 @@ union LoadStoreWUBIL { struct { uint32_t imm12 : 12; uint32_t rt : 4; - uint32_t rn : 4; + uint32_t rn : 4; uint32_t o1 : 1; uint32_t W : 1; uint32_t o2 : 1; @@ -152,12 +152,12 @@ static_assert(sizeof(LoadStoreWUBIL) == 4, " "); union LoadStoreWUBR { uint32_t flat; struct { - uint32_t rm : 4; + uint32_t rm : 4; uint32_t _0 : 1; uint32_t type : 2; uint32_t imm5 : 5; uint32_t rt : 4; - uint32_t rn : 4; + uint32_t rn : 4; uint32_t o1 : 1; uint32_t W : 1; uint32_t o2 : 1; @@ -179,7 +179,7 @@ union LoadStoreDualHSBIL { uint32_t _1_b7 : 1; uint32_t imm4H : 4; uint32_t rt : 4; - uint32_t rn : 4; + uint32_t rn : 4; uint32_t o1 : 1; uint32_t W : 1; uint32_t _1_b22 : 1; @@ -201,7 +201,7 @@ union LoadStoreDualHSBR { uint32_t _1_b7 : 1; uint32_t _0000 : 4; uint32_t rt : 4; - uint32_t rn : 4; + uint32_t rn : 4; uint32_t o1 : 1; uint32_t W : 1; uint32_t _0 : 1; @@ -218,7 +218,7 @@ union LoadStoreM { uint32_t flat; struct { uint32_t register_list : 16; - uint32_t rn : 4; + uint32_t rn : 4; uint32_t L : 1; uint32_t W : 1; uint32_t op : 1; @@ -240,7 +240,7 @@ union IntTestCompRRI { uint32_t type : 2; uint32_t imm5 : 5; uint32_t _0000 : 4; - uint32_t rn : 4; + uint32_t rn : 4; uint32_t _1 : 1; uint32_t opc : 2; uint32_t _00010 : 5; @@ -259,7 +259,7 @@ union IntTestCompRRR { uint32_t _0 : 1; uint32_t rs : 4; uint32_t _0000 : 4; - uint32_t rn : 4; + uint32_t rn : 4; uint32_t _1_b20 : 1; uint32_t opc : 2; uint32_t _00010 : 5; @@ -274,7 +274,7 @@ union IntTestCompRI { struct { uint32_t imm12 : 12; uint32_t _0000 : 4; - uint32_t rn : 4; + uint32_t rn : 4; uint32_t _1 : 1; uint32_t opc : 2; uint32_t _00110 : 5; @@ -287,12 +287,12 @@ static_assert(sizeof(IntTestCompRI) == 4, " "); union LogicalArithRRRI { uint32_t flat; struct { - uint32_t rm : 4; + uint32_t rm : 4; uint32_t _0 : 1; uint32_t type : 2; uint32_t imm5 : 5; uint32_t rd : 4; - uint32_t rn : 4; + uint32_t rn : 4; uint32_t s : 1; uint32_t opc : 2; uint32_t _00011 : 5; @@ -305,13 +305,13 @@ static_assert(sizeof(LogicalArithRRRI) == 4, " "); union LogicalArithRRRR { uint32_t flat; struct { - uint32_t rm : 4; + uint32_t rm : 4; uint32_t _1 : 1; uint32_t type : 2; uint32_t _0 : 1; uint32_t rs : 4; uint32_t rd : 4; - uint32_t rn : 4; + uint32_t rn : 4; uint32_t s : 1; uint32_t opc : 2; uint32_t _00011 : 5; @@ -322,30 +322,30 @@ static_assert(sizeof(LogicalArithRRRR) == 4, " "); union LogicalArithmeticRRI { uint32_t flat; - struct { - uint32_t imm12 : 12; - uint32_t rd : 4; - uint32_t rn : 4; - uint32_t s : 1; - uint32_t opc : 2; - uint32_t _00111 : 5; - uint32_t cond : 4; - } __attribute__((packed)); + struct { + uint32_t imm12 : 12; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t s : 1; + uint32_t opc : 2; + uint32_t _00111 : 5; + uint32_t cond : 4; } __attribute__((packed)); +} __attribute__((packed)); static_assert(sizeof(LogicalArithmeticRRI) == 4, " "); union MoveHW { uint32_t flat; - struct { - uint32_t imm12 : 12; - uint32_t rd : 4; - uint32_t imm4 : 4; - uint32_t _00 : 2; - uint32_t H : 1; - uint32_t _00110 : 5; - uint32_t cond : 4; - } __attribute__((packed)); + struct { + uint32_t imm12 : 12; + uint32_t rd : 4; + uint32_t imm4 : 4; + uint32_t _00 : 2; + uint32_t H : 1; + uint32_t _00110 : 5; + uint32_t cond : 4; } __attribute__((packed)); +} __attribute__((packed)); static_assert(sizeof(MoveHW) == 4, " "); @@ -403,7 +403,7 @@ union Misc { uint32_t _19_to_16 : 4; uint32_t _0_b20 : 1; uint32_t op0 : 2; - uint32_t _00010: 5; + uint32_t _00010 : 5; uint32_t cond : 4; } __attribute__((packed)); } __attribute__((packed)); @@ -414,11 +414,11 @@ union Media { uint32_t flat; struct { uint32_t _3_to_0 : 4; - uint32_t _1: 1; + uint32_t _1 : 1; uint32_t op1 : 3; uint32_t _19_to_8 : 12; uint32_t op0 : 5; - uint32_t _011: 3; + uint32_t _011 : 3; uint32_t cond : 4; } __attribute__((packed)); } __attribute__((packed)); @@ -434,7 +434,7 @@ union IntSatArith { uint32_t Rn : 4; uint32_t _0_b20 : 1; uint32_t opc : 2; - uint32_t _00010: 5; + uint32_t _00010 : 5; uint32_t cond : 4; } __attribute__((packed)); } __attribute__((packed)); @@ -451,7 +451,7 @@ union Sat16 { uint32_t sat_imm : 4; uint32_t _10 : 2; uint32_t U : 1; - uint32_t _01101: 5; + uint32_t _01101 : 5; uint32_t cond : 4; } __attribute__((packed)); } __attribute__((packed)); @@ -469,7 +469,7 @@ union Sat32 { uint32_t sat_imm : 5; uint32_t _1 : 1; uint32_t U : 1; - uint32_t _01101: 5; + uint32_t _01101 : 5; uint32_t cond : 4; } __attribute__((packed)); } __attribute__((packed)); @@ -486,7 +486,7 @@ union ExtAdd { uint32_t Rn : 4; uint32_t op : 2; uint32_t U : 1; - uint32_t _01101: 5; + uint32_t _01101 : 5; uint32_t cond : 4; } __attribute__((packed)); } __attribute__((packed)); @@ -503,7 +503,7 @@ union BitExt { uint32_t widthm1 : 5; uint32_t _1 : 1; uint32_t U : 1; - uint32_t _01111: 5; + uint32_t _01111 : 5; uint32_t cond : 4; } __attribute__((packed)); } __attribute__((packed)); @@ -518,7 +518,7 @@ union SpecialRegsAndHints { uint32_t imm4 : 4; uint32_t _10 : 2; uint32_t R : 1; - uint32_t _00110: 5; + uint32_t _00110 : 5; uint32_t cond : 4; } __attribute__((packed)); } __attribute__((packed)); @@ -528,27 +528,12 @@ static_assert(sizeof(SpecialRegsAndHints) == 4, " "); static constexpr auto kPCRegNum = 15u; static constexpr auto kLRRegNum = 14u; -static const char * const kIntRegName[] = { - "R0", - "R1", - "R2", - "R3", - "R4", - "R5", - "R6", - "R7", - "R8", - "R9", - "R10", - "R11", - "R12", - "R13", - "R14", - "R15" -}; +static const char *const kIntRegName[] = { + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", + "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"}; -typedef bool (TryDecode)(Instruction&, uint32_t); -typedef std::optional (InstEval)(uint32_t, uint32_t); +typedef bool(TryDecode)(Instruction &, uint32_t); +typedef std::optional(InstEval)(uint32_t, uint32_t); static void AddIntRegOp(Instruction &inst, unsigned index, unsigned size, Operand::Action action) { @@ -569,8 +554,8 @@ static void AddIntRegOp(Instruction &inst, const char *reg_name, unsigned size, } static void AddExprOp(Instruction &inst, OperandExpression *op_expr, - uint64_t size = 32, Operand::Action action = - Operand::kActionRead) { + uint64_t size = 32, + Operand::Action action = Operand::kActionRead) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.expr = op_expr; @@ -603,10 +588,9 @@ static void AddAddrRegOp(Instruction &inst, const char *reg_name, op.action = mem_action; } -static void AddShiftOp(Instruction &inst, - Operand::ShiftRegister::Shift shift_op, - const char *reg_name, unsigned reg_size, - unsigned shift_size) { +static void +AddShiftOp(Instruction &inst, Operand::ShiftRegister::Shift shift_op, + const char *reg_name, unsigned reg_size, unsigned shift_size) { Operand::ShiftRegister shift_reg; shift_reg.reg.name = reg_name; shift_reg.reg.size = reg_size; @@ -631,7 +615,6 @@ static void AddShiftThenExtractOp(Instruction &inst, shift_reg.shift_first = true; auto &op = inst.EmplaceOperand(shift_reg); op.action = Operand::kActionRead; - } //static void AddExtractThenShiftOp(Instruction &inst, @@ -659,31 +642,27 @@ enum Shift : uint32_t { kShiftLSL, kShiftLSR, kShiftASR, kShiftROR }; // register class. static Operand::ShiftRegister::Shift GetOperandShift(Shift s) { switch (s) { - case kShiftLSL: - return Operand::ShiftRegister::kShiftLeftWithZeroes; - case kShiftLSR: - return Operand::ShiftRegister::kShiftUnsignedRight; - case kShiftASR: - return Operand::ShiftRegister::kShiftSignedRight; - case kShiftROR: - return Operand::ShiftRegister::kShiftRightAround; + case kShiftLSL: return Operand::ShiftRegister::kShiftLeftWithZeroes; + case kShiftLSR: return Operand::ShiftRegister::kShiftUnsignedRight; + case kShiftASR: return Operand::ShiftRegister::kShiftSignedRight; + case kShiftROR: return Operand::ShiftRegister::kShiftRightAround; } return Operand::ShiftRegister::kShiftInvalid; } // Do an extraction and zero extension on an expression -template -static OperandExpression * ExtractAndExtExpr(Instruction &inst, OperandExpression * op_expr, - unsigned int extract_size, - unsigned int extend_size) { - auto extract_type = llvm::Type::getIntNTy(*(inst.arch->context), - extract_size); - auto extend_type = llvm::Type::getIntNTy(*(inst.arch->context), - extend_size); +template +static OperandExpression * +ExtractAndExtExpr(Instruction &inst, OperandExpression *op_expr, + unsigned int extract_size, unsigned int extend_size) { + auto extract_type = + llvm::Type::getIntNTy(*(inst.arch->context), extract_size); + auto extend_type = llvm::Type::getIntNTy(*(inst.arch->context), extend_size); // Extract bits - op_expr = inst.EmplaceUnaryOp(llvm::Instruction::Trunc, op_expr, - extract_type); + op_expr = + inst.EmplaceUnaryOp(llvm::Instruction::Trunc, op_expr, extract_type); + // ZExtend operand to extend_size if (extend_size > extract_size) { op_expr = inst.EmplaceUnaryOp(ext, op_expr, extend_type); @@ -710,9 +689,8 @@ static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, if (carry_out) { if (!rotation_amount) { AddIntRegOp(inst, "C", 8u, Operand::kActionRead); - inst.operands.back().expr = ExtractAndExtExpr(inst, - inst.operands.back().expr, - 1u, 8u); + inst.operands.back().expr = + ExtractAndExtExpr(inst, inst.operands.back().expr, 1u, 8u); } else { AddImmOp(inst, (unrotated_value >> ((rotation_amount + 31u) % 32u)) & 0b1u); @@ -720,20 +698,19 @@ static void ExpandTo32AddImmAddCarry(Instruction &inst, uint32_t imm12, } } -static OperandExpression * RORExpr(Instruction &inst, - OperandExpression * op_expr, - OperandExpression * shift_amount) { +static OperandExpression *RORExpr(Instruction &inst, OperandExpression *op_expr, + OperandExpression *shift_amount) { const auto word_type = inst.arch->AddressType(); const auto _32 = llvm::ConstantInt::get(word_type, 32u, false); shift_amount = inst.EmplaceBinaryOp(llvm::Instruction::URem, shift_amount, inst.EmplaceConstant(_32)); - auto lhs_expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, op_expr, - shift_amount); - auto rhs_expr = inst.EmplaceBinaryOp(llvm::Instruction::Shl, op_expr, - inst.EmplaceBinaryOp(llvm::Instruction::Sub, - inst.EmplaceConstant(_32), - shift_amount)); + auto lhs_expr = + inst.EmplaceBinaryOp(llvm::Instruction::LShr, op_expr, shift_amount); + auto rhs_expr = inst.EmplaceBinaryOp( + llvm::Instruction::Shl, op_expr, + inst.EmplaceBinaryOp(llvm::Instruction::Sub, inst.EmplaceConstant(_32), + shift_amount)); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Or, lhs_expr, rhs_expr); return op_expr; } @@ -754,44 +731,42 @@ static void AddShiftRegCarryOperand(Instruction &inst, uint32_t reg_num, switch (static_cast(shift_type)) { case Shift::kShiftASR: + // shift_size - 1u - shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Sub, - shift_val_expr_c, - inst.EmplaceConstant(_1)); + shift_val_expr_c = inst.EmplaceBinaryOp( + llvm::Instruction::Sub, shift_val_expr_c, inst.EmplaceConstant(_1)); carry_expr = inst.EmplaceBinaryOp(llvm::Instruction::AShr, carry_expr, shift_val_expr_c); break; case Shift::kShiftLSL: + // 32u - shift_size - shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Sub, - inst.EmplaceConstant(_32), - shift_val_expr_c); + shift_val_expr_c = inst.EmplaceBinaryOp( + llvm::Instruction::Sub, inst.EmplaceConstant(_32), shift_val_expr_c); carry_expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, carry_expr, shift_val_expr_c); break; case Shift::kShiftLSR: + // shift_size - 1u - shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Sub, - shift_val_expr_c, - inst.EmplaceConstant(_1)); + shift_val_expr_c = inst.EmplaceBinaryOp( + llvm::Instruction::Sub, shift_val_expr_c, inst.EmplaceConstant(_1)); carry_expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, carry_expr, shift_val_expr_c); break; case Shift::kShiftROR: + // (shift_size + 31u) % 32u - shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::Add, - shift_val_expr_c, - inst.EmplaceConstant(_31)); - shift_val_expr_c = inst.EmplaceBinaryOp(llvm::Instruction::URem, - shift_val_expr_c, - inst.EmplaceConstant(_32)); + shift_val_expr_c = inst.EmplaceBinaryOp( + llvm::Instruction::Add, shift_val_expr_c, inst.EmplaceConstant(_31)); + shift_val_expr_c = inst.EmplaceBinaryOp( + llvm::Instruction::URem, shift_val_expr_c, inst.EmplaceConstant(_32)); carry_expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, carry_expr, shift_val_expr_c); break; default: LOG(FATAL) << "Invalid shift bits " << shift_type << " in " << inst.Serialize(); - } // Extract the sign bit and extend back to I8 @@ -817,8 +792,8 @@ static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, shift_val_expr); break; case Shift::kShiftLSL: - op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Shl, op_expr, - shift_val_expr); + op_expr = + inst.EmplaceBinaryOp(llvm::Instruction::Shl, op_expr, shift_val_expr); break; case Shift::kShiftLSR: op_expr = inst.EmplaceBinaryOp(llvm::Instruction::LShr, op_expr, @@ -843,9 +818,9 @@ static void AddShiftRegRegOperand(Instruction &inst, uint32_t reg_num, // PLEASE SEE AddShiftRegImmOperand! // This function extracts the carry_out that from the semantics that // AddShiftRegImmOperand handles -static void AddShiftImmCarryOperand(Instruction &inst, - uint32_t reg_num, uint32_t shift_type, - uint32_t shift_size, const char * carry_reg_name) { +static void AddShiftImmCarryOperand(Instruction &inst, uint32_t reg_num, + uint32_t shift_type, uint32_t shift_size, + const char *carry_reg_name) { auto is_rrx = false; if (!shift_size && shift_type == Shift::kShiftROR) { shift_size = 1; @@ -854,9 +829,8 @@ static void AddShiftImmCarryOperand(Instruction &inst, if (!shift_size) { AddIntRegOp(inst, carry_reg_name, 8u, Operand::kActionRead); - inst.operands.back().expr = ExtractAndExtExpr(inst, - inst.operands.back().expr, - 1u, 8u); + inst.operands.back().expr = + ExtractAndExtExpr(inst, inst.operands.back().expr, 1u, 8u); } else { switch (static_cast(shift_type)) { case Shift::kShiftASR: @@ -877,13 +851,13 @@ static void AddShiftImmCarryOperand(Instruction &inst, case Shift::kShiftROR: if (is_rrx) { AddIntRegOp(inst, reg_num, 32u, Operand::kActionRead); - inst.operands.back().expr = ExtractAndExtExpr(inst, inst.operands.back().expr, 1u, 32u); + inst.operands.back().expr = + ExtractAndExtExpr(inst, inst.operands.back().expr, 1u, 32u); } else { - AddShiftThenExtractOp(inst, - Operand::ShiftRegister::kShiftUnsignedRight, - Operand::ShiftRegister::kExtendUnsigned, - kIntRegName[reg_num], 32, - (shift_size + 31u) % 32u, 1); + AddShiftThenExtractOp( + inst, Operand::ShiftRegister::kShiftUnsignedRight, + Operand::ShiftRegister::kExtendUnsigned, kIntRegName[reg_num], 32, + (shift_size + 31u) % 32u, 1); } break; } @@ -928,9 +902,8 @@ static void AddShiftRegImmOperand(Instruction &inst, uint32_t reg_num, AddShiftOp(inst, Operand::ShiftRegister::kShiftLeftWithZeroes, "C", 8, 31); auto rrx_op = inst.operands.back().expr; inst.operands.pop_back(); - inst.operands.back().expr = inst.EmplaceBinaryOp(llvm::Instruction::Or, - inst.operands.back().expr, - rrx_op); + inst.operands.back().expr = inst.EmplaceBinaryOp( + llvm::Instruction::Or, inst.operands.back().expr, rrx_op); } if (carry_out) { AddShiftImmCarryOperand(inst, reg_num, shift_type, shift_size, "C"); @@ -942,55 +915,44 @@ static bool DecodeCondition(Instruction &inst, uint32_t cond) { auto _8_type = llvm::Type::getInt8Ty(*inst.arch->context); const auto _1 = llvm::ConstantInt::get(_8_type, 1u, false); + // Use ~0 -> 11111111 with XOR op for negation const auto negate = llvm::ConstantInt::get(_8_type, ~0u, false); bool negate_conditions = false; bool is_cond = true; - OperandExpression * op_expr = nullptr; + OperandExpression *op_expr = nullptr; switch (cond) { - case 0b0001: - negate_conditions = true; - [[clang::fallthrough]]; + case 0b0001: negate_conditions = true; [[clang::fallthrough]]; case 0b0000: { op_expr = inst.EmplaceRegister("Z"); break; } - case 0b0011: - negate_conditions = true; - [[clang::fallthrough]]; + case 0b0011: negate_conditions = true; [[clang::fallthrough]]; case 0b0010: { op_expr = inst.EmplaceRegister("C"); break; } - case 0b0101: - negate_conditions = true; - [[clang::fallthrough]]; + case 0b0101: negate_conditions = true; [[clang::fallthrough]]; case 0b0100: { op_expr = inst.EmplaceRegister("N"); break; } - case 0b0111: - negate_conditions = true; - [[clang::fallthrough]]; + case 0b0111: negate_conditions = true; [[clang::fallthrough]]; case 0b0110: { op_expr = inst.EmplaceRegister("V"); break; } - case 0b1001: - negate_conditions = true; - [[clang::fallthrough]]; + case 0b1001: negate_conditions = true; [[clang::fallthrough]]; case 0b1000: { auto c_expr = inst.EmplaceRegister("C"); auto z_expr = inst.EmplaceRegister("Z"); z_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, z_expr, - inst.EmplaceConstant(negate)); + inst.EmplaceConstant(negate)); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::And, z_expr, c_expr); break; } - case 0b1011: - negate_conditions = true; - [[clang::fallthrough]]; + case 0b1011: negate_conditions = true; [[clang::fallthrough]]; case 0b1010: { auto n_expr = inst.EmplaceRegister("N"); auto v_expr = inst.EmplaceRegister("V"); @@ -999,18 +961,16 @@ static bool DecodeCondition(Instruction &inst, uint32_t cond) { inst.EmplaceConstant(negate)); break; } - case 0b1101: - negate_conditions = true; - [[clang::fallthrough]]; + case 0b1101: negate_conditions = true; [[clang::fallthrough]]; case 0b1100: { auto n_expr = inst.EmplaceRegister("N"); auto v_expr = inst.EmplaceRegister("V"); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, n_expr, v_expr); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, op_expr, - inst.EmplaceConstant(negate)); + inst.EmplaceConstant(negate)); auto z_expr = inst.EmplaceRegister("Z"); z_expr = inst.EmplaceBinaryOp(llvm::Instruction::Xor, z_expr, - inst.EmplaceConstant(negate)); + inst.EmplaceConstant(negate)); op_expr = inst.EmplaceBinaryOp(llvm::Instruction::And, z_expr, op_expr); break; } @@ -1020,7 +980,8 @@ static bool DecodeCondition(Instruction &inst, uint32_t cond) { is_cond = false; break; default: - LOG(FATAL) << "Invalid condition bits " << cond << " in " << inst.Serialize(); + LOG(FATAL) << "Invalid condition bits " << cond << " in " + << inst.Serialize(); break; } @@ -1036,7 +997,8 @@ static bool DecodeCondition(Instruction &inst, uint32_t cond) { return is_cond; } -std::optional EvalReg(const Instruction &inst, const Operand::Register &op) { +std::optional EvalReg(const Instruction &inst, + const Operand::Register &op) { if (op.name == kIntRegName[kPCRegNum] || op.name == "PC") { return inst.pc; } else if (op.name == "NEXT_PC") { @@ -1061,8 +1023,7 @@ std::optional EvalShift(const Operand::ShiftRegister &op, auto val = static_cast(*maybe_val); switch (op.shift_op) { - case Operand::ShiftRegister::kShiftInvalid: - return maybe_val; + case Operand::ShiftRegister::kShiftInvalid: return maybe_val; case Operand::ShiftRegister::kShiftLeftAround: return __builtin_rotateleft32(val, static_cast(op.shift_size)); case Operand::ShiftRegister::kShiftRightAround: @@ -1074,9 +1035,8 @@ std::optional EvalShift(const Operand::ShiftRegister &op, case Operand::ShiftRegister::kShiftUnsignedRight: return val >> op.shift_size; case Operand::ShiftRegister::kShiftSignedRight: - return static_cast(static_cast(val) >> op.shift_size); - default: - return std::nullopt; + return static_cast(static_cast(val) >> op.shift_size); + default: return std::nullopt; } } @@ -1093,10 +1053,8 @@ std::optional EvalExtract(const Operand::ShiftRegister &op, auto val = static_cast(*maybe_val); switch (op.extend_op) { - case Operand::ShiftRegister::kExtendInvalid: - return maybe_val; - case Operand::ShiftRegister::kExtendSigned: - { + case Operand::ShiftRegister::kExtendInvalid: return maybe_val; + case Operand::ShiftRegister::kExtendSigned: { val &= (1u << (op.extract_size)) - 1u; auto sign = val >> (op.extract_size - 1u); @@ -1108,21 +1066,17 @@ std::optional EvalExtract(const Operand::ShiftRegister &op, } case Operand::ShiftRegister::kExtendUnsigned: return val & ((1u << (op.extract_size)) - 1u); - default: - return std::nullopt; + default: return std::nullopt; } } -std::optional EvalOperand(const Instruction &inst, const Operand &op) { - switch(op.type) { - case Operand::kTypeInvalid: - return std::nullopt; - case Operand::kTypeImmediate: - return op.imm.val; - case Operand::kTypeRegister: - return EvalReg(inst, op.reg); - case Operand::kTypeAddress: - { +std::optional EvalOperand(const Instruction &inst, + const Operand &op) { + switch (op.type) { + case Operand::kTypeInvalid: return std::nullopt; + case Operand::kTypeImmediate: return op.imm.val; + case Operand::kTypeRegister: return EvalReg(inst, op.reg); + case Operand::kTypeAddress: { auto seg_val = EvalReg(inst, op.addr.segment_base_reg); auto base_val = EvalReg(inst, op.addr.base_reg); auto index_val = EvalReg(inst, op.addr.index_reg); @@ -1135,16 +1089,18 @@ std::optional EvalOperand(const Instruction &inst, const Operand &op) static_cast(*seg_val) + static_cast(*base_val) + (static_cast(*index_val) * op.addr.scale) + op.addr.displacement); - } case Operand::kTypeShiftRegister: if (op.shift_reg.shift_first) { - return EvalExtract(op.shift_reg, EvalShift(op.shift_reg, EvalReg(inst, op.shift_reg.reg))); + return EvalExtract( + op.shift_reg, + EvalShift(op.shift_reg, EvalReg(inst, op.shift_reg.reg))); } else { - return EvalShift(op.shift_reg, EvalExtract(op.shift_reg, EvalReg(inst, op.shift_reg.reg))); + return EvalShift( + op.shift_reg, + EvalExtract(op.shift_reg, EvalReg(inst, op.shift_reg.reg))); } - default: - return std::nullopt; + default: return std::nullopt; } } @@ -1157,6 +1113,7 @@ std::optional EvalOperand(const Instruction &inst, const Operand &op) static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, InstEval *evaluator, bool is_cond) { if (rd == kPCRegNum) { + // Updates the flags (condition codes) if (s) { inst.category = Instruction::kCategoryError; @@ -1193,52 +1150,49 @@ static bool EvalPCDest(Instruction &inst, const bool s, const unsigned int rd, } // High 3 bit opc -static InstEval * kIdpEvaluators[] = { - [0b000] = +[](uint32_t src1, uint32_t src2) { - return std::optional(src1 & src2); - }, - [0b001] = +[](uint32_t src1, uint32_t src2) { - return std::optional(src1 ^ src2); - }, - [0b010] = +[](uint32_t src1, uint32_t src2) { - return std::optional(src1 - src2); - }, - [0b011] = +[](uint32_t src1, uint32_t src2) { - return std::optional(src2 - src1); - }, - [0b100] = +[](uint32_t src1, uint32_t src2) { - return std::optional(src2 + src1); - }, - [0b101] = +[](uint32_t src1, uint32_t src2) { - return std::optional(std::nullopt); - }, - [0b110] = +[](uint32_t src1, uint32_t src2) { - return std::optional(std::nullopt); - }, - [0b111] = +[](uint32_t src1, uint32_t src2) { - return std::optional(std::nullopt); - }, +static InstEval *kIdpEvaluators[] = { + [0b000] = + +[](uint32_t src1, uint32_t src2) { + return std::optional(src1 & src2); + }, + [0b001] = + +[](uint32_t src1, uint32_t src2) { + return std::optional(src1 ^ src2); + }, + [0b010] = + +[](uint32_t src1, uint32_t src2) { + return std::optional(src1 - src2); + }, + [0b011] = + +[](uint32_t src1, uint32_t src2) { + return std::optional(src2 - src1); + }, + [0b100] = + +[](uint32_t src1, uint32_t src2) { + return std::optional(src2 + src1); + }, + [0b101] = + +[](uint32_t src1, uint32_t src2) { + return std::optional(std::nullopt); + }, + [0b110] = + +[](uint32_t src1, uint32_t src2) { + return std::optional(std::nullopt); + }, + [0b111] = + +[](uint32_t src1, uint32_t src2) { + return std::optional(std::nullopt); + }, }; // High 3 bit opc and low bit s, opc:s -static const char * const kIdpNamesRRR[] = { - [0b0000] = "ANDrr", - [0b0001] = "ANDSrr", - [0b0010] = "EORrr", - [0b0011] = "EORSrr", - [0b0100] = "SUBrr", - [0b0101] = "SUBSrr", - [0b0110] = "RSBrr", - [0b0111] = "RSBSrr", - [0b1000] = "ADDrr", - [0b1001] = "ADDSrr", - [0b1010] = "ADCrr", - [0b1011] = "ADCSrr", - [0b1100] = "SBCrr", - [0b1101] = "SBCSrr", - [0b1110] = "RSCrr", - [0b1111] = "RSCSrr" -}; +static const char *const kIdpNamesRRR[] = { + [0b0000] = "ANDrr", [0b0001] = "ANDSrr", [0b0010] = "EORrr", + [0b0011] = "EORSrr", [0b0100] = "SUBrr", [0b0101] = "SUBSrr", + [0b0110] = "RSBrr", [0b0111] = "RSBSrr", [0b1000] = "ADDrr", + [0b1001] = "ADDSrr", [0b1010] = "ADCrr", [0b1011] = "ADCSrr", + [0b1100] = "SBCrr", [0b1101] = "SBCSrr", [0b1110] = "RSCrr", + [0b1111] = "RSCSrr"}; //000 AND, ANDS (register) //001 EOR, EORS (register) @@ -1254,10 +1208,11 @@ static const char * const kIdpNamesRRR[] = { //101 ADC, ADCS (register) //110 SBC, SBCS (register) //111 RSC, RSCS (register) -static bool TryDecodeIntegerDataProcessingRRRI(Instruction &inst, uint32_t bits) { +static bool TryDecodeIntegerDataProcessingRRRI(Instruction &inst, + uint32_t bits) { const IntDataProcessingRRRI enc = {bits}; - inst.function = kIdpNamesRRR[ (enc.opc << 1u) | enc.s]; + inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s]; auto is_cond = DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); @@ -1266,11 +1221,12 @@ static bool TryDecodeIntegerDataProcessingRRRI(Instruction &inst, uint32_t bits) } // Integer Data Processing (three register, register shift) -static bool TryDecodeIntegerDataProcessingRRRR(Instruction &inst, uint32_t bits) { - const IntDataProcessingRRRR enc = { bits }; +static bool TryDecodeIntegerDataProcessingRRRR(Instruction &inst, + uint32_t bits) { + const IntDataProcessingRRRR enc = {bits}; - if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum - || enc.rm == kPCRegNum) { + if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum || + enc.rm == kPCRegNum) { inst.category = Instruction::kCategoryError; return false; } @@ -1302,8 +1258,9 @@ static bool TryDecodeIntegerDataProcessingRRRR(Instruction &inst, uint32_t bits) //101 ADC, ADCS (immediate) //110 SBC, SBCS (immediate) //111 RSC, RSCS (immediate) -static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) { - const IntDataProcessingRRI enc = { bits }; +static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, + uint32_t bits) { + const IntDataProcessingRRI enc = {bits}; inst.function = kIdpNamesRRR[(enc.opc << 1u) | enc.s]; auto is_cond = DecodeCondition(inst, enc.cond); @@ -1311,7 +1268,8 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) // Raise the program counter to align to a multiple of 4 bytes if (enc.rn == kPCRegNum && (enc.opc == 0b100u || enc.opc == 0b010u)) { - int64_t diff = static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); + int64_t diff = + static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); AddAddrRegOp(inst, "PC", 32, Operand::kActionRead, diff); } else { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); @@ -1322,24 +1280,13 @@ static bool TryDecodeIntegerDataProcessingRRI(Instruction &inst, uint32_t bits) return EvalPCDest(inst, enc.s, enc.rd, kIdpEvaluators[enc.opc], is_cond); } -static const char * const kMulAccRRR[] = { - [0b0000] = "MUL", - [0b0001] = "MULS", - [0b0010] = "MLA", - [0b0011] = "MLAS", - [0b0100] = "UMAAL", - [0b0101] = nullptr, - [0b0110] = "MLS", - [0b0111] = nullptr, - [0b1000] = "UMULL", - [0b1001] = "UMULLS", - [0b1010] = "UMLAL", - [0b1011] = "UMLALS", - [0b1100] = "SMULL", - [0b1101] = "SMULLS", - [0b1110] = "SMLAL", - [0b1111] = "SMLALS" -}; +static const char *const kMulAccRRR[] = { + [0b0000] = "MUL", [0b0001] = "MULS", [0b0010] = "MLA", + [0b0011] = "MLAS", [0b0100] = "UMAAL", [0b0101] = nullptr, + [0b0110] = "MLS", [0b0111] = nullptr, [0b1000] = "UMULL", + [0b1001] = "UMULLS", [0b1010] = "UMLAL", [0b1011] = "UMLALS", + [0b1100] = "SMULL", [0b1101] = "SMULLS", [0b1110] = "SMLAL", + [0b1111] = "SMLALS"}; //000 MUL, MULS //001 MLA, MLAS @@ -1352,11 +1299,12 @@ static const char * const kMulAccRRR[] = { //110 SMULL, SMULLS - writes to RdHi + RdLo //111 SMLAL, SMLALS - writes to RdHi + RdLo, read RdHi static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { - const MultiplyAndAccumulate enc = { bits }; + const MultiplyAndAccumulate enc = {bits}; + // MUL, MULS only: if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; // All other instructions: if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; - if (enc.rdhi == kPCRegNum || (enc.rdlo == kPCRegNum && !enc.opc) - || enc.rn == kPCRegNum || enc.rm == kPCRegNum) { + if (enc.rdhi == kPCRegNum || (enc.rdlo == kPCRegNum && !enc.opc) || + enc.rn == kPCRegNum || enc.rm == kPCRegNum) { inst.category = Instruction::kCategoryError; return false; } @@ -1373,8 +1321,9 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { // 2nd write reg only needed for instructions with an opc that begins with 1 and UMALL if (((enc.opc >> 2) & 0b1u) || enc.opc == 0b010u) { + // if dHi == dLo then UNPREDICTABLE; - if (enc.rdlo == enc.rdhi){ + if (enc.rdlo == enc.rdhi) { inst.category = Instruction::kCategoryError; return false; } @@ -1402,23 +1351,21 @@ static bool TryDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { return true; } -static const char * const kHMulAccRRR[] = { - [0b0000] = "SMLABB", // (M == 0 && N == 0) - [0b0010] = "SMLABT", // (M == 1 && N == 0) - [0b0001] = "SMLATB", // (M == 0 && N == 1) - [0b0011] = "SMLATT", // (M == 1 && N == 1) - [0b0100] = "SMLAWB", - [0b0101] = "SMULWB", - [0b0110] = "SMLAWT", - [0b0111] = "SMULWT", - [0b1000] = "SMLALBB", // (M == 0 && N == 0) - [0b1010] = "SMLALBT", // (M == 1 && N == 0) - [0b1001] = "SMLALTB", // (M == 0 && N == 1) - [0b1011] = "SMLALTT", // (M == 1 && N == 1) - [0b1100] = "SMULBB", // (M == 0 && N == 0) - [0b1110] = "SMULBT", // (M == 1 && N == 0) - [0b1101] = "SMULTB", // (M == 0 && N == 1) - [0b1111] = "SMULTT", // (M == 1 && N == 1) +static const char *const kHMulAccRRR[] = { + [0b0000] = "SMLABB", // (M == 0 && N == 0) + [0b0010] = "SMLABT", // (M == 1 && N == 0) + [0b0001] = "SMLATB", // (M == 0 && N == 1) + [0b0011] = "SMLATT", // (M == 1 && N == 1) + [0b0100] = "SMLAWB", [0b0101] = "SMULWB", + [0b0110] = "SMLAWT", [0b0111] = "SMULWT", + [0b1000] = "SMLALBB", // (M == 0 && N == 0) + [0b1010] = "SMLALBT", // (M == 1 && N == 0) + [0b1001] = "SMLALTB", // (M == 0 && N == 1) + [0b1011] = "SMLALTT", // (M == 1 && N == 1) + [0b1100] = "SMULBB", // (M == 0 && N == 0) + [0b1110] = "SMULBT", // (M == 1 && N == 0) + [0b1101] = "SMULTB", // (M == 0 && N == 1) + [0b1111] = "SMULTT", // (M == 1 && N == 1) }; // opc M N @@ -1434,14 +1381,15 @@ static const char * const kHMulAccRRR[] = { static bool TryHalfwordDecodeMultiplyAndAccumulate(Instruction &inst, uint32_t bits) { - const HMultiplyAndAccumulate enc = { bits }; + const HMultiplyAndAccumulate enc = {bits}; bool add_ra = enc.opc == 0b10u || (enc.opc == 0b1u && !enc.N) || !enc.opc; + // if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE; // if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; // if dHi == dLo then UNPREDICTABLE; - if (enc.rd == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum - || ((enc.ra == kPCRegNum) && add_ra) - || ((enc.opc == 0b10u) && (enc.rd == enc.ra))) { + if (enc.rd == kPCRegNum || enc.rn == kPCRegNum || enc.rm == kPCRegNum || + ((enc.ra == kPCRegNum) && add_ra) || + ((enc.opc == 0b10u) && (enc.rd == enc.ra))) { inst.category = Instruction::kCategoryError; } @@ -1475,9 +1423,9 @@ static bool TryHalfwordDecodeMultiplyAndAccumulate(Instruction &inst, // Rm AddIntRegOp(inst, enc.rm, 32, Operand::kActionRead); if (enc.M) { - inst.operands.back().expr = inst.EmplaceBinaryOp(llvm::Instruction::AShr, - inst.operands.back().expr, - inst.EmplaceConstant(_16)); + inst.operands.back().expr = + inst.EmplaceBinaryOp(llvm::Instruction::AShr, inst.operands.back().expr, + inst.EmplaceConstant(_16)); } else { inst.operands.back().expr = ExtractAndExtExpr( inst, inst.operands.back().expr, 16u, 32u); @@ -1490,63 +1438,47 @@ static bool TryHalfwordDecodeMultiplyAndAccumulate(Instruction &inst, inst.category = Instruction::kCategoryNormal; return true; - } // Index from: op1 | Ra == 15 | op2 -static const char * kSMulDiv(uint32_t index) { - switch(index) { - case 0b0000000: - return "SMLAD"; - case 0b0000001: - return "SMLADX"; - case 0b0000010: - return "SMLSD"; - case 0b0000011: - return "SMLSDX"; - case 0b0001000: - return "SMUAD"; - case 0b0001001: - return "SMUADX"; - case 0b0001010: - return "SMUSD"; - case 0b0001011: - return "SMUSDX"; - // case 0b0010000: - Note(Sonya): a != 15 is constrained UNPREDICTABLE - case 0b0011000: - return "SDIV"; - // case 0b0110000: - Note(Sonya): a != 15 is constrained UNPREDICTABLE - case 0b0111000: - return "UDIV"; - case 0b1000000: - case 0b1001000: - return "SMLALD"; - case 0b1000001: - case 0b1001001: - return "SMLALDX"; - case 0b1000010: - case 0b1001010: - return "SMLSLD"; - case 0b1000011: - case 0b1001011: - return "SMLSLDX"; - case 0b1010000: - return "SMMLA"; - case 0b1010001: - return "SMMLAR"; - case 0b1010110: - // case 0b1011110: - Note(Sonya): a == 15 is constrained UNPREDICTABLE - return "SMMLS"; - case 0b1010111: - // case 0b1011111: - Note(Sonya): a == 15 is constrained UNPREDICTABLE - return "SMMLSR"; - case 0b1011000: - return "SMMUL"; - case 0b1011001: - return "SMMULR"; - default: - return nullptr; // UNALLOCATED - } +static const char *kSMulDiv(uint32_t index) { + switch (index) { + case 0b0000000: return "SMLAD"; + case 0b0000001: return "SMLADX"; + case 0b0000010: return "SMLSD"; + case 0b0000011: return "SMLSDX"; + case 0b0001000: return "SMUAD"; + case 0b0001001: return "SMUADX"; + case 0b0001010: return "SMUSD"; + case 0b0001011: return "SMUSDX"; + + // case 0b0010000: - Note(Sonya): a != 15 is constrained UNPREDICTABLE + case 0b0011000: return "SDIV"; + + // case 0b0110000: - Note(Sonya): a != 15 is constrained UNPREDICTABLE + case 0b0111000: return "UDIV"; + case 0b1000000: + case 0b1001000: return "SMLALD"; + case 0b1000001: + case 0b1001001: return "SMLALDX"; + case 0b1000010: + case 0b1001010: return "SMLSLD"; + case 0b1000011: + case 0b1001011: return "SMLSLDX"; + case 0b1010000: return "SMMLA"; + case 0b1010001: return "SMMLAR"; + case 0b1010110: + + // case 0b1011110: - Note(Sonya): a == 15 is constrained UNPREDICTABLE + return "SMMLS"; + case 0b1010111: + + // case 0b1011111: - Note(Sonya): a == 15 is constrained UNPREDICTABLE + return "SMMLSR"; + case 0b1011000: return "SMMUL"; + case 0b1011001: return "SMMULR"; + default: return nullptr; // UNALLOCATED + } } // op1 Ra op2 @@ -1580,12 +1512,13 @@ static const char * kSMulDiv(uint32_t index) { // 11x UNALLOCATED // Signed multiply, Divide static bool TryDecodeSignedMultiplyDivide(Instruction &inst, uint32_t bits) { - const SignedMulDiv enc = { bits }; + const SignedMulDiv enc = {bits}; - auto instruction = kSMulDiv(enc.op1 << 4 | (enc.ra == kPCRegNum) << 3 | enc.op2); - if (!instruction || enc.rd == kPCRegNum || enc.rn == kPCRegNum - || enc.rm == kPCRegNum - || (enc.op1 == 0b100 && (enc.ra == kPCRegNum || enc.ra == enc.rd))) { + auto instruction = + kSMulDiv(enc.op1 << 4 | (enc.ra == kPCRegNum) << 3 | enc.op2); + if (!instruction || enc.rd == kPCRegNum || enc.rn == kPCRegNum || + enc.rm == kPCRegNum || + (enc.op1 == 0b100 && (enc.ra == kPCRegNum || enc.ra == enc.rd))) { inst.category = Instruction::kCategoryError; return false; } @@ -1604,8 +1537,8 @@ static bool TryDecodeSignedMultiplyDivide(Instruction &inst, uint32_t bits) { if ((enc.op1 == 0b100 || !enc.op1) && (enc.op2 & 0b1)) { const auto word_type = inst.arch->AddressType(); const auto _16 = llvm::ConstantInt::get(word_type, 16u, false); - inst.operands.back().expr = RORExpr(inst, inst.operands.back().expr, - inst.EmplaceConstant(_16)); + inst.operands.back().expr = + RORExpr(inst, inst.operands.back().expr, inst.EmplaceConstant(_16)); } if (!div && enc.ra != kPCRegNum) { @@ -1629,22 +1562,12 @@ static bool TryDecodeSignedMultiplyDivide(Instruction &inst, uint32_t bits) { return true; } -static const char * const kLoadSWUB[] = { - [0b0000] = "STRp", - [0b0001] = "LDRp", - [0b0010] = "STRBp", - [0b0011] = "LDRBp", - [0b0100] = "STRT", - [0b0101] = "LDRT", - [0b0110] = "STRBT", - [0b0111] = "LDRBT", - [0b1000] = "STR", - [0b1001] = "LDR", - [0b1010] = "STRB", - [0b1011] = "LDRB", - [0b1100] = "STRp", - [0b1101] = "LDRp", - [0b1110] = "STRBp", +static const char *const kLoadSWUB[] = { + [0b0000] = "STRp", [0b0001] = "LDRp", [0b0010] = "STRBp", + [0b0011] = "LDRBp", [0b0100] = "STRT", [0b0101] = "LDRT", + [0b0110] = "STRBT", [0b0111] = "LDRBT", [0b1000] = "STR", + [0b1001] = "LDR", [0b1010] = "STRB", [0b1011] = "LDRB", + [0b1100] = "STRp", [0b1101] = "LDRp", [0b1110] = "STRBp", [0b1111] = "LDRBp", }; @@ -1670,9 +1593,10 @@ static const char * const kLoadSWUB[] = { // LDR{}{} , [ {, #{+/-}}] // LDR{}{} , [], #{+/-} // LDR{}{} , [, #{+/-}]! -template -static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { - const LoadStoreWUBIL enc = { bits }; +template +static bool TryDecodeLoadStoreWordUBIL(Instruction &inst, uint32_t bits) { + const LoadStoreWUBIL enc = {bits}; bool write_back = (!enc.P || enc.W); bool is_add = enc.u; @@ -1688,7 +1612,8 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes int64_t pc_adjust = 0; if (kAlignPC && enc.rn == kPCRegNum) { - pc_adjust = static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); + pc_adjust = + static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); } auto disp = static_cast(enc.imm12); @@ -1701,7 +1626,8 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { if (!is_index) { AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); } else { - AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, disp + pc_adjust); + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, + disp + pc_adjust); } AddIntRegOp(inst, enc.rt, 32, kRegAction); @@ -1743,16 +1669,16 @@ static bool TryDecodeLoadStoreWordUBIL (Instruction &inst, uint32_t bits) { // Post-indexed (P == 0 && W == 0): LDR{}{} , [], {+/-}{, } // Pre-indexed (P == 1 && W == 1): LDR{}{} , [, {+/-}{, }]! // Load/Store Word, Unsigned Byte (register) -template +template static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { - const LoadStoreWUBR enc = { bits }; + const LoadStoreWUBR enc = {bits}; bool write_back = (!enc.P || enc.W); // if wback && (n == 15 || n == t) then UNPREDICTABLE; - if ((write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt)) - || (enc.rm == kPCRegNum && (enc.P || !enc.o2 || !enc.W)) - || (enc.rt == kPCRegNum && enc.o2)) { + if ((write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt)) || + (enc.rm == kPCRegNum && (enc.P || !enc.o2 || !enc.W)) || + (enc.rt == kPCRegNum && enc.o2)) { inst.category = Instruction::kCategoryError; return false; } @@ -1765,8 +1691,8 @@ static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes int64_t pc_adjust = 0; if (kAlignPC && enc.rn == kPCRegNum) { - pc_adjust = static_cast(inst.pc & ~(3u)) - - static_cast(inst.pc); + pc_adjust = + static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); } AddShiftRegImmOperand(inst, enc.rm, enc.type, enc.imm5, 0u); @@ -1781,11 +1707,9 @@ static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { if (!is_index) { AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); } else { - AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, - pc_adjust); - inst.operands.back().expr = inst.EmplaceBinaryOp(disp_op, - inst.operands.back().expr, - disp_expr); + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); + inst.operands.back().expr = + inst.EmplaceBinaryOp(disp_op, inst.operands.back().expr, disp_expr); } AddIntRegOp(inst, enc.rt, 32, kRegAction); @@ -1795,9 +1719,8 @@ static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); AddAddrRegOp(inst, kIntRegName[enc.rn], 32, Operand::kActionRead, pc_adjust); - inst.operands.back().expr = inst.EmplaceBinaryOp(disp_op, - inst.operands.back().expr, - disp_expr); + inst.operands.back().expr = + inst.EmplaceBinaryOp(disp_op, inst.operands.back().expr, disp_expr); } if (enc.rt == kPCRegNum) { @@ -1815,31 +1738,15 @@ static bool TryDecodeLoadStoreWordUBReg(Instruction &inst, uint32_t bits) { // op2 != 00 for extra load store instructions // (see: Data-processing and miscellaneous instructions & Extra load/store) -static const char * const kLoadStoreDHSB[] = { - [0b00010] = "LDRDp", - [0b00001] = "STRHp", - [0b00011] = "STRDp", - [0b00101] = "LDRHp", - [0b00110] = "LDRSBp", - [0b00111] = "LDRSHp", - [0b01010] = nullptr, - [0b01001] = "STRHT", - [0b01011] = nullptr, - [0b01101] = "LDRHT", - [0b01110] = "LDRSBT", - [0b01111] = "LDRSHT", - [0b10010] = "LDRD", - [0b10001] = "STRH", - [0b10011] = "STRD", - [0b10101] = "LDRH", - [0b10110] = "LDRSB", - [0b10111] = "LDRSH", - [0b11010] = "LDRDp", - [0b11001] = "STRHp", - [0b11011] = "STRDp", - [0b11101] = "LDRHp", - [0b11110] = "LDRSBp", - [0b11111] = "LDRSHp", +static const char *const kLoadStoreDHSB[] = { + [0b00010] = "LDRDp", [0b00001] = "STRHp", [0b00011] = "STRDp", + [0b00101] = "LDRHp", [0b00110] = "LDRSBp", [0b00111] = "LDRSHp", + [0b01010] = nullptr, [0b01001] = "STRHT", [0b01011] = nullptr, + [0b01101] = "LDRHT", [0b01110] = "LDRSBT", [0b01111] = "LDRSHT", + [0b10010] = "LDRD", [0b10001] = "STRH", [0b10011] = "STRD", + [0b10101] = "LDRH", [0b10110] = "LDRSB", [0b10111] = "LDRSH", + [0b11010] = "LDRDp", [0b11001] = "STRHp", [0b11011] = "STRDp", + [0b11101] = "LDRHp", [0b11110] = "LDRSBp", [0b11111] = "LDRSHp", }; //P:W o1 Rn op2 @@ -1872,15 +1779,15 @@ static const char * const kLoadStoreDHSB[] = { // 11 1 != 1111 10 LDRSB (immediate) — pre-indexed if t == 15 wback && n == t then UNPREDICTABLE; // 11 1 != 1111 11 LDRSH (immediate) — pre-indexed if t == 15 wback && n == t then UNPREDICTABLE; // Load/Store Dual, Half, Signed Byte (immediate, literal) -template +template static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst, - uint32_t bits) { - const LoadStoreDualHSBIL enc = { bits }; + uint32_t bits) { + const LoadStoreDualHSBIL enc = {bits}; auto instruction = kLoadStoreDHSB[enc.P << 4 | enc.W << 3 | enc.o1 << 2 | enc.op2]; if (enc.rn == kPCRegNum && !instruction && enc.op2 == 0b10) { - if (enc.rt &0b1) { + if (enc.rt & 0b1) { inst.category = Instruction::kCategoryError; return false; } @@ -1898,10 +1805,9 @@ static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst, bool is_dual = !enc.o1 && enc.op2 >> 1; uint32_t rt2 = enc.rt + 1; - if ((!is_dual && enc.rt == kPCRegNum) || (is_dual && rt2 == kPCRegNum) - || (write_back - && (enc.rn == kPCRegNum || enc.rn == enc.rt - || (is_dual && enc.rn == rt2)))) { + if ((!is_dual && enc.rt == kPCRegNum) || (is_dual && rt2 == kPCRegNum) || + (write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt || + (is_dual && enc.rn == rt2)))) { inst.category = Instruction::kCategoryError; return false; } @@ -1910,8 +1816,8 @@ static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst, // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes int64_t pc_adjust = 0; if (kAlignPC && enc.rn == kPCRegNum) { - pc_adjust = static_cast(inst.pc & ~(3u)) - - static_cast(inst.pc); + pc_adjust = + static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); } auto disp = static_cast(enc.imm4H << 4 | enc.imm4L); @@ -1925,10 +1831,12 @@ static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst, if (!is_index) { AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); } else { - AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, disp + pc_adjust); + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, + disp + pc_adjust); } AddIntRegOp(inst, enc.rt, 32, kRegAction); + // Add t2 = t + 1 reg for dual instructions if (is_dual) { AddIntRegOp(inst, enc.rt + 1, 32, kRegAction); @@ -1938,7 +1846,7 @@ static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst, if (write_back) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); AddAddrRegOp(inst, kIntRegName[enc.rn], 32, Operand::kActionRead, - disp + pc_adjust); + disp + pc_adjust); } if (enc.rt == kPCRegNum) { @@ -1974,11 +1882,11 @@ static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst, // 1 1 10 LDRSB (register) — pre-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE; // 1 1 11 LDRSH (register) — pre-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE // Load/Store Dual, Half, Signed Byte (register) -template +template static bool TryDecodeLoadStoreDualHalfSignedBReg(Instruction &inst, uint32_t bits) { - const LoadStoreDualHSBR enc = { bits }; + const LoadStoreDualHSBR enc = {bits}; auto instruction = kLoadStoreDHSB[enc.P << 4 | enc.W << 3 | enc.o1 << 2 | enc.op2]; @@ -1989,14 +1897,12 @@ static bool TryDecodeLoadStoreDualHalfSignedBReg(Instruction &inst, bool is_unpriv = enc.W && !enc.P; uint32_t rt2 = enc.rt + 1; - if (!instruction - || (write_back - && (enc.rn == kPCRegNum || enc.rn == enc.rt - || (is_dual && enc.rn == rt2) - || (is_unpriv && (enc.rt == kPCRegNum || enc.rm == kPCRegNum)))) - || (is_dual - && (enc.rt == kLRRegNum || enc.rm == kPCRegNum - || (enc.op2 == 0b10 && (enc.rm == enc.rt || enc.rm == rt2))))) { + if (!instruction || + (write_back && + (enc.rn == kPCRegNum || enc.rn == enc.rt || (is_dual && enc.rn == rt2) || + (is_unpriv && (enc.rt == kPCRegNum || enc.rm == kPCRegNum)))) || + (is_dual && (enc.rt == kLRRegNum || enc.rm == kPCRegNum || + (enc.op2 == 0b10 && (enc.rm == enc.rt || enc.rm == rt2))))) { inst.category = Instruction::kCategoryError; return false; } else { @@ -2007,8 +1913,8 @@ static bool TryDecodeLoadStoreDualHalfSignedBReg(Instruction &inst, // LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes int64_t pc_adjust = 0; if (kAlignPC && enc.rn == kPCRegNum) { - pc_adjust = static_cast(inst.pc & ~(3u)) - - static_cast(inst.pc); + pc_adjust = + static_cast(inst.pc & ~(3u)) - static_cast(inst.pc); } // Note: AArch32 has shift_size = 0 and type = LSL so disp is an unshifted reg @@ -2026,11 +1932,9 @@ static bool TryDecodeLoadStoreDualHalfSignedBReg(Instruction &inst, if (!is_index) { AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); } else { - AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, - pc_adjust); - inst.operands.back().expr = inst.EmplaceBinaryOp(disp_op, - inst.operands.back().expr, - disp_expr); + AddAddrRegOp(inst, kIntRegName[enc.rn], kMemSize, kMemAction, pc_adjust); + inst.operands.back().expr = + inst.EmplaceBinaryOp(disp_op, inst.operands.back().expr, disp_expr); } AddIntRegOp(inst, enc.rt, 32, kRegAction); @@ -2044,9 +1948,8 @@ static bool TryDecodeLoadStoreDualHalfSignedBReg(Instruction &inst, AddIntRegOp(inst, enc.rn, 32, Operand::kActionWrite); AddAddrRegOp(inst, kIntRegName[enc.rn], 32, Operand::kActionRead, pc_adjust); - inst.operands.back().expr = inst.EmplaceBinaryOp(disp_op, - inst.operands.back().expr, - disp_expr); + inst.operands.back().expr = + inst.EmplaceBinaryOp(disp_op, inst.operands.back().expr, disp_expr); } if (enc.rt == kPCRegNum) { @@ -2074,55 +1977,54 @@ static bool TryDecodeLoadStoreDualHalfSignedBReg(Instruction &inst, // 1 1 0 0 STMIB, STMFA if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if i == n && wback && i != LowestSetBit(registers) then bits(32) UNKNOWN; // 1 1 0 1 LDMIB, LDMED if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if wback && registers == '1' then UNPREDICTABLE; // 1 1 1xxxxxxxxxxxxxxx LDM (exception return) if n == 15 then UNPREDICTABLE; if wback && registers == '1' then UNPREDICTABLE; -static const char * const kLoadStoreM[] = { - [0b0000] = "STMDA", - [0b0001] = "LDMDA", - [0b0010] = "STMu", // (User registers) - [0b0011] = "LDM", // (User registers) || (exception return) - [0b0100] = "STM", - [0b0101] = "LDM", - [0b0110] = "STMu", // (User registers) - [0b0111] = "LDM", // (User registers) || (exception return) - [0b1000] = "STMDB", - [0b1001] = "LDMDB", - [0b1010] = "STMu", // (User registers) - [0b1011] = "LDM", // (User registers) || (exception return) - [0b1100] = "STMIB", - [0b1101] = "LDMIB", - [0b1110] = "STMu", // (User registers) - [0b1111] = "LDM", // (User registers) || (exception return) +static const char *const kLoadStoreM[] = { + [0b0000] = "STMDA", [0b0001] = "LDMDA", + [0b0010] = "STMu", // (User registers) + [0b0011] = "LDM", // (User registers) || (exception return) + [0b0100] = "STM", [0b0101] = "LDM", + [0b0110] = "STMu", // (User registers) + [0b0111] = "LDM", // (User registers) || (exception return) + [0b1000] = "STMDB", [0b1001] = "LDMDB", + [0b1010] = "STMu", // (User registers) + [0b1011] = "LDM", // (User registers) || (exception return) + [0b1100] = "STMIB", [0b1101] = "LDMIB", + [0b1110] = "STMu", // (User registers) + [0b1111] = "LDM", // (User registers) || (exception return) }; // Load/Store Multiple // Note that: // LDM{}{} SP!, is an alias for POP{}{} // STMDB{}{} SP!, is an alias for PUSH{}{} -template static bool TryDecodeLoadStoreMultiple(Instruction &inst, uint32_t bits) { - const LoadStoreM enc = { bits }; + const LoadStoreM enc = {bits}; inst.function = kLoadStoreM[enc.P << 3 | enc.U << 2 | enc.op << 1 | enc.L]; if (enc.op && enc.L && (enc.register_list >> 15)) { + // Exception Return inst.function += "e"; } else if (enc.op && enc.L) { + // User registers inst.function += "u"; } auto wback = enc.W; uint32_t reg_cnt = 0; - for (uint32_t i = 0; 16u > i; i++) { - if ((0b1 << i) & enc.register_list) { - if (wback && i == enc.rn && ((!reg_cnt && !enc.L) || enc.L)) { - // if i == n && wback && i != LowestSetBit(registers) then bits(32) UNKNOWN; - inst.category = Instruction::kCategoryError; - return false; - } - reg_cnt++; + for (uint32_t i = 0; 16u > i; i++) { + if ((0b1 << i) & enc.register_list) { + if (wback && i == enc.rn && ((!reg_cnt && !enc.L) || enc.L)) { + + // if i == n && wback && i != LowestSetBit(registers) then bits(32) UNKNOWN; + inst.category = Instruction::kCategoryError; + return false; } + reg_cnt++; } + } if (enc.rn == 15 || (reg_cnt < 1u)) { inst.category = Instruction::kCategoryError; @@ -2158,6 +2060,7 @@ static bool TryDecodeLoadStoreMultiple(Instruction &inst, uint32_t bits) { } disp = 4; break; + // TODO(Sonya): STM (User registers), LDM (User registers), LDM (exception return) } @@ -2184,27 +2087,30 @@ static bool TryDecodeLoadStoreMultiple(Instruction &inst, uint32_t bits) { // Index from: op1 | Ra == 15 | op2 -static const char* kSpecial(uint32_t index) { +static const char *kSpecial(uint32_t index) { if (index >> 8) { return nullptr; // TODO(Sonya) MSR (immediate) } switch (index) { - case 0b000000000: - return "NOP"; + case 0b000000000: return "NOP"; case 0b000000001: + // TODO(Sonya) return "YIELD"; case 0b000000010: + // TODO(Sonya) return "WFE"; case 0b000000011: + // TODO(Sonya) return "WFI"; case 0b000000100: + // TODO(Sonya) return "SEV"; case 0b000000101: + // TODO(Sonya) return "SEVL"; return nullptr; case 0b000000110: - case 0b000000111: - return "HINT_1"; // Reserved hint, behaves as NOP + case 0b000000111: return "HINT_1"; // Reserved hint, behaves as NOP case 0b000001000: case 0b000001001: case 0b000001010: @@ -2213,18 +2119,16 @@ static const char* kSpecial(uint32_t index) { case 0b000001101: case 0b000001110: case 0b000001111: - return "HINT_2"; // Reserved hint, behaves as NOP + return "HINT_2"; // Reserved hint, behaves as NOP + // case 0b000010000: return "ESB"; // ARMv8.2 - case 0b000010001: - return "HINT_3"; // Reserved hint, behaves as NOP + case 0b000010001: return "HINT_3"; // Reserved hint, behaves as NOP case 0b000010010: - case 0b000010011: - return "HINT_4"; // Reserved hint, behaves as NOP + case 0b000010011: return "HINT_4"; // Reserved hint, behaves as NOP case 0b000010100: case 0b000010101: case 0b000010110: - case 0b000010111: - return "HINT_5"; // Reserved hint, behaves as NOP + case 0b000010111: return "HINT_5"; // Reserved hint, behaves as NOP case 0b000011000: case 0b000011001: case 0b000011010: @@ -2232,8 +2136,7 @@ static const char* kSpecial(uint32_t index) { case 0b000011100: case 0b000011101: case 0b000011110: - case 0b000011111: - return "HINT_6"; // Reserved hint, behaves as NOP + case 0b000011111: return "HINT_6"; // Reserved hint, behaves as NOP case 0b011100000: case 0b011100001: case 0b011100010: @@ -2249,22 +2152,16 @@ static const char* kSpecial(uint32_t index) { case 0b011101100: case 0b011101101: case 0b011101110: - case 0b011101111: - return "HINT_11"; // Reserved hint, behaves as NOP + case 0b011101111: return "HINT_11"; // Reserved hint, behaves as NOP } switch (index >> 5) { - case 0b0001: - return "HINT_7"; // Reserved hint, behaves as NOP + case 0b0001: return "HINT_7"; // Reserved hint, behaves as NOP case 0b0010: - case 0b0011: - return "HINT_8"; // Reserved hint, behaves as NOP + case 0b0011: return "HINT_8"; // Reserved hint, behaves as NOP case 0b0100: - case 0b0101: - return "HINT_9"; // Reserved hint, behaves as NOP - case 0b0110: - return "HINT_10"; // Reserved hint, behaves as NOP - default: - return nullptr; + case 0b0101: return "HINT_9"; // Reserved hint, behaves as NOP + case 0b0110: return "HINT_10"; // Reserved hint, behaves as NOP + default: return nullptr; } } @@ -2292,10 +2189,11 @@ static const char* kSpecial(uint32_t index) { // Move Special Register and Hints (immediate) // TODO(Sonya): This literally only has functionality for NOP and "behaves as NOP" static bool TryMoveSpecialRegisterAndHintsI(Instruction &inst, uint32_t bits) { - const SpecialRegsAndHints enc = { bits }; + const SpecialRegsAndHints enc = {bits}; // (R:imm4 != 00000)<1 bit>:imm12 - auto instruction = kSpecial(((enc.R << 4 | enc.imm4) != 0b0u) << 8 | (enc.imm12 & 255u)); + auto instruction = + kSpecial(((enc.R << 4 | enc.imm4) != 0b0u) << 8 | (enc.imm12 & 255u)); if (!instruction) { inst.category = Instruction::kCategoryError; return false; @@ -2313,33 +2211,28 @@ static bool TryMoveSpecialRegisterAndHintsI(Instruction &inst, uint32_t bits) { // Can package semantics for MOV with ORR and MVN with BIC since src1 will be // 0 and 1 for MOV and MVN respectively, mirroring the semantics in LOGICAL.cpp -static InstEval * kLogArithEvaluators[] = { - [0b0] = +[](uint32_t src1, uint32_t src2) { - return std::optional(src1 | src2); - }, - [0b1] = +[](uint32_t src1, uint32_t src2) { - return std::optional(src1 & ~src2); - }, +static InstEval *kLogArithEvaluators[] = { + [0b0] = +[](uint32_t src1, + uint32_t src2) { return std::optional(src1 | src2); }, + [0b1] = + +[](uint32_t src1, uint32_t src2) { + return std::optional(src1 & ~src2); + }, }; //00 ORR, ORRS (register) -- rd, rn, & rm //01 MOV, MOVS (register) -- rd, & rm only //10 BIC, BICS (register) -- rd, rn, & rm //11 MVN, MVNS (register) -- rd, & rm only -static const char * const kLogicalArithmeticRRRI[] = { - [0b000] = "ORRrr", - [0b001] = "ORRSrr", - [0b010] = "MOVrr", - [0b011] = "MOVSrr", - [0b100] = "BICrr", - [0b101] = "BICSrr", - [0b110] = "MVNrr", - [0b111] = "MVNSrr", +static const char *const kLogicalArithmeticRRRI[] = { + [0b000] = "ORRrr", [0b001] = "ORRSrr", [0b010] = "MOVrr", + [0b011] = "MOVSrr", [0b100] = "BICrr", [0b101] = "BICSrr", + [0b110] = "MVNrr", [0b111] = "MVNSrr", }; // Logical Arithmetic (three register, immediate shift) static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { - const LogicalArithRRRI enc = { bits }; + const LogicalArithRRRI enc = {bits}; inst.function = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; auto is_cond = DecodeCondition(inst, enc.cond); @@ -2349,24 +2242,27 @@ static bool TryLogicalArithmeticRRRI(Instruction &inst, uint32_t bits) { // enc.opc == x0 if (!(enc.opc & 0b1u)) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + // enc.opc == 01 } else if (!(enc.opc & 0b10u)) { AddImmOp(inst, 0); + // enc.opc == 11 } else { AddImmOp(inst, ~0u); } AddShiftRegImmOperand(inst, enc.rm, enc.type, enc.imm5, enc.s); - return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u], is_cond); + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u], + is_cond); } // Logical Arithmetic (three register, register shift) static bool TryLogicalArithmeticRRRR(Instruction &inst, uint32_t bits) { - const LogicalArithRRRR enc = { bits }; + const LogicalArithRRRR enc = {bits}; - if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum - || enc.rm == kPCRegNum) { + if (enc.rn == kPCRegNum || enc.rd == kPCRegNum || enc.rs == kPCRegNum || + enc.rm == kPCRegNum) { inst.category = Instruction::kCategoryError; return false; } @@ -2376,12 +2272,15 @@ static bool TryLogicalArithmeticRRRR(Instruction &inst, uint32_t bits) { AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + // enc.opc == x0 if (!(enc.opc & 0b1u)) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + // enc.opc == 01 } else if (!(enc.opc & 0b10u)) { AddImmOp(inst, 0); + // enc.opc == 11 } else { AddImmOp(inst, ~0u); @@ -2393,30 +2292,34 @@ static bool TryLogicalArithmeticRRRR(Instruction &inst, uint32_t bits) { // Logical Arithmetic (two register and immediate) static bool TryLogicalArithmeticRRI(Instruction &inst, uint32_t bits) { - const LogicalArithmeticRRI enc = { bits }; + const LogicalArithmeticRRI enc = {bits}; inst.function = kLogicalArithmeticRRRI[enc.opc << 1u | enc.s]; auto is_cond = DecodeCondition(inst, enc.cond); AddIntRegOp(inst, enc.rd, 32, Operand::kActionWrite); + // enc.opc == x0 if (!(enc.opc & 0b1u)) { AddIntRegOp(inst, enc.rn, 32, Operand::kActionRead); + // enc.opc == 01 } else if (!(enc.opc & 0b10u)) { AddImmOp(inst, 0u); + // enc.opc == 11 } else { AddImmOp(inst, ~0u); } ExpandTo32AddImmAddCarry(inst, enc.imm12, enc.s); - return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u], is_cond); + return EvalPCDest(inst, enc.s, enc.rd, kLogArithEvaluators[enc.opc >> 1u], + is_cond); } // Move Halfword (immediate) static bool TryDecodeMoveHalfword(Instruction &inst, uint32_t bits) { - const MoveHW enc = { bits }; + const MoveHW enc = {bits}; // if d == 15 then UNPREDICTABLE; if (enc.rd == kPCRegNum) { @@ -2445,7 +2348,7 @@ static bool TryDecodeMoveHalfword(Instruction &inst, uint32_t bits) { //01 TEQ (register) //10 CMP (register) //11 CMN (register) -static const char * const kIntegerTestAndCompareR[] = { +static const char *const kIntegerTestAndCompareR[] = { [0b00] = "TSTr", [0b01] = "TEQr", [0b10] = "CMPr", @@ -2454,7 +2357,7 @@ static const char * const kIntegerTestAndCompareR[] = { // Integer Test and Compare (two register, immediate shift) static bool TryIntegerTestAndCompareRRI(Instruction &inst, uint32_t bits) { - const IntTestCompRRI enc = { bits }; + const IntTestCompRRI enc = {bits}; auto instruction = kIntegerTestAndCompareR[enc.opc]; @@ -2470,7 +2373,7 @@ static bool TryIntegerTestAndCompareRRI(Instruction &inst, uint32_t bits) { // Integer Test and Compare (two register, register shift) static bool TryIntegerTestAndCompareRRR(Instruction &inst, uint32_t bits) { - const IntTestCompRRR enc = { bits }; + const IntTestCompRRR enc = {bits}; if (enc.rn == kPCRegNum || enc.rs == kPCRegNum || enc.rm == kPCRegNum) { inst.category = Instruction::kCategoryError; @@ -2489,7 +2392,7 @@ static bool TryIntegerTestAndCompareRRR(Instruction &inst, uint32_t bits) { // Integer Test and Compare (one register and immediate) static bool TryIntegerTestAndCompareRI(Instruction &inst, uint32_t bits) { - const IntTestCompRI enc = { bits }; + const IntTestCompRI enc = {bits}; auto instruction = kIntegerTestAndCompareR[enc.opc]; @@ -2501,7 +2404,6 @@ static bool TryIntegerTestAndCompareRI(Instruction &inst, uint32_t bits) { inst.category = Instruction::kCategoryNormal; return true; - } // cond H @@ -2510,12 +2412,14 @@ static bool TryIntegerTestAndCompareRI(Instruction &inst, uint32_t bits) { //1111 BL, BLX (immediate) — A2 // Branch (immediate) static bool TryBranchImm(Instruction &inst, uint32_t bits) { - const BranchI enc = { bits }; + const BranchI enc = {bits}; auto is_cond = DecodeCondition(inst, enc.cond); auto is_func = false; + // PC used by the branch instruction is actually the address of the next instruction - auto target_pc = static_cast(inst.pc + 8 + static_cast(enc.imm24 << 2)); + auto target_pc = static_cast(inst.pc + 8 + + static_cast(enc.imm24 << 2)); if (enc.cond != 0b1111) { if (!enc.H) { target_pc = target_pc & ~0b11u; @@ -2570,20 +2474,21 @@ static bool TryBranchImm(Instruction &inst, uint32_t bits) { return true; } -static const char * const kBX[] = { +static const char *const kBX[] = { [0b01] = "BX", - [0b10] = "BXJ", // unsupported + [0b10] = "BXJ", // unsupported [0b11] = "BLX", }; static bool TryDecodeBX(Instruction &inst, uint32_t bits) { - const Misc enc = { bits }; + const Misc enc = {bits}; - if (enc.op1 == 0b10) { // BJX unsupported + if (enc.op1 == 0b10) { // BJX unsupported LOG(ERROR) << "BJX unsupported"; inst.category = Instruction::kCategoryError; return false; } else if (enc.op1 == 0b11 && enc.Rm == kPCRegNum) { + // if m == 15 then UNPREDICTABLE; inst.category = Instruction::kCategoryError; return false; @@ -2634,8 +2539,9 @@ static bool TryDecodeBX(Instruction &inst, uint32_t bits) { // Count Leading Zeros static bool TryDecodeCLZ(Instruction &inst, uint32_t bits) { - const Misc enc = { bits }; + const Misc enc = {bits}; if (enc.Rd == kPCRegNum || enc.Rm == kPCRegNum) { + // if d == 15 || m == 15 then UNPREDICTABLE; inst.category = Instruction::kCategoryError; return false; @@ -2650,7 +2556,7 @@ static bool TryDecodeCLZ(Instruction &inst, uint32_t bits) { return true; } -static const char * const kSatArith[] = { +static const char *const kSatArith[] = { [0b00] = "QADD", [0b01] = "QSUB", [0b10] = "QDADD", @@ -2660,7 +2566,8 @@ static const char * const kSatArith[] = { // Integer Saturating Arithmetic static bool TryDecodeIntegerSaturatingArithmetic(Instruction &inst, uint32_t bits) { - const IntSatArith enc = { bits }; + const IntSatArith enc = {bits}; + // if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; if (enc.Rd == kPCRegNum || enc.Rm == kPCRegNum || enc.Rn == kPCRegNum) { inst.category = Instruction::kCategoryError; @@ -2678,7 +2585,7 @@ static bool TryDecodeIntegerSaturatingArithmetic(Instruction &inst, // Saturate 16-bit static bool TryDecodeSat16(Instruction &inst, uint32_t bits) { - const Sat16 enc = { bits }; + const Sat16 enc = {bits}; DecodeCondition(inst, enc.cond); // if d == 15 || n == 15 then UNPREDICTABLE; @@ -2703,7 +2610,7 @@ static bool TryDecodeSat16(Instruction &inst, uint32_t bits) { // Saturate 32-bit static bool TryDecodeSat32(Instruction &inst, uint32_t bits) { - const Sat32 enc = { bits }; + const Sat32 enc = {bits}; DecodeCondition(inst, enc.cond); // if d == 15 || n == 15 then UNPREDICTABLE; @@ -2740,40 +2647,27 @@ static bool TryDecodeSat32(Instruction &inst, uint32_t bits) { // 1 10 1111 UXTB // 1 11 != 1111 UXTAH // 1 11 1111 UXTH -static const char * kExtAdd(uint32_t index) { - switch(index) { - case 0b0000: - return "SXTAB16"; - case 0b0001: - return "SXTB16"; - case 0b0100: - return "SXTAB"; - case 0b0101: - return "SXTB"; - case 0b0110: - return "SXTAH"; - case 0b0111: - return "SXTH"; - case 0b1000: - return "UXTAB16"; - case 0b1001: - return "UXTB16"; - case 0b1100: - return "UXTAB"; - case 0b1101: - return "UXTB"; - case 0b1110: - return "UXTAH"; - case 0b1111: - return "UXTH"; - default: - return nullptr; - } +static const char *kExtAdd(uint32_t index) { + switch (index) { + case 0b0000: return "SXTAB16"; + case 0b0001: return "SXTB16"; + case 0b0100: return "SXTAB"; + case 0b0101: return "SXTB"; + case 0b0110: return "SXTAH"; + case 0b0111: return "SXTH"; + case 0b1000: return "UXTAB16"; + case 0b1001: return "UXTB16"; + case 0b1100: return "UXTAB"; + case 0b1101: return "UXTB"; + case 0b1110: return "UXTAH"; + case 0b1111: return "UXTH"; + default: return nullptr; + } } // Extend and Add static bool TryExtAdd(Instruction &inst, uint32_t bits) { - const ExtAdd enc = { bits }; + const ExtAdd enc = {bits}; DecodeCondition(inst, enc.cond); auto instruction = kExtAdd(enc.U << 3 | enc.op << 1 | (enc.Rn == kPCRegNum)); @@ -2801,14 +2695,14 @@ static bool TryExtAdd(Instruction &inst, uint32_t bits) { // U // 0 SBFX // 1 UBFX -static const char * const kBitExt[] = { +static const char *const kBitExt[] = { [0b0] = "SBFX", [0b1] = "UBFX", }; // Bitfield Extract static bool TryBitExtract(Instruction &inst, uint32_t bits) { - const BitExt enc = { bits }; + const BitExt enc = {bits}; DecodeCondition(inst, enc.cond); inst.function = kBitExt[enc.U]; @@ -2816,9 +2710,8 @@ static bool TryBitExtract(Instruction &inst, uint32_t bits) { // if d == 15 || n == 15 then UNPREDICTABLE; // msbit = lsbit + widthminus1; // if msbit > 31 then UNPREDICTABLE; - if (enc.Rd == kPCRegNum - || enc.Rn == kPCRegNum - || (enc.lsb + enc.widthm1) > 31) { + if (enc.Rd == kPCRegNum || enc.Rn == kPCRegNum || + (enc.lsb + enc.widthm1) > 31) { inst.category = Instruction::kCategoryError; return false; } @@ -2862,32 +2755,34 @@ static bool TryBitExtract(Instruction &inst, uint32_t bits) { //11x1x x10 Bitfield Extract //11xxx 011 UNALLOCATED //11xxx x01 UNALLOCATED -static TryDecode * TryMedia(uint32_t bits) { - const Media enc = { bits }; +static TryDecode *TryMedia(uint32_t bits) { + const Media enc = {bits}; + // op0 | op1 switch (enc.op0 >> 3) { - case 0b00: // TODO(Sonya): Parallel Arithmetic + case 0b00: // TODO(Sonya): Parallel Arithmetic return nullptr; - case 0b10: - return TryDecodeSignedMultiplyDivide; + case 0b10: return TryDecodeSignedMultiplyDivide; } // TODO(Sonya) switch (enc.op0 << 3 | enc.op1) { case 0b01000101: + // SEL case 0b01000000: case 0b01000010: case 0b01000100: case 0b01000110: + // PKHBT, PKHTB return nullptr; case 0b01010001: - case 0b01110001: - return TryDecodeSat16; + case 0b01110001: return TryDecodeSat16; case 0b01011001: case 0b01011101: case 0b01111001: case 0b01111101: + // Reverse Bit/Byte return nullptr; case 0b01010000: @@ -2905,8 +2800,7 @@ static TryDecode * TryMedia(uint32_t bits) { case 0b01111000: case 0b01111010: case 0b01111100: - case 0b01111110: - return TryDecodeSat32; + case 0b01111110: return TryDecodeSat32; case 0b01000011: case 0b01001011: case 0b01010011: @@ -2914,16 +2808,18 @@ static TryDecode * TryMedia(uint32_t bits) { case 0b01100011: case 0b01101011: case 0b01110011: - case 0b01111011: - return TryExtAdd; + case 0b01111011: return TryExtAdd; case 0b11000000: + // Unsigned Sum of Absolute Differences case 0b11100000: case 0b11100100: case 0b11101000: case 0b11101100: + // Bitfield Insert case 0b11111111: + // Permanently UNDEFINED return nullptr; case 0b11010010: @@ -2933,10 +2829,8 @@ static TryDecode * TryMedia(uint32_t bits) { case 0b11110010: case 0b11110110: case 0b11111010: - case 0b11111110: - return TryBitExtract; - default: - return nullptr; + case 0b11111110: return TryBitExtract; + default: return nullptr; } } @@ -2960,39 +2854,37 @@ static TryDecode * TryMedia(uint32_t bits) { // 000 Move special register (register) // 100 Cyclic Redundancy Check // 101 Integer Saturating Arithmetic -static TryDecode * TryMiscellaneous(uint32_t bits) { - const Misc enc = { bits }; +static TryDecode *TryMiscellaneous(uint32_t bits) { + const Misc enc = {bits}; + // op0 | op1 switch (enc.op0 << 3 | enc.op1) { case 0b01001: case 0b01010: - case 0b01011: - return TryDecodeBX; - case 0b11001: - return TryDecodeCLZ; + case 0b01011: return TryDecodeBX; + case 0b11001: return TryDecodeCLZ; case 0b11110: // TODO(Sonya): ERET return nullptr; } // TODO(Sonya) switch (enc.op1) { - case 0b111: // Exception Generation - case 0b000: // Move special register (register) - case 0b100: // Cyclic Redundancy Check + case 0b111: // Exception Generation + case 0b000: // Move special register (register) + case 0b100: // Cyclic Redundancy Check return nullptr; - case 0b101: - return TryDecodeIntegerSaturatingArithmetic; + case 0b101: return TryDecodeIntegerSaturatingArithmetic; default: return nullptr; } } // Corresponds to Data-processing register (immediate shift) // op0<24 to 23> | op1 <20> -static TryDecode * kDataProcessingRI[] = { +static TryDecode *kDataProcessingRI[] = { [0b000] = TryDecodeIntegerDataProcessingRRRI, [0b001] = TryDecodeIntegerDataProcessingRRRI, [0b010] = TryDecodeIntegerDataProcessingRRRI, [0b011] = TryDecodeIntegerDataProcessingRRRI, - [0b100] = nullptr, // op0:op1 != 100 + [0b100] = nullptr, // op0:op1 != 100 [0b101] = TryIntegerTestAndCompareRRI, [0b110] = TryLogicalArithmeticRRRI, [0b111] = TryLogicalArithmeticRRRI, @@ -3000,12 +2892,12 @@ static TryDecode * kDataProcessingRI[] = { // Corresponds to Data-processing register (register shift) // op0<24 to 23> | op1 <20> -static TryDecode * kDataProcessingRR[] = { +static TryDecode *kDataProcessingRR[] = { [0b000] = TryDecodeIntegerDataProcessingRRRR, [0b001] = TryDecodeIntegerDataProcessingRRRR, [0b010] = TryDecodeIntegerDataProcessingRRRR, [0b011] = TryDecodeIntegerDataProcessingRRRR, - [0b100] = nullptr, // op0:op1 != 100 + [0b100] = nullptr, // op0:op1 != 100 [0b101] = TryIntegerTestAndCompareRRR, [0b110] = TryLogicalArithmeticRRRR, [0b111] = TryLogicalArithmeticRRRR, @@ -3013,7 +2905,7 @@ static TryDecode * kDataProcessingRR[] = { // Corresponds to Data-processing immediate // op0<24 to 23> | op1 <21 to 20> -static TryDecode * kDataProcessingI[] = { +static TryDecode *kDataProcessingI[] = { [0b0000] = TryDecodeIntegerDataProcessingRRI, [0b0001] = TryDecodeIntegerDataProcessingRRI, [0b0010] = TryDecodeIntegerDataProcessingRRI, @@ -3034,92 +2926,194 @@ static TryDecode * kDataProcessingI[] = { // Corresponds to: Load/Store Word, Unsigned Byte (immediate, literal) // o2<22> | o1<21> -static TryDecode * kLoadStoreWordUBIL[] = { - [0b00] = TryDecodeLoadStoreWordUBIL, - [0b01] = TryDecodeLoadStoreWordUBIL, - [0b10] = TryDecodeLoadStoreWordUBIL, - [0b11] = TryDecodeLoadStoreWordUBIL, +static TryDecode *kLoadStoreWordUBIL[] = { + [0b00] = TryDecodeLoadStoreWordUBIL, + [0b01] = TryDecodeLoadStoreWordUBIL, + [0b10] = TryDecodeLoadStoreWordUBIL, + [0b11] = TryDecodeLoadStoreWordUBIL, }; // Corresponds to: Load/Store Word, Unsigned Byte (register) // o2<22> | o1<21> -static TryDecode * kLoadStoreWordUBR[] = { - [0b00] = TryDecodeLoadStoreWordUBReg, - [0b01] = TryDecodeLoadStoreWordUBReg, - [0b10] = TryDecodeLoadStoreWordUBReg, - [0b11] = TryDecodeLoadStoreWordUBReg, +static TryDecode *kLoadStoreWordUBR[] = { + [0b00] = TryDecodeLoadStoreWordUBReg, + [0b01] = TryDecodeLoadStoreWordUBReg, + [0b10] = TryDecodeLoadStoreWordUBReg, + [0b11] = TryDecodeLoadStoreWordUBReg, }; // Extra load/store -static TryDecode * kExtraLoadStore[] = { - [0b000001] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b000010] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b000011] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b000101] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b000110] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b000111] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b001001] = TryDecodeLoadStoreDualHalfSignedBReg, +static TryDecode *kExtraLoadStore[] = { + [0b000001] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b000010] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b000011] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b000101] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b000110] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b000111] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b001001] = + TryDecodeLoadStoreDualHalfSignedBReg, [0b001010] = nullptr, [0b001011] = nullptr, - [0b001101] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b001110] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b001111] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b010001] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b010010] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b010011] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b010101] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b010110] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b010111] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b011001] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b011010] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b011011] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b011101] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b011110] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b011111] = TryDecodeLoadStoreDualHalfSignedBReg, - [0b100001] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b100010] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b100011] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b100101] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b100110] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b100111] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b101001] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b101010] = TryDecodeLoadStoreDualHalfSignedBIL, // only valid for Rn == 15 (PC) + [0b001101] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b001110] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b001111] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b010001] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b010010] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b010011] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b010101] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b010110] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b010111] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b011001] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b011010] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b011011] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b011101] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b011110] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b011111] = + TryDecodeLoadStoreDualHalfSignedBReg, + [0b100001] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b100010] = + TryDecodeLoadStoreDualHalfSignedBIL, + [0b100011] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b100101] = + TryDecodeLoadStoreDualHalfSignedBIL, + [0b100110] = + TryDecodeLoadStoreDualHalfSignedBIL, + [0b100111] = + TryDecodeLoadStoreDualHalfSignedBIL, + [0b101001] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b101010] = TryDecodeLoadStoreDualHalfSignedBIL< + Operand::kActionRead, Operand::kActionWrite, 16u, + true>, // only valid for Rn == 15 (PC) [0b101011] = nullptr, - [0b101101] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b101110] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b101111] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b110001] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b110010] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b110011] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b110101] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b110110] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b110111] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b111001] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b111010] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b111011] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b111101] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b111110] = TryDecodeLoadStoreDualHalfSignedBIL, - [0b111111] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b101101] = + TryDecodeLoadStoreDualHalfSignedBIL, + [0b101110] = + TryDecodeLoadStoreDualHalfSignedBIL, + [0b101111] = + TryDecodeLoadStoreDualHalfSignedBIL, + [0b110001] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b110010] = + TryDecodeLoadStoreDualHalfSignedBIL, + [0b110011] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b110101] = + TryDecodeLoadStoreDualHalfSignedBIL, + [0b110110] = + TryDecodeLoadStoreDualHalfSignedBIL, + [0b110111] = + TryDecodeLoadStoreDualHalfSignedBIL, + [0b111001] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b111010] = + TryDecodeLoadStoreDualHalfSignedBIL, + [0b111011] = TryDecodeLoadStoreDualHalfSignedBIL, + [0b111101] = + TryDecodeLoadStoreDualHalfSignedBIL, + [0b111110] = + TryDecodeLoadStoreDualHalfSignedBIL, + [0b111111] = + TryDecodeLoadStoreDualHalfSignedBIL, }; // Load Store Multiple

| | | -static TryDecode * kMLoadStore[] = { - [0b0000] = TryDecodeLoadStoreMultiple, //"STMDA", - [0b0001] = TryDecodeLoadStoreMultiple, //"LDMDA", - [0b0010] = nullptr, //"STMu", // (User registers) - [0b0011] = nullptr, //"LDM", // (User registers) || (exception return) - [0b0100] = TryDecodeLoadStoreMultiple, //"STM", - [0b0101] = TryDecodeLoadStoreMultiple, - [0b0110] = nullptr, //"STMu", // (User registers) - [0b0111] = nullptr, //"LDM", // (User registers) || (exception return) - [0b1000] = TryDecodeLoadStoreMultiple, - [0b1001] = TryDecodeLoadStoreMultiple, //"LDMDB", - [0b1010] = nullptr, //"STMu", // (User registers) - [0b1011] = nullptr, //"LDM", // (User registers) || (exception return) - [0b1100] = TryDecodeLoadStoreMultiple, //"STMIB", - [0b1101] = TryDecodeLoadStoreMultiple, //"LDMIB", - [0b1110] = nullptr, //"STMu", // (User registers) - [0b1111] = nullptr, //"LDM", // (User registers) || (exception return) +static TryDecode *kMLoadStore[] = { + [0b0000] = TryDecodeLoadStoreMultiple, //"STMDA", + [0b0001] = + TryDecodeLoadStoreMultiple, //"LDMDA", + [0b0010] = nullptr, //"STMu", // (User registers) + [0b0011] = nullptr, //"LDM", // (User registers) || (exception return) + [0b0100] = TryDecodeLoadStoreMultiple, //"STM", + [0b0101] = TryDecodeLoadStoreMultiple, + [0b0110] = nullptr, //"STMu", // (User registers) + [0b0111] = nullptr, //"LDM", // (User registers) || (exception return) + [0b1000] = + TryDecodeLoadStoreMultiple, + [0b1001] = + TryDecodeLoadStoreMultiple, //"LDMDB", + [0b1010] = nullptr, //"STMu", // (User registers) + [0b1011] = nullptr, //"LDM", // (User registers) || (exception return) + [0b1100] = TryDecodeLoadStoreMultiple, //"STMIB", + [0b1101] = + TryDecodeLoadStoreMultiple, //"LDMIB", + [0b1110] = nullptr, //"STMu", // (User registers) + [0b1111] = nullptr, //"LDM", // (User registers) || (exception return) }; // Corresponds to: Data-processing and miscellaneous instructions @@ -3132,25 +3126,31 @@ static TryDecode * kMLoadStore[] = { // 0 != 10xx0 0 Data-processing register (immediate shift) // 0 != 10xx0 0 1 Data-processing register (register shift) // 1 Data-processing immediate -static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { - const DataProcessingAndMisc enc = { bits }; +static TryDecode *TryDataProcessingAndMisc(uint32_t bits) { + const DataProcessingAndMisc enc = {bits}; + // op0 == 0 if (!enc.op0) { + // op2 == 1, op4 == 1 if (enc.op2 && enc.op4) { + // Extra load/store -- op3 != 00 if (enc.op3) { + // Index with <22> | P <24> | W <21> | o1 <20> | op2 != 00 <6:5> - return kExtraLoadStore[(((enc.op1 >> 2) & 0b1) << 5) - | ((enc.op1 >> 4) << 4) - | (((enc.op1 >> 1) & 0b1) << 3) - | ((enc.op1 & 0b1) << 2) - | enc.op3 ]; + return kExtraLoadStore[(((enc.op1 >> 2) & 0b1) << 5) | + ((enc.op1 >> 4) << 4) | + (((enc.op1 >> 1) & 0b1) << 3) | + ((enc.op1 & 0b1) << 2) | enc.op3]; + // op3 == 00 } else { + // Multiply and Accumulate -- op1 == 0xxxx if (!(enc.op1 >> 4)) { return TryDecodeMultiplyAndAccumulate; + // TODO(Sonya): Synchronization primitives and Load-Acquire/Store-Release -- op1 == 1xxxx } else { return nullptr; @@ -3158,20 +3158,25 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { } // op1 == 10xx0 } else if (((enc.op1 >> 3) == 0b10u) && !(enc.op1 & 0b00001u)) { + // Miscellaneous if (!enc.op2) { return TryMiscellaneous(bits); + // Halfword Multiply and Accumulate } else { return TryHalfwordDecodeMultiplyAndAccumulate; } // op1 != 10xx0 } else { + // Data-processing register (immediate shift) -- op4 == 0 if (!enc.op4) { + // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 lowest bit // index is the concatenation of op0 and op1 return kDataProcessingRI[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; + // Data-processing register (register shift) -- op4 == 1 } else { return kDataProcessingRR[(enc.op1 >> 2) | (enc.op1 & 0b1u)]; @@ -3179,6 +3184,7 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { } // Data-processing immediate -- op0 == 1 } else { + // op0 -> enc.op1 2 high order bits, op1 -> enc.op1 2 lowest bits // index is the concatenation of op0 and op1 return kDataProcessingI[((enc.op1 >> 1) & 0b1100u) | (enc.op1 & 0b11u)]; @@ -3196,22 +3202,27 @@ static TryDecode * TryDataProcessingAndMisc(uint32_t bits) { // 10x Branch, branch with link, and block data transfer // 11x System register access, Advanced SIMD, floating-point, and Supervisor call // 1111 0xx Unconditional instructions -static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { - const TopLevelEncodings enc = { bits }; +static TryDecode *TryDecodeTopLevelEncodings(uint32_t bits) { + const TopLevelEncodings enc = {bits}; + // op0 == 0xx if (!(enc.op0 >> 2)) { if (enc.cond != 0b1111u) { + // Data-processing and miscellaneous instructions -- op0 == 00x if (!(enc.op0 >> 1)) { return TryDataProcessingAndMisc(bits); + // Load/Store Word, Unsigned Byte (immediate, literal) -- op0 == 010 } else if (enc.op0 == 0b010u) { - const LoadStoreWUBIL enc_ls_word = { bits }; + const LoadStoreWUBIL enc_ls_word = {bits}; return kLoadStoreWordUBIL[enc_ls_word.o2 << 1u | enc_ls_word.o1]; + // Load/Store Word, Unsigned Byte (register) -- op0 == 011, op1 == 0 } else if (!enc.op1) { - const LoadStoreWUBR enc_ls_word = { bits }; + const LoadStoreWUBR enc_ls_word = {bits}; return kLoadStoreWordUBR[enc_ls_word.o2 << 1u | enc_ls_word.o1]; + // Media instructions -- op0 == 011, op1 == 1 } else { return TryMedia(bits); @@ -3222,19 +3233,23 @@ static TryDecode * TryDecodeTopLevelEncodings(uint32_t bits) { } // op0 == 1xx } else { + // Branch, branch with link, and block data transfer -- op0 == 10x if (enc.op0 >> 1 == 0b10u) { + // Branch (immediate) op0 == 101 if (enc.op0 == 0b101u) { return TryBranchImm; + // TODO(Sonya): Exception Save/Restore -- cond == 1111, op0 == 100 } else if (enc.cond == 0b1111u) { return nullptr; + // Load/Store Multiple -- cond != 1111, op0 == 100 } else { - const LoadStoreM enc_ls_word = { bits }; - return kMLoadStore[enc_ls_word.P << 3 | enc_ls_word.U << 2 - | enc_ls_word.op << 1 | enc_ls_word.L]; + const LoadStoreM enc_ls_word = {bits}; + return kMLoadStore[enc_ls_word.P << 3 | enc_ls_word.U << 2 | + enc_ls_word.op << 1 | enc_ls_word.L]; } // TODO(Sonya): System register access, Advanced SIMD, floating-point, and Supervisor call -- op0 == 11x } else { @@ -3251,10 +3266,11 @@ static uint32_t BytesToBits(const uint8_t *bytes) { bits = (bits << 8) | static_cast(bytes[0]); return bits; } -} // namespace +} // namespace // Decode an instruction -bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes, +bool AArch32Arch::DecodeInstruction(uint64_t address, + std::string_view inst_bytes, Instruction &inst) const { inst.pc = address; @@ -3291,4 +3307,4 @@ bool AArch32Arch::DecodeInstruction(uint64_t address, std::string_view inst_byte return ret; } -} // namespace remill +} // namespace remill diff --git a/lib/Arch/AArch32/Runtime/Instructions.cpp b/lib/Arch/AArch32/Runtime/Instructions.cpp index b64847023..1bfd77b9c 100644 --- a/lib/Arch/AArch32/Runtime/Instructions.cpp +++ b/lib/Arch/AArch32/Runtime/Instructions.cpp @@ -63,11 +63,14 @@ DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; #include "lib/Arch/AArch32/Semantics/LOGICAL.cpp" #include "lib/Arch/AArch32/Semantics/BITBYTE.cpp" #include "lib/Arch/AArch32/Semantics/BRANCH.cpp" + //#include "lib/Arch/AArch32/Semantics/CALL_RET.cpp" #include "lib/Arch/AArch32/Semantics/COND.cpp" + //#include "lib/Arch/AArch32/Semantics/CONVERT.cpp" //#include "lib/Arch/AArch32/Semantics/DATAXFER.cpp" #include "lib/Arch/AArch32/Semantics/MISC.cpp" + //#include "lib/Arch/AArch32/Semantics/SHIFT.cpp" //#include "lib/Arch/AArch32/Semantics/SIMD.cpp" //#include "lib/Arch/AArch32/Semantics/SYSTEM.cpp" diff --git a/lib/Arch/AArch32/Semantics/BINARY.cpp b/lib/Arch/AArch32/Semantics/BINARY.cpp index 0cd6ad97c..ebd88b945 100644 --- a/lib/Arch/AArch32/Semantics/BINARY.cpp +++ b/lib/Arch/AArch32/Semantics/BINARY.cpp @@ -41,6 +41,7 @@ DEF_COND_SEM(ANDS, R32W dst, R32 src1, I32 src2, I8 carry_out) { state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); state.sr.c = Read(carry_out); + // PSTATE.V unchanged return memory; } @@ -58,6 +59,7 @@ DEF_COND_SEM(EORS, R32W dst, R32 src1, I32 src2, I8 carry_out) { state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); state.sr.c = Read(carry_out); + // PSTATE.V unchanged return memory; } @@ -106,7 +108,7 @@ DEF_COND_SEM(ADDS, R32W dst, R32 src1, I32 src2, I8 carry_out) { DEF_COND_SEM(ADC, R32W dst, R32 src1, I32 src2) { auto value = Read(src2); - Write(dst, UAdd(UAdd(Read(src1),value), uint32_t(state.sr.c))); + Write(dst, UAdd(UAdd(Read(src1), value), uint32_t(state.sr.c))); return memory; } @@ -182,12 +184,14 @@ DEF_COND_SEM(MULS, R32W dst, R32 src1, R32 src2, R32 src3) { auto res = Unsigned(SAdd(SMul(lhs, rhs), acc)); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); + // PSTATE.C, PSTATE.V unchanged Write(dst, res); return memory; } -DEF_COND_SEM(UMAAL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { +DEF_COND_SEM(UMAAL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, + R32 src4) { auto rhs = ZExt(Read(src3)); auto lhs = ZExt(Read(src2)); auto acc_hi = ZExt(Read(src1)); @@ -207,52 +211,62 @@ DEF_COND_SEM(MLS, R32W dst, R32 src1, R32 src2, R32 src3) { return memory; } -DEF_COND_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { +DEF_COND_SEM(UMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, + R32 src4) { auto rhs = ZExt(Read(src3)); auto lhs = ZExt(Read(src2)); - auto acc = UOr(UShl(ZExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto acc = UOr(UShl(ZExt(Read(src1)), 32ul), + ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = UAdd(UMul(lhs, rhs), acc); Write(dst_hi, TruncTo(UShr(res, 32ul))); Write(dst_lo, TruncTo(res)); return memory; } -DEF_COND_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { +DEF_COND_SEM(UMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, + R32 src4) { auto rhs = ZExt(Read(src3)); auto lhs = ZExt(Read(src2)); - auto acc = UOr(UShl(ZExt(Read(src1)), 32ul), ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) + auto acc = UOr(UShl(ZExt(Read(src1)), 32ul), + ZExt(Read(src4))); // UInt(R[dHi]:R[dLo]) auto res = UAdd(UMul(lhs, rhs), acc); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); + // PSTATE.C, PSTATE.V unchanged Write(dst_hi, TruncTo(UShr(res, 32ul))); Write(dst_lo, TruncTo(res)); return memory; } -DEF_COND_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { +DEF_COND_SEM(SMULL, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, + R32 src4) { auto rhs = SExt(Signed(Read(src3))); auto lhs = SExt(Signed(Read(src2))); - auto acc = SOr(SShl(SExt(Read(src1)), 32ul), Signed(ZExt(Read(src4)))); // UInt(R[dHi]:R[dLo]) + auto acc = SOr(SShl(SExt(Read(src1)), 32ul), + Signed(ZExt(Read(src4)))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); Write(dst_hi, TruncTo(SShr(res, 32ul))); Write(dst_lo, TruncTo(res)); return memory; } -DEF_COND_SEM(SMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { +DEF_COND_SEM(SMULLS, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, + R32 src4) { auto rhs = SExt(Signed(Read(src3))); auto lhs = SExt(Signed(Read(src2))); - auto acc = SOr(SShl(SExt(Read(src1)), 32ul), Signed(ZExt(Read(src4)))); // UInt(R[dHi]:R[dLo]) + auto acc = SOr(SShl(SExt(Read(src1)), 32ul), + Signed(ZExt(Read(src4)))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); + // PSTATE.C, PSTATE.V unchanged Write(dst_hi, TruncTo(SShr(res, 32ul))); Write(dst_lo, TruncTo(res)); return memory; } -} // namespace +} // namespace DEF_ISEL(MUL) = MUL; DEF_ISEL(MULS) = MULS; @@ -281,15 +295,14 @@ DEF_COND_SEM(SMLAh, R32W dst, R32 src1, R32 src2, R32 src3) { // if result != SInt(result<31:0>) then // Signed overflow // PSTATE.Q = '1'; - state.sr.q = Select(SCmpNeq(res, SExt(trun_res)), - uint8_t(1), state.sr.q); + state.sr.q = Select(SCmpNeq(res, SExt(trun_res)), uint8_t(1), state.sr.q); return memory; } DEF_COND_SEM(SMULWh, R32W dst, R32 src1, R32 src2) { auto rhs = SExt(Signed(Read(src2))); auto lhs = SExt(Signed(Read(src1))); - auto res = SShr(SMul(lhs, rhs), 16ul); // R[d] = result<47:16> + auto res = SShr(SMul(lhs, rhs), 16ul); // R[d] = result<47:16> auto trun_res = TruncTo(res); Write(dst, trun_res); return memory; @@ -298,15 +311,14 @@ DEF_COND_SEM(SMULWh, R32W dst, R32 src1, R32 src2) { DEF_COND_SEM(SMLAWh, R32W dst, R32 src1, R32 src2, R32 src3) { auto rhs = SExt(Signed(Read(src2))); auto lhs = SExt(Signed(Read(src1))); - auto acc = SShl(SExt(Signed(Read(src3))), 16ul); // SInt(R[a]) << 16 - auto res = SShr(SAdd(SMul(lhs, rhs), acc), 16ul); // R[d] = result<47:16> + auto acc = SShl(SExt(Signed(Read(src3))), 16ul); // SInt(R[a]) << 16 + auto res = SShr(SAdd(SMul(lhs, rhs), acc), 16ul); // R[d] = result<47:16> auto trun_res = TruncTo(res); Write(dst, trun_res); // if (result >> 16) != SInt(R[d]) then // Signed overflow // PSTATE.Q = '1'; - state.sr.q = Select(SCmpNeq(res, SExt(trun_res)), - uint8_t(1), state.sr.q); + state.sr.q = Select(SCmpNeq(res, SExt(trun_res)), uint8_t(1), state.sr.q); return memory; } @@ -316,20 +328,23 @@ DEF_COND_SEM(SMULh, R32W dst, R32 src1, R32 src2) { auto res = SMul(lhs, rhs); Write(dst, TruncTo(res)); return memory; + // Signed overflow cannot occur } -DEF_COND_SEM(SMLALh, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, R32 src4) { +DEF_COND_SEM(SMLALh, R32W dst_hi, R32W dst_lo, R32 src1, R32 src2, R32 src3, + R32 src4) { auto rhs = SExt(Signed(Read(src3))); auto lhs = SExt(Signed(Read(src2))); - auto acc = SOr(SShl(SExt(Signed(Read(src1))), 32ul), Signed(ZExt(Read(src4)))); // UInt(R[dHi]:R[dLo]) + auto acc = SOr(SShl(SExt(Signed(Read(src1))), 32ul), + Signed(ZExt(Read(src4)))); // UInt(R[dHi]:R[dLo]) auto res = SAdd(SMul(lhs, rhs), acc); Write(dst_hi, TruncTo(SShr(res, 32ul))); Write(dst_lo, TruncTo(res)); return memory; } -}// namespace +} // namespace DEF_ISEL(SMLABB) = SMLAh; DEF_ISEL(SMLABT) = SMLAh; @@ -404,7 +419,7 @@ DEF_COND_SEM(SSAT16, R32W dst, I32 imm1, R32 src1) { Write(dst, Unsigned(res)); return memory; } -} // namespace +} // namespace DEF_ISEL(USAT) = USAT; DEF_ISEL(SSAT) = SSAT; @@ -450,7 +465,7 @@ DEF_COND_SEM(QDSUB, R32W dst, R32 src1, R32 src2) { Write(dst, Trunc(Unsigned(res))); return memory; } -} // namespace +} // namespace DEF_ISEL(QADD) = QADD; DEF_ISEL(QDADD) = QDADD; @@ -459,43 +474,42 @@ DEF_ISEL(QDSUB) = QDSUB; // TODO Signed multiply, Divide namespace { -DEF_COND_SEM(SMLAD, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm ra +DEF_COND_SEM(SMLAD, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm ra auto rn = Signed(Read(src1)); auto rm = Signed(Read(src2)); auto ra = Signed(Read(src3)); - auto prod1 = SMul(SExtTo(Trunc(rn)), - SExtTo(Trunc(rm))); - auto prod2 = SMul(SExtTo(SShr(rn, 16u)), - SExtTo(SShr(rm, 16u))); + auto prod1 = SMul(SExtTo(Trunc(rn)), SExtTo(Trunc(rm))); + auto prod2 = + SMul(SExtTo(SShr(rn, 16u)), SExtTo(SShr(rm, 16u))); auto res = SAdd(SAdd(prod1, prod2), SExt(ra)); WriteTrunc(dst, Unsigned(res)); // if result != SInt(result<31:0>) then // Signed overflow // PSTATE.Q = '1'; - state.sr.q = Select(SCmpNeq(res, SExtTo(Trunc(res))), - uint8_t(1), state.sr.q); + state.sr.q = + Select(SCmpNeq(res, SExtTo(Trunc(res))), uint8_t(1), state.sr.q); return memory; } -DEF_COND_SEM(SMLSD, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm ra +DEF_COND_SEM(SMLSD, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm ra auto rn = Signed(Read(src1)); auto rm = Signed(Read(src2)); auto ra = Signed(Read(src3)); auto prod1 = SMul(SExtTo(Signed(Trunc(rn))), SExtTo(Signed(Trunc(rm)))); - auto prod2 = SMul(SExtTo(SShr(rn, 16u)), - SExtTo(SShr(rm, 16u))); + auto prod2 = + SMul(SExtTo(SShr(rn, 16u)), SExtTo(SShr(rm, 16u))); auto res = SAdd(SSub(prod1, prod2), SExt(ra)); WriteTrunc(dst, Unsigned(res)); // if result != SInt(result<31:0>) then // Signed overflow // PSTATE.Q = '1'; - state.sr.q = Select(SCmpNeq(res, SExtTo(Trunc(res))), - uint8_t(1), state.sr.q); + state.sr.q = + Select(SCmpNeq(res, SExtTo(Trunc(res))), uint8_t(1), state.sr.q); return memory; } -DEF_COND_SEM(SDIV, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm +DEF_COND_SEM(SDIV, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm auto rn = Signed(Read(src1)); auto rm = Signed(Read(src2)); if (!rm) { @@ -506,7 +520,7 @@ DEF_COND_SEM(SDIV, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm return memory; } -DEF_COND_SEM(UDIV, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm +DEF_COND_SEM(UDIV, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm auto rn = Read(src1); auto rm = Read(src2); if (!rm) { @@ -517,30 +531,30 @@ DEF_COND_SEM(UDIV, R32W dst, R32 src1, R32 src2, R32 src3) { // rn rm return memory; } -DEF_COND_SEM(SMLALD, R32W dst_lo, R32W dst_hi, R32 src1, R32 src2, R32 src3, R32 src4) { // ra - lo rd - hi rn rm ra - lo rd - hi +DEF_COND_SEM(SMLALD, R32W dst_lo, R32W dst_hi, R32 src1, R32 src2, R32 src3, + R32 src4) { // ra - lo rd - hi rn rm ra - lo rd - hi auto rn = Signed(Read(src1)); auto rm = Signed(Read(src2)); auto lo = SExt(Signed(Read(src3))); auto hi = SExt(Signed(Read(src4))); - auto prod1 = SMul(SExtTo(Trunc(rn)), - SExtTo(Trunc(rm))); - auto prod2 = SMul(SExtTo(SShr(rn, 16u)), - SExtTo(SShr(rm, 16u))); + auto prod1 = SMul(SExtTo(Trunc(rn)), SExtTo(Trunc(rm))); + auto prod2 = + SMul(SExtTo(SShr(rn, 16u)), SExtTo(SShr(rm, 16u))); auto res = SAdd(SAdd(prod1, prod2), SOr(lo, SShl(hi, 32u))); WriteTrunc(dst_lo, Unsigned(res)); WriteTrunc(dst_hi, Unsigned(SShr(res, 32u))); return memory; } -DEF_COND_SEM(SMLSLD, R32W dst_lo, R32W dst_hi, R32 src1, R32 src2, R32 src3, R32 src4) { // ra - lo rd - hi rn rm ra - lo rd - hi +DEF_COND_SEM(SMLSLD, R32W dst_lo, R32W dst_hi, R32 src1, R32 src2, R32 src3, + R32 src4) { // ra - lo rd - hi rn rm ra - lo rd - hi auto rn = Signed(Read(src1)); auto rm = Signed(Read(src2)); auto lo = SExt(Signed(Read(src3))); auto hi = SExt(Signed(Read(src4))); - auto prod1 = SMul(SExtTo(Trunc(rn)), - SExtTo(Trunc(rm))); - auto prod2 = SMul(SExtTo(SShr(rn, 16u)), - SExtTo(SShr(rm, 16u))); + auto prod1 = SMul(SExtTo(Trunc(rn)), SExtTo(Trunc(rm))); + auto prod2 = + SMul(SExtTo(SShr(rn, 16u)), SExtTo(SShr(rm, 16u))); auto res = SAdd(SSub(prod1, prod2), SOr(lo, SShl(hi, 32u))); WriteTrunc(dst_lo, Unsigned(res)); WriteTrunc(dst_hi, Unsigned(SShr(res, 32u))); @@ -566,7 +580,7 @@ DEF_COND_SEM(SMMLS, R32W dst, R32 src1, R32 src2, R32 src3, I32 src4) { WriteTrunc(dst, Unsigned(res)); return memory; } -} // namespace +} // namespace DEF_ISEL(SMLAD) = SMLAD; DEF_ISEL(SMLADX) = SMLAD; @@ -611,10 +625,14 @@ DEF_COND_SEM(SXTAB16, R32W dst, R32 src1, R32 src2, I32 src3) { auto rot = Read(src3); src = ROR_C(src, rot, 32u); + // low/high 16 bits of rn + the low byte sign extended of the low/high 16 bits of rm - auto low = ZExt(UAdd(Trunc(src_add), Unsigned(SExtTo(Signed(TruncTo(src)))))); - auto high = SExt(UAdd(Trunc(UShr(src_add, 16u)), - Unsigned(SExtTo(Signed(TruncTo(UShr(src, 16u))))))); + auto low = + ZExt(UAdd(Trunc(src_add), + Unsigned(SExtTo(Signed(TruncTo(src)))))); + auto high = SExt(UAdd( + Trunc(UShr(src_add, 16u)), + Unsigned(SExtTo(Signed(TruncTo(UShr(src, 16u))))))); auto res = UOr(low, UShl(Unsigned(high), 16u)); Write(dst, res); @@ -627,9 +645,10 @@ DEF_COND_SEM(SXTAB, R32W dst, R32 src1, R32 src2, I32 src3) { auto rot = Read(src3); src = ROR_C(src, rot, 32u); + // Extract low byte - auto res = UAdd(Unsigned(SExtTo(Signed(TruncTo(src)))), - src_add); + auto res = + UAdd(Unsigned(SExtTo(Signed(TruncTo(src)))), src_add); Write(dst, res); return memory; @@ -641,8 +660,9 @@ DEF_COND_SEM(SXTAH, R32W dst, R32 src1, R32 src2, I32 src3) { auto rot = Read(src3); src = ROR_C(src, rot, 32u); + // Extract low 2 bytes and sign extend - auto res = UAdd(Unsigned(SExt(Signed(Trunc(src)))) , src_add); + auto res = UAdd(Unsigned(SExt(Signed(Trunc(src)))), src_add); Write(dst, res); return memory; @@ -654,6 +674,7 @@ DEF_COND_SEM(UXTAB16, R32W dst, R32 src1, R32 src2, I32 src3) { auto rot = Read(src3); src = ROR_C(src, rot, 32u); + // low/high 16 bits of rn + the low byte of the low/high 16 bits of rm auto low = ZExt(UAdd(Trunc(src_add), UAnd(Trunc(src), uint16_t(255u)))); auto high = ZExt(UAdd(Trunc(UShr(src_add, 16u)), @@ -670,8 +691,9 @@ DEF_COND_SEM(UXTAB, R32W dst, R32 src1, R32 src2, I32 src3) { auto rot = Read(src3); src = ROR_C(src, rot, 32u); + // Extract low byte i.e. 0b11111111 = 255 - auto res = UAdd(UAnd(src, uint32_t(255u)), src_add); + auto res = UAdd(UAnd(src, uint32_t(255u)), src_add); Write(dst, res); return memory; @@ -683,13 +705,14 @@ DEF_COND_SEM(UXTAH, R32W dst, R32 src1, R32 src2, I32 src3) { auto rot = Read(src3); src = ROR_C(src, rot, 32u); + // Extract low 2 bytes i.e. 0b1111111111111111 = 65535 auto res = UAdd(UAnd(src, uint32_t(65535u)), src_add); Write(dst, res); return memory; } -} +} // namespace DEF_ISEL(SXTAB16) = SXTAB16; DEF_ISEL(SXTB16) = SXTAB16; @@ -703,4 +726,3 @@ DEF_ISEL(UXTAB) = UXTAB; DEF_ISEL(UXTB) = UXTAB; DEF_ISEL(UXTAH) = UXTAH; DEF_ISEL(UXTH) = UXTAH; - diff --git a/lib/Arch/AArch32/Semantics/BITBYTE.cpp b/lib/Arch/AArch32/Semantics/BITBYTE.cpp index 3ad698b60..32b4a348e 100644 --- a/lib/Arch/AArch32/Semantics/BITBYTE.cpp +++ b/lib/Arch/AArch32/Semantics/BITBYTE.cpp @@ -20,7 +20,7 @@ DEF_COND_SEM(CLZ, R32W dst, R32 src) { WriteZExt(dst, count); return memory; } -} // namespace +} // namespace DEF_ISEL(CLZ) = CLZ; @@ -31,6 +31,7 @@ DEF_COND_SEM(SBFX, R32W dst, R32 src1, I32 src2, I32 src3) { auto lsbit = Read(src2); auto widthminus1 = Read(src3); auto msbit = Signed(lsbit + widthminus1); + // Extract and retain high bit sign of msbit // Shift lift to remove the high bits, then shift right to remove the low bits auto res = SShr(SShl(src, int32_t(31) - Signed(msbit)), @@ -44,13 +45,14 @@ DEF_COND_SEM(UBFX, R32W dst, R32 src1, I32 src2, I32 src3) { auto lsbit = Read(src2); auto widthminus1 = Read(src3); auto msbit = lsbit + widthminus1; + // Extract unsigned // Shift lift to remove the high bits, then shift right to remove the low bits auto res = UShr(UShl(src, uint32_t(31) - msbit), uint32_t(31) - widthminus1); Write(dst, res); return memory; } -} +} // namespace DEF_ISEL(SBFX) = SBFX; DEF_ISEL(UBFX) = UBFX; diff --git a/lib/Arch/AArch32/Semantics/BRANCH.cpp b/lib/Arch/AArch32/Semantics/BRANCH.cpp index d62834a92..422de5867 100644 --- a/lib/Arch/AArch32/Semantics/BRANCH.cpp +++ b/lib/Arch/AArch32/Semantics/BRANCH.cpp @@ -23,7 +23,7 @@ DEF_SEM(B, R8, R8W, I32 taken_pc, R32W next_pc_dst) { } DEF_SEM(BCOND, R8 cond, R8W branch_taken, I32 taken_pc, I32 not_taken_pc, - R32W next_pc_dst) { + R32W next_pc_dst) { auto c = Read(cond); auto new_pc = Select(c, Read(taken_pc), Read(not_taken_pc)); Write(REG_PC, new_pc); @@ -60,7 +60,7 @@ DEF_SEM(BLCOND, R8 cond, R8W branch_taken, PC target_addr, PC ret_addr, Write(branch_taken, c); return memory; } -} // namespace +} // namespace DEF_ISEL(B) = B; DEF_ISEL(BCOND) = BCOND; diff --git a/lib/Arch/AArch32/Semantics/COND.cpp b/lib/Arch/AArch32/Semantics/COND.cpp index b0a6e7adb..7e298c0af 100644 --- a/lib/Arch/AArch32/Semantics/COND.cpp +++ b/lib/Arch/AArch32/Semantics/COND.cpp @@ -21,6 +21,7 @@ DEF_COND_SEM(TST, R32 src1, I32 src2, I8 carry_out) { state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); state.sr.c = Read(carry_out); + // PSTATE.V unchanged return memory; } @@ -31,6 +32,7 @@ DEF_COND_SEM(TEQ, R32 src1, I32 src2, I8 carry_out) { state.sr.n = SignFlag(res); state.sr.z = ZeroFlag(res); state.sr.c = Read(carry_out); + // PSTATE.V unchanged return memory; } @@ -48,7 +50,7 @@ DEF_COND_SEM(CMN, R32 src1, I32 src2, I8 carry_out) { AddWithCarryNZCV(state, lhs, rhs, uint32_t(0)); return memory; } -} // namespace +} // namespace DEF_ISEL(TSTr) = TST; DEF_ISEL(TEQr) = TEQ; diff --git a/lib/Arch/AArch32/Semantics/FLAGS.cpp b/lib/Arch/AArch32/Semantics/FLAGS.cpp index 0432bf56f..dd6946c1c 100644 --- a/lib/Arch/AArch32/Semantics/FLAGS.cpp +++ b/lib/Arch/AArch32/Semantics/FLAGS.cpp @@ -148,11 +148,12 @@ struct Carry { }; ALWAYS_INLINE static void SetFPSRStatusFlags(State &state, int mask) { + // TODO(Sonya): Update these flags to work on AArch32 -// state.sr.ixc |= static_cast(0 != (mask & FE_INEXACT)); -// state.sr.ofc |= static_cast(0 != (mask & FE_OVERFLOW)); -// state.sr.ufc |= static_cast(0 != (mask & FE_UNDERFLOW)); -// state.sr.ioc |= static_cast(0 != (mask & FE_INVALID)); + // state.sr.ixc |= static_cast(0 != (mask & FE_INEXACT)); + // state.sr.ofc |= static_cast(0 != (mask & FE_OVERFLOW)); + // state.sr.ufc |= static_cast(0 != (mask & FE_UNDERFLOW)); + // state.sr.ioc |= static_cast(0 != (mask & FE_INVALID)); } template diff --git a/lib/Arch/AArch32/Semantics/LOGICAL.cpp b/lib/Arch/AArch32/Semantics/LOGICAL.cpp index 4229442c0..bdeb986cd 100644 --- a/lib/Arch/AArch32/Semantics/LOGICAL.cpp +++ b/lib/Arch/AArch32/Semantics/LOGICAL.cpp @@ -15,7 +15,7 @@ */ namespace { -DEF_COND_SEM(ORR, R32W dst, R32 src1, I32 src2){ +DEF_COND_SEM(ORR, R32W dst, R32 src1, I32 src2) { auto value = Read(src2); auto result = UOr(Read(src1), value); Write(dst, result); @@ -30,11 +30,12 @@ DEF_COND_SEM(ORRS, R32W dst, R32 src1, I32 src2, I8 carry_out) { state.sr.n = SignFlag(result); state.sr.z = ZeroFlag(result); state.sr.c = Read(carry_out); + // PSTATE.V unchanged return memory; } -DEF_COND_SEM(BIC, R32W dst, R32 src1, I32 src2){ +DEF_COND_SEM(BIC, R32W dst, R32 src1, I32 src2) { auto value = UNot(Read(src2)); auto result = UAnd(Read(src1), value); Write(dst, result); @@ -49,11 +50,12 @@ DEF_COND_SEM(BICS, R32W dst, R32 src1, I32 src2, I8 carry_out) { state.sr.n = SignFlag(result); state.sr.z = ZeroFlag(result); state.sr.c = Read(carry_out); + // PSTATE.V unchanged return memory; } -} // namespace +} // namespace DEF_ISEL(ORRrr) = ORR; DEF_ISEL(ORRSrr) = ORRS; @@ -67,12 +69,12 @@ DEF_ISEL(MVNSrr) = BICS; DEF_ISEL(MOVW) = ORR; namespace { -DEF_COND_SEM(MOVT, R32W dst, R32 src1, R32 src2){ +DEF_COND_SEM(MOVT, R32W dst, R32 src1, R32 src2) { auto value = ZExt(Trunc(Read(src1))); auto result = UOr(UShl(Read(src2), 16), value); Write(dst, result); return memory; } -} // namespace +} // namespace DEF_ISEL(MOVT) = MOVT; diff --git a/lib/Arch/AArch32/Semantics/MEM.cpp b/lib/Arch/AArch32/Semantics/MEM.cpp index 3fa7e5675..39e1b7fb4 100644 --- a/lib/Arch/AArch32/Semantics/MEM.cpp +++ b/lib/Arch/AArch32/Semantics/MEM.cpp @@ -15,6 +15,7 @@ */ namespace { + // Offset DEF_COND_SEM(STR, M32W dst, R32 src1) { auto src = Read(src1); @@ -79,7 +80,8 @@ DEF_COND_SEM(LDRBp, M8 src1, R32W dst, R32W dst_reg, R32 src2) { } DEF_COND_SEM(STRT, M32W dst, R32 src1, R32W dst_reg, R32 src2) { - memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + memory = __remill_sync_hyper_call(state, memory, + SyncHyperCall::kAArch32CheckNotEL2); auto src = Read(src1); auto new_val = Read(src2); Write(dst, TruncTo(src)); @@ -88,7 +90,8 @@ DEF_COND_SEM(STRT, M32W dst, R32 src1, R32W dst_reg, R32 src2) { } DEF_COND_SEM(STRTB, M8W dst, R32 src1, R32W dst_reg, R32 src2) { - memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + memory = __remill_sync_hyper_call(state, memory, + SyncHyperCall::kAArch32CheckNotEL2); auto src = Read(src1); auto new_val = Read(src2); Write(dst, TruncTo(src)); @@ -97,7 +100,8 @@ DEF_COND_SEM(STRTB, M8W dst, R32 src1, R32W dst_reg, R32 src2) { } DEF_COND_SEM(LDRT, M32 src1, R32W dst, R32W dst_reg, R32 src2) { - memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + memory = __remill_sync_hyper_call(state, memory, + SyncHyperCall::kAArch32CheckNotEL2); auto src = Read(src1); auto new_val = Read(src2); WriteZExt(dst, src); @@ -106,7 +110,8 @@ DEF_COND_SEM(LDRT, M32 src1, R32W dst, R32W dst_reg, R32 src2) { } DEF_COND_SEM(LDRTB, M8 src1, R32W dst, R32W dst_reg, R32 src2) { - memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + memory = __remill_sync_hyper_call(state, memory, + SyncHyperCall::kAArch32CheckNotEL2); auto src = Read(src1); auto new_val = Read(src2); WriteZExt(dst, src); @@ -114,7 +119,7 @@ DEF_COND_SEM(LDRTB, M8 src1, R32W dst, R32W dst_reg, R32 src2) { return memory; } -} // namespace +} // namespace DEF_ISEL(STR) = STR; DEF_ISEL(STRB) = STRB; @@ -130,6 +135,7 @@ DEF_ISEL(LDRT) = LDRT; DEF_ISEL(LDRBT) = LDRTB; namespace { + // Offset DEF_COND_SEM(STRH, M16W dst, R32 src1) { auto src = Read(src1); @@ -233,7 +239,8 @@ DEF_COND_SEM(LDRSHp, M16 src1, R32W dst, R32W dst_reg, R32 src2) { } DEF_COND_SEM(STRHT, M16W dst, R32 src1, R32W dst_reg, R32 src2) { - memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + memory = __remill_sync_hyper_call(state, memory, + SyncHyperCall::kAArch32CheckNotEL2); auto src = Read(src1); auto new_val = Read(src2); WriteTrunc(dst, src); @@ -242,7 +249,8 @@ DEF_COND_SEM(STRHT, M16W dst, R32 src1, R32W dst_reg, R32 src2) { } DEF_COND_SEM(LDRHT, M16 src1, R32W dst, R32W dst_reg, R32 src2) { - memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + memory = __remill_sync_hyper_call(state, memory, + SyncHyperCall::kAArch32CheckNotEL2); auto src = Read(src1); auto new_val = Read(src2); WriteZExt(dst, src); @@ -251,7 +259,8 @@ DEF_COND_SEM(LDRHT, M16 src1, R32W dst, R32W dst_reg, R32 src2) { } DEF_COND_SEM(LDRSBT, M8 src1, R32W dst, R32W dst_reg, R32 src2) { - memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + memory = __remill_sync_hyper_call(state, memory, + SyncHyperCall::kAArch32CheckNotEL2); auto src = Read(src1); auto new_val = Read(src2); WriteSExt(dst, src); @@ -260,7 +269,8 @@ DEF_COND_SEM(LDRSBT, M8 src1, R32W dst, R32W dst_reg, R32 src2) { } DEF_COND_SEM(LDRSHT, M16 src1, R32W dst, R32W dst_reg, R32 src2) { - memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAArch32CheckNotEL2); + memory = __remill_sync_hyper_call(state, memory, + SyncHyperCall::kAArch32CheckNotEL2); auto src = Read(src1); auto new_val = Read(src2); WriteSExt(dst, src); @@ -268,7 +278,7 @@ DEF_COND_SEM(LDRSHT, M16 src1, R32W dst, R32W dst_reg, R32 src2) { return memory; } -} // namespace +} // namespace DEF_ISEL(STRH) = STRH; DEF_ISEL(STRHp) = STRHp; @@ -350,7 +360,7 @@ DEF_COND_SEM(LDM, I16 reg_list, R32W dst, R32 dst_new, M32 src_mem, R32W dst0, DEF_COND_SEM(STMDB, I16 reg_list, R32W dst, R32 dst_new, M32W dst_mem, R32 src0, R32 src1, R32 src2, R32 src3, R32 src4, R32 src5, R32 src6, R32 src7, R32 src8, R32 src9, R32 src10, R32 src11, R32 src12, - R32 src13,R32 src14, R32 src15) { + R32 src13, R32 src14, R32 src15) { auto regs = Read(reg_list); uint32_t index = 0; if (UAnd(regs, uint16_t(0b1u))) { @@ -404,17 +414,19 @@ DEF_COND_SEM(STMDB, I16 reg_list, R32W dst, R32 dst_new, M32W dst_mem, R32 src0, Write(dst, Read(dst_new)); return memory; } -} // namespace +} // namespace DEF_ISEL(STMDA) = STMDB; DEF_ISEL(LDMDA) = LDM; DEF_ISEL(STM) = STMDB; DEF_ISEL(LDM) = LDM; + //DEF_ISEL(STMu) = STMu; DEF_ISEL(STMDB) = STMDB; DEF_ISEL(LDMDB) = LDM; + //DEF_ISEL(LDMu) = LDMu; DEF_ISEL(STMIB) = STMDB; DEF_ISEL(LDMIB) = LDM; -//DEF_ISEL(LDMe) = LDMe; +//DEF_ISEL(LDMe) = LDMe; diff --git a/lib/Arch/AArch64/Arch.cpp b/lib/Arch/AArch64/Arch.cpp index eee339e7d..08dcb1174 100644 --- a/lib/Arch/AArch64/Arch.cpp +++ b/lib/Arch/AArch64/Arch.cpp @@ -33,6 +33,7 @@ #define REMILL_AARCH_STRICT_REGNUM +#include "Decode.h" #include "remill/Arch/Arch.h" #include "remill/Arch/Instruction.h" #include "remill/Arch/Name.h" @@ -41,13 +42,11 @@ #include "remill/BC/Version.h" #include "remill/OS/OS.h" - -#include "Decode.h" - // clang-format off #define ADDRESS_SIZE_BITS 64 #define INCLUDED_FROM_REMILL #include "remill/Arch/AArch64/Runtime/State.h" + // clang-format on namespace remill { @@ -461,7 +460,8 @@ void AArch64Arch::PopulateBasicBlockFunction(llvm::Module *module, const auto pc_arg = NthArgument(bb_func, kPCArgNum); const auto state_ptr_arg = NthArgument(bb_func, kStatePointerArgNum); - llvm::StringRef next_pc_name(kNextPCVariableName.data(), kNextPCVariableName.size()); + llvm::StringRef next_pc_name(kNextPCVariableName.data(), + kNextPCVariableName.size()); ir.CreateStore(pc_arg, ir.CreateAlloca(addr, nullptr, next_pc_name)); ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "WZR")); @@ -1859,7 +1859,7 @@ bool TryDecodeBL_ONLY_BRANCH_IMM(const InstData &data, Instruction &inst) { (data.imm26.simm26 << 2ULL)); inst.branch_not_taken_pc = inst.next_pc; AddPCDisp(inst, data.imm26.simm26 << 2LL); - DecodeFallThroughPC(inst); // Decodes the return address. + DecodeFallThroughPC(inst); // Decodes the return address. return true; } diff --git a/lib/Arch/AArch64/Semantics/BRANCH.cpp b/lib/Arch/AArch64/Semantics/BRANCH.cpp index faa3a2338..d7913521d 100644 --- a/lib/Arch/AArch64/Semantics/BRANCH.cpp +++ b/lib/Arch/AArch64/Semantics/BRANCH.cpp @@ -189,7 +189,8 @@ DEF_SEM(TBZ, I8 bit_pos, R8W cond, PC taken, PC not_taken, S src, R64W pc_dst) { } template -DEF_SEM(TBNZ, I8 bit_pos, R8W cond, PC taken, PC not_taken, S src, R64W pc_dst) { +DEF_SEM(TBNZ, I8 bit_pos, R8W cond, PC taken, PC not_taken, S src, + R64W pc_dst) { addr_t taken_pc = Read(taken); addr_t not_taken_pc = Read(not_taken); auto bit_n = ZExtTo(Read(bit_pos)); diff --git a/lib/Arch/Arch.cpp b/lib/Arch/Arch.cpp index 39276db16..f8edc21e9 100644 --- a/lib/Arch/Arch.cpp +++ b/lib/Arch/Arch.cpp @@ -82,14 +82,12 @@ static unsigned AddressSize(ArchName arch_name) { case kArchX86_AVX: case kArchX86_AVX512: case kArchAArch32LittleEndian: - case kArchSparc32: - return 32; + case kArchSparc32: return 32; case kArchAMD64: case kArchAMD64_AVX: case kArchAMD64_AVX512: case kArchAArch64LittleEndian: - case kArchSparc64: - return 64; + case kArchSparc64: return 64; } return 0; } @@ -221,8 +219,8 @@ auto Arch::Get(llvm::LLVMContext &context, std::string_view os, return Arch::Build(&context, GetOSName(os), GetArchName(arch_name)); } -auto Arch::Get(llvm::LLVMContext &context, OSName os, - ArchName arch_name) -> ArchPtr { +auto Arch::Get(llvm::LLVMContext &context, OSName os, ArchName arch_name) + -> ArchPtr { return Arch::Build(&context, os, arch_name); } @@ -288,8 +286,8 @@ void Arch::ForEachRegister(std::function cb) const { // Return information about a register, given its name. const Register *Arch::RegisterByName(std::string_view name_) const { std::string name(name_.data(), name_.size()); - auto [curr_val_it, added] = impl->reg_by_name.emplace(std::move(name), - nullptr); + auto [curr_val_it, added] = + impl->reg_by_name.emplace(std::move(name), nullptr); if (added) { return nullptr; } else { @@ -648,9 +646,9 @@ void Arch::PrepareModule(llvm::Module *mod) const { PrepareModuleDataLayout(mod); } -const Register *Arch::AddRegister( - const char *reg_name_, llvm::Type *val_type, size_t offset, - const char *parent_reg_name) const { +const Register *Arch::AddRegister(const char *reg_name_, llvm::Type *val_type, + size_t offset, + const char *parent_reg_name) const { const std::string reg_name(reg_name_); auto ® = impl->reg_by_name[reg_name]; @@ -670,8 +668,8 @@ const Register *Arch::AddRegister( gep_index_list.push_back( llvm::Constant::getNullValue(llvm::Type::getInt32Ty(*context))); - auto [gep_offset, gep_type_at_offset] = BuildIndexes( - dl, impl->state_type, 0, offset, gep_index_list); + auto [gep_offset, gep_type_at_offset] = + BuildIndexes(dl, impl->state_type, 0, offset, gep_index_list); if (!val_type) { CHECK_EQ(gep_offset, offset); @@ -716,7 +714,8 @@ void Arch::InitFromSemanticsModule(llvm::Module *module) const { const auto &dl = module->getDataLayout(); const auto basic_block = BasicBlockFunction(module); - const auto state_ptr_type = NthArgument(basic_block, kStatePointerArgNum)->getType(); + const auto state_ptr_type = + NthArgument(basic_block, kStatePointerArgNum)->getType(); const auto state_type = llvm::dyn_cast(state_ptr_type->getPointerElementType()); diff --git a/lib/Arch/Instruction.cpp b/lib/Arch/Instruction.cpp index 959fa35f2..93d6ca0f8 100644 --- a/lib/Arch/Instruction.cpp +++ b/lib/Arch/Instruction.cpp @@ -17,6 +17,8 @@ #include "remill/Arch/Instruction.h" #include +#include +#include #include #include @@ -24,8 +26,6 @@ #include "remill/Arch/Arch.h" #include "remill/Arch/Name.h" #include "remill/BC/Util.h" -#include -#include namespace remill { @@ -103,11 +103,15 @@ std::string Operand::Serialize(void) const { switch (shift_reg.shift_op) { case Operand::ShiftRegister::kShiftInvalid: break; - case Operand::ShiftRegister::kShiftLeftWithZeroes: ss << "(LSL "; break; + case Operand::ShiftRegister::kShiftLeftWithZeroes: + ss << "(LSL "; + break; case Operand::ShiftRegister::kShiftLeftWithOnes: ss << "(MSL "; break; - case Operand::ShiftRegister::kShiftUnsignedRight: ss << "(LSR "; break; + case Operand::ShiftRegister::kShiftUnsignedRight: + ss << "(LSR "; + break; case Operand::ShiftRegister::kShiftSignedRight: ss << "(ASR "; break; @@ -125,8 +129,7 @@ std::string Operand::Serialize(void) const { auto extract_begin = [&](void) { switch (shift_reg.extend_op) { - case Operand::ShiftRegister::kExtendInvalid: - break; + case Operand::ShiftRegister::kExtendInvalid: break; case Operand::ShiftRegister::kExtendSigned: ss << "(SEXT (TRUNC "; @@ -140,17 +143,14 @@ std::string Operand::Serialize(void) const { auto extract_end = [&](void) { switch (shift_reg.extend_op) { - case Operand::ShiftRegister::kExtendInvalid: - break; + case Operand::ShiftRegister::kExtendInvalid: break; case Operand::ShiftRegister::kExtendSigned: - ss << " " << shift_reg.extract_size << ") " - << size << ")"; + ss << " " << shift_reg.extract_size << ") " << size << ")"; break; case Operand::ShiftRegister::kExtendUnsigned: - ss << " " << shift_reg.extract_size << ") " - << size << ")"; + ss << " " << shift_reg.extract_size << ") " << size << ")"; break; } }; @@ -272,9 +272,7 @@ std::string Operand::Serialize(void) const { ss << ")"; // End of `(ADDR_`. break; } - case Operand::kTypeExpression: - ss << expr->Serialize(); - break; + case Operand::kTypeExpression: ss << expr->Serialize(); break; } ss << ")"; return ss.str(); @@ -295,10 +293,7 @@ std::string Condition::Serialize(void) const { case Condition::kTypeIsZero: ss << "(REG_" << lhs_reg.size << " " << lhs_reg.name << ") = 0"; break; - case Condition::kTypeTrue: - ss << "TRUE"; - break; - + case Condition::kTypeTrue: ss << "TRUE"; break; } return ss.str(); } @@ -337,55 +332,56 @@ void Instruction::Reset(void) { next_expr_index = 0; } -OperandExpression * Instruction::AllocateExpression(void) { +OperandExpression *Instruction::AllocateExpression(void) { CHECK_LT(next_expr_index, kMaxNumExpr); return &(exprs[next_expr_index++]); } -OperandExpression* Instruction::EmplaceRegister(const Register * reg) { +OperandExpression *Instruction::EmplaceRegister(const Register *reg) { auto expr = AllocateExpression(); expr->emplace(reg); expr->type = reg->type; return expr; } -OperandExpression * Instruction::EmplaceRegister(std::string_view reg_name) { +OperandExpression *Instruction::EmplaceRegister(std::string_view reg_name) { return EmplaceRegister(arch->RegisterByName(reg_name)); } -OperandExpression* Instruction::EmplaceConstant(llvm::Constant * val) { +OperandExpression *Instruction::EmplaceConstant(llvm::Constant *val) { auto expr = AllocateExpression(); expr->emplace(val); expr->type = val->getType(); return expr; } -OperandExpression* Instruction::EmplaceVariable(std::string_view var_name, llvm::Type * type) { +OperandExpression *Instruction::EmplaceVariable(std::string_view var_name, + llvm::Type *type) { auto expr = AllocateExpression(); expr->emplace(var_name.data(), var_name.size()); expr->type = type; return expr; } -OperandExpression* Instruction::EmplaceBinaryOp(unsigned opcode, - OperandExpression *op1, - OperandExpression *op2) { +OperandExpression *Instruction::EmplaceBinaryOp(unsigned opcode, + OperandExpression *op1, + OperandExpression *op2) { auto expr = AllocateExpression(); expr->emplace(LLVMOpExpr{opcode, op1, op2}); expr->type = op1->type; return expr; } -OperandExpression* Instruction::EmplaceUnaryOp(unsigned opcode, - OperandExpression *op1, - llvm::Type* type) { +OperandExpression *Instruction::EmplaceUnaryOp(unsigned opcode, + OperandExpression *op1, + llvm::Type *type) { auto expr = AllocateExpression(); expr->emplace(LLVMOpExpr{opcode, op1, nullptr}); expr->type = type; return expr; } -Operand & Instruction::EmplaceOperand(const Operand::Register ®_op) { +Operand &Instruction::EmplaceOperand(const Operand::Register ®_op) { operands.emplace_back(); auto &op = operands.back(); op.type = Operand::kTypeExpression; @@ -406,7 +402,8 @@ Operand &Instruction::EmplaceOperand(const Operand::Immediate &imm_op) { auto &context = *arch->context; auto ty = llvm::Type::getIntNTy(context, arch->address_size); - op.expr = EmplaceConstant(llvm::ConstantInt::get(ty, imm_op.val, imm_op.is_signed)); + op.expr = + EmplaceConstant(llvm::ConstantInt::get(ty, imm_op.val, imm_op.is_signed)); op.size = arch->address_size; op.type = Operand::kTypeExpression; return op; @@ -438,8 +435,7 @@ Operand &Instruction::EmplaceOperand(const Operand::ShiftRegister &shift_op) { auto do_extract = [&](void) { if (Operand::ShiftRegister::kExtendInvalid != shift_op.extend_op) { - auto extract_type = - llvm::Type::getIntNTy(context, shift_op.extract_size); + auto extract_type = llvm::Type::getIntNTy(context, shift_op.extract_size); if (reg_size > shift_op.extract_size) { curr_size = shift_op.extract_size; @@ -449,8 +445,8 @@ Operand &Instruction::EmplaceOperand(const Operand::ShiftRegister &shift_op) { CHECK(reg_size == shift_op.extract_size) << "Invalid extraction size. Can't extract " << shift_op.extract_size << " bits from a " << reg_size - << "-bit value in operand " << op.Serialize() << " of instruction at " - << std::hex << pc; + << "-bit value in operand " << op.Serialize() + << " of instruction at " << std::hex << pc; } if (op.size > shift_op.extract_size) { @@ -490,34 +486,41 @@ Operand &Instruction::EmplaceOperand(const Operand::ShiftRegister &shift_op) { // Left shift. case Operand::ShiftRegister::kShiftLeftWithZeroes: - expr = EmplaceBinaryOp(llvm::Instruction::Shl, expr, EmplaceConstant(shift_val)); + expr = EmplaceBinaryOp(llvm::Instruction::Shl, expr, + EmplaceConstant(shift_val)); break; // Masking shift left. case Operand::ShiftRegister::kShiftLeftWithOnes: { const auto mask_val = llvm::ConstantInt::get(reg_type, ~((~zero) << shift_size)); - expr = EmplaceBinaryOp(llvm::Instruction::Shl, expr, EmplaceConstant(shift_val)); - expr = EmplaceBinaryOp(llvm::Instruction::Or, expr, EmplaceConstant(mask_val)); + expr = EmplaceBinaryOp(llvm::Instruction::Shl, expr, + EmplaceConstant(shift_val)); + expr = EmplaceBinaryOp(llvm::Instruction::Or, expr, + EmplaceConstant(mask_val)); break; } // Logical right shift. case Operand::ShiftRegister::kShiftUnsignedRight: - expr = EmplaceBinaryOp(llvm::Instruction::LShr, expr, EmplaceConstant(shift_val)); + expr = EmplaceBinaryOp(llvm::Instruction::LShr, expr, + EmplaceConstant(shift_val)); break; // Arithmetic right shift. case Operand::ShiftRegister::kShiftSignedRight: - expr = EmplaceBinaryOp(llvm::Instruction::AShr, expr, EmplaceConstant(shift_val)); + expr = EmplaceBinaryOp(llvm::Instruction::AShr, expr, + EmplaceConstant(shift_val)); break; // Rotate left. case Operand::ShiftRegister::kShiftLeftAround: { const uint64_t shr_amount = (~shift_size + one) & (op.size - one); const auto shr_val = llvm::ConstantInt::get(op_type, shr_amount); - auto expr1 = EmplaceBinaryOp(llvm::Instruction::LShr, expr, EmplaceConstant(shr_val)); - auto expr2 = EmplaceBinaryOp(llvm::Instruction::Shl, expr, EmplaceConstant(shift_val)); + auto expr1 = EmplaceBinaryOp(llvm::Instruction::LShr, expr, + EmplaceConstant(shr_val)); + auto expr2 = EmplaceBinaryOp(llvm::Instruction::Shl, expr, + EmplaceConstant(shift_val)); expr = EmplaceBinaryOp(llvm::Instruction::Or, expr1, expr2); break; } @@ -526,8 +529,10 @@ Operand &Instruction::EmplaceOperand(const Operand::ShiftRegister &shift_op) { case Operand::ShiftRegister::kShiftRightAround: { const uint64_t shl_amount = (~shift_size + one) & (op.size - one); const auto shl_val = llvm::ConstantInt::get(op_type, shl_amount); - auto expr1 = EmplaceBinaryOp(llvm::Instruction::LShr, expr, EmplaceConstant(shift_val)); - auto expr2 = EmplaceBinaryOp(llvm::Instruction::Shl, expr, EmplaceConstant(shl_val)); + auto expr1 = EmplaceBinaryOp(llvm::Instruction::LShr, expr, + EmplaceConstant(shift_val)); + auto expr2 = EmplaceBinaryOp(llvm::Instruction::Shl, expr, + EmplaceConstant(shl_val)); expr = EmplaceBinaryOp(llvm::Instruction::Or, expr1, expr2); break; } @@ -552,7 +557,7 @@ Operand &Instruction::EmplaceOperand(const Operand::ShiftRegister &shift_op) { return op; } -Operand& Instruction::EmplaceOperand(const Operand::Address &addr_op) { +Operand &Instruction::EmplaceOperand(const Operand::Address &addr_op) { operands.emplace_back(); auto &op = operands.back(); @@ -560,22 +565,23 @@ Operand& Instruction::EmplaceOperand(const Operand::Address &addr_op) { const auto zero = llvm::ConstantInt::get(word_type, 0, false); const auto word_size = arch->address_size; - CHECK(word_size >= addr_op.base_reg.size)<< "Memory base register " - << addr_op.base_reg.name << "for instruction at " << std::hex << pc + CHECK(word_size >= addr_op.base_reg.size) + << "Memory base register " << addr_op.base_reg.name + << "for instruction at " << std::hex << pc << " is wider than the machine word size."; - CHECK(word_size >= addr_op.index_reg.size)<< "Memory index register " - << addr_op.base_reg.name << "for instruction at " << std::hex << pc + CHECK(word_size >= addr_op.index_reg.size) + << "Memory index register " << addr_op.base_reg.name + << "for instruction at " << std::hex << pc << " is wider than the machine word size."; - auto reg_or_zero = [=](const Operand::Register & reg) { + auto reg_or_zero = [=](const Operand::Register ®) { if (!reg.name.empty()) { if (auto reg_pointer = arch->RegisterByName(reg.name)) { return EmplaceRegister(reg_pointer); } else { - return EmplaceVariable( - reg.name, - llvm::Type::getIntNTy(*arch->context, reg.size)); + return EmplaceVariable(reg.name, + llvm::Type::getIntNTy(*arch->context, reg.size)); } } else { return EmplaceConstant(zero); @@ -587,23 +593,25 @@ Operand& Instruction::EmplaceOperand(const Operand::Address &addr_op) { if (!addr_op.index_reg.name.empty() && addr_op.scale) { auto index = reg_or_zero(addr_op.index_reg); if (addr_op.scale != 1) { - auto scale = llvm::ConstantInt::get(word_type, - static_cast(addr_op.scale), - true); - index = EmplaceBinaryOp(llvm::Instruction::Mul, index, EmplaceConstant(scale)); + auto scale = llvm::ConstantInt::get( + word_type, static_cast(addr_op.scale), true); + index = EmplaceBinaryOp(llvm::Instruction::Mul, index, + EmplaceConstant(scale)); } addr = EmplaceBinaryOp(llvm::Instruction::Add, addr, index); } if (addr_op.displacement) { if (0 < addr_op.displacement) { - auto disp = llvm::ConstantInt::get(word_type, - static_cast(addr_op.displacement)); - addr = EmplaceBinaryOp(llvm::Instruction::Add, addr, EmplaceConstant(disp)); + auto disp = llvm::ConstantInt::get( + word_type, static_cast(addr_op.displacement)); + addr = + EmplaceBinaryOp(llvm::Instruction::Add, addr, EmplaceConstant(disp)); } else { - auto disp = llvm::ConstantInt::get(word_type, - static_cast(-addr_op.displacement)); - addr = EmplaceBinaryOp(llvm::Instruction::Sub, addr, EmplaceConstant(disp)); + auto disp = llvm::ConstantInt::get( + word_type, static_cast(-addr_op.displacement)); + addr = + EmplaceBinaryOp(llvm::Instruction::Sub, addr, EmplaceConstant(disp)); } } diff --git a/lib/Arch/SPARC32/Arch.cpp b/lib/Arch/SPARC32/Arch.cpp index 0300a3c42..1d6b6c8d2 100644 --- a/lib/Arch/SPARC32/Arch.cpp +++ b/lib/Arch/SPARC32/Arch.cpp @@ -14,21 +14,22 @@ * limitations under the License. */ +#include "remill/Arch/Arch.h" + #include -#include "remill/Arch/Arch.h" +#include "Decode.h" #include "remill/Arch/Instruction.h" #include "remill/Arch/Name.h" #include "remill/BC/ABI.h" #include "remill/BC/Util.h" #include "remill/OS/OS.h" -#include "Decode.h" - // clang-format off #define ADDRESS_SIZE_BITS 32 #define INCLUDED_FROM_REMILL #include "remill/Arch/SPARC32/Runtime/State.h" + // clang-format on namespace remill { @@ -39,84 +40,72 @@ static const std::string_view kPCRegName = "pc"; } // namespace -const std::string_view kCCRName[4] = { - "icc", {}, "xcc", {} -}; +const std::string_view kCCRName[4] = {"icc", {}, "xcc", {}}; -const std::string_view kFCCRName[8] = { - "fcc0", "fcc1", "fcc2", "fcc3", - "icc", {}, "xcc", {} -}; +const std::string_view kFCCRName[8] = {"fcc0", "fcc1", "fcc2", "fcc3", + "icc", {}, "xcc", {}}; const std::string_view kReadIntRegName[32] = { - "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", - "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", - "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", - "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7" -}; - -const std::string_view kWriteIntRegName[32] = { - "ignore_write_to_g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", - "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", - "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", - "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7" -}; + "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", "o0", "o1", "o2", + "o3", "o4", "o5", "sp", "o7", "l0", "l1", "l2", "l3", "l4", "l5", + "l6", "l7", "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"}; + +const std::string_view kWriteIntRegName[32] = {"ignore_write_to_g0", + "g1", + "g2", + "g3", + "g4", + "g5", + "g6", + "g7", + "o0", + "o1", + "o2", + "o3", + "o4", + "o5", + "o6", + "o7", + "l0", + "l1", + "l2", + "l3", + "l4", + "l5", + "l6", + "l7", + "i0", + "i1", + "i2", + "i3", + "i4", + "i5", + "i6", + "i7"}; const std::string_view kCondName[16] = { - [0b0000] = "N", - [0b0001] = "E", - [0b0010] = "LE", - [0b0011] = "L", - [0b0100] = "LEU", - [0b0101] = "CS", - [0b0110] = "NEG", - [0b0111] = "VS", - [0b1000] = "A", - [0b1001] = "NE", - [0b1010] = "G", - [0b1011] = "GE", - [0b1100] = "GU", - [0b1101] = "CC", - [0b1110] = "POS", - [0b1111] = "VC", + [0b0000] = "N", [0b0001] = "E", [0b0010] = "LE", [0b0011] = "L", + [0b0100] = "LEU", [0b0101] = "CS", [0b0110] = "NEG", [0b0111] = "VS", + [0b1000] = "A", [0b1001] = "NE", [0b1010] = "G", [0b1011] = "GE", + [0b1100] = "GU", [0b1101] = "CC", [0b1110] = "POS", [0b1111] = "VC", }; const std::string_view kFCondName[16] = { - [0b0000] = "N", - [0b0001] = "NE", - [0b0010] = "LG", - [0b0011] = "UL", - [0b0100] = "L", - [0b0101] = "UG", - [0b0110] = "G", - [0b0111] = "U", - [0b1000] = "A", - [0b1001] = "E", - [0b1010] = "UE", - [0b1011] = "GE", - [0b1100] = "UGE", - [0b1101] = "LE", - [0b1110] = "ULE", - [0b1111] = "O" -}; + [0b0000] = "N", [0b0001] = "NE", [0b0010] = "LG", [0b0011] = "UL", + [0b0100] = "L", [0b0101] = "UG", [0b0110] = "G", [0b0111] = "U", + [0b1000] = "A", [0b1001] = "E", [0b1010] = "UE", [0b1011] = "GE", + [0b1100] = "UGE", [0b1101] = "LE", [0b1110] = "ULE", [0b1111] = "O"}; const std::string_view kRCondName[8] = { - [0b000] = {}, - [0b001] = "Z", - [0b010] = "LEZ", - [0b011] = "LZ", - [0b100] = {}, - [0b101] = "NZ", - [0b110] = "GZ", - [0b111] = "GEZ" -}; + [0b000] = {}, [0b001] = "Z", [0b010] = "LEZ", [0b011] = "LZ", + [0b100] = {}, [0b101] = "NZ", [0b110] = "GZ", [0b111] = "GEZ"}; void AddSrcRegop(Instruction &inst, const char *reg_name, unsigned size) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.type = Operand::kTypeRegister; op.size = size; - op.action = Operand::kActionRead; + op.action = Operand::kActionRead; op.reg.name = reg_name; op.reg.size = size; } @@ -126,18 +115,17 @@ void AddDestRegop(Instruction &inst, const char *reg_name, unsigned size) { auto &op = inst.operands.back(); op.type = Operand::kTypeRegister; op.size = size; - op.action = Operand::kActionWrite; + op.action = Operand::kActionWrite; op.reg.name = reg_name; op.reg.size = size; } -void AddImmop(Instruction &inst, uint64_t imm, - unsigned size, bool is_signed) { +void AddImmop(Instruction &inst, uint64_t imm, unsigned size, bool is_signed) { inst.operands.emplace_back(); auto &op = inst.operands.back(); op.type = Operand::kTypeImmediate; op.size = size; - op.action = Operand::kActionRead; + op.action = Operand::kActionRead; op.imm.val = imm; op.imm.is_signed = is_signed; } @@ -178,9 +166,8 @@ class SPARC32Arch final : public Arch { llvm::DataLayout DataLayout(void) const final; // Decode an instruction. - bool DecodeInstruction( - uint64_t address, std::string_view instr_bytes, - Instruction &inst) const final; + bool DecodeInstruction(uint64_t address, std::string_view instr_bytes, + Instruction &inst) const final; // Returns `true` if memory access are little endian byte ordered. bool MemoryAccessIsLittleEndian(void) const final { @@ -264,7 +251,8 @@ void SPARC32Arch::PopulateBasicBlockFunction(llvm::Module *module, REG(o7, gpr.o7.dword, u32); ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "g0"), false); - ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "ignore_write_to_g0"), false); + ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "ignore_write_to_g0"), + false); REG(g1, gpr.g1.dword, u32); REG(g2, gpr.g2.dword, u32); @@ -392,23 +380,27 @@ void SPARC32Arch::PopulateBasicBlockFunction(llvm::Module *module, // `WINDOW_LINK = &(WINDOW->prev_window);` llvm::Value *gep_indexes[2] = {zero_u32, llvm::ConstantInt::get(u32, 33)}; - auto window_link = ir.CreateInBoundsGEP(window_type, window, gep_indexes, "WINDOW_LINK"); + auto window_link = + ir.CreateInBoundsGEP(window_type, window, gep_indexes, "WINDOW_LINK"); auto nullptr_window = llvm::Constant::getNullValue(prev_window_link->type); ir.CreateStore(nullptr_window, window_link, false); - ir.CreateStore(zero_u8, ir.CreateAlloca(u8, nullptr, "IGNORE_BRANCH_TAKEN"), false); + ir.CreateStore(zero_u8, ir.CreateAlloca(u8, nullptr, "IGNORE_BRANCH_TAKEN"), + false); ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "IGNORE_PC"), false); - ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "IGNORE_NEXT_PC"), false); - ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "IGNORE_RETURN_PC"), false); + ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "IGNORE_NEXT_PC"), + false); + ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "IGNORE_RETURN_PC"), + false); const auto pc_arg = NthArgument(bb_func, kPCArgNum); const auto state_ptr_arg = NthArgument(bb_func, kStatePointerArgNum); (void) RegisterByName(kNextPCVariableName)->AddressOf(state_ptr_arg, ir); - ir.CreateStore( - pc_arg, RegisterByName(kPCVariableName)->AddressOf(state_ptr_arg, ir), - false); + ir.CreateStore(pc_arg, + RegisterByName(kPCVariableName)->AddressOf(state_ptr_arg, ir), + false); } llvm::Triple SPARC32Arch::Triple(void) const { @@ -445,8 +437,9 @@ bool SPARC32Arch::NextInstructionIsDelayed(const Instruction &inst, } // Decode an instruction. -bool SPARC32Arch::DecodeInstruction( - uint64_t address, std::string_view inst_bytes, Instruction &inst) const { +bool SPARC32Arch::DecodeInstruction(uint64_t address, + std::string_view inst_bytes, + Instruction &inst) const { inst.pc = address; inst.arch_name = arch_name; inst.arch = this; @@ -475,12 +468,11 @@ bool SPARC32Arch::DecodeInstruction( if (!sparc32::TryDecode(inst)) { inst.category = Instruction::kCategoryInvalid; inst.operands.clear(); - LOG(ERROR) - << "Unable to decode: " << inst.Serialize(); + LOG(ERROR) << "Unable to decode: " << inst.Serialize(); return false; } -// LOG(ERROR) << inst.Serialize(); + // LOG(ERROR) << inst.Serialize(); return inst.IsValid(); } @@ -488,15 +480,14 @@ bool SPARC32Arch::DecodeInstruction( } // namespace sparc // TODO(pag): We pretend that these are singletons, but they aren't really! -Arch::ArchPtr Arch::GetSPARC( - llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_) { +Arch::ArchPtr Arch::GetSPARC(llvm::LLVMContext *context_, OSName os_name_, + ArchName arch_name_) { if (arch_name_ == kArchSparc32) { return std::make_unique(context_, os_name_, arch_name_); } else { - LOG(FATAL) - << "Invalid arch name passed to Arch::GetSPARC: " - << GetArchName(arch_name_); + LOG(FATAL) << "Invalid arch name passed to Arch::GetSPARC: " + << GetArchName(arch_name_); return {}; } } diff --git a/lib/Arch/SPARC32/Decode.h b/lib/Arch/SPARC32/Decode.h index ba4ea6c2c..b4a67916b 100644 --- a/lib/Arch/SPARC32/Decode.h +++ b/lib/Arch/SPARC32/Decode.h @@ -16,9 +16,10 @@ #pragma once -#include #include +#include + #include "remill/Arch/Arch.h" #include "remill/Arch/Instruction.h" @@ -28,10 +29,10 @@ namespace sparc { union Format0a { uint32_t flat; struct { - uint32_t imm22:22; - uint32_t op2:3; - uint32_t rd:5; - uint32_t op:2; + uint32_t imm22 : 22; + uint32_t op2 : 3; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format0a) == 4, " "); @@ -39,11 +40,11 @@ static_assert(sizeof(Format0a) == 4, " "); union Format0b { uint32_t flat; struct { - int32_t disp22:22; - uint32_t op2:3; - uint32_t cond:4; - uint32_t a:1; - uint32_t op:2; + int32_t disp22 : 22; + uint32_t op2 : 3; + uint32_t cond : 4; + uint32_t a : 1; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format0b) == 4, " "); @@ -51,14 +52,14 @@ static_assert(sizeof(Format0b) == 4, " "); union Format0c { uint32_t flat; struct { - int32_t disp19:19; - uint32_t p:1; - uint32_t cc0:1; - uint32_t cc1:1; - uint32_t op2:3; - uint32_t cond:4; - uint32_t a:1; - uint32_t op:2; + int32_t disp19 : 19; + uint32_t p : 1; + uint32_t cc0 : 1; + uint32_t cc1 : 1; + uint32_t op2 : 3; + uint32_t cond : 4; + uint32_t a : 1; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format0c) == 4, " "); @@ -66,15 +67,15 @@ static_assert(sizeof(Format0c) == 4, " "); union Format0d { uint32_t flat; struct { - uint32_t d16lo:14; - uint32_t rs1:5; - uint32_t p:1; - uint32_t d16hi:2; - uint32_t op2:3; - uint32_t rcond:3; - uint32_t must_be_zero:1; // Bit 28. - uint32_t a:1; - uint32_t op:2; + uint32_t d16lo : 14; + uint32_t rs1 : 5; + uint32_t p : 1; + uint32_t d16hi : 2; + uint32_t op2 : 3; + uint32_t rcond : 3; + uint32_t must_be_zero : 1; // Bit 28. + uint32_t a : 1; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format0d) == 4, " "); @@ -82,14 +83,15 @@ static_assert(sizeof(Format0d) == 4, " "); union Format3 { uint32_t flat; struct { - uint32_t ai0_ai1_b:14; - uint32_t rs1:5; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + uint32_t ai0_ai1_b : 14; + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format3) == 4, " "); + // SPARC Format 3a //_________________________________________________________________ //| op| rd | op3 | rs1 |i| asi | rs2 | @@ -97,13 +99,13 @@ static_assert(sizeof(Format3) == 4, " "); union Format3ai0 { uint32_t flat; struct { - uint32_t rs2:5; - uint32_t asi:8; - uint32_t i:1; // Must be 0. - uint32_t rs1:5; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + uint32_t rs2 : 5; + uint32_t asi : 8; + uint32_t i : 1; // Must be 0. + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format3ai0) == 4, " "); @@ -115,12 +117,12 @@ static_assert(sizeof(Format3ai0) == 4, " "); union Format3ai1 { uint32_t flat; struct { - int32_t simm13:13; - uint32_t i:1; // Must be 1. - uint32_t rs1:5; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + int32_t simm13 : 13; + uint32_t i : 1; // Must be 1. + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)); @@ -131,12 +133,12 @@ union Format3ai1 { union Format3b { uint32_t flat; struct { - uint32_t rs2:5; - uint32_t opf:9; - uint32_t rs1:5; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; // 3 + uint32_t rs2 : 5; + uint32_t opf : 9; + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; // 3 } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format3b) == 4, " "); @@ -144,14 +146,14 @@ static_assert(sizeof(Format3b) == 4, " "); union Format3c { uint32_t flat; struct { - uint32_t rs2:5; - uint32_t opf:9; - uint32_t rs1:5; - uint32_t op3:6; - uint32_t cc0:1; - uint32_t cc1:1; - uint32_t _1:3; - uint32_t op:2; // 3 + uint32_t rs2 : 5; + uint32_t opf : 9; + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t cc0 : 1; + uint32_t cc1 : 1; + uint32_t _1 : 3; + uint32_t op : 2; // 3 } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format3b) == 4, " "); @@ -159,14 +161,14 @@ static_assert(sizeof(Format3b) == 4, " "); union Format3di0 { uint32_t flat; struct { - uint32_t rs2:5; - uint32_t _1:5; - uint32_t rcond:3; - uint32_t i:1; - uint32_t rs1:5; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; // 3 + uint32_t rs2 : 5; + uint32_t _1 : 5; + uint32_t rcond : 3; + uint32_t i : 1; + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; // 3 } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format3di0) == 4, " "); @@ -174,13 +176,13 @@ static_assert(sizeof(Format3di0) == 4, " "); union Format3di1 { uint32_t flat; struct { - uint32_t simm10:10; - uint32_t rcond:3; - uint32_t i:1; - uint32_t rs1:5; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; // 3 + uint32_t simm10 : 10; + uint32_t rcond : 3; + uint32_t i : 1; + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; // 3 } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format3di1) == 4, " "); @@ -188,14 +190,14 @@ static_assert(sizeof(Format3di1) == 4, " "); union Format3ei0 { uint32_t flat; struct { - uint32_t rs2:5; - uint32_t _1:7; - uint32_t x:1; - uint32_t i:1; // Must be 0. - uint32_t rs1:5; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + uint32_t rs2 : 5; + uint32_t _1 : 7; + uint32_t x : 1; + uint32_t i : 1; // Must be 0. + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format3ei0) == 4, " "); @@ -203,14 +205,14 @@ static_assert(sizeof(Format3ei0) == 4, " "); union Format3ei1 { uint32_t flat; struct { - uint32_t shcnt32:5; - uint32_t _1:7; - uint32_t x:1; - uint32_t i:1; // Must be 0. - uint32_t rs1:5; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + uint32_t shcnt32 : 5; + uint32_t _1 : 7; + uint32_t x : 1; + uint32_t i : 1; // Must be 0. + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format3ei1) == 4, " "); @@ -218,14 +220,14 @@ static_assert(sizeof(Format3ei1) == 4, " "); union Format3ei2 { uint32_t flat; struct { - uint32_t shcnt64:6; - uint32_t _1:6; - uint32_t x:1; - uint32_t i:1; // Must be 0. - uint32_t rs1:5; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + uint32_t shcnt64 : 6; + uint32_t _1 : 6; + uint32_t x : 1; + uint32_t i : 1; // Must be 0. + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format3ei2) == 4, " "); @@ -233,14 +235,14 @@ static_assert(sizeof(Format3ei2) == 4, " "); union Format3f { uint32_t flat; struct { - uint32_t mmask:4; - uint32_t cmask:3; - uint32_t _1:6; - uint32_t i:1; // Must be 1. - uint32_t bits:5; - uint32_t op3:6; - uint32_t _2:5; - uint32_t op:2; + uint32_t mmask : 4; + uint32_t cmask : 3; + uint32_t _1 : 6; + uint32_t i : 1; // Must be 1. + uint32_t bits : 5; + uint32_t op3 : 6; + uint32_t _2 : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format3f) == 4, " "); @@ -248,15 +250,15 @@ static_assert(sizeof(Format3f) == 4, " "); union Format4a { uint32_t flat; struct { - uint32_t rs2:5; - uint32_t unused:6; - uint32_t cc0:1; - uint32_t cc1:1; - uint32_t i:1; // 0. - uint32_t rs1:5; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + uint32_t rs2 : 5; + uint32_t unused : 6; + uint32_t cc0 : 1; + uint32_t cc1 : 1; + uint32_t i : 1; // 0. + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format4a) == 4, " "); @@ -264,14 +266,14 @@ static_assert(sizeof(Format4a) == 4, " "); union Format4b { uint32_t flat; struct { - int32_t simm11:11; - uint32_t cc0:1; - uint32_t cc1:1; - uint32_t i:1; // 0. - uint32_t rs1:5; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + int32_t simm11 : 11; + uint32_t cc0 : 1; + uint32_t cc1 : 1; + uint32_t i : 1; // 0. + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format4b) == 4, " "); @@ -279,16 +281,16 @@ static_assert(sizeof(Format4b) == 4, " "); union Format4c { uint32_t flat; struct { - uint32_t rs2:5; - uint32_t unused:6; - uint32_t cc0:1; - uint32_t cc1:1; - uint32_t i:1; // 0. - uint32_t cond:4; - uint32_t cc2:1; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + uint32_t rs2 : 5; + uint32_t unused : 6; + uint32_t cc0 : 1; + uint32_t cc1 : 1; + uint32_t i : 1; // 0. + uint32_t cond : 4; + uint32_t cc2 : 1; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format4c) == 4, " "); @@ -296,15 +298,15 @@ static_assert(sizeof(Format4c) == 4, " "); union Format4d { uint32_t flat; struct { - int32_t simm11:11; - uint32_t cc0:1; - uint32_t cc1:1; - uint32_t i:1; // 0. - uint32_t cond:4; - uint32_t cc2:1; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + int32_t simm11 : 11; + uint32_t cc0 : 1; + uint32_t cc1 : 1; + uint32_t i : 1; // 0. + uint32_t cond : 4; + uint32_t cc2 : 1; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)); static_assert(sizeof(Format4d) == 4, " "); @@ -319,8 +321,7 @@ extern const std::string_view kRCondName[8]; void AddSrcRegop(Instruction &inst, const char *reg_name, unsigned size); void AddDestRegop(Instruction &inst, const char *reg_name, unsigned size); -void AddImmop(Instruction &inst, uint64_t imm, - unsigned size, bool is_signed); +void AddImmop(Instruction &inst, uint64_t imm, unsigned size, bool is_signed); } // namespace sparc diff --git a/lib/Arch/SPARC32/Extract.cpp b/lib/Arch/SPARC32/Extract.cpp index 81e0722b0..33f65c957 100644 --- a/lib/Arch/SPARC32/Extract.cpp +++ b/lib/Arch/SPARC32/Extract.cpp @@ -15,10 +15,10 @@ */ #include -#include - #include +#include + #include "Decode.h" using namespace remill::sparc; @@ -30,29 +30,15 @@ namespace { static constexpr unsigned kAddressSize = 32; static const std::string_view kCondBrName[1U << 4U] = { - [0b0000] = "N", - [0b0001] = "123", - [0b0010] = "12", - [0b0011] = "13", - [0b0100] = "1", - [0b0101] = "23", - [0b0110] = "2", - [0b0111] = "3", - [0b1000] = "A", - [0b1001] = "0", - [0b1010] = "03", - [0b1011] = "02", - [0b1100] = "023", - [0b1101] = "01", - [0b1110] = "013", - [0b1111] = "012" -}; + [0b0000] = "N", [0b0001] = "123", [0b0010] = "12", [0b0011] = "13", + [0b0100] = "1", [0b0101] = "23", [0b0110] = "2", [0b0111] = "3", + [0b1000] = "A", [0b1001] = "0", [0b1010] = "03", [0b1011] = "02", + [0b1100] = "023", [0b1101] = "01", [0b1110] = "013", [0b1111] = "012"}; static const std::string_view kFpuRegName_fN[] = { - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", + "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", + "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; static void AddBranchTaken(Instruction &inst) { @@ -93,7 +79,7 @@ static void AddIntRegop(Instruction &inst, unsigned index, unsigned size, auto &op = inst.operands.back(); op.type = Operand::kTypeRegister; op.size = size; - op.action = action; + op.action = action; op.reg.size = size; if (Operand::kActionRead == action) { if (!index) { @@ -150,7 +136,7 @@ static void AddPCRelop(Instruction &inst, int64_t disp) { auto &op = inst.operands.back(); op.type = Operand::kTypeAddress; op.size = kAddressSize; - op.action = Operand::kActionRead; + op.action = Operand::kActionRead; op.addr.kind = Operand::Address::kControlFlowTarget; op.addr.address_size = kAddressSize; op.addr.base_reg.name = "PC"; @@ -163,7 +149,7 @@ static void AddNextPCRelop(Instruction &inst, int64_t disp) { auto &op = inst.operands.back(); op.type = Operand::kTypeAddress; op.size = kAddressSize; - op.action = Operand::kActionRead; + op.action = Operand::kActionRead; op.addr.kind = Operand::Address::kControlFlowTarget; op.addr.address_size = kAddressSize; op.addr.base_reg.name = "NEXT_PC"; @@ -178,11 +164,11 @@ static void AddBasePlusOffsetMemop(Instruction &inst, Operand::Action action, auto &op = inst.operands.back(); op.type = Operand::kTypeAddress; op.size = access_size; - op.action = action; + op.action = action; - op.addr.kind = action == Operand::kActionRead ? - Operand::Address::kMemoryRead : - Operand::Address::kMemoryWrite; + op.addr.kind = action == Operand::kActionRead + ? Operand::Address::kMemoryRead + : Operand::Address::kMemoryWrite; op.addr.address_size = kAddressSize; if (base_reg && index_reg) { @@ -242,8 +228,7 @@ static bool TryDecodeRDasr(Instruction &inst, uint32_t bits) { case 26: // rd %cfr, rd inst.function = "RDCFR"; break; - default: - return false; + default: return false; } AddIntRegop(inst, enc.rd, kAddressSize, Operand::kActionWrite); @@ -286,7 +271,7 @@ static bool TryDecodeWRasr(Instruction &inst, uint32_t bits) { case 27: // wr rs1, reg_or_imm, %pause inst.function = "WRPAUSE"; break; - default:return false; + default: return false; } AddIntRegop(inst, enc_i0.rs1, kAddressSize, Operand::kActionRead); @@ -302,8 +287,8 @@ static bool TryDecodeCALL(Instruction &inst, uint32_t bits) { union { uint32_t flat; struct { - int32_t disp30:30; - uint32_t op:2; + int32_t disp30 : 30; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)) enc; enc.flat = bits; @@ -321,8 +306,8 @@ static bool TryDecodeCALL(Instruction &inst, uint32_t bits) { inst.has_branch_taken_delay_slot = true; inst.has_branch_not_taken_delay_slot = false; - inst.branch_taken_pc = static_cast( - static_cast(inst.pc) + disp); + inst.branch_taken_pc = + static_cast(static_cast(inst.pc) + disp); inst.next_pc += 4; @@ -332,11 +317,10 @@ static bool TryDecodeCALL(Instruction &inst, uint32_t bits) { inst.branch_not_taken_pc = inst.next_pc; // pc+8. } - AddSrcRegop(inst, "PC", kAddressSize); // Old PC. - AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. + AddSrcRegop(inst, "PC", kAddressSize); // Old PC. + AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. AddPCRelop(inst, disp); // New NPC. - AddIntRegop(inst, 15 /* %o7 */, kAddressSize, - Operand::kActionWrite); + AddIntRegop(inst, 15 /* %o7 */, kAddressSize, Operand::kActionWrite); AddPCDest(inst); AddNPCDest(inst); @@ -359,14 +343,14 @@ static bool TryDecodeJMPL(Instruction &inst, uint32_t bits) { Format3ai0 enc_i0 = {bits}; Format3ai1 enc_i1 = {bits}; - AddSrcRegop(inst, "PC", kAddressSize); // Old PC. - AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. + AddSrcRegop(inst, "PC", kAddressSize); // Old PC. + AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. inst.operands.emplace_back(); auto &op = inst.operands.back(); op.type = Operand::kTypeAddress; op.size = kAddressSize; - op.action = Operand::kActionRead; + op.action = Operand::kActionRead; op.addr.kind = Operand::Address::kControlFlowTarget; op.addr.address_size = kAddressSize; @@ -383,6 +367,7 @@ static bool TryDecodeJMPL(Instruction &inst, uint32_t bits) { } if (!enc_i0.rd) { + // NOTE(pag): This is stricter than what is in the manual, but is more in // line with how we deal with function calls, and how actual // software operates. @@ -392,7 +377,7 @@ static bool TryDecodeJMPL(Instruction &inst, uint32_t bits) { // an `unimp ` might be placed after the call's // delay slot, which the callee must skip past in its return. if ((enc_i1.simm13 == 8 || enc_i1.simm13 == 12) && - (enc_i1.rs1 == 15 /* %o7 */ || enc_i1.rs1 == 31 /* %i7 */)) { + (enc_i1.rs1 == 15 /* %o7 */ || enc_i1.rs1 == 31 /* %i7 */)) { inst.function = "RETL"; inst.category = Instruction::kCategoryFunctionReturn; } else { @@ -443,7 +428,7 @@ static bool TryDecodeRETT(Instruction &inst, uint32_t bits) { Format3ai1 enc_i1 = {bits}; inst.category = Instruction::kCategoryFunctionReturn; - AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. + AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. inst.operands.emplace_back(); auto &dst_op = inst.operands.back(); @@ -474,7 +459,7 @@ static bool TryDecodeRETT(Instruction &inst, uint32_t bits) { return false; // RETT to `0`. } } else { - if (enc_i0.rs1 && enc_i0.rs2) { // `r[rs1] + r[rs2]`. + if (enc_i0.rs1 && enc_i0.rs2) { // `r[rs1] + r[rs2]`. dst_op.addr.base_reg.name = kReadIntRegName[enc_i0.rs1]; dst_op.addr.base_reg.size = kAddressSize; @@ -528,14 +513,14 @@ static bool TryDecodeTcc(Instruction &inst, uint32_t bits) { union { uint32_t flat; struct { - uint32_t rs2:5; - uint32_t _0:8; - uint32_t i:1; - uint32_t rs1:5; - uint32_t op3:6; - uint32_t cond:4; - uint32_t _1:1; - uint32_t op:2; + uint32_t rs2 : 5; + uint32_t _0 : 8; + uint32_t i : 1; + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t cond : 4; + uint32_t _1 : 1; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)) enc_i0 = {bits}; static_assert(sizeof(enc_i0) == 4); @@ -543,14 +528,14 @@ static bool TryDecodeTcc(Instruction &inst, uint32_t bits) { union { uint32_t flat; struct { - uint32_t imm7:7; - uint32_t _0:6; - uint32_t i:1; - uint32_t rs1:5; - uint32_t op3:6; - uint32_t cond:4; - uint32_t _1:1; - uint32_t op:2; + uint32_t imm7 : 7; + uint32_t _0 : 6; + uint32_t i : 1; + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t cond : 4; + uint32_t _1 : 1; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)) enc_i1 = {bits}; static_assert(sizeof(enc_i1) == 4); @@ -606,7 +591,7 @@ static bool TryDecodeTcc(Instruction &inst, uint32_t bits) { // TODO(pag): Handle write to TBR on `trap_instruction`. AddBranchTaken(inst); - AddSrcRegop(inst, "NEXT_PC", 32); // New PC on taken. + AddSrcRegop(inst, "NEXT_PC", 32); // New PC on taken. AddNextPCRelop(inst, 4); // New NPC on taken. // Trap vector number. @@ -623,9 +608,9 @@ static bool TryDecodeTcc(Instruction &inst, uint32_t bits) { } // Generic decoder for conditional branches (Bcc, BPcc). -static bool TryDecode_Branch( - Instruction &inst, unsigned cond, bool anul, int64_t disp, - std::string_view iform, std::string_view ccr, bool is_fcc = false) { +static bool TryDecode_Branch(Instruction &inst, unsigned cond, bool anul, + int64_t disp, std::string_view iform, + std::string_view ccr, bool is_fcc = false) { // Branch always. if (cond == 0b1000) { @@ -786,42 +771,42 @@ static bool TryDecodeBPr(Instruction &inst, uint32_t bits) { inst.next_pc += 4; inst.branch_not_taken_pc = inst.next_pc; // Skip delayed instruction. - // Not anulled means that the delayed instruction is executed on the taken - // and not-taken paths. - if (!enc.a) { - AddSrcRegop(inst, "NEXT_PC", kAddressSize); // PC if not taken. - AddNextPCRelop(inst, 4); // NPC if not taken. - - inst.has_branch_not_taken_delay_slot = true; - - // Anulled means that the delayed instruction is executed on the taken - // path, but not on the not-taken path. - } else { - AddNextPCRelop(inst, 4); // PC if not taken. - AddNextPCRelop(inst, 8); // NPC if not taken. - - inst.has_branch_not_taken_delay_slot = false; - } - - AddPCDest(inst); - AddNPCDest(inst); - - // NOTE(pag): This is part of a SPARC idiom of `jmpl,rett`, but we don't - // have elaborate pipeline support to handle things. See - // semantics of `UNSUPPORTED_DCTI`. - if (inst.in_delay_slot) { - inst.function = "UNSUPPORTED_DCTI"; - inst.operands.clear(); - inst.has_branch_taken_delay_slot = false; - inst.has_branch_not_taken_delay_slot = false; - inst.category = Instruction::kCategoryNormal; - inst.next_pc = inst.pc + 4; - - } else { - inst.function.reserve(9); - inst.function.insert(0, "BR"); - inst.function += kRCondName[enc.rcond]; - } + // Not anulled means that the delayed instruction is executed on the taken + // and not-taken paths. + if (!enc.a) { + AddSrcRegop(inst, "NEXT_PC", kAddressSize); // PC if not taken. + AddNextPCRelop(inst, 4); // NPC if not taken. + + inst.has_branch_not_taken_delay_slot = true; + + // Anulled means that the delayed instruction is executed on the taken + // path, but not on the not-taken path. + } else { + AddNextPCRelop(inst, 4); // PC if not taken. + AddNextPCRelop(inst, 8); // NPC if not taken. + + inst.has_branch_not_taken_delay_slot = false; + } + + AddPCDest(inst); + AddNPCDest(inst); + + // NOTE(pag): This is part of a SPARC idiom of `jmpl,rett`, but we don't + // have elaborate pipeline support to handle things. See + // semantics of `UNSUPPORTED_DCTI`. + if (inst.in_delay_slot) { + inst.function = "UNSUPPORTED_DCTI"; + inst.operands.clear(); + inst.has_branch_taken_delay_slot = false; + inst.has_branch_not_taken_delay_slot = false; + inst.category = Instruction::kCategoryNormal; + inst.next_pc = inst.pc + 4; + + } else { + inst.function.reserve(9); + inst.function.insert(0, "BR"); + inst.function += kRCondName[enc.rcond]; + } return true; } @@ -831,106 +816,106 @@ static bool TryDecodeCB(Instruction &inst, uint32_t bits) { int64_t disp = enc.disp22 << 2; // Branch always. - if (enc.cond == 0b1000) { - inst.category = Instruction::kCategoryDirectJump; - inst.branch_taken_pc = inst.pc + disp; - inst.has_branch_not_taken_delay_slot = false; - - if (!enc.a) { - AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. - AddPCRelop(inst, disp); // New NPC. - - inst.has_branch_taken_delay_slot = true; - inst.delayed_pc = inst.next_pc; - inst.next_pc += 4; - - } else { - AddPCRelop(inst, disp); // New PC. - AddPCRelop(inst, disp + 4); // New NPC. - inst.has_branch_taken_delay_slot = false; - } - - // Branch never. - } else if (enc.cond == 0b0000) { - inst.category = Instruction::kCategoryDirectJump; - - if (!enc.a) { - AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. - AddNextPCRelop(inst, 4); // New NPC. - - inst.has_branch_taken_delay_slot = true; - inst.has_branch_not_taken_delay_slot = false; - inst.delayed_pc = inst.next_pc; - - } else { - AddNextPCRelop(inst, 4); // New PC. - AddNextPCRelop(inst, 8); // New NPC. - - inst.has_branch_taken_delay_slot = false; - inst.has_branch_not_taken_delay_slot = false; - } - - inst.next_pc += 4; - inst.branch_taken_pc = inst.next_pc; - - // Conditional branch. - } else { - AddBranchTaken(inst); - - AddSrcRegop(inst, "NEXT_PC", kAddressSize); // PC if taken. - AddPCRelop(inst, disp); // NPC if taken. - - inst.category = Instruction::kCategoryConditionalBranch; - - inst.branch_taken_pc = inst.pc + disp; - inst.has_branch_taken_delay_slot = true; - inst.delayed_pc = inst.next_pc; - inst.next_pc += 4; - inst.branch_not_taken_pc = inst.next_pc; // Skip delayed instruction. - - // Not anulled means that the delayed instruction is executed on the taken - // and not-taken paths. - if (!enc.a) { - AddSrcRegop(inst, "NEXT_PC", kAddressSize); // PC if not taken. - AddNextPCRelop(inst, 4); // NPC if not taken. - - inst.has_branch_not_taken_delay_slot = true; - - // Anulled means that the delayed instruction is executed on the taken - // path, but not on the not-taken path. - } else { - AddNextPCRelop(inst, 4); // PC if not taken. - AddNextPCRelop(inst, 8); // NPC if not taken. - - inst.has_branch_not_taken_delay_slot = false; - } - } - - AddPCDest(inst); - AddNPCDest(inst); - - // NOTE(pag): This is part of a SPARC idiom of `jmpl,rett`, but we don't - // have elaborate pipeline support to handle things. See - // semantics of `UNSUPPORTED_DCTI`. - if (inst.in_delay_slot) { - inst.function = "UNSUPPORTED_DCTI"; - inst.operands.clear(); - inst.has_branch_taken_delay_slot = false; - inst.has_branch_not_taken_delay_slot = false; - inst.category = Instruction::kCategoryNormal; - inst.next_pc = inst.pc + 4; - - } else { - inst.function.reserve(9); - inst.function.insert(0, "CB"); - inst.function += kCondBrName[enc.cond]; - } + if (enc.cond == 0b1000) { + inst.category = Instruction::kCategoryDirectJump; + inst.branch_taken_pc = inst.pc + disp; + inst.has_branch_not_taken_delay_slot = false; + + if (!enc.a) { + AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. + AddPCRelop(inst, disp); // New NPC. + + inst.has_branch_taken_delay_slot = true; + inst.delayed_pc = inst.next_pc; + inst.next_pc += 4; + + } else { + AddPCRelop(inst, disp); // New PC. + AddPCRelop(inst, disp + 4); // New NPC. + inst.has_branch_taken_delay_slot = false; + } + + // Branch never. + } else if (enc.cond == 0b0000) { + inst.category = Instruction::kCategoryDirectJump; + + if (!enc.a) { + AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. + AddNextPCRelop(inst, 4); // New NPC. + + inst.has_branch_taken_delay_slot = true; + inst.has_branch_not_taken_delay_slot = false; + inst.delayed_pc = inst.next_pc; + + } else { + AddNextPCRelop(inst, 4); // New PC. + AddNextPCRelop(inst, 8); // New NPC. + + inst.has_branch_taken_delay_slot = false; + inst.has_branch_not_taken_delay_slot = false; + } + + inst.next_pc += 4; + inst.branch_taken_pc = inst.next_pc; + + // Conditional branch. + } else { + AddBranchTaken(inst); + + AddSrcRegop(inst, "NEXT_PC", kAddressSize); // PC if taken. + AddPCRelop(inst, disp); // NPC if taken. + + inst.category = Instruction::kCategoryConditionalBranch; + + inst.branch_taken_pc = inst.pc + disp; + inst.has_branch_taken_delay_slot = true; + inst.delayed_pc = inst.next_pc; + inst.next_pc += 4; + inst.branch_not_taken_pc = inst.next_pc; // Skip delayed instruction. + + // Not anulled means that the delayed instruction is executed on the taken + // and not-taken paths. + if (!enc.a) { + AddSrcRegop(inst, "NEXT_PC", kAddressSize); // PC if not taken. + AddNextPCRelop(inst, 4); // NPC if not taken. + + inst.has_branch_not_taken_delay_slot = true; + + // Anulled means that the delayed instruction is executed on the taken + // path, but not on the not-taken path. + } else { + AddNextPCRelop(inst, 4); // PC if not taken. + AddNextPCRelop(inst, 8); // NPC if not taken. + + inst.has_branch_not_taken_delay_slot = false; + } + } + + AddPCDest(inst); + AddNPCDest(inst); + + // NOTE(pag): This is part of a SPARC idiom of `jmpl,rett`, but we don't + // have elaborate pipeline support to handle things. See + // semantics of `UNSUPPORTED_DCTI`. + if (inst.in_delay_slot) { + inst.function = "UNSUPPORTED_DCTI"; + inst.operands.clear(); + inst.has_branch_taken_delay_slot = false; + inst.has_branch_not_taken_delay_slot = false; + inst.category = Instruction::kCategoryNormal; + inst.next_pc = inst.pc + 4; + + } else { + inst.function.reserve(9); + inst.function.insert(0, "CB"); + inst.function += kCondBrName[enc.cond]; + } return true; } -static bool TryDecode_rs1_simm32_op_rs2_rd( - Instruction &inst, uint32_t bits, const char *iform) { +static bool TryDecode_rs1_simm32_op_rs2_rd(Instruction &inst, uint32_t bits, + const char *iform) { Format3ai0 enc_i0 = {bits}; Format3ai1 enc_i1 = {bits}; @@ -948,8 +933,8 @@ static bool TryDecode_rs1_simm32_op_rs2_rd( return true; } -static bool TryDecode_rs1_imm_asi_op_rs2_rd( - Instruction &inst, uint32_t bits, const char *iform) { +static bool TryDecode_rs1_imm_asi_op_rs2_rd(Instruction &inst, uint32_t bits, + const char *iform) { Format3ai0 enc_i0 = {bits}; inst.function = iform; @@ -1064,7 +1049,7 @@ static bool TryDecodeADDXcc(Instruction &inst, uint32_t bits) { return TryDecode_rs1_simm32_op_rs2_rd(inst, bits, "ADDXcc"); } -static bool TryDecodeIMPDEP1 (Instruction &inst, uint32_t bits) { +static bool TryDecodeIMPDEP1(Instruction &inst, uint32_t bits) { Format3b enc = {bits}; inst.function = "IMPDEP1"; inst.category = Instruction::kCategoryNormal; @@ -1077,38 +1062,36 @@ struct fpu_opcode { uint32_t size; }; -#define SZERO 0 -#define SWORD 32 -#define DWORD 64 -#define QWORD 128 +#define SZERO 0 +#define SWORD 32 +#define DWORD 64 +#define QWORD 128 -static bool TryDecodeOpf_rs1_op_rs2_rd( - Instruction &inst, uint32_t bits, uint32_t rs1_size, - uint32_t rs2_size, uint32_t rd_size, const char *iform) { +static bool TryDecodeOpf_rs1_op_rs2_rd(Instruction &inst, uint32_t bits, + uint32_t rs1_size, uint32_t rs2_size, + uint32_t rd_size, const char *iform) { Format3b enc = {bits}; inst.function = iform; inst.category = Instruction::kCategoryNormal; - if (rs1_size && - !AddFpuRegOp(inst, enc.rs1, rs1_size, Operand::kActionRead)) { + if (rs1_size && !AddFpuRegOp(inst, enc.rs1, rs1_size, Operand::kActionRead)) { return false; } - if (rs2_size && - !AddFpuRegOp(inst, enc.rs2, rs2_size, Operand::kActionRead)) { + if (rs2_size && !AddFpuRegOp(inst, enc.rs2, rs2_size, Operand::kActionRead)) { return false; } - if (rd_size && - !AddFpuRegOp(inst, enc.rd, rd_size, Operand::kActionWrite)) { + if (rd_size && !AddFpuRegOp(inst, enc.rd, rd_size, Operand::kActionWrite)) { return false; } return true; } #define DEFINE_FUNCTION(name, rs1_size, rs2_size, rd_size) \ - static bool TryDecode ## name(Instruction &inst, uint32_t bits) { \ - return TryDecodeOpf_rs1_op_rs2_rd(inst, bits, rs1_size, rs2_size, rd_size, #name); \ + static bool TryDecode##name(Instruction &inst, uint32_t bits) { \ + return TryDecodeOpf_rs1_op_rs2_rd(inst, bits, rs1_size, rs2_size, rd_size, \ + #name); \ } DEFINE_FUNCTION(FABSS, SZERO, SWORD, SWORD) @@ -1165,270 +1148,141 @@ DEFINE_FUNCTION(FQTOD, SZERO, QWORD, DWORD) #undef DEFINE_FUNCTION static bool (*const kop10_op352Level[1u << 8])(Instruction &, uint32_t) = { - [0b00000000] = nullptr, - [0b00000001] = TryDecodeFMOVS, - [0b00000010] = TryDecodeFMOVD, - [0b00000011] = TryDecodeFMOVQ, - [0b00000100] = nullptr, - [0b00000101] = TryDecodeFNEGS, - [0b00000110] = TryDecodeFNEGD, - [0b00000111] = TryDecodeFNEGQ, - [0b00001000] = nullptr, - [0b00001001] = TryDecodeFABSS, - [0b00001010] = TryDecodeFABSD, - [0b00001011] = TryDecodeFABSQ, - [0b00001100] = nullptr, - [0b00001101] = nullptr, - [0b00001110] = nullptr, - [0b00001111] = nullptr, - [0b00010000] = nullptr, - [0b00010001] = nullptr, - [0b00010010] = nullptr, - [0b00010011] = nullptr, - [0b00010100] = nullptr, - [0b00010101] = nullptr, - [0b00010110] = nullptr, - [0b00010111] = nullptr, - [0b00011000] = nullptr, - [0b00011001] = nullptr, - [0b00011010] = nullptr, - [0b00011011] = nullptr, - [0b00011100] = nullptr, - [0b00011101] = nullptr, - [0b00011110] = nullptr, - [0b00011111] = nullptr, - [0b00100000] = nullptr, - [0b00100001] = nullptr, - [0b00100010] = nullptr, - [0b00100011] = nullptr, - [0b00100100] = nullptr, - [0b00100101] = nullptr, - [0b00100110] = nullptr, - [0b00100111] = nullptr, - [0b00101000] = nullptr, - [0b00101001] = TryDecodeFSQRTS, - [0b00101010] = TryDecodeFSQRTD, - [0b00101011] = TryDecodeFSQRTQ, - [0b00101100] = nullptr, - [0b00101101] = nullptr, - [0b00101110] = nullptr, - [0b00101111] = nullptr, - [0b00110000] = nullptr, - [0b00110001] = nullptr, - [0b00110010] = nullptr, - [0b00110011] = nullptr, - [0b00110100] = nullptr, - [0b00110101] = nullptr, - [0b00110110] = nullptr, - [0b00110111] = nullptr, - [0b00111000] = nullptr, - [0b00111001] = nullptr, - [0b00111010] = nullptr, - [0b00111011] = nullptr, - [0b00111100] = nullptr, - [0b00111101] = nullptr, - [0b00111110] = nullptr, - [0b00111111] = nullptr, - [0b01000000] = nullptr, - [0b01000001] = TryDecodeFADDS, - [0b01000010] = TryDecodeFADDD, - [0b01000011] = TryDecodeFADDQ, - [0b01000100] = nullptr, - [0b01000101] = TryDecodeFSUBS, - [0b01000110] = TryDecodeFSUBD, - [0b01000111] = TryDecodeFSUBQ, - [0b01001000] = nullptr, - [0b01001001] = TryDecodeFMULS, - [0b01001010] = TryDecodeFMULD, - [0b01001011] = TryDecodeFMULQ, - [0b01001100] = nullptr, - [0b01001101] = TryDecodeFDIVS, - [0b01001110] = TryDecodeFDIVD, - [0b01001111] = TryDecodeFDIVQ, - [0b01010000] = nullptr, - [0b01010001] = nullptr, - [0b01010010] = nullptr, - [0b01010011] = nullptr, - [0b01010100] = nullptr, - [0b01010101] = nullptr, - [0b01010110] = nullptr, - [0b01010111] = nullptr, - [0b01011000] = nullptr, - [0b01011001] = nullptr, - [0b01011010] = nullptr, - [0b01011011] = nullptr, - [0b01011100] = nullptr, - [0b01011101] = nullptr, - [0b01011110] = nullptr, - [0b01011111] = nullptr, - [0b01100000] = nullptr, - [0b01100001] = TryDecodeFHADDS, - [0b01100010] = TryDecodeFHADDD, - [0b01100011] = nullptr, - [0b01100100] = nullptr, - [0b01100101] = nullptr, - [0b01100110] = nullptr, - [0b01100111] = nullptr, - [0b01101000] = nullptr, - [0b01101001] = TryDecodeFSMULD, - [0b01101010] = nullptr, - [0b01101011] = nullptr, - [0b01101100] = nullptr, - [0b01101101] = nullptr, - [0b01101110] = TryDecodeFDMULQ, - [0b01101111] = nullptr, - [0b01110000] = nullptr, - [0b01110001] = nullptr, - [0b01110010] = nullptr, - [0b01110011] = nullptr, - [0b01110100] = nullptr, - [0b01110101] = nullptr, - [0b01110110] = nullptr, - [0b01110111] = nullptr, - [0b01111000] = nullptr, - [0b01111001] = nullptr, - [0b01111010] = nullptr, - [0b01111011] = nullptr, - [0b01111100] = nullptr, - [0b01111101] = nullptr, - [0b01111110] = nullptr, - [0b01111111] = nullptr, - [0b10000000] = nullptr, - [0b10000001] = TryDecodeFSTOX, - [0b10000010] = TryDecodeFDTOX, - [0b10000011] = TryDecodeFQTOX, - [0b10000100] = TryDecodeFXTOS, - [0b10000101] = nullptr, - [0b10000110] = nullptr, - [0b10000111] = nullptr, - [0b10001000] = TryDecodeFXTOD, - [0b10001001] = nullptr, - [0b10001010] = nullptr, - [0b10001011] = nullptr, - [0b10001100] = TryDecodeFXTOQ, - [0b10001101] = nullptr, - [0b10001110] = nullptr, - [0b10001111] = nullptr, - [0b10010000] = nullptr, - [0b10010001] = nullptr, - [0b10010010] = nullptr, - [0b10010011] = nullptr, - [0b10010100] = nullptr, - [0b10010101] = nullptr, - [0b10010110] = nullptr, - [0b10010111] = nullptr, - [0b10011000] = nullptr, - [0b10011001] = nullptr, - [0b10011010] = nullptr, - [0b10011011] = nullptr, - [0b10011100] = nullptr, - [0b10011101] = nullptr, - [0b10011110] = nullptr, - [0b10011111] = nullptr, - [0b10100000] = nullptr, - [0b10100001] = nullptr, - [0b10100010] = nullptr, - [0b10100011] = nullptr, - [0b10100100] = nullptr, - [0b10100101] = nullptr, - [0b10100110] = nullptr, - [0b10100111] = nullptr, - [0b10101000] = nullptr, - [0b10101001] = nullptr, - [0b10101010] = nullptr, - [0b10101011] = nullptr, - [0b10101100] = nullptr, - [0b10101101] = nullptr, - [0b10101110] = nullptr, - [0b10101111] = nullptr, - [0b10110000] = nullptr, - [0b10110001] = nullptr, - [0b10110010] = nullptr, - [0b10110011] = nullptr, - [0b10110100] = nullptr, - [0b10110101] = nullptr, - [0b10110110] = nullptr, - [0b10110111] = nullptr, - [0b10111000] = nullptr, - [0b10111001] = nullptr, - [0b10111010] = nullptr, - [0b10111011] = nullptr, - [0b10111100] = nullptr, - [0b10111101] = nullptr, - [0b10111110] = nullptr, - [0b10111111] = nullptr, - [0b11000000] = nullptr, - [0b11000001] = nullptr, - [0b11000010] = nullptr, - [0b11000011] = nullptr, - [0b11000100] = TryDecodeFITOS, - [0b11000101] = nullptr, - [0b11000110] = TryDecodeFDTOS, - [0b11000111] = TryDecodeFQTOS, - [0b11001000] = TryDecodeFITOD, - [0b11001001] = TryDecodeFSTOD, - [0b11001010] = nullptr, - [0b11001011] = TryDecodeFQTOD, - [0b11001100] = TryDecodeFITOQ, - [0b11001101] = TryDecodeFSTOQ, - [0b11001110] = TryDecodeFDTOQ, - [0b11001111] = nullptr, - [0b11010000] = nullptr, - [0b11010001] = TryDecodeFSTOI, - [0b11010010] = TryDecodeFDTOI, - [0b11010011] = TryDecodeFQTOI, - [0b11010100] = nullptr, - [0b11010101] = nullptr, - [0b11010110] = nullptr, - [0b11010111] = nullptr, - [0b11011000] = nullptr, - [0b11011001] = nullptr, - [0b11011010] = nullptr, - [0b11011011] = nullptr, - [0b11011100] = nullptr, - [0b11011101] = nullptr, - [0b11011110] = nullptr, - [0b11011111] = nullptr, - [0b11100000] = nullptr, - [0b11100001] = nullptr, - [0b11100010] = nullptr, - [0b11100011] = nullptr, - [0b11100100] = nullptr, - [0b11100101] = nullptr, - [0b11100110] = nullptr, - [0b11100111] = nullptr, - [0b11101000] = nullptr, - [0b11101001] = nullptr, - [0b11101010] = nullptr, - [0b11101011] = nullptr, - [0b11101100] = nullptr, - [0b11101101] = nullptr, - [0b11101110] = nullptr, - [0b11101111] = nullptr, - [0b11110000] = nullptr, - [0b11110001] = nullptr, - [0b11110010] = nullptr, - [0b11110011] = nullptr, - [0b11110100] = nullptr, - [0b11110101] = nullptr, - [0b11110110] = nullptr, - [0b11110111] = nullptr, - [0b11111000] = nullptr, - [0b11111001] = nullptr, - [0b11111010] = nullptr, - [0b11111011] = nullptr, - [0b11111100] = nullptr, - [0b11111101] = nullptr, - [0b11111110] = nullptr, - [0b11111111] = nullptr, + [0b00000000] = nullptr, [0b00000001] = TryDecodeFMOVS, + [0b00000010] = TryDecodeFMOVD, [0b00000011] = TryDecodeFMOVQ, + [0b00000100] = nullptr, [0b00000101] = TryDecodeFNEGS, + [0b00000110] = TryDecodeFNEGD, [0b00000111] = TryDecodeFNEGQ, + [0b00001000] = nullptr, [0b00001001] = TryDecodeFABSS, + [0b00001010] = TryDecodeFABSD, [0b00001011] = TryDecodeFABSQ, + [0b00001100] = nullptr, [0b00001101] = nullptr, + [0b00001110] = nullptr, [0b00001111] = nullptr, + [0b00010000] = nullptr, [0b00010001] = nullptr, + [0b00010010] = nullptr, [0b00010011] = nullptr, + [0b00010100] = nullptr, [0b00010101] = nullptr, + [0b00010110] = nullptr, [0b00010111] = nullptr, + [0b00011000] = nullptr, [0b00011001] = nullptr, + [0b00011010] = nullptr, [0b00011011] = nullptr, + [0b00011100] = nullptr, [0b00011101] = nullptr, + [0b00011110] = nullptr, [0b00011111] = nullptr, + [0b00100000] = nullptr, [0b00100001] = nullptr, + [0b00100010] = nullptr, [0b00100011] = nullptr, + [0b00100100] = nullptr, [0b00100101] = nullptr, + [0b00100110] = nullptr, [0b00100111] = nullptr, + [0b00101000] = nullptr, [0b00101001] = TryDecodeFSQRTS, + [0b00101010] = TryDecodeFSQRTD, [0b00101011] = TryDecodeFSQRTQ, + [0b00101100] = nullptr, [0b00101101] = nullptr, + [0b00101110] = nullptr, [0b00101111] = nullptr, + [0b00110000] = nullptr, [0b00110001] = nullptr, + [0b00110010] = nullptr, [0b00110011] = nullptr, + [0b00110100] = nullptr, [0b00110101] = nullptr, + [0b00110110] = nullptr, [0b00110111] = nullptr, + [0b00111000] = nullptr, [0b00111001] = nullptr, + [0b00111010] = nullptr, [0b00111011] = nullptr, + [0b00111100] = nullptr, [0b00111101] = nullptr, + [0b00111110] = nullptr, [0b00111111] = nullptr, + [0b01000000] = nullptr, [0b01000001] = TryDecodeFADDS, + [0b01000010] = TryDecodeFADDD, [0b01000011] = TryDecodeFADDQ, + [0b01000100] = nullptr, [0b01000101] = TryDecodeFSUBS, + [0b01000110] = TryDecodeFSUBD, [0b01000111] = TryDecodeFSUBQ, + [0b01001000] = nullptr, [0b01001001] = TryDecodeFMULS, + [0b01001010] = TryDecodeFMULD, [0b01001011] = TryDecodeFMULQ, + [0b01001100] = nullptr, [0b01001101] = TryDecodeFDIVS, + [0b01001110] = TryDecodeFDIVD, [0b01001111] = TryDecodeFDIVQ, + [0b01010000] = nullptr, [0b01010001] = nullptr, + [0b01010010] = nullptr, [0b01010011] = nullptr, + [0b01010100] = nullptr, [0b01010101] = nullptr, + [0b01010110] = nullptr, [0b01010111] = nullptr, + [0b01011000] = nullptr, [0b01011001] = nullptr, + [0b01011010] = nullptr, [0b01011011] = nullptr, + [0b01011100] = nullptr, [0b01011101] = nullptr, + [0b01011110] = nullptr, [0b01011111] = nullptr, + [0b01100000] = nullptr, [0b01100001] = TryDecodeFHADDS, + [0b01100010] = TryDecodeFHADDD, [0b01100011] = nullptr, + [0b01100100] = nullptr, [0b01100101] = nullptr, + [0b01100110] = nullptr, [0b01100111] = nullptr, + [0b01101000] = nullptr, [0b01101001] = TryDecodeFSMULD, + [0b01101010] = nullptr, [0b01101011] = nullptr, + [0b01101100] = nullptr, [0b01101101] = nullptr, + [0b01101110] = TryDecodeFDMULQ, [0b01101111] = nullptr, + [0b01110000] = nullptr, [0b01110001] = nullptr, + [0b01110010] = nullptr, [0b01110011] = nullptr, + [0b01110100] = nullptr, [0b01110101] = nullptr, + [0b01110110] = nullptr, [0b01110111] = nullptr, + [0b01111000] = nullptr, [0b01111001] = nullptr, + [0b01111010] = nullptr, [0b01111011] = nullptr, + [0b01111100] = nullptr, [0b01111101] = nullptr, + [0b01111110] = nullptr, [0b01111111] = nullptr, + [0b10000000] = nullptr, [0b10000001] = TryDecodeFSTOX, + [0b10000010] = TryDecodeFDTOX, [0b10000011] = TryDecodeFQTOX, + [0b10000100] = TryDecodeFXTOS, [0b10000101] = nullptr, + [0b10000110] = nullptr, [0b10000111] = nullptr, + [0b10001000] = TryDecodeFXTOD, [0b10001001] = nullptr, + [0b10001010] = nullptr, [0b10001011] = nullptr, + [0b10001100] = TryDecodeFXTOQ, [0b10001101] = nullptr, + [0b10001110] = nullptr, [0b10001111] = nullptr, + [0b10010000] = nullptr, [0b10010001] = nullptr, + [0b10010010] = nullptr, [0b10010011] = nullptr, + [0b10010100] = nullptr, [0b10010101] = nullptr, + [0b10010110] = nullptr, [0b10010111] = nullptr, + [0b10011000] = nullptr, [0b10011001] = nullptr, + [0b10011010] = nullptr, [0b10011011] = nullptr, + [0b10011100] = nullptr, [0b10011101] = nullptr, + [0b10011110] = nullptr, [0b10011111] = nullptr, + [0b10100000] = nullptr, [0b10100001] = nullptr, + [0b10100010] = nullptr, [0b10100011] = nullptr, + [0b10100100] = nullptr, [0b10100101] = nullptr, + [0b10100110] = nullptr, [0b10100111] = nullptr, + [0b10101000] = nullptr, [0b10101001] = nullptr, + [0b10101010] = nullptr, [0b10101011] = nullptr, + [0b10101100] = nullptr, [0b10101101] = nullptr, + [0b10101110] = nullptr, [0b10101111] = nullptr, + [0b10110000] = nullptr, [0b10110001] = nullptr, + [0b10110010] = nullptr, [0b10110011] = nullptr, + [0b10110100] = nullptr, [0b10110101] = nullptr, + [0b10110110] = nullptr, [0b10110111] = nullptr, + [0b10111000] = nullptr, [0b10111001] = nullptr, + [0b10111010] = nullptr, [0b10111011] = nullptr, + [0b10111100] = nullptr, [0b10111101] = nullptr, + [0b10111110] = nullptr, [0b10111111] = nullptr, + [0b11000000] = nullptr, [0b11000001] = nullptr, + [0b11000010] = nullptr, [0b11000011] = nullptr, + [0b11000100] = TryDecodeFITOS, [0b11000101] = nullptr, + [0b11000110] = TryDecodeFDTOS, [0b11000111] = TryDecodeFQTOS, + [0b11001000] = TryDecodeFITOD, [0b11001001] = TryDecodeFSTOD, + [0b11001010] = nullptr, [0b11001011] = TryDecodeFQTOD, + [0b11001100] = TryDecodeFITOQ, [0b11001101] = TryDecodeFSTOQ, + [0b11001110] = TryDecodeFDTOQ, [0b11001111] = nullptr, + [0b11010000] = nullptr, [0b11010001] = TryDecodeFSTOI, + [0b11010010] = TryDecodeFDTOI, [0b11010011] = TryDecodeFQTOI, + [0b11010100] = nullptr, [0b11010101] = nullptr, + [0b11010110] = nullptr, [0b11010111] = nullptr, + [0b11011000] = nullptr, [0b11011001] = nullptr, + [0b11011010] = nullptr, [0b11011011] = nullptr, + [0b11011100] = nullptr, [0b11011101] = nullptr, + [0b11011110] = nullptr, [0b11011111] = nullptr, + [0b11100000] = nullptr, [0b11100001] = nullptr, + [0b11100010] = nullptr, [0b11100011] = nullptr, + [0b11100100] = nullptr, [0b11100101] = nullptr, + [0b11100110] = nullptr, [0b11100111] = nullptr, + [0b11101000] = nullptr, [0b11101001] = nullptr, + [0b11101010] = nullptr, [0b11101011] = nullptr, + [0b11101100] = nullptr, [0b11101101] = nullptr, + [0b11101110] = nullptr, [0b11101111] = nullptr, + [0b11110000] = nullptr, [0b11110001] = nullptr, + [0b11110010] = nullptr, [0b11110011] = nullptr, + [0b11110100] = nullptr, [0b11110101] = nullptr, + [0b11110110] = nullptr, [0b11110111] = nullptr, + [0b11111000] = nullptr, [0b11111001] = nullptr, + [0b11111010] = nullptr, [0b11111011] = nullptr, + [0b11111100] = nullptr, [0b11111101] = nullptr, + [0b11111110] = nullptr, [0b11111111] = nullptr, }; static bool TryDecodeOpf52(Instruction &inst, uint32_t bits) { Format3b enc = {bits}; auto func = kop10_op352Level[enc.opf]; if (!func) { - LOG(ERROR) - << "OP=10 op3=110100 opf=" << std::bitset<8>(enc.opf); + LOG(ERROR) << "OP=10 op3=110100 opf=" << std::bitset<8>(enc.opf); return TryDecodeIMPDEP1(inst, bits); } return func(inst, bits); @@ -1438,14 +1292,14 @@ static bool TryDecodeFMOVcc(Instruction &inst, uint32_t bits) { union { uint32_t flat; struct { - uint32_t rs2:5; - uint32_t opf_low:6; - uint32_t opf_cc:3; - uint32_t cond:4; - uint32_t _1:1; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + uint32_t rs2 : 5; + uint32_t opf_low : 6; + uint32_t opf_cc : 3; + uint32_t cond : 4; + uint32_t _1 : 1; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)) enc = {bits}; static_assert(sizeof(enc) == 4); @@ -1458,7 +1312,7 @@ static bool TryDecodeFMOVcc(Instruction &inst, uint32_t bits) { inst.category = Instruction::kCategoryNormal; inst.function.reserve(12); auto access_size = kAddressSize; - switch(enc.opf_low) { + switch (enc.opf_low) { case 0b0001: access_size = 32; inst.function.insert(0, "FMOVS"); @@ -1471,14 +1325,14 @@ static bool TryDecodeFMOVcc(Instruction &inst, uint32_t bits) { access_size = 128; inst.function.insert(0, "FMOVQ"); break; - default: - return false; + default: return false; } AddFpuRegOp(inst, enc.rs2, access_size, Operand::kActionRead); AddFpuRegOp(inst, enc.rd, access_size, Operand::kActionWrite); - inst.function += (enc.opf_cc < 0b100) ? kFCondName[enc.cond] : kCondName[enc.cond]; + inst.function += + (enc.opf_cc < 0b100) ? kFCondName[enc.cond] : kCondName[enc.cond]; inst.function.push_back('_'); inst.function += cc; return true; @@ -1488,14 +1342,14 @@ static bool TryDecodeFMOVr(Instruction &inst, uint32_t bits) { union { uint32_t flat; struct { - uint32_t rs2:5; - uint32_t opf_low:5; - uint32_t rcond:3; - uint32_t _1:1; - uint32_t rs1:5; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + uint32_t rs2 : 5; + uint32_t opf_low : 5; + uint32_t rcond : 3; + uint32_t _1 : 1; + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)) enc = {bits}; static_assert(sizeof(enc) == 4); @@ -1507,7 +1361,7 @@ static bool TryDecodeFMOVr(Instruction &inst, uint32_t bits) { inst.category = Instruction::kCategoryNormal; inst.function.reserve(9); auto access_size = kAddressSize; - switch(enc.opf_low) { + switch (enc.opf_low) { case 0b0001: access_size = 32; inst.function.insert(0, "FMOVRS"); @@ -1520,8 +1374,7 @@ static bool TryDecodeFMOVr(Instruction &inst, uint32_t bits) { access_size = 128; inst.function.insert(0, "FMOVRQ"); break; - default: - return false; + default: return false; } AddIntRegop(inst, enc.rs1, kAddressSize, Operand::kActionRead); @@ -1536,43 +1389,42 @@ static bool TryDecodeFMOV(Instruction &inst, uint32_t bits) { union { uint32_t flat; struct { - uint32_t rs2:5; - uint32_t opf_low:6; - uint32_t opf_cc:3; - uint32_t cond:4; - uint32_t _1:1; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + uint32_t rs2 : 5; + uint32_t opf_low : 6; + uint32_t opf_cc : 3; + uint32_t cond : 4; + uint32_t _1 : 1; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)) enc = {bits}; static_assert(sizeof(enc) == 4); - if ((enc.opf_low == 0b0001) - || (enc.opf_low == 0b0010) - || (enc.opf_low == 0b0011)) { + if ((enc.opf_low == 0b0001) || (enc.opf_low == 0b0010) || + (enc.opf_low == 0b0011)) { return TryDecodeFMOVcc(inst, bits); } return TryDecodeFMOVr(inst, bits); } static const fpu_opcode Opf05[1 << 4U] = { - [0b0000] = {{}, 0}, - [0b0001] = {"FCMPS", 0x00002020}, - [0b0010] = {"FCMPD", 0x00004040}, - [0b0011] = {"FCMPQ", 0x00008080}, - [0b0100] = {{}, 0}, - [0b0101] = {"FCMPES", 0x00002020}, - [0b0110] = {"FCMPED", 0x00004040}, - [0b0111] = {"FCMPEQ", 0x00008080}, - [0b1000] = {{}, 0}, - [0b1001] = {{}, 0}, - [0b1010] = {{}, 0}, - [0b1011] = {{}, 0}, - [0b1100] = {{}, 0}, - [0b1101] = {{}, 0}, - [0b1110] = {{}, 0}, - [0b1111] = {{}, 0}, + [0b0000] = {{}, 0}, + [0b0001] = {"FCMPS", 0x00002020}, + [0b0010] = {"FCMPD", 0x00004040}, + [0b0011] = {"FCMPQ", 0x00008080}, + [0b0100] = {{}, 0}, + [0b0101] = {"FCMPES", 0x00002020}, + [0b0110] = {"FCMPED", 0x00004040}, + [0b0111] = {"FCMPEQ", 0x00008080}, + [0b1000] = {{}, 0}, + [0b1001] = {{}, 0}, + [0b1010] = {{}, 0}, + [0b1011] = {{}, 0}, + [0b1100] = {{}, 0}, + [0b1101] = {{}, 0}, + [0b1110] = {{}, 0}, + [0b1111] = {{}, 0}, }; static bool TryDecodeFCMP(Instruction &inst, uint32_t bits) { @@ -1580,10 +1432,10 @@ static bool TryDecodeFCMP(Instruction &inst, uint32_t bits) { union { uint32_t flat; struct { - uint32_t rs1:8; - uint32_t rs2:8; - uint32_t rd:8; - uint32_t _1:8; + uint32_t rs1 : 8; + uint32_t rs2 : 8; + uint32_t rd : 8; + uint32_t _1 : 8; } __attribute__((packed)); } __attribute__((packed)) opd_size = {Opf05[enc.opf & 0b1111].size}; @@ -1622,27 +1474,22 @@ static bool TryDecodeFCMP_FMOV(Instruction &inst, uint32_t bits) { } -enum class RegClass { - kInt, - kFP -}; +enum class RegClass { kInt, kFP }; -static bool TryDecode_Load( - Instruction &inst, uint32_t bits, const char *iform, - unsigned mem_size, unsigned reg_size, RegClass rclass=RegClass::kInt) { +static bool TryDecode_Load(Instruction &inst, uint32_t bits, const char *iform, + unsigned mem_size, unsigned reg_size, + RegClass rclass = RegClass::kInt) { Format3ai0 enc_i0 = {bits}; Format3ai1 enc_i1 = {bits}; inst.function = iform; inst.category = Instruction::kCategoryNormal; if (enc_i1.i) { - AddBasePlusOffsetMemop( - inst, Operand::kActionRead, mem_size, enc_i0.rs1, - 0, enc_i1.simm13); + AddBasePlusOffsetMemop(inst, Operand::kActionRead, mem_size, enc_i0.rs1, 0, + enc_i1.simm13); } else { - AddBasePlusOffsetMemop( - inst, Operand::kActionRead, mem_size, enc_i0.rs1, - enc_i0.rs2, 0); + AddBasePlusOffsetMemop(inst, Operand::kActionRead, mem_size, enc_i0.rs1, + enc_i0.rs2, 0); } if (RegClass::kInt == rclass) { @@ -1654,9 +1501,9 @@ static bool TryDecode_Load( return true; } -static bool TryDecode_Store( - Instruction &inst, uint32_t bits, const char *iform, - unsigned reg_size, unsigned mem_size, RegClass rclass=RegClass::kInt) { +static bool TryDecode_Store(Instruction &inst, uint32_t bits, const char *iform, + unsigned reg_size, unsigned mem_size, + RegClass rclass = RegClass::kInt) { Format3ai0 enc_i0 = {bits}; Format3ai1 enc_i1 = {bits}; inst.function = iform; @@ -1670,13 +1517,11 @@ static bool TryDecode_Store( } if (enc_i1.i) { - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, mem_size, enc_i0.rs1, - 0, enc_i1.simm13); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, mem_size, enc_i0.rs1, 0, + enc_i1.simm13); } else { - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, mem_size, enc_i0.rs1, - enc_i0.rs2, 0); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, mem_size, enc_i0.rs1, + enc_i0.rs2, 0); } return true; } @@ -1701,9 +1546,9 @@ static bool TryDecodeLD(Instruction &inst, uint32_t bits) { return TryDecode_Load(inst, bits, "LD", 32, 32); } -static bool TryDecode_LoadDouble( - Instruction &inst, uint32_t bits, const char *iform, - unsigned access_size, RegClass rclass=RegClass::kInt) { +static bool TryDecode_LoadDouble(Instruction &inst, uint32_t bits, + const char *iform, unsigned access_size, + RegClass rclass = RegClass::kInt) { Format3ai0 enc_i0 = {bits}; Format3ai1 enc_i1 = {bits}; inst.function = iform; @@ -1716,19 +1561,15 @@ static bool TryDecode_LoadDouble( return false; // Must be an even register. } if (enc_i1.i) { - AddBasePlusOffsetMemop( - inst, Operand::kActionRead, access_size, enc_i0.rs1, - 0, enc_i1.simm13); - AddBasePlusOffsetMemop( - inst, Operand::kActionRead, access_size, enc_i0.rs1, - 0, enc_i1.simm13 + (access_size / 8)); + AddBasePlusOffsetMemop(inst, Operand::kActionRead, access_size, enc_i0.rs1, + 0, enc_i1.simm13); + AddBasePlusOffsetMemop(inst, Operand::kActionRead, access_size, enc_i0.rs1, + 0, enc_i1.simm13 + (access_size / 8)); } else { - AddBasePlusOffsetMemop( - inst, Operand::kActionRead, access_size, enc_i0.rs1, - enc_i0.rs2, 0); - AddBasePlusOffsetMemop( - inst, Operand::kActionRead, access_size, enc_i0.rs1, - enc_i0.rs2, access_size / 8); + AddBasePlusOffsetMemop(inst, Operand::kActionRead, access_size, enc_i0.rs1, + enc_i0.rs2, 0); + AddBasePlusOffsetMemop(inst, Operand::kActionRead, access_size, enc_i0.rs1, + enc_i0.rs2, access_size / 8); } if (RegClass::kInt == rclass) { @@ -1765,13 +1606,11 @@ static bool TryDecodeLDSTUB(Instruction &inst, uint32_t bits) { // if i != 0 if (enc_i1.i) { - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, 8, enc_i0.rs1, - 0, enc_i1.simm13); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, 8, enc_i0.rs1, 0, + enc_i1.simm13); } else { - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, 8, enc_i0.rs1, - 0, enc_i0.rs2); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, 8, enc_i0.rs1, 0, + enc_i0.rs2); } AddIntRegop(inst, enc_i0.rd, kAddressSize, Operand::kActionWrite); @@ -1790,9 +1629,9 @@ static bool TryDecodeST(Instruction &inst, uint32_t bits) { return TryDecode_Store(inst, bits, "ST", 32, 32); } -static bool TryDecode_StoreDouble( - Instruction &inst, uint32_t bits, const char *iform, - unsigned access_size, RegClass rclass=RegClass::kInt) { +static bool TryDecode_StoreDouble(Instruction &inst, uint32_t bits, + const char *iform, unsigned access_size, + RegClass rclass = RegClass::kInt) { Format3ai0 enc_i0 = {bits}; Format3ai1 enc_i1 = {bits}; inst.function = iform; @@ -1815,20 +1654,16 @@ static bool TryDecode_StoreDouble( } if (enc_i1.i) { - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, access_size, enc_i0.rs1, - 0, enc_i1.simm13); - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, access_size, enc_i0.rs1, - 0, enc_i1.simm13 + (access_size / 8)); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, access_size, enc_i0.rs1, + 0, enc_i1.simm13); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, access_size, enc_i0.rs1, + 0, enc_i1.simm13 + (access_size / 8)); } else { - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, access_size, enc_i0.rs1, - enc_i0.rs2, 0); - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, access_size, enc_i0.rs1, - enc_i0.rs2, (access_size / 8)); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, access_size, enc_i0.rs1, + enc_i0.rs2, 0); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, access_size, enc_i0.rs1, + enc_i0.rs2, (access_size / 8)); } return true; } @@ -1865,9 +1700,9 @@ static bool TryDecodeSETHI(Instruction &inst, uint32_t bits) { return true; } -static bool TryDecodeSET_IDIOM( - Instruction &inst, uint32_t bits1, uint32_t bits2, - const char *base, const char *multi) { +static bool TryDecodeSET_IDIOM(Instruction &inst, uint32_t bits1, + uint32_t bits2, const char *base, + const char *multi) { Format0a enc1 = {bits1}; Format3ai0 enc2_i0 = {bits2}; Format3ai1 enc2_i1 = {bits2}; @@ -1883,6 +1718,7 @@ static bool TryDecodeSET_IDIOM( // sethi imm_high, rd // or rd, imm_low, rd if (enc2_i1.rs1 == enc1.rd) { + //const auto imm = static_cast(imm_low | imm_high); inst.function = "SET"; AddImmop(inst, static_cast(imm_high), kAddressSize, false); @@ -1984,13 +1820,13 @@ static bool TryDecodeSET_IDIOM( return true; } -static bool TryDecodeSET_SETHI_OR( - Instruction &inst, uint32_t bits1, uint32_t bits2) { +static bool TryDecodeSET_SETHI_OR(Instruction &inst, uint32_t bits1, + uint32_t bits2) { return TryDecodeSET_IDIOM(inst, bits1, bits2, "OR", "SETHI_OR"); } -static bool TryDecodeSET_SETHI_ADD( - Instruction &inst, uint32_t bits1, uint32_t bits2) { +static bool TryDecodeSET_SETHI_ADD(Instruction &inst, uint32_t bits1, + uint32_t bits2) { return TryDecodeSET_IDIOM(inst, bits1, bits2, "ADD", "SETHI_ADD"); } @@ -2014,11 +1850,11 @@ static bool TryDecode_Shift(Instruction &inst, uint32_t bits, Format3ai0 enc_i1 = {bits}; AddIntRegop(inst, enc_i0.rs1, kAddressSize, Operand::kActionRead); if (enc_i1.i) { -/* if (enc_i1.asi) { + /* if (enc_i1.asi) { LOG(ERROR) << "TryDecode_Shift asi is null"; return false; // Reserved bits; must be zero. }*/ - AddImmop(inst, enc_i1.rs2 /* shcnt */, kAddressSize, false); + AddImmop(inst, enc_i1.rs2 /* shcnt */, kAddressSize, false); // Embed the masking of the shift in the operand. } else if (enc_i0.rs2) { @@ -2036,7 +1872,7 @@ static bool TryDecode_Shift(Instruction &inst, uint32_t bits, // Register `%g0` is `rs2`. } else { - AddImmop(inst, 0 /* shcnt */, kAddressSize, false); + AddImmop(inst, 0 /* shcnt */, kAddressSize, false); } AddIntRegop(inst, enc_i0.rd, kAddressSize, Operand::kActionWrite); @@ -2067,8 +1903,7 @@ static bool TryDecodeMOVcc(Instruction &inst, uint32_t bits) { } if (enc_i1.i) { - AddImmop(inst, static_cast(enc_i1.simm11), - kAddressSize, true); + AddImmop(inst, static_cast(enc_i1.simm11), kAddressSize, true); } else { AddIntRegop(inst, enc_i0.rs2, kAddressSize, Operand::kActionRead); } @@ -2078,7 +1913,8 @@ static bool TryDecodeMOVcc(Instruction &inst, uint32_t bits) { inst.category = Instruction::kCategoryNormal; inst.function.reserve(12); inst.function.insert(0, "MOV"); - inst.function += (cc_index < 0b100) ? kFCondName[enc_i0.cond] : kCondName[enc_i0.cond]; + inst.function += + (cc_index < 0b100) ? kFCondName[enc_i0.cond] : kCondName[enc_i0.cond]; inst.function.push_back('_'); inst.function += cc; return true; @@ -2095,8 +1931,7 @@ static bool TryDecodeMOVr(Instruction &inst, uint32_t bits) { if (enc_i1.i) { AddIntRegop(inst, enc_i1.rs1, kAddressSize, Operand::kActionRead); - AddImmop(inst, static_cast(enc_i1.simm10), - kAddressSize, true); + AddImmop(inst, static_cast(enc_i1.simm10), kAddressSize, true); } else { AddIntRegop(inst, enc_i0.rs1, kAddressSize, Operand::kActionRead); AddIntRegop(inst, enc_i0.rs2, kAddressSize, Operand::kActionRead); @@ -2163,15 +1998,14 @@ static bool TryDecodeSWAP(Instruction &inst, uint32_t bits) { inst.is_atomic_read_modify_write = true; inst.function = "SWAP"; inst.category = Instruction::kCategoryNormal; + // if i != 0 if (enc_i1.i) { - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, kAddressSize, enc_i0.rs1, - 0, enc_i1.simm13); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, kAddressSize, + enc_i0.rs1, 0, enc_i1.simm13); } else { - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, kAddressSize, enc_i0.rs1, - 0, enc_i0.rs2); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, kAddressSize, + enc_i0.rs1, 0, enc_i0.rs2); } AddIntRegop(inst, enc_i0.rd, kAddressSize, Operand::kActionWrite); @@ -2180,153 +2014,85 @@ static bool TryDecodeSWAP(Instruction &inst, uint32_t bits) { static bool (*const kop00_op2Level[1u << 3])(Instruction &, uint32_t) = { - [0b000] = TryDecodeUNIMP, - [0b001] = TryDecodeBPcc, - [0b010] = TryDecodeBcc, - [0b011] = TryDecodeBPr, - [0b100] = TryDecodeSETHI, - [0b101] = TryDecodeFBPcc, - [0b110] = TryDecodeFBcc, - [0b111] = TryDecodeCB, + [0b000] = TryDecodeUNIMP, [0b001] = TryDecodeBPcc, + [0b010] = TryDecodeBcc, [0b011] = TryDecodeBPr, + [0b100] = TryDecodeSETHI, [0b101] = TryDecodeFBPcc, + [0b110] = TryDecodeFBcc, [0b111] = TryDecodeCB, }; static bool (*const kop10_op3Level[1U << 6])(Instruction &, uint32_t) = { - [0b000000] = TryDecodeADD, - [0b000001] = TryDecodeAND, - [0b000010] = TryDecodeOR, - [0b000011] = TryDecodeXOR, - [0b000100] = TryDecodeSUB, - [0b000101] = TryDecodeANDN, - [0b000110] = TryDecodeORN, - [0b000111] = TryDecodeXNOR, - [0b001000] = TryDecodeADDX, - [0b001001] = TryDecodeMULX, - [0b001010] = TryDecodeUMUL, - [0b001011] = TryDecodeSMUL, - [0b001100] = TryDecodeSUBX, - [0b001101] = nullptr, - [0b001110] = TryDecodeUDIV, - [0b001111] = TryDecodeSDIV, - [0b010000] = TryDecodeADDcc, - [0b010001] = TryDecodeANDcc, - [0b010010] = TryDecodeORcc, - [0b010011] = TryDecodeXORcc, - [0b010100] = TryDecodeSUBcc, - [0b010101] = TryDecodeANDNcc, - [0b010110] = TryDecodeORNcc, - [0b010111] = TryDecodeXNORcc, - [0b011000] = TryDecodeADDXcc, - [0b011001] = nullptr, - [0b011010] = TryDecodeUMULcc, - [0b011011] = TryDecodeSMULcc, - [0b011100] = TryDecodeSUBXcc, - [0b011101] = nullptr, - [0b011110] = TryDecodeUDIVcc, - [0b011111] = TryDecodeSDIVcc, - [0b100000] = nullptr, - [0b100001] = nullptr, - [0b100010] = nullptr, - [0b100011] = nullptr, - [0b100100] = TryDecodeMULScc, - [0b100101] = TryDecodeSLL, - [0b100110] = TryDecodeSRL, - [0b100111] = TryDecodeSRA, - [0b101000] = TryDecodeRDasr, - [0b101001] = nullptr, - [0b101010] = nullptr, - [0b101011] = nullptr, - [0b101100] = TryDecodeMOVcc, - [0b101101] = nullptr, - [0b101110] = nullptr, - [0b101111] = TryDecodeMOVr, - [0b110000] = TryDecodeWRasr, - [0b110001] = nullptr, - [0b110010] = nullptr, - [0b110011] = nullptr, - [0b110100] = TryDecodeOpf52, - [0b110101] = TryDecodeFCMP_FMOV, - [0b110110] = nullptr, - [0b110111] = nullptr, - [0b111000] = TryDecodeJMPL, - [0b111001] = TryDecodeRETT, - [0b111010] = TryDecodeTcc, - [0b111011] = nullptr, - [0b111100] = TryDecodeSave, - [0b111101] = TryDecodeRestore, - [0b111110] = nullptr, - [0b111111] = nullptr, + [0b000000] = TryDecodeADD, [0b000001] = TryDecodeAND, + [0b000010] = TryDecodeOR, [0b000011] = TryDecodeXOR, + [0b000100] = TryDecodeSUB, [0b000101] = TryDecodeANDN, + [0b000110] = TryDecodeORN, [0b000111] = TryDecodeXNOR, + [0b001000] = TryDecodeADDX, [0b001001] = TryDecodeMULX, + [0b001010] = TryDecodeUMUL, [0b001011] = TryDecodeSMUL, + [0b001100] = TryDecodeSUBX, [0b001101] = nullptr, + [0b001110] = TryDecodeUDIV, [0b001111] = TryDecodeSDIV, + [0b010000] = TryDecodeADDcc, [0b010001] = TryDecodeANDcc, + [0b010010] = TryDecodeORcc, [0b010011] = TryDecodeXORcc, + [0b010100] = TryDecodeSUBcc, [0b010101] = TryDecodeANDNcc, + [0b010110] = TryDecodeORNcc, [0b010111] = TryDecodeXNORcc, + [0b011000] = TryDecodeADDXcc, [0b011001] = nullptr, + [0b011010] = TryDecodeUMULcc, [0b011011] = TryDecodeSMULcc, + [0b011100] = TryDecodeSUBXcc, [0b011101] = nullptr, + [0b011110] = TryDecodeUDIVcc, [0b011111] = TryDecodeSDIVcc, + [0b100000] = nullptr, [0b100001] = nullptr, + [0b100010] = nullptr, [0b100011] = nullptr, + [0b100100] = TryDecodeMULScc, [0b100101] = TryDecodeSLL, + [0b100110] = TryDecodeSRL, [0b100111] = TryDecodeSRA, + [0b101000] = TryDecodeRDasr, [0b101001] = nullptr, + [0b101010] = nullptr, [0b101011] = nullptr, + [0b101100] = TryDecodeMOVcc, [0b101101] = nullptr, + [0b101110] = nullptr, [0b101111] = TryDecodeMOVr, + [0b110000] = TryDecodeWRasr, [0b110001] = nullptr, + [0b110010] = nullptr, [0b110011] = nullptr, + [0b110100] = TryDecodeOpf52, [0b110101] = TryDecodeFCMP_FMOV, + [0b110110] = nullptr, [0b110111] = nullptr, + [0b111000] = TryDecodeJMPL, [0b111001] = TryDecodeRETT, + [0b111010] = TryDecodeTcc, [0b111011] = nullptr, + [0b111100] = TryDecodeSave, [0b111101] = TryDecodeRestore, + [0b111110] = nullptr, [0b111111] = nullptr, }; static bool (*const kop11_op3Level[1u << 6])(Instruction &, uint32_t) = { - [0b000000] = TryDecodeLD, - [0b000001] = TryDecodeLDUB, - [0b000010] = TryDecodeLDUH, - [0b000011] = TryDecodeLDD, - [0b000100] = TryDecodeST, - [0b000101] = TryDecodeSTB, - [0b000110] = TryDecodeSTH, - [0b000111] = TryDecodeSTD, - [0b001000] = nullptr, - [0b001001] = TryDecodeLDSB, - [0b001010] = TryDecodeLDSH, - [0b001011] = nullptr, - [0b001100] = nullptr, - [0b001101] = TryDecodeLDSTUB, - [0b001110] = TryDecodeSTX, - [0b001111] = TryDecodeSWAP, - [0b010000] = nullptr, - [0b010001] = nullptr, - [0b010010] = nullptr, - [0b010011] = nullptr, - [0b010100] = nullptr, - [0b010101] = nullptr, - [0b010110] = nullptr, - [0b010111] = nullptr, - [0b011000] = nullptr, - [0b011001] = nullptr, - [0b011010] = nullptr, - [0b011011] = nullptr, - [0b011100] = nullptr, - [0b011101] = nullptr, - [0b011110] = nullptr, - [0b011111] = nullptr, - [0b100000] = TryDecodeLDF, - [0b100001] = nullptr, - [0b100010] = nullptr, - [0b100011] = TryDecodeLDDF, - [0b100100] = TryDecodeSTF, - [0b100101] = nullptr, - [0b100110] = nullptr, - [0b100111] = TryDecodeSTDF, - [0b101000] = nullptr, - [0b101001] = nullptr, - [0b101010] = nullptr, - [0b101011] = nullptr, - [0b101100] = nullptr, - [0b101101] = nullptr, - [0b101110] = nullptr, - [0b101111] = nullptr, - [0b110000] = nullptr, - [0b110001] = nullptr, - [0b110010] = nullptr, - [0b110011] = nullptr, - [0b110100] = nullptr, - [0b110101] = nullptr, - [0b110110] = nullptr, - [0b110111] = nullptr, - [0b111000] = nullptr, - [0b111001] = nullptr, - [0b111010] = nullptr, - [0b111011] = nullptr, - [0b111100] = TryDecodeCASA, - [0b111101] = nullptr, - [0b111110] = nullptr, - [0b111111] = nullptr, - - //[0b100001] = TryDecodeLDFSR - //[0b100101] = TryDecodeSTFSR, - //[0b100110] = TryDecodeSTDFQ, - // [0b111110] = TryDecodeCASXA, + [0b000000] = TryDecodeLD, [0b000001] = TryDecodeLDUB, + [0b000010] = TryDecodeLDUH, [0b000011] = TryDecodeLDD, + [0b000100] = TryDecodeST, [0b000101] = TryDecodeSTB, + [0b000110] = TryDecodeSTH, [0b000111] = TryDecodeSTD, + [0b001000] = nullptr, [0b001001] = TryDecodeLDSB, + [0b001010] = TryDecodeLDSH, [0b001011] = nullptr, + [0b001100] = nullptr, [0b001101] = TryDecodeLDSTUB, + [0b001110] = TryDecodeSTX, [0b001111] = TryDecodeSWAP, + [0b010000] = nullptr, [0b010001] = nullptr, + [0b010010] = nullptr, [0b010011] = nullptr, + [0b010100] = nullptr, [0b010101] = nullptr, + [0b010110] = nullptr, [0b010111] = nullptr, + [0b011000] = nullptr, [0b011001] = nullptr, + [0b011010] = nullptr, [0b011011] = nullptr, + [0b011100] = nullptr, [0b011101] = nullptr, + [0b011110] = nullptr, [0b011111] = nullptr, + [0b100000] = TryDecodeLDF, [0b100001] = nullptr, + [0b100010] = nullptr, [0b100011] = TryDecodeLDDF, + [0b100100] = TryDecodeSTF, [0b100101] = nullptr, + [0b100110] = nullptr, [0b100111] = TryDecodeSTDF, + [0b101000] = nullptr, [0b101001] = nullptr, + [0b101010] = nullptr, [0b101011] = nullptr, + [0b101100] = nullptr, [0b101101] = nullptr, + [0b101110] = nullptr, [0b101111] = nullptr, + [0b110000] = nullptr, [0b110001] = nullptr, + [0b110010] = nullptr, [0b110011] = nullptr, + [0b110100] = nullptr, [0b110101] = nullptr, + [0b110110] = nullptr, [0b110111] = nullptr, + [0b111000] = nullptr, [0b111001] = nullptr, + [0b111010] = nullptr, [0b111011] = nullptr, + [0b111100] = TryDecodeCASA, [0b111101] = nullptr, + [0b111110] = nullptr, [0b111111] = nullptr, + + //[0b100001] = TryDecodeLDFSR + //[0b100101] = TryDecodeSTFSR, + //[0b100110] = TryDecodeSTDFQ, + // [0b111110] = TryDecodeCASXA, }; // SETHI, Branches, and ILLTRAP @@ -2334,8 +2100,7 @@ static bool TryDecode_op00(Instruction &inst, uint32_t bits) { auto index = (bits >> 22u) & 0x7u; auto func = kop00_op2Level[index]; if (!func) { - LOG(ERROR) - << "OP=00 op2=" << std::bitset<3>(index); + LOG(ERROR) << "OP=00 op2=" << std::bitset<3>(index); return false; } return func(inst, bits); @@ -2350,8 +2115,7 @@ static bool TryDecode_op10(Instruction &inst, uint32_t bits) { auto index = (bits >> 19u) & 0x3Fu; auto func = kop10_op3Level[index]; if (!func) { - LOG(ERROR) - << "OP=10 op3=" << std::bitset<6>(index); + LOG(ERROR) << "OP=10 op3=" << std::bitset<6>(index); return false; } return func(inst, bits); @@ -2361,19 +2125,14 @@ static bool TryDecode_op11(Instruction &inst, uint32_t bits) { auto index = (bits >> 19u) & 0x3Fu; auto func = kop11_op3Level[index]; if (!func) { - LOG(ERROR) - << "OP=11 op3=" << std::bitset<6>(index); + LOG(ERROR) << "OP=11 op3=" << std::bitset<6>(index); return false; } return func(inst, bits); } static bool (*const kopLevel[])(Instruction &, uint32_t) = { - TryDecode_op00, - TryDecode_op01, - TryDecode_op10, - TryDecode_op11 -}; + TryDecode_op00, TryDecode_op01, TryDecode_op10, TryDecode_op11}; static uint32_t BytesToBits(const uint8_t *bytes) { uint32_t bits = 0; @@ -2397,9 +2156,8 @@ bool TryDecode(Instruction &inst) { } else if (num_bytes == 8) { if (inst.in_delay_slot) { - LOG(WARNING) - << "Decoding 8-byte pseudo-op at " << std::hex << inst.pc << std::dec - << " in delay slot; ignoring second four bytes"; + LOG(WARNING) << "Decoding 8-byte pseudo-op at " << std::hex << inst.pc + << std::dec << " in delay slot; ignoring second four bytes"; inst.bytes.resize(4); inst.next_pc = inst.pc + 4; return TryDecode(inst); @@ -2418,7 +2176,7 @@ bool TryDecode(Instruction &inst) { const auto bits2_op3 = (bits2 >> 19u) & 0x3Fu; if (bits2_op == 0b10 && bits2_op3 == 0b000010) { // OR. ret = TryDecodeSET_SETHI_OR(inst, bits1, bits2); - } else if (bits2_op == 0b10 && bits2_op3 == 0b000000) { // ADD + } else if (bits2_op == 0b10 && bits2_op3 == 0b000000) { // ADD ret = TryDecodeSET_SETHI_ADD(inst, bits1, bits2); } } @@ -2428,8 +2186,8 @@ bool TryDecode(Instruction &inst) { inst.next_pc = inst.pc + 4; ret = TryDecode(inst); - LOG_IF(ERROR, !ret) - << "Unsupported 8-byte instruction: " << inst.Serialize(); + LOG_IF(ERROR, !ret) << "Unsupported 8-byte instruction: " + << inst.Serialize(); } return ret; diff --git a/lib/Arch/SPARC32/Runtime/Instructions.cpp b/lib/Arch/SPARC32/Runtime/Instructions.cpp index 15d000289..a80129d5d 100644 --- a/lib/Arch/SPARC32/Runtime/Instructions.cpp +++ b/lib/Arch/SPARC32/Runtime/Instructions.cpp @@ -24,111 +24,111 @@ #include "remill/Arch/SPARC32/Runtime/State.h" #include "remill/Arch/SPARC32/Runtime/Types.h" -#define REG_PC state.pc.aword -#define REG_NPC state.next_pc.aword -#define REG_SP state.gpr.o6.aword -#define REG_FP state.gpr.i6.aword - -#define REG_G0 state.gpr.g0.aword -#define REG_G1 state.gpr.g1.aword -#define REG_G7 state.gpr.g7.aword // Thread local pointer - -#define REG_L0 state.gpr.l0.aword -#define REG_L1 state.gpr.l1.aword -#define REG_L2 state.gpr.l2.aword -#define REG_L3 state.gpr.l3.aword -#define REG_L4 state.gpr.l4.aword -#define REG_L5 state.gpr.l5.aword -#define REG_L6 state.gpr.l6.aword -#define REG_L7 state.gpr.l7.aword - -#define REG_I0 state.gpr.i0.aword -#define REG_I1 state.gpr.i1.aword -#define REG_I2 state.gpr.i2.aword -#define REG_I3 state.gpr.i3.aword -#define REG_I4 state.gpr.i4.aword -#define REG_I5 state.gpr.i5.aword -#define REG_I6 state.gpr.i6.aword -#define REG_I7 state.gpr.i7.aword - -#define REG_O0 state.gpr.o0.aword -#define REG_O1 state.gpr.o1.aword -#define REG_O2 state.gpr.o2.aword -#define REG_O3 state.gpr.o3.aword -#define REG_O4 state.gpr.o4.aword -#define REG_O5 state.gpr.o5.aword -#define REG_O6 state.gpr.o6.aword -#define REG_O7 state.gpr.o7.aword - -#define REG_F0 state.fpreg.v[0].floats.elems[0] -#define REG_F1 state.fpreg.v[0].floats.elems[1] -#define REG_F2 state.fpreg.v[0].floats.elems[2] -#define REG_F3 state.fpreg.v[0].floats.elems[3] - -#define REG_D0 state.fpreg.v[0].qwords.elems[0] +#define REG_PC state.pc.aword +#define REG_NPC state.next_pc.aword +#define REG_SP state.gpr.o6.aword +#define REG_FP state.gpr.i6.aword + +#define REG_G0 state.gpr.g0.aword +#define REG_G1 state.gpr.g1.aword +#define REG_G7 state.gpr.g7.aword // Thread local pointer + +#define REG_L0 state.gpr.l0.aword +#define REG_L1 state.gpr.l1.aword +#define REG_L2 state.gpr.l2.aword +#define REG_L3 state.gpr.l3.aword +#define REG_L4 state.gpr.l4.aword +#define REG_L5 state.gpr.l5.aword +#define REG_L6 state.gpr.l6.aword +#define REG_L7 state.gpr.l7.aword + +#define REG_I0 state.gpr.i0.aword +#define REG_I1 state.gpr.i1.aword +#define REG_I2 state.gpr.i2.aword +#define REG_I3 state.gpr.i3.aword +#define REG_I4 state.gpr.i4.aword +#define REG_I5 state.gpr.i5.aword +#define REG_I6 state.gpr.i6.aword +#define REG_I7 state.gpr.i7.aword + +#define REG_O0 state.gpr.o0.aword +#define REG_O1 state.gpr.o1.aword +#define REG_O2 state.gpr.o2.aword +#define REG_O3 state.gpr.o3.aword +#define REG_O4 state.gpr.o4.aword +#define REG_O5 state.gpr.o5.aword +#define REG_O6 state.gpr.o6.aword +#define REG_O7 state.gpr.o7.aword + +#define REG_F0 state.fpreg.v[0].floats.elems[0] +#define REG_F1 state.fpreg.v[0].floats.elems[1] +#define REG_F2 state.fpreg.v[0].floats.elems[2] +#define REG_F3 state.fpreg.v[0].floats.elems[3] + +#define REG_D0 state.fpreg.v[0].qwords.elems[0] // GSR Register -#define GSR_ALIGN state.asr.gsr.align -#define GSR_MASK state.asr.gsr.mask - -#define REG_Y state.asr.yreg.aword - -#define FLAG_ICC_CF state.asr.ccr.icc.c -#define FLAG_ICC_VF state.asr.ccr.icc.v -#define FLAG_ICC_ZF state.asr.ccr.icc.z -#define FLAG_ICC_NF state.asr.ccr.icc.n - -#define FLAG_XCC_CF state.asr.ccr.xcc.c -#define FLAG_XCC_VF state.asr.ccr.xcc.v -#define FLAG_XCC_ZF state.asr.ccr.xcc.z -#define FLAG_XCC_NF state.asr.ccr.xcc.n - -#define REG_ICC state.asr.ccr.icc.flat -#define REG_XCC state.asr.ccr.xcc.flat -#define REG_CCC state.csr.ccc - -#define FSR_FCC0 state.fsr.fcc0 -#define FSR_FCC1 state.fsr.fcc1 -#define FSR_FCC2 state.fsr.fcc2 -#define FSR_FCC3 state.fsr.fcc3 - -#define FSR_CEXC state.fsr.cexc -#define FSR_FTT state.fsr.ftt -#define FSR_RD state.fsr.rd - -#define PSR_TPC state.psr.tpc -#define PSR_TNPC state.psr.tnpc -#define PSR_TSTATE state.psr.tstate -#define PSR_TT state.psr.tt -#define PSR_TBA state.psr.tba -#define PSR_PSTATE state.psr.pstate -#define PSR_TL state.psr.tl -#define PSR_PIL state.psr.pil -#define PSR_WSTATE state.psr.wstate -#define PSR_CWP state.psr.cwp -#define PSR_CANSAVE state.psr.cansave -#define PSR_CANRESTORE state.psr.canrestore -#define PSR_CLEANWIN state.psr.cleanwin -#define PSR_OTHERWIN state.psr.otherwin -#define PSR_GL state.psr.gl - -#define ASR_Y state.asr.yreg.dword -#define ASR_ASI state.asr.asi_flat -#define ASR_PC state.pc.aword -#define ASR_FPRS state.asr.fprs_flat -#define ASR_GSR state.asr.gsr.flat -#define ASR_SOFTINT state.asr.softint -#define ASR_STICK_CMPR state.asr.stick_cmpr -#define ASR_PAUSE state.asr.pause - -#define HYPER_CALL state.hyper_call -#define INTERRUPT_VECTOR state.hyper_call_vector -#define HYPER_CALL_VECTOR state.hyper_call_vector +#define GSR_ALIGN state.asr.gsr.align +#define GSR_MASK state.asr.gsr.mask + +#define REG_Y state.asr.yreg.aword + +#define FLAG_ICC_CF state.asr.ccr.icc.c +#define FLAG_ICC_VF state.asr.ccr.icc.v +#define FLAG_ICC_ZF state.asr.ccr.icc.z +#define FLAG_ICC_NF state.asr.ccr.icc.n + +#define FLAG_XCC_CF state.asr.ccr.xcc.c +#define FLAG_XCC_VF state.asr.ccr.xcc.v +#define FLAG_XCC_ZF state.asr.ccr.xcc.z +#define FLAG_XCC_NF state.asr.ccr.xcc.n + +#define REG_ICC state.asr.ccr.icc.flat +#define REG_XCC state.asr.ccr.xcc.flat +#define REG_CCC state.csr.ccc + +#define FSR_FCC0 state.fsr.fcc0 +#define FSR_FCC1 state.fsr.fcc1 +#define FSR_FCC2 state.fsr.fcc2 +#define FSR_FCC3 state.fsr.fcc3 + +#define FSR_CEXC state.fsr.cexc +#define FSR_FTT state.fsr.ftt +#define FSR_RD state.fsr.rd + +#define PSR_TPC state.psr.tpc +#define PSR_TNPC state.psr.tnpc +#define PSR_TSTATE state.psr.tstate +#define PSR_TT state.psr.tt +#define PSR_TBA state.psr.tba +#define PSR_PSTATE state.psr.pstate +#define PSR_TL state.psr.tl +#define PSR_PIL state.psr.pil +#define PSR_WSTATE state.psr.wstate +#define PSR_CWP state.psr.cwp +#define PSR_CANSAVE state.psr.cansave +#define PSR_CANRESTORE state.psr.canrestore +#define PSR_CLEANWIN state.psr.cleanwin +#define PSR_OTHERWIN state.psr.otherwin +#define PSR_GL state.psr.gl + +#define ASR_Y state.asr.yreg.dword +#define ASR_ASI state.asr.asi_flat +#define ASR_PC state.pc.aword +#define ASR_FPRS state.asr.fprs_flat +#define ASR_GSR state.asr.gsr.flat +#define ASR_SOFTINT state.asr.softint +#define ASR_STICK_CMPR state.asr.stick_cmpr +#define ASR_PAUSE state.asr.pause + +#define HYPER_CALL state.hyper_call +#define INTERRUPT_VECTOR state.hyper_call_vector +#define HYPER_CALL_VECTOR state.hyper_call_vector #if ADDRESS_SIZE_BITS == 64 -# define SPARC_STACKBIAS 0 +# define SPARC_STACKBIAS 0 #else -# define SPARC_STACKBIAS 0 +# define SPARC_STACKBIAS 0 #endif namespace { @@ -136,7 +136,9 @@ namespace { // Takes the place of an unsupported instruction. DEF_SEM(HandleUnsupported) { return __remill_sync_hyper_call( - state, memory, SyncHyperCall::IF_32BIT_ELSE(kSPARC32EmulateInstruction, kSPARC64EmulateInstruction)); + state, memory, + SyncHyperCall::IF_32BIT_ELSE(kSPARC32EmulateInstruction, + kSPARC64EmulateInstruction)); } // Takes the place of an invalid instruction. @@ -145,12 +147,13 @@ DEF_SEM(HandleInvalidInstruction) { return memory; } -DEF_HELPER(SAVE_WINDOW, RegisterWindow *window, RegisterWindow *&prev_window) -> void { +DEF_HELPER(SAVE_WINDOW, RegisterWindow *window, RegisterWindow *&prev_window) + ->void { -// TODO(pag): These two lines should be uncommented for correctness, but then -// they don't result in as nice bitcode in McSema :-( -// window->prev_window = state.window; -// state.window = window; + // TODO(pag): These two lines should be uncommented for correctness, but then + // they don't result in as nice bitcode in McSema :-( + // window->prev_window = state.window; + // state.window = window; prev_window = window; @@ -183,18 +186,18 @@ DEF_HELPER(SAVE_WINDOW, RegisterWindow *window, RegisterWindow *&prev_window) -> Write(REG_I7, REG_O7); } -DEF_HELPER(RESTORE_WINDOW, RegisterWindow *&prev_window) -> void { +DEF_HELPER(RESTORE_WINDOW, RegisterWindow *&prev_window)->void { const auto window = prev_window ? prev_window : state.window; if (!window) { - memory = __remill_sync_hyper_call( - state, memory, SyncHyperCall::kSPARCWindowUnderflow); + memory = __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCWindowUnderflow); return; } -// TODO(pag): This next line should be uncommented for correctness, but then -// it means not as nice bitcode for mcsema. -// state.window = window->prev_window; + // TODO(pag): This next line should be uncommented for correctness, but then + // it means not as nice bitcode for mcsema. + // state.window = window->prev_window; // Move input register to output Write(REG_O0, REG_I0); @@ -233,6 +236,7 @@ DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; #include "lib/Arch/SPARC32/Semantics/FLAGS.cpp" #include "lib/Arch/SPARC32/Semantics/COND.cpp" + #include "lib/Arch/SPARC32/Semantics/BINARY.cpp" #include "lib/Arch/SPARC32/Semantics/BRANCH.cpp" #include "lib/Arch/SPARC32/Semantics/DATAXFER.cpp" @@ -241,4 +245,3 @@ DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; #include "lib/Arch/SPARC32/Semantics/MISC.cpp" #include "lib/Arch/SPARC32/Semantics/TRAP.cpp" #include "lib/Arch/SPARC32/Semantics/WINDOW.cpp" - diff --git a/lib/Arch/SPARC32/Semantics/BINARY.cpp b/lib/Arch/SPARC32/Semantics/BINARY.cpp index b4ca1e344..61cf16676 100644 --- a/lib/Arch/SPARC32/Semantics/BINARY.cpp +++ b/lib/Arch/SPARC32/Semantics/BINARY.cpp @@ -18,35 +18,39 @@ ALWAYS_INLINE static void WriteFlagsAddSub(State &state, T lhs, T rhs, T res) { } template -ALWAYS_INLINE static void WriteXCCFlagsIncDec(State &state, T lhs, T rhs, T res) { +ALWAYS_INLINE static void WriteXCCFlagsIncDec(State &state, T lhs, T rhs, + T res) { FLAG_XCC_ZF = ZeroFlag(res); FLAG_XCC_NF = SignFlag(res); FLAG_XCC_VF = Overflow::Flag(lhs, rhs, res); } template -ALWAYS_INLINE static void WriteICCFlagsIncDec(State &state, T lhs, T rhs, T res) { +ALWAYS_INLINE static void WriteICCFlagsIncDec(State &state, T lhs, T rhs, + T res) { FLAG_ICC_ZF = ZeroFlag(res); FLAG_ICC_NF = SignFlag(res); FLAG_ICC_VF = Overflow::Flag(lhs, rhs, res); } template -ALWAYS_INLINE static void WriteICCFlagsAddSub(State &state, uint32_t lhs, uint32_t rhs, uint32_t res) { +ALWAYS_INLINE static void WriteICCFlagsAddSub(State &state, uint32_t lhs, + uint32_t rhs, uint32_t res) { FLAG_ICC_CF = Carry::Flag(lhs, rhs, res); WriteICCFlagsIncDec(state, lhs, rhs, res); } template -ALWAYS_INLINE static void WriteXCCFlagsAddSub(State &state, uint64_t lhs, uint64_t rhs, uint64_t res) { +ALWAYS_INLINE static void WriteXCCFlagsAddSub(State &state, uint64_t lhs, + uint64_t rhs, uint64_t res) { FLAG_XCC_CF = Carry::Flag(lhs, rhs, res); WriteXCCFlagsIncDec(state, lhs, rhs, res); } template DEF_SEM(SUB, S1 src1, S2 src2, D dst) { -Write(dst, USub(Read(src1), Read(src2))); -return memory; + Write(dst, USub(Read(src1), Read(src2))); + return memory; } template @@ -200,8 +204,8 @@ DEF_SEM(SDIV, S1 src1, S2 src2, D dst) { auto lhs = Read(src1); auto lhs_wide = ZExt(lhs); auto y = Read(REG_Y); - auto y_lhs_wide = Signed(UOr(decltype(lhs_wide)( - UShl(y, Literal(32))), lhs_wide)); + auto y_lhs_wide = Signed( + UOr(decltype(lhs_wide)(UShl(y, Literal(32))), lhs_wide)); auto rhs = Signed(Read(src2)); auto rhs_wide = SExt(rhs); auto quot = SDiv(y_lhs_wide, rhs_wide); @@ -214,8 +218,8 @@ DEF_SEM(SDIVcc, S1 src1, S2 src2, D dst) { auto lhs = Read(src1); auto lhs_wide = ZExt(lhs); auto y = Read(REG_Y); - auto y_lhs_wide = Signed(UOr(decltype(lhs_wide)( - UShl(y, Literal(32))), lhs_wide)); + auto y_lhs_wide = Signed( + UOr(decltype(lhs_wide)(UShl(y, Literal(32))), lhs_wide)); auto rhs = Read(src2); auto rhs_wide = SExt(rhs); auto quot = SDiv(y_lhs_wide, rhs_wide); @@ -287,7 +291,8 @@ DEF_SEM(MULSCC_R32, R32 src1, R32 src2, R32W dest) { auto lsb_y = UAnd(y, Literal(0x1)); auto masked_rs1 = UAnd(rs1, Literal(0xffffffff)); auto masked_rs2 = UAnd(rs2, Literal(0xffffffff)); - auto new_rs2 = Select(UCmpEq(lsb_y, 0), Literal(0), masked_rs2); + auto new_rs2 = + Select(UCmpEq(lsb_y, 0), Literal(0), masked_rs2); auto flag_nf = Literal(Read(FLAG_ICC_NF)); auto flag_vf = Literal(Read(FLAG_ICC_VF)); @@ -296,21 +301,23 @@ DEF_SEM(MULSCC_R32, R32 src1, R32 src2, R32W dest) { auto new_rs1 = UOr(UShr(masked_rs1, Literal(1)), Literal(shifted_flag)); auto res = UAdd(new_rs1, new_rs2); + // Y register is shifted right by one bit, with the LSB of the unshifted // r[rs1] replacing the MSB of Y auto shifted_y = UShr(y, Literal(1)); - auto lsb_rs1 = UAnd(rs1, Literal(0x1)); - auto new_y = UOr(shifted_y, decltype(y)(UShl(lsb_rs1, Literal(31)))); + auto lsb_rs1 = UAnd(rs1, Literal(0x1)); + auto new_y = UOr(shifted_y, + decltype(y)(UShl(lsb_rs1, Literal(31)))); Write(REG_Y, new_y); Write(dest, res); - WriteICCFlagsAddSub( - state, static_cast(new_rs1), - static_cast(new_rs2), static_cast(res)); + WriteICCFlagsAddSub(state, static_cast(new_rs1), + static_cast(new_rs2), + static_cast(res)); return memory; } -} +} // namespace DEF_ISEL(MULScc) = MULSCC_R32; diff --git a/lib/Arch/SPARC32/Semantics/BRANCH.cpp b/lib/Arch/SPARC32/Semantics/BRANCH.cpp index 1fcfecdaf..4fd19f96a 100644 --- a/lib/Arch/SPARC32/Semantics/BRANCH.cpp +++ b/lib/Arch/SPARC32/Semantics/BRANCH.cpp @@ -7,8 +7,7 @@ namespace { // NOTE(pag): `new_pc == pc_of_jmp + 4`, and `new_npc` // is the target EA. template -DEF_SEM(JMPL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst, - T dst_pc, T dst_npc) { +DEF_SEM(JMPL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst, T dst_pc, T dst_npc) { auto new_dst = Read(pc_of_jmp); auto new_dst_pc = Read(new_pc); auto new_dst_npc = Read(new_npc); @@ -20,8 +19,8 @@ DEF_SEM(JMPL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst, // This is a variation on JMPL that also stores the return address. template -DEF_SEM(CALL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst, - T dst_pc, T dst_npc, T return_pc_dst) { +DEF_SEM(CALL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst, T dst_pc, T dst_npc, + T return_pc_dst) { Write(dst, Read(pc_of_jmp)); Write(dst_pc, Read(new_pc)); Write(dst_npc, Read(new_npc)); @@ -37,10 +36,10 @@ DEF_SEM(CALL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst, // is placed inside of a delay slot. #define MAKE_BRANCH(name, cond, cc) \ namespace { \ - DEF_SEM(name ## cond ## _ ## cc, R8W branch_taken, PC new_taken_pc, PC new_taken_npc, \ - PC new_not_taken_pc, PC new_not_taken_npc, \ + DEF_SEM(name##cond##_##cc, R8W branch_taken, PC new_taken_pc, \ + PC new_taken_npc, PC new_not_taken_pc, PC new_not_taken_npc, \ R32W pc_dst, R32W npc_dst) { \ - if (Cond ## cond ## _ ## cc(state)) { \ + if (Cond##cond##_##cc(state)) { \ Write(branch_taken, true); \ Write(pc_dst, Read(new_taken_pc)); \ Write(npc_dst, Read(new_taken_npc)); \ @@ -52,35 +51,31 @@ DEF_SEM(CALL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst, return memory; \ } \ } \ - DEF_ISEL(name ## cond ## _ ## cc) = name ## cond ## _ ## cc; + DEF_ISEL(name##cond##_##cc) = name##cond##_##cc; template -DEF_SEM(BA, PC new_taken_pc, PC new_taken_npc, - T pc_dst, T npc_dst) { +DEF_SEM(BA, PC new_taken_pc, PC new_taken_npc, T pc_dst, T npc_dst) { Write(pc_dst, Read(new_taken_pc)); Write(npc_dst, Read(new_taken_npc)); return memory; } template -DEF_SEM(BN, PC new_not_taken_pc, PC new_not_taken_npc, - T pc_dst, T npc_dst) { +DEF_SEM(BN, PC new_not_taken_pc, PC new_not_taken_npc, T pc_dst, T npc_dst) { Write(pc_dst, Read(new_not_taken_pc)); Write(npc_dst, Read(new_not_taken_npc)); return memory; } template -DEF_SEM(FBA, PC new_taken_pc, PC new_taken_npc, - T pc_dst, T npc_dst) { +DEF_SEM(FBA, PC new_taken_pc, PC new_taken_npc, T pc_dst, T npc_dst) { Write(pc_dst, Read(new_taken_pc)); Write(npc_dst, Read(new_taken_npc)); return memory; } template -DEF_SEM(FBN, PC new_not_taken_pc, PC new_not_taken_npc, - T pc_dst, T npc_dst) { +DEF_SEM(FBN, PC new_not_taken_pc, PC new_not_taken_npc, T pc_dst, T npc_dst) { Write(pc_dst, Read(new_not_taken_pc)); Write(npc_dst, Read(new_not_taken_npc)); return memory; @@ -112,8 +107,8 @@ DEF_SEM(FBN, PC new_not_taken_pc, PC new_not_taken_npc, // 5 B*A(a=1) any cti 12,40,44,... (16 annulled) // 6 B*cc dcti 12,unpredictable DEF_SEM(UNSUPPORTED_DCTI) { - return __remill_sync_hyper_call( - state, memory, SyncHyperCall::kSPARCUnhandledDCTI); + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCUnhandledDCTI); } // TODO(pag): Double check that `new_pc` reads `rs1/rs2` from the pre- @@ -154,8 +149,8 @@ DEF_ISEL(FBN_fcc2) = FBN; DEF_ISEL(FBN_fcc3) = FBN; #define MAKE_BRANCH_CC(name, cond) \ - MAKE_BRANCH(name, cond, icc) \ - MAKE_BRANCH(name, cond, xcc) \ + MAKE_BRANCH(name, cond, icc) \ + MAKE_BRANCH(name, cond, xcc) MAKE_BRANCH_CC(B, NE) MAKE_BRANCH_CC(B, E) @@ -173,10 +168,10 @@ MAKE_BRANCH_CC(B, VC) MAKE_BRANCH_CC(B, VS) #define MAKE_BRANCH_F(name, cond) \ - MAKE_BRANCH(name, cond, fcc0) \ - MAKE_BRANCH(name, cond, fcc1) \ - MAKE_BRANCH(name, cond, fcc2) \ - MAKE_BRANCH(name, cond, fcc3) + MAKE_BRANCH(name, cond, fcc0) \ + MAKE_BRANCH(name, cond, fcc1) \ + MAKE_BRANCH(name, cond, fcc2) \ + MAKE_BRANCH(name, cond, fcc3) MAKE_BRANCH_F(FB, U) MAKE_BRANCH_F(FB, G) @@ -202,22 +197,22 @@ MAKE_BRANCH_F(FB, O) #define MAKE_BRANCH(name, cond) \ namespace { \ - DEF_SEM(name ## cond, R8W branch_taken, PC new_taken_pc, PC new_taken_npc, \ - PC new_not_taken_pc, PC new_not_taken_npc, \ - R32W pc_dst, R32W npc_dst) { \ - if (Cond ## cond ## _ccc(state)) { \ - Write(branch_taken, true); \ - Write(pc_dst, Read(new_taken_pc)); \ - Write(npc_dst, Read(new_taken_npc)); \ - } else { \ - Write(branch_taken, false); \ - Write(pc_dst, Read(new_not_taken_pc)); \ - Write(npc_dst, Read(new_not_taken_npc)); \ - } \ - return memory; \ + DEF_SEM(name##cond, R8W branch_taken, PC new_taken_pc, PC new_taken_npc, \ + PC new_not_taken_pc, PC new_not_taken_npc, R32W pc_dst, \ + R32W npc_dst) { \ + if (Cond##cond##_ccc(state)) { \ + Write(branch_taken, true); \ + Write(pc_dst, Read(new_taken_pc)); \ + Write(npc_dst, Read(new_taken_npc)); \ + } else { \ + Write(branch_taken, false); \ + Write(pc_dst, Read(new_not_taken_pc)); \ + Write(npc_dst, Read(new_not_taken_npc)); \ + } \ + return memory; \ } \ } \ - DEF_ISEL(name ## cond) = name ## cond; + DEF_ISEL(name##cond) = name##cond; MAKE_BRANCH(CB, A) MAKE_BRANCH(CB, N) diff --git a/lib/Arch/SPARC32/Semantics/COND.cpp b/lib/Arch/SPARC32/Semantics/COND.cpp index 30a658ce3..f6814d4c9 100644 --- a/lib/Arch/SPARC32/Semantics/COND.cpp +++ b/lib/Arch/SPARC32/Semantics/COND.cpp @@ -3,106 +3,90 @@ */ #define MAKE_CONDITIONS(cc) \ - static inline bool \ - CondA_ ## cc(const State &state) { \ - return true; \ - } \ - static inline bool \ - CondN_ ## cc(const State &state) { \ - return false; \ - } \ - static inline bool \ - CondE_ ## cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_zf = ccr.z; \ - return flag_zf; \ - } \ - static inline bool \ - CondNE_ ## cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_zf = ccr.z; \ - return !flag_zf; \ - } \ - static inline bool \ - CondG_ ## cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_nf = ccr.n; \ - const bool flag_zf = ccr.z; \ - const bool flag_vf = ccr.v; \ - return (flag_nf == flag_vf) && !flag_zf; \ - } \ - static inline bool \ - CondLE_ ## cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_nf = ccr.n; \ - const bool flag_zf = ccr.z; \ - const bool flag_vf = ccr.v; \ - return (flag_nf != flag_vf) || flag_zf; \ - } \ - static inline bool \ - CondGE_ ## cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_nf = ccr.n; \ - const bool flag_vf = ccr.v; \ - return flag_nf == flag_vf; \ - } \ - static inline bool \ - CondL_ ## cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_nf = ccr.n; \ - const bool flag_vf = ccr.v; \ - return flag_nf != flag_vf; \ - } \ - static inline bool \ - CondGU_ ## cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_cf = ccr.c; \ - const bool flag_zf = ccr.z; \ - return !(flag_cf || flag_zf); \ - } \ - static inline bool \ - CondLEU_ ## cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_cf = ccr.c; \ - const bool flag_zf = ccr.z; \ - return flag_cf || flag_zf; \ - } \ - static inline bool \ - CondCS_ ## cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_cf = ccr.c; \ - return flag_cf; \ - } \ - static inline bool \ - CondCC_ ## cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_cf = ccr.c; \ - return !flag_cf; \ - } \ - static inline bool \ - CondPOS_ ## cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_nf = ccr.n; \ - return !flag_nf; \ - } \ - static inline bool \ - CondNEG_ ## cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_nf = ccr.n; \ - return flag_nf; \ - } \ - static inline bool \ - CondVS_ ## cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_vf = ccr.v; \ - return flag_vf; \ - } \ - static inline bool \ - CondVC_ ## cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_vf = ccr.v; \ - return !flag_vf; \ - } + static inline bool CondA_##cc(const State &state) { \ + return true; \ + } \ + static inline bool CondN_##cc(const State &state) { \ + return false; \ + } \ + static inline bool CondE_##cc(const State &state) { \ + const auto ccr = state.asr.ccr.cc; \ + const bool flag_zf = ccr.z; \ + return flag_zf; \ + } \ + static inline bool CondNE_##cc(const State &state) { \ + const auto ccr = state.asr.ccr.cc; \ + const bool flag_zf = ccr.z; \ + return !flag_zf; \ + } \ + static inline bool CondG_##cc(const State &state) { \ + const auto ccr = state.asr.ccr.cc; \ + const bool flag_nf = ccr.n; \ + const bool flag_zf = ccr.z; \ + const bool flag_vf = ccr.v; \ + return (flag_nf == flag_vf) && !flag_zf; \ + } \ + static inline bool CondLE_##cc(const State &state) { \ + const auto ccr = state.asr.ccr.cc; \ + const bool flag_nf = ccr.n; \ + const bool flag_zf = ccr.z; \ + const bool flag_vf = ccr.v; \ + return (flag_nf != flag_vf) || flag_zf; \ + } \ + static inline bool CondGE_##cc(const State &state) { \ + const auto ccr = state.asr.ccr.cc; \ + const bool flag_nf = ccr.n; \ + const bool flag_vf = ccr.v; \ + return flag_nf == flag_vf; \ + } \ + static inline bool CondL_##cc(const State &state) { \ + const auto ccr = state.asr.ccr.cc; \ + const bool flag_nf = ccr.n; \ + const bool flag_vf = ccr.v; \ + return flag_nf != flag_vf; \ + } \ + static inline bool CondGU_##cc(const State &state) { \ + const auto ccr = state.asr.ccr.cc; \ + const bool flag_cf = ccr.c; \ + const bool flag_zf = ccr.z; \ + return !(flag_cf || flag_zf); \ + } \ + static inline bool CondLEU_##cc(const State &state) { \ + const auto ccr = state.asr.ccr.cc; \ + const bool flag_cf = ccr.c; \ + const bool flag_zf = ccr.z; \ + return flag_cf || flag_zf; \ + } \ + static inline bool CondCS_##cc(const State &state) { \ + const auto ccr = state.asr.ccr.cc; \ + const bool flag_cf = ccr.c; \ + return flag_cf; \ + } \ + static inline bool CondCC_##cc(const State &state) { \ + const auto ccr = state.asr.ccr.cc; \ + const bool flag_cf = ccr.c; \ + return !flag_cf; \ + } \ + static inline bool CondPOS_##cc(const State &state) { \ + const auto ccr = state.asr.ccr.cc; \ + const bool flag_nf = ccr.n; \ + return !flag_nf; \ + } \ + static inline bool CondNEG_##cc(const State &state) { \ + const auto ccr = state.asr.ccr.cc; \ + const bool flag_nf = ccr.n; \ + return flag_nf; \ + } \ + static inline bool CondVS_##cc(const State &state) { \ + const auto ccr = state.asr.ccr.cc; \ + const bool flag_vf = ccr.v; \ + return flag_vf; \ + } \ + static inline bool CondVC_##cc(const State &state) { \ + const auto ccr = state.asr.ccr.cc; \ + const bool flag_vf = ccr.v; \ + return !flag_vf; \ + } MAKE_CONDITIONS(xcc) MAKE_CONDITIONS(icc) @@ -111,206 +95,156 @@ MAKE_CONDITIONS(icc) #define MAKE_CONDITIONS(fcc) \ - static inline bool \ - CondU_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x3); \ - } \ - static inline bool \ - CondG_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x2); \ - } \ - static inline bool \ - CondUG_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x3) \ - || (state.fsr.fcc == 0x2); \ - } \ - static inline bool \ - CondL_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x1); \ - } \ - static inline bool \ - CondUL_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x3) \ - || (state.fsr.fcc == 0x1); \ - } \ - static inline bool \ - CondLG_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x2) \ - || (state.fsr.fcc == 0x1);\ - } \ - static inline bool \ - CondLGU_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x3) \ - || (state.fsr.fcc == 0x2) \ - || (state.fsr.fcc == 0x1);\ - } \ - static inline bool \ - CondNE_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x3) \ - || (state.fsr.fcc == 0x2) \ - || (state.fsr.fcc == 0x1);\ - } \ - static inline bool \ - CondE_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x0); \ - } \ - static inline bool \ - CondUE_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x3) \ - || (state.fsr.fcc == 0x0);\ - } \ - static inline bool \ - CondGE_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x2) \ - || (state.fsr.fcc == 0x0);\ - } \ - static inline bool \ - CondUGE_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x3) \ - || (state.fsr.fcc == 0x2) \ - || (state.fsr.fcc == 0x0);\ - } \ - static inline bool \ - CondLE_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x1) \ - || (state.fsr.fcc == 0x0); \ - } \ - static inline bool \ - CondULE_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x3) \ - || (state.fsr.fcc == 0x1) \ - || (state.fsr.fcc == 0x0); \ - } \ - static inline bool \ - CondGLE_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x2) \ - || (state.fsr.fcc == 0x1) \ - || (state.fsr.fcc == 0x0);\ - } \ - static inline bool \ - CondO_ ## fcc(const State &state) { \ - return (state.fsr.fcc == 0x2) \ - || (state.fsr.fcc == 0x1) \ - || (state.fsr.fcc == 0x0);\ - } + static inline bool CondU_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x3); \ + } \ + static inline bool CondG_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x2); \ + } \ + static inline bool CondUG_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x3) || (state.fsr.fcc == 0x2); \ + } \ + static inline bool CondL_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x1); \ + } \ + static inline bool CondUL_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x3) || (state.fsr.fcc == 0x1); \ + } \ + static inline bool CondLG_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x2) || (state.fsr.fcc == 0x1); \ + } \ + static inline bool CondLGU_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x3) || (state.fsr.fcc == 0x2) || \ + (state.fsr.fcc == 0x1); \ + } \ + static inline bool CondNE_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x3) || (state.fsr.fcc == 0x2) || \ + (state.fsr.fcc == 0x1); \ + } \ + static inline bool CondE_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x0); \ + } \ + static inline bool CondUE_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x3) || (state.fsr.fcc == 0x0); \ + } \ + static inline bool CondGE_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x2) || (state.fsr.fcc == 0x0); \ + } \ + static inline bool CondUGE_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x3) || (state.fsr.fcc == 0x2) || \ + (state.fsr.fcc == 0x0); \ + } \ + static inline bool CondLE_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x1) || (state.fsr.fcc == 0x0); \ + } \ + static inline bool CondULE_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x3) || (state.fsr.fcc == 0x1) || \ + (state.fsr.fcc == 0x0); \ + } \ + static inline bool CondGLE_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x2) || (state.fsr.fcc == 0x1) || \ + (state.fsr.fcc == 0x0); \ + } \ + static inline bool CondO_##fcc(const State &state) { \ + return (state.fsr.fcc == 0x2) || (state.fsr.fcc == 0x1) || \ + (state.fsr.fcc == 0x0); \ + } MAKE_CONDITIONS(fcc0) MAKE_CONDITIONS(fcc1) MAKE_CONDITIONS(fcc2) MAKE_CONDITIONS(fcc3) -template -static inline bool -CondRZ(const State &state, T cc) { +template +static inline bool CondRZ(const State &state, T cc) { return cc == 0; } -template -static inline bool -CondRLEZ(const State &state, T cc) { +template +static inline bool CondRLEZ(const State &state, T cc) { return Signed(cc) <= 0; } -template -static inline bool -CondRLZ(const State &state, T cc) { +template +static inline bool CondRLZ(const State &state, T cc) { return Signed(cc) < 0; } -template -static inline bool -CondRNZ(const State &state, T cc) { +template +static inline bool CondRNZ(const State &state, T cc) { return cc != 0; } -template -static inline bool -CondRGZ(const State &state, T cc) { +template +static inline bool CondRGZ(const State &state, T cc) { return Signed(cc) > 0; } -template -static inline bool -CondRGEZ(const State &state, T cc) { +template +static inline bool CondRGEZ(const State &state, T cc) { return Signed(cc) >= 0; } -static inline bool -CondA_ccc(const State &state) { +static inline bool CondA_ccc(const State &state) { return state.csr.ccc == 0b1000; } -static inline bool -CondN_ccc(const State &state) { +static inline bool CondN_ccc(const State &state) { return state.csr.ccc == 0b0000; } -static inline bool -Cond3_ccc(const State &state) { +static inline bool Cond3_ccc(const State &state) { return state.csr.ccc == 0b0111; } -static inline bool -Cond2_ccc(const State &state) { +static inline bool Cond2_ccc(const State &state) { return state.csr.ccc == 0b0110; } -static inline bool -Cond23_ccc(const State &state) { +static inline bool Cond23_ccc(const State &state) { return state.csr.ccc == 0b0101; } -static inline bool -Cond1_ccc(const State &state) { +static inline bool Cond1_ccc(const State &state) { return state.csr.ccc == 0b0100; } -static inline bool -Cond13_ccc(const State &state) { +static inline bool Cond13_ccc(const State &state) { return state.csr.ccc == 0b0011; } -static inline bool -Cond12_ccc(const State &state) { +static inline bool Cond12_ccc(const State &state) { return state.csr.ccc == 0b0010; } -static inline bool -Cond123_ccc(const State &state) { +static inline bool Cond123_ccc(const State &state) { return state.csr.ccc == 0b0001; } -static inline bool -Cond0_ccc(const State &state) { +static inline bool Cond0_ccc(const State &state) { return state.csr.ccc == 0b1001; } -static inline bool -Cond03_ccc(const State &state) { +static inline bool Cond03_ccc(const State &state) { return state.csr.ccc == 0b1010; } -static inline bool -Cond02_ccc(const State &state) { +static inline bool Cond02_ccc(const State &state) { return state.csr.ccc == 0b1011; } -static inline bool -Cond023_ccc(const State &state) { +static inline bool Cond023_ccc(const State &state) { return state.csr.ccc == 0b1100; } -static inline bool -Cond01_ccc(const State &state) { +static inline bool Cond01_ccc(const State &state) { return state.csr.ccc == 0b1101; } -static inline bool -Cond013_ccc(const State &state) { +static inline bool Cond013_ccc(const State &state) { return state.csr.ccc == 0b1110; } -static inline bool -Cond012_ccc(const State &state) { +static inline bool Cond012_ccc(const State &state) { return state.csr.ccc == 0b1111; } diff --git a/lib/Arch/SPARC32/Semantics/DATAXFER.cpp b/lib/Arch/SPARC32/Semantics/DATAXFER.cpp index 5a3214908..72a467aae 100644 --- a/lib/Arch/SPARC32/Semantics/DATAXFER.cpp +++ b/lib/Arch/SPARC32/Semantics/DATAXFER.cpp @@ -140,7 +140,7 @@ DEF_SEM(LDSTUB, M8W src_mem, R dst) { return memory; } -} +} // namespace DEF_ISEL(CASA) = CASA; DEF_ISEL(CASAX) = CASAX; @@ -169,7 +169,7 @@ DEF_SEM(MOVN_xcc, S src, D dst) { return memory; } -} +} // namespace DEF_ISEL(MOVA_icc) = MOVA_icc; DEF_ISEL(MOVA_xcc) = MOVA_xcc; @@ -179,22 +179,22 @@ DEF_ISEL(MOVN_xcc) = MOVN_xcc; #define MAKE_SEMANTICS(name, cond, cc) \ namespace { \ - template \ - DEF_SEM(name ## cond ## _ ## cc, S src, D dst) { \ - auto new_value = Read(src); \ - auto old_value = Read(dst); \ - auto branch_taken = Cond ## cond ## _ ## cc(state); \ - auto value = Select(branch_taken, new_value, \ - decltype(new_value)(old_value)); \ - WriteZExt(dst, value); \ - return memory; \ - } \ + template \ + DEF_SEM(name##cond##_##cc, S src, D dst) { \ + auto new_value = Read(src); \ + auto old_value = Read(dst); \ + auto branch_taken = Cond##cond##_##cc(state); \ + auto value = \ + Select(branch_taken, new_value, decltype(new_value)(old_value)); \ + WriteZExt(dst, value); \ + return memory; \ + } \ } \ - DEF_ISEL(MOV ## cond ## _ ## cc) = name ## cond ## _ ## cc; + DEF_ISEL(MOV##cond##_##cc) = name##cond##_##cc; #define MAKE_SEMANTICS_CC(name, cond) \ - MAKE_SEMANTICS(name, cond, icc) \ - MAKE_SEMANTICS(name, cond, xcc) + MAKE_SEMANTICS(name, cond, icc) \ + MAKE_SEMANTICS(name, cond, xcc) #define MAKE_SEMANTICS_FCC(name, cond) \ MAKE_SEMANTICS(name, cond, fcc0) \ @@ -235,7 +235,7 @@ MAKE_SEMANTICS_FCC(MOVF, LE) MAKE_SEMANTICS_FCC(MOVF, ULE) MAKE_SEMANTICS_FCC(MOVF, O) -} +} // namespace #undef MAKE_SEMANTICS #undef MAKE_SEMANTICS_CC @@ -244,17 +244,18 @@ MAKE_SEMANTICS_FCC(MOVF, O) #define MAKE_SEMANTICS(name, cond) \ namespace { \ template \ - DEF_SEM(name ## cond, C reg_cc, S src, D dst) { \ - auto new_value = Read(src); \ - auto old_value = Read(dst); \ - auto cc = Read(reg_cc); \ - auto cond_taken = CondR ## cond(state, cc); \ - auto value = Select(cond_taken, new_value, decltype(new_value)(old_value)); \ - WriteZExt(dst, value); \ - return memory; \ + DEF_SEM(name##cond, C reg_cc, S src, D dst) { \ + auto new_value = Read(src); \ + auto old_value = Read(dst); \ + auto cc = Read(reg_cc); \ + auto cond_taken = CondR##cond(state, cc); \ + auto value = \ + Select(cond_taken, new_value, decltype(new_value)(old_value)); \ + WriteZExt(dst, value); \ + return memory; \ } \ } \ - DEF_ISEL(MOVR ## cond) = name ## cond; + DEF_ISEL(MOVR##cond) = name##cond; MAKE_SEMANTICS(MOVR, Z) MAKE_SEMANTICS(MOVR, LEZ) @@ -303,7 +304,7 @@ DEF_SEM(FMoveNeverQuad, V64 src, V64W dst) { return memory; } -} +} // namespace DEF_ISEL(FMOVSA_icc) = FMoveAlwaysSingle; DEF_ISEL(FMOVSA_xcc) = FMoveAlwaysSingle; @@ -350,43 +351,40 @@ DEF_ISEL(FMOVQN_fcc3) = FMoveNeverQuad; #define MAKE_SEMANTICS(name, cond, cc) \ namespace { \ - DEF_SEM(FMOVS ## cond ## _ ## cc, V32 src, V32W dst) { \ + DEF_SEM(FMOVS##cond##_##cc, V32 src, V32W dst) { \ auto new_val = FExtractV32(FReadV32(src), 0); \ auto old_val = FExtractV32(FReadV32(dst), 0); \ - auto branch_taken = Cond ## cond ## _ ## cc(state); \ - auto value = Select(branch_taken, new_val, \ - decltype(new_val)(old_val)); \ + auto branch_taken = Cond##cond##_##cc(state); \ + auto value = Select(branch_taken, new_val, decltype(new_val)(old_val)); \ FWriteV32(dst, value); \ WriteTrunc(FSR_CEXC, 0); \ WriteTrunc(FSR_FTT, 0); \ return memory; \ } \ - DEF_SEM(FMOVD ## cond ## _ ## cc, V64 src, V64W dst) { \ + DEF_SEM(FMOVD##cond##_##cc, V64 src, V64W dst) { \ auto new_val = FExtractV64(FReadV64(src), 0); \ auto old_val = FExtractV64(FReadV64(dst), 0); \ - auto branch_taken = Cond ## cond ## _ ## cc(state); \ - auto value = Select(branch_taken, new_val, \ - decltype(new_val)(old_val)); \ + auto branch_taken = Cond##cond##_##cc(state); \ + auto value = Select(branch_taken, new_val, decltype(new_val)(old_val)); \ FWriteV64(dst, value); \ WriteTrunc(FSR_CEXC, 0); \ WriteTrunc(FSR_FTT, 0); \ return memory; \ } \ - DEF_SEM(FMOVQ ## cond ## _ ## cc, V64 src, V64W dst) { \ + DEF_SEM(FMOVQ##cond##_##cc, V64 src, V64W dst) { \ auto new_val = FExtractV64(FReadV64(src), 0); \ auto old_val = FExtractV64(FReadV64(dst), 0); \ - auto branch_taken = Cond ## cond ## _ ## cc(state); \ - auto value = Select(branch_taken, new_val, \ - decltype(new_val)(old_val)); \ + auto branch_taken = Cond##cond##_##cc(state); \ + auto value = Select(branch_taken, new_val, decltype(new_val)(old_val)); \ FWriteV64(dst, value); \ WriteTrunc(FSR_CEXC, 0); \ WriteTrunc(FSR_FTT, 0); \ return memory; \ } \ } \ - DEF_ISEL(FMOVS ## cond ## _ ## cc) = FMOVS ## cond ## _ ## cc; \ - DEF_ISEL(FMOVD ## cond ## _ ## cc) = FMOVD ## cond ## _ ## cc; \ - DEF_ISEL(FMOVQ ## cond ## _ ## cc) = FMOVQ ## cond ## _ ## cc; + DEF_ISEL(FMOVS##cond##_##cc) = FMOVS##cond##_##cc; \ + DEF_ISEL(FMOVD##cond##_##cc) = FMOVD##cond##_##cc; \ + DEF_ISEL(FMOVQ##cond##_##cc) = FMOVQ##cond##_##cc; #define MAKE_SEMANTICS_CC(name, cond) \ MAKE_SEMANTICS(name, cond, icc) \ @@ -434,49 +432,43 @@ MAKE_SEMANTICS_FCC(FMOV, O) #define MAKE_SEMANTICS(name, cond) \ namespace { \ - DEF_SEM(name ## S ## cond, R32 reg_cc, V32 src, V32W dst) { \ + DEF_SEM(name##S##cond, R32 reg_cc, V32 src, V32W dst) { \ auto new_val = FExtractV32(FReadV32(src), 0); \ auto old_val = FExtractV32(FReadV32(dst), 0); \ auto cc = Read(reg_cc); \ - auto cond_taken = CondR ## cond(state, cc); \ - auto value = Select(cond_taken, \ - new_val, \ - decltype(new_val)(old_val)); \ + auto cond_taken = CondR##cond(state, cc); \ + auto value = Select(cond_taken, new_val, decltype(new_val)(old_val)); \ FWriteV32(dst, value); \ WriteTrunc(FSR_CEXC, 0); \ WriteTrunc(FSR_FTT, 0); \ return memory; \ } \ - DEF_SEM(name ## D ## cond, R32 reg_cc, V64 src, V64W dst) { \ + DEF_SEM(name##D##cond, R32 reg_cc, V64 src, V64W dst) { \ auto new_val = FExtractV64(FReadV64(src), 0); \ auto old_val = FExtractV64(FReadV64(dst), 0); \ auto cc = Read(reg_cc); \ - auto cond_taken = CondR ## cond(state, cc); \ - auto value = Select(cond_taken, \ - new_val, \ - decltype(new_val)(old_val)); \ + auto cond_taken = CondR##cond(state, cc); \ + auto value = Select(cond_taken, new_val, decltype(new_val)(old_val)); \ FWriteV64(dst, value); \ WriteTrunc(FSR_CEXC, 0); \ WriteTrunc(FSR_FTT, 0); \ return memory; \ } \ - DEF_SEM(name ## Q ## cond, R32 reg_cc, V64 src, V64W dst) { \ + DEF_SEM(name##Q##cond, R32 reg_cc, V64 src, V64W dst) { \ auto new_val = FExtractV64(FReadV64(src), 0); \ auto old_val = FExtractV64(FReadV64(dst), 0); \ auto cc = Read(reg_cc); \ - auto cond_taken = CondR ## cond(state, cc); \ - auto value = Select(cond_taken, \ - new_val, \ - decltype(new_val)(old_val)); \ + auto cond_taken = CondR##cond(state, cc); \ + auto value = Select(cond_taken, new_val, decltype(new_val)(old_val)); \ FWriteV64(dst, value); \ WriteTrunc(FSR_CEXC, 0); \ WriteTrunc(FSR_FTT, 0); \ return memory; \ } \ } \ - DEF_ISEL(name ## S ## cond) = name ## S ## cond; \ - DEF_ISEL(name ## D ## cond) = name ## D ## cond; \ - DEF_ISEL(name ## Q ## cond) = name ## Q ## cond; + DEF_ISEL(name##S##cond) = name##S##cond; \ + DEF_ISEL(name##D##cond) = name##D##cond; \ + DEF_ISEL(name##Q##cond) = name##Q##cond; MAKE_SEMANTICS(FMOVR, Z) MAKE_SEMANTICS(FMOVR, LEZ) diff --git a/lib/Arch/SPARC32/Semantics/FLAGS.cpp b/lib/Arch/SPARC32/Semantics/FLAGS.cpp index 0be1358f3..bdf8aaac7 100644 --- a/lib/Arch/SPARC32/Semantics/FLAGS.cpp +++ b/lib/Arch/SPARC32/Semantics/FLAGS.cpp @@ -20,38 +20,35 @@ namespace { // Zero flags, tells us whether or not a value is zero. template -[[gnu::const]] -ALWAYS_INLINE static bool ZeroFlag(T res) { +[[gnu::const]] ALWAYS_INLINE static bool ZeroFlag(T res) { return T(0) == res; } // Zero flags, tells us whether or not a value is zero. template -[[gnu::const]] -ALWAYS_INLINE static bool NotZeroFlag(T res) { +[[gnu::const]] ALWAYS_INLINE static bool NotZeroFlag(T res) { return T(0) != res; } // Sign flag, tells us if a result is signed or unsigned. template -[[gnu::const]] -ALWAYS_INLINE static bool SignFlag(T res) { +[[gnu::const]] ALWAYS_INLINE static bool SignFlag(T res) { return 0 > Signed(res); } // Tests whether there is an even number of bits in the low order byte. -[[gnu::const]] -ALWAYS_INLINE static bool ParityFlag(uint8_t r0) { +[[gnu::const]] ALWAYS_INLINE static bool ParityFlag(uint8_t r0) { return !__builtin_parity(static_cast(r0)); -// auto r1 = r0 >> 1_u8; -// auto r2 = r1 >> 1_u8; -// auto r3 = r2 >> 1_u8; -// auto r4 = r3 >> 1_u8; -// auto r5 = r4 >> 1_u8; -// auto r6 = r5 >> 1_u8; -// auto r7 = r6 >> 1_u8; -// -// return !(1 & (r0 ^ r1 ^ r2 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7)); + + // auto r1 = r0 >> 1_u8; + // auto r2 = r1 >> 1_u8; + // auto r3 = r2 >> 1_u8; + // auto r4 = r3 >> 1_u8; + // auto r5 = r4 >> 1_u8; + // auto r6 = r5 >> 1_u8; + // auto r7 = r6 >> 1_u8; + // + // return !(1 & (r0 ^ r1 ^ r2 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7)); } struct tag_add {}; @@ -68,13 +65,10 @@ struct Overflow; template <> struct Overflow { template - [[gnu::const]] - ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { static_assert(std::is_unsigned::value, "Invalid specialization of `Overflow::Flag` for addition."); - enum { - kSignShift = sizeof(T) * 8 - 1 - }; + enum { kSignShift = sizeof(T) * 8 - 1 }; // Overflow occurs on addition if both operands have the same sign and // the sign of the sum is different. @@ -90,14 +84,11 @@ struct Overflow { template <> struct Overflow { template - [[gnu::const]] - ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { - static_assert(std::is_unsigned::value, + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { + static_assert(std::is_unsigned::value, "Invalid specialization of `Overflow::Flag` for " "subtraction."); - enum { - kSignShift = sizeof(T) * 8 - 1 - }; + enum { kSignShift = sizeof(T) * 8 - 1 }; // Overflow occurs on subtraction if the operands have different signs and // the sign of the difference differs from the sign of r[rs1]. @@ -116,10 +107,9 @@ struct Overflow { // Integer multiplication overflow check, where result is twice the width of // the operands. template - [[gnu::const]] - ALWAYS_INLINE static bool Flag( - T, T, R res, - typename std::enable_if::type=0) { + [[gnu::const]] ALWAYS_INLINE static bool + Flag(T, T, R res, + typename std::enable_if::type = 0) { return static_cast(static_cast(res)) != res; } @@ -127,10 +117,9 @@ struct Overflow { // Signed integer multiplication overflow check, where the result is // truncated to the size of the operands. template - [[gnu::const]] - ALWAYS_INLINE static bool Flag( - T lhs, T rhs, T, - typename std::enable_if::value,int>::type=0) { + [[gnu::const]] ALWAYS_INLINE static bool + Flag(T lhs, T rhs, T, + typename std::enable_if::value, int>::type = 0) { auto lhs_wide = SExt(lhs); auto rhs_wide = SExt(rhs); return Flag(lhs, rhs, lhs_wide * rhs_wide); @@ -141,31 +130,23 @@ struct Overflow { template <> struct Overflow { template - [[gnu::const]] - ALWAYS_INLINE static bool Flag( - T, T, R res, - typename std::enable_if::type=0) { + [[gnu::const]] ALWAYS_INLINE static bool + Flag(T, T, R res, + typename std::enable_if::type = 0) { - enum { - kSignShift = sizeof(T) * 8 - 1 - }; + enum { kSignShift = sizeof(T) * 8 - 1 }; return (SExt(res << kSignShift) > 0) || (SExt(res << kSignShift) < -1); } template - [[gnu::const]] - ALWAYS_INLINE static R Value( - T lhs, T rhs, R res, - typename std::enable_if::type=0) { + [[gnu::const]] ALWAYS_INLINE static R + Value(T lhs, T rhs, R res, + typename std::enable_if::type = 0) { - enum { - kSignShift = sizeof(T) * 8 - 1 - }; + enum { kSignShift = sizeof(T) * 8 - 1 }; - enum:R { - kValueMax = static_cast(1) << sizeof(T) * 8 - }; + enum : R { kValueMax = static_cast(1) << sizeof(T) * 8 }; if (SExt(res << kSignShift) > 0) { return kValueMax - 1; @@ -175,37 +156,28 @@ struct Overflow { return res; } } - }; template <> struct Overflow { template - [[gnu::const]] - ALWAYS_INLINE static bool Flag( - T, T, R res, - typename std::enable_if::type=0) { + [[gnu::const]] ALWAYS_INLINE static bool + Flag(T, T, R res, + typename std::enable_if::type = 0) { - enum { - kShift = sizeof(T) * 8 - }; + enum { kShift = sizeof(T) * 8 }; return (SExt(res << kShift) > 0); } template - [[gnu::const]] - ALWAYS_INLINE static R Value( - T lhs, T rhs, R res, - typename std::enable_if::type=0) { - - enum { - kShift = sizeof(T) * 8 - }; - - enum:R { - kValueMax = static_cast(1) << sizeof(T) * 8 - }; + [[gnu::const]] ALWAYS_INLINE static R + Value(T lhs, T rhs, R res, + typename std::enable_if::type = 0) { + + enum { kShift = sizeof(T) * 8 }; + + enum : R { kValueMax = static_cast(1) << sizeof(T) * 8 }; if (SExt(res << kShift) > 0) { return kValueMax - 1; @@ -223,8 +195,7 @@ struct Carry; template <> struct Carry { template - [[gnu::const]] - ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { static_assert(std::is_unsigned::value, "Invalid specialization of `Carry::Flag` for addition."); return res < lhs || res < rhs; @@ -235,8 +206,7 @@ struct Carry { template <> struct Carry { template - [[gnu::const]] - ALWAYS_INLINE static bool Flag(T lhs, T rhs, T) { + [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T) { static_assert(std::is_unsigned::value, "Invalid specialization of `Carry::Flag` for addition."); return lhs < rhs; @@ -248,6 +218,4 @@ ALWAYS_INLINE void SetFPSRStatusFlags(State &state, int mask) { state.fsr.cexc = static_cast(mask & FE_ALL_EXCEPT); } -} // namespace - - +} // namespace diff --git a/lib/Arch/SPARC32/Semantics/FOP.cpp b/lib/Arch/SPARC32/Semantics/FOP.cpp index 815264fcf..83b2d2535 100644 --- a/lib/Arch/SPARC32/Semantics/FOP.cpp +++ b/lib/Arch/SPARC32/Semantics/FOP.cpp @@ -8,15 +8,15 @@ namespace { DEF_SEM(FADDS, RF32 src1, RF32 src2, RF32W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the Floating point exception and prevent // recording of the instructions - auto old_except = - __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto sum = FAdd(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, sum); return memory; @@ -25,15 +25,15 @@ DEF_SEM(FADDS, RF32 src1, RF32 src2, RF32W dst) { DEF_SEM(FADDD, RF64 src1, RF64 src2, RF64W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the Floating point exception and prevent // recording of the instructions - auto old_except = - __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto sum = FAdd64(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, sum); return memory; @@ -42,14 +42,15 @@ DEF_SEM(FADDD, RF64 src1, RF64 src2, RF64W dst) { DEF_SEM(FSUBS, RF32 src1, RF32 src2, RF32W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the Floating point exception and prevent // recording of the instructions auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto sub = FSub32(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, sub); return memory; @@ -58,14 +59,15 @@ DEF_SEM(FSUBS, RF32 src1, RF32 src2, RF32W dst) { DEF_SEM(FSUBD, RF64 src1, RF64 src2, RF64W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the Floating point exception and prevent // recording of the instructions auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto sub = FSub64(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, sub); return memory; @@ -74,15 +76,15 @@ DEF_SEM(FSUBD, RF64 src1, RF64 src2, RF64W dst) { DEF_SEM(FMULS, RF32 src1, RF32 src2, RF32W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the Floating point exception and prevent // recording of the instructions - auto old_except = - __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto mul = FMul32(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, mul); return memory; @@ -91,15 +93,15 @@ DEF_SEM(FMULS, RF32 src1, RF32 src2, RF32W dst) { DEF_SEM(FMULD, RF64 src1, RF64 src2, RF64W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the Floating point exception and prevent // recording of the instructions - auto old_except = - __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto mul = FMul64(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, mul); return memory; @@ -108,14 +110,14 @@ DEF_SEM(FMULD, RF64 src1, RF64 src2, RF64W dst) { DEF_SEM(FDIVS, RF32 src1, RF32 src2, RF32W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the fp exception and prevent recording - auto old_except = - __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto div = FDiv32(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, div); return memory; @@ -124,52 +126,52 @@ DEF_SEM(FDIVS, RF32 src1, RF32 src2, RF32W dst) { DEF_SEM(FDIVD, RF64 src1, RF64 src2, RF64W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the fp exception and prevent recording - auto old_except = - __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto div = FDiv64(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, div); return memory; } -DEF_SEM(FsMULD, RF32 src1, RF32 src2, RF64W dst) { +DEF_SEM(FsMULD, RF32 src1, RF32 src2, RF64W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the fp exception and prevent recording - auto old_except = - __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto mul = FMul64(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, mul); return memory; } -DEF_SEM(FdMULQ, RF64 src1, RF64 src2, RF64W dst) { +DEF_SEM(FdMULQ, RF64 src1, RF64 src2, RF64W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the fp exception and prevent recording - auto old_except = - __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto mul = FMul64(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, mul); return memory; } -} +} // namespace DEF_ISEL(FADDS) = FADDS; DEF_ISEL(FADDD) = FADDD; @@ -333,7 +335,7 @@ DEF_SEM(FSTOX, RF32 src, R64W dst) { return memory; } -} +} // namespace DEF_ISEL(FMOVS) = FMOVS; DEF_ISEL(FMOVD) = FMOVD; @@ -374,24 +376,24 @@ DEF_ISEL(FXTOQ) = FXTOQ; #define MAKE_COMPARE(fcc) \ - template \ - void FCompare_ ## fcc(State &state, Memory *memory, \ - S val1, S val2, bool signal) { \ - if (std::isnan(val1) || std::isnan(val2)) { \ - Write(state.fsr.fcc, Literal(3)); \ - } else { \ - if (FCmpEq(val1, val2)) { \ - /* result = '00'; */ \ - Write(state.fsr.fcc, Literal(0)); \ - } else if (FCmpLt(val1, val2)) { \ - /* result = '01'; */ \ - Write(state.fsr.fcc, Literal(1)); \ - } else { /* FCmpGt(val1, val2) */ \ - /* result = '10'; */ \ - Write(state.fsr.fcc, Literal(2)); \ - } \ - } \ - } + template \ + void FCompare_##fcc(State &state, Memory *memory, S val1, S val2, \ + bool signal) { \ + if (std::isnan(val1) || std::isnan(val2)) { \ + Write(state.fsr.fcc, Literal(3)); \ + } else { \ + if (FCmpEq(val1, val2)) { \ + /* result = '00'; */ \ + Write(state.fsr.fcc, Literal(0)); \ + } else if (FCmpLt(val1, val2)) { \ + /* result = '01'; */ \ + Write(state.fsr.fcc, Literal(1)); \ + } else { /* FCmpGt(val1, val2) */ \ + /* result = '10'; */ \ + Write(state.fsr.fcc, Literal(2)); \ + } \ + } \ + } namespace { @@ -401,53 +403,53 @@ MAKE_COMPARE(fcc1) MAKE_COMPARE(fcc2) MAKE_COMPARE(fcc3) -} +} // namespace #undef MAKE_COMPARE #define MAKE_SEMANTICS_FCMP(fcc) \ - DEF_SEM(FCMPS_ ## fcc, RF32 src1, RF32 src2) { \ - auto val1 = Read(src1); \ - auto val2 = Read(src2); \ - FCompare_ ## fcc(state, memory, val1, val2, false); \ - return memory; \ - } \ - \ - DEF_SEM(FCMPD_ ## fcc, RF64 src1, RF64 src2) { \ + DEF_SEM(FCMPS_##fcc, RF32 src1, RF32 src2) { \ auto val1 = Read(src1); \ auto val2 = Read(src2); \ - FCompare_ ## fcc(state, memory, val1, val2, false); \ - return memory; \ - } \ - \ - DEF_SEM(FCMPQ_ ## fcc, RF64 src1, RF64 src2) { \ + FCompare_##fcc(state, memory, val1, val2, false); \ + return memory; \ + } \ +\ + DEF_SEM(FCMPD_##fcc, RF64 src1, RF64 src2) { \ auto val1 = Read(src1); \ auto val2 = Read(src2); \ - FCompare_ ## fcc(state, memory, val1, val2, false); \ - return memory; \ - } + FCompare_##fcc(state, memory, val1, val2, false); \ + return memory; \ + } \ +\ + DEF_SEM(FCMPQ_##fcc, RF64 src1, RF64 src2) { \ + auto val1 = Read(src1); \ + auto val2 = Read(src2); \ + FCompare_##fcc(state, memory, val1, val2, false); \ + return memory; \ + } #define MAKE_SEMANTICS_FCMPE(fcc) \ - DEF_SEM(FCMPES_ ## fcc, RF32 src1, RF32 src2) { \ + DEF_SEM(FCMPES_##fcc, RF32 src1, RF32 src2) { \ auto val1 = Read(src1); \ auto val2 = Read(src2); \ - FCompare_ ## fcc(state, memory, val1, val2, false); \ - return memory; \ - } \ - \ - DEF_SEM(FCMPED_ ## fcc, RF64 src1, RF64 src2) { \ + FCompare_##fcc(state, memory, val1, val2, false); \ + return memory; \ + } \ +\ + DEF_SEM(FCMPED_##fcc, RF64 src1, RF64 src2) { \ auto val1 = Read(src1); \ auto val2 = Read(src2); \ - FCompare_ ## fcc(state, memory, val1, val2, false); \ - return memory; \ - } \ - \ - DEF_SEM(FCMPEQ_ ## fcc, RF64 src1, RF64 src2) { \ + FCompare_##fcc(state, memory, val1, val2, false); \ + return memory; \ + } \ +\ + DEF_SEM(FCMPEQ_##fcc, RF64 src1, RF64 src2) { \ auto val1 = Read(src1); \ auto val2 = Read(src2); \ - FCompare_ ## fcc(state, memory, val1, val2, false); \ - return memory; \ - } + FCompare_##fcc(state, memory, val1, val2, false); \ + return memory; \ + } namespace { @@ -461,7 +463,7 @@ MAKE_SEMANTICS_FCMPE(fcc1) MAKE_SEMANTICS_FCMPE(fcc2) MAKE_SEMANTICS_FCMPE(fcc3) -} +} // namespace #undef MAKE_SEMANTICS_FCMP #undef MAKE_SEMANTICS_FCMPE diff --git a/lib/Arch/SPARC32/Semantics/MISC.cpp b/lib/Arch/SPARC32/Semantics/MISC.cpp index 42b90e9be..f9b836fe9 100644 --- a/lib/Arch/SPARC32/Semantics/MISC.cpp +++ b/lib/Arch/SPARC32/Semantics/MISC.cpp @@ -14,15 +14,15 @@ DEF_ISEL(NOP) = NOP; #define MAKE_SEMANTICS_WR(op) \ namespace { \ - DEF_SEM(WR ## op, R32 src1, I32 src2) { \ - auto lhs = Read(src1); \ - auto rhs = Read(src2); \ - auto res = UXor(lhs, rhs); \ - WriteZExt(ASR_ ## op, res); \ - return memory; \ - } \ + DEF_SEM(WR##op, R32 src1, I32 src2) { \ + auto lhs = Read(src1); \ + auto rhs = Read(src2); \ + auto res = UXor(lhs, rhs); \ + WriteZExt(ASR_##op, res); \ + return memory; \ } \ - DEF_ISEL(WR ## op) = WR ## op; + } \ + DEF_ISEL(WR##op) = WR##op; MAKE_SEMANTICS_WR(Y) MAKE_SEMANTICS_WR(PAUSE) @@ -34,13 +34,13 @@ MAKE_SEMANTICS_WR(ASI) #define MAKE_SEMANTICS_RD(op) \ namespace { \ - DEF_SEM(RD ## op, R32W dst) { \ - auto asr = Read(ASR_ ## op); \ - Write(dst, asr); \ - return memory; \ - } \ + DEF_SEM(RD##op, R32W dst) { \ + auto asr = Read(ASR_##op); \ + Write(dst, asr); \ + return memory; \ + } \ } \ - DEF_ISEL(RD ## op) = RD ## op; + DEF_ISEL(RD##op) = RD##op; MAKE_SEMANTICS_RD(Y) MAKE_SEMANTICS_RD(ASI) @@ -52,16 +52,19 @@ namespace { DEF_SEM(IMPDEP1, I32 opf) { HYPER_CALL_VECTOR = Literal(Read(opf)); return __remill_sync_hyper_call( - state, memory, SyncHyperCall::IF_32BIT_ELSE(kSPARC32EmulateInstruction, kSPARC64EmulateInstruction)); + state, memory, + SyncHyperCall::IF_32BIT_ELSE(kSPARC32EmulateInstruction, + kSPARC64EmulateInstruction)); } DEF_SEM(IMPDEP2, I32 opf) { HYPER_CALL_VECTOR = Literal(Read(opf)); return __remill_sync_hyper_call( - state, memory, SyncHyperCall::IF_32BIT_ELSE(kSPARC32EmulateInstruction, kSPARC64EmulateInstruction)); + state, memory, + SyncHyperCall::IF_32BIT_ELSE(kSPARC32EmulateInstruction, + kSPARC64EmulateInstruction)); } -} +} // namespace DEF_ISEL(IMPDEP1) = IMPDEP1; DEF_ISEL(IMPDEP2) = IMPDEP2; - diff --git a/lib/Arch/SPARC32/Semantics/TRAP.cpp b/lib/Arch/SPARC32/Semantics/TRAP.cpp index 248bfebf0..e9475a285 100644 --- a/lib/Arch/SPARC32/Semantics/TRAP.cpp +++ b/lib/Arch/SPARC32/Semantics/TRAP.cpp @@ -8,47 +8,52 @@ // is placed inside of a delay slot. #define MAKE_TRAP(cond, cc) \ namespace { \ - DEF_SEM(T ## cond, R8W branch_taken, PC new_pc, PC new_npc, \ - I32 vec_a, I32 vec_b, R32W pc_dst, R32W npc_dst) { \ - Write(branch_taken, Cond ## cond ## _ ## cc(state)); \ - HYPER_CALL = AsyncHyperCall::kSPARCTrapCond ## cond; \ + DEF_SEM(T##cond, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, \ + I32 vec_b, R32W pc_dst, R32W npc_dst) { \ + Write(branch_taken, Cond##cond##_##cc(state)); \ + HYPER_CALL = AsyncHyperCall::kSPARCTrapCond##cond; \ HYPER_CALL_VECTOR = UAnd(UAdd(Read(vec_a), Read(vec_b)), 0x7fu); \ return memory; \ } \ - DEF_SEM(T ## cond ## _sync, R8W branch_taken, PC new_pc, PC new_npc, \ - I32 vec_a, I32 vec_b, R32W pc_dst, R32W npc_dst) { \ - Write(branch_taken, Cond ## cond ## _ ## cc(state)); \ - HYPER_CALL = AsyncHyperCall::kSPARCTrapCond ## cond; \ + DEF_SEM(T##cond##_sync, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, \ + I32 vec_b, R32W pc_dst, R32W npc_dst) { \ + Write(branch_taken, Cond##cond##_##cc(state)); \ + HYPER_CALL = AsyncHyperCall::kSPARCTrapCond##cond; \ HYPER_CALL_VECTOR = UAnd(UAdd(Read(vec_a), Read(vec_b)), 0x7fu); \ - return __remill_sync_hyper_call( \ - state, memory, SyncHyperCall::kSPARCTrapCond ## cond); \ + return __remill_sync_hyper_call(state, memory, \ + SyncHyperCall::kSPARCTrapCond##cond); \ } \ } \ - DEF_ISEL(T ## cond) = T ## cond; \ - DEF_ISEL(T ## cond ## _sync) = T ## cond ## _sync + DEF_ISEL(T##cond) = T##cond; \ + DEF_ISEL(T##cond##_sync) = T##cond##_sync namespace { -DEF_SEM(TA, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, R32W pc_dst, R32W npc_dst) { +DEF_SEM(TA, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, + R32W pc_dst, R32W npc_dst) { HYPER_CALL = AsyncHyperCall::kSPARCTrapCondA; HYPER_CALL_VECTOR = UAnd(UAdd(Read(vec_a), Read(vec_b)), 0x7fu); Write(branch_taken, true); return memory; } -DEF_SEM(TA_sync, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, R32W pc_dst, R32W npc_dst) { +DEF_SEM(TA_sync, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, + R32W pc_dst, R32W npc_dst) { HYPER_CALL = AsyncHyperCall::kSPARCTrapCondA; HYPER_CALL_VECTOR = UAnd(UAdd(Read(vec_a), Read(vec_b)), 0x7fu); - return __remill_sync_hyper_call(state, memory, SyncHyperCall::kSPARCTrapCondA); + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCTrapCondA); } -DEF_SEM(TN, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, R32W pc_dst, R32W npc_dst) { +DEF_SEM(TN, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, + R32W pc_dst, R32W npc_dst) { Write(pc_dst, Read(new_pc)); Write(npc_dst, Read(new_npc)); return memory; } -DEF_SEM(TN_sync, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, R64W pc_dst, R64W npc_dst) { +DEF_SEM(TN_sync, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, + R64W pc_dst, R64W npc_dst) { return memory; } @@ -79,6 +84,7 @@ MAKE_TRAP(VS, icc); namespace { DEF_SEM(UNIMP_SYNC, I32 struct_size) { + // TODO(pag): See if callees inspect the struct size when this is after the // delay slot of a CALL. See "Programming Note" in v8 manual, B.31, // p137. @@ -88,6 +94,7 @@ DEF_SEM(UNIMP_SYNC, I32 struct_size) { } DEF_SEM(UNIMP_ASYNC, I32 struct_size) { + // TODO(pag): See if callees inspect the struct size when this is after the // delay slot of a CALL. See "Programming Note" in v8 manual, B.31, // p137. diff --git a/lib/Arch/SPARC32/Semantics/WINDOW.cpp b/lib/Arch/SPARC32/Semantics/WINDOW.cpp index f9baebb0d..977231bf8 100644 --- a/lib/Arch/SPARC32/Semantics/WINDOW.cpp +++ b/lib/Arch/SPARC32/Semantics/WINDOW.cpp @@ -5,7 +5,8 @@ namespace { template -DEF_SEM(SAVE, S1 src1, S2 src2, D dst, RegisterWindow *window, RegisterWindow *&prev_window) { +DEF_SEM(SAVE, S1 src1, S2 src2, D dst, RegisterWindow *window, + RegisterWindow *&prev_window) { addr_t sp_base = Read(src1); addr_t sp_offset = Read(src2); addr_t new_sp = UAdd(sp_base, sp_offset); diff --git a/lib/Arch/SPARC64/Arch.cpp b/lib/Arch/SPARC64/Arch.cpp index 91c1b7729..0919da751 100644 --- a/lib/Arch/SPARC64/Arch.cpp +++ b/lib/Arch/SPARC64/Arch.cpp @@ -14,21 +14,22 @@ * limitations under the License. */ +#include "remill/Arch/Arch.h" + #include -#include "remill/Arch/Arch.h" +#include "Decode.h" #include "remill/Arch/Instruction.h" #include "remill/Arch/Name.h" #include "remill/BC/ABI.h" #include "remill/BC/Util.h" #include "remill/OS/OS.h" -#include "Decode.h" - // clang-format off #define ADDRESS_SIZE_BITS 64 #define INCLUDED_FROM_REMILL #include "remill/Arch/SPARC64/Runtime/State.h" + // clang-format on namespace remill { @@ -73,9 +74,8 @@ class SPARC64Arch final : public Arch { llvm::DataLayout DataLayout(void) const final; // Decode an instruction. - bool DecodeInstruction( - uint64_t address, std::string_view instr_bytes, - Instruction &inst) const final; + bool DecodeInstruction(uint64_t address, std::string_view instr_bytes, + Instruction &inst) const final; // Returns `true` if memory access are little endian byte ordered. bool MemoryAccessIsLittleEndian(void) const final { @@ -160,7 +160,8 @@ void SPARC64Arch::PopulateBasicBlockFunction(llvm::Module *module, REG(o7, gpr.o7.qword, u64); ir.CreateStore(zero_u64, ir.CreateAlloca(u64, nullptr, "g0"), false); - ir.CreateStore(zero_u64, ir.CreateAlloca(u64, nullptr, "ignore_write_to_g0"), false); + ir.CreateStore(zero_u64, ir.CreateAlloca(u64, nullptr, "ignore_write_to_g0"), + false); REG(g1, gpr.g1.qword, u64); REG(g2, gpr.g2.qword, u64); @@ -352,23 +353,27 @@ void SPARC64Arch::PopulateBasicBlockFunction(llvm::Module *module, // `WINDOW_LINK = &(WINDOW->prev_window);` llvm::Value *gep_indexes[2] = {zero_u32, llvm::ConstantInt::get(u32, 33)}; - auto window_link = ir.CreateInBoundsGEP(window_type, window, gep_indexes, "WINDOW_LINK"); + auto window_link = + ir.CreateInBoundsGEP(window_type, window, gep_indexes, "WINDOW_LINK"); auto nullptr_window = llvm::Constant::getNullValue(prev_window_link->type); ir.CreateStore(nullptr_window, window_link, false); - ir.CreateStore(zero_u8, ir.CreateAlloca(u8, nullptr, "IGNORE_BRANCH_TAKEN"), false); + ir.CreateStore(zero_u8, ir.CreateAlloca(u8, nullptr, "IGNORE_BRANCH_TAKEN"), + false); ir.CreateStore(zero_u64, ir.CreateAlloca(u64, nullptr, "IGNORE_PC"), false); - ir.CreateStore(zero_u64, ir.CreateAlloca(u64, nullptr, "IGNORE_NEXT_PC"), false); - ir.CreateStore(zero_u64, ir.CreateAlloca(u64, nullptr, "IGNORE_RETURN_PC"), false); + ir.CreateStore(zero_u64, ir.CreateAlloca(u64, nullptr, "IGNORE_NEXT_PC"), + false); + ir.CreateStore(zero_u64, ir.CreateAlloca(u64, nullptr, "IGNORE_RETURN_PC"), + false); const auto pc_arg = NthArgument(bb_func, kPCArgNum); const auto state_ptr_arg = NthArgument(bb_func, kStatePointerArgNum); (void) RegisterByName(kNextPCVariableName)->AddressOf(state_ptr_arg, ir); - ir.CreateStore( - pc_arg, RegisterByName(kPCVariableName)->AddressOf(state_ptr_arg, ir), - false); + ir.CreateStore(pc_arg, + RegisterByName(kPCVariableName)->AddressOf(state_ptr_arg, ir), + false); } llvm::Triple SPARC64Arch::Triple(void) const { @@ -405,8 +410,9 @@ bool SPARC64Arch::NextInstructionIsDelayed(const Instruction &inst, } // Decode an instruction. -bool SPARC64Arch::DecodeInstruction( - uint64_t address, std::string_view inst_bytes, Instruction &inst) const { +bool SPARC64Arch::DecodeInstruction(uint64_t address, + std::string_view inst_bytes, + Instruction &inst) const { inst.pc = address; inst.arch_name = arch_name; @@ -436,27 +442,25 @@ bool SPARC64Arch::DecodeInstruction( if (!sparc64::TryDecode(inst)) { inst.category = Instruction::kCategoryInvalid; inst.operands.clear(); - LOG(ERROR) - << "Unable to decode: " << inst.Serialize(); + LOG(ERROR) << "Unable to decode: " << inst.Serialize(); return false; } return inst.IsValid(); } -} // namespace sparc +} // namespace sparc -Arch::ArchPtr Arch::GetSPARC64( - llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_) { +Arch::ArchPtr Arch::GetSPARC64(llvm::LLVMContext *context_, OSName os_name_, + ArchName arch_name_) { if (arch_name_ == kArchSparc64) { return std::make_unique(context_, os_name_, arch_name_); } else { - LOG(FATAL) - << "Invalid arch name passed to Arch::GetSPARC::" - << GetArchName(arch_name_); + LOG(FATAL) << "Invalid arch name passed to Arch::GetSPARC::" + << GetArchName(arch_name_); return {}; } } -} // namespace remill +} // namespace remill diff --git a/lib/Arch/SPARC64/Decode.h b/lib/Arch/SPARC64/Decode.h index 640a02fe3..1f9af5672 100644 --- a/lib/Arch/SPARC64/Decode.h +++ b/lib/Arch/SPARC64/Decode.h @@ -16,16 +16,17 @@ #pragma once -#include #include +#include + #include "remill/Arch/Arch.h" #include "remill/Arch/Instruction.h" namespace remill { namespace sparc64 { -bool TryDecode(Instruction &inst) ; +bool TryDecode(Instruction &inst); } // namespace sparc64 } // namespace remill diff --git a/lib/Arch/SPARC64/Extract.cpp b/lib/Arch/SPARC64/Extract.cpp index f540506f4..e56e9770b 100644 --- a/lib/Arch/SPARC64/Extract.cpp +++ b/lib/Arch/SPARC64/Extract.cpp @@ -15,11 +15,11 @@ */ #include -#include -#include "Decode.h" +#include #include "../SPARC32/Decode.h" +#include "Decode.h" namespace remill { using namespace remill::sparc; @@ -28,15 +28,12 @@ namespace sparc64 { namespace { static const std::string_view kFpuRegName_fN[] = { - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", - "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39", - "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", - "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55", - "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63" -}; + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", + "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", + "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "f32", + "f33", "f34", "f35", "f36", "f37", "f38", "f39", "f40", "f41", "f42", "f43", + "f44", "f45", "f46", "f47", "f48", "f49", "f50", "f51", "f52", "f53", "f54", + "f55", "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63"}; static constexpr unsigned kAddressSize32 = 32; static constexpr unsigned kAddressSize = 64; @@ -80,7 +77,7 @@ static void AddIntRegop(Instruction &inst, unsigned index, unsigned size, auto &op = inst.operands.back(); op.type = Operand::kTypeRegister; op.size = size; - op.action = action; + op.action = action; op.reg.size = size; if (Operand::kActionRead == action) { if (!index) { @@ -128,7 +125,7 @@ static void AddPCRelop(Instruction &inst, int64_t disp) { auto &op = inst.operands.back(); op.type = Operand::kTypeAddress; op.size = kAddressSize; - op.action = Operand::kActionRead; + op.action = Operand::kActionRead; op.addr.kind = Operand::Address::kControlFlowTarget; op.addr.address_size = kAddressSize; op.addr.base_reg.name = "PC"; @@ -141,7 +138,7 @@ static void AddNextPCRelop(Instruction &inst, int64_t disp) { auto &op = inst.operands.back(); op.type = Operand::kTypeAddress; op.size = kAddressSize; - op.action = Operand::kActionRead; + op.action = Operand::kActionRead; op.addr.kind = Operand::Address::kControlFlowTarget; op.addr.address_size = kAddressSize; op.addr.base_reg.name = "NEXT_PC"; @@ -156,11 +153,11 @@ static void AddBasePlusOffsetMemop(Instruction &inst, Operand::Action action, auto &op = inst.operands.back(); op.type = Operand::kTypeAddress; op.size = access_size; - op.action = action; + op.action = action; - op.addr.kind = action == Operand::kActionRead ? - Operand::Address::kMemoryRead : - Operand::Address::kMemoryWrite; + op.addr.kind = action == Operand::kActionRead + ? Operand::Address::kMemoryRead + : Operand::Address::kMemoryWrite; op.addr.address_size = kAddressSize; if (base_reg && index_reg) { @@ -220,7 +217,7 @@ static bool TryDecodeRDasr(Instruction &inst, uint32_t bits) { case 26: // rd %cfr, rd inst.function = "RDCFR"; break; - default:return false; + default: return false; } AddIntRegop(inst, enc.rd, kAddressSize, Operand::kActionWrite); @@ -279,7 +276,7 @@ static bool TryDecodeRDPr(Instruction &inst, uint32_t bits) { case 16: // rdpr %gl, rd inst.function = "RDPR_GL"; break; - default:return false; + default: return false; } AddIntRegop(inst, enc.rd, kAddressSize, Operand::kActionWrite); @@ -322,7 +319,7 @@ static bool TryDecodeWRasr(Instruction &inst, uint32_t bits) { case 27: // wr rs1, reg_or_imm, %pause inst.function = "WRPAUSE"; break; - default:return false; + default: return false; } AddIntRegop(inst, enc_i0.rs1, kAddressSize, Operand::kActionRead); @@ -338,8 +335,8 @@ static bool TryDecodeCALL(Instruction &inst, uint32_t bits) { union { uint32_t flat; struct { - int32_t disp30:30; - uint32_t op:2; + int32_t disp30 : 30; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)) enc; enc.flat = bits; @@ -357,8 +354,8 @@ static bool TryDecodeCALL(Instruction &inst, uint32_t bits) { inst.has_branch_taken_delay_slot = true; inst.has_branch_not_taken_delay_slot = false; - inst.branch_taken_pc = static_cast( - static_cast(inst.pc) + disp); + inst.branch_taken_pc = + static_cast(static_cast(inst.pc) + disp); inst.next_pc += 4; @@ -368,11 +365,10 @@ static bool TryDecodeCALL(Instruction &inst, uint32_t bits) { inst.branch_not_taken_pc = inst.next_pc; // pc+8. } - AddSrcRegop(inst, "PC", kAddressSize); // Old PC. - AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. + AddSrcRegop(inst, "PC", kAddressSize); // Old PC. + AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. AddPCRelop(inst, disp); // New NPC. - AddIntRegop(inst, 15 /* %o7 */, kAddressSize, - Operand::kActionWrite); + AddIntRegop(inst, 15 /* %o7 */, kAddressSize, Operand::kActionWrite); AddPCDest(inst); AddNPCDest(inst); @@ -394,14 +390,14 @@ static bool TryDecodeJMPL(Instruction &inst, uint32_t bits) { Format3ai0 enc_i0 = {bits}; Format3ai1 enc_i1 = {bits}; - AddSrcRegop(inst, "PC", kAddressSize); // Old PC. - AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. + AddSrcRegop(inst, "PC", kAddressSize); // Old PC. + AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. inst.operands.emplace_back(); auto &op = inst.operands.back(); op.type = Operand::kTypeAddress; op.size = kAddressSize; - op.action = Operand::kActionRead; + op.action = Operand::kActionRead; op.addr.kind = Operand::Address::kControlFlowTarget; op.addr.address_size = kAddressSize; @@ -418,6 +414,7 @@ static bool TryDecodeJMPL(Instruction &inst, uint32_t bits) { } if (!enc_i0.rd) { + // NOTE(pag): This is stricter than what is in the manual, but is more in // line with how we deal with function calls, and how actual // software operates. @@ -427,7 +424,7 @@ static bool TryDecodeJMPL(Instruction &inst, uint32_t bits) { // an `unimp ` might be placed after the call's // delay slot, which the callee must skip past in its return. if ((enc_i1.simm13 == 8 || enc_i1.simm13 == 12) && - (enc_i1.rs1 == 15 /* %o7 */ || enc_i1.rs1 == 31 /* %i7 */)) { + (enc_i1.rs1 == 15 /* %o7 */ || enc_i1.rs1 == 31 /* %i7 */)) { inst.function = "RETL"; inst.category = Instruction::kCategoryFunctionReturn; } else { @@ -478,16 +475,16 @@ static bool TryDecodeTcc(Instruction &inst, uint32_t bits) { union { uint32_t flat; struct { - uint32_t rs2:5; - uint32_t _0:6; - uint32_t cc0:1; - uint32_t cc1:1; - uint32_t i:1; - uint32_t rs1:5; - uint32_t op3:6; - uint32_t cond:4; - uint32_t _1:1; - uint32_t op:2; + uint32_t rs2 : 5; + uint32_t _0 : 6; + uint32_t cc0 : 1; + uint32_t cc1 : 1; + uint32_t i : 1; + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t cond : 4; + uint32_t _1 : 1; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)) enc_i0 = {bits}; static_assert(sizeof(enc_i0) == 4); @@ -495,16 +492,16 @@ static bool TryDecodeTcc(Instruction &inst, uint32_t bits) { union { uint32_t flat; struct { - uint32_t imm7:7; - uint32_t _0:4; - uint32_t cc0:1; - uint32_t cc1:1; - uint32_t i:1; - uint32_t rs1:5; - uint32_t op3:6; - uint32_t cond:4; - uint32_t _1:1; - uint32_t op:2; + uint32_t imm7 : 7; + uint32_t _0 : 4; + uint32_t cc0 : 1; + uint32_t cc1 : 1; + uint32_t i : 1; + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t cond : 4; + uint32_t _1 : 1; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)) enc_i1 = {bits}; static_assert(sizeof(enc_i1) == 4); @@ -565,7 +562,7 @@ static bool TryDecodeTcc(Instruction &inst, uint32_t bits) { // TODO(pag): Handle write to TBR on `trap_instruction`. AddBranchTaken(inst); - AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC on taken. + AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC on taken. AddNextPCRelop(inst, 4); // New NPC on taken. // Trap vector number. @@ -584,9 +581,9 @@ static bool TryDecodeTcc(Instruction &inst, uint32_t bits) { } // Generic decoder for conditional branches (Bcc, BPcc). -static bool TryDecode_Branch( - Instruction &inst, unsigned cond, bool anul, int64_t disp, - std::string_view iform, std::string_view ccr, bool is_fcc = false) { +static bool TryDecode_Branch(Instruction &inst, unsigned cond, bool anul, + int64_t disp, std::string_view iform, + std::string_view ccr, bool is_fcc = false) { // Branch always. if (cond == 0b1000) { @@ -654,8 +651,8 @@ static bool TryDecode_Branch( inst.has_branch_not_taken_delay_slot = true; - // Anulled means that the delayed instruction is executed on the taken - // path, but not on the not-taken path. + // Anulled means that the delayed instruction is executed on the taken + // path, but not on the not-taken path. } else { AddNextPCRelop(inst, 4); // PC if not taken. AddNextPCRelop(inst, 8); // NPC if not taken. @@ -752,42 +749,42 @@ static bool TryDecodeBPr(Instruction &inst, uint32_t bits) { inst.next_pc += 4; inst.branch_not_taken_pc = inst.next_pc; // Skip delayed instruction. - // Not anulled means that the delayed instruction is executed on the taken - // and not-taken paths. - if (!enc.a) { - AddSrcRegop(inst, "NEXT_PC", kAddressSize); // PC if not taken. - AddNextPCRelop(inst, 4); // NPC if not taken. - - inst.has_branch_not_taken_delay_slot = true; - - // Anulled means that the delayed instruction is executed on the taken - // path, but not on the not-taken path. - } else { - AddNextPCRelop(inst, 4); // PC if not taken. - AddNextPCRelop(inst, 8); // NPC if not taken. - - inst.has_branch_not_taken_delay_slot = false; - } - - AddPCDest(inst); - AddNPCDest(inst); - - // NOTE(pag): This is part of a SPARC idiom of `jmpl,rett`, but we don't - // have elaborate pipeline support to handle things. See - // semantics of `UNSUPPORTED_DCTI`. - if (inst.in_delay_slot) { - inst.function = "UNSUPPORTED_DCTI"; - inst.operands.clear(); - inst.has_branch_taken_delay_slot = false; - inst.has_branch_not_taken_delay_slot = false; - inst.category = Instruction::kCategoryNormal; - inst.next_pc = inst.pc + 4; - - } else { - inst.function.reserve(9); - inst.function.insert(0, "BR"); - inst.function += kRCondName[enc.rcond]; - } + // Not anulled means that the delayed instruction is executed on the taken + // and not-taken paths. + if (!enc.a) { + AddSrcRegop(inst, "NEXT_PC", kAddressSize); // PC if not taken. + AddNextPCRelop(inst, 4); // NPC if not taken. + + inst.has_branch_not_taken_delay_slot = true; + + // Anulled means that the delayed instruction is executed on the taken + // path, but not on the not-taken path. + } else { + AddNextPCRelop(inst, 4); // PC if not taken. + AddNextPCRelop(inst, 8); // NPC if not taken. + + inst.has_branch_not_taken_delay_slot = false; + } + + AddPCDest(inst); + AddNPCDest(inst); + + // NOTE(pag): This is part of a SPARC idiom of `jmpl,rett`, but we don't + // have elaborate pipeline support to handle things. See + // semantics of `UNSUPPORTED_DCTI`. + if (inst.in_delay_slot) { + inst.function = "UNSUPPORTED_DCTI"; + inst.operands.clear(); + inst.has_branch_taken_delay_slot = false; + inst.has_branch_not_taken_delay_slot = false; + inst.category = Instruction::kCategoryNormal; + inst.next_pc = inst.pc + 4; + + } else { + inst.function.reserve(9); + inst.function.insert(0, "BR"); + inst.function += kRCondName[enc.rcond]; + } return true; } @@ -822,9 +819,9 @@ static bool TryDecodeSETHI(Instruction &inst, uint32_t bits) { return true; } -static bool TryDecodeSET_IDIOM( - Instruction &inst, uint32_t bits1, uint32_t bits2, - const char *base, const char *multi) { +static bool TryDecodeSET_IDIOM(Instruction &inst, uint32_t bits1, + uint32_t bits2, const char *base, + const char *multi) { Format0a enc1 = {bits1}; Format3ai0 enc2_i0 = {bits2}; Format3ai1 enc2_i1 = {bits2}; @@ -840,6 +837,7 @@ static bool TryDecodeSET_IDIOM( // sethi imm_high, rd // or rd, imm_low, rd if (enc2_i1.rs1 == enc1.rd) { + //const auto imm = static_cast(imm_low | imm_high); inst.function = "SET"; AddImmop(inst, static_cast(imm_high), kAddressSize, false); @@ -941,13 +939,13 @@ static bool TryDecodeSET_IDIOM( return true; } -static bool TryDecodeSET_SETHI_OR( - Instruction &inst, uint32_t bits1, uint32_t bits2) { +static bool TryDecodeSET_SETHI_OR(Instruction &inst, uint32_t bits1, + uint32_t bits2) { return TryDecodeSET_IDIOM(inst, bits1, bits2, "OR", "SETHI_OR"); } -static bool TryDecodeSET_SETHI_ADD( - Instruction &inst, uint32_t bits1, uint32_t bits2) { +static bool TryDecodeSET_SETHI_ADD(Instruction &inst, uint32_t bits1, + uint32_t bits2) { return TryDecodeSET_IDIOM(inst, bits1, bits2, "ADD", "SETHI_ADD"); } @@ -956,7 +954,7 @@ static bool TryDecodeRETURN(Instruction &inst, uint32_t bits) { Format3ai1 enc_i1 = {bits}; inst.category = Instruction::kCategoryFunctionReturn; - AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. + AddSrcRegop(inst, "NEXT_PC", kAddressSize); // New PC. inst.operands.emplace_back(); auto &dst_op = inst.operands.back(); @@ -987,7 +985,7 @@ static bool TryDecodeRETURN(Instruction &inst, uint32_t bits) { return false; // RETT to `0`. } } else { - if (enc_i0.rs1 && enc_i0.rs2) { // `r[rs1] + r[rs2]`. + if (enc_i0.rs1 && enc_i0.rs2) { // `r[rs1] + r[rs2]`. dst_op.addr.base_reg.name = kReadIntRegName[enc_i0.rs1]; dst_op.addr.base_reg.size = kAddressSize; @@ -1038,8 +1036,8 @@ static bool TryDecodeRETURN(Instruction &inst, uint32_t bits) { } -static bool TryDecode_rs1_simm32_op_rs2_rd( - Instruction &inst, uint32_t bits, const char *iform) { +static bool TryDecode_rs1_simm32_op_rs2_rd(Instruction &inst, uint32_t bits, + const char *iform) { Format3ai0 enc_i0 = {bits}; Format3ai1 enc_i1 = {bits}; @@ -1066,8 +1064,7 @@ static bool TryDecodeMOVcc(Instruction &inst, uint32_t bits) { } if (enc_i1.i) { - AddImmop(inst, static_cast(enc_i1.simm11), - kAddressSize, true); + AddImmop(inst, static_cast(enc_i1.simm11), kAddressSize, true); } else { AddIntRegop(inst, enc_i0.rs2, kAddressSize, Operand::kActionRead); } @@ -1098,8 +1095,7 @@ static bool TryDecodeMOVr(Instruction &inst, uint32_t bits) { if (enc_i1.i) { AddIntRegop(inst, enc_i1.rs1, kAddressSize, Operand::kActionRead); - AddImmop(inst, static_cast(enc_i1.simm10), - kAddressSize, true); + AddImmop(inst, static_cast(enc_i1.simm10), kAddressSize, true); } else { AddIntRegop(inst, enc_i0.rs1, kAddressSize, Operand::kActionRead); AddIntRegop(inst, enc_i0.rs2, kAddressSize, Operand::kActionRead); @@ -1179,22 +1175,22 @@ struct fpu_opcode { }; static const fpu_opcode Opf05[1 << 4U] = { - [0b0000] = {{}, 0}, - [0b0001] = {"FCMPS", 0x00002020}, - [0b0010] = {"FCMPD", 0x00004040}, - [0b0011] = {"FCMPQ", 0x00008080}, - [0b0100] = {{}, 0}, - [0b0101] = {"FCMPES", 0x00002020}, - [0b0110] = {"FCMPED", 0x00004040}, - [0b0111] = {"FCMPEQ", 0x00008080}, - [0b1000] = {{}, 0}, - [0b1001] = {{}, 0}, - [0b1010] = {{}, 0}, - [0b1011] = {{}, 0}, - [0b1100] = {{}, 0}, - [0b1101] = {{}, 0}, - [0b1110] = {{}, 0}, - [0b1111] = {{}, 0}, + [0b0000] = {{}, 0}, + [0b0001] = {"FCMPS", 0x00002020}, + [0b0010] = {"FCMPD", 0x00004040}, + [0b0011] = {"FCMPQ", 0x00008080}, + [0b0100] = {{}, 0}, + [0b0101] = {"FCMPES", 0x00002020}, + [0b0110] = {"FCMPED", 0x00004040}, + [0b0111] = {"FCMPEQ", 0x00008080}, + [0b1000] = {{}, 0}, + [0b1001] = {{}, 0}, + [0b1010] = {{}, 0}, + [0b1011] = {{}, 0}, + [0b1100] = {{}, 0}, + [0b1101] = {{}, 0}, + [0b1110] = {{}, 0}, + [0b1111] = {{}, 0}, }; static bool TryDecodeFCMP(Instruction &inst, uint32_t bits) { @@ -1202,10 +1198,10 @@ static bool TryDecodeFCMP(Instruction &inst, uint32_t bits) { union { uint32_t flat; struct { - uint32_t rs1:8; - uint32_t rs2:8; - uint32_t rd:8; - uint32_t _1:8; + uint32_t rs1 : 8; + uint32_t rs2 : 8; + uint32_t rd : 8; + uint32_t _1 : 8; } __attribute__((packed)); } __attribute__((packed)) opd_size = {Opf05[enc.opf & 0b1111].size}; @@ -1234,14 +1230,14 @@ static bool TryDecodeFMOVcc(Instruction &inst, uint32_t bits) { union { uint32_t flat; struct { - uint32_t rs2:5; - uint32_t opf_low:6; - uint32_t opf_cc:3; - uint32_t cond:4; - uint32_t _1:1; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + uint32_t rs2 : 5; + uint32_t opf_low : 6; + uint32_t opf_cc : 3; + uint32_t cond : 4; + uint32_t _1 : 1; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)) enc = {bits}; static_assert(sizeof(enc) == 4); @@ -1254,7 +1250,7 @@ static bool TryDecodeFMOVcc(Instruction &inst, uint32_t bits) { inst.category = Instruction::kCategoryNormal; inst.function.reserve(12); auto access_size = kAddressSize; - switch(enc.opf_low) { + switch (enc.opf_low) { case 0b0001: access_size = 32; inst.function.insert(0, "FMOVS"); @@ -1267,8 +1263,7 @@ static bool TryDecodeFMOVcc(Instruction &inst, uint32_t bits) { access_size = 128; inst.function.insert(0, "FMOVQ"); break; - default: - return false; + default: return false; } AddFpuRegOp(inst, enc.rs2, access_size, Operand::kActionRead); @@ -1288,27 +1283,26 @@ static bool TryDecodeFMOVr(Instruction &inst, uint32_t bits) { union { uint32_t flat; struct { - uint32_t rs2:5; - uint32_t opf_low:5; - uint32_t rcond:3; - uint32_t _1:1; - uint32_t rs1:5; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + uint32_t rs2 : 5; + uint32_t opf_low : 5; + uint32_t rcond : 3; + uint32_t _1 : 1; + uint32_t rs1 : 5; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)) enc = {bits}; static_assert(sizeof(enc) == 4); - if ((enc.rcond == 0b000) - || (enc.rcond == 0b100)) { + if ((enc.rcond == 0b000) || (enc.rcond == 0b100)) { return false; // Reserved. } inst.category = Instruction::kCategoryNormal; inst.function.reserve(9); auto access_size = kAddressSize; - switch(enc.opf_low) { + switch (enc.opf_low) { case 0b0001: access_size = 32; inst.function.insert(0, "FMOVRS"); @@ -1321,8 +1315,7 @@ static bool TryDecodeFMOVr(Instruction &inst, uint32_t bits) { access_size = 128; inst.function.insert(0, "FMOVRQ"); break; - default: - return false; + default: return false; } AddIntRegop(inst, enc.rs1, kAddressSize, Operand::kActionRead); @@ -1337,21 +1330,20 @@ static bool TryDecodeFMOV(Instruction &inst, uint32_t bits) { union { uint32_t flat; struct { - uint32_t rs2:5; - uint32_t opf_low:6; - uint32_t opf_cc:3; - uint32_t cond:4; - uint32_t _1:1; - uint32_t op3:6; - uint32_t rd:5; - uint32_t op:2; + uint32_t rs2 : 5; + uint32_t opf_low : 6; + uint32_t opf_cc : 3; + uint32_t cond : 4; + uint32_t _1 : 1; + uint32_t op3 : 6; + uint32_t rd : 5; + uint32_t op : 2; } __attribute__((packed)); } __attribute__((packed)) enc = {bits}; static_assert(sizeof(enc) == 4); - if ((enc.opf_low == 0b0001) - || (enc.opf_low == 0b0010) - || (enc.opf_low == 0b0011)) { + if ((enc.opf_low == 0b0001) || (enc.opf_low == 0b0010) || + (enc.opf_low == 0b0011)) { return TryDecodeFMOVcc(inst, bits); } return TryDecodeFMOVr(inst, bits); @@ -1368,9 +1360,9 @@ static bool TryDecodeFCMP_FMOV(Instruction &inst, uint32_t bits) { return TryDecodeFMOV(inst, bits); } -static bool TryDecodeOpf_rs1_op_rs2_rd( - Instruction &inst, uint32_t bits, uint32_t rs1_size, - uint32_t rs2_size, uint32_t rd_size, const char *iform) { +static bool TryDecodeOpf_rs1_op_rs2_rd(Instruction &inst, uint32_t bits, + uint32_t rs1_size, uint32_t rs2_size, + uint32_t rd_size, const char *iform) { Format3b enc = {bits}; inst.function = iform; inst.category = Instruction::kCategoryNormal; @@ -1429,14 +1421,15 @@ static bool TryDecodeBSHUFFLE(Instruction &inst, uint32_t bits) { return true; } -#define SZERO 0 -#define SWORD 32 -#define DWORD 64 -#define QWORD 128 +#define SZERO 0 +#define SWORD 32 +#define DWORD 64 +#define QWORD 128 #define DEFINE_FUNCTION(name, rs1_size, rs2_size, rd_size) \ - static bool TryDecode ## name(Instruction &inst, uint32_t bits) { \ - return TryDecodeOpf_rs1_op_rs2_rd(inst, bits, rs1_size, rs2_size, rd_size, #name); \ + static bool TryDecode##name(Instruction &inst, uint32_t bits) { \ + return TryDecodeOpf_rs1_op_rs2_rd(inst, bits, rs1_size, rs2_size, rd_size, \ + #name); \ } DEFINE_FUNCTION(FABSS, SZERO, SWORD, SWORD) @@ -1491,277 +1484,149 @@ DEFINE_FUNCTION(FQTOS, SZERO, QWORD, SWORD) DEFINE_FUNCTION(FQTOD, SZERO, QWORD, DWORD) static bool (*const kop10_op352Level[1u << 8])(Instruction &, uint32_t) = { - [0b00000000] = nullptr, - [0b00000001] = TryDecodeFMOVS, - [0b00000010] = TryDecodeFMOVD, - [0b00000011] = TryDecodeFMOVQ, - [0b00000100] = nullptr, - [0b00000101] = TryDecodeFNEGS, - [0b00000110] = TryDecodeFNEGD, - [0b00000111] = TryDecodeFNEGQ, - [0b00001000] = nullptr, - [0b00001001] = TryDecodeFABSS, - [0b00001010] = TryDecodeFABSD, - [0b00001011] = TryDecodeFABSQ, - [0b00001100] = nullptr, - [0b00001101] = nullptr, - [0b00001110] = nullptr, - [0b00001111] = nullptr, - [0b00010000] = nullptr, - [0b00010001] = nullptr, - [0b00010010] = nullptr, - [0b00010011] = nullptr, - [0b00010100] = nullptr, - [0b00010101] = nullptr, - [0b00010110] = nullptr, - [0b00010111] = nullptr, - [0b00011000] = nullptr, - [0b00011001] = TryDecodeBMASK, - [0b00011010] = nullptr, - [0b00011011] = nullptr, - [0b00011100] = nullptr, - [0b00011101] = nullptr, - [0b00011110] = nullptr, - [0b00011111] = nullptr, - [0b00100000] = nullptr, - [0b00100001] = nullptr, - [0b00100010] = nullptr, - [0b00100011] = nullptr, - [0b00100100] = nullptr, - [0b00100101] = nullptr, - [0b00100110] = nullptr, - [0b00100111] = nullptr, - [0b00101000] = nullptr, - [0b00101001] = TryDecodeFSQRTS, - [0b00101010] = TryDecodeFSQRTD, - [0b00101011] = TryDecodeFSQRTQ, - [0b00101100] = nullptr, - [0b00101101] = nullptr, - [0b00101110] = nullptr, - [0b00101111] = nullptr, - [0b00110000] = nullptr, - [0b00110001] = nullptr, - [0b00110010] = nullptr, - [0b00110011] = nullptr, - [0b00110100] = nullptr, - [0b00110101] = nullptr, - [0b00110110] = nullptr, - [0b00110111] = nullptr, - [0b00111000] = nullptr, - [0b00111001] = nullptr, - [0b00111010] = nullptr, - [0b00111011] = nullptr, - [0b00111100] = nullptr, - [0b00111101] = nullptr, - [0b00111110] = nullptr, - [0b00111111] = nullptr, - [0b01000000] = nullptr, - [0b01000001] = TryDecodeFADDS, - [0b01000010] = TryDecodeFADDD, - [0b01000011] = TryDecodeFADDQ, - [0b01000100] = nullptr, - [0b01000101] = TryDecodeFSUBS, - [0b01000110] = TryDecodeFSUBD, - [0b01000111] = TryDecodeFSUBQ, - [0b01001000] = nullptr, - [0b01001001] = TryDecodeFMULS, - [0b01001010] = TryDecodeFMULD, - [0b01001011] = TryDecodeFMULQ, - [0b01001100] = nullptr, - [0b01001101] = TryDecodeFDIVS, - [0b01001110] = TryDecodeFDIVD, - [0b01001111] = TryDecodeFDIVQ, - [0b01010000] = nullptr, - [0b01010001] = nullptr, - [0b01010010] = nullptr, - [0b01010011] = nullptr, - [0b01010100] = nullptr, - [0b01010101] = nullptr, - [0b01010110] = nullptr, - [0b01010111] = nullptr, - [0b01011000] = nullptr, - [0b01011001] = nullptr, - [0b01011010] = nullptr, - [0b01011011] = nullptr, - [0b01011100] = nullptr, - [0b01011101] = nullptr, - [0b01011110] = nullptr, - [0b01011111] = nullptr, - [0b01100000] = nullptr, - [0b01100001] = TryDecodeFHADDS, - [0b01100010] = TryDecodeFHADDD, - [0b01100011] = nullptr, - [0b01100100] = nullptr, - [0b01100101] = nullptr, - [0b01100110] = nullptr, - [0b01100111] = nullptr, - [0b01101000] = nullptr, - [0b01101001] = TryDecodeFSMULD, - [0b01101010] = nullptr, - [0b01101011] = nullptr, - [0b01101100] = nullptr, - [0b01101101] = nullptr, - [0b01101110] = TryDecodeFDMULQ, - [0b01101111] = nullptr, - [0b01110000] = nullptr, - [0b01110001] = nullptr, - [0b01110010] = nullptr, - [0b01110011] = nullptr, - [0b01110100] = nullptr, - [0b01110101] = nullptr, - [0b01110110] = nullptr, - [0b01110111] = nullptr, - [0b01111000] = nullptr, - [0b01111001] = nullptr, - [0b01111010] = nullptr, - [0b01111011] = nullptr, - [0b01111100] = nullptr, - [0b01111101] = nullptr, - [0b01111110] = nullptr, - [0b01111111] = nullptr, - [0b10000000] = nullptr, - [0b10000001] = TryDecodeFSTOX, - [0b10000010] = TryDecodeFDTOX, - [0b10000011] = TryDecodeFQTOX, - [0b10000100] = TryDecodeFXTOS, - [0b10000101] = nullptr, - [0b10000110] = nullptr, - [0b10000111] = nullptr, - [0b10001000] = TryDecodeFXTOD, - [0b10001001] = nullptr, - [0b10001010] = nullptr, - [0b10001011] = nullptr, - [0b10001100] = TryDecodeFXTOQ, - [0b10001101] = nullptr, - [0b10001110] = nullptr, - [0b10001111] = nullptr, - [0b10010000] = nullptr, - [0b10010001] = nullptr, - [0b10010010] = nullptr, - [0b10010011] = nullptr, - [0b10010100] = nullptr, - [0b10010101] = nullptr, - [0b10010110] = nullptr, - [0b10010111] = nullptr, - [0b10011000] = nullptr, - [0b10011001] = nullptr, - [0b10011010] = nullptr, - [0b10011011] = nullptr, - [0b10011100] = nullptr, - [0b10011101] = nullptr, - [0b10011110] = nullptr, - [0b10011111] = nullptr, - [0b10100000] = nullptr, - [0b10100001] = nullptr, - [0b10100010] = nullptr, - [0b10100011] = nullptr, - [0b10100100] = nullptr, - [0b10100101] = nullptr, - [0b10100110] = nullptr, - [0b10100111] = nullptr, - [0b10101000] = nullptr, - [0b10101001] = nullptr, - [0b10101010] = nullptr, - [0b10101011] = nullptr, - [0b10101100] = nullptr, - [0b10101101] = nullptr, - [0b10101110] = nullptr, - [0b10101111] = nullptr, - [0b10110000] = nullptr, - [0b10110001] = nullptr, - [0b10110010] = nullptr, - [0b10110011] = nullptr, - [0b10110100] = nullptr, - [0b10110101] = nullptr, - [0b10110110] = nullptr, - [0b10110111] = nullptr, - [0b10111000] = nullptr, - [0b10111001] = nullptr, - [0b10111010] = nullptr, - [0b10111011] = nullptr, - [0b10111100] = nullptr, - [0b10111101] = nullptr, - [0b10111110] = nullptr, - [0b10111111] = nullptr, - [0b11000000] = nullptr, - [0b11000001] = nullptr, - [0b11000010] = nullptr, - [0b11000011] = nullptr, - [0b11000100] = TryDecodeFITOS, - [0b11000101] = nullptr, - [0b11000110] = TryDecodeFDTOS, - [0b11000111] = TryDecodeFQTOS, - [0b11001000] = TryDecodeFITOD, - [0b11001001] = TryDecodeFSTOD, - [0b11001010] = nullptr, - [0b11001011] = TryDecodeFQTOD, - [0b11001100] = TryDecodeFITOQ, - [0b11001101] = TryDecodeFSTOQ, - [0b11001110] = TryDecodeFDTOQ, - [0b11001111] = nullptr, - [0b11010000] = nullptr, - [0b11010001] = TryDecodeFSTOI, - [0b11010010] = TryDecodeFDTOI, - [0b11010011] = TryDecodeFQTOI, - [0b11010100] = nullptr, - [0b11010101] = nullptr, - [0b11010110] = nullptr, - [0b11010111] = nullptr, - [0b11011000] = nullptr, - [0b11011001] = nullptr, - [0b11011010] = nullptr, - [0b11011011] = nullptr, - [0b11011100] = nullptr, - [0b11011101] = nullptr, - [0b11011110] = nullptr, - [0b11011111] = nullptr, - [0b11100000] = nullptr, - [0b11100001] = nullptr, - [0b11100010] = nullptr, - [0b11100011] = nullptr, - [0b11100100] = nullptr, - [0b11100101] = nullptr, - [0b11100110] = nullptr, - [0b11100111] = nullptr, - [0b11101000] = nullptr, - [0b11101001] = nullptr, - [0b11101010] = nullptr, - [0b11101011] = nullptr, - [0b11101100] = nullptr, - [0b11101101] = nullptr, - [0b11101110] = nullptr, - [0b11101111] = nullptr, - [0b11110000] = nullptr, - [0b11110001] = nullptr, - [0b11110010] = nullptr, - [0b11110011] = nullptr, - [0b11110100] = nullptr, - [0b11110101] = nullptr, - [0b11110110] = nullptr, - [0b11110111] = nullptr, - [0b11111000] = nullptr, - [0b11111001] = nullptr, - [0b11111010] = nullptr, - [0b11111011] = nullptr, - [0b11111100] = nullptr, - [0b11111101] = nullptr, - [0b11111110] = nullptr, - [0b11111111] = nullptr, + [0b00000000] = nullptr, [0b00000001] = TryDecodeFMOVS, + [0b00000010] = TryDecodeFMOVD, [0b00000011] = TryDecodeFMOVQ, + [0b00000100] = nullptr, [0b00000101] = TryDecodeFNEGS, + [0b00000110] = TryDecodeFNEGD, [0b00000111] = TryDecodeFNEGQ, + [0b00001000] = nullptr, [0b00001001] = TryDecodeFABSS, + [0b00001010] = TryDecodeFABSD, [0b00001011] = TryDecodeFABSQ, + [0b00001100] = nullptr, [0b00001101] = nullptr, + [0b00001110] = nullptr, [0b00001111] = nullptr, + [0b00010000] = nullptr, [0b00010001] = nullptr, + [0b00010010] = nullptr, [0b00010011] = nullptr, + [0b00010100] = nullptr, [0b00010101] = nullptr, + [0b00010110] = nullptr, [0b00010111] = nullptr, + [0b00011000] = nullptr, [0b00011001] = TryDecodeBMASK, + [0b00011010] = nullptr, [0b00011011] = nullptr, + [0b00011100] = nullptr, [0b00011101] = nullptr, + [0b00011110] = nullptr, [0b00011111] = nullptr, + [0b00100000] = nullptr, [0b00100001] = nullptr, + [0b00100010] = nullptr, [0b00100011] = nullptr, + [0b00100100] = nullptr, [0b00100101] = nullptr, + [0b00100110] = nullptr, [0b00100111] = nullptr, + [0b00101000] = nullptr, [0b00101001] = TryDecodeFSQRTS, + [0b00101010] = TryDecodeFSQRTD, [0b00101011] = TryDecodeFSQRTQ, + [0b00101100] = nullptr, [0b00101101] = nullptr, + [0b00101110] = nullptr, [0b00101111] = nullptr, + [0b00110000] = nullptr, [0b00110001] = nullptr, + [0b00110010] = nullptr, [0b00110011] = nullptr, + [0b00110100] = nullptr, [0b00110101] = nullptr, + [0b00110110] = nullptr, [0b00110111] = nullptr, + [0b00111000] = nullptr, [0b00111001] = nullptr, + [0b00111010] = nullptr, [0b00111011] = nullptr, + [0b00111100] = nullptr, [0b00111101] = nullptr, + [0b00111110] = nullptr, [0b00111111] = nullptr, + [0b01000000] = nullptr, [0b01000001] = TryDecodeFADDS, + [0b01000010] = TryDecodeFADDD, [0b01000011] = TryDecodeFADDQ, + [0b01000100] = nullptr, [0b01000101] = TryDecodeFSUBS, + [0b01000110] = TryDecodeFSUBD, [0b01000111] = TryDecodeFSUBQ, + [0b01001000] = nullptr, [0b01001001] = TryDecodeFMULS, + [0b01001010] = TryDecodeFMULD, [0b01001011] = TryDecodeFMULQ, + [0b01001100] = nullptr, [0b01001101] = TryDecodeFDIVS, + [0b01001110] = TryDecodeFDIVD, [0b01001111] = TryDecodeFDIVQ, + [0b01010000] = nullptr, [0b01010001] = nullptr, + [0b01010010] = nullptr, [0b01010011] = nullptr, + [0b01010100] = nullptr, [0b01010101] = nullptr, + [0b01010110] = nullptr, [0b01010111] = nullptr, + [0b01011000] = nullptr, [0b01011001] = nullptr, + [0b01011010] = nullptr, [0b01011011] = nullptr, + [0b01011100] = nullptr, [0b01011101] = nullptr, + [0b01011110] = nullptr, [0b01011111] = nullptr, + [0b01100000] = nullptr, [0b01100001] = TryDecodeFHADDS, + [0b01100010] = TryDecodeFHADDD, [0b01100011] = nullptr, + [0b01100100] = nullptr, [0b01100101] = nullptr, + [0b01100110] = nullptr, [0b01100111] = nullptr, + [0b01101000] = nullptr, [0b01101001] = TryDecodeFSMULD, + [0b01101010] = nullptr, [0b01101011] = nullptr, + [0b01101100] = nullptr, [0b01101101] = nullptr, + [0b01101110] = TryDecodeFDMULQ, [0b01101111] = nullptr, + [0b01110000] = nullptr, [0b01110001] = nullptr, + [0b01110010] = nullptr, [0b01110011] = nullptr, + [0b01110100] = nullptr, [0b01110101] = nullptr, + [0b01110110] = nullptr, [0b01110111] = nullptr, + [0b01111000] = nullptr, [0b01111001] = nullptr, + [0b01111010] = nullptr, [0b01111011] = nullptr, + [0b01111100] = nullptr, [0b01111101] = nullptr, + [0b01111110] = nullptr, [0b01111111] = nullptr, + [0b10000000] = nullptr, [0b10000001] = TryDecodeFSTOX, + [0b10000010] = TryDecodeFDTOX, [0b10000011] = TryDecodeFQTOX, + [0b10000100] = TryDecodeFXTOS, [0b10000101] = nullptr, + [0b10000110] = nullptr, [0b10000111] = nullptr, + [0b10001000] = TryDecodeFXTOD, [0b10001001] = nullptr, + [0b10001010] = nullptr, [0b10001011] = nullptr, + [0b10001100] = TryDecodeFXTOQ, [0b10001101] = nullptr, + [0b10001110] = nullptr, [0b10001111] = nullptr, + [0b10010000] = nullptr, [0b10010001] = nullptr, + [0b10010010] = nullptr, [0b10010011] = nullptr, + [0b10010100] = nullptr, [0b10010101] = nullptr, + [0b10010110] = nullptr, [0b10010111] = nullptr, + [0b10011000] = nullptr, [0b10011001] = nullptr, + [0b10011010] = nullptr, [0b10011011] = nullptr, + [0b10011100] = nullptr, [0b10011101] = nullptr, + [0b10011110] = nullptr, [0b10011111] = nullptr, + [0b10100000] = nullptr, [0b10100001] = nullptr, + [0b10100010] = nullptr, [0b10100011] = nullptr, + [0b10100100] = nullptr, [0b10100101] = nullptr, + [0b10100110] = nullptr, [0b10100111] = nullptr, + [0b10101000] = nullptr, [0b10101001] = nullptr, + [0b10101010] = nullptr, [0b10101011] = nullptr, + [0b10101100] = nullptr, [0b10101101] = nullptr, + [0b10101110] = nullptr, [0b10101111] = nullptr, + [0b10110000] = nullptr, [0b10110001] = nullptr, + [0b10110010] = nullptr, [0b10110011] = nullptr, + [0b10110100] = nullptr, [0b10110101] = nullptr, + [0b10110110] = nullptr, [0b10110111] = nullptr, + [0b10111000] = nullptr, [0b10111001] = nullptr, + [0b10111010] = nullptr, [0b10111011] = nullptr, + [0b10111100] = nullptr, [0b10111101] = nullptr, + [0b10111110] = nullptr, [0b10111111] = nullptr, + [0b11000000] = nullptr, [0b11000001] = nullptr, + [0b11000010] = nullptr, [0b11000011] = nullptr, + [0b11000100] = TryDecodeFITOS, [0b11000101] = nullptr, + [0b11000110] = TryDecodeFDTOS, [0b11000111] = TryDecodeFQTOS, + [0b11001000] = TryDecodeFITOD, [0b11001001] = TryDecodeFSTOD, + [0b11001010] = nullptr, [0b11001011] = TryDecodeFQTOD, + [0b11001100] = TryDecodeFITOQ, [0b11001101] = TryDecodeFSTOQ, + [0b11001110] = TryDecodeFDTOQ, [0b11001111] = nullptr, + [0b11010000] = nullptr, [0b11010001] = TryDecodeFSTOI, + [0b11010010] = TryDecodeFDTOI, [0b11010011] = TryDecodeFQTOI, + [0b11010100] = nullptr, [0b11010101] = nullptr, + [0b11010110] = nullptr, [0b11010111] = nullptr, + [0b11011000] = nullptr, [0b11011001] = nullptr, + [0b11011010] = nullptr, [0b11011011] = nullptr, + [0b11011100] = nullptr, [0b11011101] = nullptr, + [0b11011110] = nullptr, [0b11011111] = nullptr, + [0b11100000] = nullptr, [0b11100001] = nullptr, + [0b11100010] = nullptr, [0b11100011] = nullptr, + [0b11100100] = nullptr, [0b11100101] = nullptr, + [0b11100110] = nullptr, [0b11100111] = nullptr, + [0b11101000] = nullptr, [0b11101001] = nullptr, + [0b11101010] = nullptr, [0b11101011] = nullptr, + [0b11101100] = nullptr, [0b11101101] = nullptr, + [0b11101110] = nullptr, [0b11101111] = nullptr, + [0b11110000] = nullptr, [0b11110001] = nullptr, + [0b11110010] = nullptr, [0b11110011] = nullptr, + [0b11110100] = nullptr, [0b11110101] = nullptr, + [0b11110110] = nullptr, [0b11110111] = nullptr, + [0b11111000] = nullptr, [0b11111001] = nullptr, + [0b11111010] = nullptr, [0b11111011] = nullptr, + [0b11111100] = nullptr, [0b11111101] = nullptr, + [0b11111110] = nullptr, [0b11111111] = nullptr, }; static bool TryDecodeOpf52(Instruction &inst, uint32_t bits) { Format3b enc = {bits}; auto func = kop10_op352Level[enc.opf]; if (!func) { - LOG(ERROR) - << "Decoding IMPDEP1 with OP=10 op3=110100 opf=" << std::bitset<8>(enc.opf) - << " at "<< std::hex << inst.pc << std::dec; + LOG(ERROR) << "Decoding IMPDEP1 with OP=10 op3=110100 opf=" + << std::bitset<8>(enc.opf) << " at " << std::hex << inst.pc + << std::dec; return TryDecodeIMPDEP1(inst, bits); } return func(inst, bits); } -static bool TryDecodeEDGE8cc (Instruction &inst, uint32_t bits) { +static bool TryDecodeEDGE8cc(Instruction &inst, uint32_t bits) { Format3b enc = {bits}; inst.function = "EDGE8cc"; inst.category = Instruction::kCategoryNormal; @@ -1793,324 +1658,308 @@ DEFINE_FUNCTION(FNADDS, SWORD, SWORD, SWORD) DEFINE_FUNCTION(FNADDD, DWORD, DWORD, DWORD) static bool (*const kop10_op354Level[1u << 8])(Instruction &, uint32_t) = { - [0b00000000] = TryDecodeEDGE8cc, - [0b00000001] = nullptr, - [0b00000010] = nullptr, - [0b00000011] = nullptr, - [0b00000100] = nullptr, - [0b00000101] = nullptr, - [0b00000110] = nullptr, - [0b00000111] = nullptr, - [0b00001000] = nullptr, - [0b00001001] = nullptr, - [0b00001010] = nullptr, - [0b00001011] = nullptr, - [0b00001100] = nullptr, - [0b00001101] = nullptr, - [0b00001110] = nullptr, - [0b00001111] = nullptr, - [0b00010000] = nullptr, - [0b00010001] = nullptr, - [0b00010010] = nullptr, - [0b00010011] = nullptr, - [0b00010100] = nullptr, - [0b00010101] = nullptr, - [0b00010110] = nullptr, - [0b00010111] = nullptr, - [0b00011000] = TryDecodeALIGNADDRESS, - [0b00011001] = nullptr, - [0b00011010] = TryDecodeALIGNADDRESS_LITTLE, - [0b00011011] = nullptr, - [0b00011100] = nullptr, - [0b00011101] = nullptr, - [0b00011110] = nullptr, - [0b00011111] = nullptr, - [0b00100000] = nullptr, - [0b00100001] = nullptr, - [0b00100010] = nullptr, - [0b00100011] = nullptr, - [0b00100100] = nullptr, - [0b00100101] = nullptr, - [0b00100110] = nullptr, - [0b00100111] = nullptr, - [0b00101000] = nullptr, - [0b00101001] = nullptr, - [0b00101010] = nullptr, - [0b00101011] = nullptr, - [0b00101100] = nullptr, - [0b00101101] = nullptr, - [0b00101110] = nullptr, - [0b00101111] = nullptr, - [0b00110000] = nullptr, - [0b00110001] = nullptr, - [0b00110010] = nullptr, - [0b00110011] = nullptr, - [0b00110100] = nullptr, - [0b00110101] = nullptr, - [0b00110110] = nullptr, - [0b00110111] = nullptr, - [0b00111000] = nullptr, - [0b00111001] = nullptr, - [0b00111010] = nullptr, - [0b00111011] = nullptr, - [0b00111100] = nullptr, - [0b00111101] = nullptr, - [0b00111110] = nullptr, - [0b00111111] = nullptr, - [0b01000000] = nullptr, - [0b01000001] = nullptr, - [0b01000010] = nullptr, - [0b01000011] = nullptr, - [0b01000100] = nullptr, - [0b01000101] = nullptr, - [0b01000110] = nullptr, - [0b01000111] = nullptr, - [0b01001000] = TryDecodeFALIGNDATA, - [0b01001001] = nullptr, - [0b01001010] = nullptr, - [0b01001011] = nullptr, - [0b01001100] = TryDecodeBSHUFFLE, - [0b01001101] = nullptr, - [0b01001110] = nullptr, - [0b01001111] = nullptr, - [0b01010000] = nullptr, - [0b01010001] = TryDecodeFNADDS, - [0b01010010] = TryDecodeFNADDD, - [0b01010011] = nullptr, - [0b01010100] = nullptr, - [0b01010101] = nullptr, - [0b01010110] = nullptr, - [0b01010111] = nullptr, - [0b01011000] = nullptr, - [0b01011001] = nullptr, - [0b01011010] = nullptr, - [0b01011011] = nullptr, - [0b01011100] = nullptr, - [0b01011101] = nullptr, - [0b01011110] = nullptr, - [0b01011111] = nullptr, - [0b01100000] = TryDecodeFZEROD, - [0b01100001] = TryDecodeFZEROS, - [0b01100010] = TryDecodeFNORD, - [0b01100011] = nullptr, - [0b01100100] = nullptr, - [0b01100101] = nullptr, - [0b01100110] = nullptr, - [0b01100111] = TryDecodeFNORS, - [0b01101000] = nullptr, - [0b01101001] = nullptr, - [0b01101010] = nullptr, - [0b01101011] = nullptr, - [0b01101100] = TryDecodeFXORS, - [0b01101101] = TryDecodeFXORD, - [0b01101110] = TryDecodeFNANDD, - [0b01101111] = TryDecodeFNANDS, - [0b01110000] = TryDecodeFANDD, - [0b01110001] = TryDecodeFANDS, - [0b01110010] = TryDecodeFXNORD, - [0b01110011] = TryDecodeFXNORS, - [0b01110100] = nullptr, - [0b01110101] = nullptr, - [0b01110110] = nullptr, - [0b01110111] = nullptr, - [0b01111000] = nullptr, - [0b01111001] = nullptr, - [0b01111010] = nullptr, - [0b01111011] = nullptr, - [0b01111100] = TryDecodeFORD, - [0b01111101] = TryDecodeFORS, - [0b01111110] = TryDecodeFONED, - [0b01111111] = TryDecodeFONES, - [0b10000000] = nullptr, - [0b10000001] = nullptr, - [0b10000010] = nullptr, - [0b10000011] = nullptr, - [0b10000100] = nullptr, - [0b10000101] = nullptr, - [0b10000110] = nullptr, - [0b10000111] = nullptr, - [0b10001000] = nullptr, - [0b10001001] = nullptr, - [0b10001010] = nullptr, - [0b10001011] = nullptr, - [0b10001100] = nullptr, - [0b10001101] = nullptr, - [0b10001110] = nullptr, - [0b10001111] = nullptr, - [0b10010000] = nullptr, - [0b10010001] = nullptr, - [0b10010010] = nullptr, - [0b10010011] = nullptr, - [0b10010100] = nullptr, - [0b10010101] = nullptr, - [0b10010110] = nullptr, - [0b10010111] = nullptr, - [0b10011000] = nullptr, - [0b10011001] = nullptr, - [0b10011010] = nullptr, - [0b10011011] = nullptr, - [0b10011100] = nullptr, - [0b10011101] = nullptr, - [0b10011110] = nullptr, - [0b10011111] = nullptr, - [0b10100000] = nullptr, - [0b10100001] = nullptr, - [0b10100010] = nullptr, - [0b10100011] = nullptr, - [0b10100100] = nullptr, - [0b10100101] = nullptr, - [0b10100110] = nullptr, - [0b10100111] = nullptr, - [0b10101000] = nullptr, - [0b10101001] = nullptr, - [0b10101010] = nullptr, - [0b10101011] = nullptr, - [0b10101100] = nullptr, - [0b10101101] = nullptr, - [0b10101110] = nullptr, - [0b10101111] = nullptr, - [0b10110000] = nullptr, - [0b10110001] = nullptr, - [0b10110010] = nullptr, - [0b10110011] = nullptr, - [0b10110100] = nullptr, - [0b10110101] = nullptr, - [0b10110110] = nullptr, - [0b10110111] = nullptr, - [0b10111000] = nullptr, - [0b10111001] = nullptr, - [0b10111010] = nullptr, - [0b10111011] = nullptr, - [0b10111100] = nullptr, - [0b10111101] = nullptr, - [0b10111110] = nullptr, - [0b10111111] = nullptr, - [0b11000000] = nullptr, - [0b11000001] = nullptr, - [0b11000010] = nullptr, - [0b11000011] = nullptr, - [0b11000100] = nullptr, - [0b11000101] = nullptr, - [0b11000110] = nullptr, - [0b11000111] = nullptr, - [0b11001000] = nullptr, - [0b11001001] = nullptr, - [0b11001010] = nullptr, - [0b11001011] = nullptr, - [0b11001100] = nullptr, - [0b11001101] = nullptr, - [0b11001110] = nullptr, - [0b11001111] = nullptr, - [0b11010000] = nullptr, - [0b11010001] = nullptr, - [0b11010010] = nullptr, - [0b11010011] = nullptr, - [0b11010100] = nullptr, - [0b11010101] = nullptr, - [0b11010110] = nullptr, - [0b11010111] = nullptr, - [0b11011000] = nullptr, - [0b11011001] = nullptr, - [0b11011010] = nullptr, - [0b11011011] = nullptr, - [0b11011100] = nullptr, - [0b11011101] = nullptr, - [0b11011110] = nullptr, - [0b11011111] = nullptr, - [0b11100000] = nullptr, - [0b11100001] = nullptr, - [0b11100010] = nullptr, - [0b11100011] = nullptr, - [0b11100100] = nullptr, - [0b11100101] = nullptr, - [0b11100110] = nullptr, - [0b11100111] = nullptr, - [0b11101000] = nullptr, - [0b11101001] = nullptr, - [0b11101010] = nullptr, - [0b11101011] = nullptr, - [0b11101100] = nullptr, - [0b11101101] = nullptr, - [0b11101110] = nullptr, - [0b11101111] = nullptr, - [0b11110000] = nullptr, - [0b11110001] = nullptr, - [0b11110010] = nullptr, - [0b11110011] = nullptr, - [0b11110100] = nullptr, - [0b11110101] = nullptr, - [0b11110110] = nullptr, - [0b11110111] = nullptr, - [0b11111000] = nullptr, - [0b11111001] = nullptr, - [0b11111010] = nullptr, - [0b11111011] = nullptr, - [0b11111100] = nullptr, - [0b11111101] = nullptr, - [0b11111110] = nullptr, - [0b11111111] = nullptr, - }; + [0b00000000] = TryDecodeEDGE8cc, + [0b00000001] = nullptr, + [0b00000010] = nullptr, + [0b00000011] = nullptr, + [0b00000100] = nullptr, + [0b00000101] = nullptr, + [0b00000110] = nullptr, + [0b00000111] = nullptr, + [0b00001000] = nullptr, + [0b00001001] = nullptr, + [0b00001010] = nullptr, + [0b00001011] = nullptr, + [0b00001100] = nullptr, + [0b00001101] = nullptr, + [0b00001110] = nullptr, + [0b00001111] = nullptr, + [0b00010000] = nullptr, + [0b00010001] = nullptr, + [0b00010010] = nullptr, + [0b00010011] = nullptr, + [0b00010100] = nullptr, + [0b00010101] = nullptr, + [0b00010110] = nullptr, + [0b00010111] = nullptr, + [0b00011000] = TryDecodeALIGNADDRESS, + [0b00011001] = nullptr, + [0b00011010] = TryDecodeALIGNADDRESS_LITTLE, + [0b00011011] = nullptr, + [0b00011100] = nullptr, + [0b00011101] = nullptr, + [0b00011110] = nullptr, + [0b00011111] = nullptr, + [0b00100000] = nullptr, + [0b00100001] = nullptr, + [0b00100010] = nullptr, + [0b00100011] = nullptr, + [0b00100100] = nullptr, + [0b00100101] = nullptr, + [0b00100110] = nullptr, + [0b00100111] = nullptr, + [0b00101000] = nullptr, + [0b00101001] = nullptr, + [0b00101010] = nullptr, + [0b00101011] = nullptr, + [0b00101100] = nullptr, + [0b00101101] = nullptr, + [0b00101110] = nullptr, + [0b00101111] = nullptr, + [0b00110000] = nullptr, + [0b00110001] = nullptr, + [0b00110010] = nullptr, + [0b00110011] = nullptr, + [0b00110100] = nullptr, + [0b00110101] = nullptr, + [0b00110110] = nullptr, + [0b00110111] = nullptr, + [0b00111000] = nullptr, + [0b00111001] = nullptr, + [0b00111010] = nullptr, + [0b00111011] = nullptr, + [0b00111100] = nullptr, + [0b00111101] = nullptr, + [0b00111110] = nullptr, + [0b00111111] = nullptr, + [0b01000000] = nullptr, + [0b01000001] = nullptr, + [0b01000010] = nullptr, + [0b01000011] = nullptr, + [0b01000100] = nullptr, + [0b01000101] = nullptr, + [0b01000110] = nullptr, + [0b01000111] = nullptr, + [0b01001000] = TryDecodeFALIGNDATA, + [0b01001001] = nullptr, + [0b01001010] = nullptr, + [0b01001011] = nullptr, + [0b01001100] = TryDecodeBSHUFFLE, + [0b01001101] = nullptr, + [0b01001110] = nullptr, + [0b01001111] = nullptr, + [0b01010000] = nullptr, + [0b01010001] = TryDecodeFNADDS, + [0b01010010] = TryDecodeFNADDD, + [0b01010011] = nullptr, + [0b01010100] = nullptr, + [0b01010101] = nullptr, + [0b01010110] = nullptr, + [0b01010111] = nullptr, + [0b01011000] = nullptr, + [0b01011001] = nullptr, + [0b01011010] = nullptr, + [0b01011011] = nullptr, + [0b01011100] = nullptr, + [0b01011101] = nullptr, + [0b01011110] = nullptr, + [0b01011111] = nullptr, + [0b01100000] = TryDecodeFZEROD, + [0b01100001] = TryDecodeFZEROS, + [0b01100010] = TryDecodeFNORD, + [0b01100011] = nullptr, + [0b01100100] = nullptr, + [0b01100101] = nullptr, + [0b01100110] = nullptr, + [0b01100111] = TryDecodeFNORS, + [0b01101000] = nullptr, + [0b01101001] = nullptr, + [0b01101010] = nullptr, + [0b01101011] = nullptr, + [0b01101100] = TryDecodeFXORS, + [0b01101101] = TryDecodeFXORD, + [0b01101110] = TryDecodeFNANDD, + [0b01101111] = TryDecodeFNANDS, + [0b01110000] = TryDecodeFANDD, + [0b01110001] = TryDecodeFANDS, + [0b01110010] = TryDecodeFXNORD, + [0b01110011] = TryDecodeFXNORS, + [0b01110100] = nullptr, + [0b01110101] = nullptr, + [0b01110110] = nullptr, + [0b01110111] = nullptr, + [0b01111000] = nullptr, + [0b01111001] = nullptr, + [0b01111010] = nullptr, + [0b01111011] = nullptr, + [0b01111100] = TryDecodeFORD, + [0b01111101] = TryDecodeFORS, + [0b01111110] = TryDecodeFONED, + [0b01111111] = TryDecodeFONES, + [0b10000000] = nullptr, + [0b10000001] = nullptr, + [0b10000010] = nullptr, + [0b10000011] = nullptr, + [0b10000100] = nullptr, + [0b10000101] = nullptr, + [0b10000110] = nullptr, + [0b10000111] = nullptr, + [0b10001000] = nullptr, + [0b10001001] = nullptr, + [0b10001010] = nullptr, + [0b10001011] = nullptr, + [0b10001100] = nullptr, + [0b10001101] = nullptr, + [0b10001110] = nullptr, + [0b10001111] = nullptr, + [0b10010000] = nullptr, + [0b10010001] = nullptr, + [0b10010010] = nullptr, + [0b10010011] = nullptr, + [0b10010100] = nullptr, + [0b10010101] = nullptr, + [0b10010110] = nullptr, + [0b10010111] = nullptr, + [0b10011000] = nullptr, + [0b10011001] = nullptr, + [0b10011010] = nullptr, + [0b10011011] = nullptr, + [0b10011100] = nullptr, + [0b10011101] = nullptr, + [0b10011110] = nullptr, + [0b10011111] = nullptr, + [0b10100000] = nullptr, + [0b10100001] = nullptr, + [0b10100010] = nullptr, + [0b10100011] = nullptr, + [0b10100100] = nullptr, + [0b10100101] = nullptr, + [0b10100110] = nullptr, + [0b10100111] = nullptr, + [0b10101000] = nullptr, + [0b10101001] = nullptr, + [0b10101010] = nullptr, + [0b10101011] = nullptr, + [0b10101100] = nullptr, + [0b10101101] = nullptr, + [0b10101110] = nullptr, + [0b10101111] = nullptr, + [0b10110000] = nullptr, + [0b10110001] = nullptr, + [0b10110010] = nullptr, + [0b10110011] = nullptr, + [0b10110100] = nullptr, + [0b10110101] = nullptr, + [0b10110110] = nullptr, + [0b10110111] = nullptr, + [0b10111000] = nullptr, + [0b10111001] = nullptr, + [0b10111010] = nullptr, + [0b10111011] = nullptr, + [0b10111100] = nullptr, + [0b10111101] = nullptr, + [0b10111110] = nullptr, + [0b10111111] = nullptr, + [0b11000000] = nullptr, + [0b11000001] = nullptr, + [0b11000010] = nullptr, + [0b11000011] = nullptr, + [0b11000100] = nullptr, + [0b11000101] = nullptr, + [0b11000110] = nullptr, + [0b11000111] = nullptr, + [0b11001000] = nullptr, + [0b11001001] = nullptr, + [0b11001010] = nullptr, + [0b11001011] = nullptr, + [0b11001100] = nullptr, + [0b11001101] = nullptr, + [0b11001110] = nullptr, + [0b11001111] = nullptr, + [0b11010000] = nullptr, + [0b11010001] = nullptr, + [0b11010010] = nullptr, + [0b11010011] = nullptr, + [0b11010100] = nullptr, + [0b11010101] = nullptr, + [0b11010110] = nullptr, + [0b11010111] = nullptr, + [0b11011000] = nullptr, + [0b11011001] = nullptr, + [0b11011010] = nullptr, + [0b11011011] = nullptr, + [0b11011100] = nullptr, + [0b11011101] = nullptr, + [0b11011110] = nullptr, + [0b11011111] = nullptr, + [0b11100000] = nullptr, + [0b11100001] = nullptr, + [0b11100010] = nullptr, + [0b11100011] = nullptr, + [0b11100100] = nullptr, + [0b11100101] = nullptr, + [0b11100110] = nullptr, + [0b11100111] = nullptr, + [0b11101000] = nullptr, + [0b11101001] = nullptr, + [0b11101010] = nullptr, + [0b11101011] = nullptr, + [0b11101100] = nullptr, + [0b11101101] = nullptr, + [0b11101110] = nullptr, + [0b11101111] = nullptr, + [0b11110000] = nullptr, + [0b11110001] = nullptr, + [0b11110010] = nullptr, + [0b11110011] = nullptr, + [0b11110100] = nullptr, + [0b11110101] = nullptr, + [0b11110110] = nullptr, + [0b11110111] = nullptr, + [0b11111000] = nullptr, + [0b11111001] = nullptr, + [0b11111010] = nullptr, + [0b11111011] = nullptr, + [0b11111100] = nullptr, + [0b11111101] = nullptr, + [0b11111110] = nullptr, + [0b11111111] = nullptr, +}; static bool TryDecodeOpf54(Instruction &inst, uint32_t bits) { Format3b enc = {bits}; auto func = kop10_op354Level[enc.opf]; if (!func) { - LOG(ERROR) - << "Decoding IMPDEP1 with OP=10 op3=110110 opf=" << std::bitset<8>(enc.opf) - << " at "<< std::hex << inst.pc << std::dec; + LOG(ERROR) << "Decoding IMPDEP1 with OP=10 op3=110110 opf=" + << std::bitset<8>(enc.opf) << " at " << std::hex << inst.pc + << std::dec; return TryDecodeIMPDEP1(inst, bits); } return func(inst, bits); } #define DEFINE_TryDecode(ins) \ - static bool TryDecode ## ins(Instruction &inst, uint32_t bits) { \ + static bool TryDecode##ins(Instruction &inst, uint32_t bits) { \ return TryDecode_rs1_simm32_op_rs2_rd(inst, bits, #ins); \ } // Logical Operations -DEFINE_TryDecode(AND) -DEFINE_TryDecode(ANDcc) -DEFINE_TryDecode(ANDN) -DEFINE_TryDecode(ANDNcc) - -DEFINE_TryDecode(OR) -DEFINE_TryDecode(ORcc) -DEFINE_TryDecode(ORN) -DEFINE_TryDecode(ORNcc) - -DEFINE_TryDecode(XOR) -DEFINE_TryDecode(XORcc) -DEFINE_TryDecode(XNOR) -DEFINE_TryDecode(XNORcc) - -// Binary Operations -DEFINE_TryDecode(ADD) -DEFINE_TryDecode(ADDC) -DEFINE_TryDecode(ADDcc) -DEFINE_TryDecode(ADDCcc) - -DEFINE_TryDecode(SUB) -DEFINE_TryDecode(SUBC) -DEFINE_TryDecode(SUBcc) -DEFINE_TryDecode(SUBCcc) - -DEFINE_TryDecode(UMUL) -DEFINE_TryDecode(SMUL) -DEFINE_TryDecode(MULX) -DEFINE_TryDecode(UMULcc) -DEFINE_TryDecode(SMULcc) - -DEFINE_TryDecode(UDIV) -DEFINE_TryDecode(SDIV) -DEFINE_TryDecode(UDIVX) -DEFINE_TryDecode(SDIVX) -DEFINE_TryDecode(UDIVcc) -DEFINE_TryDecode(SDIVcc) +DEFINE_TryDecode(AND) DEFINE_TryDecode(ANDcc) DEFINE_TryDecode(ANDN) + DEFINE_TryDecode(ANDNcc) + + DEFINE_TryDecode(OR) DEFINE_TryDecode(ORcc) DEFINE_TryDecode(ORN) + DEFINE_TryDecode(ORNcc) + + DEFINE_TryDecode(XOR) DEFINE_TryDecode(XORcc) + DEFINE_TryDecode(XNOR) DEFINE_TryDecode(XNORcc) + + // Binary Operations + DEFINE_TryDecode(ADD) DEFINE_TryDecode(ADDC) DEFINE_TryDecode( + ADDcc) DEFINE_TryDecode(ADDCcc) + + DEFINE_TryDecode(SUB) DEFINE_TryDecode(SUBC) DEFINE_TryDecode( + SUBcc) DEFINE_TryDecode(SUBCcc) + + DEFINE_TryDecode(UMUL) DEFINE_TryDecode(SMUL) DEFINE_TryDecode(MULX) + DEFINE_TryDecode(UMULcc) DEFINE_TryDecode(SMULcc) + + DEFINE_TryDecode(UDIV) DEFINE_TryDecode(SDIV) + DEFINE_TryDecode(UDIVX) DEFINE_TryDecode(SDIVX) + DEFINE_TryDecode(UDIVcc) DEFINE_TryDecode(SDIVcc) #undef DEFINE_TryDecode #define DEFINE_TryDecode(ins) \ - static bool TryDecode ## ins(Instruction &inst, uint32_t bits) { \ + static bool TryDecode##ins(Instruction &inst, uint32_t bits) { \ if (!TryDecode_rs1_simm32_op_rs2_rd(inst, bits, #ins)) { \ return false; \ } \ @@ -2118,31 +1967,33 @@ DEFINE_TryDecode(SDIVcc) return true; \ } -DEFINE_TryDecode(TADDcc) -DEFINE_TryDecode(TSUBcc) -DEFINE_TryDecode(TADDccTV) -DEFINE_TryDecode(TSUBccTV) + DEFINE_TryDecode(TADDcc) + DEFINE_TryDecode(TSUBcc) + DEFINE_TryDecode(TADDccTV) + DEFINE_TryDecode(TSUBccTV) #undef DEFINE_TryDecode -static bool TryDecodeSWAP(Instruction &inst, uint32_t bits) { + static bool TryDecodeSWAP( + Instruction &inst, + uint32_t bits) { inst.is_atomic_read_modify_write = true; return TryDecode_rs1_simm32_op_rs2_rd(inst, bits, "SWAP"); } static bool TryDecode_Shift(Instruction &inst, uint32_t bits, - const char *iform_name, unsigned rs1_size=32) { + const char *iform_name, unsigned rs1_size = 32) { Format3ai0 enc_i0 = {bits}; Format3ai0 enc_i1 = {bits}; AddIntRegop(inst, enc_i0.rs1, rs1_size, Operand::kActionRead); if (enc_i1.i) { -/* if (enc_i1.asi) { + /* if (enc_i1.asi) { LOG(ERROR) << "TryDecode_Shift asi is null"; return false; // Reserved bits; must be zero. }*/ - AddImmop(inst, enc_i1.rs2 /* shcnt */, kAddressSize32, false); + AddImmop(inst, enc_i1.rs2 /* shcnt */, kAddressSize32, false); // Embed the masking of the shift in the operand. } else if (enc_i0.rs2) { @@ -2160,7 +2011,7 @@ static bool TryDecode_Shift(Instruction &inst, uint32_t bits, // Register `%g0` is `rs2`. } else { - AddImmop(inst, 0 /* shcnt */, kAddressSize32, false); + AddImmop(inst, 0 /* shcnt */, kAddressSize32, false); } AddIntRegop(inst, enc_i0.rd, kAddressSize, Operand::kActionWrite); @@ -2170,13 +2021,13 @@ static bool TryDecode_Shift(Instruction &inst, uint32_t bits, } static bool TryDecode_ShiftX(Instruction &inst, uint32_t bits, - const char *iform_name) { + const char *iform_name) { Format3ei0 enc_i0 = {bits}; Format3ei2 enc_i2 = {bits}; AddIntRegop(inst, enc_i0.rs1, kAddressSize, Operand::kActionRead); if (enc_i2.i) { - AddImmop(inst, enc_i2.shcnt64 /* shcnt */, kAddressSize, false); + AddImmop(inst, enc_i2.shcnt64 /* shcnt */, kAddressSize, false); // Embed the masking of the shift in the operand. } else if (enc_i0.rs2) { @@ -2194,7 +2045,7 @@ static bool TryDecode_ShiftX(Instruction &inst, uint32_t bits, // Register `%g0` is `rs2`. } else { - AddImmop(inst, 0 /* shcnt */, kAddressSize, false); + AddImmop(inst, 0 /* shcnt */, kAddressSize, false); } AddIntRegop(inst, enc_i0.rd, kAddressSize, Operand::kActionWrite); @@ -2230,15 +2081,12 @@ static bool TryDecodeSRA(Instruction &inst, uint32_t bits) { } } -enum class RegClass { - kInt, - kFP -}; +enum class RegClass { kInt, kFP }; -static bool TryDecode_Load( - Instruction &inst, uint32_t bits, const char *iform, - unsigned mem_size, unsigned reg_size, RegClass rclass=RegClass::kInt, - bool has_asi=false) { +static bool TryDecode_Load(Instruction &inst, uint32_t bits, const char *iform, + unsigned mem_size, unsigned reg_size, + RegClass rclass = RegClass::kInt, + bool has_asi = false) { Format3ai0 enc_i0 = {bits}; Format3ai1 enc_i1 = {bits}; inst.function = iform; @@ -2254,13 +2102,11 @@ static bool TryDecode_Load( } if (enc_i1.i) { - AddBasePlusOffsetMemop( - inst, Operand::kActionRead, mem_size, enc_i0.rs1, - 0, enc_i1.simm13); + AddBasePlusOffsetMemop(inst, Operand::kActionRead, mem_size, enc_i0.rs1, 0, + enc_i1.simm13); } else { - AddBasePlusOffsetMemop( - inst, Operand::kActionRead, mem_size, enc_i0.rs1, - enc_i0.rs2, 0); + AddBasePlusOffsetMemop(inst, Operand::kActionRead, mem_size, enc_i0.rs1, + enc_i0.rs2, 0); } if (RegClass::kInt == rclass) { @@ -2272,10 +2118,10 @@ static bool TryDecode_Load( return true; } -static bool TryDecode_Store( - Instruction &inst, uint32_t bits, const char *iform, - unsigned reg_size, unsigned mem_size, RegClass rclass=RegClass::kInt, - bool has_asi=false) { +static bool TryDecode_Store(Instruction &inst, uint32_t bits, const char *iform, + unsigned reg_size, unsigned mem_size, + RegClass rclass = RegClass::kInt, + bool has_asi = false) { Format3ai0 enc_i0 = {bits}; Format3ai1 enc_i1 = {bits}; inst.function = iform; @@ -2298,13 +2144,11 @@ static bool TryDecode_Store( } if (enc_i1.i) { - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, mem_size, enc_i0.rs1, - 0, enc_i1.simm13); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, mem_size, enc_i0.rs1, 0, + enc_i1.simm13); } else { - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, mem_size, enc_i0.rs1, - enc_i0.rs2, 0); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, mem_size, enc_i0.rs1, + enc_i0.rs2, 0); } return true; } @@ -2350,27 +2194,33 @@ static bool TryDecodeLDQF(Instruction &inst, uint32_t bits) { } static bool TryDecodeLDSBA(Instruction &inst, uint32_t bits) { - return TryDecode_Load(inst, bits, "LDSBA", 8, kAddressSize, RegClass::kInt, true); + return TryDecode_Load(inst, bits, "LDSBA", 8, kAddressSize, RegClass::kInt, + true); } static bool TryDecodeLDSHA(Instruction &inst, uint32_t bits) { - return TryDecode_Load(inst, bits, "LDSHA", 16, kAddressSize, RegClass::kInt, true); + return TryDecode_Load(inst, bits, "LDSHA", 16, kAddressSize, RegClass::kInt, + true); } static bool TryDecodeLDSWA(Instruction &inst, uint32_t bits) { - return TryDecode_Load(inst, bits, "LDSWA", 32, kAddressSize, RegClass::kInt, true); + return TryDecode_Load(inst, bits, "LDSWA", 32, kAddressSize, RegClass::kInt, + true); } static bool TryDecodeLDUBA(Instruction &inst, uint32_t bits) { - return TryDecode_Load(inst, bits, "LDUBA", 8, kAddressSize, RegClass::kInt, true); + return TryDecode_Load(inst, bits, "LDUBA", 8, kAddressSize, RegClass::kInt, + true); } static bool TryDecodeLDUHA(Instruction &inst, uint32_t bits) { - return TryDecode_Load(inst, bits, "LDUHA", 16, kAddressSize, RegClass::kInt, true); + return TryDecode_Load(inst, bits, "LDUHA", 16, kAddressSize, RegClass::kInt, + true); } static bool TryDecodeLDUWA(Instruction &inst, uint32_t bits) { - return TryDecode_Load(inst, bits, "LDUWA", 32, kAddressSize, RegClass::kInt, true); + return TryDecode_Load(inst, bits, "LDUWA", 32, kAddressSize, RegClass::kInt, + true); } static bool TryDecodeLDXA(Instruction &inst, uint32_t bits) { @@ -2399,13 +2249,11 @@ static bool TryDecodeLDSTUB(Instruction &inst, uint32_t bits) { // if i != 0 if (enc_i1.i) { - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, 8, enc_i0.rs1, - 0, enc_i1.simm13); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, 8, enc_i0.rs1, 0, + enc_i1.simm13); } else { - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, 8, enc_i0.rs1, - 0, enc_i0.rs2); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, 8, enc_i0.rs1, 0, + enc_i0.rs2); } AddIntRegop(inst, enc_i0.rd, kAddressSize, Operand::kActionWrite); @@ -2424,14 +2272,12 @@ static bool TryDecodeLDSTUBA(Instruction &inst, uint32_t bits) { // if i != 0 if (enc_i1.i) { AddDestRegop(inst, "ASI_REG", 8); - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, 8, enc_i0.rs1, - 0, enc_i1.simm13); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, 8, enc_i0.rs1, 0, + enc_i1.simm13); } else { AddImmop(inst, enc_i0.asi, 8, false); - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, 8, enc_i0.rs1, - 0, enc_i0.rs2); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, 8, enc_i0.rs1, 0, + enc_i0.rs2); } AddIntRegop(inst, enc_i0.rd, kAddressSize, Operand::kActionWrite); @@ -2443,28 +2289,19 @@ static bool TryDecodeLDFSR(Instruction &inst, uint32_t bits) { Format3ai1 enc_i1 = {bits}; if (enc_i1.i) { - AddBasePlusOffsetMemop( - inst, Operand::kActionRead, kAddressSize32, enc_i0.rs1, - 0, enc_i1.simm13); + AddBasePlusOffsetMemop(inst, Operand::kActionRead, kAddressSize32, + enc_i0.rs1, 0, enc_i1.simm13); } else { - AddBasePlusOffsetMemop( - inst, Operand::kActionRead, kAddressSize32, enc_i0.rs1, - enc_i0.rs2, 0); + AddBasePlusOffsetMemop(inst, Operand::kActionRead, kAddressSize32, + enc_i0.rs1, enc_i0.rs2, 0); } inst.category = Instruction::kCategoryNormal; - switch(enc_i0.rd) { - case 0: - inst.function = "LDFSR"; - break; - case 1: - inst.function = "LDXFSR"; - break; - case 3: - inst.function = "LDXEFSR"; - break; - default: - return false; + switch (enc_i0.rd) { + case 0: inst.function = "LDFSR"; break; + case 1: inst.function = "LDXFSR"; break; + case 3: inst.function = "LDXEFSR"; break; + default: return false; } return true; } @@ -2486,15 +2323,18 @@ static bool TryDecodeSTX(Instruction &inst, uint32_t bits) { } static bool TryDecodeSTBA(Instruction &inst, uint32_t bits) { - return TryDecode_Store(inst, bits, "STBA", kAddressSize, 8, RegClass::kInt, true); + return TryDecode_Store(inst, bits, "STBA", kAddressSize, 8, RegClass::kInt, + true); } static bool TryDecodeSTHA(Instruction &inst, uint32_t bits) { - return TryDecode_Store(inst, bits, "STHA", kAddressSize, 16, RegClass::kInt, true); + return TryDecode_Store(inst, bits, "STHA", kAddressSize, 16, RegClass::kInt, + true); } static bool TryDecodeSTWA(Instruction &inst, uint32_t bits) { - return TryDecode_Store(inst, bits, "STWA", kAddressSize, 32, RegClass::kInt, true); + return TryDecode_Store(inst, bits, "STWA", kAddressSize, 32, RegClass::kInt, + true); } static bool TryDecodeSTXA(Instruction &inst, uint32_t bits) { @@ -2530,28 +2370,19 @@ static bool TryDecodeSTFSR(Instruction &inst, uint32_t bits) { Format3ai1 enc_i1 = {bits}; if (enc_i1.i) { - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, kAddressSize32, enc_i0.rs1, - 0, enc_i1.simm13); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, kAddressSize32, + enc_i0.rs1, 0, enc_i1.simm13); } else { - AddBasePlusOffsetMemop( - inst, Operand::kActionWrite, kAddressSize32, enc_i0.rs1, - enc_i0.rs2, 0); + AddBasePlusOffsetMemop(inst, Operand::kActionWrite, kAddressSize32, + enc_i0.rs1, enc_i0.rs2, 0); } inst.category = Instruction::kCategoryNormal; - switch(enc_i0.rd) { - case 0: - inst.function = "STFSR"; - break; - case 1: - inst.function = "STXFSR"; - break; - case 3: - inst.function = "STXEFSR"; - break; - default: - return false; + switch (enc_i0.rd) { + case 0: inst.function = "STFSR"; break; + case 1: inst.function = "STXFSR"; break; + case 3: inst.function = "STXEFSR"; break; + default: return false; } return true; } @@ -2565,13 +2396,13 @@ static bool TryDecodeMEMBAR_RDasr(Instruction &inst, uint32_t bits) { inst.function = "MEMBAR"; inst.category = Instruction::kCategoryNormal; - AddImmop(inst, enc.mmask /* mmask */, kAddressSize32, false); - AddImmop(inst, enc.cmask /* cmask */, kAddressSize32, false); + AddImmop(inst, enc.mmask /* mmask */, kAddressSize32, false); + AddImmop(inst, enc.cmask /* cmask */, kAddressSize32, false); return true; } -static bool TryDecode_rs1_imm_asi_op_rs2_rd( - Instruction &inst, uint32_t bits, const char *iform) { +static bool TryDecode_rs1_imm_asi_op_rs2_rd(Instruction &inst, uint32_t bits, + const char *iform) { Format3ai0 enc_i0 = {bits}; inst.function = iform; @@ -2604,9 +2435,8 @@ static bool TryDecodeFLUSH(Instruction &inst, uint32_t bits) { inst.function = "FLUSH"; inst.category = Instruction::kCategoryNormal; if (enc_i0.i == 0) { - AddBasePlusOffsetMemop( - inst, Operand::kActionRead, kAddressSize, enc_i0.rs1, - enc_i0.rs2, 0); + AddBasePlusOffsetMemop(inst, Operand::kActionRead, kAddressSize, enc_i0.rs1, + enc_i0.rs2, 0); } return true; } @@ -2619,15 +2449,13 @@ static bool TryDecodePREFETCH(Instruction &inst, uint32_t bits) { inst.category = Instruction::kCategoryNormal; if (enc_i0.i == 0) { - AddBasePlusOffsetMemop( - inst, Operand::kActionRead, kAddressSize, enc_i0.rs1, - enc_i0.rs2, 0); + AddBasePlusOffsetMemop(inst, Operand::kActionRead, kAddressSize, enc_i0.rs1, + enc_i0.rs2, 0); } else { - AddBasePlusOffsetMemop( - inst, Operand::kActionRead, kAddressSize32, enc_i0.rs1, - 0, enc_i1.simm13); + AddBasePlusOffsetMemop(inst, Operand::kActionRead, kAddressSize32, + enc_i0.rs1, 0, enc_i1.simm13); } - AddImmop(inst, enc_i0.rd /* fcn */, kAddressSize32, false); + AddImmop(inst, enc_i0.rd /* fcn */, kAddressSize32, false); return true; } @@ -2641,164 +2469,126 @@ static bool TryDecodePREFETCHA(Instruction &inst, uint32_t bits) { if (enc_i1.i) { AddDestRegop(inst, "ASI_REG", 8); - AddBasePlusOffsetMemop( - inst, Operand::kActionRead, kAddressSize32, enc_i0.rs1, - 0, enc_i1.simm13); + AddBasePlusOffsetMemop(inst, Operand::kActionRead, kAddressSize32, + enc_i0.rs1, 0, enc_i1.simm13); } else { AddImmop(inst, enc_i0.asi, 8, false); - AddBasePlusOffsetMemop( - inst, Operand::kActionRead, kAddressSize, enc_i0.rs1, - enc_i0.rs2, 0); + AddBasePlusOffsetMemop(inst, Operand::kActionRead, kAddressSize, enc_i0.rs1, + enc_i0.rs2, 0); } - AddImmop(inst, enc_i0.rd /* fcn */, kAddressSize32, false); + AddImmop(inst, enc_i0.rd /* fcn */, kAddressSize32, false); return true; } static bool (*const kop00_op2Level[1u << 3])(Instruction &, uint32_t) = { - [0b000] = TryDecodeUNIMP, - [0b001] = TryDecodeBPcc, - [0b010] = TryDecodeBcc, - [0b011] = TryDecodeBPr, - [0b100] = TryDecodeSETHI, - [0b101] = TryDecodeFBPcc, - [0b110] = TryDecodeFBcc, - [0b111] = nullptr, + [0b000] = TryDecodeUNIMP, [0b001] = TryDecodeBPcc, + [0b010] = TryDecodeBcc, [0b011] = TryDecodeBPr, + [0b100] = TryDecodeSETHI, [0b101] = TryDecodeFBPcc, + [0b110] = TryDecodeFBcc, [0b111] = nullptr, }; static bool (*const kop10_op3Level[1U << 6])(Instruction &, uint32_t) = { - [0b000000] = TryDecodeADD, - [0b000001] = TryDecodeAND, - [0b000010] = TryDecodeOR, - [0b000011] = TryDecodeXOR, - [0b000100] = TryDecodeSUB, - [0b000101] = TryDecodeANDN, - [0b000110] = TryDecodeORN, - [0b000111] = TryDecodeXNOR, - [0b001000] = TryDecodeADDC, - [0b001001] = TryDecodeMULX, - [0b001010] = TryDecodeUMUL, - [0b001011] = TryDecodeSMUL, - [0b001100] = TryDecodeSUBC, - [0b001101] = TryDecodeUDIVX, - [0b001110] = TryDecodeUDIV, - [0b001111] = TryDecodeSDIV, - [0b010000] = TryDecodeADDcc, - [0b010001] = TryDecodeANDcc, - [0b010010] = TryDecodeORcc, - [0b010011] = TryDecodeXORcc, - [0b010100] = TryDecodeSUBcc, - [0b010101] = TryDecodeANDNcc, - [0b010110] = TryDecodeORNcc, - [0b010111] = TryDecodeXNORcc, - [0b011000] = TryDecodeADDCcc, - [0b011001] = nullptr, - [0b011010] = TryDecodeUMULcc, - [0b011011] = TryDecodeSMULcc, - [0b011100] = TryDecodeSUBCcc, - [0b011101] = nullptr, - [0b011110] = TryDecodeUDIVcc, - [0b011111] = TryDecodeSDIVcc, - [0b100000] = TryDecodeTADDcc, - [0b100001] = TryDecodeTSUBcc, - [0b100010] = TryDecodeTADDccTV, - [0b100011] = TryDecodeTSUBccTV, - [0b100100] = nullptr, - [0b100101] = TryDecodeSLL, - [0b100110] = TryDecodeSRL, - [0b100111] = TryDecodeSRA, - [0b101000] = TryDecodeMEMBAR_RDasr, - [0b101001] = nullptr, - [0b101010] = TryDecodeRDPr, - [0b101011] = TryDecodeFLUSHW, - [0b101100] = TryDecodeMOVcc, - [0b101101] = TryDecodeSDIVX, - [0b101110] = nullptr, - [0b101111] = TryDecodeMOVr, - [0b110000] = TryDecodeWRasr, - [0b110001] = nullptr, - [0b110010] = nullptr, - [0b110011] = nullptr, - [0b110100] = TryDecodeOpf52, - [0b110101] = TryDecodeFCMP_FMOV, - [0b110110] = TryDecodeOpf54, - [0b110111] = TryDecodeIMPDEP2, - [0b111000] = TryDecodeJMPL, - [0b111001] = TryDecodeRETURN, - [0b111010] = TryDecodeTcc, - [0b111011] = TryDecodeFLUSH, - [0b111100] = TryDecodeSave, - [0b111101] = TryDecodeRestore, - [0b111110] = nullptr, - [0b111111] = nullptr, + [0b000000] = TryDecodeADD, + [0b000001] = TryDecodeAND, + [0b000010] = TryDecodeOR, + [0b000011] = TryDecodeXOR, + [0b000100] = TryDecodeSUB, + [0b000101] = TryDecodeANDN, + [0b000110] = TryDecodeORN, + [0b000111] = TryDecodeXNOR, + [0b001000] = TryDecodeADDC, + [0b001001] = TryDecodeMULX, + [0b001010] = TryDecodeUMUL, + [0b001011] = TryDecodeSMUL, + [0b001100] = TryDecodeSUBC, + [0b001101] = TryDecodeUDIVX, + [0b001110] = TryDecodeUDIV, + [0b001111] = TryDecodeSDIV, + [0b010000] = TryDecodeADDcc, + [0b010001] = TryDecodeANDcc, + [0b010010] = TryDecodeORcc, + [0b010011] = TryDecodeXORcc, + [0b010100] = TryDecodeSUBcc, + [0b010101] = TryDecodeANDNcc, + [0b010110] = TryDecodeORNcc, + [0b010111] = TryDecodeXNORcc, + [0b011000] = TryDecodeADDCcc, + [0b011001] = nullptr, + [0b011010] = TryDecodeUMULcc, + [0b011011] = TryDecodeSMULcc, + [0b011100] = TryDecodeSUBCcc, + [0b011101] = nullptr, + [0b011110] = TryDecodeUDIVcc, + [0b011111] = TryDecodeSDIVcc, + [0b100000] = TryDecodeTADDcc, + [0b100001] = TryDecodeTSUBcc, + [0b100010] = TryDecodeTADDccTV, + [0b100011] = TryDecodeTSUBccTV, + [0b100100] = nullptr, + [0b100101] = TryDecodeSLL, + [0b100110] = TryDecodeSRL, + [0b100111] = TryDecodeSRA, + [0b101000] = TryDecodeMEMBAR_RDasr, + [0b101001] = nullptr, + [0b101010] = TryDecodeRDPr, + [0b101011] = TryDecodeFLUSHW, + [0b101100] = TryDecodeMOVcc, + [0b101101] = TryDecodeSDIVX, + [0b101110] = nullptr, + [0b101111] = TryDecodeMOVr, + [0b110000] = TryDecodeWRasr, + [0b110001] = nullptr, + [0b110010] = nullptr, + [0b110011] = nullptr, + [0b110100] = TryDecodeOpf52, + [0b110101] = TryDecodeFCMP_FMOV, + [0b110110] = TryDecodeOpf54, + [0b110111] = TryDecodeIMPDEP2, + [0b111000] = TryDecodeJMPL, + [0b111001] = TryDecodeRETURN, + [0b111010] = TryDecodeTcc, + [0b111011] = TryDecodeFLUSH, + [0b111100] = TryDecodeSave, + [0b111101] = TryDecodeRestore, + [0b111110] = nullptr, + [0b111111] = nullptr, }; static bool (*const kop11_op3Level[1u << 6])(Instruction &, uint32_t) = { - [0b000000] = TryDecodeLDUW, - [0b000001] = TryDecodeLDUB, - [0b000010] = TryDecodeLDUH, - [0b000011] = nullptr, - [0b000100] = TryDecodeSTW, - [0b000101] = TryDecodeSTB, - [0b000110] = TryDecodeSTH, - [0b000111] = nullptr, - [0b001000] = TryDecodeLDSW, - [0b001001] = TryDecodeLDSB, - [0b001010] = TryDecodeLDSH, - [0b001011] = TryDecodeLDX, - [0b001100] = nullptr, - [0b001101] = TryDecodeLDSTUB, - [0b001110] = TryDecodeSTX, - [0b001111] = TryDecodeSWAP, - [0b010000] = TryDecodeLDUWA, - [0b010001] = TryDecodeLDUBA, - [0b010010] = TryDecodeLDUHA, - [0b010011] = nullptr, - [0b010100] = TryDecodeSTWA, - [0b010101] = TryDecodeSTBA, - [0b010110] = TryDecodeSTHA, - [0b010111] = nullptr, - [0b011000] = TryDecodeLDSWA, - [0b011001] = TryDecodeLDSBA, - [0b011010] = TryDecodeLDSHA, - [0b011011] = TryDecodeLDXA, - [0b011100] = nullptr, - [0b011101] = TryDecodeLDSTUBA, - [0b011110] = TryDecodeSTXA, - [0b011111] = nullptr, - [0b100000] = TryDecodeLDF, - [0b100001] = TryDecodeLDFSR, - [0b100010] = TryDecodeLDQF, - [0b100011] = TryDecodeLDDF, - [0b100100] = TryDecodeSTF, - [0b100101] = TryDecodeSTFSR, - [0b100110] = TryDecodeSTQF, - [0b100111] = TryDecodeSTDF, - [0b101000] = nullptr, - [0b101001] = nullptr, - [0b101010] = nullptr, - [0b101011] = nullptr, - [0b101100] = nullptr, - [0b101101] = TryDecodePREFETCH, - [0b101110] = nullptr, - [0b101111] = nullptr, - [0b110000] = TryDecodeLDFA, - [0b110001] = nullptr, - [0b110010] = TryDecodeLDQFA, - [0b110011] = TryDecodeLDDFA, - [0b110100] = TryDecodeSTFA, - [0b110101] = nullptr, - [0b110110] = TryDecodeSTQFA, - [0b110111] = TryDecodeSTDFA, - [0b111000] = nullptr, - [0b111001] = nullptr, - [0b111010] = nullptr, - [0b111011] = nullptr, - [0b111100] = TryDecodeCASA, - [0b111101] = TryDecodePREFETCHA, - [0b111110] = TryDecodeCASXA, - [0b111111] = nullptr, + [0b000000] = TryDecodeLDUW, [0b000001] = TryDecodeLDUB, + [0b000010] = TryDecodeLDUH, [0b000011] = nullptr, + [0b000100] = TryDecodeSTW, [0b000101] = TryDecodeSTB, + [0b000110] = TryDecodeSTH, [0b000111] = nullptr, + [0b001000] = TryDecodeLDSW, [0b001001] = TryDecodeLDSB, + [0b001010] = TryDecodeLDSH, [0b001011] = TryDecodeLDX, + [0b001100] = nullptr, [0b001101] = TryDecodeLDSTUB, + [0b001110] = TryDecodeSTX, [0b001111] = TryDecodeSWAP, + [0b010000] = TryDecodeLDUWA, [0b010001] = TryDecodeLDUBA, + [0b010010] = TryDecodeLDUHA, [0b010011] = nullptr, + [0b010100] = TryDecodeSTWA, [0b010101] = TryDecodeSTBA, + [0b010110] = TryDecodeSTHA, [0b010111] = nullptr, + [0b011000] = TryDecodeLDSWA, [0b011001] = TryDecodeLDSBA, + [0b011010] = TryDecodeLDSHA, [0b011011] = TryDecodeLDXA, + [0b011100] = nullptr, [0b011101] = TryDecodeLDSTUBA, + [0b011110] = TryDecodeSTXA, [0b011111] = nullptr, + [0b100000] = TryDecodeLDF, [0b100001] = TryDecodeLDFSR, + [0b100010] = TryDecodeLDQF, [0b100011] = TryDecodeLDDF, + [0b100100] = TryDecodeSTF, [0b100101] = TryDecodeSTFSR, + [0b100110] = TryDecodeSTQF, [0b100111] = TryDecodeSTDF, + [0b101000] = nullptr, [0b101001] = nullptr, + [0b101010] = nullptr, [0b101011] = nullptr, + [0b101100] = nullptr, [0b101101] = TryDecodePREFETCH, + [0b101110] = nullptr, [0b101111] = nullptr, + [0b110000] = TryDecodeLDFA, [0b110001] = nullptr, + [0b110010] = TryDecodeLDQFA, [0b110011] = TryDecodeLDDFA, + [0b110100] = TryDecodeSTFA, [0b110101] = nullptr, + [0b110110] = TryDecodeSTQFA, [0b110111] = TryDecodeSTDFA, + [0b111000] = nullptr, [0b111001] = nullptr, + [0b111010] = nullptr, [0b111011] = nullptr, + [0b111100] = TryDecodeCASA, [0b111101] = TryDecodePREFETCHA, + [0b111110] = TryDecodeCASXA, [0b111111] = nullptr, }; // SETHI, Branches, and ILLTRAP @@ -2806,8 +2596,7 @@ static bool TryDecode_op00(Instruction &inst, uint32_t bits) { auto index = (bits >> 22u) & 0x7u; auto func = kop00_op2Level[index]; if (!func) { - LOG(ERROR) - << "OP=00 op2=" << std::bitset<3>(index); + LOG(ERROR) << "OP=00 op2=" << std::bitset<3>(index); return false; } return func(inst, bits); @@ -2822,8 +2611,7 @@ static bool TryDecode_op10(Instruction &inst, uint32_t bits) { auto index = (bits >> 19u) & 0x3Fu; auto func = kop10_op3Level[index]; if (!func) { - LOG(ERROR) - << "OP=10 op3=" << std::bitset<6>(index); + LOG(ERROR) << "OP=10 op3=" << std::bitset<6>(index); return false; } return func(inst, bits); @@ -2833,19 +2621,14 @@ static bool TryDecode_op11(Instruction &inst, uint32_t bits) { auto index = (bits >> 19u) & 0x3Fu; auto func = kop11_op3Level[index]; if (!func) { - LOG(ERROR) - << "OP=11 op3=" << std::bitset<6>(index); + LOG(ERROR) << "OP=11 op3=" << std::bitset<6>(index); return false; } return func(inst, bits); } static bool (*const kopLevel[])(Instruction &, uint32_t) = { - TryDecode_op00, - TryDecode_op01, - TryDecode_op10, - TryDecode_op11 -}; + TryDecode_op00, TryDecode_op01, TryDecode_op10, TryDecode_op11}; static uint32_t BytesToBits(const uint8_t *bytes) { uint32_t bits = 0; @@ -2856,7 +2639,7 @@ static uint32_t BytesToBits(const uint8_t *bytes) { return bits; } -} +} // namespace bool TryDecode(Instruction &inst) { const auto num_bytes = inst.bytes.size(); @@ -2869,9 +2652,8 @@ bool TryDecode(Instruction &inst) { } else if (num_bytes == 8) { if (inst.in_delay_slot) { - LOG(WARNING) - << "Decoding 8-byte pseudo-op at " << std::hex << inst.pc << std::dec - << " in delay slot; ignoring second four bytes"; + LOG(WARNING) << "Decoding 8-byte pseudo-op at " << std::hex << inst.pc + << std::dec << " in delay slot; ignoring second four bytes"; inst.bytes.resize(4); inst.next_pc = inst.pc + 4; return TryDecode(inst); @@ -2891,7 +2673,7 @@ bool TryDecode(Instruction &inst) { const auto bits2_op3 = (bits2 >> 19u) & 0x3Fu; if (bits2_op == 0b10 && bits2_op3 == 0b000010) { // OR. ret = TryDecodeSET_SETHI_OR(inst, bits1, bits2); - } else if (bits2_op == 0b10 && bits2_op3 == 0b000000) { // ADD + } else if (bits2_op == 0b10 && bits2_op3 == 0b000000) { // ADD ret = TryDecodeSET_SETHI_ADD(inst, bits1, bits2); } } @@ -2901,8 +2683,8 @@ bool TryDecode(Instruction &inst) { inst.next_pc = inst.pc + 4; ret = TryDecode(inst); - LOG_IF(ERROR, !ret) - << "Unsupported 8-byte instruction: " << inst.Serialize(); + LOG_IF(ERROR, !ret) << "Unsupported 8-byte instruction: " + << inst.Serialize(); } return ret; diff --git a/lib/Arch/SPARC64/Runtime/Instructions.cpp b/lib/Arch/SPARC64/Runtime/Instructions.cpp index ed5d81f92..f1b70eb5a 100644 --- a/lib/Arch/SPARC64/Runtime/Instructions.cpp +++ b/lib/Arch/SPARC64/Runtime/Instructions.cpp @@ -24,111 +24,111 @@ #include "remill/Arch/SPARC64/Runtime/State.h" #include "remill/Arch/SPARC64/Runtime/Types.h" -#define REG_PC state.pc.aword -#define REG_NPC state.next_pc.aword -#define REG_SP state.gpr.o6.aword -#define REG_FP state.gpr.i6.aword - -#define REG_G0 state.gpr.g0.aword -#define REG_G1 state.gpr.g1.aword -#define REG_G7 state.gpr.g7.aword // Thread local pointer - -#define REG_L0 state.gpr.l0.aword -#define REG_L1 state.gpr.l1.aword -#define REG_L2 state.gpr.l2.aword -#define REG_L3 state.gpr.l3.aword -#define REG_L4 state.gpr.l4.aword -#define REG_L5 state.gpr.l5.aword -#define REG_L6 state.gpr.l6.aword -#define REG_L7 state.gpr.l7.aword - -#define REG_I0 state.gpr.i0.aword -#define REG_I1 state.gpr.i1.aword -#define REG_I2 state.gpr.i2.aword -#define REG_I3 state.gpr.i3.aword -#define REG_I4 state.gpr.i4.aword -#define REG_I5 state.gpr.i5.aword -#define REG_I6 state.gpr.i6.aword -#define REG_I7 state.gpr.i7.aword - -#define REG_O0 state.gpr.o0.aword -#define REG_O1 state.gpr.o1.aword -#define REG_O2 state.gpr.o2.aword -#define REG_O3 state.gpr.o3.aword -#define REG_O4 state.gpr.o4.aword -#define REG_O5 state.gpr.o5.aword -#define REG_O6 state.gpr.o6.aword -#define REG_O7 state.gpr.o7.aword - -#define REG_F0 state.fpreg.v[0].floats.elems[0] -#define REG_F1 state.fpreg.v[0].floats.elems[1] -#define REG_F2 state.fpreg.v[0].floats.elems[2] -#define REG_F3 state.fpreg.v[0].floats.elems[3] - -#define REG_D0 state.fpreg.v[0].doubles.elems[0] -#define REG_D2 state.fpreg.v[0].doubles.elems[1] +#define REG_PC state.pc.aword +#define REG_NPC state.next_pc.aword +#define REG_SP state.gpr.o6.aword +#define REG_FP state.gpr.i6.aword + +#define REG_G0 state.gpr.g0.aword +#define REG_G1 state.gpr.g1.aword +#define REG_G7 state.gpr.g7.aword // Thread local pointer + +#define REG_L0 state.gpr.l0.aword +#define REG_L1 state.gpr.l1.aword +#define REG_L2 state.gpr.l2.aword +#define REG_L3 state.gpr.l3.aword +#define REG_L4 state.gpr.l4.aword +#define REG_L5 state.gpr.l5.aword +#define REG_L6 state.gpr.l6.aword +#define REG_L7 state.gpr.l7.aword + +#define REG_I0 state.gpr.i0.aword +#define REG_I1 state.gpr.i1.aword +#define REG_I2 state.gpr.i2.aword +#define REG_I3 state.gpr.i3.aword +#define REG_I4 state.gpr.i4.aword +#define REG_I5 state.gpr.i5.aword +#define REG_I6 state.gpr.i6.aword +#define REG_I7 state.gpr.i7.aword + +#define REG_O0 state.gpr.o0.aword +#define REG_O1 state.gpr.o1.aword +#define REG_O2 state.gpr.o2.aword +#define REG_O3 state.gpr.o3.aword +#define REG_O4 state.gpr.o4.aword +#define REG_O5 state.gpr.o5.aword +#define REG_O6 state.gpr.o6.aword +#define REG_O7 state.gpr.o7.aword + +#define REG_F0 state.fpreg.v[0].floats.elems[0] +#define REG_F1 state.fpreg.v[0].floats.elems[1] +#define REG_F2 state.fpreg.v[0].floats.elems[2] +#define REG_F3 state.fpreg.v[0].floats.elems[3] + +#define REG_D0 state.fpreg.v[0].doubles.elems[0] +#define REG_D2 state.fpreg.v[0].doubles.elems[1] // GSR Register -#define GSR_ALIGN state.asr.gsr.align -#define GSR_MASK state.asr.gsr.mask - -#define REG_Y state.asr.yreg.aword - -#define FLAG_ICC_CF state.asr.ccr.icc.c -#define FLAG_ICC_VF state.asr.ccr.icc.v -#define FLAG_ICC_ZF state.asr.ccr.icc.z -#define FLAG_ICC_NF state.asr.ccr.icc.n - -#define FLAG_XCC_CF state.asr.ccr.xcc.c -#define FLAG_XCC_VF state.asr.ccr.xcc.v -#define FLAG_XCC_ZF state.asr.ccr.xcc.z -#define FLAG_XCC_NF state.asr.ccr.xcc.n - -#define REG_ICC state.asr.ccr.icc.flat -#define REG_XCC state.asr.ccr.xcc.flat -#define REG_CCC state.csr.ccc - -#define FSR_FCC_0 state.fsr.fcc0 -#define FSR_FCC_1 state.fsr.fcc1 -#define FSR_FCC_2 state.fsr.fcc2 -#define FSR_FCC_4 state.fsr.fcc4 - -#define FSR_CEXC state.fsr.cexc -#define FSR_FTT state.fsr.ftt -#define FSR_RD state.fsr.rd - -#define PSR_TPC state.psr.tpc -#define PSR_TNPC state.psr.tnpc -#define PSR_TSTATE state.psr.tstate -#define PSR_TT state.psr.tt -#define PSR_TBA state.psr.tba -#define PSR_PSTATE state.psr.pstate -#define PSR_TL state.psr.tl -#define PSR_PIL state.psr.pil -#define PSR_WSTATE state.psr.wstate -#define PSR_CWP state.psr.cwp -#define PSR_CANSAVE state.psr.cansave -#define PSR_CANRESTORE state.psr.canrestore -#define PSR_CLEANWIN state.psr.cleanwin -#define PSR_OTHERWIN state.psr.otherwin -#define PSR_GL state.psr.gl - -#define ASR_Y state.asr.yreg.aword -#define ASR_ASI state.asr.asi_flat -#define ASR_FPRS state.asr.fprs_flat -#define ASR_GSR state.asr.gsr.flat -#define ASR_SOFTINT state.asr.softint -#define ASR_STICK_CMPR state.asr.stick_cmpr -#define ASR_PAUSE state.asr.pause - -#define HYPER_CALL state.hyper_call -#define INTERRUPT_VECTOR state.hyper_call_vector -#define HYPER_CALL_VECTOR state.hyper_call_vector +#define GSR_ALIGN state.asr.gsr.align +#define GSR_MASK state.asr.gsr.mask + +#define REG_Y state.asr.yreg.aword + +#define FLAG_ICC_CF state.asr.ccr.icc.c +#define FLAG_ICC_VF state.asr.ccr.icc.v +#define FLAG_ICC_ZF state.asr.ccr.icc.z +#define FLAG_ICC_NF state.asr.ccr.icc.n + +#define FLAG_XCC_CF state.asr.ccr.xcc.c +#define FLAG_XCC_VF state.asr.ccr.xcc.v +#define FLAG_XCC_ZF state.asr.ccr.xcc.z +#define FLAG_XCC_NF state.asr.ccr.xcc.n + +#define REG_ICC state.asr.ccr.icc.flat +#define REG_XCC state.asr.ccr.xcc.flat +#define REG_CCC state.csr.ccc + +#define FSR_FCC_0 state.fsr.fcc0 +#define FSR_FCC_1 state.fsr.fcc1 +#define FSR_FCC_2 state.fsr.fcc2 +#define FSR_FCC_4 state.fsr.fcc4 + +#define FSR_CEXC state.fsr.cexc +#define FSR_FTT state.fsr.ftt +#define FSR_RD state.fsr.rd + +#define PSR_TPC state.psr.tpc +#define PSR_TNPC state.psr.tnpc +#define PSR_TSTATE state.psr.tstate +#define PSR_TT state.psr.tt +#define PSR_TBA state.psr.tba +#define PSR_PSTATE state.psr.pstate +#define PSR_TL state.psr.tl +#define PSR_PIL state.psr.pil +#define PSR_WSTATE state.psr.wstate +#define PSR_CWP state.psr.cwp +#define PSR_CANSAVE state.psr.cansave +#define PSR_CANRESTORE state.psr.canrestore +#define PSR_CLEANWIN state.psr.cleanwin +#define PSR_OTHERWIN state.psr.otherwin +#define PSR_GL state.psr.gl + +#define ASR_Y state.asr.yreg.aword +#define ASR_ASI state.asr.asi_flat +#define ASR_FPRS state.asr.fprs_flat +#define ASR_GSR state.asr.gsr.flat +#define ASR_SOFTINT state.asr.softint +#define ASR_STICK_CMPR state.asr.stick_cmpr +#define ASR_PAUSE state.asr.pause + +#define HYPER_CALL state.hyper_call +#define INTERRUPT_VECTOR state.hyper_call_vector +#define HYPER_CALL_VECTOR state.hyper_call_vector #if ADDRESS_SIZE_BITS == 64 -# define SPARC_STACKBIAS 0 +# define SPARC_STACKBIAS 0 #else -# define SPARC_STACKBIAS 0 +# define SPARC_STACKBIAS 0 #endif namespace { @@ -136,7 +136,9 @@ namespace { // Takes the place of an unsupported instruction. DEF_SEM(HandleUnsupported) { return __remill_sync_hyper_call( - state, memory, SyncHyperCall::IF_32BIT_ELSE(kSPARC32EmulateInstruction, kSPARC64EmulateInstruction)); + state, memory, + SyncHyperCall::IF_32BIT_ELSE(kSPARC32EmulateInstruction, + kSPARC64EmulateInstruction)); } // Takes the place of an invalid instruction. @@ -145,12 +147,13 @@ DEF_SEM(HandleInvalidInstruction) { return memory; } -DEF_HELPER(SAVE_WINDOW, RegisterWindow *window, RegisterWindow *&prev_window) -> void { +DEF_HELPER(SAVE_WINDOW, RegisterWindow *window, RegisterWindow *&prev_window) + ->void { -// TODO(pag): These two lines should be uncommented for correctness, but then -// they don't result in as nice bitcode in McSema :-( -// window->prev_window = state.window; -// state.window = window; + // TODO(pag): These two lines should be uncommented for correctness, but then + // they don't result in as nice bitcode in McSema :-( + // window->prev_window = state.window; + // state.window = window; prev_window = window; @@ -183,18 +186,18 @@ DEF_HELPER(SAVE_WINDOW, RegisterWindow *window, RegisterWindow *&prev_window) -> Write(REG_I7, REG_O7); } -DEF_HELPER(RESTORE_WINDOW, RegisterWindow *&prev_window) -> void { +DEF_HELPER(RESTORE_WINDOW, RegisterWindow *&prev_window)->void { const auto window = prev_window ? prev_window : state.window; if (!window) { - memory = __remill_sync_hyper_call( - state, memory, SyncHyperCall::kSPARCWindowUnderflow); + memory = __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCWindowUnderflow); return; } -// TODO(pag): This next line should be uncommented for correctness, but then -// it means not as nice bitcode for mcsema. -// state.window = window->prev_window; + // TODO(pag): This next line should be uncommented for correctness, but then + // it means not as nice bitcode for mcsema. + // state.window = window->prev_window; // Move input register to output Write(REG_O0, REG_I0); @@ -231,17 +234,16 @@ DEF_HELPER(RESTORE_WINDOW, RegisterWindow *&prev_window) -> void { DEF_ISEL(UNSUPPORTED_INSTRUCTION) = HandleUnsupported; DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction; -#include "lib/Arch/SPARC32/Semantics/FLAGS.cpp" #include "lib/Arch/SPARC32/Semantics/COND.cpp" - +#include "lib/Arch/SPARC32/Semantics/FLAGS.cpp" #include "lib/Arch/SPARC64/Semantics/ADDRESS.cpp" -#include "lib/Arch/SPARC64/Semantics/BITBYTE.cpp" #include "lib/Arch/SPARC64/Semantics/BINARY.cpp" -#include "lib/Arch/SPARC64/Semantics/DATAXFER.cpp" -#include "lib/Arch/SPARC64/Semantics/MISC.cpp" -#include "lib/Arch/SPARC64/Semantics/LOGICAL.cpp" +#include "lib/Arch/SPARC64/Semantics/BITBYTE.cpp" #include "lib/Arch/SPARC64/Semantics/BRANCH.cpp" +#include "lib/Arch/SPARC64/Semantics/DATAXFER.cpp" #include "lib/Arch/SPARC64/Semantics/FOP.cpp" -#include "lib/Arch/SPARC64/Semantics/VIS.cpp" +#include "lib/Arch/SPARC64/Semantics/LOGICAL.cpp" +#include "lib/Arch/SPARC64/Semantics/MISC.cpp" #include "lib/Arch/SPARC64/Semantics/TRAP.cpp" +#include "lib/Arch/SPARC64/Semantics/VIS.cpp" #include "lib/Arch/SPARC64/Semantics/WRASR.cpp" diff --git a/lib/Arch/SPARC64/Semantics/ADDRESS.cpp b/lib/Arch/SPARC64/Semantics/ADDRESS.cpp index afaff8583..a1135abeb 100644 --- a/lib/Arch/SPARC64/Semantics/ADDRESS.cpp +++ b/lib/Arch/SPARC64/Semantics/ADDRESS.cpp @@ -41,34 +41,29 @@ DEF_SEM(ALIGNADDRESS_LITTLE, R64 src1, R64 src2, R64W dst) { } DEF_SEM(FALIGNDATAG, V128 src1, V128 src2, V128W dst) { + // extract F[rs1] and F[rs2] and concat them auto rs1 = UReadV8(src1); auto rs2 = UReadV8(src2); auto concat_vec = UClearV8(UReadV8(dst)); - _Pragma("unroll") - for (size_t i = 0; i < 8; ++i) { - concat_vec = UInsertV8( - concat_vec, i, UExtractV8(rs1, i)); + _Pragma("unroll") for (size_t i = 0; i < 8; ++i) { + concat_vec = UInsertV8(concat_vec, i, UExtractV8(rs1, i)); } - _Pragma("unroll") - for (size_t i = 0; i < 8; ++i) { - concat_vec = UInsertV8( - concat_vec, i, UExtractV8(rs2, i)); + _Pragma("unroll") for (size_t i = 0; i < 8; ++i) { + concat_vec = UInsertV8(concat_vec, i, UExtractV8(rs2, i)); } // Recover the vector from the GSR.align value auto align = Read(GSR_ALIGN); auto recv_vec = UClearV8(UReadV8(dst)); - _Pragma("unroll") - for (size_t i = 0; i < 8; ++i) { - recv_vec = UInsertV8( - recv_vec, i, UExtractV8(concat_vec, align + i)); + _Pragma("unroll") for (size_t i = 0; i < 8; ++i) { + recv_vec = UInsertV8(recv_vec, i, UExtractV8(concat_vec, align + i)); } UWriteV8(dst, recv_vec); return memory; } -} // namespace +} // namespace DEF_ISEL(ALIGNADDRESS) = ALIGNADDRESS; DEF_ISEL(ALIGNADDRESS_LITTLE) = ALIGNADDRESS_LITTLE; diff --git a/lib/Arch/SPARC64/Semantics/BINARY.cpp b/lib/Arch/SPARC64/Semantics/BINARY.cpp index 6561a9067..c59171a2c 100644 --- a/lib/Arch/SPARC64/Semantics/BINARY.cpp +++ b/lib/Arch/SPARC64/Semantics/BINARY.cpp @@ -32,27 +32,31 @@ ALWAYS_INLINE static void WriteFlagsAddSub(State &state, T lhs, T rhs, T res) { } template -ALWAYS_INLINE static void WriteXCCFlagsIncDec(State &state, T lhs, T rhs, T res) { +ALWAYS_INLINE static void WriteXCCFlagsIncDec(State &state, T lhs, T rhs, + T res) { FLAG_XCC_ZF = ZeroFlag(res); FLAG_XCC_NF = SignFlag(res); FLAG_XCC_VF = Overflow::Flag(lhs, rhs, res); } template -ALWAYS_INLINE static void WriteICCFlagsIncDec(State &state, T lhs, T rhs, T res) { +ALWAYS_INLINE static void WriteICCFlagsIncDec(State &state, T lhs, T rhs, + T res) { FLAG_ICC_ZF = ZeroFlag(res); FLAG_ICC_NF = SignFlag(res); FLAG_ICC_VF = Overflow::Flag(lhs, rhs, res); } template -ALWAYS_INLINE static void WriteICCFlagsAddSub(State &state, uint32_t lhs, uint32_t rhs, uint32_t res) { +ALWAYS_INLINE static void WriteICCFlagsAddSub(State &state, uint32_t lhs, + uint32_t rhs, uint32_t res) { FLAG_ICC_CF = Carry::Flag(lhs, rhs, res); WriteICCFlagsIncDec(state, lhs, rhs, res); } template -ALWAYS_INLINE static void WriteXCCFlagsAddSub(State &state, uint64_t lhs, uint64_t rhs, uint64_t res) { +ALWAYS_INLINE static void WriteXCCFlagsAddSub(State &state, uint64_t lhs, + uint64_t rhs, uint64_t res) { FLAG_XCC_CF = Carry::Flag(lhs, rhs, res); WriteXCCFlagsIncDec(state, lhs, rhs, res); } @@ -80,9 +84,8 @@ DEF_SEM(ADDCC, S1 src1, S2 src2, D dst) { auto rhs = Read(src2); auto res = UAdd(lhs, rhs); Write(dst, res); - WriteICCFlagsAddSub( - state, Literal(lhs), - Literal(rhs), Literal(res)); + WriteICCFlagsAddSub(state, Literal(lhs), + Literal(rhs), Literal(res)); WriteXCCFlagsAddSub(state, lhs, rhs, res); return memory; } @@ -95,9 +98,9 @@ DEF_SEM(ADDCCC, S1 src1, S2 src2, D dst) { auto sum = UAdd(lhs, rhs); auto res = UAdd(sum, carry); Write(dst, res); - WriteICCFlagsAddSub( - state, static_cast(lhs), - static_cast(rhs), static_cast(sum)); + WriteICCFlagsAddSub(state, static_cast(lhs), + static_cast(rhs), + static_cast(sum)); WriteXCCFlagsAddSub(state, lhs, rhs, res); return memory; } @@ -128,9 +131,9 @@ DEF_SEM(ADDXCC, S1 src1, S2 src2, D dst) { auto rhs = Read(src2); auto sum = UAdd(lhs, rhs); Write(dst, sum); - WriteICCFlagsAddSub( - state, static_cast(lhs), - static_cast(rhs), static_cast(sum)); + WriteICCFlagsAddSub(state, static_cast(lhs), + static_cast(rhs), + static_cast(sum)); WriteXCCFlagsAddSub(state, lhs, rhs, sum); return memory; } @@ -143,9 +146,9 @@ DEF_SEM(ADDXCCC, S1 src1, S2 src2, D dst) { auto sum = UAdd(lhs, rhs); auto res = UAdd(sum, carry); Write(dst, res); - WriteICCFlagsAddSub( - state, static_cast(lhs), - static_cast(rhs), static_cast(res)); + WriteICCFlagsAddSub(state, static_cast(lhs), + static_cast(rhs), + static_cast(res)); WriteXCCFlagsAddSub(state, lhs, rhs, res); return memory; } @@ -163,9 +166,9 @@ DEF_SEM(SUBCC, S1 src1, S2 src2, D dst) { auto rhs = Read(src2); auto res = USub(lhs, rhs); Write(dst, res); - WriteICCFlagsAddSub( - state, static_cast(lhs), static_cast(rhs), - static_cast(res)); + WriteICCFlagsAddSub(state, static_cast(lhs), + static_cast(rhs), + static_cast(res)); WriteXCCFlagsAddSub(state, lhs, rhs, res); return memory; } @@ -189,9 +192,9 @@ DEF_SEM(SUBCCC, S1 src1, S2 src2, D dst) { auto sub = USub(lhs, rhs); auto res = USub(sub, carry); WriteZExt(dst, res); - WriteICCFlagsAddSub( - state, static_cast(lhs), static_cast(rhs), - static_cast(res)); + WriteICCFlagsAddSub(state, static_cast(lhs), + static_cast(rhs), + static_cast(res)); WriteXCCFlagsAddSub(state, lhs, rhs, res); return memory; } @@ -201,15 +204,16 @@ template DEF_SEM(TADDCC, S1 src1, S2 src2, D dst) { auto rs1 = Read(src1); auto rs2 = Read(src2); + // Check for the tag overflow auto tag_rs1 = UAnd(rs1, Literal(0x3)); auto tag_rs2 = UAnd(rs2, Literal(0x3)); auto tag_ov = UCmpNeq(UOr(tag_rs1, tag_rs2), 0); auto sum = UAdd(rs1, rs2); - FLAG_ICC_VF = tag_ov; //|| Overflow::Flag(rs1, rs2, sum)); - FLAG_ICC_CF = Carry::Flag( - static_cast(rs1), static_cast(rs2), - static_cast(sum)); + FLAG_ICC_VF = tag_ov; //|| Overflow::Flag(rs1, rs2, sum)); + FLAG_ICC_CF = Carry::Flag(static_cast(rs1), + static_cast(rs2), + static_cast(sum)); FLAG_ICC_ZF = ZeroFlag(static_cast(sum)); FLAG_ICC_NF = SignFlag(static_cast(sum)); WriteXCCFlagsAddSub(state, rs1, rs2, sum); @@ -221,6 +225,7 @@ template DEF_SEM(TADDCCTV, R8W cond, S1 src1, S2 src2, D dst) { auto rs1 = Read(src1); auto rs2 = Read(src2); + // Check for the tag overflow auto tag_rs1 = UAnd(rs1, Literal(0x3)); auto tag_rs2 = UAnd(rs2, Literal(0x3)); @@ -237,8 +242,7 @@ DEF_SEM(TADDCCTV, R8W cond, S1 src1, S2 src2, D dst) { Write(dst, sum); FLAG_ICC_VF = tag_ov; FLAG_ICC_CF = Carry::Flag( - Literal(rs1), Literal(rs2), - Literal(sum)); + Literal(rs1), Literal(rs2), Literal(sum)); FLAG_ICC_ZF = ZeroFlag(static_cast(sum)); FLAG_ICC_NF = SignFlag(static_cast(sum)); WriteXCCFlagsAddSub(state, rs1, rs2, sum); @@ -249,15 +253,16 @@ template DEF_SEM(TSUBCC, S1 src1, S2 src2, D dst) { auto rs1 = Read(src1); auto rs2 = Read(src2); + // Check for the tag overflow auto tag_rs1 = UAnd(rs1, Literal(0x3)); auto tag_rs2 = UAnd(rs2, Literal(0x3)); auto tag_ov = UCmpNeq(UOr(tag_rs1, tag_rs2), 0); auto res = USub(rs1, rs2); - FLAG_ICC_VF = tag_ov; //|| Overflow::Flag(rs1, rs2, sum)); - FLAG_ICC_CF = Carry::Flag( - static_cast(rs1), static_cast(rs2), - static_cast(res)); + FLAG_ICC_VF = tag_ov; //|| Overflow::Flag(rs1, rs2, sum)); + FLAG_ICC_CF = Carry::Flag(static_cast(rs1), + static_cast(rs2), + static_cast(res)); FLAG_ICC_ZF = ZeroFlag(static_cast(res)); FLAG_ICC_NF = SignFlag(static_cast(res)); WriteXCCFlagsAddSub(state, rs1, rs2, res); @@ -268,6 +273,7 @@ template DEF_SEM(TSUBCCTV, R8W cond, S1 src1, S2 src2, D dst) { auto rs1 = Read(src1); auto rs2 = Read(src2); + // Check for the tag overflow auto tag_rs1 = UAnd(rs1, Literal(0x3)); auto tag_rs2 = UAnd(rs2, Literal(0x3)); @@ -285,15 +291,14 @@ DEF_SEM(TSUBCCTV, R8W cond, S1 src1, S2 src2, D dst) { Write(dst, res); FLAG_ICC_VF = tag_ov; FLAG_ICC_CF = Carry::Flag( - Literal(rs1), Literal(rs2), - Literal(res)); + Literal(rs1), Literal(rs2), Literal(res)); FLAG_ICC_ZF = ZeroFlag(Literal(res)); FLAG_ICC_NF = SignFlag(Literal(res)); WriteXCCFlagsAddSub(state, rs1, rs2, res); return memory; } -} +} // namespace DEF_ISEL(ADD) = ADD; DEF_ISEL(ADDC) = ADDC; @@ -405,7 +410,8 @@ DEF_SEM(SDIV, S1 src1, S2 src2, D dst) { auto lhs = Read(src1); auto lhs_wide = ZExt(lhs); auto y = Read(REG_Y); - auto y_lhs_wide = Signed(UOr(decltype(lhs_wide)(UShl(y, Literal(32))), lhs_wide)); + auto y_lhs_wide = Signed( + UOr(decltype(lhs_wide)(UShl(y, Literal(32))), lhs_wide)); auto rhs = Signed(Read(src2)); auto rhs_wide = SExt(rhs); auto quot = SDiv(y_lhs_wide, rhs_wide); @@ -418,8 +424,8 @@ DEF_SEM(SDIVCC, S1 src1, S2 src2, D dst) { auto lhs = Read(src1); auto lhs_wide = ZExt(lhs); auto y = Read(REG_Y); - auto y_lhs_wide = Signed(UOr(decltype(lhs_wide)( - UShl(y, Literal(32))), lhs_wide)); + auto y_lhs_wide = Signed( + UOr(decltype(lhs_wide)(UShl(y, Literal(32))), lhs_wide)); auto rhs = Read(src2); auto rhs_wide = SExt(rhs); auto quot = SDiv(y_lhs_wide, rhs_wide); @@ -490,7 +496,7 @@ DEF_SEM(UDIVX, S1 src1, S2 src2, D dst) { return memory; } -} +} // namespace DEF_ISEL(SMUL) = SMUL; DEF_ISEL(SMULcc) = SMULCC; @@ -518,7 +524,8 @@ DEF_SEM(MULSCC_R32, R32 src1, R32 src2, R32W dest) { auto lsb_y = UAnd(y, Literal(0x1)); auto masked_rs1 = UAnd(rs1, Literal(0xffffffff)); auto masked_rs2 = UAnd(rs2, Literal(0xffffffff)); - auto new_rs2 = Select(UCmpEq(lsb_y, 0), Literal(0), masked_rs2); + auto new_rs2 = + Select(UCmpEq(lsb_y, 0), Literal(0), masked_rs2); auto flag_nf = Literal(Read(FLAG_ICC_NF)); auto flag_vf = Literal(Read(FLAG_ICC_VF)); @@ -527,17 +534,19 @@ DEF_SEM(MULSCC_R32, R32 src1, R32 src2, R32W dest) { auto new_rs1 = UOr(UShr(masked_rs1, Literal(1)), Literal(shifted_flag)); auto res = UAdd(new_rs1, new_rs2); + // Y register is shifted right by one bit, with the LSB of the unshifted // r[rs1] replacing the MSB of Y auto shifted_y = UShr(y, Literal(1)); - auto lsb_rs1 = UAnd(rs1, Literal(0x1)); - auto new_y = UOr(shifted_y, decltype(y)(UShl(lsb_rs1, Literal(31)))); + auto lsb_rs1 = UAnd(rs1, Literal(0x1)); + auto new_y = UOr(shifted_y, + decltype(y)(UShl(lsb_rs1, Literal(31)))); Write(REG_Y, new_y); Write(dest, res); - WriteICCFlagsAddSub( - state, static_cast(new_rs1), - static_cast(new_rs2), static_cast(res)); + WriteICCFlagsAddSub(state, static_cast(new_rs1), + static_cast(new_rs2), + static_cast(res)); // All undefined. FLAG_XCC_CF = 0; @@ -549,7 +558,6 @@ DEF_SEM(MULSCC_R32, R32 src1, R32 src2, R32W dest) { return memory; } -} +} // namespace DEF_ISEL(MULScc) = MULSCC_R32; - diff --git a/lib/Arch/SPARC64/Semantics/BITBYTE.cpp b/lib/Arch/SPARC64/Semantics/BITBYTE.cpp index f1fcc3cbe..b1cafba53 100644 --- a/lib/Arch/SPARC64/Semantics/BITBYTE.cpp +++ b/lib/Arch/SPARC64/Semantics/BITBYTE.cpp @@ -19,7 +19,7 @@ namespace { -template +template DEF_SEM(BMASK, S1 src1, S2 src2, D dst) { auto lhs = Read(src1); auto rhs = Read(src2); @@ -37,23 +37,22 @@ DEF_SEM(BSHUFFLE, V64 src1, V64 src2, V64W dst) { auto mask = Read(GSR_MASK); auto num_elems = NumVectorElems(rs1_vec); - _Pragma("unroll") - for (size_t i = 0; i < NumVectorElems(dst_vec); ++i) { - auto e = UShr(mask, decltype(mask)(28 - i*4)); + _Pragma("unroll") for (size_t i = 0; i < NumVectorElems(dst_vec); ++i) { + auto e = UShr(mask, decltype(mask)(28 - i * 4)); auto index = UXor(e, Literal(0xff)); - if(index >= num_elems) { - dst_vec = UInsertV8( - dst_vec, num_elems - i, UExtractV8(rs2_vec, (2*num_elems-1) - index)); + if (index >= num_elems) { + dst_vec = UInsertV8(dst_vec, num_elems - i, + UExtractV8(rs2_vec, (2 * num_elems - 1) - index)); } else { - dst_vec = UInsertV8( - dst_vec, num_elems - i, UExtractV8(rs2_vec, (num_elems-1) - index)); + dst_vec = UInsertV8(dst_vec, num_elems - i, + UExtractV8(rs2_vec, (num_elems - 1) - index)); } } UWriteV8(dst, dst_vec); return memory; } -} +} // namespace DEF_ISEL(BMASK) = BMASK; DEF_ISEL(BSHUFFLE) = BSHUFFLE; diff --git a/lib/Arch/SPARC64/Semantics/BRANCH.cpp b/lib/Arch/SPARC64/Semantics/BRANCH.cpp index 202455a44..23cb7e017 100644 --- a/lib/Arch/SPARC64/Semantics/BRANCH.cpp +++ b/lib/Arch/SPARC64/Semantics/BRANCH.cpp @@ -19,8 +19,7 @@ namespace { template -DEF_SEM(JMPL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst, - T dst_pc, T dst_npc) { +DEF_SEM(JMPL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst, T dst_pc, T dst_npc) { Write(dst, Read(pc_of_jmp)); Write(dst_pc, Read(new_pc)); Write(dst_npc, Read(new_npc)); @@ -29,8 +28,8 @@ DEF_SEM(JMPL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst, // This is a variation on JMPL that also stores the return address. template -DEF_SEM(CALL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst, - T dst_pc, T dst_npc, T return_pc_dst) { +DEF_SEM(CALL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst, T dst_pc, T dst_npc, + T return_pc_dst) { Write(dst, Read(pc_of_jmp)); Write(dst_pc, Read(new_pc)); Write(dst_npc, Read(new_npc)); @@ -41,32 +40,28 @@ DEF_SEM(CALL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst, } template -DEF_SEM(BA, PC new_taken_pc, PC new_taken_npc, - T pc_dst, T npc_dst) { +DEF_SEM(BA, PC new_taken_pc, PC new_taken_npc, T pc_dst, T npc_dst) { Write(pc_dst, Read(new_taken_pc)); Write(npc_dst, Read(new_taken_npc)); return memory; } template -DEF_SEM(BN, PC new_not_taken_pc, PC new_not_taken_npc, - T pc_dst, T npc_dst) { +DEF_SEM(BN, PC new_not_taken_pc, PC new_not_taken_npc, T pc_dst, T npc_dst) { Write(pc_dst, Read(new_not_taken_pc)); Write(npc_dst, Read(new_not_taken_npc)); return memory; } template -DEF_SEM(FBA, PC new_taken_pc, PC new_taken_npc, - T pc_dst, T npc_dst) { +DEF_SEM(FBA, PC new_taken_pc, PC new_taken_npc, T pc_dst, T npc_dst) { Write(pc_dst, Read(new_taken_pc)); Write(npc_dst, Read(new_taken_npc)); return memory; } template -DEF_SEM(FBN, PC new_not_taken_pc, PC new_not_taken_npc, - T pc_dst, T npc_dst) { +DEF_SEM(FBN, PC new_not_taken_pc, PC new_not_taken_npc, T pc_dst, T npc_dst) { Write(pc_dst, Read(new_not_taken_pc)); Write(npc_dst, Read(new_not_taken_npc)); return memory; @@ -88,10 +83,10 @@ DEF_SEM(RETURN, PC new_pc, PC new_npc, T dst_pc, T dst_npc, // is placed inside of a delay slot. #define MAKE_BRANCH(name, cond, cc) \ namespace { \ - DEF_SEM(name ## cond ## _ ## cc, R8W branch_taken, PC new_taken_pc, PC new_taken_npc, \ - PC new_not_taken_pc, PC new_not_taken_npc, \ + DEF_SEM(name##cond##_##cc, R8W branch_taken, PC new_taken_pc, \ + PC new_taken_npc, PC new_not_taken_pc, PC new_not_taken_npc, \ R64W pc_dst, R64W npc_dst) { \ - if (Cond ## cond ## _ ## cc(state)) { \ + if (Cond##cond##_##cc(state)) { \ Write(branch_taken, true); \ Write(pc_dst, Read(new_taken_pc)); \ Write(npc_dst, Read(new_taken_npc)); \ @@ -103,11 +98,11 @@ DEF_SEM(RETURN, PC new_pc, PC new_npc, T dst_pc, T dst_npc, return memory; \ } \ } \ - DEF_ISEL(name ## cond ## _ ## cc) = name ## cond ## _ ## cc; + DEF_ISEL(name##cond##_##cc) = name##cond##_##cc; DEF_SEM(UNSUPPORTED_DCTI) { - return __remill_sync_hyper_call( - state, memory, SyncHyperCall::kSPARCUnhandledDCTI); + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCUnhandledDCTI); } } // namespace @@ -138,8 +133,8 @@ DEF_ISEL(FBN_fcc2) = FBN; DEF_ISEL(FBN_fcc3) = FBN; #define MAKE_BRANCH_CC(name, cond) \ - MAKE_BRANCH(name, cond, icc) \ - MAKE_BRANCH(name, cond, xcc) \ + MAKE_BRANCH(name, cond, icc) \ + MAKE_BRANCH(name, cond, xcc) MAKE_BRANCH_CC(B, NE) MAKE_BRANCH_CC(B, E) @@ -157,10 +152,10 @@ MAKE_BRANCH_CC(B, VC) MAKE_BRANCH_CC(B, VS) #define MAKE_BRANCH_F(name, cond) \ - MAKE_BRANCH(name, cond, fcc0);\ - MAKE_BRANCH(name, cond, fcc1);\ - MAKE_BRANCH(name, cond, fcc2);\ - MAKE_BRANCH(name, cond, fcc3);\ + MAKE_BRANCH(name, cond, fcc0); \ + MAKE_BRANCH(name, cond, fcc1); \ + MAKE_BRANCH(name, cond, fcc2); \ + MAKE_BRANCH(name, cond, fcc3); MAKE_BRANCH_F(FB, U); MAKE_BRANCH_F(FB, G); @@ -183,12 +178,12 @@ MAKE_BRANCH_F(FB, O); #define MAKE_BRANCH(name, cond) \ namespace { \ - template \ - DEF_SEM(name ## cond, R8W branch_taken, S reg_cc, PC new_taken_pc, PC new_taken_npc, \ - PC new_not_taken_pc, PC new_not_taken_npc, \ + template \ + DEF_SEM(name##cond, R8W branch_taken, S reg_cc, PC new_taken_pc, \ + PC new_taken_npc, PC new_not_taken_pc, PC new_not_taken_npc, \ R64W pc_dst, R64W npc_dst) { \ auto cc = Read(reg_cc); \ - if (CondR ## cond (state, cc)) { \ + if (CondR##cond(state, cc)) { \ Write(branch_taken, true); \ Write(pc_dst, Read(new_taken_pc)); \ Write(npc_dst, Read(new_taken_npc)); \ @@ -200,7 +195,7 @@ MAKE_BRANCH_F(FB, O); return memory; \ } \ } \ - DEF_ISEL(name ## cond ) = name ## cond ; + DEF_ISEL(name##cond) = name##cond; MAKE_BRANCH(BR, Z) MAKE_BRANCH(BR, LEZ) diff --git a/lib/Arch/SPARC64/Semantics/DATAXFER.cpp b/lib/Arch/SPARC64/Semantics/DATAXFER.cpp index abf1a5b90..bd550f438 100644 --- a/lib/Arch/SPARC64/Semantics/DATAXFER.cpp +++ b/lib/Arch/SPARC64/Semantics/DATAXFER.cpp @@ -28,8 +28,8 @@ template DEF_SEM(STA, R8 asi, S src, D dst) { WriteZExt(dst, Read(src)); HYPER_CALL_VECTOR = Read(asi); - return __remill_sync_hyper_call( - state, memory, SyncHyperCall::kSPARCSetAsiRegister); + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCSetAsiRegister); } DEF_SEM(STF, RF32 src, MF32W dst) { @@ -48,16 +48,16 @@ DEF_SEM(STFA, R8 asi, RF32 src, MF32W dst) { auto lhs = Read(src); Write(dst, lhs); HYPER_CALL_VECTOR = Read(asi); - return __remill_sync_hyper_call( - state, memory, SyncHyperCall::kSPARCSetAsiRegister); + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCSetAsiRegister); } DEF_SEM(STDFA, R8 asi, RF64 src, MF64W dst) { auto lhs = Read(src); Write(dst, lhs); HYPER_CALL_VECTOR = Read(asi); - return __remill_sync_hyper_call( - state, memory, SyncHyperCall::kSPARCSetAsiRegister); + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCSetAsiRegister); } DEF_SEM(STTW_R32, R32 src1, R32 src2, MV64W dst) { @@ -87,7 +87,7 @@ DEF_SEM(SETHI, S src, D dst) { return memory; } -template +template DEF_SEM(SET, S1 src1, S2 src2, D dst) { const auto high_bits = Read(src1); const auto low_bits = Read(src2); @@ -113,7 +113,7 @@ DEF_SEM(SETHI_ADD, S1 src1, S2 src2, D1 dst1, D2 dst2) { return memory; } -} +} // namespace DEF_ISEL(STB) = ST; DEF_ISEL(STH) = ST; @@ -153,8 +153,8 @@ template DEF_SEM(LDUA, R8 asi, S src, D dst) { WriteZExt(dst, Read(src)); HYPER_CALL_VECTOR = Read(asi); - return __remill_sync_hyper_call( - state, memory, SyncHyperCall::kSPARCSetAsiRegister); + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCSetAsiRegister); } template @@ -167,8 +167,8 @@ template DEF_SEM(LDSA, R8 asi, S src, D dst) { WriteSExt(dst, Signed(Read(src))); HYPER_CALL_VECTOR = Read(asi); - return __remill_sync_hyper_call( - state, memory, SyncHyperCall::kSPARCSetAsiRegister); + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCSetAsiRegister); } DEF_SEM(LDF, MV64 src, R32W dst) { @@ -187,16 +187,16 @@ DEF_SEM(LDFA, R8 asi, MV64 src, R32W dst) { auto vec = UReadV32(src); WriteZExt(dst, UExtractV32(vec, 0)); HYPER_CALL_VECTOR = Read(asi); - return __remill_sync_hyper_call( - state, memory, SyncHyperCall::kSPARCSetAsiRegister); + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCSetAsiRegister); } DEF_SEM(LDDFA, R8 asi, MV64 src, R64W dst) { auto vec = UReadV64(src); WriteZExt(dst, UExtractV64(vec, 0)); HYPER_CALL_VECTOR = Read(asi); - return __remill_sync_hyper_call( - state, memory, SyncHyperCall::kSPARCSetAsiRegister); + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCSetAsiRegister); } DEF_SEM(LDTW_IMMEXC, MV64 src_mem, R32W dst1, R32W dst2) { @@ -215,7 +215,7 @@ DEF_SEM(LDTW_R32EXC, MV64 src_mem, R32W dst1, R32W dst2) { return memory; } -} // namespace +} // namespace DEF_ISEL(LDUB) = LDU; DEF_ISEL(LDUH) = LDU; @@ -261,8 +261,8 @@ DEF_SEM(LDSTUBA, R8 asi, M8W src_mem, R dst) { auto mem_val = Read(src_mem); WriteZExt(dst, mem_val); Write(src_mem, static_cast(0xffu)); - return __remill_sync_hyper_call( - state, memory, SyncHyperCall::kSPARCSetAsiRegister); + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCSetAsiRegister); } DEF_SEM(CASA, R32 src1, R32 src2, R32W dst) { @@ -291,11 +291,11 @@ DEF_SEM(SWAPA, R8 asi, M32W src, R64W dst) { WriteZExt(dst, old_src); WriteTrunc(src, old_dst); HYPER_CALL_VECTOR = Read(asi); - return __remill_sync_hyper_call( - state, memory, SyncHyperCall::kSPARCSetAsiRegister); + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCSetAsiRegister); } -} +} // namespace DEF_ISEL(LDSTUB) = LDSTUB; DEF_ISEL(LDSTUBA) = LDSTUBA; @@ -325,7 +325,7 @@ DEF_SEM(MOVN_xcc, S src, D dst) { return memory; } -} +} // namespace DEF_ISEL(MOVA_icc) = MOVA_icc; DEF_ISEL(MOVA_xcc) = MOVA_xcc; @@ -335,17 +335,17 @@ DEF_ISEL(MOVN_xcc) = MOVN_xcc; #define MAKE_SEMANTICS(name, cond, cc) \ namespace { \ template \ - DEF_SEM(name ## cond ## _ ## cc, S src, D dst) { \ + DEF_SEM(name##cond##_##cc, S src, D dst) { \ auto new_value = Read(src); \ auto old_value = Read(dst); \ - auto branch_taken = Cond ## cond ## _ ## cc(state); \ - auto value = Select(branch_taken, new_value, \ - decltype(new_value)(old_value)); \ + auto branch_taken = Cond##cond##_##cc(state); \ + auto value = \ + Select(branch_taken, new_value, decltype(new_value)(old_value)); \ WriteZExt(dst, value); \ return memory; \ } \ } \ - DEF_ISEL(MOV ## cond ## _ ## cc) = name ## cond ## _ ## cc; + DEF_ISEL(MOV##cond##_##cc) = name##cond##_##cc; #define MAKE_SEMANTICS_CC(name, cond) \ MAKE_SEMANTICS(name, cond, icc) \ @@ -394,18 +394,19 @@ MAKE_SEMANTICS_FCC(MOVF, O) #define MAKE_SEMANTICS(name, cond) \ namespace { \ - template \ - DEF_SEM(name ## cond, C reg_cc, S src, D dst) { \ + template \ + DEF_SEM(name##cond, C reg_cc, S src, D dst) { \ auto new_value = Read(src); \ auto old_value = Read(dst); \ auto cc = Read(reg_cc); \ - auto cond_taken = CondR ## cond(state, cc); \ - auto value = Select(cond_taken, new_value, decltype(new_value)(old_value)); \ + auto cond_taken = CondR##cond(state, cc); \ + auto value = \ + Select(cond_taken, new_value, decltype(new_value)(old_value)); \ WriteZExt(dst, value); \ return memory; \ } \ } \ - DEF_ISEL(name ## cond) = name ## cond; + DEF_ISEL(name##cond) = name##cond; MAKE_SEMANTICS(MOVR, Z) MAKE_SEMANTICS(MOVR, LEZ) @@ -454,7 +455,7 @@ DEF_SEM(FMoveNeverQuad, RF64 src, RF64W dst) { return memory; } -} +} // namespace DEF_ISEL(FMOVSA_icc) = FMoveAlwaysSingle; DEF_ISEL(FMOVSA_xcc) = FMoveAlwaysSingle; @@ -501,43 +502,40 @@ DEF_ISEL(FMOVQN_fcc3) = FMoveNeverQuad; #define MAKE_SEMANTICS(name, cond, cc) \ namespace { \ - DEF_SEM(FMOVS ## cond ## _ ## cc, RF32 src, RF32W dst) { \ + DEF_SEM(FMOVS##cond##_##cc, RF32 src, RF32W dst) { \ auto new_val = Read(src); \ auto old_val = Read(dst); \ - auto branch_taken = Cond ## cond ## _ ## cc(state); \ - auto value = Select(branch_taken, new_val, \ - decltype(new_val)(old_val)); \ + auto branch_taken = Cond##cond##_##cc(state); \ + auto value = Select(branch_taken, new_val, decltype(new_val)(old_val)); \ Write(dst, value); \ WriteTrunc(FSR_CEXC, 0); \ WriteTrunc(FSR_FTT, 0); \ return memory; \ } \ - DEF_SEM(FMOVD ## cond ## _ ## cc, RF64 src, RF64W dst) { \ - auto new_val = Read(src); \ - auto old_val = Read(dst); \ - auto branch_taken = Cond ## cond ## _ ## cc(state); \ - auto value = Select(branch_taken, new_val, \ - decltype(new_val)(old_val)); \ + DEF_SEM(FMOVD##cond##_##cc, RF64 src, RF64W dst) { \ + auto new_val = Read(src); \ + auto old_val = Read(dst); \ + auto branch_taken = Cond##cond##_##cc(state); \ + auto value = Select(branch_taken, new_val, decltype(new_val)(old_val)); \ Write(dst, value); \ WriteTrunc(FSR_CEXC, 0); \ WriteTrunc(FSR_FTT, 0); \ - return memory; \ + return memory; \ } \ - DEF_SEM(FMOVQ ## cond ## _ ## cc, RF64 src, RF64W dst) { \ - auto new_val = Read(src); \ - auto old_val = Read(dst); \ - auto branch_taken = Cond ## cond ## _ ## cc(state); \ - auto value = Select(branch_taken, new_val, \ - decltype(new_val)(old_val)); \ + DEF_SEM(FMOVQ##cond##_##cc, RF64 src, RF64W dst) { \ + auto new_val = Read(src); \ + auto old_val = Read(dst); \ + auto branch_taken = Cond##cond##_##cc(state); \ + auto value = Select(branch_taken, new_val, decltype(new_val)(old_val)); \ Write(dst, value); \ WriteTrunc(FSR_CEXC, 0); \ WriteTrunc(FSR_FTT, 0); \ return memory; \ } \ } \ - DEF_ISEL(FMOVS ## cond ## _ ## cc) = FMOVS ## cond ## _ ## cc; \ - DEF_ISEL(FMOVD ## cond ## _ ## cc) = FMOVD ## cond ## _ ## cc; \ - DEF_ISEL(FMOVQ ## cond ## _ ## cc) = FMOVQ ## cond ## _ ## cc; + DEF_ISEL(FMOVS##cond##_##cc) = FMOVS##cond##_##cc; \ + DEF_ISEL(FMOVD##cond##_##cc) = FMOVD##cond##_##cc; \ + DEF_ISEL(FMOVQ##cond##_##cc) = FMOVQ##cond##_##cc; #define MAKE_SEMANTICS_CC(name, cond) \ MAKE_SEMANTICS(name, cond, icc) \ @@ -585,49 +583,43 @@ MAKE_SEMANTICS_FCC(FMOV, O) #define MAKE_SEMANTICS(name, cond) \ namespace { \ - DEF_SEM(name ## S ## cond, R64 reg_cc, V32 src, V32W dst) { \ + DEF_SEM(name##S##cond, R64 reg_cc, V32 src, V32W dst) { \ auto new_val = FExtractV32(FReadV32(src), 0); \ auto old_val = FExtractV32(FReadV32(dst), 0); \ auto cc = Read(reg_cc); \ - auto cond_taken = CondR ## cond(state, cc); \ - auto value = Select(cond_taken, \ - new_val, \ - decltype(new_val)(old_val)); \ + auto cond_taken = CondR##cond(state, cc); \ + auto value = Select(cond_taken, new_val, decltype(new_val)(old_val)); \ FWriteV32(dst, value); \ WriteTrunc(FSR_CEXC, 0); \ WriteTrunc(FSR_FTT, 0); \ return memory; \ } \ - DEF_SEM(name ## D ## cond, R64 reg_cc, V64 src, V64W dst) { \ - auto new_val = FExtractV64(FReadV64(src), 0); \ - auto old_val = FExtractV64(FReadV64(dst), 0); \ - auto cc = Read(reg_cc); \ - auto cond_taken = CondR ## cond(state, cc); \ - auto value = Select(cond_taken, \ - new_val, \ - decltype(new_val)(old_val)); \ - FWriteV64(dst, value); \ - WriteTrunc(FSR_CEXC, 0); \ - WriteTrunc(FSR_FTT, 0); \ - return memory; \ + DEF_SEM(name##D##cond, R64 reg_cc, V64 src, V64W dst) { \ + auto new_val = FExtractV64(FReadV64(src), 0); \ + auto old_val = FExtractV64(FReadV64(dst), 0); \ + auto cc = Read(reg_cc); \ + auto cond_taken = CondR##cond(state, cc); \ + auto value = Select(cond_taken, new_val, decltype(new_val)(old_val)); \ + FWriteV64(dst, value); \ + WriteTrunc(FSR_CEXC, 0); \ + WriteTrunc(FSR_FTT, 0); \ + return memory; \ } \ - DEF_SEM(name ## Q ## cond, R64 reg_cc, V64 src, V64W dst) { \ + DEF_SEM(name##Q##cond, R64 reg_cc, V64 src, V64W dst) { \ auto new_val = FExtractV64(FReadV64(src), 0); \ auto old_val = FExtractV64(FReadV64(dst), 0); \ auto cc = Read(reg_cc); \ - auto cond_taken = CondR ## cond(state, cc); \ - auto value = Select(cond_taken, \ - new_val, \ - decltype(new_val)(old_val)); \ + auto cond_taken = CondR##cond(state, cc); \ + auto value = Select(cond_taken, new_val, decltype(new_val)(old_val)); \ FWriteV64(dst, value); \ WriteTrunc(FSR_CEXC, 0); \ WriteTrunc(FSR_FTT, 0); \ return memory; \ } \ } \ - DEF_ISEL(name ## S ## cond) = name ## S ## cond; \ - DEF_ISEL(name ## D ## cond) = name ## D ## cond; \ - DEF_ISEL(name ## Q ## cond) = name ## Q ## cond; + DEF_ISEL(name##S##cond) = name##S##cond; \ + DEF_ISEL(name##D##cond) = name##D##cond; \ + DEF_ISEL(name##Q##cond) = name##Q##cond; MAKE_SEMANTICS(FMOVR, Z) MAKE_SEMANTICS(FMOVR, LEZ) @@ -635,4 +627,3 @@ MAKE_SEMANTICS(FMOVR, LZ) MAKE_SEMANTICS(FMOVR, NZ) MAKE_SEMANTICS(FMOVR, GZ) MAKE_SEMANTICS(FMOVR, GEZ) - diff --git a/lib/Arch/SPARC64/Semantics/FOP.cpp b/lib/Arch/SPARC64/Semantics/FOP.cpp index 390fa6f3c..e18f0890c 100644 --- a/lib/Arch/SPARC64/Semantics/FOP.cpp +++ b/lib/Arch/SPARC64/Semantics/FOP.cpp @@ -41,7 +41,7 @@ DEF_SEM(FMOVQ, RF64 src, RF64W dst) { return memory; } -} +} // namespace DEF_ISEL(FMOVS) = FMOVS; DEF_ISEL(FMOVD) = FMOVD; @@ -135,7 +135,7 @@ DEF_SEM(FNOT2D, RF64 src, RF64W dst) { return memory; } -} +} // namespace DEF_ISEL(FABSS) = FABSS; DEF_ISEL(FABSD) = FABSD; @@ -158,15 +158,15 @@ namespace { DEF_SEM(FADDS, RF32 src1, RF32 src2, RF32W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the Floating point exception and prevent // recording of the instructions - auto old_except = - __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto sum = FAdd(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, sum); return memory; @@ -175,15 +175,15 @@ DEF_SEM(FADDS, RF32 src1, RF32 src2, RF32W dst) { DEF_SEM(FADDD, RF64 src1, RF64 src2, RF64W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the Floating point exception and prevent // recording of the instructions - auto old_except = - __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto sum = FAdd64(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, sum); return memory; @@ -192,15 +192,15 @@ DEF_SEM(FADDD, RF64 src1, RF64 src2, RF64W dst) { DEF_SEM(FSUBS, RF32 src1, RF32 src2, RF32W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the Floating point exception and prevent // recording of the instructions - auto old_except = - __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto sub = FSub32(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, sub); return memory; @@ -209,15 +209,15 @@ DEF_SEM(FSUBS, RF32 src1, RF32 src2, RF32W dst) { DEF_SEM(FSUBD, RF64 src1, RF64 src2, RF64W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the Floating point exception and prevent // recording of the instructions - auto old_except = - __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto sub = FSub64(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, sub); return memory; @@ -226,15 +226,15 @@ DEF_SEM(FSUBD, RF64 src1, RF64 src2, RF64W dst) { DEF_SEM(FMULS, RF32 src1, RF32 src2, RF32W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the Floating point exception and prevent // recording of the instructions - auto old_except = - __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); + auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto mul = FMul32(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, mul); return memory; @@ -243,30 +243,32 @@ DEF_SEM(FMULS, RF32 src1, RF32 src2, RF32W dst) { DEF_SEM(FMULD, RF64 src1, RF64 src2, RF64W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the Floating point exception and prevent // recording of the instructions auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto mul = FMul64(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, mul); return memory; } -DEF_SEM(FsMULD, RF32 src1, RF32 src2, RF64W dst) { +DEF_SEM(FsMULD, RF32 src1, RF32 src2, RF64W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the Floating point exception and prevent // recording of the instructions auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto mul = FMul64(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, mul); return memory; @@ -275,14 +277,15 @@ DEF_SEM(FsMULD, RF32 src1, RF32 src2, RF64W dst) { DEF_SEM(FDIVS, RF32 src1, RF32 src2, RF32W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the Floating point exception and prevent // recording of the instructions auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto div = FDiv32(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, div); return memory; @@ -291,20 +294,21 @@ DEF_SEM(FDIVS, RF32 src1, RF32 src2, RF32W dst) { DEF_SEM(FDIVD, RF64 src1, RF64 src2, RF64W dst) { auto lhs = Read(src1); auto rhs = Read(src2); + // Test and clear the Floating point exception and prevent // recording of the instructions auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT); BarrierReorder(); auto div = FDiv64(lhs, rhs); BarrierReorder(); - auto new_except = __remill_fpu_exception_test_and_clear( - FE_ALL_EXCEPT, old_except); + auto new_except = + __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); SetFPSRStatusFlags(state, new_except); Write(dst, div); return memory; } -} +} // namespace DEF_ISEL(FADDS) = FADDS; DEF_ISEL(FADDD) = FADDD; @@ -431,7 +435,7 @@ DEF_SEM(FNADDS, RF32 src1, RF32 src2, RF32W dst) { return memory; } -} +} // namespace DEF_ISEL(FSTOX) = FSTOX; DEF_ISEL(FSTOI) = FSTOI; @@ -466,23 +470,23 @@ DEF_ISEL(FNADDD) = FNADDD; #define MAKE_COMPARE(fcc) \ template \ - void FCompare_ ## fcc(State &state, Memory *memory, \ - S val1, S val2, bool signal) { \ + void FCompare_##fcc(State &state, Memory *memory, S val1, S val2, \ + bool signal) { \ if (std::isnan(val1) || std::isnan(val2)) { \ Write(state.fsr.fcc, Literal(3)); \ } else { \ if (FCmpEq(val1, val2)) { \ - /* result = '00'; */ \ - Write(state.fsr.fcc, Literal(0)); \ + /* result = '00'; */ \ + Write(state.fsr.fcc, Literal(0)); \ } else if (FCmpLt(val1, val2)) { \ - /* result = '01'; */ \ - Write(state.fsr.fcc, Literal(1)); \ - } else { /* FCmpGt(val1, val2) */ \ + /* result = '01'; */ \ + Write(state.fsr.fcc, Literal(1)); \ + } else { /* FCmpGt(val1, val2) */ \ /* result = '10'; */ \ - Write(state.fsr.fcc, Literal(2)); \ + Write(state.fsr.fcc, Literal(2)); \ } \ } \ - } + } namespace { @@ -492,51 +496,51 @@ MAKE_COMPARE(fcc1) MAKE_COMPARE(fcc2) MAKE_COMPARE(fcc3) -} +} // namespace #undef MAKE_COMPARE #define MAKE_SEMANTICS_FCMP(fcc) \ - DEF_SEM(FCMPS_ ## fcc, RF32 src1, RF32 src2) { \ + DEF_SEM(FCMPS_##fcc, RF32 src1, RF32 src2) { \ auto val1 = Read(src1); \ auto val2 = Read(src2); \ - FCompare_ ## fcc(state, memory, val1, val2, false); \ + FCompare_##fcc(state, memory, val1, val2, false); \ return memory; \ } \ - \ - DEF_SEM(FCMPD_ ## fcc, RF64 src1, RF64 src2) { \ +\ + DEF_SEM(FCMPD_##fcc, RF64 src1, RF64 src2) { \ auto val1 = Read(src1); \ auto val2 = Read(src2); \ - FCompare_ ## fcc(state, memory, val1, val2, false); \ + FCompare_##fcc(state, memory, val1, val2, false); \ return memory; \ } \ - \ - DEF_SEM(FCMPQ_ ## fcc, RF64 src1, RF64 src2) { \ +\ + DEF_SEM(FCMPQ_##fcc, RF64 src1, RF64 src2) { \ auto val1 = Read(src1); \ auto val2 = Read(src2); \ - FCompare_ ## fcc(state, memory, val1, val2, false); \ + FCompare_##fcc(state, memory, val1, val2, false); \ return memory; \ } #define MAKE_SEMANTICS_FCMPE(fcc) \ - DEF_SEM(FCMPES_ ## fcc, RF32 src1, RF32 src2) { \ + DEF_SEM(FCMPES_##fcc, RF32 src1, RF32 src2) { \ auto val1 = Read(src1); \ auto val2 = Read(src2); \ - FCompare_ ## fcc(state, memory, val1, val2, false); \ + FCompare_##fcc(state, memory, val1, val2, false); \ return memory; \ } \ - \ - DEF_SEM(FCMPED_ ## fcc, RF64 src1, RF64 src2) { \ +\ + DEF_SEM(FCMPED_##fcc, RF64 src1, RF64 src2) { \ auto val1 = Read(src1); \ auto val2 = Read(src2); \ - FCompare_ ## fcc(state, memory, val1, val2, false); \ + FCompare_##fcc(state, memory, val1, val2, false); \ return memory; \ } \ - \ - DEF_SEM(FCMPEQ_ ## fcc, RF64 src1, RF64 src2) { \ +\ + DEF_SEM(FCMPEQ_##fcc, RF64 src1, RF64 src2) { \ auto val1 = Read(src1); \ auto val2 = Read(src2); \ - FCompare_ ## fcc(state, memory, val1, val2, false); \ + FCompare_##fcc(state, memory, val1, val2, false); \ return memory; \ } @@ -552,7 +556,7 @@ MAKE_SEMANTICS_FCMPE(fcc1) MAKE_SEMANTICS_FCMPE(fcc2) MAKE_SEMANTICS_FCMPE(fcc3) -} +} // namespace #undef MAKE_SEMANTICS_FCMP #undef MAKE_SEMANTICS_FCMPE @@ -588,4 +592,3 @@ DEF_ISEL(FCMPEQ_fcc2) = FCMPEQ_fcc2; DEF_ISEL(FCMPES_fcc3) = FCMPES_fcc3; DEF_ISEL(FCMPED_fcc3) = FCMPED_fcc3; DEF_ISEL(FCMPEQ_fcc3) = FCMPEQ_fcc3; - diff --git a/lib/Arch/SPARC64/Semantics/LOGICAL.cpp b/lib/Arch/SPARC64/Semantics/LOGICAL.cpp index 70b3448b8..09524ae0a 100644 --- a/lib/Arch/SPARC64/Semantics/LOGICAL.cpp +++ b/lib/Arch/SPARC64/Semantics/LOGICAL.cpp @@ -18,8 +18,8 @@ namespace { -ALWAYS_INLINE void SetFlagsLogical( - State &state, uint64_t lhs, uint64_t rhs, uint64_t res) { +ALWAYS_INLINE void SetFlagsLogical(State &state, uint64_t lhs, uint64_t rhs, + uint64_t res) { const auto res_32 = static_cast(res); FLAG_ICC_CF = false; FLAG_ICC_ZF = ZeroFlag(res_32); @@ -32,7 +32,7 @@ ALWAYS_INLINE void SetFlagsLogical( FLAG_XCC_VF = false; } -} +} // namespace // Logical Operations namespace { @@ -56,7 +56,7 @@ DEF_SEM(ANDCC, S1 src1, S2 src2, D dst) { return memory; } -} +} // namespace // AND, ANDcc DEF_ISEL(AND) = AND; @@ -83,7 +83,7 @@ DEF_SEM(ANDNCC, S1 src1, S2 src2, D dst) { return memory; } -} +} // namespace // ANDN, ANDNcc DEF_ISEL(ANDN) = ANDN; @@ -110,7 +110,7 @@ DEF_SEM(ORCC, S1 src1, S2 src2, D dst) { return memory; } -} +} // namespace DEF_ISEL(OR) = OR; DEF_ISEL(ORcc) = ORCC; @@ -136,7 +136,7 @@ DEF_SEM(ORNCC, S1 src1, S2 src2, D dst) { return memory; } -} +} // namespace DEF_ISEL(ORN) = ORN; DEF_ISEL(ORNcc) = ORNCC; @@ -162,7 +162,7 @@ DEF_SEM(XORCC, S1 src1, S2 src2, D dst) { return memory; } -} +} // namespace DEF_ISEL(XOR) = XOR; DEF_ISEL(XORcc) = XORCC; @@ -188,7 +188,7 @@ DEF_SEM(XNORCC, S1 src1, S2 src2, D dst) { return memory; } -} +} // namespace DEF_ISEL(XNOR) = XNOR; DEF_ISEL(XNORcc) = XNORCC; @@ -231,4 +231,3 @@ DEF_ISEL(SRA) = SRA; DEF_ISEL(SLLX) = SLL; DEF_ISEL(SRLX) = SRL; DEF_ISEL(SRAX) = SRA; - diff --git a/lib/Arch/SPARC64/Semantics/MISC.cpp b/lib/Arch/SPARC64/Semantics/MISC.cpp index d0f011c41..de3f9c554 100644 --- a/lib/Arch/SPARC64/Semantics/MISC.cpp +++ b/lib/Arch/SPARC64/Semantics/MISC.cpp @@ -55,8 +55,8 @@ DEF_SEM(PREFETCH, M64 address, I32 fcn) { DEF_SEM(PREFETCHA, R8 asi, M64 address, I32 fcn) { HYPER_CALL_VECTOR = Read(asi); - return __remill_sync_hyper_call( - state, memory, SyncHyperCall::kSPARCSetAsiRegister); + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCSetAsiRegister); } } // namespace @@ -71,7 +71,8 @@ DEF_ISEL(PREFETCHA) = PREFETCHA; namespace { template -DEF_SEM(SAVE, S1 src1, S2 src2, D dst, RegisterWindow *window, RegisterWindow *&prev_window) { +DEF_SEM(SAVE, S1 src1, S2 src2, D dst, RegisterWindow *window, + RegisterWindow *&prev_window) { addr_t sp_base = Read(src1); addr_t sp_offset = Read(src2); addr_t new_sp = UAdd(sp_base, sp_offset); diff --git a/lib/Arch/SPARC64/Semantics/TRAP.cpp b/lib/Arch/SPARC64/Semantics/TRAP.cpp index be15813ea..3165f2f96 100644 --- a/lib/Arch/SPARC64/Semantics/TRAP.cpp +++ b/lib/Arch/SPARC64/Semantics/TRAP.cpp @@ -22,47 +22,52 @@ // is placed inside of a delay slot. #define MAKE_TRAP(cond, cc) \ namespace { \ - DEF_SEM(T ## cond ## _ ## cc, R8W branch_taken, PC new_pc, PC new_npc, \ - I32 vec_a, I32 vec_b, R64W pc_dst, R64W npc_dst) { \ - Write(branch_taken, Cond ## cond ## _ ## cc(state)); \ - HYPER_CALL = AsyncHyperCall::kSPARCTrapCond ## cond; \ + DEF_SEM(T##cond##_##cc, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, \ + I32 vec_b, R64W pc_dst, R64W npc_dst) { \ + Write(branch_taken, Cond##cond##_##cc(state)); \ + HYPER_CALL = AsyncHyperCall::kSPARCTrapCond##cond; \ HYPER_CALL_VECTOR = UAnd(UAdd(Read(vec_a), Read(vec_b)), 0x7fu); \ return memory; \ } \ - DEF_SEM(T ## cond ## _sync ## _ ## cc, R8W branch_taken, PC new_pc, PC new_npc, \ + DEF_SEM(T##cond##_sync##_##cc, R8W branch_taken, PC new_pc, PC new_npc, \ I32 vec_a, I32 vec_b, R64W pc_dst, R64W npc_dst) { \ - Write(branch_taken, Cond ## cond ## _ ## cc(state)); \ - HYPER_CALL = AsyncHyperCall::kSPARCTrapCond ## cond; \ + Write(branch_taken, Cond##cond##_##cc(state)); \ + HYPER_CALL = AsyncHyperCall::kSPARCTrapCond##cond; \ HYPER_CALL_VECTOR = UAnd(UAdd(Read(vec_a), Read(vec_b)), 0x7fu); \ - return __remill_sync_hyper_call( \ - state, memory, SyncHyperCall::kSPARCTrapCond ## cond); \ + return __remill_sync_hyper_call(state, memory, \ + SyncHyperCall::kSPARCTrapCond##cond); \ } \ } \ - DEF_ISEL(T ## cond ## _ ## cc) = T ## cond ## _ ## cc; \ - DEF_ISEL(T ## cond ## _sync ## _ ## cc) = T ## cond ## _sync ## _ ## cc + DEF_ISEL(T##cond##_##cc) = T##cond##_##cc; \ + DEF_ISEL(T##cond##_sync##_##cc) = T##cond##_sync##_##cc namespace { -DEF_SEM(TA, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, R64W pc_dst, R64W npc_dst) { +DEF_SEM(TA, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, + R64W pc_dst, R64W npc_dst) { HYPER_CALL = AsyncHyperCall::kSPARCTrapCondA; HYPER_CALL_VECTOR = UAnd(UAdd(Read(vec_a), Read(vec_b)), 0x7fu); Write(branch_taken, true); return memory; } -DEF_SEM(TA_sync, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, R64W pc_dst, R64W npc_dst) { +DEF_SEM(TA_sync, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, + R64W pc_dst, R64W npc_dst) { HYPER_CALL = AsyncHyperCall::kSPARCTrapCondA; HYPER_CALL_VECTOR = UAnd(UAdd(Read(vec_a), Read(vec_b)), 0x7fu); - return __remill_sync_hyper_call(state, memory, SyncHyperCall::kSPARCTrapCondA); + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kSPARCTrapCondA); } -DEF_SEM(TN, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, R64W pc_dst, R64W npc_dst) { +DEF_SEM(TN, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, + R64W pc_dst, R64W npc_dst) { Write(pc_dst, Read(new_pc)); Write(npc_dst, Read(new_npc)); return memory; } -DEF_SEM(TN_sync, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, R64W pc_dst, R64W npc_dst) { +DEF_SEM(TN_sync, R8W branch_taken, PC new_pc, PC new_npc, I32 vec_a, I32 vec_b, + R64W pc_dst, R64W npc_dst) { return memory; } @@ -128,4 +133,3 @@ DEF_SEM(ILLTRAP_ASYNC, I32 struct_size) { DEF_ISEL(ILLTRAP_SYNC) = ILLTRAP_SYNC; // In a delay slot. DEF_ISEL(ILLTRAP_ASYNC) = ILLTRAP_ASYNC; // Not in a delay slot. - diff --git a/lib/Arch/SPARC64/Semantics/VIS.cpp b/lib/Arch/SPARC64/Semantics/VIS.cpp index 3b7101cdb..778fc0e46 100644 --- a/lib/Arch/SPARC64/Semantics/VIS.cpp +++ b/lib/Arch/SPARC64/Semantics/VIS.cpp @@ -54,27 +54,29 @@ DEF_SEM(EDGE8CC, R64 src1, R64 src2, R64W dst) { auto rs2 = Read(src2); auto imask = Literal(0x7); auto shift = Literal(3); - auto omask= Literal(0xff); + auto omask = Literal(0xff); + // l1 = rs1 & 0x7 rs[3:0] auto l1 = UAnd(rs1, imask); auto rs1_shifted = UShr(rs1, shift); + // l2 = rs2 & 0x7 rs[3:0] auto l2 = UAnd(rs2, imask); auto rs2_shifted = UShr(rs2, shift); auto left_edge = UShr(omask, decltype(omask)(l1)); auto right_edge = UShl(omask, decltype(omask)(USub(imask, l2))); - auto value = Select( - UCmpEq(rs1_shifted, rs2_shifted), - left_edge, UAnd(right_edge, left_edge)); + auto value = Select(UCmpEq(rs1_shifted, rs2_shifted), left_edge, + UAnd(right_edge, left_edge)); auto diff = USub(rs1, rs2); - WriteICCFlagsAddSub(state, Literal(rs1), Literal(rs2), Literal(diff)); + WriteICCFlagsAddSub(state, Literal(rs1), + Literal(rs2), Literal(diff)); WriteXCCFlagsAddSub(state, rs1, rs2, diff); WriteZExt(dst, value); return memory; } -} +} // namespace DEF_ISEL(FORS) = PACK_ORS; DEF_ISEL(FORD) = PACK_ORD; @@ -89,17 +91,20 @@ namespace { DEF_SEM(IMPDEP1, I32 opf) { HYPER_CALL_VECTOR = Literal(Read(opf)); return __remill_sync_hyper_call( - state, memory, SyncHyperCall::IF_32BIT_ELSE(kSPARC32EmulateInstruction, kSPARC64EmulateInstruction)); + state, memory, + SyncHyperCall::IF_32BIT_ELSE(kSPARC32EmulateInstruction, + kSPARC64EmulateInstruction)); } DEF_SEM(IMPDEP2, I32 opf) { HYPER_CALL_VECTOR = Literal(Read(opf)); return __remill_sync_hyper_call( - state, memory, SyncHyperCall::IF_32BIT_ELSE(kSPARC32EmulateInstruction, kSPARC64EmulateInstruction)); + state, memory, + SyncHyperCall::IF_32BIT_ELSE(kSPARC32EmulateInstruction, + kSPARC64EmulateInstruction)); } -} +} // namespace DEF_ISEL(IMPDEP1) = IMPDEP1; DEF_ISEL(IMPDEP2) = IMPDEP2; - diff --git a/lib/Arch/SPARC64/Semantics/WRASR.cpp b/lib/Arch/SPARC64/Semantics/WRASR.cpp index b0594538d..d4311f010 100644 --- a/lib/Arch/SPARC64/Semantics/WRASR.cpp +++ b/lib/Arch/SPARC64/Semantics/WRASR.cpp @@ -21,15 +21,15 @@ #define MAKE_SEMANTICS_WR(op) \ namespace { \ - DEF_SEM(WR ## op, R32 src1, I32 src2) { \ - auto lhs = Read(src1); \ - auto rhs = Read(src2); \ - auto res = UXor(lhs, rhs); \ - WriteZExt(ASR_ ## op, res); \ - return memory; \ - } \ + DEF_SEM(WR##op, R32 src1, I32 src2) { \ + auto lhs = Read(src1); \ + auto rhs = Read(src2); \ + auto res = UXor(lhs, rhs); \ + WriteZExt(ASR_##op, res); \ + return memory; \ } \ - DEF_ISEL(WR ## op) = WR ## op; + } \ + DEF_ISEL(WR##op) = WR##op; MAKE_SEMANTICS_WR(Y) MAKE_SEMANTICS_WR(PAUSE) @@ -41,21 +41,21 @@ MAKE_SEMANTICS_WR(ASI) #define MAKE_SEMANTICS_RD(op) \ namespace { \ - DEF_SEM(RD ## op, R64W dst) { \ - auto asr = Read(ASR_ ## op); \ - WriteZExt(dst, asr); \ - return memory; \ - } \ + DEF_SEM(RD##op, R64W dst) { \ + auto asr = Read(ASR_##op); \ + WriteZExt(dst, asr); \ + return memory; \ + } \ } \ - DEF_ISEL(RD ## op) = RD ## op; + DEF_ISEL(RD##op) = RD##op; MAKE_SEMANTICS_RD(Y) MAKE_SEMANTICS_RD(ASI) + //MAKE_SEMANTICS_RD(PC) MAKE_SEMANTICS_RD(FPRS) - namespace { template @@ -192,7 +192,7 @@ DEF_SEM(WRPRGL, R64 src1, R src2) { WriteTrunc(PSR_GL, res); return memory; } -} +} // namespace DEF_ISEL(WRPRTPC) = WRPRTPC; DEF_ISEL(WRPRTPC_IMM) = WRPRTPC; diff --git a/lib/Arch/X86/Arch.cpp b/lib/Arch/X86/Arch.cpp index f831989e2..c79fe0bca 100644 --- a/lib/Arch/X86/Arch.cpp +++ b/lib/Arch/X86/Arch.cpp @@ -30,6 +30,7 @@ #include #include +#include "XED.h" #include "remill/Arch/Instruction.h" #include "remill/Arch/Name.h" #include "remill/BC/ABI.h" @@ -37,8 +38,6 @@ #include "remill/BC/Version.h" #include "remill/OS/OS.h" -#include "XED.h" - // clang-format off #define HAS_FEATURE_AVX 1 #define HAS_FEATURE_AVX512 1 @@ -809,7 +808,6 @@ class X86Arch final : public Arch { llvm::Function *bb_func) const override; private: - X86Arch(void) = delete; }; @@ -1067,8 +1065,8 @@ bool X86Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes, if (xed_decoded_inst_is_xacquire(xedd) || xed_decoded_inst_is_xrelease(xedd)) { - LOG(ERROR) << "Ignoring XACQUIRE/XRELEASE prefix at " << std::hex - << inst.pc << std::dec; + LOG(ERROR) << "Ignoring XACQUIRE/XRELEASE prefix at " << std::hex << inst.pc + << std::dec; } // Make sure we disallow decoding of AVX instructions when running with non- diff --git a/lib/Arch/X86/Runtime/Instructions.cpp b/lib/Arch/X86/Runtime/Instructions.cpp index ce9dae4b9..895f0ec9e 100644 --- a/lib/Arch/X86/Runtime/Instructions.cpp +++ b/lib/Arch/X86/Runtime/Instructions.cpp @@ -165,11 +165,12 @@ DEF_HELPER(PopFromStack)->T { return val; } -DEF_HELPER(SquareRoot32, float32_t src_float) -> float32_t { +DEF_HELPER(SquareRoot32, float32_t src_float)->float32_t { auto square_root = src_float; // Special cases for invalid square root operations. See Intel manual, Table E-10. if (IsNaN(src_float)) { + // If src is SNaN, return the SNaN converted to a QNaN: if (IsSignalingNaN(src_float)) { nan32_t temp_nan = {src_float}; @@ -181,6 +182,7 @@ DEF_HELPER(SquareRoot32, float32_t src_float) -> float32_t { square_root = src_float; } } else { // a number, that is, not a NaN + // A negative operand (except -0.0) results in the QNaN indefinite value. if (IsNegative(src_float) && src_float != -0.0) { uint32_t indef_qnan = 0xFFC00000U; diff --git a/lib/Arch/X86/Semantics/AVX.cpp b/lib/Arch/X86/Semantics/AVX.cpp index 4f1837b6b..600068d47 100644 --- a/lib/Arch/X86/Semantics/AVX.cpp +++ b/lib/Arch/X86/Semantics/AVX.cpp @@ -42,13 +42,13 @@ DEF_SEM(VPBROADCASTB, D dst, S1 src1) { return memory; } -template +template DEF_SEM(VINSERTF128, VV256W dst, V256 src1, S2 src2, I8 src3) { auto dst_vec = UReadV128(src1); auto src2_vec = UReadV128(src2); auto src3_i8 = Read(src3); auto i = static_cast(src3_i8 & 1u); - dst_vec = UInsertV128(dst_vec, i, UExtractV128(src2_vec, 0)); + dst_vec = UInsertV128(dst_vec, i, UExtractV128(src2_vec, 0)); UWriteV128(dst, dst_vec); return memory; } diff --git a/lib/Arch/X86/Semantics/MISC.cpp b/lib/Arch/X86/Semantics/MISC.cpp index fa3afbc3c..81d779b9e 100644 --- a/lib/Arch/X86/Semantics/MISC.cpp +++ b/lib/Arch/X86/Semantics/MISC.cpp @@ -15,6 +15,7 @@ */ #pragma once + // Disable the "loop not unrolled warnings" #pragma clang diagnostic ignored "-Wpass-failed" @@ -115,7 +116,7 @@ DEF_SEM(DoNothing) { return memory; } -template +template DEF_SEM(DoNothingWithParam, Args...) { return memory; } @@ -176,9 +177,11 @@ DEF_ISEL(XLAT) = DoXLAT; DEF_ISEL(CPUID) = DoCPUID; -DEF_ISEL(UD0_GPR32_MEMd) = DoNothingWithParam; +DEF_ISEL(UD0_GPR32_MEMd) = + DoNothingWithParam; -DEF_ISEL(UD1_GPR32_MEMd) = DoNothingWithParam; +DEF_ISEL(UD1_GPR32_MEMd) = + DoNothingWithParam; DEF_ISEL(UD2) = DoNothingWithParam; diff --git a/lib/Arch/X86/Semantics/MMX.cpp b/lib/Arch/X86/Semantics/MMX.cpp index 362d668d2..84dc31812 100644 --- a/lib/Arch/X86/Semantics/MMX.cpp +++ b/lib/Arch/X86/Semantics/MMX.cpp @@ -1961,8 +1961,7 @@ DEF_SEM(PFMAX, D dst, S1 src_dst, S2 src) { auto src1 = FReadV32(src_dst); auto src2 = FReadV32(src); auto out = src1; - _Pragma("unroll") - for (auto i = 0u; i < 2; ++i) { + _Pragma("unroll") for (auto i = 0u; i < 2; ++i) { auto s1_val = FExtractV32(src1, i); auto s2_val = FExtractV32(src2, i); if (!std::isunordered(s1_val, s2_val) && s2_val > s1_val) { @@ -1978,8 +1977,7 @@ DEF_SEM(PFMIN, D dst, S1 src_dst, S2 src) { auto src1 = FReadV32(src_dst); auto src2 = FReadV32(src); auto out = src1; - _Pragma("unroll") - for (auto i = 0u; i < 2; ++i) { + _Pragma("unroll") for (auto i = 0u; i < 2; ++i) { auto s1_val = FExtractV32(src1, i); auto s2_val = FExtractV32(src2, i); if (!std::isunordered(s1_val, s2_val) && s2_val < s1_val) { @@ -1995,8 +1993,7 @@ DEF_SEM(PFCMPGT, D dst, S1 src_dst, S2 src) { auto src1 = FReadV32(src_dst); auto src2 = FReadV32(src); uint32v2_t out = {}; - _Pragma("unroll") - for (auto i = 0u; i < 2; ++i) { + _Pragma("unroll") for (auto i = 0u; i < 2; ++i) { auto s1_val = FExtractV32(src1, i); auto s2_val = FExtractV32(src2, i); if (!std::isunordered(s1_val, s2_val) && s1_val > s2_val) { @@ -2012,8 +2009,7 @@ DEF_SEM(PFCMPGE, D dst, S1 src_dst, S2 src) { auto src1 = FReadV32(src_dst); auto src2 = FReadV32(src); uint32v2_t out = {}; - _Pragma("unroll") - for (auto i = 0u; i < 2; ++i) { + _Pragma("unroll") for (auto i = 0u; i < 2; ++i) { auto s1_val = FExtractV32(src1, i); auto s2_val = FExtractV32(src2, i); if (!std::isunordered(s1_val, s2_val) && s1_val >= s2_val) { @@ -2029,8 +2025,7 @@ DEF_SEM(PFCMPEQ, D dst, S1 src_dst, S2 src) { auto src1 = FReadV32(src_dst); auto src2 = FReadV32(src); uint32v2_t out = {}; - _Pragma("unroll") - for (auto i = 0u; i < 2; ++i) { + _Pragma("unroll") for (auto i = 0u; i < 2; ++i) { auto s1_val = FExtractV32(src1, i); auto s2_val = FExtractV32(src2, i); if (!std::isunordered(s1_val, s2_val) && s1_val == s2_val) { @@ -2045,8 +2040,10 @@ template DEF_SEM(PFRSQRT, D dst, S1, S2 src) { auto src2 = FReadV32(src); auto out = FClearV32(FReadV32(dst)); - out = FInsertV32(out, 0, FDiv(1.0f, SquareRoot32(memory, state, FExtractV32(src2, 0)))); - out = FInsertV32(out, 1, FDiv(1.0f, SquareRoot32(memory, state, FExtractV32(src2, 1)))); + out = FInsertV32( + out, 0, FDiv(1.0f, SquareRoot32(memory, state, FExtractV32(src2, 0)))); + out = FInsertV32( + out, 1, FDiv(1.0f, SquareRoot32(memory, state, FExtractV32(src2, 1)))); FWriteV32(dst, out); return memory; } diff --git a/lib/Arch/X86/Semantics/SEMAPHORE.cpp b/lib/Arch/X86/Semantics/SEMAPHORE.cpp index 67c3a8c11..ff9413771 100644 --- a/lib/Arch/X86/Semantics/SEMAPHORE.cpp +++ b/lib/Arch/X86/Semantics/SEMAPHORE.cpp @@ -17,20 +17,20 @@ namespace { #define MAKE_CMPXCHG_XAX(xax, xax_write, xax_read) \ - template \ - DEF_SEM(CMPXCHG_ ## xax, D dst, S1 src1, S2 src2) { \ - auto desired_val = Read(src2); \ - auto check_val = Read(REG_ ## xax_read); \ - auto prev_value = check_val; \ - auto swap_flag = UCmpXchg(dst, check_val, desired_val); \ - auto sub_res = USub(prev_value, check_val); \ - WriteFlagsAddSub(state, prev_value, check_val, sub_res); \ - Write(FLAG_ZF, swap_flag); \ - if (!swap_flag) { \ - WriteZExt(REG_ ## xax_write, check_val); \ - } \ - return memory; \ - } + template \ + DEF_SEM(CMPXCHG_##xax, D dst, S1 src1, S2 src2) { \ + auto desired_val = Read(src2); \ + auto check_val = Read(REG_##xax_read); \ + auto prev_value = check_val; \ + auto swap_flag = UCmpXchg(dst, check_val, desired_val); \ + auto sub_res = USub(prev_value, check_val); \ + WriteFlagsAddSub(state, prev_value, check_val, sub_res); \ + Write(FLAG_ZF, swap_flag); \ + if (!swap_flag) { \ + WriteZExt(REG_##xax_write, check_val); \ + } \ + return memory; \ + } MAKE_CMPXCHG_XAX(AL, AL, AL) MAKE_CMPXCHG_XAX(AX, AX, AX) diff --git a/lib/Arch/X86/Semantics/SSE.cpp b/lib/Arch/X86/Semantics/SSE.cpp index dfd457a2a..9f8851830 100644 --- a/lib/Arch/X86/Semantics/SSE.cpp +++ b/lib/Arch/X86/Semantics/SSE.cpp @@ -15,6 +15,7 @@ */ #pragma once + // Disable the "loop not unrolled warnings" #pragma clang diagnostic ignored "-Wpass-failed" @@ -1631,6 +1632,7 @@ namespace { template DEF_SEM(SQRTSS, D dst, S1 src1) { + // Extract a "single-precision" (32-bit) float from [31:0] of src1 vector: auto src_float = FExtractV32(FReadV32(src1), 0); @@ -1640,7 +1642,7 @@ DEF_SEM(SQRTSS, D dst, S1 src1) { temp_vec = FInsertV32(temp_vec, 0, square_root); // Write out the result and return memory state: - FWriteV32(dst, temp_vec); // SSE: Writes to XMM, AVX: Zero-extends XMM. + FWriteV32(dst, temp_vec); // SSE: Writes to XMM, AVX: Zero-extends XMM. return memory; } @@ -1681,6 +1683,7 @@ DEF_SEM(VSQRTSS, D dst, S1 src1, S2 src2) { template DEF_SEM(VRSQRTSS, D dst, S1 src1, S2 src2) { + // Extract the single-precision float from [31:0] of the src2 vector: auto src_float = FExtractV32(FReadV32(src2), 0); diff --git a/lib/BC/ABI.cpp b/lib/BC/ABI.cpp index 4492cdcd9..e9a353d9c 100644 --- a/lib/BC/ABI.cpp +++ b/lib/BC/ABI.cpp @@ -26,6 +26,7 @@ const std::string_view kReturnPCVariableName = "RETURN_PC"; const std::string_view kBranchTakenVariableName = "BRANCH_TAKEN"; const std::string_view kInvalidInstructionISelName = "INVALID_INSTRUCTION"; -const std::string_view kUnsupportedInstructionISelName = "UNSUPPORTED_INSTRUCTION"; +const std::string_view kUnsupportedInstructionISelName = + "UNSUPPORTED_INSTRUCTION"; } // namespace remill diff --git a/lib/BC/DeadStoreEliminator.cpp b/lib/BC/DeadStoreEliminator.cpp index ee3bd7084..48a42f18e 100644 --- a/lib/BC/DeadStoreEliminator.cpp +++ b/lib/BC/DeadStoreEliminator.cpp @@ -36,9 +36,9 @@ #include #include "remill/Arch/Arch.h" +#include "remill/BC/ABI.h" #include "remill/BC/Compat/CallSite.h" #include "remill/BC/Compat/VectorType.h" -#include "remill/BC/ABI.h" #include "remill/BC/Util.h" #include "remill/OS/FileSystem.h" @@ -417,7 +417,7 @@ static void StreamCallOrInvokeToDOT(std::ostream &dot, LOG(ERROR) << "Encountered callsite that is not call nor invoke!"; } - if(!cs.getCalledValue()->getName().empty()) { + if (!cs.getCalledValue()->getName().empty()) { dot << cs.getCalledValue()->getName().str(); } else { dot << cs.getCalledValue()->getValueID(); @@ -1136,8 +1136,10 @@ VisitResult ForwardAliasVisitor::visitPHINode(llvm::PHINode &inst) { } VisitResult ForwardAliasVisitor::visitCallInst(llvm::CallInst &inst) { + //const auto val = inst.getCalledOperand()->stripPointerCasts(); - const auto val = compat::llvm::CallSite(&inst).getCalledValue()->stripPointerCasts(); + const auto val = + compat::llvm::CallSite(&inst).getCalledValue()->stripPointerCasts(); if (auto const_val = llvm::dyn_cast(val); const_val) { // Don't let this affect anything. @@ -1189,7 +1191,8 @@ VisitResult ForwardAliasVisitor::visitCallInst(llvm::CallInst &inst) { } VisitResult ForwardAliasVisitor::visitInvokeInst(llvm::InvokeInst &inst) { - auto val = compat::llvm::CallSite(&inst).getCalledValue()->stripPointerCasts(); + auto val = + compat::llvm::CallSite(&inst).getCalledValue()->stripPointerCasts(); if (llvm::isa(val)) { live_args[&inst].set(); // Weird to invoke inline assembly. diff --git a/lib/BC/InstructionLifter.cpp b/lib/BC/InstructionLifter.cpp index 268dda89c..330bb8798 100644 --- a/lib/BC/InstructionLifter.cpp +++ b/lib/BC/InstructionLifter.cpp @@ -55,12 +55,12 @@ InstructionLifter::Impl::Impl(const Arch *arch_, unsupported_instruction( GetInstructionFunction(module, kUnsupportedInstructionISelName)) { - CHECK(invalid_instruction != nullptr) - << kInvalidInstructionISelName << " doesn't exist"; + CHECK(invalid_instruction != nullptr) + << kInvalidInstructionISelName << " doesn't exist"; - CHECK(unsupported_instruction != nullptr) - << kUnsupportedInstructionISelName << " doesn't exist"; - } + CHECK(unsupported_instruction != nullptr) + << kUnsupportedInstructionISelName << " doesn't exist"; +} InstructionLifter::~InstructionLifter(void) {} @@ -114,9 +114,11 @@ LiftStatus InstructionLifter::LiftIntoBlock(Instruction &arch_inst, } llvm::IRBuilder<> ir(block); - const auto mem_ptr_ref = LoadRegAddress(block, state_ptr, kMemoryVariableName); + const auto mem_ptr_ref = + LoadRegAddress(block, state_ptr, kMemoryVariableName); const auto pc_ref = LoadRegAddress(block, state_ptr, kPCVariableName); - const auto next_pc_ref = LoadRegAddress(block, state_ptr, kNextPCVariableName); + const auto next_pc_ref = + LoadRegAddress(block, state_ptr, kNextPCVariableName); const auto next_pc = ir.CreateLoad(next_pc_ref); // If this instruction appears within a delay slot, then we're going to assume @@ -140,9 +142,8 @@ LiftStatus InstructionLifter::LiftIntoBlock(Instruction &arch_inst, // the program counter in the semantics code. ir.CreateStore(next_pc, pc_ref); ir.CreateStore( - ir.CreateAdd(next_pc, - llvm::ConstantInt::get(impl->word_type, - arch_inst.bytes.size())), + ir.CreateAdd(next_pc, llvm::ConstantInt::get(impl->word_type, + arch_inst.bytes.size())), next_pc_ref); } @@ -217,9 +218,10 @@ LiftStatus InstructionLifter::LiftIntoBlock(Instruction &arch_inst, } // Load the address of a register. -llvm::Value *InstructionLifter::LoadRegAddress( - llvm::BasicBlock *block, llvm::Value *state_ptr, - std::string_view reg_name_) const { +llvm::Value * +InstructionLifter::LoadRegAddress(llvm::BasicBlock *block, + llvm::Value *state_ptr, + std::string_view reg_name_) const { const auto func = block->getParent(); // Invalidate the cache. @@ -231,8 +233,8 @@ llvm::Value *InstructionLifter::LoadRegAddress( } std::string reg_name(reg_name_.data(), reg_name_.size()); - auto [reg_ptr_it, added] = impl->reg_ptr_cache.emplace( - std::move(reg_name), nullptr); + auto [reg_ptr_it, added] = + impl->reg_ptr_cache.emplace(std::move(reg_name), nullptr); if (reg_ptr_it->second) { (void) added; @@ -281,8 +283,7 @@ llvm::Value *InstructionLifter::LoadRegAddress( return reg_ptr; } else { - LOG(FATAL) - << "Could not locate variable or register " << reg_name_; + LOG(FATAL) << "Could not locate variable or register " << reg_name_; return nullptr; } } @@ -294,9 +295,9 @@ void InstructionLifter::ClearCache(void) const { } // Load the value of a register. -llvm::Value *InstructionLifter::LoadRegValue( - llvm::BasicBlock *block, llvm::Value *state_ptr, - std::string_view reg_name) const { +llvm::Value *InstructionLifter::LoadRegValue(llvm::BasicBlock *block, + llvm::Value *state_ptr, + std::string_view reg_name) const { auto ptr = LoadRegAddress(block, state_ptr, reg_name); CHECK_NOTNULL(ptr); auto ptr_ty = ptr->getType()->getPointerElementType(); @@ -304,9 +305,10 @@ llvm::Value *InstructionLifter::LoadRegValue( } // Return a register value, or zero. -llvm::Value *InstructionLifter::LoadWordRegValOrZero( - llvm::BasicBlock *block, llvm::Value *state_ptr, - std::string_view reg_name, llvm::ConstantInt *zero) { +llvm::Value *InstructionLifter::LoadWordRegValOrZero(llvm::BasicBlock *block, + llvm::Value *state_ptr, + std::string_view reg_name, + llvm::ConstantInt *zero) { if (reg_name.empty()) { return zero; @@ -631,7 +633,7 @@ InstructionLifter::LiftImmediateOperand(Instruction &inst, llvm::BasicBlock *, } // Lift an expression operand. -llvm::Value* InstructionLifter::LiftExpressionOperand(Instruction &inst, +llvm::Value *InstructionLifter::LiftExpressionOperand(Instruction &inst, llvm::BasicBlock *block, llvm::Value *state_ptr, llvm::Argument *arg, @@ -663,20 +665,20 @@ llvm::Value* InstructionLifter::LiftExpressionOperand(Instruction &inst, if (val_size < arg_size) { if (arg_type->isIntegerTy()) { CHECK(val_type->isIntegerTy()) - << "Expected " << op.Serialize() << " to be an integral type " - << "for instruction at " << std::hex << inst.pc; + << "Expected " << op.Serialize() << " to be an integral type " + << "for instruction at " << std::hex << inst.pc; CHECK(word_size == arg_size) - << "Expected integer argument to be machine word size (" - << word_size << " bits) but is is " << arg_size << " instead " - << "in instruction at " << std::hex << inst.pc; + << "Expected integer argument to be machine word size (" + << word_size << " bits) but is is " << arg_size << " instead " + << "in instruction at " << std::hex << inst.pc; val = new llvm::ZExtInst(val, impl->word_type, "", block); } else if (arg_type->isFloatingPointTy()) { CHECK(val_type->isFloatingPointTy()) - << "Expected " << op.Serialize() << " to be a floating point type " - << "for instruction at " << std::hex << inst.pc; + << "Expected " << op.Serialize() << " to be a floating point type " + << "for instruction at " << std::hex << inst.pc; val = new llvm::FPExtInst(val, arg_type, "", block); } @@ -684,20 +686,20 @@ llvm::Value* InstructionLifter::LiftExpressionOperand(Instruction &inst, } else if (val_size > arg_size) { if (arg_type->isIntegerTy()) { CHECK(val_type->isIntegerTy()) - << "Expected " << op.Serialize() << " to be an integral type " - << "for instruction at " << std::hex << inst.pc; + << "Expected " << op.Serialize() << " to be an integral type " + << "for instruction at " << std::hex << inst.pc; CHECK(word_size == arg_size) - << "Expected integer argument to be machine word size (" - << word_size << " bits) but is is " << arg_size << " instead " - << "in instruction at " << std::hex << inst.pc; + << "Expected integer argument to be machine word size (" + << word_size << " bits) but is is " << arg_size << " instead " + << "in instruction at " << std::hex << inst.pc; val = new llvm::TruncInst(val, arg_type, "", block); } else if (arg_type->isFloatingPointTy()) { CHECK(val_type->isFloatingPointTy()) - << "Expected " << op.Serialize() << " to be a floating point type " - << "for instruction at " << std::hex << inst.pc; + << "Expected " << op.Serialize() << " to be a floating point type " + << "for instruction at " << std::hex << inst.pc; val = new llvm::FPTruncInst(val, arg_type, "", block); } @@ -712,54 +714,41 @@ llvm::Value *InstructionLifter::LiftExpressionOperandRec( Instruction &inst, llvm::BasicBlock *block, llvm::Value *state_ptr, llvm::Argument *arg, const OperandExpression *op) { if (auto llvm_op = std::get_if(op)) { - auto lhs = LiftExpressionOperandRec(inst, block, state_ptr, nullptr, llvm_op->op1); - llvm::Value * rhs = nullptr; + auto lhs = + LiftExpressionOperandRec(inst, block, state_ptr, nullptr, llvm_op->op1); + llvm::Value *rhs = nullptr; if (llvm_op->op2) { - rhs = LiftExpressionOperandRec(inst, block, state_ptr, nullptr, llvm_op->op2); + rhs = LiftExpressionOperandRec(inst, block, state_ptr, nullptr, + llvm_op->op2); } llvm::IRBuilder<> ir(block); switch (llvm_op->llvm_opcode) { - case llvm::Instruction::Add: - return ir.CreateAdd(lhs, rhs); - case llvm::Instruction::Sub: - return ir.CreateSub(lhs, rhs); - case llvm::Instruction::Mul: - return ir.CreateMul(lhs, rhs); - case llvm::Instruction::Shl: - return ir.CreateShl(lhs, rhs); - case llvm::Instruction::LShr: - return ir.CreateLShr(lhs, rhs); - case llvm::Instruction::AShr: - return ir.CreateAShr(lhs, rhs); - case llvm::Instruction::ZExt: - return ir.CreateZExt(lhs, op->type); - case llvm::Instruction::SExt: - return ir.CreateSExt(lhs, op->type); - case llvm::Instruction::Trunc: - return ir.CreateTrunc(lhs, op->type); - case llvm::Instruction::And: - return ir.CreateAnd(lhs, rhs); - case llvm::Instruction::Or: - return ir.CreateOr(lhs, rhs); - case llvm::Instruction::URem: - return ir.CreateURem(lhs, rhs); - case llvm::Instruction::Xor: - return ir.CreateXor(lhs, rhs); + case llvm::Instruction::Add: return ir.CreateAdd(lhs, rhs); + case llvm::Instruction::Sub: return ir.CreateSub(lhs, rhs); + case llvm::Instruction::Mul: return ir.CreateMul(lhs, rhs); + case llvm::Instruction::Shl: return ir.CreateShl(lhs, rhs); + case llvm::Instruction::LShr: return ir.CreateLShr(lhs, rhs); + case llvm::Instruction::AShr: return ir.CreateAShr(lhs, rhs); + case llvm::Instruction::ZExt: return ir.CreateZExt(lhs, op->type); + case llvm::Instruction::SExt: return ir.CreateSExt(lhs, op->type); + case llvm::Instruction::Trunc: return ir.CreateTrunc(lhs, op->type); + case llvm::Instruction::And: return ir.CreateAnd(lhs, rhs); + case llvm::Instruction::Or: return ir.CreateOr(lhs, rhs); + case llvm::Instruction::URem: return ir.CreateURem(lhs, rhs); + case llvm::Instruction::Xor: return ir.CreateXor(lhs, rhs); default: - LOG(FATAL) - << "Invalid Expression " - << llvm::Instruction::getOpcodeName(llvm_op->llvm_opcode) ; + LOG(FATAL) << "Invalid Expression " + << llvm::Instruction::getOpcodeName(llvm_op->llvm_opcode); return nullptr; - } - } else if (auto reg_op = std::get_if(op)) { + } else if (auto reg_op = std::get_if(op)) { if (!arg || !llvm::isa(arg->getType())) { return LoadRegValue(block, state_ptr, (*reg_op)->name); } else { return LoadRegAddress(block, state_ptr, (*reg_op)->name); } - } else if (auto ci_op = std::get_if(op)) { + } else if (auto ci_op = std::get_if(op)) { return *ci_op; } else if (auto str_op = std::get_if(op)) { @@ -873,8 +862,8 @@ InstructionLifter::LiftOperand(Instruction &inst, llvm::BasicBlock *block, LOG(FATAL) << "Expected that a memory operand should be represented by " << "machine word type. Argument type is " << LLVMThingToString(arg_type) << " and word type is " - << LLVMThingToString(impl->word_type) << " in instruction at " - << std::hex << inst.pc; + << LLVMThingToString(impl->word_type) + << " in instruction at " << std::hex << inst.pc; } return LiftAddressOperand(inst, block, state_ptr, arg, arch_op); diff --git a/lib/BC/InstructionLifter.h b/lib/BC/InstructionLifter.h index 0f43e714f..f85f306c5 100644 --- a/lib/BC/InstructionLifter.h +++ b/lib/BC/InstructionLifter.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#include - +#include #include #include #include @@ -33,8 +32,7 @@ #include #include #include - -#include +#include #include #include @@ -76,9 +74,9 @@ class InstructionLifter::Impl { // clear out `reg_ptr_cache`. llvm::Function *last_func{nullptr}; - llvm::Module * const module; - llvm::Function * const invalid_instruction; - llvm::Function * const unsupported_instruction; + llvm::Module *const module; + llvm::Function *const invalid_instruction; + llvm::Function *const unsupported_instruction; }; } // namespace remill diff --git a/lib/BC/TraceLifter.cpp b/lib/BC/TraceLifter.cpp index 26a2a1bf0..b087dd04a 100644 --- a/lib/BC/TraceLifter.cpp +++ b/lib/BC/TraceLifter.cpp @@ -16,15 +16,13 @@ #include -#include "InstructionLifter.h" - #include #include -namespace remill { -namespace { +#include "InstructionLifter.h" -} // namespace +namespace remill { +namespace {} // namespace TraceManager::~TraceManager(void) {} @@ -152,7 +150,8 @@ TraceLifter::Impl::Impl(InstructionLifter *inst_lifter_, TraceManager *manager_) intrinsics(inst_lifter.impl->intrinsics), context(inst_lifter.impl->word_type->getContext()), module(intrinsics->async_hyper_call->getParent()), - addr_mask(arch->address_size >= 64 ? ~0ULL : (~0ULL >> arch->address_size)), + addr_mask(arch->address_size >= 64 ? ~0ULL + : (~0ULL >> arch->address_size)), manager(*manager_), func(nullptr), block(nullptr), @@ -301,8 +300,8 @@ bool TraceLifter::Impl::Lift( if (auto entry_block = &(func->front())) { auto pc = LoadProgramCounterArg(func); - auto next_pc_ref = - inst_lifter.LoadRegAddress(entry_block, state_ptr, kNextPCVariableName); + auto next_pc_ref = inst_lifter.LoadRegAddress(entry_block, state_ptr, + kNextPCVariableName); // Initialize `NEXT_PC`. (void) new llvm::StoreInst(pc, next_pc_ref, entry_block); @@ -607,8 +606,8 @@ bool TraceLifter::Impl::Lift( check_call_return: do { auto pc = LoadProgramCounter(block); - auto ret_pc = - llvm::ConstantInt::get(inst_lifter.impl->word_type, inst.next_pc); + auto ret_pc = llvm::ConstantInt::get(inst_lifter.impl->word_type, + inst.next_pc); llvm::IRBuilder<> ir(block); auto eq = ir.CreateICmpEQ(pc, ret_pc); @@ -630,7 +629,7 @@ bool TraceLifter::Impl::Lift( AddTerminatingTailCall(taken_block, intrinsics->function_return); auto not_taken_block = GetOrCreateBranchNotTakenBlock(); llvm::BranchInst::Create(taken_block, not_taken_block, - LoadBranchTaken(block), block); + LoadBranchTaken(block), block); break; } @@ -672,8 +671,8 @@ bool TraceLifter::Impl::Lift( // and its original targets. if (try_delay) { auto new_taken_block = llvm::BasicBlock::Create(context, "", func); - auto new_not_taken_block = llvm::BasicBlock::Create(context, "", - func); + auto new_not_taken_block = + llvm::BasicBlock::Create(context, "", func); try_add_delay_slot(true, new_taken_block); try_add_delay_slot(false, new_not_taken_block); diff --git a/lib/BC/Util.cpp b/lib/BC/Util.cpp index 06f9c2977..c1a8a4548 100644 --- a/lib/BC/Util.cpp +++ b/lib/BC/Util.cpp @@ -115,8 +115,8 @@ llvm::CallInst *AddCall(llvm::BasicBlock *source_block, arg_types[kStatePointerArgNum] = args[kStatePointerArgNum]->getType(); arg_types[kMemoryPointerArgNum] = args[kMemoryPointerArgNum]->getType(); arg_types[kPCArgNum] = args[kPCArgNum]->getType(); - auto func_type = llvm::FunctionType::get( - arg_types[kMemoryPointerArgNum], arg_types, false); + auto func_type = llvm::FunctionType::get(arg_types[kMemoryPointerArgNum], + arg_types, false); llvm::FunctionCallee callee(func_type, dest_func); return ir.CreateCall(callee, args); } @@ -164,8 +164,8 @@ llvm::Value *FindVarInFunction(llvm::BasicBlock *block, std::string_view name, // Find a local variable defined in the entry block of the function. We use // this to find register variables. -llvm::Value *FindVarInFunction(llvm::Function *function, - std::string_view name_, bool allow_failure) { +llvm::Value *FindVarInFunction(llvm::Function *function, std::string_view name_, + bool allow_failure) { llvm::StringRef name(name_.data(), name_.size()); if (!function->empty()) { for (auto &instr : function->getEntryBlock()) { @@ -356,8 +356,8 @@ std::unique_ptr LoadModuleFromFile(llvm::LLVMContext *context, if (!module) { LOG_IF(FATAL, !allow_failure) - << "Unable to parse module file " << file_name_ - << ": " << err.getMessage().str(); + << "Unable to parse module file " << file_name_ << ": " + << err.getMessage().str(); return {}; } @@ -474,13 +474,15 @@ namespace { #endif // REMILL_BUILD_SEMANTICS_DIR_AARCH64 #ifndef REMILL_BUILD_SEMANTICS_DIR_SPARC32 -#error "Macro `REMILL_BUILD_SEMANTICS_DIR_SPARC32` must be defined to support the SPARC32 architectures." -#define REMILL_BUILD_SEMANTICS_DIR_SPARC32 +# error \ + "Macro `REMILL_BUILD_SEMANTICS_DIR_SPARC32` must be defined to support the SPARC32 architectures." +# define REMILL_BUILD_SEMANTICS_DIR_SPARC32 #endif // REMILL_BUILD_SEMANTICS_DIR_SPARC32 #ifndef REMILL_BUILD_SEMANTICS_DIR_SPARC64 -#error "Macro `REMILL_BUILD_SEMANTICS_DIR_SPARC64` must be defined to support the SPARC64 architectures." -#define REMILL_BUILD_SEMANTICS_DIR_SPARC64 +# error \ + "Macro `REMILL_BUILD_SEMANTICS_DIR_SPARC64` must be defined to support the SPARC64 architectures." +# define REMILL_BUILD_SEMANTICS_DIR_SPARC64 #endif // REMILL_BUILD_SEMANTICS_DIR_SPARC64 #ifndef REMILL_INSTALL_SEMANTICS_DIR @@ -493,16 +495,17 @@ namespace { #define MAJOR_MINOR S(LLVM_VERSION_MAJOR) "." S(LLVM_VERSION_MINOR) static const char *gSemanticsSearchPaths[] = { - // Derived from the build. - REMILL_BUILD_SEMANTICS_DIR_X86 "\0", - REMILL_BUILD_SEMANTICS_DIR_AARCH32 "\0", - REMILL_BUILD_SEMANTICS_DIR_AARCH64 "\0", - REMILL_BUILD_SEMANTICS_DIR_SPARC32 "\0", - REMILL_BUILD_SEMANTICS_DIR_SPARC64 "\0", - REMILL_INSTALL_SEMANTICS_DIR "\0", - "/usr/local/share/remill/" MAJOR_MINOR "/semantics", - "/usr/share/remill/" MAJOR_MINOR "/semantics", - "/share/remill/" MAJOR_MINOR "/semantics", + + // Derived from the build. + REMILL_BUILD_SEMANTICS_DIR_X86 "\0", + REMILL_BUILD_SEMANTICS_DIR_AARCH32 "\0", + REMILL_BUILD_SEMANTICS_DIR_AARCH64 "\0", + REMILL_BUILD_SEMANTICS_DIR_SPARC32 "\0", + REMILL_BUILD_SEMANTICS_DIR_SPARC64 "\0", + REMILL_INSTALL_SEMANTICS_DIR "\0", + "/usr/local/share/remill/" MAJOR_MINOR "/semantics", + "/usr/share/remill/" MAJOR_MINOR "/semantics", + "/share/remill/" MAJOR_MINOR "/semantics", }; } // namespace @@ -821,10 +824,9 @@ static llvm::Constant *MoveConstantIntoModule(llvm::Constant *c, type = ::remill::RecontextualizeType(type, dest_context); } else { #if LLVM_VERSION_NUMBER > LLVM_VERSION(3, 8) - if (!llvm::isa(c) && - !llvm::isa(c) && - !llvm::isa(c) && - !c->needsRelocation()) { + if (!llvm::isa(c) && !llvm::isa(c) && + !llvm::isa(c) && !c->needsRelocation()) { + //LOG(ERROR) << "Not moving: " << LLVMThingToString(c); return c; } @@ -1916,14 +1918,18 @@ BuildIndexes(const llvm::DataLayout &dl, llvm::Type *type, size_t offset, indexes_out.push_back(llvm::ConstantInt::get(index_type, index, false)); return BuildIndexes(dl, elem_type, offset, goal_offset, indexes_out); - } else if (auto fvt_type = llvm::dyn_cast(type); fvt_type) { + } else if (auto fvt_type = llvm::dyn_cast(type); + fvt_type) { + // It is possible that this gets called on an unexpected type // such as FixedVectorType; if so, report the issue and fix if/when it // happens LOG(FATAL) << "Called BuildIndexes on unsupported type: " << remill::LLVMThingToString(type); #if LLVM_VERSION_NUMBER >= LLVM_VERSION(11, 0) - } else if (auto svt_type = llvm::dyn_cast(type); svt_type) { + } else if (auto svt_type = llvm::dyn_cast(type); + svt_type) { + // same as above, but for scalable vectors LOG(FATAL) << "Called BuildIndexes on unsupported type: " << remill::LLVMThingToString(type); diff --git a/tests/AArch64/Lift.cpp b/tests/AArch64/Lift.cpp index 880bea5c3..71de1aaff 100644 --- a/tests/AArch64/Lift.cpp +++ b/tests/AArch64/Lift.cpp @@ -142,8 +142,8 @@ extern "C" int main(int argc, char *argv[]) { } DLOG(INFO) << "Serializing bitcode to " << FLAGS_bc_out; - auto host_arch = remill::Arch::Build( - &context, os_name, remill::GetArchName(REMILL_ARCH)); + auto host_arch = + remill::Arch::Build(&context, os_name, remill::GetArchName(REMILL_ARCH)); host_arch->PrepareModule(module.get()); remill::StoreModuleToFile(module.get(), FLAGS_bc_out); diff --git a/tests/X86/Lift.cpp b/tests/X86/Lift.cpp index 670d1faf7..7733bb1a8 100644 --- a/tests/X86/Lift.cpp +++ b/tests/X86/Lift.cpp @@ -142,8 +142,8 @@ extern "C" int main(int argc, char *argv[]) { } DLOG(INFO) << "Serializing bitcode to " << FLAGS_bc_out; - auto host_arch = remill::Arch::Build( - &context, os_name, remill::GetArchName(REMILL_ARCH)); + auto host_arch = + remill::Arch::Build(&context, os_name, remill::GetArchName(REMILL_ARCH)); host_arch->PrepareModule(module.get()); remill::StoreModuleToFile(module.get(), FLAGS_bc_out); From 74649f30b7faa329c0ea9a8c99bf49bcc70f7ace Mon Sep 17 00:00:00 2001 From: sschriner Date: Wed, 10 Feb 2021 11:58:23 -0500 Subject: [PATCH 126/130] Smoke Test --- .github/workflows/vcpkg_ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/vcpkg_ci.yml b/.github/workflows/vcpkg_ci.yml index 6a157c8e1..e3cd45ee6 100644 --- a/.github/workflows/vcpkg_ci.yml +++ b/.github/workflows/vcpkg_ci.yml @@ -53,6 +53,7 @@ jobs: run: | remill-lift-${{ matrix.llvm }} --arch amd64 --ir_out /dev/stdout --bytes c704ba01000000 remill-lift-${{ matrix.llvm }} --arch aarch64 --ir_out /dev/stdout --address 0x400544 --bytes FD7BBFA90000009000601891FD030091B7FFFF97E0031F2AFD7BC1A8C0035FD6 + remill-lift-${{ matrix.llvm }} --arch aarch32 -ir_out /dev/stderr --bytes 0cd04de208008de504108de500208de508309de504009de500109de5903122e0c20fa0e110109fe5001091e5002081e5040081e50cd08de21eff2fe14000000000000000 build_mac: strategy: @@ -87,3 +88,4 @@ jobs: run: | remill-lift-${{ matrix.llvm }} --arch amd64 --ir_out /dev/stdout --bytes c704ba01000000 remill-lift-${{ matrix.llvm }} --arch aarch64 --ir_out /dev/stdout --address 0x400544 --bytes FD7BBFA90000009000601891FD030091B7FFFF97E0031F2AFD7BC1A8C0035FD6 + remill-lift-${{ matrix.llvm }} --arch aarch32 -ir_out /dev/stderr --bytes 0cd04de208008de504108de500208de508309de504009de500109de5903122e0c20fa0e110109fe5001091e5002081e5040081e50cd08de21eff2fe14000000000000000 From 2696e70c903d3d6816b183e7db7729f2fc47bca4 Mon Sep 17 00:00:00 2001 From: sschriner Date: Fri, 12 Feb 2021 18:20:21 -0500 Subject: [PATCH 127/130] Add false delay slot to kCategoryConditionalDirectFunctionCall --- lib/BC/TraceLifter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/BC/TraceLifter.cpp b/lib/BC/TraceLifter.cpp index b087dd04a..84aa5ca52 100644 --- a/lib/BC/TraceLifter.cpp +++ b/lib/BC/TraceLifter.cpp @@ -571,6 +571,7 @@ bool TraceLifter::Impl::Lift( goto direct_func_call; } try_add_delay_slot(true, block); + try_add_delay_slot(false, block); trace_work_list.insert(inst.branch_taken_pc); auto target_trace = get_trace_decl(inst.branch_taken_pc); auto do_cond_call = llvm::BasicBlock::Create(context, "", func); From 76f8be1c35bb5600041a74fbf8dba9a77c263a4b Mon Sep 17 00:00:00 2001 From: Alessandro Gario <5714290+alessandrogario@users.noreply.github.com> Date: Tue, 23 Feb 2021 00:49:14 +0100 Subject: [PATCH 128/130] CI: Use single packaging job, add changelog support (#491) --- .github/workflows/vcpkg_ci.yml | 49 ++++++++++++---------------------- scripts/generate_changelog.sh | 30 +++++++++++++++++++++ 2 files changed, 47 insertions(+), 32 deletions(-) create mode 100755 scripts/generate_changelog.sh diff --git a/.github/workflows/vcpkg_ci.yml b/.github/workflows/vcpkg_ci.yml index 5b998a68f..628eeedd8 100644 --- a/.github/workflows/vcpkg_ci.yml +++ b/.github/workflows/vcpkg_ci.yml @@ -132,13 +132,25 @@ jobs: - release_linux: + release_packages: # Do not run the release procedure if any of the builds has failed needs: [ build_linux, build_mac ] runs-on: ubuntu-20.04 if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') steps: + - name: Clone the remill repository + uses: actions/checkout@v2 + with: + path: remill + fetch-depth: 0 + + - name: Generate the changelog + shell: bash + working-directory: remill + run: | + ./scripts/generate_changelog.sh changelog.md + - name: Download all artifacts uses: actions/download-artifact@v2 @@ -152,6 +164,7 @@ jobs: with: tag_name: ${{ github.ref }} release_name: Version ${{ github.ref }} + body_path: remill/changelog.md draft: true prerelease: true @@ -163,6 +176,9 @@ jobs: zip -r9 remill_ubuntu-20.04_packages.zip \ ubuntu-20.04* + zip -r9 remill_macos-10.15_packages.zip \ + macos-10.15* + - name: Upload the Ubuntu 18.04 packages uses: actions/upload-release-asset@v1 @@ -187,37 +203,6 @@ jobs: asset_name: remill_ubuntu-20.04_packages.zip asset_content_type: application/gzip - - - - release_macos: - # Do not run the release procedure if any of the builds has failed - needs: [ build_linux, build_mac ] - runs-on: 'macos-10.15' - if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') - - steps: - - name: Download all artifacts - uses: actions/download-artifact@v2 - - - name: Draft the new release - id: create_release - uses: actions/create-release@v1 - - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - with: - tag_name: ${{ github.ref }} - release_name: Version ${{ github.ref }} - draft: true - prerelease: true - - - name: Group the packages by platform - run: | - zip -r9 remill_macos-10.15_packages.zip \ - macos-10.15* - - name: Upload the macOS 10.15 packages uses: actions/upload-release-asset@v1 diff --git a/scripts/generate_changelog.sh b/scripts/generate_changelog.sh new file mode 100755 index 000000000..f0af523aa --- /dev/null +++ b/scripts/generate_changelog.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +PROJECT_NAME="remill" + +main() { + if [[ $# != 1 ]] ; then + printf "Usage:\n\tgenerate_changelog.sh \n" + return 1 + fi + + local output_path="${1}" + local current_version="$(git describe --tags --always)" + local previous_version="$(git describe --tags --always --abbrev=0 ${current_version}^)" + + echo "Current version: ${current_version}" + echo "Previous version: ${previous_version}" + echo "Output file: ${output_path}" + + printf "# Changelog\n\n" > "${output_path}" + printf "The following are the changes that happened between versions ${previous_version} and ${current_version}\n\n" >> "${output_path}" + + git log ${previous_version}...${current_version} \ + --pretty=format:" * [%h](http://github.com/lifting-bits/${PROJECT_NAME}/commit/%H) - %s" \ + --reverse | grep -v 'Merge branch' >> "${output_path}" + + return 0 +} + +main $@ +exit $? From 71cdec999fc5940c3fa54fad5fca571f7863db8b Mon Sep 17 00:00:00 2001 From: Alessandro Gario <5714290+alessandrogario@users.noreply.github.com> Date: Tue, 23 Feb 2021 05:13:27 +0100 Subject: [PATCH 129/130] CI: Add tag handler (#492) --- .github/workflows/vcpkg_ci.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/vcpkg_ci.yml b/.github/workflows/vcpkg_ci.yml index 628eeedd8..ff63a4354 100644 --- a/.github/workflows/vcpkg_ci.yml +++ b/.github/workflows/vcpkg_ci.yml @@ -1,12 +1,20 @@ name: VCPKG Continuous Integration + on: + # Run this workflow once every 6 hours against the master branch + schedule: + - cron: "0 */6 * * *" + push: branches: - - master + - 'master' + + tags: + - '*' + pull_request: - schedule: - # run CI every day even if no PRs/merges occur - - cron: '0 6 * * *' + branches: + - '*' jobs: build_linux: From fdb289b4d1230b2e9cb6e1f207596f9a45681f5b Mon Sep 17 00:00:00 2001 From: Peter Goodman Date: Wed, 24 Feb 2021 13:46:55 -0500 Subject: [PATCH 130/130] Delay slot fixes to TraceLifter --- lib/BC/TraceLifter.cpp | 213 +++++++++++++++++------------------------ 1 file changed, 86 insertions(+), 127 deletions(-) diff --git a/lib/BC/TraceLifter.cpp b/lib/BC/TraceLifter.cpp index 84aa5ca52..a27ef7dca 100644 --- a/lib/BC/TraceLifter.cpp +++ b/lib/BC/TraceLifter.cpp @@ -407,48 +407,7 @@ bool TraceLifter::Impl::Lift( case Instruction::kCategoryIndirectJump: { try_add_delay_slot(true, block); - - // The trace manager might know about the targets of things like - // jump tables, so we will let it tell us about those possibilities. - std::unordered_map devirt_targets; - manager.ForEachDevirtualizedTarget( - inst, - [&](uint64_t target_addr, DevirtualizedTargetKind target_kind) { - if (target_kind == DevirtualizedTargetKind::kTraceHead) { - auto target_block = - llvm::BasicBlock::Create(context, "", func); - devirt_targets[target_addr] = target_block; - - // Always add to the work list. This will cause us to lift - // if we haven't, and guarantee that `get_trace_decl` returns - // something. - trace_work_list.insert(target_addr); - auto target_trace = get_trace_decl(target_addr); - AddTerminatingTailCall(target_block, target_trace); - - } else { - devirt_targets[target_addr] = GetOrCreateBlock(target_addr); - inst_work_list.insert(target_addr); - } - }); - - if (devirt_targets.empty()) { - AddTerminatingTailCall(block, intrinsics->jump); - break; - } - - auto default_case = llvm::BasicBlock::Create(context, "", func); - - auto pc = LoadProgramCounter(block); - auto pc_type = pc->getType(); - auto dispatcher = llvm::SwitchInst::Create( - pc, default_case, devirt_targets.size(), block); - for (auto devirt_target : devirt_targets) { - dispatcher->addCase( - llvm::dyn_cast(llvm::ConstantInt::get( - pc_type, devirt_target.first, false)), - devirt_target.second); - } + AddTerminatingTailCall(block, intrinsics->jump); break; } @@ -469,74 +428,41 @@ bool TraceLifter::Impl::Lift( ir.CreateStore(ir.CreateLoad(ret_pc_ref), next_pc_ref); ir.CreateBr(GetOrCreateBranchNotTakenBlock()); - // The trace manager might know about the targets of things like - // virtual tables, so we will let it tell us about those possibilities. - std::unordered_map devirt_targets; - manager.ForEachDevirtualizedTarget( - inst, - [&](uint64_t target_addr, DevirtualizedTargetKind target_kind) { - if (target_kind == DevirtualizedTargetKind::kTraceLocal) { - LOG(WARNING) - << "Ignoring trace-local target in devirtualizable call"; - return; - } - - auto target_block = llvm::BasicBlock::Create(context, "", func); - devirt_targets[target_addr] = target_block; - - // Always add to the work list. This will cause us to lift - // if we haven't, and guarantee that `get_trace_decl` returns - // something. - trace_work_list.insert(target_addr); - auto target_trace = get_trace_decl(target_addr); - AddCall(target_block, target_trace); - - llvm::BranchInst::Create(fall_through_block, target_block); - }); - - if (devirt_targets.empty()) { - AddCall(block, intrinsics->function_call); - llvm::BranchInst::Create(fall_through_block, block); - continue; - } - - auto default_case = llvm::BasicBlock::Create(context, "", func); - AddCall(default_case, intrinsics->function_call); - llvm::BranchInst::Create(fall_through_block, default_case); - - auto pc = LoadProgramCounter(block); - auto pc_type = pc->getType(); - auto dispatcher = llvm::SwitchInst::Create( - pc, default_case, devirt_targets.size(), block); - for (auto devirt_target : devirt_targets) { - dispatcher->addCase( - llvm::dyn_cast(llvm::ConstantInt::get( - pc_type, devirt_target.first, false)), - devirt_target.second); - } - + AddCall(block, intrinsics->function_call); + llvm::BranchInst::Create(fall_through_block, block); block = fall_through_block; continue; } case Instruction::kCategoryConditionalIndirectFunctionCall: { - if (inst.branch_not_taken_pc == inst.branch_taken_pc) { - goto direct_func_call; + auto taken_block = llvm::BasicBlock::Create(context, "", func); + auto not_taken_block = GetOrCreateBranchNotTakenBlock(); + const auto orig_not_taken_block = not_taken_block; + + // If we might need to add delay slots, then try to lift the delayed + // instruction on each side of the conditional branch, injecting in + // new blocks (for the delayed instruction) between the branch + // and its original targets. + if (try_delay) { + not_taken_block = llvm::BasicBlock::Create(context, "", func); + + try_add_delay_slot(true, taken_block); + try_add_delay_slot(false, not_taken_block); + + llvm::BranchInst::Create(orig_not_taken_block, not_taken_block); } - try_add_delay_slot(true, block); - trace_work_list.insert(inst.branch_taken_pc); - auto do_cond_call = llvm::BasicBlock::Create(context, "", func); - auto next_block = GetOrCreateBranchNotTakenBlock(); - llvm::BranchInst::Create(do_cond_call, next_block, + + llvm::BranchInst::Create(taken_block, not_taken_block, LoadBranchTaken(block), block); - AddCall(do_cond_call, intrinsics->function_call); - const auto ret_pc_ref = LoadReturnProgramCounterRef(block); - const auto next_pc_ref = LoadNextProgramCounterRef(block); - llvm::IRBuilder<> ir(do_cond_call); - ir.CreateStore(ir.CreateLoad(ret_pc_ref), next_pc_ref); - ir.CreateBr(next_block); + AddCall(taken_block, intrinsics->function_call); + const auto ret_pc_ref = LoadReturnProgramCounterRef(taken_block); + const auto next_pc_ref = LoadNextProgramCounterRef(taken_block); + llvm::IRBuilder<> ir(taken_block); + ir.CreateStore(ir.CreateLoad(ret_pc_ref), next_pc_ref); + ir.CreateBr(orig_not_taken_block); + block = orig_not_taken_block; continue; } @@ -570,22 +496,39 @@ bool TraceLifter::Impl::Lift( if (inst.branch_not_taken_pc == inst.branch_taken_pc) { goto direct_func_call; } - try_add_delay_slot(true, block); - try_add_delay_slot(false, block); + + auto taken_block = llvm::BasicBlock::Create(context, "", func); + auto not_taken_block = GetOrCreateBranchNotTakenBlock(); + const auto orig_not_taken_block = not_taken_block; + + // If we might need to add delay slots, then try to lift the delayed + // instruction on each side of the conditional branch, injecting in + // new blocks (for the delayed instruction) between the branch + // and its original targets. + if (try_delay) { + not_taken_block = llvm::BasicBlock::Create(context, "", func); + + try_add_delay_slot(true, taken_block); + try_add_delay_slot(false, not_taken_block); + + llvm::BranchInst::Create(orig_not_taken_block, not_taken_block); + } + + llvm::BranchInst::Create(taken_block, not_taken_block, + LoadBranchTaken(block), block); + trace_work_list.insert(inst.branch_taken_pc); auto target_trace = get_trace_decl(inst.branch_taken_pc); - auto do_cond_call = llvm::BasicBlock::Create(context, "", func); - auto next_block = GetOrCreateBranchNotTakenBlock(); - llvm::BranchInst::Create(do_cond_call, next_block, - LoadBranchTaken(block), block); - AddCall(do_cond_call, target_trace); - const auto ret_pc_ref = LoadReturnProgramCounterRef(block); - const auto next_pc_ref = LoadNextProgramCounterRef(block); - llvm::IRBuilder<> ir(do_cond_call); - ir.CreateStore(ir.CreateLoad(ret_pc_ref), next_pc_ref); - ir.CreateBr(next_block); + AddCall(taken_block, intrinsics->function_call); + AddCall(taken_block, target_trace); + const auto ret_pc_ref = LoadReturnProgramCounterRef(taken_block); + const auto next_pc_ref = LoadNextProgramCounterRef(taken_block); + llvm::IRBuilder<> ir(taken_block); + ir.CreateStore(ir.CreateLoad(ret_pc_ref), next_pc_ref); + ir.CreateBr(orig_not_taken_block); + block = orig_not_taken_block; continue; } @@ -595,6 +538,8 @@ bool TraceLifter::Impl::Lift( // `do_hyper_call` block, we assign it to `state.block`, then go // to `check_call_return` to add the hyper call into that block, // checking if the hyper call returns to the next PC or not. + // + // TODO(pag): Delay slots? case Instruction::kCategoryConditionalAsyncHyperCall: { auto do_hyper_call = llvm::BasicBlock::Create(context, "", func); llvm::BranchInst::Create(do_hyper_call, GetOrCreateNextBlock(), @@ -627,11 +572,28 @@ bool TraceLifter::Impl::Lift( case Instruction::kCategoryConditionalFunctionReturn: { auto taken_block = llvm::BasicBlock::Create(context, "", func); - AddTerminatingTailCall(taken_block, intrinsics->function_return); auto not_taken_block = GetOrCreateBranchNotTakenBlock(); + const auto orig_not_taken_block = not_taken_block; + + // If we might need to add delay slots, then try to lift the delayed + // instruction on each side of the conditional branch, injecting in + // new blocks (for the delayed instruction) between the branch + // and its original targets. + if (try_delay) { + not_taken_block = llvm::BasicBlock::Create(context, "", func); + + try_add_delay_slot(true, taken_block); + try_add_delay_slot(false, not_taken_block); + + llvm::BranchInst::Create(orig_not_taken_block, not_taken_block); + } + llvm::BranchInst::Create(taken_block, not_taken_block, LoadBranchTaken(block), block); - break; + + AddTerminatingTailCall(taken_block, intrinsics->function_return); + block = orig_not_taken_block; + continue; } case Instruction::kCategoryConditionalBranch: { @@ -663,31 +625,28 @@ bool TraceLifter::Impl::Lift( } case Instruction::kCategoryConditionalIndirectJump: { auto taken_block = llvm::BasicBlock::Create(context, "", func); - AddTerminatingTailCall(taken_block, intrinsics->jump); auto not_taken_block = GetOrCreateBranchNotTakenBlock(); + const auto orig_not_taken_block = not_taken_block; // If we might need to add delay slots, then try to lift the delayed // instruction on each side of the conditional branch, injecting in // new blocks (for the delayed instruction) between the branch // and its original targets. if (try_delay) { - auto new_taken_block = llvm::BasicBlock::Create(context, "", func); - auto new_not_taken_block = - llvm::BasicBlock::Create(context, "", func); - - try_add_delay_slot(true, new_taken_block); - try_add_delay_slot(false, new_not_taken_block); + not_taken_block = llvm::BasicBlock::Create(context, "", func); - llvm::BranchInst::Create(taken_block, new_taken_block); - llvm::BranchInst::Create(not_taken_block, new_not_taken_block); + try_add_delay_slot(true, taken_block); + try_add_delay_slot(false, not_taken_block); - taken_block = new_taken_block; - not_taken_block = new_not_taken_block; + llvm::BranchInst::Create(orig_not_taken_block, not_taken_block); } llvm::BranchInst::Create(taken_block, not_taken_block, LoadBranchTaken(block), block); - break; + + AddTerminatingTailCall(taken_block, intrinsics->jump); + block = orig_not_taken_block; + continue; } } }