New arch support (#461)

* This branch contains support for new architectures.

* Initial start to support for AArch 32

* Progress

* Forgot the new files

* Added all data Integer processing instructions without S + ADDS and started ANDS

* Updated

* Finished Integer Data Processing with three registers, added integer data processing with 2 regs + immediate, started MUL instructions

* UMULL, UMULLS, UMLAL, UMLALS

* Corrected condition for addend or 0 immediate for UMULL/UMLAL + SMULL/SMLAL instructions

* Correct ops in Binary.cpp

* UMAAL

* SMULL, SMULLS, SMLAL, SMLALS + corrected acc was missing shift left in concatination

* Updated decoding instructions based on top level encodings

* Update returns around kDataProcessingRI and kDataProcessingI with comments to explain the correlation to the instruction rep

* Added appropriate inst.category flags to Multiply and accumulate

* Load/Store Word, Unsigned Byte (immediate, literal) && start of Logical Arithmetic (three register, immediate shift)

* Was missing UMAAL DEF_ISEL in Binary.cpp

* AddAddrRegOp

* Logical Arithmetic (three register, immediate shift) without accounting for the possible PC jump

* Made DecodeA32ExpandImm much much smaller

* Replaced some imm ops with AddImmOp calls

* Created AddShiftOp

* Added interpreter for evaluating new PC value at decoding time to handle direct jumps and conditional jumps

* Created EvalPCDest added PC evaluation to Logical Arithmetic Instructions

* AddShiftOp -> AddShiftOp, AddShiftThenExtractOp, AddExtractThenShiftOp

* Cleaned up some formatting, Renamed DecodeA32ExpandImm to ExpandTo32AddImmAddCarry and added a clarifying comment

* Added comment to EvalPCDest for clarity

* Cleaned up some things, updated the decoding semantics and semantics for the logical instructions

* Shortened kLogArithEvaluators and fixed a bug

* Updates from testing instructions

* Fixed DEF_ISEL for pre/post index instructions in MEM.cpp

* Integer Test and Compare (two register, immediate shift)

* Logical Arithmetic (two register and immediate)

* Integer Test and Compare (one register and immediate)

* Added to the top level encoding infrastructure to handle the Data-processing register (register shift) set of instructions and 3 corresponding subsets

* Add structs for the 3 subsets of Data-processing register (register shift)

* Code status before refactoring operand types

* This branch contains support for new architectures.

* Initial start to support for AArch 32

* Progress

* Forgot the new files

* Added all data Integer processing instructions without S + ADDS and started ANDS

* Updated

* Finished Integer Data Processing with three registers, added integer data processing with 2 regs + immediate, started MUL instructions

* UMULL, UMULLS, UMLAL, UMLALS

* Corrected condition for addend or 0 immediate for UMULL/UMLAL + SMULL/SMLAL instructions

* Correct ops in Binary.cpp

* UMAAL

* SMULL, SMULLS, SMLAL, SMLALS + corrected acc was missing shift left in concatination

* Updated decoding instructions based on top level encodings

* Update returns around kDataProcessingRI and kDataProcessingI with comments to explain the correlation to the instruction rep

* Added appropriate inst.category flags to Multiply and accumulate

* Load/Store Word, Unsigned Byte (immediate, literal) && start of Logical Arithmetic (three register, immediate shift)

* Was missing UMAAL DEF_ISEL in Binary.cpp

* AddAddrRegOp

* Logical Arithmetic (three register, immediate shift) without accounting for the possible PC jump

* Made DecodeA32ExpandImm much much smaller

* Replaced some imm ops with AddImmOp calls

* Created AddShiftOp

* Added interpreter for evaluating new PC value at decoding time to handle direct jumps and conditional jumps

* Created EvalPCDest added PC evaluation to Logical Arithmetic Instructions

* AddShiftOp -> AddShiftOp, AddShiftThenExtractOp, AddExtractThenShiftOp

* Cleaned up some formatting, Renamed DecodeA32ExpandImm to ExpandTo32AddImmAddCarry and added a clarifying comment

* Added comment to EvalPCDest for clarity

* Cleaned up some things, updated the decoding semantics and semantics for the logical instructions

* Shortened kLogArithEvaluators and fixed a bug

* Updates from testing instructions

* Fixed DEF_ISEL for pre/post index instructions in MEM.cpp

* Integer Test and Compare (two register, immediate shift)

* Logical Arithmetic (two register and immediate)

* Integer Test and Compare (one register and immediate)

* Added to the top level encoding infrastructure to handle the Data-processing register (register shift) set of instructions and 3 corresponding subsets

* Add structs for the 3 subsets of Data-processing register (register shift)

* Code status before refactoring operand types

* Finished updates off master

* Start of operand refactor

* Finished Expression Operand Support

* Fix the .gitignore to add AArch32 to lib/Arch && removed all extra rrx ops from semantics

* Updated .gitignore again, Added AddShiftRegRegOperand, Updated AddShiftRegImmOperand, Finished Register shift instructions for Integer Test and Compare, Logical Arithmetic, Integer Data Processing

* Updated ROR in AddShiftRegRegOperand

* Created ExtractAndZExtExpr

* Fixed comment formatting in if else statements

* Created RORExpr

* Small fixes

* Small fix in Logical Arithmetic (two register and immediate)

* Corrected AddShiftRegRegOperand and cleaned it up. Split the carry op into a separate function.

* conditional support + Start of Branch instructions

* Created AddExprOp, cleaned up some expressions in reg shifted reg, and updated some occurances of ShiftThenExtractOp with ExtractAndZExtExpr

* Updates from testing register shifted by register value inst

* Fix to ROR in AddShiftRegCarryOperand

* Corrected negation in DecodeCondition

* DecodeCondition edit

* DecodeCondition and AddShiftRegCarryOperand edits

* Updated arch_for_decode to arch

* Halfword Multiply and Accumulate

* Edits from testing Halfword Multiply and Accumulate

* Changed order of operands in Halfword Multiply and Accumulate to better reflect inst format + updated inst errors

* Branch (Imm) & BX/BXL

* Update aarch32 cmake

* cmake update

* CLZ

* Forgot BITBYTE.cpp

* MOVT

* Integer Saturating Arithmetic

* updated semantics in SMLAWh & SMLAh to use Select for setting PSTATE.Q

* Started Load/Store Word, Unsigned Byte (register) & fixed MOV halfword

* Load/Store Word, Unsigned Byte (register)

* Finished testing load/Store Word, Unsigned Byte (register)

* Load/Store Dual, Half, Signed Byte (register)

* Rest of Extra load store: Load/Store Dual, Half, Signed Byte (immediate, literal)

* Finished testing all the Load/store additions

* Signed multiply, Divide

* Cleaned up SExt some

* Saturate Insts and Start of Load Store Multiple - STMDB and LDM (aliases which support PUSH and POP of multiple regs)

* Condensed args in STMDB and LDM semantics

* Rest of Multiple Load/Store that do not execute in a different mode

* Bitfield Extract

* Extend and Add

* fix

* NOP

* Small fix

* Simplified the bit reps in TryMoveSpecialRegisterAndHintsI

* Moved Bitfield extract semantics out of BINARY and into BITBYTE

* Finished correcting S/ZExt and Trunc use

* Ran scripts/format-files to format

* Smoke Test

* Add false delay slot to kCategoryConditionalDirectFunctionCall

* CI: Use single packaging job, add changelog support (#491)

* CI: Add tag handler (#492)

* Delay slot fixes to TraceLifter

Co-authored-by: Peter Goodman <peter.goodman@gmail.com>
Co-authored-by: Alessandro Gario <5714290+alessandrogario@users.noreply.github.com>
This commit is contained in:
Sonya
2021-02-24 14:01:09 -05:00
committed by GitHub
parent 71cdec999f
commit 6322f794d1
85 changed files with 9405 additions and 3550 deletions
+2
View File
@@ -63,6 +63,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
- name: Locate the packages
id: package_names
@@ -123,6 +124,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
- name: Locate the packages
id: package_names
+3
View File
@@ -183,6 +183,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")
@@ -265,6 +266,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}\""
@@ -347,6 +349,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}")
+2
View File
@@ -145,6 +145,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")
@@ -231,6 +232,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}\""
+4
View File
@@ -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
@@ -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 &reg, addr_t val) {
reg.aword = val;
}
} // namespace
+118
View File
@@ -0,0 +1,118 @@
/*
* 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 _11;
uint8_t q; // Sticky overflow bit.
uint8_t _padding[4];
} __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
@@ -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<uint8_t> R8W;
typedef RnW<uint8_t> R8W;
typedef RnW<uint16_t> R16W;
// Note: AArch64 zero-extends like x86, but the smallest register size that
// can be accessed is 32 bits.
typedef RnW<uint32_t> R32W;
typedef Rn<uint8_t> R8;
//typedef Rn<uint16_t> R16;
typedef Rn<uint32_t> R32;
typedef Vn<vec8_t> V8;
typedef Vn<vec16_t> V16;
typedef Vn<vec32_t> V32;
typedef Vn<vec64_t> V64;
typedef Vn<vec128_t> V128;
typedef VnW<vec128_t> V128W;
typedef MnW<uint8_t> M8W;
typedef MnW<uint16_t> M16W;
typedef MnW<uint32_t> M32W;
typedef MnW<uint64_t> M64W;
typedef MVnW<vec8_t> MV8W;
typedef MVnW<vec16_t> MV16W;
typedef MVnW<vec32_t> MV32W;
typedef MVnW<vec64_t> MV64W;
typedef MVnW<vec128_t> MV128W;
typedef Mn<uint8_t> M8;
typedef Mn<uint16_t> M16;
typedef Mn<uint32_t> M32;
typedef Mn<uint64_t> M64;
typedef MVn<vec8_t> MV8;
typedef MVn<vec16_t> MV16;
typedef MVn<vec32_t> MV32;
typedef MVn<vec64_t> MV64;
typedef MVn<vec128_t> MV128;
typedef MVn<vec256_t> MV256;
typedef In<uint8_t> I8;
typedef In<uint16_t> I16;
typedef In<uint32_t> I32;
typedef In<float32_t> F32;
typedef In<float64_t> F64;
typedef In<addr_t> PC;
typedef In<addr_t> ADDR;
+15 -10
View File
@@ -31,6 +31,7 @@
#include <llvm/IR/DataLayout.h>
#include <llvm/IR/IRBuilder.h>
#pragma clang diagnostic pop
// clang-format on
#include <functional>
@@ -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;
@@ -246,6 +247,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;
@@ -278,26 +280,29 @@ 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`.
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);
// 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<ArchImpl> impl;
+85 -7
View File
@@ -17,14 +17,36 @@
#pragma once
#include <string>
#include <variant>
#include <vector>
namespace llvm {
class Constant;
class Type;
} // namespace llvm
namespace remill {
class Arch;
struct Register;
class OperandExpression;
enum ArchName : unsigned;
struct LLVMOpExpr {
unsigned llvm_opcode;
OperandExpression *op1;
OperandExpression *op2;
};
class OperandExpression : public std::variant<LLVMOpExpr, const Register *,
llvm::Constant *, std::string> {
public:
std::string Serialize(void) const;
llvm::Type *type{nullptr};
};
// Generic instruction operand.
class Operand {
public:
@@ -36,7 +58,8 @@ class Operand {
kTypeRegister,
kTypeShiftRegister,
kTypeImmediate,
kTypeAddress
kTypeAddress,
kTypeExpression,
} type;
enum Action { kActionInvalid, kActionRead, kActionWrite } action;
@@ -61,8 +84,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 +96,7 @@ class Operand {
kShiftRightAround // Rotate right.
} shift_op;
enum Extend : unsigned {
enum Extend : uint8_t {
kExtendInvalid,
kExtendUnsigned,
kExtendSigned,
@@ -124,6 +148,23 @@ class Operand {
}
} addr;
OperandExpression *expr;
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;
};
@@ -178,9 +219,13 @@ class Instruction {
kCategoryError,
kCategoryDirectJump,
kCategoryIndirectJump,
kCategoryConditionalIndirectJump,
kCategoryDirectFunctionCall,
kCategoryConditionalDirectFunctionCall,
kCategoryIndirectFunctionCall,
kCategoryConditionalIndirectFunctionCall,
kCategoryFunctionReturn,
kCategoryConditionalFunctionReturn,
kCategoryConditionalBranch,
kCategoryAsyncHyperCall,
kCategoryConditionalAsyncHyperCall,
@@ -211,29 +256,41 @@ class Instruction {
inline bool IsIndirectControlFlow(void) const {
switch (category) {
case kCategoryIndirectFunctionCall:
case kCategoryConditionalIndirectFunctionCall:
case kCategoryIndirectJump:
case kCategoryConditionalBranch:
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;
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 {
@@ -254,6 +311,27 @@ class Instruction {
inline bool IsNoOp(void) const {
return kCategoryNoOp == category;
}
// 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);
private:
static constexpr auto kMaxNumExpr = 64u;
OperandExpression exprs[kMaxNumExpr];
unsigned next_expr_index{0};
};
} // namespace remill
+45 -43
View File
@@ -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 <string_view>
@@ -80,6 +81,7 @@ enum ArchName : uint32_t {
kArchAMD64_AVX,
kArchAMD64_AVX512,
kArchAArch32LittleEndian,
kArchAArch64LittleEndian,
kArchSparc32,
+30
View File
@@ -58,6 +58,36 @@
ALWAYS_INLINE __attribute__((flatten)) static Memory *name( \
Memory *memory, State &state, ##__VA_ARGS__)
template <typename R, typename... 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( \
Memory *memory, State &state, ##__VA_ARGS__); \
static Memory *name##_spec(Memory *memory, State &state, R8 __cond, \
R8W __branch_taken, ##__VA_ARGS__) { \
return nullptr; \
} \
template <typename... Args> \
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( \
+3
View File
@@ -60,6 +60,9 @@ class SyncHyperCall {
// TODO(pag): How to distinguish little- and big-endian?
kAArch64EmulateInstruction = 0x200U,
kAArch64Breakpoint,
kAArch32EmulateInstruction = 0x300U,
kAArch32CheckNotEL2,
kSPARC32EmulateInstruction = 0x400U,
kSPARC64EmulateInstruction,
+2 -1
View File
@@ -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<uint##input_size##_t>(val); \
return in_val ? (static_cast<uint##size##_t>(builtin(in_val)) - \
static_cast<uint##input_size##_t>(disp)) : size; \
static_cast<uint##input_size##_t>(disp)) \
: size; \
}
MAKE_BUILTIN(CountLeadingZeros, 8, 32, __builtin_clz, 24)
+2 -1
View File
@@ -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__)
+67 -63
View File
@@ -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
};
+73 -71
View File
@@ -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
};
+2 -1
View File
@@ -17,9 +17,10 @@
#pragma once
#if __has_include(<llvm-c/Types.h>)
#include <llvm-c/Types.h>
# include <llvm-c/Types.h>
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;
+54 -56
View File
@@ -15,10 +15,10 @@
*/
#pragma once
#include "remill/BC/Version.h"
#include <llvm/IR/Instruction.h>
#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,83 +29,81 @@
#if LLVM_VERSION_NUMBER < LLVM_VERSION(11, 0)
#include <llvm/IR/CallSite.h>
# include <llvm/IR/CallSite.h>
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::getInstruction;
};
using parent::isCall;
using parent::isInvoke;
using parent::parent;
using parent::operator bool;
using parent::getCalledFunction;
using parent::getCalledValue;
using parent::getInstruction;
using parent::setCalledFunction;
};
} // namespace remill::compat::llvm
} // namespace remill::compat::llvm
#else
#include <llvm/IR/AbstractCallSite.h>
#include <llvm/Analysis/InlineCost.h>
#include <llvm/Transforms/Utils/Cloning.h>
# include <llvm/Analysis/InlineCost.h>
# include <llvm/IR/AbstractCallSite.h>
# include <llvm/Transforms/Utils/Cloning.h>
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);
}
::llvm::Value *getCalledValue() {
if (!static_cast<bool>(*this)) {
return nullptr;
}
return cb->getCalledOperand();
}
bool isCall() const {
return ::llvm::isa<::llvm::CallInst>(cb);
::llvm::Function *getCalledFunction() const {
if (!*this) {
return nullptr;
}
return cb->getCalledFunction();
}
::llvm::Value *getCalledValue() {
if (!static_cast<bool>(*this)) {
return nullptr;
}
return cb->getCalledOperand();
}
void setCalledFunction(::llvm::Function *fn) {
return cb->setCalledFunction(fn);
}
::llvm::Function *getCalledFunction() const {
if ( !*this) {
return nullptr;
}
return cb->getCalledFunction();
}
operator bool() const {
return cb;
}
void setCalledFunction(::llvm::Function *fn) {
return cb->setCalledFunction(fn);
}
::llvm::CallBase *getInstruction() {
return cb;
}
};
operator bool() const {
return cb;
}
::llvm::CallBase *getInstruction() {
return cb;
}
};
} // namespace remill::compat::llvm
} // namespace remill::compat::llvm
#endif
+13
View File
@@ -38,6 +38,7 @@ class Arch;
class Instruction;
class IntrinsicTable;
class Operand;
class OperandExpression;
class TraceLifter;
enum LiftStatus {
@@ -112,6 +113,18 @@ class InstructionLifter {
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 *
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 *
LiftAddressOperand(Instruction &inst, llvm::BasicBlock *block,
+2 -2
View File
@@ -16,11 +16,11 @@
#pragma once
#include <remill/BC/Lifter.h>
#include <functional>
#include <unordered_map>
#include <remill/BC/Lifter.h>
namespace remill {
using TraceMap = std::unordered_map<uint64_t, llvm::Function *>;
+2 -2
View File
@@ -28,6 +28,7 @@
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Module.h>
#pragma clang diagnostic pop
// clang-format on
#include <array>
@@ -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);
+184
View File
@@ -0,0 +1,184 @@
/*
* 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 <glog/logging.h>
#include <llvm/ADT/Triple.h>
#include <llvm/IR/Attributes.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Module.h>
#include <iomanip>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#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<uintptr_t>(&reinterpret_cast<const volatile char &>( \
static_cast<type *>(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<AArch32Arch>(context_, os_name_, arch_name_);
}
} // namespace remill
+56
View File
@@ -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.
*/
#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
+45
View File
@@ -0,0 +1,45 @@
# 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
EXPORT remillTargets
)
File diff suppressed because it is too large Load Diff
+34
View File
@@ -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 <algorithm>
#include <bitset>
#include <cmath>
#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
+66
View File
@@ -0,0 +1,66 @@
# 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"
"${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()
add_runtime_helper(aarch32 1)
+78
View File
@@ -0,0 +1,78 @@
/*
* 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 <algorithm>
#include <bitset>
#include <cmath>
// 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_LR state.gpr.r14.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/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"
// clang-format on
+728
View File
@@ -0,0 +1,728 @@
/*
* 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 <typename T>
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<T>(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_COND_SEM(AND, R32W dst, R32 src1, I32 src2) {
auto value = Read(src2);
Write(dst, UAnd(Read(src1), value));
return memory;
}
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);
state.sr.n = SignFlag(res);
state.sr.z = ZeroFlag(res);
state.sr.c = Read(carry_out);
// PSTATE.V unchanged
return memory;
}
DEF_COND_SEM(EOR, R32W dst, R32 src1, I32 src2) {
auto value = Read(src2);
Write(dst, UXor(Read(src1), value));
return memory;
}
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);
state.sr.n = SignFlag(res);
state.sr.z = ZeroFlag(res);
state.sr.c = Read(carry_out);
// PSTATE.V unchanged
return memory;
}
DEF_COND_SEM(RSB, R32W dst, R32 src1, I32 src2) {
auto value = Read(src2);
Write(dst, USub(value, Read(src1)));
return memory;
}
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));
Write(dst, res);
return memory;
}
DEF_COND_SEM(SUB, R32W dst, R32 src1, I32 src2) {
auto value = Read(src2);
Write(dst, USub(Read(src1), value));
return memory;
}
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));
Write(dst, res);
return memory;
}
DEF_COND_SEM(ADD, R32W dst, R32 src1, I32 src2) {
auto value = Read(src2);
Write(dst, UAdd(Read(src1), value));
return memory;
}
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));
Write(dst, res);
return memory;
}
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_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));
Write(dst, res);
return memory;
}
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_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));
Write(dst, res);
return memory;
}
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_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));
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;
// Multiply and Accumulate
namespace {
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));
auto res = Unsigned(SAdd(SMul(lhs, rhs), acc));
Write(dst, res);
return memory;
}
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));
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) {
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<uint32_t>(res));
Write(dst_hi, TruncTo<uint32_t>(UShr(res, 32ul)));
return memory;
}
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));
auto res = Unsigned(SSub(acc, SMul(lhs, rhs)));
Write(dst, res);
return memory;
}
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 res = UAdd(UMul(lhs, rhs), acc);
Write(dst_hi, TruncTo<uint32_t>(UShr(res, 32ul)));
Write(dst_lo, TruncTo<uint32_t>(res));
return memory;
}
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 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<uint32_t>(UShr(res, 32ul)));
Write(dst_lo, TruncTo<uint32_t>(res));
return memory;
}
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 res = SAdd(SMul(lhs, rhs), acc);
Write(dst_hi, TruncTo<uint32_t>(SShr(res, 32ul)));
Write(dst_lo, TruncTo<uint32_t>(res));
return memory;
}
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 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<uint32_t>(SShr(res, 32ul)));
Write(dst_lo, TruncTo<uint32_t>(res));
return memory;
}
} // namespace
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(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<uint32_t>(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)), 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 trun_res = TruncTo<uint32_t>(res);
Write(dst, trun_res);
return memory;
}
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 trun_res = TruncTo<uint32_t>(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);
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<uint32_t>(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(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<uint32_t>(SShr(res, 32ul)));
Write(dst_lo, TruncTo<uint32_t>(res));
return memory;
}
} // namespace
DEF_ISEL(SMLABB) = SMLAh;
DEF_ISEL(SMLABT) = SMLAh;
DEF_ISEL(SMLATB) = SMLAh;
DEF_ISEL(SMLATT) = SMLAh;
DEF_ISEL(SMLAWB) = SMLAWh;
DEF_ISEL(SMULWB) = SMULWh;
DEF_ISEL(SMLAWT) = SMLAWh;
DEF_ISEL(SMULWT) = SMULWh;
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;
// Saturate 16-bit && Saturate 32-bit
namespace {
template <typename T>
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 <typename T>
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(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, 32);
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)));
rhs = SignedSatQ(state, SShl(rhs, 1u), 32);
auto res = SAdd(lhs, rhs);
res = SignedSatQ(state, res, 32);
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 res = SSub(lhs, rhs);
res = SignedSatQ(state, res, 32);
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)));
rhs = SignedSatQ(state, SShl(rhs, 1u), 32);
auto res = SSub(lhs, rhs);
res = SignedSatQ(state, res, 32);
Write(dst, Trunc(Unsigned(res)));
return memory;
}
} // namespace
DEF_ISEL(QADD) = QADD;
DEF_ISEL(QDADD) = QDADD;
DEF_ISEL(QSUB) = QSUB;
DEF_ISEL(QDSUB) = QDSUB;
// 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(SExtTo<int64_t>(Trunc(rn)), SExtTo<int64_t>(Trunc(rm)));
auto prod2 =
SMul(SExtTo<int64_t>(SShr(rn, 16u)), SExtTo<int64_t>(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<int64_t>(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 = Signed(Read(src1));
auto rm = Signed(Read(src2));
auto ra = Signed(Read(src3));
auto prod1 = SMul(SExtTo<int64_t>(Signed(Trunc(rn))),
SExtTo<int64_t>(Signed(Trunc(rm))));
auto prod2 =
SMul(SExtTo<int64_t>(SShr(rn, 16u)), SExtTo<int64_t>(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<int64_t>(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 = Signed(Read(src1));
auto rm = Signed(Read(src2));
auto lo = SExt(Signed(Read(src3)));
auto hi = SExt(Signed(Read(src4)));
auto prod1 = SMul(SExtTo<int64_t>(Trunc(rn)), SExtTo<int64_t>(Trunc(rm)));
auto prod2 =
SMul(SExtTo<int64_t>(SShr(rn, 16u)), SExtTo<int64_t>(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
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<int64_t>(Trunc(rn)), SExtTo<int64_t>(Trunc(rm)));
auto prod2 =
SMul(SExtTo<int64_t>(SShr(rn, 16u)), SExtTo<int64_t>(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)));
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;
// Extend and Add
namespace {
template <typename T>
T ROR_C(T val, T shift, T nbits) {
if (shift == 0) {
return val;
}
auto m = URem(shift, nbits);
auto shr = UShr(val, m);
auto shl = UShl(val, nbits - 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, 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<uint16_t>(Signed(TruncTo<uint8_t>(src))))));
auto high = SExt(UAdd(
Trunc(UShr(src_add, 16u)),
Unsigned(SExtTo<uint16_t>(Signed(TruncTo<uint8_t>(UShr(src, 16u)))))));
auto res = UOr(low, UShl(Unsigned(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, 32u);
// Extract low byte
auto res =
UAdd(Unsigned(SExtTo<uint32_t>(Signed(TruncTo<uint8_t>(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, 32u);
// 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, 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)),
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, 32u);
// 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, 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;
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;
+58
View File
@@ -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_COND_SEM(CLZ, R32W dst, R32 src) {
auto count = CountLeadingZeros(Read(src));
WriteZExt(dst, count);
return memory;
}
} // 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 <msbit:lsbit> 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 <msbit:lsbit> 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;
+72
View File
@@ -0,0 +1,72 @@
/*
* 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(REG_PC, 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(REG_PC, new_pc);
Write(next_pc_dst, new_pc);
Write(branch_taken, c);
return memory;
}
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;
+58
View File
@@ -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_COND_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_COND_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_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_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));
return memory;
}
} // namespace
DEF_ISEL(TSTr) = TST;
DEF_ISEL(TEQr) = TEQ;
DEF_ISEL(CMPr) = CMP;
DEF_ISEL(CMNr) = CMN;
+190
View File
@@ -0,0 +1,190 @@
/*
* 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 <typename T>
[[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 <typename T>
[[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 <typename T>
[[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<unsigned>(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 <typename T>
struct Overflow;
// Computes an overflow flag when two numbers are added together.
template <>
struct Overflow<tag_add> {
template <typename T>
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
static_assert(std::is_unsigned<T>::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<tag_sub> {
template <typename T>
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
static_assert(std::is_unsigned<T>::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<tag_mul> {
// Integer multiplication overflow check, where result is twice the width of
// the operands.
template <typename T, typename R>
[[gnu::const]] ALWAYS_INLINE static bool
Flag(T, T, R res,
typename std::enable_if<sizeof(T) < sizeof(R), int>::type = 0) {
return static_cast<R>(static_cast<T>(res)) != res;
}
// Signed integer multiplication overflow check, where the result is
// truncated to the size of the operands.
template <typename T>
[[gnu::const]] ALWAYS_INLINE static bool
Flag(T lhs, T rhs, T,
typename std::enable_if<std::is_signed<T>::value, int>::type = 0) {
auto lhs_wide = SExt(lhs);
auto rhs_wide = SExt(rhs);
return Flag<T, decltype(lhs_wide)>(lhs, rhs, lhs_wide * rhs_wide);
}
};
// Generic carry flag.
template <typename Tag>
struct Carry;
// Computes an carry flag when two numbers are added together.
template <>
struct Carry<tag_add> {
template <typename T>
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
static_assert(std::is_unsigned<T>::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<tag_sub> {
template <typename T>
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T) {
static_assert(std::is_unsigned<T>::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<uint8_t>(0 != (mask & FE_INEXACT));
// state.sr.ofc |= static_cast<uint8_t>(0 != (mask & FE_OVERFLOW));
// state.sr.ufc |= static_cast<uint8_t>(0 != (mask & FE_UNDERFLOW));
// state.sr.ioc |= static_cast<uint64_t>(0 != (mask & FE_INVALID));
}
template <typename F, typename T>
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 <typename F, typename T>
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
+80
View File
@@ -0,0 +1,80 @@
/*
* 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(ORR, R32W dst, R32 src1, I32 src2) {
auto value = Read(src2);
auto result = UOr(Read(src1), value);
Write(dst, result);
return memory;
}
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);
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) {
auto value = UNot(Read(src2));
auto result = UAnd(Read(src1), value);
Write(dst, result);
return memory;
}
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);
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;
DEF_ISEL(MOVW) = ORR;
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;
+432
View File
@@ -0,0 +1,432 @@
/*
* 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
DEF_COND_SEM(STR, M32W dst, R32 src1) {
auto src = Read(src1);
Write(dst, src);
return memory;
}
DEF_COND_SEM(STRB, M8W dst, R32 src1) {
auto src = Read(src1);
Write(dst, TruncTo<uint8_t>(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, src);
Write(dst_reg, new_val);
return memory;
}
// Pre + Post
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<uint8_t>(src));
Write(dst_reg, new_val);
return memory;
}
// Offset
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
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);
Write(dst_reg, new_val);
return memory;
}
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<uint32_t>(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<uint8_t>(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);
WriteZExt(dst, src);
Write(dst_reg, new_val);
return memory;
}
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);
WriteZExt(dst, src);
Write(dst_reg, new_val);
return memory;
}
} // namespace
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;
namespace {
// Offset
DEF_COND_SEM(STRH, M16W dst, R32 src1) {
auto src = Read(src1);
Write(dst, TruncTo<uint16_t>(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<uint16_t>(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<uint64_t>(Read(src2)), 32ul);
auto rhs = ZExt<uint64_t>(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<uint64_t>(Read(src2)), 32ul);
auto rhs = ZExt<uint64_t>(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<uint32_t>(src));
Write(dst2, TruncTo<uint32_t>(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<uint32_t>(src));
Write(dst2, TruncTo<uint32_t>(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;
// Load/Store Multiple
namespace {
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(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 1))) {
Write(dst1, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 2))) {
Write(dst2, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 3))) {
Write(dst3, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 4))) {
Write(dst4, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 5))) {
Write(dst5, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 6))) {
Write(dst6, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 7))) {
Write(dst7, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 8))) {
Write(dst8, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 9))) {
Write(dst9, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 10))) {
Write(dst10, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 11))) {
Write(dst11, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 12))) {
Write(dst12, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 13))) {
Write(dst13, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 14))) {
Write(dst14, Read(GetElementPtr(src_mem, index++)));
}
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 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(GetElementPtr(dst_mem, index++), Read(src0));
}
if (UAnd(regs, uint16_t(0b1u << 1))) {
Write(GetElementPtr(dst_mem, index++), Read(src1));
}
if (UAnd(regs, uint16_t(0b1u << 2))) {
Write(GetElementPtr(dst_mem, index++), Read(src2));
}
if (UAnd(regs, uint16_t(0b1u << 3))) {
Write(GetElementPtr(dst_mem, index++), Read(src3));
}
if (UAnd(regs, uint16_t(0b1u << 4))) {
Write(GetElementPtr(dst_mem, index++), Read(src4));
}
if (UAnd(regs, uint16_t(0b1u << 5))) {
Write(GetElementPtr(dst_mem, index++), Read(src5));
}
if (UAnd(regs, uint16_t(0b1u << 6))) {
Write(GetElementPtr(dst_mem, index++), Read(src6));
}
if (UAnd(regs, uint16_t(0b1u << 7))) {
Write(GetElementPtr(dst_mem, index++), Read(src7));
}
if (UAnd(regs, uint16_t(0b1u << 8))) {
Write(GetElementPtr(dst_mem, index++), Read(src8));
}
if (UAnd(regs, uint16_t(0b1u << 9))) {
Write(GetElementPtr(dst_mem, index++), Read(src9));
}
if (UAnd(regs, uint16_t(0b1u << 10))) {
Write(GetElementPtr(dst_mem, index++), Read(src10));
}
if (UAnd(regs, uint16_t(0b1u << 11))) {
Write(GetElementPtr(dst_mem, index++), Read(src11));
}
if (UAnd(regs, uint16_t(0b1u << 12))) {
Write(GetElementPtr(dst_mem, index++), Read(src12));
}
if (UAnd(regs, uint16_t(0b1u << 13))) {
Write(GetElementPtr(dst_mem, index++), Read(src13));
}
if (UAnd(regs, uint16_t(0b1u << 14))) {
Write(GetElementPtr(dst_mem, index++), Read(src14));
}
if (UAnd(regs, uint16_t(0b1u << 15))) {
Write(GetElementPtr(dst_mem, index++), Read(src15));
}
Write(dst, Read(dst_new));
return memory;
}
} // 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;
+36
View File
@@ -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;
+5 -5
View File
@@ -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;
}
+2 -1
View File
@@ -189,7 +189,8 @@ DEF_SEM(TBZ, I8 bit_pos, R8W cond, PC taken, PC not_taken, S src, R64W pc_dst) {
}
template <typename S>
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<S>(Read(bit_pos));
+24 -15
View File
@@ -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,14 +81,13 @@ static unsigned AddressSize(ArchName arch_name) {
case kArchX86:
case kArchX86_AVX:
case kArchX86_AVX512:
case kArchSparc32:
return 32;
case kArchAArch32LittleEndian:
case kArchSparc32: return 32;
case kArchAMD64:
case kArchAMD64_AVX:
case kArchAMD64_AVX512:
case kArchAArch64LittleEndian:
case kArchSparc64:
return 64;
case kArchSparc64: return 64;
}
return 0;
}
@@ -168,6 +167,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_);
@@ -215,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);
}
@@ -282,8 +286,8 @@ void Arch::ForEachRegister(std::function<void(const Register *)> 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 {
@@ -352,6 +356,10 @@ 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;
}
@@ -638,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 &reg = impl->reg_by_name[reg_name];
@@ -660,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);
@@ -706,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<llvm::StructType>(state_ptr_type->getPointerElementType());
+2
View File
@@ -22,6 +22,7 @@ add_library(remill_arch STATIC
Name.cpp
)
add_subdirectory(AArch32)
add_subdirectory(AArch64)
add_subdirectory(SPARC32)
add_subdirectory(SPARC64)
@@ -30,6 +31,7 @@ add_subdirectory(X86)
set_property(TARGET remill_arch PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(remill_arch LINK_PUBLIC
remill_arch_aarch32
remill_arch_aarch64
remill_arch_sparc32
remill_arch_sparc64
+423 -32
View File
@@ -17,20 +17,45 @@
#include "remill/Arch/Instruction.h"
#include <glog/logging.h>
#include <llvm/IR/Instruction.h>
#include <llvm/IR/Instructions.h>
#include <iomanip>
#include <sstream>
#include "remill/Arch/Arch.h"
#include "remill/Arch/Name.h"
#include "remill/BC/Util.h"
namespace remill {
std::string OperandExpression::Serialize(void) const {
std::stringstream ss;
if (auto llvm_op = std::get_if<LLVMOpExpr>(this)) {
ss << "(" << llvm::Instruction::getOpcodeName(llvm_op->llvm_opcode) << " "
<< 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<const Register *>(this)) {
ss << (*reg_op)->name;
} else if (auto ci_op = std::get_if<llvm::Constant *>(this)) {
ss << remill::LLVMThingToString(*ci_op);
} else if (auto str_op = std::get_if<std::string>(this)) {
ss << *str_op;
}
return ss.str();
}
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) {}
@@ -45,7 +70,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) {
@@ -72,49 +98,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 << ")";
}
};
auto extract_begin = [&](void) {
switch (shift_reg.extend_op) {
case Operand::ShiftRegister::kExtendInvalid: break;
case Operand::ShiftRegister::kExtendSigned:
ss << "(SEXT (TRUNC ";
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();
}
switch (shift_reg.extend_op) {
case Operand::ShiftRegister::kExtendInvalid:
ss << "(REG_" << shift_reg.reg.size << " " << shift_reg.reg.name
<< ")";
break;
ss << "(REG_" << shift_reg.reg.size << " " << shift_reg.reg.name << ")";
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::kExtendUnsigned:
ss << "(ZEXT (TRUNC (REG_" << shift_reg.reg.size << " "
<< shift_reg.reg.name << ") " << shift_reg.extract_size << ") "
<< size << ")";
break;
}
if (Operand::ShiftRegister::kShiftInvalid != shift_reg.shift_op) {
ss << " " << shift_reg.shift_size << ")";
if (shift_reg.shift_first) {
shift_end();
extract_end();
} else {
extract_end();
shift_end();
}
break;
}
case Operand::kTypeImmediate:
ss << "(";
if (imm.is_signed) {
@@ -130,7 +190,7 @@ std::string Operand::Serialize(void) const {
}
break;
case Operand::kTypeAddress:
case Operand::kTypeAddress: {
ss << "(";
// Nice version of the memory size.
@@ -211,11 +271,34 @@ std::string Operand::Serialize(void) const {
}
ss << ")"; // End of `(ADDR_`.
break;
}
case Operand::kTypeExpression: ss << expr->Serialize(); break;
}
ss << ")";
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),
@@ -246,6 +329,310 @@ void Instruction::Reset(void) {
operands.clear();
function.clear();
bytes.clear();
next_expr_index = 0;
}
OperandExpression *Instruction::AllocateExpression(void) {
CHECK_LT(next_expr_index, kMaxNumExpr);
return &(exprs[next_expr_index++]);
}
OperandExpression *Instruction::EmplaceRegister(const Register *reg) {
auto expr = AllocateExpression();
expr->emplace<const Register *>(reg);
expr->type = reg->type;
return expr;
}
OperandExpression *Instruction::EmplaceRegister(std::string_view reg_name) {
return EmplaceRegister(arch->RegisterByName(reg_name));
}
OperandExpression *Instruction::EmplaceConstant(llvm::Constant *val) {
auto expr = AllocateExpression();
expr->emplace<llvm::Constant *>(val);
expr->type = val->getType();
return expr;
}
OperandExpression *Instruction::EmplaceVariable(std::string_view var_name,
llvm::Type *type) {
auto expr = AllocateExpression();
expr->emplace<std::string>(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>(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>(LLVMOpExpr{opcode, op1, nullptr});
expr->type = type;
return expr;
}
Operand &Instruction::EmplaceOperand(const Operand::Register &reg_op) {
operands.emplace_back();
auto &op = operands.back();
op.type = Operand::kTypeExpression;
op.size = reg_op.size;
if (auto reg = arch->RegisterByName(reg_op.name)) {
op.expr = EmplaceRegister(reg);
} else {
auto &context = *arch->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->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.size = arch->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->address_size;
auto &arch_reg = shift_op.reg;
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);
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->AddressType();
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
<< " 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()) {
if (auto reg_pointer = arch->RegisterByName(reg.name)) {
return EmplaceRegister(reg_pointer);
} else {
return EmplaceVariable(reg.name,
llvm::Type::getIntNTy(*arch->context, reg.size));
}
} 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<uint64_t>(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<uint64_t>(addr_op.displacement));
addr =
EmplaceBinaryOp(llvm::Instruction::Add, addr, EmplaceConstant(disp));
} else {
auto disp = llvm::ConstantInt::get(
word_type, static_cast<uint64_t>(-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->context, static_cast<unsigned>(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;
}
std::string Instruction::Serialize(void) const {
@@ -259,6 +646,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;
@@ -339,6 +727,9 @@ 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 <unknown>)"
<< " (NOT_TAKEN " << branch_not_taken_pc << std::dec << "))";
default: break;
}
+6
View File
@@ -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",
+80 -89
View File
@@ -14,21 +14,22 @@
* limitations under the License.
*/
#include "remill/Arch/Arch.h"
#include <glog/logging.h>
#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"
};
"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 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<sparc::SPARC32Arch>(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 {};
}
}
+145 -144
View File
@@ -16,9 +16,10 @@
#pragma once
#include <cstdint>
#include <glog/logging.h>
#include <cstdint>
#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
File diff suppressed because it is too large Load Diff
+101 -98
View File
@@ -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_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_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_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_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_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_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_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 GSR_ALIGN state.asr.gsr.align
#define GSR_MASK state.asr.gsr.mask
#define REG_Y state.asr.yreg.aword
#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_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 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 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_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 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 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 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 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"
+24 -17
View File
@@ -18,35 +18,39 @@ ALWAYS_INLINE static void WriteFlagsAddSub(State &state, T lhs, T rhs, T res) {
}
template <typename Tag, typename T>
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<Tag>::Flag(lhs, rhs, res);
}
template <typename Tag, typename T>
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<Tag>::Flag(lhs, rhs, res);
}
template <typename Tag>
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<Tag>::Flag(lhs, rhs, res);
WriteICCFlagsIncDec<Tag>(state, lhs, rhs, res);
}
template <typename Tag>
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<Tag>::Flag(lhs, rhs, res);
WriteXCCFlagsIncDec<Tag>(state, lhs, rhs, res);
}
template <typename S1, typename S2, typename D>
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 <typename S1, typename S2, typename D>
@@ -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<decltype(y)>(32))), lhs_wide));
auto y_lhs_wide = Signed(
UOr(decltype(lhs_wide)(UShl(y, Literal<decltype(y)>(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<decltype(y)>(32))), lhs_wide));
auto y_lhs_wide = Signed(
UOr(decltype(lhs_wide)(UShl(y, Literal<decltype(y)>(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<decltype(y)>(0x1));
auto masked_rs1 = UAnd(rs1, Literal<decltype(rs1)>(0xffffffff));
auto masked_rs2 = UAnd(rs2, Literal<decltype(rs2)>(0xffffffff));
auto new_rs2 = Select(UCmpEq(lsb_y, 0), Literal<decltype(rs2)>(0), masked_rs2);
auto new_rs2 =
Select(UCmpEq(lsb_y, 0), Literal<decltype(rs2)>(0), masked_rs2);
auto flag_nf = Literal<uint32_t>(Read(FLAG_ICC_NF));
auto flag_vf = Literal<uint32_t>(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<decltype(masked_rs1)>(1)),
Literal<decltype(masked_rs1)>(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<decltype(y)>(1));
auto lsb_rs1 = UAnd(rs1, Literal<decltype(rs1)>(0x1));
auto new_y = UOr(shifted_y, decltype(y)(UShl(lsb_rs1, Literal<decltype(lsb_rs1)>(31))));
auto lsb_rs1 = UAnd(rs1, Literal<decltype(rs1)>(0x1));
auto new_y = UOr(shifted_y,
decltype(y)(UShl(lsb_rs1, Literal<decltype(lsb_rs1)>(31))));
Write(REG_Y, new_y);
Write(dest, res);
WriteICCFlagsAddSub<tag_add>(
state, static_cast<uint32_t>(new_rs1),
static_cast<uint32_t>(new_rs2), static_cast<uint32_t>(res));
WriteICCFlagsAddSub<tag_add>(state, static_cast<uint32_t>(new_rs1),
static_cast<uint32_t>(new_rs2),
static_cast<uint32_t>(res));
return memory;
}
}
} // namespace
DEF_ISEL(MULScc) = MULSCC_R32;
+33 -38
View File
@@ -7,8 +7,7 @@ namespace {
// NOTE(pag): `new_pc == pc_of_jmp + 4`, and `new_npc`
// is the target EA.
template <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
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<R32W>;
DEF_ISEL(FBN_fcc3) = FBN<R32W>;
#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)
+166 -232
View File
@@ -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<typename T>
static inline bool
CondRZ(const State &state, T cc) {
template <typename T>
static inline bool CondRZ(const State &state, T cc) {
return cc == 0;
}
template<typename T>
static inline bool
CondRLEZ(const State &state, T cc) {
template <typename T>
static inline bool CondRLEZ(const State &state, T cc) {
return Signed(cc) <= 0;
}
template<typename T>
static inline bool
CondRLZ(const State &state, T cc) {
template <typename T>
static inline bool CondRLZ(const State &state, T cc) {
return Signed(cc) < 0;
}
template<typename T>
static inline bool
CondRNZ(const State &state, T cc) {
template <typename T>
static inline bool CondRNZ(const State &state, T cc) {
return cc != 0;
}
template<typename T>
static inline bool
CondRGZ(const State &state, T cc) {
template <typename T>
static inline bool CondRGZ(const State &state, T cc) {
return Signed(cc) > 0;
}
template<typename T>
static inline bool
CondRGEZ(const State &state, T cc) {
template <typename T>
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;
}
+51 -59
View File
@@ -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<R32, R32W>;
DEF_ISEL(MOVA_xcc) = MOVA_xcc<R32, R32W>;
@@ -179,22 +179,22 @@ DEF_ISEL(MOVN_xcc) = MOVN_xcc<R32, R32W>;
#define MAKE_SEMANTICS(name, cond, cc) \
namespace { \
template <typename S, typename D> \
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 <typename S, typename D> \
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<R32, R32W>;
} \
DEF_ISEL(MOV##cond##_##cc) = name##cond##_##cc<R32, R32W>;
#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 <typename C, typename S, typename D> \
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<R32, R32, R32W>;
DEF_ISEL(MOVR##cond) = name##cond<R32, R32, R32W>;
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)
+47 -79
View File
@@ -20,38 +20,35 @@ namespace {
// Zero flags, tells us whether or not a value is zero.
template <typename T>
[[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 <typename T>
[[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 <typename T>
[[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<unsigned>(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<tag_add> {
template <typename T>
[[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<T>::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<tag_add> {
template <>
struct Overflow<tag_sub> {
template <typename T>
[[gnu::const]]
ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
static_assert(std::is_unsigned<T>::value,
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
static_assert(std::is_unsigned<T>::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<tag_mul> {
// Integer multiplication overflow check, where result is twice the width of
// the operands.
template <typename T, typename R>
[[gnu::const]]
ALWAYS_INLINE static bool Flag(
T, T, R res,
typename std::enable_if<sizeof(T) < sizeof(R),int>::type=0) {
[[gnu::const]] ALWAYS_INLINE static bool
Flag(T, T, R res,
typename std::enable_if<sizeof(T) < sizeof(R), int>::type = 0) {
return static_cast<R>(static_cast<T>(res)) != res;
}
@@ -127,10 +117,9 @@ struct Overflow<tag_mul> {
// Signed integer multiplication overflow check, where the result is
// truncated to the size of the operands.
template <typename T>
[[gnu::const]]
ALWAYS_INLINE static bool Flag(
T lhs, T rhs, T,
typename std::enable_if<std::is_signed<T>::value,int>::type=0) {
[[gnu::const]] ALWAYS_INLINE static bool
Flag(T lhs, T rhs, T,
typename std::enable_if<std::is_signed<T>::value, int>::type = 0) {
auto lhs_wide = SExt(lhs);
auto rhs_wide = SExt(rhs);
return Flag<T, decltype(lhs_wide)>(lhs, rhs, lhs_wide * rhs_wide);
@@ -141,31 +130,23 @@ struct Overflow<tag_mul> {
template <>
struct Overflow<tag_sdiv> {
template <typename T, typename R>
[[gnu::const]]
ALWAYS_INLINE static bool Flag(
T, T, R res,
typename std::enable_if<sizeof(T) < sizeof(R),int>::type=0) {
[[gnu::const]] ALWAYS_INLINE static bool
Flag(T, T, R res,
typename std::enable_if<sizeof(T) < sizeof(R), int>::type = 0) {
enum {
kSignShift = sizeof(T) * 8 - 1
};
enum { kSignShift = sizeof(T) * 8 - 1 };
return (SExt(res << kSignShift) > 0) || (SExt(res << kSignShift) < -1);
}
template <typename T, typename R>
[[gnu::const]]
ALWAYS_INLINE static R Value(
T lhs, T rhs, R res,
typename std::enable_if<sizeof(T) < sizeof(R),int>::type=0) {
[[gnu::const]] ALWAYS_INLINE static R
Value(T lhs, T rhs, R res,
typename std::enable_if<sizeof(T) < sizeof(R), int>::type = 0) {
enum {
kSignShift = sizeof(T) * 8 - 1
};
enum { kSignShift = sizeof(T) * 8 - 1 };
enum:R {
kValueMax = static_cast<R>(1) << sizeof(T) * 8
};
enum : R { kValueMax = static_cast<R>(1) << sizeof(T) * 8 };
if (SExt(res << kSignShift) > 0) {
return kValueMax - 1;
@@ -175,37 +156,28 @@ struct Overflow<tag_sdiv> {
return res;
}
}
};
template <>
struct Overflow<tag_udiv> {
template <typename T, typename R>
[[gnu::const]]
ALWAYS_INLINE static bool Flag(
T, T, R res,
typename std::enable_if<sizeof(T) < sizeof(R),int>::type=0) {
[[gnu::const]] ALWAYS_INLINE static bool
Flag(T, T, R res,
typename std::enable_if<sizeof(T) < sizeof(R), int>::type = 0) {
enum {
kShift = sizeof(T) * 8
};
enum { kShift = sizeof(T) * 8 };
return (SExt(res << kShift) > 0);
}
template <typename T, typename R>
[[gnu::const]]
ALWAYS_INLINE static R Value(
T lhs, T rhs, R res,
typename std::enable_if<sizeof(T) < sizeof(R),int>::type=0) {
enum {
kShift = sizeof(T) * 8
};
[[gnu::const]] ALWAYS_INLINE static R
Value(T lhs, T rhs, R res,
typename std::enable_if<sizeof(T) < sizeof(R), int>::type = 0) {
enum:R {
kValueMax = static_cast<R>(1) << sizeof(T) * 8
};
enum { kShift = sizeof(T) * 8 };
enum : R { kValueMax = static_cast<R>(1) << sizeof(T) * 8 };
if (SExt(res << kShift) > 0) {
return kValueMax - 1;
@@ -223,8 +195,7 @@ struct Carry;
template <>
struct Carry<tag_add> {
template <typename T>
[[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<T>::value,
"Invalid specialization of `Carry::Flag` for addition.");
return res < lhs || res < rhs;
@@ -235,8 +206,7 @@ struct Carry<tag_add> {
template <>
struct Carry<tag_sub> {
template <typename T>
[[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<T>::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<uint8_t>(mask & FE_ALL_EXCEPT);
}
} // namespace
} // namespace
+92 -90
View File
@@ -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 <typename S> \
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<R8>(3)); \
} else { \
if (FCmpEq(val1, val2)) { \
/* result = '00'; */ \
Write(state.fsr.fcc, Literal<R8>(0)); \
} else if (FCmpLt(val1, val2)) { \
/* result = '01'; */ \
Write(state.fsr.fcc, Literal<R8>(1)); \
} else { /* FCmpGt(val1, val2) */ \
/* result = '10'; */ \
Write(state.fsr.fcc, Literal<R8>(2)); \
} \
} \
}
template <typename S> \
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<R8>(3)); \
} else { \
if (FCmpEq(val1, val2)) { \
/* result = '00'; */ \
Write(state.fsr.fcc, Literal<R8>(0)); \
} else if (FCmpLt(val1, val2)) { \
/* result = '01'; */ \
Write(state.fsr.fcc, Literal<R8>(1)); \
} else { /* FCmpGt(val1, val2) */ \
/* result = '10'; */ \
Write(state.fsr.fcc, Literal<R8>(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
+21 -18
View File
@@ -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<decltype(state.hyper_call_vector)>(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<decltype(state.hyper_call_vector)>(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;
+24 -17
View File
@@ -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.
+2 -1
View File
@@ -5,7 +5,8 @@
namespace {
template <typename S1, typename S2, typename D>
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);
+29 -25
View File
@@ -14,21 +14,22 @@
* limitations under the License.
*/
#include "remill/Arch/Arch.h"
#include <glog/logging.h>
#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<sparc::SPARC64Arch>(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
+3 -2
View File
@@ -16,16 +16,17 @@
#pragma once
#include <cstdint>
#include <glog/logging.h>
#include <cstdint>
#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
File diff suppressed because it is too large Load Diff
+106 -104
View File
@@ -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_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_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_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_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_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_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_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 GSR_ALIGN state.asr.gsr.align
#define GSR_MASK state.asr.gsr.mask
#define REG_Y state.asr.yreg.aword
#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_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 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 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_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 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 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 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 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"
+8 -13
View File
@@ -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;
+55 -47
View File
@@ -32,27 +32,31 @@ ALWAYS_INLINE static void WriteFlagsAddSub(State &state, T lhs, T rhs, T res) {
}
template <typename Tag, typename T>
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<Tag>::Flag(lhs, rhs, res);
}
template <typename Tag, typename T>
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<Tag>::Flag(lhs, rhs, res);
}
template <typename Tag>
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<Tag>::Flag(lhs, rhs, res);
WriteICCFlagsIncDec<Tag>(state, lhs, rhs, res);
}
template <typename Tag>
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<Tag>::Flag(lhs, rhs, res);
WriteXCCFlagsIncDec<Tag>(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<tag_add>(
state, Literal<uint32_t>(lhs),
Literal<uint32_t>(rhs), Literal<uint32_t>(res));
WriteICCFlagsAddSub<tag_add>(state, Literal<uint32_t>(lhs),
Literal<uint32_t>(rhs), Literal<uint32_t>(res));
WriteXCCFlagsAddSub<tag_add>(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<tag_add>(
state, static_cast<uint32_t>(lhs),
static_cast<uint32_t>(rhs), static_cast<uint32_t>(sum));
WriteICCFlagsAddSub<tag_add>(state, static_cast<uint32_t>(lhs),
static_cast<uint32_t>(rhs),
static_cast<uint32_t>(sum));
WriteXCCFlagsAddSub<tag_add>(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<tag_add>(
state, static_cast<uint32_t>(lhs),
static_cast<uint32_t>(rhs), static_cast<uint32_t>(sum));
WriteICCFlagsAddSub<tag_add>(state, static_cast<uint32_t>(lhs),
static_cast<uint32_t>(rhs),
static_cast<uint32_t>(sum));
WriteXCCFlagsAddSub<tag_add>(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<tag_add>(
state, static_cast<uint32_t>(lhs),
static_cast<uint32_t>(rhs), static_cast<uint32_t>(res));
WriteICCFlagsAddSub<tag_add>(state, static_cast<uint32_t>(lhs),
static_cast<uint32_t>(rhs),
static_cast<uint32_t>(res));
WriteXCCFlagsAddSub<tag_add>(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<tag_sub>(
state, static_cast<uint32_t>(lhs), static_cast<uint32_t>(rhs),
static_cast<uint32_t>(res));
WriteICCFlagsAddSub<tag_sub>(state, static_cast<uint32_t>(lhs),
static_cast<uint32_t>(rhs),
static_cast<uint32_t>(res));
WriteXCCFlagsAddSub<tag_sub>(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<tag_sub>(
state, static_cast<uint32_t>(lhs), static_cast<uint32_t>(rhs),
static_cast<uint32_t>(res));
WriteICCFlagsAddSub<tag_sub>(state, static_cast<uint32_t>(lhs),
static_cast<uint32_t>(rhs),
static_cast<uint32_t>(res));
WriteXCCFlagsAddSub<tag_sub>(state, lhs, rhs, res);
return memory;
}
@@ -201,15 +204,16 @@ template <typename S1, typename S2, typename D>
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<S1>(0x3));
auto tag_rs2 = UAnd(rs2, Literal<S2>(0x3));
auto tag_ov = UCmpNeq(UOr(tag_rs1, tag_rs2), 0);
auto sum = UAdd(rs1, rs2);
FLAG_ICC_VF = tag_ov; //|| Overflow<tag_add>::Flag(rs1, rs2, sum));
FLAG_ICC_CF = Carry<tag_add>::Flag(
static_cast<uint32_t>(rs1), static_cast<uint32_t>(rs2),
static_cast<uint32_t>(sum));
FLAG_ICC_VF = tag_ov; //|| Overflow<tag_add>::Flag(rs1, rs2, sum));
FLAG_ICC_CF = Carry<tag_add>::Flag(static_cast<uint32_t>(rs1),
static_cast<uint32_t>(rs2),
static_cast<uint32_t>(sum));
FLAG_ICC_ZF = ZeroFlag(static_cast<uint32_t>(sum));
FLAG_ICC_NF = SignFlag(static_cast<uint32_t>(sum));
WriteXCCFlagsAddSub<tag_add>(state, rs1, rs2, sum);
@@ -221,6 +225,7 @@ template <typename S1, typename S2, typename D>
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<S1>(0x3));
auto tag_rs2 = UAnd(rs2, Literal<S2>(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<tag_add>::Flag(
Literal<uint32_t>(rs1), Literal<uint32_t>(rs2),
Literal<uint32_t>(sum));
Literal<uint32_t>(rs1), Literal<uint32_t>(rs2), Literal<uint32_t>(sum));
FLAG_ICC_ZF = ZeroFlag(static_cast<uint32_t>(sum));
FLAG_ICC_NF = SignFlag(static_cast<uint32_t>(sum));
WriteXCCFlagsAddSub<tag_add>(state, rs1, rs2, sum);
@@ -249,15 +253,16 @@ template <typename S1, typename S2, typename D>
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<S1>(0x3));
auto tag_rs2 = UAnd(rs2, Literal<S2>(0x3));
auto tag_ov = UCmpNeq(UOr(tag_rs1, tag_rs2), 0);
auto res = USub(rs1, rs2);
FLAG_ICC_VF = tag_ov; //|| Overflow<tag_add>::Flag(rs1, rs2, sum));
FLAG_ICC_CF = Carry<tag_sub>::Flag(
static_cast<uint32_t>(rs1), static_cast<uint32_t>(rs2),
static_cast<uint32_t>(res));
FLAG_ICC_VF = tag_ov; //|| Overflow<tag_add>::Flag(rs1, rs2, sum));
FLAG_ICC_CF = Carry<tag_sub>::Flag(static_cast<uint32_t>(rs1),
static_cast<uint32_t>(rs2),
static_cast<uint32_t>(res));
FLAG_ICC_ZF = ZeroFlag(static_cast<uint32_t>(res));
FLAG_ICC_NF = SignFlag(static_cast<uint32_t>(res));
WriteXCCFlagsAddSub<tag_sub>(state, rs1, rs2, res);
@@ -268,6 +273,7 @@ template <typename S1, typename S2, typename D>
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<S1>(0x3));
auto tag_rs2 = UAnd(rs2, Literal<S2>(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<tag_sub>::Flag(
Literal<uint32_t>(rs1), Literal<uint32_t>(rs2),
Literal<uint32_t>(res));
Literal<uint32_t>(rs1), Literal<uint32_t>(rs2), Literal<uint32_t>(res));
FLAG_ICC_ZF = ZeroFlag(Literal<uint32_t>(res));
FLAG_ICC_NF = SignFlag(Literal<uint32_t>(res));
WriteXCCFlagsAddSub<tag_sub>(state, rs1, rs2, res);
return memory;
}
}
} // namespace
DEF_ISEL(ADD) = ADD<R64, R64, R64W>;
DEF_ISEL(ADDC) = ADDC<R64, R64, R64W>;
@@ -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<decltype(y)>(32))), lhs_wide));
auto y_lhs_wide = Signed(
UOr(decltype(lhs_wide)(UShl(y, Literal<decltype(y)>(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<decltype(y)>(32))), lhs_wide));
auto y_lhs_wide = Signed(
UOr(decltype(lhs_wide)(UShl(y, Literal<decltype(y)>(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<R64, R64, R64W>;
DEF_ISEL(SMULcc) = SMULCC<R64, R64, R64W>;
@@ -518,7 +524,8 @@ DEF_SEM(MULSCC_R32, R32 src1, R32 src2, R32W dest) {
auto lsb_y = UAnd(y, Literal<decltype(y)>(0x1));
auto masked_rs1 = UAnd(rs1, Literal<decltype(rs1)>(0xffffffff));
auto masked_rs2 = UAnd(rs2, Literal<decltype(rs2)>(0xffffffff));
auto new_rs2 = Select(UCmpEq(lsb_y, 0), Literal<decltype(rs2)>(0), masked_rs2);
auto new_rs2 =
Select(UCmpEq(lsb_y, 0), Literal<decltype(rs2)>(0), masked_rs2);
auto flag_nf = Literal<uint32_t>(Read(FLAG_ICC_NF));
auto flag_vf = Literal<uint32_t>(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<decltype(masked_rs1)>(1)),
Literal<decltype(masked_rs1)>(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<decltype(y)>(1));
auto lsb_rs1 = UAnd(rs1, Literal<decltype(rs1)>(0x1));
auto new_y = UOr(shifted_y, decltype(y)(UShl(lsb_rs1, Literal<decltype(lsb_rs1)>(31))));
auto lsb_rs1 = UAnd(rs1, Literal<decltype(rs1)>(0x1));
auto new_y = UOr(shifted_y,
decltype(y)(UShl(lsb_rs1, Literal<decltype(lsb_rs1)>(31))));
Write(REG_Y, new_y);
Write(dest, res);
WriteICCFlagsAddSub<tag_add>(
state, static_cast<uint32_t>(new_rs1),
static_cast<uint32_t>(new_rs2), static_cast<uint32_t>(res));
WriteICCFlagsAddSub<tag_add>(state, static_cast<uint32_t>(new_rs1),
static_cast<uint32_t>(new_rs2),
static_cast<uint32_t>(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;
+9 -10
View File
@@ -19,7 +19,7 @@
namespace {
template<typename S1, typename S2, typename D>
template <typename S1, typename S2, typename D>
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<decltype(e)>(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<R64, R64, R64W>;
DEF_ISEL(BSHUFFLE) = BSHUFFLE;
+24 -29
View File
@@ -19,8 +19,7 @@
namespace {
template <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
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<R64W>;
DEF_ISEL(FBN_fcc3) = FBN<R64W>;
#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<typename S> \
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 <typename S> \
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 <R64>;
DEF_ISEL(name##cond) = name##cond<R64>;
MAKE_BRANCH(BR, Z)
MAKE_BRANCH(BR, LEZ)
+72 -81
View File
@@ -28,8 +28,8 @@ template <typename S, typename D>
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<typename S1, typename S2, typename D>
template <typename S1, typename S2, typename D>
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<R8, M8W>;
DEF_ISEL(STH) = ST<R16, M16W>;
@@ -153,8 +153,8 @@ template <typename S, typename D>
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 <typename S, typename D>
@@ -167,8 +167,8 @@ template <typename S, typename D>
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<M8, R64W>;
DEF_ISEL(LDUH) = LDU<M16, R64W>;
@@ -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<uint8_t>(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<R64W>;
DEF_ISEL(LDSTUBA) = LDSTUBA<R64W>;
@@ -325,7 +325,7 @@ DEF_SEM(MOVN_xcc, S src, D dst) {
return memory;
}
}
} // namespace
DEF_ISEL(MOVA_icc) = MOVA_icc<R64, R64W>;
DEF_ISEL(MOVA_xcc) = MOVA_xcc<R64, R64W>;
@@ -335,17 +335,17 @@ DEF_ISEL(MOVN_xcc) = MOVN_xcc<R64, R64W>;
#define MAKE_SEMANTICS(name, cond, cc) \
namespace { \
template <typename S, typename D> \
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<R64, R64W>;
DEF_ISEL(MOV##cond##_##cc) = name##cond##_##cc<R64, R64W>;
#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 <typename C, typename S, typename D> \
DEF_SEM(name ## cond, C reg_cc, S src, D dst) { \
template <typename C, typename S, typename D> \
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<R64, R64, R64W>;
DEF_ISEL(name##cond) = name##cond<R64, R64, R64W>;
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 ## Q ## cond, R64 reg_cc, V64 src, V64W dst) { \
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)); \
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) { \
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_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)
+64 -61
View File
@@ -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 <typename S> \
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<R8>(3)); \
} else { \
if (FCmpEq(val1, val2)) { \
/* result = '00'; */ \
Write(state.fsr.fcc, Literal<R8>(0)); \
/* result = '00'; */ \
Write(state.fsr.fcc, Literal<R8>(0)); \
} else if (FCmpLt(val1, val2)) { \
/* result = '01'; */ \
Write(state.fsr.fcc, Literal<R8>(1)); \
} else { /* FCmpGt(val1, val2) */ \
/* result = '01'; */ \
Write(state.fsr.fcc, Literal<R8>(1)); \
} else { /* FCmpGt(val1, val2) */ \
/* result = '10'; */ \
Write(state.fsr.fcc, Literal<R8>(2)); \
Write(state.fsr.fcc, Literal<R8>(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;
+9 -10
View File
@@ -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<uint32_t>(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<R64, R64, R64W>;
@@ -83,7 +83,7 @@ DEF_SEM(ANDNCC, S1 src1, S2 src2, D dst) {
return memory;
}
}
} // namespace
// ANDN, ANDNcc
DEF_ISEL(ANDN) = ANDN<R64, R64, R64W>;
@@ -110,7 +110,7 @@ DEF_SEM(ORCC, S1 src1, S2 src2, D dst) {
return memory;
}
}
} // namespace
DEF_ISEL(OR) = OR<R64, R64, R64W>;
DEF_ISEL(ORcc) = ORCC<R64, R64, R64W>;
@@ -136,7 +136,7 @@ DEF_SEM(ORNCC, S1 src1, S2 src2, D dst) {
return memory;
}
}
} // namespace
DEF_ISEL(ORN) = ORN<R64, R64, R64W>;
DEF_ISEL(ORNcc) = ORNCC<R64, R64, R64W>;
@@ -162,7 +162,7 @@ DEF_SEM(XORCC, S1 src1, S2 src2, D dst) {
return memory;
}
}
} // namespace
DEF_ISEL(XOR) = XOR<R64, R64, R64W>;
DEF_ISEL(XORcc) = XORCC<R64, R64, R64W>;
@@ -188,7 +188,7 @@ DEF_SEM(XNORCC, S1 src1, S2 src2, D dst) {
return memory;
}
}
} // namespace
DEF_ISEL(XNOR) = XNOR<R64, R64, R64W>;
DEF_ISEL(XNORcc) = XNORCC<R64, R64, R64W>;
@@ -231,4 +231,3 @@ DEF_ISEL(SRA) = SRA<R32, I32, R64W>;
DEF_ISEL(SLLX) = SLL<R64, I64, R64W>;
DEF_ISEL(SRLX) = SRL<R64, I64, R64W>;
DEF_ISEL(SRAX) = SRA<R64, I64, R64W>;
+4 -3
View File
@@ -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 <typename S1, typename S2, typename D>
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);
+21 -17
View File
@@ -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.
+15 -10
View File
@@ -54,27 +54,29 @@ DEF_SEM(EDGE8CC, R64 src1, R64 src2, R64W dst) {
auto rs2 = Read(src2);
auto imask = Literal<I64>(0x7);
auto shift = Literal<I64>(3);
auto omask= Literal<I8>(0xff);
auto omask = Literal<I8>(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<tag_sub>(state, Literal<uint32_t>(rs1), Literal<uint32_t>(rs2), Literal<uint32_t>(diff));
WriteICCFlagsAddSub<tag_sub>(state, Literal<uint32_t>(rs1),
Literal<uint32_t>(rs2), Literal<uint32_t>(diff));
WriteXCCFlagsAddSub<tag_sub>(state, rs1, rs2, diff);
WriteZExt(dst, value);
return memory;
}
}
} // namespace
DEF_ISEL(FORS) = PACK_ORS<V32W, V32W, V32W>;
DEF_ISEL(FORD) = PACK_ORD<V64W, V64W, V64W>;
@@ -89,17 +91,20 @@ namespace {
DEF_SEM(IMPDEP1, I32 opf) {
HYPER_CALL_VECTOR = Literal<decltype(state.hyper_call_vector)>(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<decltype(state.hyper_call_vector)>(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;
+16 -16
View File
@@ -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 <typename R>
@@ -192,7 +192,7 @@ DEF_SEM(WRPRGL, R64 src1, R src2) {
WriteTrunc(PSR_GL, res);
return memory;
}
}
} // namespace
DEF_ISEL(WRPRTPC) = WRPRTPC<R64>;
DEF_ISEL(WRPRTPC_IMM) = WRPRTPC<I64>;
+3 -5
View File
@@ -30,6 +30,7 @@
#include <sstream>
#include <string>
#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-
+3 -1
View File
@@ -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;
+2 -2
View File
@@ -42,13 +42,13 @@ DEF_SEM(VPBROADCASTB, D dst, S1 src1) {
return memory;
}
template<typename S2>
template <typename S2>
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<unsigned>(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;
}
+6 -3
View File
@@ -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 <typename...Args>
template <typename... Args>
DEF_SEM(DoNothingWithParam, Args...) {
return memory;
}
@@ -176,9 +177,11 @@ DEF_ISEL(XLAT) = DoXLAT;
DEF_ISEL(CPUID) = DoCPUID;
DEF_ISEL(UD0_GPR32_MEMd) = DoNothingWithParam<R32, M32, IF_32BIT_ELSE(R32W, R64W)>;
DEF_ISEL(UD0_GPR32_MEMd) =
DoNothingWithParam<R32, M32, IF_32BIT_ELSE(R32W, R64W)>;
DEF_ISEL(UD1_GPR32_MEMd) = DoNothingWithParam<R32, M32, IF_32BIT_ELSE(R32W, R64W)>;
DEF_ISEL(UD1_GPR32_MEMd) =
DoNothingWithParam<R32, M32, IF_32BIT_ELSE(R32W, R64W)>;
DEF_ISEL(UD2) = DoNothingWithParam<IF_32BIT_ELSE(R32W, R64W)>;
+9 -12
View File
@@ -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 <typename D, typename S1, typename S2>
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;
}
+14 -14
View File
@@ -17,20 +17,20 @@
namespace {
#define MAKE_CMPXCHG_XAX(xax, xax_write, xax_read) \
template <typename D, typename S1, typename S2> \
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<tag_sub>(state, prev_value, check_val, sub_res); \
Write(FLAG_ZF, swap_flag); \
if (!swap_flag) { \
WriteZExt(REG_ ## xax_write, check_val); \
} \
return memory; \
}
template <typename D, typename S1, typename S2> \
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<tag_sub>(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)
+4 -1
View File
@@ -15,6 +15,7 @@
*/
#pragma once
// Disable the "loop not unrolled warnings"
#pragma clang diagnostic ignored "-Wpass-failed"
@@ -1631,6 +1632,7 @@ namespace {
template <typename D, typename S1>
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 <typename D, typename S1, typename S2>
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);
+2 -1
View File
@@ -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
+7 -4
View File
@@ -36,9 +36,9 @@
#include <vector>
#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<llvm::Constant>(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<llvm::InlineAsm>(val)) {
live_args[&inst].set(); // Weird to invoke inline assembly.
+161 -25
View File
@@ -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;
@@ -630,6 +632,137 @@ 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) {
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<uint64_t>`,
// 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<llvm::PointerType>(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::LiftExpressionOperandRec(
Instruction &inst, llvm::BasicBlock *block, llvm::Value *state_ptr,
llvm::Argument *arg, const OperandExpression *op) {
if (auto llvm_op = std::get_if<LLVMOpExpr>(op)) {
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);
}
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);
default:
LOG(FATAL) << "Invalid Expression "
<< llvm::Instruction::getOpcodeName(llvm_op->llvm_opcode);
return nullptr;
}
} else if (auto reg_op = std::get_if<const Register *>(op)) {
if (!arg || !llvm::isa<llvm::PointerType>(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<llvm::Constant *>(op)) {
return *ci_op;
} else if (auto str_op = std::get_if<std::string>(op)) {
if (!arg || !llvm::isa<llvm::PointerType>(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;
}
}
// Zero-extend a value to be the machine word size.
llvm::Value *InstructionLifter::LiftAddressOperand(Instruction &inst,
llvm::BasicBlock *block,
@@ -729,11 +862,14 @@ 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);
case Operand::kTypeExpression:
return LiftExpressionOperand(inst, block, state_ptr, arg, arch_op);
}
LOG(FATAL) << "Got a unknown operand type of "
+5 -7
View File
@@ -14,8 +14,7 @@
* limitations under the License.
*/
#include <remill/BC/InstructionLifter.h>
#include <glog/logging.h>
#include <llvm/ADT/SmallVector.h>
#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/Constants.h>
@@ -33,8 +32,7 @@
#include <llvm/Transforms/Scalar.h>
#include <llvm/Transforms/Utils/Cloning.h>
#include <llvm/Transforms/Utils/ValueMapper.h>
#include <glog/logging.h>
#include <remill/BC/InstructionLifter.h>
#include <functional>
#include <ios>
@@ -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
+142 -101
View File
@@ -16,15 +16,13 @@
#include <remill/BC/TraceLifter.h>
#include "InstructionLifter.h"
#include <set>
#include <sstream>
namespace remill {
namespace {
#include "InstructionLifter.h"
} // namespace
namespace remill {
namespace {} // namespace
TraceManager::~TraceManager(void) {}
@@ -102,6 +100,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);
}
@@ -151,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),
@@ -300,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);
@@ -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<uint64_t, llvm::BasicBlock *> 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>(llvm::ConstantInt::get(
pc_type, devirt_target.first, false)),
devirt_target.second);
}
AddTerminatingTailCall(block, intrinsics->jump);
break;
}
@@ -467,58 +426,46 @@ 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());
// 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<uint64_t, llvm::BasicBlock *> 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>(llvm::ConstantInt::get(
pc_type, devirt_target.first, false)),
devirt_target.second);
}
ir.CreateBr(GetOrCreateBranchNotTakenBlock());
AddCall(block, intrinsics->function_call);
llvm::BranchInst::Create(fall_through_block, block);
block = fall_through_block;
continue;
}
case Instruction::kCategoryConditionalIndirectFunctionCall: {
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);
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;
}
// 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 +475,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,17 +487,59 @@ 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;
}
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);
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;
}
// Lift an async hyper call to check if it should do the hypercall.
// If so, it will jump to the `do_hyper_call` block, otherwise it will
// jump to the block associated with the next PC. In the case of the
// `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(),
@@ -562,8 +552,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);
@@ -580,6 +570,32 @@ bool TraceLifter::Impl::Lift(
AddTerminatingTailCall(block, intrinsics->function_return);
break;
case Instruction::kCategoryConditionalFunctionReturn: {
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);
AddTerminatingTailCall(taken_block, intrinsics->function_return);
block = orig_not_taken_block;
continue;
}
case Instruction::kCategoryConditionalBranch: {
auto taken_block = GetOrCreateBranchTakenBlock();
auto not_taken_block = GetOrCreateBranchNotTakenBlock();
@@ -607,6 +623,31 @@ bool TraceLifter::Impl::Lift(
LoadBranchTaken(block), block);
break;
}
case Instruction::kCategoryConditionalIndirectJump: {
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);
AddTerminatingTailCall(taken_block, intrinsics->jump);
block = orig_not_taken_block;
continue;
}
}
}
+35 -21
View File
@@ -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<llvm::Module> 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 {};
}
@@ -461,6 +461,12 @@ namespace {
# define REMILL_BUILD_SEMANTICS_DIR_X86
#endif // REMILL_BUILD_SEMANTICS_DIR_X86
#ifndef REMILL_BUILD_SEMANTICS_DIR_AARCH32
# error \
"Macro `REMILL_BUILD_SEMANTICS_DIR_AARCH32` must be defined to support AArch64 architecture."
# define REMILL_BUILD_SEMANTICS_DIR_AARCH32
#endif // REMILL_BUILD_SEMANTICS_DIR_AARCH32
#ifndef REMILL_BUILD_SEMANTICS_DIR_AARCH64
# error \
"Macro `REMILL_BUILD_SEMANTICS_DIR_AARCH64` must be defined to support AArch64 architecture."
@@ -468,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
@@ -487,15 +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_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
@@ -2123,14 +2133,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<llvm::FixedVectorType>(type); fvt_type) {
} else if (auto fvt_type = llvm::dyn_cast<llvm::FixedVectorType>(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<llvm::ScalableVectorType>(type); svt_type) {
} else if (auto svt_type = llvm::dyn_cast<llvm::ScalableVectorType>(type);
svt_type) {
// same as above, but for scalable vectors
LOG(FATAL) << "Called BuildIndexes on unsupported type: "
<< remill::LLVMThingToString(type);
+2 -2
View File
@@ -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);
+2 -2
View File
@@ -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);