diff --git a/include/remill/Arch/Arch.h b/include/remill/Arch/Arch.h index 90f5ce95f..4fc5ff8ef 100644 --- a/include/remill/Arch/Arch.h +++ b/include/remill/Arch/Arch.h @@ -438,13 +438,21 @@ class Arch { ArchName arch_name); // Defined in `lib/Arch/SPARC32/Arch.cpp`. - static ArchPtr GetSPARC(llvm::LLVMContext *context, OSName os, + static ArchPtr GetSPARC32(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); + // Defined in `lib/Arch/Sleigh/SPARC32/SPARC32Arch.cpp + static ArchPtr GetSPARC32Sleigh(llvm::LLVMContext *context, OSName os, + ArchName arch_name); + + // Defined in `lib/Arch/Sleigh/SPARC64/SPARC64.cpp + static ArchPtr GetSPARC64Sleigh(llvm::LLVMContext *context, OSName os, + ArchName arch_name); + Arch(void) = delete; }; diff --git a/include/remill/Arch/Name.h b/include/remill/Arch/Name.h index 8bc57056a..4c030d3db 100644 --- a/include/remill/Arch/Name.h +++ b/include/remill/Arch/Name.h @@ -116,6 +116,7 @@ enum ArchName : uint32_t { kArchSparc32, kArchSparc64, + kArchSparc32_SLEIGH, kArchThumb2LittleEndian, diff --git a/include/remill/Arch/SPARC32/Runtime/State.h b/include/remill/Arch/SPARC32/Runtime/State.h index e11323ed9..0a3ebc62b 100644 --- a/include/remill/Arch/SPARC32/Runtime/State.h +++ b/include/remill/Arch/SPARC32/Runtime/State.h @@ -23,86 +23,57 @@ #include "remill/Arch/Runtime/Types.h" struct Reg final { - addr_t dword; + uint32_t dword; } __attribute__((packed)); +struct DoubleReg final { + union { + struct { + Reg reg1; + Reg reg2; + }; + uint64_t qword; + }; +}; -union PtrReg final { - addr_t dword; -} __attribute__((packed)); - -static_assert(sizeof(PtrReg) == 4); +static_assert(sizeof(uint32_t) * 2 == sizeof(DoubleReg), "Invalid packing of `DoubleReg`."); struct GPR { + DoubleReg i0_1; + volatile uint64_t _2; + DoubleReg i2_3; + volatile uint64_t _3; + DoubleReg i4_5; + volatile uint64_t _5; + DoubleReg fp_7; + volatile uint64_t _6; - // Prevents LLVM from casting a `GPR` into an `i64` to access `I0`. - volatile addr_t _0; - Reg i0; - volatile addr_t _1; - Reg i1; - volatile addr_t _2; - Reg i2; - volatile addr_t _3; - Reg i3; - volatile addr_t _4; - Reg i4; - volatile addr_t _5; - Reg i5; - volatile addr_t _6; - PtrReg i6; - volatile addr_t _7; - Reg i7; - - volatile addr_t _8; - Reg l0; - volatile addr_t _9; - Reg l1; - volatile addr_t _10; - Reg l2; - volatile addr_t _11; - Reg l3; - volatile addr_t _12; - Reg l4; - volatile addr_t _13; - Reg l5; - volatile addr_t _14; - Reg l6; - volatile addr_t _15; - Reg l7; + volatile uint64_t _8; + DoubleReg l0_1; + volatile uint64_t _9; + DoubleReg l2_3; + volatile uint64_t _12; + DoubleReg l4_5; + volatile uint64_t _14; + DoubleReg l6_7; - volatile addr_t _16; - Reg o0; - volatile addr_t _17; - Reg o1; - volatile addr_t _18; - Reg o2; - volatile addr_t _19; - Reg o3; - volatile addr_t _20; - Reg o4; - volatile addr_t _21; - Reg o5; - volatile addr_t _22; - PtrReg o6; - volatile addr_t _23; - Reg o7; + volatile uint64_t _16; + DoubleReg o0_1; + volatile uint64_t _18; + DoubleReg o2_3; + volatile uint64_t _20; + DoubleReg o4_5; + volatile uint64_t _22; + DoubleReg sp_7; - volatile addr_t _24; - Reg g0; - volatile addr_t _25; - Reg g1; - volatile addr_t _26; - Reg g2; - volatile addr_t _27; - Reg g3; - volatile addr_t _28; - Reg g4; - volatile addr_t _29; - Reg g5; - volatile addr_t _30; - Reg g6; - volatile addr_t _31; - Reg g7; + volatile uint64_t _24; + DoubleReg g0_1; + volatile uint64_t _25; + DoubleReg g2_3; + volatile uint64_t _28; + DoubleReg g4_5; + volatile uint64_t _30; + DoubleReg g6_7; }; enum AlternativeSpaceIdentifier : uint32_t { @@ -160,18 +131,28 @@ struct FSRReg final { static_assert(24 == sizeof(struct FSRReg), "Invalid packing of `struct FSRReg`."); -// Integer condition code register flags -struct ICCRFlags final { +// Condition Codes register flags +struct CCRFlags final { struct { volatile uint8_t _0; - bool c; + bool i_cf; volatile uint8_t _1; - bool v; + bool i_vf; volatile uint8_t _2; - bool z; + bool i_zf; volatile uint8_t _3; - bool n; - } __attribute__((packed)) icc, xcc; + bool i_nf; + } __attribute__((packed)) icc; + struct { + volatile uint8_t _0; + bool x_cf; + volatile uint8_t _1; + bool x_vf; + volatile uint8_t _2; + bool x_zf; + volatile uint8_t _3; + bool x_nf; + } __attribute__((packed)) xcc; } __attribute__((packed)); union GSRFlags final { @@ -188,41 +169,31 @@ union GSRFlags final { } __attribute__((packed)); struct ASR final { - Reg yreg; // ASR 0 volatile uint32_t _0; - 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; - } __attribute__((packed)); - } __attribute__((packed)); - volatile uint64_t _2; - 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; - } __attribute__((packed)); - } __attribute__((packed)); + Reg yreg; // asr 0 + volatile uint32_t _1; + Reg ccr; // asr 2 + volatile uint32_t _2; + Reg tick; // asr 4 + volatile uint32_t _3; + Reg pcr; // asr16 volatile uint32_t _4; - GSRFlags gsr; - volatile uint64_t _5; - addr64_t softint; // ASR 20 - volatile uint64_t _6; - addr64_t stick; // ASR 24 - volatile uint64_t _7; - addr64_t stick_cmpr; // ASR 25 - volatile uint64_t _8; - addr64_t cfr; // ASR 26 - volatile uint64_t _9; - addr64_t pause; // ASR 27 - volatile uint64_t _10; - addr64_t mwait; // ASR 28 + Reg pic; // asr 17 + volatile uint32_t _5; + Reg gsr; // asr 19 + volatile uint32_t _6; + Reg softint_set; // asr 20 + volatile uint32_t _7; + Reg softint_clr; // asr 21 + volatile uint32_t _8; + Reg softint; // asr 22 + volatile uint32_t _9; + Reg tick_cmpr; // asr 23 + volatile uint32_t _10; + Reg stick; // asr 24 + volatile uint32_t _11; + Reg stick_cmpr; // asr 25 + volatile uint32_t _12; } __attribute__((packed)); struct CSR { @@ -281,72 +252,29 @@ struct PSR { uint8_t gl; } __attribute__((packed)); -struct RegisterWindow { - volatile addr_t _0; - addr_t l0; - volatile addr_t _1; - addr_t l1; - volatile addr_t _2; - addr_t l2; - volatile addr_t _3; - addr_t l3; - volatile addr_t _4; - addr_t l4; - volatile addr_t _5; - addr_t l5; - volatile addr_t _6; - addr_t l6; - volatile addr_t _7; - addr_t l7; - - volatile addr_t _8; - addr_t i0; - volatile addr_t _9; - addr_t i1; - volatile addr_t _10; - addr_t i2; - volatile addr_t _11; - addr_t i3; - volatile addr_t _12; - addr_t i4; - volatile addr_t _13; - addr_t i5; - volatile addr_t _14; - addr_t i6; - volatile addr_t _15; - addr_t i7; - volatile addr_t _16; - RegisterWindow *prev_window; -}; - struct alignas(16) SPARC32State : public ArchState { - FPURegs fpreg; // 512 bytes volatile uint64_t _0; - GPR gpr; // 256 bytes + FPURegs fpreg; // 128 bytes volatile uint64_t _1; - ASR asr; // 176 bytes + GPR gpr; // 256 bytes volatile uint64_t _2; - PSR psr; // 56 bytes - volatile uint64_t _3; FSRReg fsr; // 24 bytes - volatile uint64_t _4; - CSR csr; // 8 bytes + volatile uint64_t _3; + ASR asr; // 168 bytes + volatile uint32_t _4; + CCRFlags ccr; volatile uint32_t _5; - Reg pc; // 4 bytes + PSR psr; // 56 bytes volatile uint32_t _6; - Reg next_pc; // 4 bytes + Reg pc; // 4 bytes volatile uint32_t _7; - - // NOTE(pag): This *must* go at the end, as if we change the target arch/data - // layout, then we want to make sure that the offset of this - // remains the same and doesn't shift other things around. -#if defined(INCLUDED_FROM_REMILL) - uint32_t window; -#else - RegisterWindow *window; // smuggled. - static_assert(sizeof(RegisterWindow *) == 4, - "Invalid size of `RegisterWindow`"); -#endif + Reg cwp; + // fake register for sleigh + uint8_t decompile_mode; + volatile uint8_t _8; + // fake register for sleigh + uint8_t didrestore; + volatile uint8_t _9; }; struct State : public SPARC32State {}; diff --git a/include/remill/Arch/SPARC32/SPARC32Base.h b/include/remill/Arch/SPARC32/SPARC32Base.h new file mode 100644 index 000000000..010c30323 --- /dev/null +++ b/include/remill/Arch/SPARC32/SPARC32Base.h @@ -0,0 +1,46 @@ +#pragma once +#include +#include + +#include + +namespace remill { + +class SPARC32ArchBase : public virtual ArchBase { + public: + SPARC32ArchBase(llvm::LLVMContext *context_, OSName os_name_, + ArchName arch_name_) + : ArchBase(context_, os_name_, arch_name_) {} + + virtual std::string_view StackPointerRegisterName(void) const override; + + std::string_view ProgramCounterRegisterName(void) const override; + + llvm::CallingConv::ID DefaultCallingConv(void) const override; + llvm::DataLayout DataLayout(void) const override; + llvm::Triple Triple(void) const override; + + // Align/Minimum/Maximum number of bytes in an instruction. + uint64_t MinInstructionAlign(const DecodingContext &) const override; + uint64_t MinInstructionSize(const DecodingContext &) const override; + uint64_t MaxInstructionSize(const DecodingContext &, + bool permit_fuse_idioms) const override; + bool MemoryAccessIsLittleEndian(void) const override; + // Returns `true` if a given instruction might have a delay slot. + bool MayHaveDelaySlot(const Instruction &inst) const override; + // Returns `true` if we should lift the semantics of `next_inst` as a delay + // slot of `inst`. The `branch_taken_path` tells us whether we are in the + // context of the taken path of a branch or the not-taken path of a branch. + virtual bool NextInstructionIsDelayed(const Instruction &inst, + const Instruction &next_inst, + bool branch_taken_path) const final; + void PopulateRegisterTable(void) const override; + // Populate a just-initialized lifted function function with architecture- + // specific variables. + void + FinishLiftedFunctionInitialization(llvm::Module *module, + llvm::Function *bb_func) const override; + virtual ~SPARC32ArchBase(void) = default; +}; + +} // namespace remill diff --git a/include/remill/BC/PCodeCFG.h b/include/remill/BC/PCodeCFG.h index 76a7d87e7..84e7d47eb 100644 --- a/include/remill/BC/PCodeCFG.h +++ b/include/remill/BC/PCodeCFG.h @@ -76,6 +76,7 @@ class PcodeCFGBuilder { private: PcodeBlock BuildBlock(size_t start_ind, size_t next_start) const; + std::optional GetControlFlowExitsForIndex(size_t index) const; BlockExit GetBlockExitsForIndex(size_t index) const; std::vector GetIntraProcTargets(size_t index) const; std::vector GetBlockStarts() const; diff --git a/lib/Arch/Arch.cpp b/lib/Arch/Arch.cpp index dbb012d3d..e9edc59f0 100644 --- a/lib/Arch/Arch.cpp +++ b/lib/Arch/Arch.cpp @@ -57,6 +57,7 @@ static unsigned AddressSize(ArchName arch_name) { case kArchAArch32LittleEndian: case kArchThumb2LittleEndian: case kArchSparc32: + case kArchSparc32_SLEIGH: case kArchPPC: return 32; case kArchAMD64: case kArchAMD64_AVX: @@ -114,6 +115,7 @@ ArchLocker Arch::Lock(ArchName arch_name_) { case ArchName::kArchAArch64LittleEndian_SLEIGH: case ArchName::kArchAMD64_SLEIGH: case ArchName::kArchX86_SLEIGH: + case ArchName::kArchSparc32_SLEIGH: case ArchName::kArchPPC: return &gSleighArchLock; default: return ArchLocker(); } @@ -227,7 +229,7 @@ auto Arch::GetArchByName(llvm::LLVMContext *context_, OSName os_name_, case kArchSparc32: { DLOG(INFO) << "Using architecture: 32-bit SPARC"; - return GetSPARC(context_, os_name_, arch_name_); + return GetSPARC32(context_, os_name_, arch_name_); } case kArchSparc64: { @@ -235,6 +237,11 @@ auto Arch::GetArchByName(llvm::LLVMContext *context_, OSName os_name_, return GetSPARC64(context_, os_name_, arch_name_); } + case kArchSparc32_SLEIGH: { + DLOG(INFO) << "Using architecture: 32-bit SPARC32_Sleigh"; + return GetSPARC32Sleigh(context_, os_name_, arch_name_); + } + case kArchPPC: { DLOG(INFO) << "Using architecture: PowerPC"; return GetSleighPPC(context_, os_name_, arch_name_); @@ -791,6 +798,8 @@ const Register *ArchBase::AddRegister(const char *reg_name_, parent_reg = reg_by_name[parent_reg_name]; } + DLOG(INFO) << "Adding register " << reg_name << " with type " << val_type; + auto reg_impl = new Register(reg_name, offset, val_type, parent_reg, this); //reg_impl->ComputeGEPAccessors(dl, this->state_type); diff --git a/lib/Arch/Instruction.cpp b/lib/Arch/Instruction.cpp index b7c350f5b..ba6a12fcb 100644 --- a/lib/Arch/Instruction.cpp +++ b/lib/Arch/Instruction.cpp @@ -669,6 +669,7 @@ std::string Instruction::Serialize(void) const { case kArchAArch32LittleEndian: ss << "AArch32"; break; case kArchAArch64LittleEndian_SLEIGH: case kArchAArch64LittleEndian: ss << "AArch64"; break; + case kArchSparc32_SLEIGH: case kArchSparc32: ss << "SPARC32"; break; case kArchSparc64: ss << "SPARC64"; break; case kArchPPC: ss << "PowerPC"; break; diff --git a/lib/Arch/Name.cpp b/lib/Arch/Name.cpp index 59892fc83..d8180f956 100644 --- a/lib/Arch/Name.cpp +++ b/lib/Arch/Name.cpp @@ -73,6 +73,9 @@ ArchName GetArchName(std::string_view arch_name) { } else if (arch_name == "sparc64") { return kArchSparc64; + } else if (arch_name == "sparc32_sleigh") { + return kArchSparc32_SLEIGH; + } else if (arch_name == "ppc") { return kArchPPC; @@ -100,6 +103,7 @@ static const std::string_view kArchNames[] = { [kArchAArch64LittleEndian_SLEIGH] = "aarch64_sleigh", [kArchSparc32] = "sparc32", [kArchSparc64] = "sparc64", + [kArchSparc32_SLEIGH] = "sparc32_sleigh", [kArchThumb2LittleEndian] = "thumb2", [kArchPPC] = "ppc", }; diff --git a/lib/Arch/SPARC32/Arch.cpp b/lib/Arch/SPARC32/Arch.cpp index 81be2c2a7..30af04400 100644 --- a/lib/Arch/SPARC32/Arch.cpp +++ b/lib/Arch/SPARC32/Arch.cpp @@ -15,6 +15,7 @@ */ #include +#include #include // For `Arch` and `ArchImpl`. #include "Decode.h" @@ -25,7 +26,6 @@ #include "remill/OS/OS.h" // clang-format off -#define ADDRESS_SIZE_BITS 32 #define INCLUDED_FROM_REMILL #include "remill/Arch/SPARC32/Runtime/State.h" @@ -33,11 +33,6 @@ namespace remill { namespace sparc { -namespace { -static const std::string_view kSPRegName = "sp"; -static const std::string_view kPCRegName = "pc"; -} // namespace - const std::string_view kCCRName[4] = {"icc", {}, "xcc", {}}; @@ -130,344 +125,22 @@ void AddImmop(Instruction &inst, uint64_t imm, unsigned size, bool is_signed) { } -class SPARC32Arch final : public DefaultContextAndLifter { +class SPARC32Arch final : public SPARC32ArchBase, public DefaultContextAndLifter { public: - SPARC32Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_) - : ArchBase(context_, os_name_, arch_name_), - DefaultContextAndLifter(context_, os_name_, arch_name_) {} + SPARC32Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_); virtual ~SPARC32Arch(void) = default; - // Returns the name of the stack pointer register. - std::string_view StackPointerRegisterName(void) const final { - return kSPRegName; - } - - // Returns the name of the program counter register. - std::string_view ProgramCounterRegisterName(void) const final { - return kPCRegName; - } - - uint64_t MinInstructionAlign(const DecodingContext &) const final { - return 4; - } - - uint64_t MinInstructionSize(const DecodingContext &) const final { - return 4; - } - - // Maximum number of bytes in an instruction. - uint64_t MaxInstructionSize(const DecodingContext &, - bool permit_fuse_idioms) const final { - return permit_fuse_idioms ? 8 : 4; // To handle `SET` idioms. - } - - // Default calling convention for this architecture. - llvm::CallingConv::ID DefaultCallingConv(void) const final { - return llvm::CallingConv::C; - } - - // Populate the table of register information. - void PopulateRegisterTable(void) const final; - - // Populate a just-initialized lifted function function with architecture- - // specific variables. - void - FinishLiftedFunctionInitialization(llvm::Module *module, - llvm::Function *bb_func) const override; - - llvm::Triple Triple(void) const final; - llvm::DataLayout DataLayout(void) const final; - // Decode an instruction. bool ArchDecodeInstruction(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 { - return false; - } - - // Returns `true` if a given instruction might have a delay slot. - bool MayHaveDelaySlot(const Instruction &inst) const final; - - // Returns `true` if we should lift the semantics of `next_inst` as a delay - // slot of `inst`. The `branch_taken_path` tells us whether we are in the - // context of the taken path of a branch or the not-taken path of a branch. - virtual bool NextInstructionIsDelayed(const Instruction &inst, - const Instruction &next_inst, - bool branch_taken_path) const final; }; -// Populate the table of register information. -void SPARC32Arch::PopulateRegisterTable(void) const { - - reg_by_offset.resize(sizeof(SPARC32State)); - -#define OFFSET_OF(type, access) \ - (reinterpret_cast(&reinterpret_cast( \ - static_cast(nullptr)->access))) - -#define REG(name, access, type) \ - AddRegister(#name, type, OFFSET_OF(SPARC32State, access), nullptr) - -#define SUB_REG(name, access, type, parent_reg_name) \ - AddRegister(#name, type, OFFSET_OF(SPARC32State, access), #parent_reg_name) - - auto u8 = llvm::Type::getInt8Ty(*context); - auto u32 = llvm::Type::getInt32Ty(*context); - auto u64 = llvm::Type::getInt64Ty(*context); - auto u128 = llvm::Type::getInt128Ty(*context); - auto f32 = llvm::Type::getFloatTy(*context); - auto f64 = llvm::Type::getDoubleTy(*context); - - std::vector window_types(33, u64); - auto window_type = RegisterWindowType(); - auto window_ptr_type = llvm::PointerType::get(*context, 0); - window_types.push_back(window_ptr_type); - window_type->setBody(window_types, false); - - REG(pc, pc.dword, u32); - SUB_REG(PC, pc.dword, u32, pc); - - REG(npc, next_pc.dword, u32); - SUB_REG(NEXT_PC, next_pc.dword, u32, npc); - - REG(sp, gpr.o6.dword, u32); - SUB_REG(SP, gpr.o6.dword, u32, sp); - - REG(fp, gpr.i6.dword, u32); - SUB_REG(FP, gpr.i6.dword, u32, fp); - - REG(i0, gpr.i0.dword, u32); - REG(i1, gpr.i1.dword, u32); - REG(i2, gpr.i2.dword, u32); - REG(i3, gpr.i3.dword, u32); - REG(i4, gpr.i4.dword, u32); - REG(i5, gpr.i5.dword, u32); - SUB_REG(i6, gpr.i6.dword, u32, fp); - REG(i7, gpr.i7.dword, u32); - REG(l0, gpr.l0.dword, u32); - REG(l1, gpr.l1.dword, u32); - REG(l2, gpr.l2.dword, u32); - REG(l3, gpr.l3.dword, u32); - REG(l4, gpr.l4.dword, u32); - REG(l5, gpr.l5.dword, u32); - REG(l6, gpr.l6.dword, u32); - REG(l7, gpr.l7.dword, u32); - REG(o0, gpr.o0.dword, u32); - REG(o1, gpr.o1.dword, u32); - REG(o2, gpr.o2.dword, u32); - REG(o3, gpr.o3.dword, u32); - REG(o4, gpr.o4.dword, u32); - REG(o5, gpr.o5.dword, u32); - SUB_REG(o6, gpr.o6.dword, u32, sp); - REG(o7, gpr.o7.dword, u32); - - REG(g1, gpr.g1.dword, u32); - REG(g2, gpr.g2.dword, u32); - REG(g3, gpr.g3.dword, u32); - REG(g4, gpr.g4.dword, u32); - REG(g5, gpr.g5.dword, u32); - REG(g6, gpr.g6.dword, u32); - REG(g7, gpr.g7.dword, u32); - - // Ancillary State Register - REG(y, asr.yreg.dword, u32); - REG(asi, asr.asi_flat, u32); - REG(tick, asr.tick, u64); - REG(fprs, asr.fprs_flat, u32); - REG(gsr, asr.gsr.flat, u64); - REG(softint, asr.softint, u64); - REG(stick, asr.stick, u64); - REG(stick_cmpr, asr.stick_cmpr, u64); - REG(cfr, asr.cfr, u64); - - REG(icc_c, asr.ccr.icc.c, u8); - REG(icc_v, asr.ccr.icc.v, u8); - REG(icc_z, asr.ccr.icc.z, u8); - REG(icc_n, asr.ccr.icc.n, u8); - - REG(xcc_c, asr.ccr.xcc.c, u8); - REG(xcc_v, asr.ccr.xcc.v, u8); - REG(xcc_z, asr.ccr.xcc.z, u8); - REG(xcc_n, asr.ccr.xcc.n, u8); - - REG(ccf_fcc0, fsr.fcc0, u8); - REG(ccf_fcc1, fsr.fcc1, u8); - REG(ccf_fcc2, fsr.fcc2, u8); - REG(ccf_fcc3, fsr.fcc3, u8); - - REG(ccc, csr.ccc, u8); - - REG(fsr_aexc, fsr.aexc, u8); - REG(fsr_cexc, fsr.cexc, u8); - - REG(v0, fpreg.v[0], u128); - REG(v1, fpreg.v[1], u128); - REG(v2, fpreg.v[2], u128); - REG(v3, fpreg.v[3], u128); - REG(v4, fpreg.v[4], u128); - REG(v5, fpreg.v[5], u128); - REG(v6, fpreg.v[6], u128); - REG(v7, fpreg.v[7], u128); - - SUB_REG(f0, fpreg.v[0].floats.elems[0], f32, v0); - SUB_REG(f1, fpreg.v[0].floats.elems[1], f32, v0); - SUB_REG(f2, fpreg.v[0].floats.elems[2], f32, v0); - SUB_REG(f3, fpreg.v[0].floats.elems[3], f32, v0); - SUB_REG(f4, fpreg.v[1].floats.elems[0], f32, v1); - SUB_REG(f5, fpreg.v[1].floats.elems[1], f32, v1); - SUB_REG(f6, fpreg.v[1].floats.elems[2], f32, v1); - SUB_REG(f7, fpreg.v[1].floats.elems[3], f32, v1); - SUB_REG(f8, fpreg.v[2].floats.elems[0], f32, v2); - SUB_REG(f9, fpreg.v[2].floats.elems[1], f32, v2); - SUB_REG(f10, fpreg.v[2].floats.elems[2], f32, v2); - SUB_REG(f11, fpreg.v[2].floats.elems[3], f32, v2); - SUB_REG(f12, fpreg.v[3].floats.elems[0], f32, v3); - SUB_REG(f13, fpreg.v[3].floats.elems[1], f32, v3); - SUB_REG(f14, fpreg.v[3].floats.elems[2], f32, v3); - SUB_REG(f15, fpreg.v[3].floats.elems[3], f32, v3); - SUB_REG(f16, fpreg.v[4].floats.elems[0], f32, v4); - SUB_REG(f17, fpreg.v[4].floats.elems[1], f32, v4); - SUB_REG(f18, fpreg.v[4].floats.elems[2], f32, v4); - SUB_REG(f19, fpreg.v[4].floats.elems[3], f32, v4); - SUB_REG(f20, fpreg.v[5].floats.elems[0], f32, v5); - SUB_REG(f21, fpreg.v[5].floats.elems[1], f32, v5); - SUB_REG(f22, fpreg.v[5].floats.elems[2], f32, v5); - SUB_REG(f23, fpreg.v[5].floats.elems[3], f32, v5); - SUB_REG(f24, fpreg.v[6].floats.elems[0], f32, v6); - SUB_REG(f25, fpreg.v[6].floats.elems[1], f32, v6); - SUB_REG(f26, fpreg.v[6].floats.elems[2], f32, v6); - SUB_REG(f27, fpreg.v[6].floats.elems[3], f32, v6); - SUB_REG(f28, fpreg.v[7].floats.elems[0], f32, v7); - SUB_REG(f29, fpreg.v[7].floats.elems[1], f32, v7); - SUB_REG(f30, fpreg.v[7].floats.elems[2], f32, v7); - SUB_REG(f31, fpreg.v[7].floats.elems[3], f32, v7); - - SUB_REG(d0, fpreg.v[0].doubles.elems[0], f64, v0); - SUB_REG(d2, fpreg.v[0].doubles.elems[1], f64, v0); - SUB_REG(d4, fpreg.v[1].doubles.elems[0], f64, v1); - SUB_REG(d6, fpreg.v[1].doubles.elems[1], f64, v1); - SUB_REG(d8, fpreg.v[2].doubles.elems[0], f64, v2); - SUB_REG(d10, fpreg.v[2].doubles.elems[1], f64, v2); - SUB_REG(d12, fpreg.v[3].doubles.elems[0], f64, v3); - SUB_REG(d14, fpreg.v[3].doubles.elems[1], f64, v3); - SUB_REG(d16, fpreg.v[4].doubles.elems[0], f64, v4); - SUB_REG(d18, fpreg.v[4].doubles.elems[1], f64, v4); - SUB_REG(d20, fpreg.v[5].doubles.elems[0], f64, v5); - SUB_REG(d22, fpreg.v[5].doubles.elems[1], f64, v5); - SUB_REG(d24, fpreg.v[6].doubles.elems[0], f64, v6); - SUB_REG(d26, fpreg.v[6].doubles.elems[1], f64, v6); - SUB_REG(d28, fpreg.v[7].doubles.elems[0], f64, v7); - SUB_REG(d30, fpreg.v[7].doubles.elems[1], f64, v7); - - // NOTE(pag): This is a bit of a lie, but kind of like in x87 with 80-bit - // extended precision, we treat quad precision floats as being - // doubles. - SUB_REG(q0, fpreg.v[0].doubles.elems[0], f64, v0); - SUB_REG(q4, fpreg.v[1].doubles.elems[0], f64, v1); - SUB_REG(q8, fpreg.v[2].doubles.elems[0], f64, v2); - SUB_REG(q12, fpreg.v[3].doubles.elems[0], f64, v3); - SUB_REG(q16, fpreg.v[4].doubles.elems[0], f64, v4); - SUB_REG(q20, fpreg.v[5].doubles.elems[0], f64, v5); - SUB_REG(q24, fpreg.v[6].doubles.elems[0], f64, v6); - SUB_REG(q28, fpreg.v[7].doubles.elems[0], f64, v7); - - REG(PREV_WINDOW_LINK, window, window_ptr_type); -} - - -// Populate a just-initialized lifted function function with architecture- -// specific variables. -void SPARC32Arch::FinishLiftedFunctionInitialization( - llvm::Module *module, llvm::Function *bb_func) const { - - auto &context = module->getContext(); - auto u8 = llvm::Type::getInt8Ty(context); - auto u32 = llvm::Type::getInt32Ty(context); - - auto zero_u8 = llvm::Constant::getNullValue(u8); - auto zero_u32 = llvm::Constant::getNullValue(u32); - - const auto entry_block = &bb_func->getEntryBlock(); - llvm::IRBuilder<> ir(entry_block); - - ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "g0"), false); - ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "ignore_write_to_g0"), - false); - - // this is for unknown asr to avoid crash. - ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "asr"), false); - - // NOTE(pag): Passing `nullptr` as the type will force `Arch::AddRegister` - // to infer the type based on what it finds. It's a pointer to - // a structure type, so we can check that. - const auto prev_window_link = RegisterByName("PREV_WINDOW_LINK"); - CHECK(prev_window_link->type->isPointerTy()); - const auto window_type = RegisterWindowType(); - CHECK(window_type->isStructTy()); - - auto window = ir.CreateAlloca(window_type, nullptr, "WINDOW"); - ir.CreateAlloca(prev_window_link->type, nullptr, "PREV_WINDOW"); - - // `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 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_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); - - 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); -} - -llvm::Triple SPARC32Arch::Triple(void) const { - auto triple = BasicTriple(); - triple.setArch(llvm::Triple::sparc); - return triple; -} - -llvm::DataLayout SPARC32Arch::DataLayout(void) const { - return llvm::DataLayout("E-m:e-p:32:32-i64:64-f128:64-n32-S64"); -} - -// Returns `true` if a given instruction might have a delay slot. -bool SPARC32Arch::MayHaveDelaySlot(const Instruction &inst) const { - return inst.has_branch_taken_delay_slot || - inst.has_branch_not_taken_delay_slot; -} - -// Returns `true` if we should lift the semantics of `next_inst` as a delay -// slot of `inst`. The `branch_taken_path` tells us whether we are in the -// context of the taken path of a branch or the not-taken path of a branch. -bool SPARC32Arch::NextInstructionIsDelayed(const Instruction &inst, - const Instruction &next_inst, - bool branch_taken_path) const { - if (inst.delayed_pc != next_inst.pc) { - return false; - } - - if (branch_taken_path) { - return inst.has_branch_taken_delay_slot; - } else { - return inst.has_branch_not_taken_delay_slot; - } -} +SPARC32Arch::SPARC32Arch(llvm::LLVMContext *context_, OSName os_name_, + ArchName arch_name_) + : ArchBase(context_, os_name_, arch_name_), + SPARC32ArchBase(context_, os_name_, arch_name_), + DefaultContextAndLifter(context_, os_name_, arch_name_) {} // Decode an instruction. bool SPARC32Arch::ArchDecodeInstruction(uint64_t address, @@ -515,13 +188,13 @@ bool SPARC32Arch::ArchDecodeInstruction(uint64_t address, } // 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_, +Arch::ArchPtr Arch::GetSPARC32(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_) { if (arch_name_ == kArchSparc32) { return std::make_unique(context_, os_name_, arch_name_); } else { - LOG(FATAL) << "Invalid arch name passed to Arch::GetSPARC: " + LOG(FATAL) << "Invalid arch name passed to Arch::GetSPARC32: " << GetArchName(arch_name_); return {}; } diff --git a/lib/Arch/SPARC32/CMakeLists.txt b/lib/Arch/SPARC32/CMakeLists.txt index c75440c50..6d048ecb9 100644 --- a/lib/Arch/SPARC32/CMakeLists.txt +++ b/lib/Arch/SPARC32/CMakeLists.txt @@ -44,4 +44,4 @@ if(REMILL_ENABLE_INSTALL_TARGET) TARGETS remill_arch_sparc32 EXPORT remillTargets ) -endif() \ No newline at end of file +endif() diff --git a/lib/Arch/SPARC32/Runtime/CMakeLists.txt b/lib/Arch/SPARC32/Runtime/CMakeLists.txt index 2a16d5c61..13bc2bc1b 100644 --- a/lib/Arch/SPARC32/Runtime/CMakeLists.txt +++ b/lib/Arch/SPARC32/Runtime/CMakeLists.txt @@ -54,32 +54,8 @@ function(add_runtime_helper target_name little_endian) INCLUDEDIRECTORIES "${REMILL_INCLUDE_DIR}" "${REMILL_SOURCE_DIR}" INSTALLDESTINATION "${REMILL_INSTALL_SEMANTICS_DIR}" ARCH sparc - - DEPENDENCIES - "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Float.h" - "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/State.h" - "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Types.h" - "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Operators.h" - "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Intrinsics.h" - "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/HyperCall.h" - "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Definitions.h" - - "${REMILL_INCLUDE_DIR}/remill/Arch/SPARC32/Runtime/State.h" - "${REMILL_INCLUDE_DIR}/remill/Arch/SPARC32/Runtime/Types.h" - - "${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/COND.cpp" - "${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/BINARY.cpp" - "${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/BRANCH.cpp" - "${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/DATAXFER.cpp" - "${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/FLAGS.cpp" - "${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/FOP.cpp" - "${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/LOGICAL.cpp" - "${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/MISC.cpp" - "${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/TRAP.cpp" - "${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/WINDOW.cpp" - - "${REMILL_LIB_DIR}/Arch/Runtime/Intrinsics.cpp" ) endfunction() add_runtime_helper(sparc32 0) +add_runtime_helper(sparc32_sleigh 0) diff --git a/lib/Arch/SPARC32/Runtime/Instructions.cpp b/lib/Arch/SPARC32/Runtime/Instructions.cpp index d348821b5..90d51a9a6 100644 --- a/lib/Arch/SPARC32/Runtime/Instructions.cpp +++ b/lib/Arch/SPARC32/Runtime/Instructions.cpp @@ -151,101 +151,9 @@ DEF_SEM(HandleInvalidInstruction) { return memory; } -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; - - prev_window = window; - - window->l0 = Read(REG_L0); - window->l1 = Read(REG_L1); - window->l2 = Read(REG_L2); - window->l3 = Read(REG_L3); - window->l4 = Read(REG_L4); - window->l5 = Read(REG_L5); - window->l6 = Read(REG_L6); - window->l7 = Read(REG_L7); - - window->i0 = Read(REG_I0); - window->i1 = Read(REG_I1); - window->i2 = Read(REG_I2); - window->i3 = Read(REG_I3); - window->i4 = Read(REG_I4); - window->i5 = Read(REG_I5); - window->i6 = Read(REG_I6); - window->i7 = Read(REG_I7); - - // Move output register to input - Write(REG_I0, REG_O0); - Write(REG_I1, REG_O1); - Write(REG_I2, REG_O2); - Write(REG_I3, REG_O3); - Write(REG_I4, REG_O4); - Write(REG_I5, REG_O5); - Write(REG_I6, REG_O6); - Write(REG_I7, REG_O7); -} - -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); - 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; - - // Move input register to output - Write(REG_O0, REG_I0); - Write(REG_O1, REG_I1); - Write(REG_O2, REG_I2); - Write(REG_O3, REG_I3); - Write(REG_O4, REG_I4); - Write(REG_O5, REG_I5); - Write(REG_O6, REG_I6); - Write(REG_O7, REG_I7); - - Write(REG_L0, window->l0); - Write(REG_L1, window->l1); - Write(REG_L2, window->l2); - Write(REG_L3, window->l3); - Write(REG_L4, window->l4); - Write(REG_L5, window->l5); - Write(REG_L6, window->l6); - Write(REG_L7, window->l7); - - Write(REG_I0, window->i0); - Write(REG_I1, window->i1); - Write(REG_I2, window->i2); - Write(REG_I3, window->i3); - Write(REG_I4, window->i4); - Write(REG_I5, window->i5); - Write(REG_I6, window->i6); - Write(REG_I7, window->i7); -} - } // namespace // Takes the place of an unsupported instruction. 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/BINARY.cpp" -#include "lib/Arch/SPARC32/Semantics/BRANCH.cpp" -#include "lib/Arch/SPARC32/Semantics/DATAXFER.cpp" -#include "lib/Arch/SPARC32/Semantics/FOP.cpp" -#include "lib/Arch/SPARC32/Semantics/LOGICAL.cpp" -#include "lib/Arch/SPARC32/Semantics/MISC.cpp" -#include "lib/Arch/SPARC32/Semantics/TRAP.cpp" -#include "lib/Arch/SPARC32/Semantics/WINDOW.cpp" diff --git a/lib/Arch/SPARC32/Semantics/BINARY.cpp b/lib/Arch/SPARC32/Semantics/BINARY.cpp deleted file mode 100644 index e1ea631ae..000000000 --- a/lib/Arch/SPARC32/Semantics/BINARY.cpp +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (c) 2020 Trail of Bits, Inc. - */ - -namespace { - -template -ALWAYS_INLINE static void WriteFlagsIncDec(State &state, T lhs, T rhs, T res) { - FLAG_ICC_ZF = ZeroFlag(res, lhs, rhs); - FLAG_ICC_NF = SignFlag(res, lhs, rhs); - FLAG_ICC_VF = Overflow::Flag(lhs, rhs, res); -} - -template -ALWAYS_INLINE static void WriteFlagsAddSub(State &state, T lhs, T rhs, T res) { - FLAG_ICC_CF = Carry::Flag(lhs, rhs, res); - WriteFlagsIncDec(state, lhs, rhs, res); -} - -template -ALWAYS_INLINE static void WriteXCCFlagsIncDec(State &state, T lhs, T rhs, - T res) { - FLAG_XCC_ZF = ZeroFlag(res, lhs, rhs); - FLAG_XCC_NF = SignFlag(res, lhs, rhs); - FLAG_XCC_VF = Overflow::Flag(lhs, rhs, res); -} - -template -ALWAYS_INLINE static void WriteICCFlagsIncDec(State &state, T lhs, T rhs, - T res) { - FLAG_ICC_ZF = ZeroFlag(res, lhs, rhs); - FLAG_ICC_NF = SignFlag(res, lhs, rhs); - FLAG_ICC_VF = Overflow::Flag(lhs, rhs, res); -} - -template -ALWAYS_INLINE static void WriteICCFlagsAddSub(State &state, uint32_t lhs, - uint32_t rhs, uint32_t res) { - FLAG_ICC_CF = Carry::Flag(lhs, rhs, res); - WriteICCFlagsIncDec(state, lhs, rhs, res); -} - -template -ALWAYS_INLINE static void WriteXCCFlagsAddSub(State &state, uint64_t lhs, - uint64_t rhs, uint64_t res) { - FLAG_XCC_CF = Carry::Flag(lhs, rhs, res); - WriteXCCFlagsIncDec(state, lhs, rhs, res); -} - -template -DEF_SEM(SUB, S1 src1, S2 src2, D dst) { - Write(dst, USub(Read(src1), Read(src2))); - return memory; -} - -template -DEF_SEM(SUBcc, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = USub(lhs, rhs); - Write(dst, res); - WriteICCFlagsAddSub(state, lhs, rhs, res); - return memory; -} - -template -DEF_SEM(SUBX, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto carry = ZExtTo(Unsigned(Read(FLAG_ICC_CF))); - auto sub = USub(lhs, rhs); - auto res = USub(sub, carry); - Write(dst, res); - return memory; -} - -template -DEF_SEM(SUBXcc, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto carry = ZExtTo(Unsigned(Read(FLAG_ICC_CF))); - auto sub = USub(lhs, rhs); - auto res = USub(sub, carry); - WriteZExt(dst, res); - WriteICCFlagsAddSub(state, lhs, rhs, res); - return memory; -} - -template -DEF_SEM(ADD, S1 src1, S2 src2, D dst) { - Write(dst, UAdd(Read(src1), Read(src2))); - return memory; -} - -template -DEF_SEM(ADDcc, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = UAdd(lhs, rhs); - Write(dst, res); - WriteICCFlagsAddSub(state, lhs, rhs, res); - return memory; -} - -template -DEF_SEM(ADDX, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto carry = ZExtTo(Unsigned(Read(FLAG_ICC_CF))); - auto sum = UAdd(lhs, rhs); - auto res = UAdd(sum, carry); - Write(dst, res); - return memory; -} - -template -DEF_SEM(ADDXcc, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto carry = ZExtTo(Unsigned(Read(FLAG_ICC_CF))); - auto sum = UAdd(lhs, rhs); - auto res = UAdd(sum, carry); - Write(dst, res); - WriteICCFlagsAddSub(state, lhs, rhs, res); - return memory; -} - -template -DEF_SEM(SMUL, S1 src1, S2 src2, D dst) { - auto lhs = Signed(Read(src1)); - auto rhs = Signed(Read(src2)); - auto lhs_wide = SExt(lhs); - auto rhs_wide = SExt(rhs); - auto res = SMul(lhs_wide, rhs_wide); - auto res_trunc = TruncTo(res); - WriteZExt(dst, res_trunc); - return memory; -} - -template -DEF_SEM(SMULcc, S1 src1, S2 src2, D dst) { - auto lhs = Signed(Read(src1)); - auto rhs = Signed(Read(src2)); - auto lhs_wide = SExt(lhs); - auto rhs_wide = SExt(rhs); - auto res = SMul(lhs_wide, rhs_wide); - auto res_trunc = TruncTo(res); - FLAG_ICC_NF = SignFlag(static_cast(res), src1, src2); - FLAG_ICC_ZF = ZeroFlag(static_cast(res), src1, src2); - FLAG_ICC_VF = 0; - FLAG_ICC_CF = 0; - auto index = Literal(32); - auto y_val = UShr(decltype(index)(res), index); - Write(ASR_Y, y_val); - WriteZExt(dst, res_trunc); - return memory; -} - -template -DEF_SEM(UMUL, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto lhs_wide = ZExt(lhs); - auto rhs_wide = ZExt(rhs); - auto res = UMul(lhs_wide, rhs_wide); - auto res_trunc = TruncTo(res); - WriteZExt(dst, res_trunc); - return memory; -} - -template -DEF_SEM(UMULcc, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto lhs_wide = ZExt(lhs); - auto rhs_wide = ZExt(rhs); - auto res = UMul(lhs_wide, rhs_wide); - auto res_trunc = TruncTo(res); - FLAG_ICC_NF = SignFlag(static_cast(res), src1, src2); - FLAG_ICC_ZF = ZeroFlag(static_cast(res), src1, src2); - FLAG_ICC_VF = 0; - FLAG_ICC_CF = 0; - auto index = Literal(32); - auto y_val = UShr(decltype(index)(res), index); - Write(ASR_Y, y_val); - WriteZExt(dst, res_trunc); - return memory; -} - -template -DEF_SEM(MULX, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto lhs_wide = ZExt(lhs); - auto rhs_wide = ZExt(rhs); - auto res = UMul(lhs_wide, rhs_wide); - auto res_trunc = TruncTo(res); - WriteZExt(dst, res_trunc); - return memory; -} - -template -DEF_SEM(SDIV, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto lhs_wide = ZExt(lhs); - auto y = Read(REG_Y); - auto y_lhs_wide = Signed( - UOr(decltype(lhs_wide)(UShl(y, Literal(32))), lhs_wide)); - auto rhs = Signed(Read(src2)); - auto rhs_wide = SExt(rhs); - auto quot = SDiv(y_lhs_wide, rhs_wide); - WriteTrunc(dst, quot); - return memory; -} - -template -DEF_SEM(SDIVcc, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto lhs_wide = ZExt(lhs); - auto y = Read(REG_Y); - auto y_lhs_wide = Signed( - UOr(decltype(lhs_wide)(UShl(y, Literal(32))), lhs_wide)); - auto rhs = Read(src2); - auto rhs_wide = SExt(rhs); - auto quot = SDiv(y_lhs_wide, rhs_wide); - FLAG_ICC_NF = SignFlag(static_cast(quot), src1, src2); - FLAG_ICC_ZF = ZeroFlag(static_cast(quot), src1, src2); - FLAG_ICC_VF = Overflow::Flag(lhs, rhs, quot); - FLAG_ICC_CF = 0; - auto res = Overflow::Value(lhs, rhs, quot); - WriteTrunc(dst, res); - return memory; -} - -template -DEF_SEM(UDIV, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto lhs_wide = ZExt(lhs); - auto rhs_wide = ZExt(rhs); - auto quot = UDiv(lhs_wide, rhs_wide); - WriteTrunc(dst, quot); - return memory; -} - -template -DEF_SEM(UDIVcc, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto lhs_wide = ZExt(lhs); - auto rhs_wide = ZExt(rhs); - auto quot = UDiv(lhs_wide, rhs_wide); - FLAG_ICC_NF = SignFlag(static_cast(quot), src1, src2); - FLAG_ICC_ZF = ZeroFlag(static_cast(quot), src1, src2); - FLAG_ICC_VF = Overflow::Flag(lhs, rhs, quot); - FLAG_ICC_CF = 0; - auto res = Overflow::Value(lhs, rhs, quot); - WriteTrunc(dst, res); - return memory; -} - -} // namespace - -DEF_ISEL(SUB) = SUB; -DEF_ISEL(SUBcc) = SUBcc; -DEF_ISEL(SUBX) = SUBX; -DEF_ISEL(SUBXcc) = SUBXcc; - -DEF_ISEL(ADD) = ADD; -DEF_ISEL(ADDcc) = ADDcc; -DEF_ISEL(ADDX) = ADDX; -DEF_ISEL(ADDXcc) = ADDXcc; - -DEF_ISEL(SMUL) = SMUL; -DEF_ISEL(SMULcc) = SMULcc; -DEF_ISEL(UMUL) = UMUL; -DEF_ISEL(UMULcc) = UMULcc; -DEF_ISEL(MULX) = MULX; - -DEF_ISEL(SDIV) = SDIV; -DEF_ISEL(SDIVcc) = SDIVcc; -DEF_ISEL(UDIV) = UDIV; -DEF_ISEL(UDIVcc) = UDIVcc; - -namespace { - -DEF_SEM(MULSCC_R32, R32 src1, R32 src2, R32W dest) { - auto rs1 = Read(src1); - auto rs2 = Read(src2); - auto y = Read(REG_Y); - auto lsb_y = UAnd(y, Literal(0x1)); - auto masked_rs1 = UAnd(rs1, Literal(0xffffffff)); - auto masked_rs2 = UAnd(rs2, Literal(0xffffffff)); - auto new_rs2 = - Select(UCmpEq(lsb_y, 0), Literal(0), masked_rs2); - - auto flag_nf = Literal(Read(FLAG_ICC_NF)); - auto flag_vf = Literal(Read(FLAG_ICC_VF)); - auto nxorv = UXor(flag_nf, flag_vf); - auto shifted_flag = UShl(nxorv, Literal(31)); - auto new_rs1 = UOr(UShr(masked_rs1, Literal(1)), - Literal(shifted_flag)); - auto res = UAdd(new_rs1, new_rs2); - - // Y register is shifted right by one bit, with the LSB of the unshifted - // r[rs1] replacing the MSB of Y - auto shifted_y = UShr(y, Literal(1)); - auto lsb_rs1 = UAnd(rs1, Literal(0x1)); - auto new_y = UOr(shifted_y, - decltype(y)(UShl(lsb_rs1, Literal(31)))); - Write(REG_Y, new_y); - Write(dest, res); - - - WriteICCFlagsAddSub(state, static_cast(new_rs1), - static_cast(new_rs2), - static_cast(res)); - return memory; -} - -} // namespace - -DEF_ISEL(MULScc) = MULSCC_R32; diff --git a/lib/Arch/SPARC32/Semantics/BRANCH.cpp b/lib/Arch/SPARC32/Semantics/BRANCH.cpp deleted file mode 100644 index 4fd19f96a..000000000 --- a/lib/Arch/SPARC32/Semantics/BRANCH.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (c) 2020 Trail of Bits, Inc. - */ - -namespace { - -// NOTE(pag): `new_pc == pc_of_jmp + 4`, and `new_npc` -// is the target EA. -template -DEF_SEM(JMPL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst, T dst_pc, T dst_npc) { - auto new_dst = Read(pc_of_jmp); - auto new_dst_pc = Read(new_pc); - auto new_dst_npc = Read(new_npc); - Write(dst, new_dst); - Write(dst_pc, new_dst_pc); - Write(dst_npc, new_dst_npc); - return memory; -} - -// This is a variation on JMPL that also stores the return address. -template -DEF_SEM(CALL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst, T dst_pc, T dst_npc, - T return_pc_dst) { - Write(dst, Read(pc_of_jmp)); - Write(dst_pc, Read(new_pc)); - Write(dst_npc, Read(new_npc)); - - // NOTE(pag): See comment above about conventions. - Write(return_pc_dst, UAdd(Read(pc_of_jmp), 8)); - return memory; -} - -// Makes an asynchronous and synchronous version of the trap. The asynchronous -// exists during normal control-flow, and introduces its own control flow and -// an async hyper call. The synchronous version exists when the trap instruction -// 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, \ - R32W pc_dst, R32W npc_dst) { \ - if (Cond##cond##_##cc(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##_##cc) = name##cond##_##cc; - -template -DEF_SEM(BA, PC new_taken_pc, PC new_taken_npc, T pc_dst, T npc_dst) { - Write(pc_dst, Read(new_taken_pc)); - Write(npc_dst, Read(new_taken_npc)); - return memory; -} - -template -DEF_SEM(BN, PC new_not_taken_pc, PC new_not_taken_npc, T pc_dst, T npc_dst) { - Write(pc_dst, Read(new_not_taken_pc)); - Write(npc_dst, Read(new_not_taken_npc)); - return memory; -} - -template -DEF_SEM(FBA, PC new_taken_pc, PC new_taken_npc, T pc_dst, T npc_dst) { - Write(pc_dst, Read(new_taken_pc)); - Write(npc_dst, Read(new_taken_npc)); - return memory; -} - -template -DEF_SEM(FBN, PC new_not_taken_pc, PC new_not_taken_npc, T pc_dst, T npc_dst) { - Write(pc_dst, Read(new_not_taken_pc)); - Write(npc_dst, Read(new_not_taken_npc)); - return memory; -} - -// A branch instruction existing in a delay slot. These are DCTI couples. They -// have weird pipeline effects, e.g. -// -// address instruction target -// ------------+------------------+-------------- -// 8 not-a-cti -// 12 cti 40 -// 16 cti 60 -// 20 not-a-cti -// 24 ... -// -// 40 not-a-cti -// 44 ... -// -// 60 not-a-cti -// 64 ... -// -// case 12: cti 40 16: cti 60 order of execution -// -----+---------------------+-----------------+--------------------- -// 1 dcti unconditional dcti taken 12,16,40,60,64,... -// 2 dcti unconditional B*cc(a=0) untaken 12,16,40,44 -// 3 dcti unconditional B*cc(a=1) untaken 12,16,44,48 (40 annulled) -// 4 dcti unconditional B*A(a=1) 12,16,60,64 (40 annulled) -// 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); -} - -// TODO(pag): Double check that `new_pc` reads `rs1/rs2` from the pre- -// incremented register window state. -template -DEF_SEM(RETT, PC new_pc, PC new_npc, T dst_pc, T dst_npc, - RegisterWindow *&prev_window) { - RESTORE_WINDOW(memory, state, prev_window); - Write(dst_pc, Read(new_pc)); - Write(dst_npc, Read(new_npc)); - return memory; -} - -} // namespace - -DEF_ISEL(UNSUPPORTED_DCTI) = UNSUPPORTED_DCTI; - -DEF_ISEL(CALL) = CALL; -DEF_ISEL(CALL_INDIRECT) = CALL; -DEF_ISEL(JMPL) = JMPL; -DEF_ISEL(RETL) = JMPL; -DEF_ISEL(RETT) = RETT; - -DEF_ISEL(BA_icc) = BA; -DEF_ISEL(BN_icc) = BN; - -DEF_ISEL(BA_xcc) = BA; -DEF_ISEL(BN_xcc) = BN; - -DEF_ISEL(FBA_fcc0) = FBA; -DEF_ISEL(FBA_fcc1) = FBA; -DEF_ISEL(FBA_fcc2) = FBA; -DEF_ISEL(FBA_fcc3) = FBA; - -DEF_ISEL(FBN_fcc0) = FBN; -DEF_ISEL(FBN_fcc1) = FBN; -DEF_ISEL(FBN_fcc2) = FBN; -DEF_ISEL(FBN_fcc3) = FBN; - -#define MAKE_BRANCH_CC(name, cond) \ - MAKE_BRANCH(name, cond, icc) \ - MAKE_BRANCH(name, cond, xcc) - -MAKE_BRANCH_CC(B, NE) -MAKE_BRANCH_CC(B, E) -MAKE_BRANCH_CC(B, G) -MAKE_BRANCH_CC(B, LE) -MAKE_BRANCH_CC(B, GE) -MAKE_BRANCH_CC(B, L) -MAKE_BRANCH_CC(B, GU) -MAKE_BRANCH_CC(B, LEU) -MAKE_BRANCH_CC(B, CC) -MAKE_BRANCH_CC(B, CS) -MAKE_BRANCH_CC(B, POS) -MAKE_BRANCH_CC(B, NEG) -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_F(FB, U) -MAKE_BRANCH_F(FB, G) -MAKE_BRANCH_F(FB, UG) -MAKE_BRANCH_F(FB, L) -MAKE_BRANCH_F(FB, UL) -MAKE_BRANCH_F(FB, LG) -MAKE_BRANCH_F(FB, NE) -MAKE_BRANCH_F(FB, E) -MAKE_BRANCH_F(FB, UE) -MAKE_BRANCH_F(FB, GE) -MAKE_BRANCH_F(FB, UGE) -MAKE_BRANCH_F(FB, LE) -MAKE_BRANCH_F(FB, ULE) -MAKE_BRANCH_F(FB, O) - - -#undef MAKE_BRANCH -#undef MAKE_BRANCH_F - - -// Branch on Coprocessor Condition Codes Instructions - -#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_ISEL(name##cond) = name##cond; - -MAKE_BRANCH(CB, A) -MAKE_BRANCH(CB, N) -MAKE_BRANCH(CB, 3) -MAKE_BRANCH(CB, 2) -MAKE_BRANCH(CB, 23) -MAKE_BRANCH(CB, 1) -MAKE_BRANCH(CB, 13) -MAKE_BRANCH(CB, 12) -MAKE_BRANCH(CB, 123) -MAKE_BRANCH(CB, 0) -MAKE_BRANCH(CB, 03) -MAKE_BRANCH(CB, 02) -MAKE_BRANCH(CB, 023) -MAKE_BRANCH(CB, 01) -MAKE_BRANCH(CB, 013) -MAKE_BRANCH(CB, 012) - -#undef MAKE_BRANCH diff --git a/lib/Arch/SPARC32/Semantics/COND.cpp b/lib/Arch/SPARC32/Semantics/COND.cpp deleted file mode 100644 index 521222f8c..000000000 --- a/lib/Arch/SPARC32/Semantics/COND.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2020 Trail of Bits, Inc. - */ - -#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 __remill_compare_eq(flag_zf); \ - } \ - static inline bool CondNE_##cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_zf = ccr.z; \ - return __remill_compare_neq(!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 __remill_compare_sgt((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 __remill_compare_sle((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 __remill_compare_sge(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 __remill_compare_slt(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 __remill_compare_ugt(!(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 __remill_compare_ule(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 __remill_compare_ult(flag_cf); \ - } \ - static inline bool CondCC_##cc(const State &state) { \ - const auto ccr = state.asr.ccr.cc; \ - const bool flag_cf = ccr.c; \ - return __remill_compare_uge(!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) - -#undef MAKE_CONDITIONS - - -#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); \ - } - -MAKE_CONDITIONS(fcc0) -MAKE_CONDITIONS(fcc1) -MAKE_CONDITIONS(fcc2) -MAKE_CONDITIONS(fcc3) - -template -static inline bool CondRZ(const State &state, T cc) { - return cc == 0; -} - -template -static inline bool CondRLEZ(const State &state, T cc) { - return Signed(cc) <= 0; -} - -template -static inline bool CondRLZ(const State &state, T cc) { - return Signed(cc) < 0; -} - -template -static inline bool CondRNZ(const State &state, T cc) { - return cc != 0; -} - -template -static inline bool CondRGZ(const State &state, T cc) { - return Signed(cc) > 0; -} - -template -static inline bool CondRGEZ(const State &state, T cc) { - return Signed(cc) >= 0; -} - -static inline bool CondA_ccc(const State &state) { - return state.csr.ccc == 0b1000; -} - -static inline bool CondN_ccc(const State &state) { - return state.csr.ccc == 0b0000; -} - -static inline bool Cond3_ccc(const State &state) { - return state.csr.ccc == 0b0111; -} - -static inline bool Cond2_ccc(const State &state) { - return state.csr.ccc == 0b0110; -} - -static inline bool Cond23_ccc(const State &state) { - return state.csr.ccc == 0b0101; -} - -static inline bool Cond1_ccc(const State &state) { - return state.csr.ccc == 0b0100; -} - -static inline bool Cond13_ccc(const State &state) { - return state.csr.ccc == 0b0011; -} - -static inline bool Cond12_ccc(const State &state) { - return state.csr.ccc == 0b0010; -} - -static inline bool Cond123_ccc(const State &state) { - return state.csr.ccc == 0b0001; -} - -static inline bool Cond0_ccc(const State &state) { - return state.csr.ccc == 0b1001; -} - -static inline bool Cond03_ccc(const State &state) { - return state.csr.ccc == 0b1010; -} - -static inline bool Cond02_ccc(const State &state) { - return state.csr.ccc == 0b1011; -} - -static inline bool Cond023_ccc(const State &state) { - return state.csr.ccc == 0b1100; -} - -static inline bool Cond01_ccc(const State &state) { - return state.csr.ccc == 0b1101; -} - -static inline bool Cond013_ccc(const State &state) { - return state.csr.ccc == 0b1110; -} - -static inline bool Cond012_ccc(const State &state) { - return state.csr.ccc == 0b1111; -} diff --git a/lib/Arch/SPARC32/Semantics/DATAXFER.cpp b/lib/Arch/SPARC32/Semantics/DATAXFER.cpp deleted file mode 100644 index 72a467aae..000000000 --- a/lib/Arch/SPARC32/Semantics/DATAXFER.cpp +++ /dev/null @@ -1,478 +0,0 @@ -/* - * Copyright (c) 2020 Trail of Bits, Inc. - */ - -namespace { - -template -DEF_SEM(LDU, S1 src, R32W dst) { - WriteZExt(dst, Read(src)); - return memory; -} - -template -DEF_SEM(LDS, S1 src, R32W dst) { - WriteSExt(dst, Read(src)); - return memory; -} - -template -DEF_SEM(LDF, S1 src, R32W dst) { - WriteZExt(dst, Read(src)); - return memory; -} - -DEF_SEM(LDD, M32 src1, M32 src2, R32W dst1, R32W dst2) { - Write(dst1, Read(src1)); - Write(dst2, Read(src2)); - return memory; -} - -template -DEF_SEM(ST, S1 src, D dst) { - WriteZExt(dst, Read(src)); - return memory; -} - -DEF_SEM(STD, R32 src1, R32 src2, M32W dst1, M32W dst2) { - Write(dst1, Read(src1)); - Write(dst2, Read(src2)); - return memory; -} - -template -DEF_SEM(SETHI, S src, D dst) { - const auto high_bits = Read(src); - Write(dst, high_bits); - return memory; -} - -template -DEF_SEM(SET, S1 src1, S2 src2, D dst) { - const auto high_bits = Read(src1); - const auto low_bits = Read(src2); - Write(dst, UOr(high_bits, low_bits)); - return memory; -} - -template -DEF_SEM(SETHI_OR, S1 src1, S2 src2, D1 dst1, D2 dst2) { - const auto high_bits = Read(src1); - const auto low_bits = Read(src2); - Write(dst1, high_bits); - Write(dst2, UOr(high_bits, low_bits)); - return memory; -} - -template -DEF_SEM(SETHI_ADD, S1 src1, S2 src2, D1 dst1, D2 dst2) { - const auto high_bits = Read(src1); - const auto low_bits = Read(src2); - Write(dst1, high_bits); - Write(dst2, UAdd(high_bits, low_bits)); - return memory; -} - -} // namespace - -DEF_ISEL(LDSB) = LDS; -DEF_ISEL(LDUB) = LDU; -DEF_ISEL(LDSH) = LDS; -DEF_ISEL(LDUH) = LDU; -DEF_ISEL(LD) = LDU; -DEF_ISEL(LDD) = LDD; -DEF_ISEL(LDF) = LDF; -DEF_ISEL(LDDF) = LDD; - -DEF_ISEL(STB) = ST; -DEF_ISEL(STH) = ST; -DEF_ISEL(ST) = ST; -DEF_ISEL(STD) = STD; -DEF_ISEL(STX) = ST; - -DEF_ISEL(STF) = ST; -DEF_ISEL(STDF) = STD; - -DEF_ISEL(SETHI) = SETHI; -DEF_ISEL(SET) = SET; -DEF_ISEL(SETHI_OR) = SETHI_OR; -DEF_ISEL(SETHI_ADD) = SETHI_ADD; - -namespace { - -DEF_SEM(CASA, R32 src1, R32 src2, R32W dst) { - uint32_t rs2 = Read(src2); - addr_t addr = Read(src1); - auto addr_rs1 = ReadPtr(addr); - uint32_t value_rs1 = Read(addr_rs1); - if (value_rs1 == rs2) { - Write(WritePtr(addr), Read(dst)); - } - Write(dst, value_rs1); - return memory; -} - -DEF_SEM(CASAX, R32 src1, R32 src2, R32W dst) { - uint32_t rs2 = Read(src2); - addr_t addr = Read(src1); - auto addr_rs1 = ReadPtr(addr); - uint32_t value_rs1 = Read(addr_rs1); - if (value_rs1 == rs2) { - Write(WritePtr(addr), Read(dst)); - } - WriteZExt(dst, value_rs1); - return memory; -} - -DEF_SEM(SWAP, M32W addr, R32W rd) { - auto old_addr = Read(addr); - auto old_rd = Read(rd); - WriteZExt(addr, old_rd); - WriteZExt(rd, old_addr); - return memory; -} - -template -DEF_SEM(LDSTUB, M8W src_mem, R dst) { - auto mem_val = Read(src_mem); - WriteZExt(dst, mem_val); - Write(src_mem, static_cast(0xffu)); - return memory; -} - -} // namespace - -DEF_ISEL(CASA) = CASA; -DEF_ISEL(CASAX) = CASAX; -DEF_ISEL(SWAP) = SWAP; -DEF_ISEL(LDSTUB) = LDSTUB; - -namespace { - -template -DEF_SEM(MOVA_icc, S src, D dst) { - WriteZExt(dst, Read(src)); - return memory; -} -template -DEF_SEM(MOVA_xcc, S src, D dst) { - WriteZExt(dst, Read(src)); - return memory; -} - -template -DEF_SEM(MOVN_icc, S src, D dst) { - return memory; -} -template -DEF_SEM(MOVN_xcc, S src, D dst) { - return memory; -} - -} // namespace - -DEF_ISEL(MOVA_icc) = MOVA_icc; -DEF_ISEL(MOVA_xcc) = MOVA_xcc; -DEF_ISEL(MOVN_icc) = MOVN_icc; -DEF_ISEL(MOVN_xcc) = MOVN_xcc; - - -#define MAKE_SEMANTICS(name, cond, cc) \ - namespace { \ - template \ - DEF_SEM(name##cond##_##cc, S src, D dst) { \ - auto new_value = Read(src); \ - auto old_value = Read(dst); \ - auto branch_taken = Cond##cond##_##cc(state); \ - auto value = \ - Select(branch_taken, new_value, decltype(new_value)(old_value)); \ - WriteZExt(dst, value); \ - return memory; \ - } \ - } \ - DEF_ISEL(MOV##cond##_##cc) = name##cond##_##cc; - -#define MAKE_SEMANTICS_CC(name, cond) \ - MAKE_SEMANTICS(name, cond, icc) \ - MAKE_SEMANTICS(name, cond, xcc) - -#define MAKE_SEMANTICS_FCC(name, cond) \ - MAKE_SEMANTICS(name, cond, fcc0) \ - MAKE_SEMANTICS(name, cond, fcc1) \ - MAKE_SEMANTICS(name, cond, fcc2) \ - MAKE_SEMANTICS(name, cond, fcc3) - - -namespace { - -MAKE_SEMANTICS_CC(MOV, NE) -MAKE_SEMANTICS_CC(MOV, E) -MAKE_SEMANTICS_CC(MOV, G) -MAKE_SEMANTICS_CC(MOV, LE) -MAKE_SEMANTICS_CC(MOV, GE) -MAKE_SEMANTICS_CC(MOV, L) -MAKE_SEMANTICS_CC(MOV, GU) -MAKE_SEMANTICS_CC(MOV, LEU) -MAKE_SEMANTICS_CC(MOV, CC) -MAKE_SEMANTICS_CC(MOV, CS) -MAKE_SEMANTICS_CC(MOV, POS) -MAKE_SEMANTICS_CC(MOV, NEG) -MAKE_SEMANTICS_CC(MOV, VC) -MAKE_SEMANTICS_CC(MOV, VS) - -MAKE_SEMANTICS_FCC(MOVF, U) -MAKE_SEMANTICS_FCC(MOVF, G) -MAKE_SEMANTICS_FCC(MOVF, UG) -MAKE_SEMANTICS_FCC(MOVF, L) -MAKE_SEMANTICS_FCC(MOVF, UL) -MAKE_SEMANTICS_FCC(MOVF, LG) -MAKE_SEMANTICS_FCC(MOVF, NE) -MAKE_SEMANTICS_FCC(MOVF, E) -MAKE_SEMANTICS_FCC(MOVF, UE) -MAKE_SEMANTICS_FCC(MOVF, GE) -MAKE_SEMANTICS_FCC(MOVF, UGE) -MAKE_SEMANTICS_FCC(MOVF, LE) -MAKE_SEMANTICS_FCC(MOVF, ULE) -MAKE_SEMANTICS_FCC(MOVF, O) - -} // namespace - -#undef MAKE_SEMANTICS -#undef MAKE_SEMANTICS_CC -#undef MAKE_SEMANTICS_FCC - -#define MAKE_SEMANTICS(name, cond) \ - namespace { \ - template \ - DEF_SEM(name##cond, C reg_cc, S src, D dst) { \ - auto new_value = Read(src); \ - auto old_value = Read(dst); \ - auto cc = Read(reg_cc); \ - auto cond_taken = CondR##cond(state, cc); \ - auto value = \ - Select(cond_taken, new_value, decltype(new_value)(old_value)); \ - WriteZExt(dst, value); \ - return memory; \ - } \ - } \ - DEF_ISEL(MOVR##cond) = name##cond; - -MAKE_SEMANTICS(MOVR, Z) -MAKE_SEMANTICS(MOVR, LEZ) -MAKE_SEMANTICS(MOVR, LZ) -MAKE_SEMANTICS(MOVR, NZ) -MAKE_SEMANTICS(MOVR, GZ) -MAKE_SEMANTICS(MOVR, GEZ) - -#undef MAKE_SEMANTICS - -namespace { - -DEF_SEM(FMoveAlwaysSingle, V32 src, V32W dst) { - auto new_val = FExtractV32(FReadV32(src), 0); - FWriteV32(dst, new_val); - WriteTrunc(FSR_CEXC, 0); - WriteTrunc(FSR_FTT, 0); - return memory; -} - -DEF_SEM(FMoveNeverSingle, V32 src, V32W dst) { - return memory; -} - -DEF_SEM(FMoveAlwaysDouble, V64 src, V64W dst) { - auto new_val = FExtractV64(FReadV64(src), 0); - FWriteV64(dst, new_val); - WriteTrunc(FSR_CEXC, 0); - WriteTrunc(FSR_FTT, 0); - return memory; -} - -DEF_SEM(FMoveNeverDouble, V64 src, V64W dst) { - return memory; -} - -DEF_SEM(FMoveAlwaysQuad, V64 src, V64W dst) { - auto new_val = FExtractV64(FReadV64(src), 0); - FWriteV64(dst, new_val); - WriteTrunc(FSR_CEXC, 0); - WriteTrunc(FSR_FTT, 0); - return memory; -} - -DEF_SEM(FMoveNeverQuad, V64 src, V64W dst) { - return memory; -} - -} // namespace - -DEF_ISEL(FMOVSA_icc) = FMoveAlwaysSingle; -DEF_ISEL(FMOVSA_xcc) = FMoveAlwaysSingle; -DEF_ISEL(FMOVSA_fcc0) = FMoveAlwaysSingle; -DEF_ISEL(FMOVSA_fcc1) = FMoveAlwaysSingle; -DEF_ISEL(FMOVSA_fcc2) = FMoveAlwaysSingle; -DEF_ISEL(FMOVSA_fcc3) = FMoveAlwaysSingle; - -DEF_ISEL(FMOVSN_icc) = FMoveNeverSingle; -DEF_ISEL(FMOVSN_xcc) = FMoveNeverSingle; -DEF_ISEL(FMOVSN_fcc0) = FMoveNeverSingle; -DEF_ISEL(FMOVSN_fcc1) = FMoveNeverSingle; -DEF_ISEL(FMOVSN_fcc2) = FMoveNeverSingle; -DEF_ISEL(FMOVSN_fcc3) = FMoveNeverSingle; - -DEF_ISEL(FMOVDA_icc) = FMoveAlwaysDouble; -DEF_ISEL(FMOVDA_xcc) = FMoveAlwaysDouble; -DEF_ISEL(FMOVDA_fcc0) = FMoveAlwaysDouble; -DEF_ISEL(FMOVDA_fcc1) = FMoveAlwaysDouble; -DEF_ISEL(FMOVDA_fcc2) = FMoveAlwaysDouble; -DEF_ISEL(FMOVDA_fcc3) = FMoveAlwaysDouble; - -DEF_ISEL(FMOVDN_icc) = FMoveNeverDouble; -DEF_ISEL(FMOVDN_xcc) = FMoveNeverDouble; -DEF_ISEL(FMOVDN_fcc0) = FMoveNeverDouble; -DEF_ISEL(FMOVDN_fcc1) = FMoveNeverDouble; -DEF_ISEL(FMOVDN_fcc2) = FMoveNeverDouble; -DEF_ISEL(FMOVDN_fcc3) = FMoveNeverDouble; - -DEF_ISEL(FMOVQA_icc) = FMoveAlwaysQuad; -DEF_ISEL(FMOVQA_xcc) = FMoveAlwaysQuad; -DEF_ISEL(FMOVQA_fcc0) = FMoveAlwaysQuad; -DEF_ISEL(FMOVQA_fcc1) = FMoveAlwaysQuad; -DEF_ISEL(FMOVQA_fcc2) = FMoveAlwaysQuad; -DEF_ISEL(FMOVQA_fcc3) = FMoveAlwaysQuad; - -DEF_ISEL(FMOVQN_icc) = FMoveNeverQuad; -DEF_ISEL(FMOVQN_xcc) = FMoveNeverQuad; -DEF_ISEL(FMOVQN_fcc0) = FMoveNeverQuad; -DEF_ISEL(FMOVQN_fcc1) = FMoveNeverQuad; -DEF_ISEL(FMOVQN_fcc2) = FMoveNeverQuad; -DEF_ISEL(FMOVQN_fcc3) = FMoveNeverQuad; - - -#define MAKE_SEMANTICS(name, cond, cc) \ - namespace { \ - 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)); \ - FWriteV32(dst, value); \ - WriteTrunc(FSR_CEXC, 0); \ - WriteTrunc(FSR_FTT, 0); \ - return memory; \ - } \ - 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)); \ - FWriteV64(dst, value); \ - WriteTrunc(FSR_CEXC, 0); \ - WriteTrunc(FSR_FTT, 0); \ - return memory; \ - } \ - 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)); \ - 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; - -#define MAKE_SEMANTICS_CC(name, cond) \ - MAKE_SEMANTICS(name, cond, icc) \ - MAKE_SEMANTICS(name, cond, xcc) - -#define MAKE_SEMANTICS_FCC(name, cond) \ - MAKE_SEMANTICS(name, cond, fcc0) \ - MAKE_SEMANTICS(name, cond, fcc1) \ - MAKE_SEMANTICS(name, cond, fcc2) \ - MAKE_SEMANTICS(name, cond, fcc3) - -MAKE_SEMANTICS_CC(FMOV, NE) -MAKE_SEMANTICS_CC(FMOV, E) -MAKE_SEMANTICS_CC(FMOV, G) -MAKE_SEMANTICS_CC(FMOV, LE) -MAKE_SEMANTICS_CC(FMOV, GE) -MAKE_SEMANTICS_CC(FMOV, L) -MAKE_SEMANTICS_CC(FMOV, GU) -MAKE_SEMANTICS_CC(FMOV, LEU) -MAKE_SEMANTICS_CC(FMOV, CC) -MAKE_SEMANTICS_CC(FMOV, CS) -MAKE_SEMANTICS_CC(FMOV, POS) -MAKE_SEMANTICS_CC(FMOV, NEG) -MAKE_SEMANTICS_CC(FMOV, VC) -MAKE_SEMANTICS_CC(FMOV, VS) - -MAKE_SEMANTICS_FCC(FMOV, U) -MAKE_SEMANTICS_FCC(FMOV, G) -MAKE_SEMANTICS_FCC(FMOV, UG) -MAKE_SEMANTICS_FCC(FMOV, L) -MAKE_SEMANTICS_FCC(FMOV, UL) -MAKE_SEMANTICS_FCC(FMOV, LG) -MAKE_SEMANTICS_FCC(FMOV, NE) -MAKE_SEMANTICS_FCC(FMOV, E) -MAKE_SEMANTICS_FCC(FMOV, UE) -MAKE_SEMANTICS_FCC(FMOV, GE) -MAKE_SEMANTICS_FCC(FMOV, UGE) -MAKE_SEMANTICS_FCC(FMOV, LE) -MAKE_SEMANTICS_FCC(FMOV, ULE) -MAKE_SEMANTICS_FCC(FMOV, O) - -#undef MAKE_SEMANTICS -#undef MAKE_SEMANTICS_CC -#undef MAKE_SEMANTICS_FCC - -#define MAKE_SEMANTICS(name, cond) \ - namespace { \ - 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)); \ - 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) { \ - 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, 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)); \ - 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; - -MAKE_SEMANTICS(FMOVR, Z) -MAKE_SEMANTICS(FMOVR, LEZ) -MAKE_SEMANTICS(FMOVR, LZ) -MAKE_SEMANTICS(FMOVR, NZ) -MAKE_SEMANTICS(FMOVR, GZ) -MAKE_SEMANTICS(FMOVR, GEZ) diff --git a/lib/Arch/SPARC32/Semantics/FLAGS.cpp b/lib/Arch/SPARC32/Semantics/FLAGS.cpp deleted file mode 100644 index 8aac67822..000000000 --- a/lib/Arch/SPARC32/Semantics/FLAGS.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/* - * 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 { - -// Zero flags, tells us whether or not a value is zero. -template -[[gnu::const]] ALWAYS_INLINE static bool ZeroFlag(T res, S1 lhs, S2 rhs) { - return __remill_flag_computation_zero(T(0) == res, lhs, rhs, res); -} - -// Zero flags, tells us whether or not a value is zero. -template -[[gnu::const]] ALWAYS_INLINE static bool NotZeroFlag(T res, S1 lhs, S2 rhs) { - return !__remill_flag_computation_zero(T(0) == res, lhs, rhs, res); -} - -// Sign flag, tells us if a result is signed or unsigned. -template -[[gnu::const]] ALWAYS_INLINE static bool SignFlag(T res, S1 lhs, S2 rhs) { - return __remill_flag_computation_sign(0 > Signed(res), lhs, rhs, res); -} - -// Tests whether there is an even number of bits in the low order byte. -[[gnu::const]] ALWAYS_INLINE static bool ParityFlag(uint8_t r0) { - return !__builtin_parity(static_cast(r0)); - - // auto r1 = r0 >> 1_u8; - // auto r2 = r1 >> 1_u8; - // auto r3 = r2 >> 1_u8; - // auto r4 = r3 >> 1_u8; - // auto r5 = r4 >> 1_u8; - // auto r6 = r5 >> 1_u8; - // auto r7 = r6 >> 1_u8; - // - // return !(1 & (r0 ^ r1 ^ r2 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7)); -} - -struct tag_add {}; -struct tag_sub {}; -struct tag_sdiv {}; -struct tag_udiv {}; -struct tag_mul {}; - -// Generic overflow flag. -template -struct Overflow; - -// Computes an overflow flag when two numbers are added together. -template <> -struct Overflow { - template - [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { - static_assert(std::is_unsigned::value, - "Invalid specialization of `Overflow::Flag` for addition."); - enum { kSignShift = sizeof(T) * 8 - 1 }; - - // Overflow occurs on addition if both operands have the same sign and - // the sign of the sum is different. - - const T sign_lhs = lhs >> kSignShift; - const T sign_rhs = rhs >> kSignShift; - const T sign_res = res >> kSignShift; - return __remill_flag_computation_overflow( - 2 == ((sign_lhs ^ sign_res) + (sign_rhs ^ sign_res)), lhs, rhs, res); - } -}; - -// Computes an overflow flag when one number is subtracted from another. -template <> -struct Overflow { - template - [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { - static_assert(std::is_unsigned::value, - "Invalid specialization of `Overflow::Flag` for " - "subtraction."); - enum { kSignShift = sizeof(T) * 8 - 1 }; - - // Overflow occurs on subtraction if the operands have different signs and - // the sign of the difference differs from the sign of r[rs1]. - - const T sign_lhs = lhs >> kSignShift; - const T sign_rhs = rhs >> kSignShift; - const T sign_res = res >> kSignShift; - return __remill_flag_computation_overflow( - 2 == ((sign_lhs ^ sign_rhs) + (sign_lhs ^ sign_res)), lhs, rhs, res); - } -}; - -// Computes an overflow flag when one number is multiplied with another. -template <> -struct Overflow { - - // Integer multiplication overflow check, where result is twice the width of - // the operands. - template - [[gnu::const]] ALWAYS_INLINE static bool - Flag(T lhs, T rhs, R res, - typename std::enable_if::type = 0) { - - return __remill_flag_computation_overflow( - static_cast(static_cast(res)) != res, lhs, rhs, res); - } - - // Signed integer multiplication overflow check, where the result is - // truncated to the size of the operands. - template - [[gnu::const]] ALWAYS_INLINE static bool - Flag(T lhs, T rhs, T, - typename std::enable_if::value, int>::type = 0) { - auto lhs_wide = SExt(lhs); - auto rhs_wide = SExt(rhs); - return Flag(lhs, rhs, lhs_wide * rhs_wide); - } -}; - -// Computes an overflow flag when one number is divided by another. -template <> -struct Overflow { - template - [[gnu::const]] ALWAYS_INLINE static bool - Flag(T lhs, T rhs, R res, - typename std::enable_if::type = 0) { - - enum { kSignShift = sizeof(T) * 8 - 1 }; - - return __remill_flag_computation_overflow( - (SExt(res << kSignShift) > 0) || (SExt(res << kSignShift) < -1), lhs, - rhs, res); - } - - template - [[gnu::const]] ALWAYS_INLINE static R - Value(T lhs, T rhs, R res, - typename std::enable_if::type = 0) { - - enum { kSignShift = sizeof(T) * 8 - 1 }; - - enum : R { kValueMax = static_cast(1) << sizeof(T) * 8 }; - - if (SExt(res << kSignShift) > 0) { - return kValueMax - 1; - } else if (SExt(res << kSignShift) < -1) { - return SNeg(kValueMax); - } else { - return res; - } - } -}; - -template <> -struct Overflow { - template - [[gnu::const]] ALWAYS_INLINE static bool - Flag(T lhs, T rhs, R res, - typename std::enable_if::type = 0) { - - enum { kShift = sizeof(T) * 8 }; - - return __remill_flag_computation_overflow((SExt(res << kShift) > 0), lhs, - rhs, res); - } - - template - [[gnu::const]] ALWAYS_INLINE static R - Value(T lhs, T rhs, R res, - typename std::enable_if::type = 0) { - - enum { kShift = sizeof(T) * 8 }; - - enum : R { kValueMax = static_cast(1) << sizeof(T) * 8 }; - - if (SExt(res << kShift) > 0) { - return kValueMax - 1; - } else { - return res; - } - } -}; - -// Generic carry flag. -template -struct Carry; - -// Computes an carry flag when two numbers are added together. -template <> -struct Carry { - template - [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { - static_assert(std::is_unsigned::value, - "Invalid specialization of `Carry::Flag` for addition."); - return __remill_flag_computation_carry(res < lhs || res < rhs, lhs, rhs, - res); - } -}; - -// Computes an carry flag when one number is subtracted from another. -template <> -struct Carry { - template - [[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) { - static_assert(std::is_unsigned::value, - "Invalid specialization of `Carry::Flag` for addition."); - return __remill_flag_computation_carry(lhs < rhs, lhs, rhs, res); - } -}; - -ALWAYS_INLINE void SetFPSRStatusFlags(State &state, int mask) { - state.fsr.aexc |= static_cast(mask & FE_ALL_EXCEPT); - state.fsr.cexc = static_cast(mask & FE_ALL_EXCEPT); -} - -} // namespace diff --git a/lib/Arch/SPARC32/Semantics/FOP.cpp b/lib/Arch/SPARC32/Semantics/FOP.cpp deleted file mode 100644 index 83b2d2535..000000000 --- a/lib/Arch/SPARC32/Semantics/FOP.cpp +++ /dev/null @@ -1,501 +0,0 @@ -/* - * Copyright (c) 2020 Trail of Bits, Inc. - */ - -namespace { - -// Floating point operations -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); - BarrierReorder(); - auto sum = FAdd(lhs, rhs); - BarrierReorder(); - auto new_except = - __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); - SetFPSRStatusFlags(state, new_except); - Write(dst, sum); - return memory; -} - -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); - BarrierReorder(); - auto sum = FAdd64(lhs, rhs); - BarrierReorder(); - auto new_except = - __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, old_except); - SetFPSRStatusFlags(state, new_except); - Write(dst, sum); - return memory; -} - -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); - SetFPSRStatusFlags(state, new_except); - Write(dst, sub); - return memory; -} - -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); - SetFPSRStatusFlags(state, new_except); - Write(dst, sub); - return memory; -} - -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); - BarrierReorder(); - auto mul = FMul32(lhs, rhs); - BarrierReorder(); - 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(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); - SetFPSRStatusFlags(state, new_except); - Write(dst, mul); - return memory; -} - -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); - BarrierReorder(); - auto div = FDiv32(lhs, rhs); - BarrierReorder(); - 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(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); - BarrierReorder(); - auto div = FDiv64(lhs, rhs); - BarrierReorder(); - 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) { - 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); - BarrierReorder(); - auto mul = FMul64(lhs, rhs); - BarrierReorder(); - 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) { - 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); - BarrierReorder(); - auto mul = FMul64(lhs, rhs); - BarrierReorder(); - 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; -DEF_ISEL(FADDQ) = FADDD; - -DEF_ISEL(FSUBS) = FSUBS; -DEF_ISEL(FSUBD) = FSUBD; -DEF_ISEL(FSUBQ) = FSUBD; - -DEF_ISEL(FMULS) = FMULS; -DEF_ISEL(FMULD) = FMULD; -DEF_ISEL(FMULQ) = FMULD; - -DEF_ISEL(FDIVS) = FDIVS; -DEF_ISEL(FDIVD) = FDIVD; -DEF_ISEL(FDIVQ) = FDIVD; - -DEF_ISEL(FSMULD) = FsMULD; -DEF_ISEL(FDMULQ) = FdMULQ; - -namespace { - -DEF_SEM(FMOVS, RF32 src, RF32W dst) { - auto value = Read(src); - Write(dst, value); - WriteTrunc(FSR_CEXC, 0); - WriteTrunc(FSR_FTT, 0); - return memory; -} - -DEF_SEM(FMOVD, RF64 src, RF64W dst) { - auto value = Read(src); - Write(dst, value); - WriteTrunc(FSR_CEXC, 0); - WriteTrunc(FSR_FTT, 0); - return memory; -} - -DEF_SEM(FABSS, RF32 src, RF32W dst) { - auto value = Read(src); - auto result = static_cast(fabs(value)); - Write(dst, result); - WriteTrunc(FSR_CEXC, 0); - WriteTrunc(FSR_FTT, 0); - return memory; -} - -DEF_SEM(FABSD, RF64 src, RF64W dst) { - auto value = Read(src); - auto result = static_cast(fabs(value)); - Write(dst, result); - WriteTrunc(FSR_CEXC, 0); - WriteTrunc(FSR_FTT, 0); - return memory; -} - -DEF_SEM(FNEGS, RF32 src, RF32W dst) { - auto value = Read(src); - auto result = -value; - Write(dst, result); - WriteTrunc(FSR_CEXC, 0); - WriteTrunc(FSR_FTT, 0); - return memory; -} - -DEF_SEM(FNEGD, RF64 src, RF64W dst) { - auto value = Read(src); - auto result = -value; - Write(dst, result); - WriteTrunc(FSR_CEXC, 0); - WriteTrunc(FSR_FTT, 0); - return memory; -} - -DEF_SEM(FSQRTS, RF32 src, RF32W dst) { - auto value = Read(src); - auto res = Float32(__builtin_sqrtf(value)); - Write(dst, res); - return memory; -} - -DEF_SEM(FSQRTD, RF64 src, RF64W dst) { - auto lhs = Read(src); - auto res = Float64(__builtin_sqrt(lhs)); - Write(dst, res); - return memory; -} - -DEF_SEM(FITOS, R32 src, RF32W dst) { - Write(dst, Float32(Read(src))); - return memory; -} - -DEF_SEM(FITOD, R32 src, RF64W dst) { - Write(dst, Float64(Read(src))); - return memory; -} - -DEF_SEM(FSTOI, RF32 src, R32W dst) { - WriteSExt(dst, Int32(Read(src))); - return memory; -} - -DEF_SEM(FSTOD, RF32 src, RF64W dst) { - Write(dst, Float64(Read(src))); - return memory; -} - -DEF_SEM(FSTOQ, RF32 src, RF64W dst) { - Write(dst, Float64(Read(src))); - return memory; -} - -DEF_SEM(FDTOI, RF64 src, R32W dst) { - WriteSExt(dst, Int32(Read(src))); - return memory; -} - -DEF_SEM(FDTOQ, RF64 src, RF64W dst) { - Write(dst, Read(src)); - return memory; -} - -DEF_SEM(FDTOS, RF64 src, RF32W dst) { - Write(dst, Float32(Read(src))); - return memory; -} - -DEF_SEM(FQTOD, RF64 src, RF64W dst) { - Write(dst, Float64(Read(src))); - return memory; -} - -DEF_SEM(FQTOS, RF64 src, RF32W dst) { - Write(dst, Float32(Read(src))); - return memory; -} - -DEF_SEM(FXTOS, R64 src, RF32W dst) { - Write(dst, Float32(Read(src))); - return memory; -} - -DEF_SEM(FXTOD, R64 src, RF64W dst) { - Write(dst, Float64(Read(src))); - return memory; -} - -DEF_SEM(FXTOQ, R64 src, RF64W dst) { - Write(dst, Float64(Read(src))); - return memory; -} - -DEF_SEM(FDTOX, RF64 src, R64W dst) { - WriteSExt(dst, Int64(Read(src))); - return memory; -} - -DEF_SEM(FSTOX, RF32 src, R64W dst) { - WriteSExt(dst, Int64(Read(src))); - return memory; -} - -} // namespace - -DEF_ISEL(FMOVS) = FMOVS; -DEF_ISEL(FMOVD) = FMOVD; -DEF_ISEL(FMOVQ) = FMOVD; - -DEF_ISEL(FABSS) = FABSS; -DEF_ISEL(FABSD) = FABSD; -DEF_ISEL(FABSQ) = FABSD; - -DEF_ISEL(FNEGS) = FNEGS; -DEF_ISEL(FNEGD) = FNEGD; -DEF_ISEL(FNEGQ) = FNEGD; - -DEF_ISEL(FSQRTS) = FSQRTS; -DEF_ISEL(FSQRTD) = FSQRTD; -DEF_ISEL(FSQRTQ) = FSQRTD; - -DEF_ISEL(FITOS) = FITOS; -DEF_ISEL(FITOD) = FITOD; -DEF_ISEL(FITOQ) = FITOD; - -DEF_ISEL(FSTOI) = FSTOI; -DEF_ISEL(FSTOD) = FSTOD; -DEF_ISEL(FSTOQ) = FSTOQ; -DEF_ISEL(FSTOX) = FSTOX; - -DEF_ISEL(FDTOI) = FDTOI; -DEF_ISEL(FDTOS) = FDTOS; -DEF_ISEL(FDTOQ) = FDTOQ; -DEF_ISEL(FDTOX) = FDTOX; - -DEF_ISEL(FQTOS) = FDTOS; -DEF_ISEL(FQTOD) = FQTOD; - -DEF_ISEL(FXTOS) = FXTOS; -DEF_ISEL(FXTOD) = FXTOD; -DEF_ISEL(FXTOQ) = FXTOQ; - - -#define MAKE_COMPARE(fcc) \ - template \ - void FCompare_##fcc(State &state, Memory *memory, S val1, S val2, \ - bool signal) { \ - if (std::isnan(val1) || std::isnan(val2)) { \ - Write(state.fsr.fcc, Literal(3)); \ - } else { \ - if (FCmpEq(val1, val2)) { \ - /* result = '00'; */ \ - Write(state.fsr.fcc, Literal(0)); \ - } else if (FCmpLt(val1, val2)) { \ - /* result = '01'; */ \ - Write(state.fsr.fcc, Literal(1)); \ - } else { /* FCmpGt(val1, val2) */ \ - /* result = '10'; */ \ - Write(state.fsr.fcc, Literal(2)); \ - } \ - } \ - } - - -namespace { - -MAKE_COMPARE(fcc0) -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) { \ - 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) { \ - 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) { \ - 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) { \ - 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) { \ - auto val1 = Read(src1); \ - auto val2 = Read(src2); \ - FCompare_##fcc(state, memory, val1, val2, false); \ - return memory; \ - } - -namespace { - -MAKE_SEMANTICS_FCMP(fcc0) -MAKE_SEMANTICS_FCMP(fcc1) -MAKE_SEMANTICS_FCMP(fcc2) -MAKE_SEMANTICS_FCMP(fcc3) - -MAKE_SEMANTICS_FCMPE(fcc0) -MAKE_SEMANTICS_FCMPE(fcc1) -MAKE_SEMANTICS_FCMPE(fcc2) -MAKE_SEMANTICS_FCMPE(fcc3) - -} // namespace - -#undef MAKE_SEMANTICS_FCMP -#undef MAKE_SEMANTICS_FCMPE - -DEF_ISEL(FCMPS_fcc0) = FCMPS_fcc0; -DEF_ISEL(FCMPD_fcc0) = FCMPD_fcc0; -DEF_ISEL(FCMPQ_fcc0) = FCMPQ_fcc0; - -DEF_ISEL(FCMPS_fcc1) = FCMPS_fcc1; -DEF_ISEL(FCMPD_fcc1) = FCMPD_fcc1; -DEF_ISEL(FCMPQ_fcc1) = FCMPQ_fcc1; - -DEF_ISEL(FCMPS_fcc2) = FCMPS_fcc2; -DEF_ISEL(FCMPD_fcc2) = FCMPD_fcc2; -DEF_ISEL(FCMPQ_fcc2) = FCMPQ_fcc2; - -DEF_ISEL(FCMPS_fcc3) = FCMPS_fcc3; -DEF_ISEL(FCMPD_fcc3) = FCMPD_fcc3; -DEF_ISEL(FCMPQ_fcc3) = FCMPQ_fcc3; - -DEF_ISEL(FCMPES_fcc0) = FCMPES_fcc0; -DEF_ISEL(FCMPED_fcc0) = FCMPED_fcc0; -DEF_ISEL(FCMPEQ_fcc0) = FCMPEQ_fcc0; - -DEF_ISEL(FCMPES_fcc1) = FCMPES_fcc1; -DEF_ISEL(FCMPED_fcc1) = FCMPED_fcc1; -DEF_ISEL(FCMPEQ_fcc1) = FCMPEQ_fcc1; - -DEF_ISEL(FCMPES_fcc2) = FCMPES_fcc2; -DEF_ISEL(FCMPED_fcc2) = FCMPED_fcc2; -DEF_ISEL(FCMPEQ_fcc2) = FCMPEQ_fcc2; - -DEF_ISEL(FCMPES_fcc3) = FCMPES_fcc3; -DEF_ISEL(FCMPED_fcc3) = FCMPED_fcc3; -DEF_ISEL(FCMPEQ_fcc3) = FCMPEQ_fcc3; diff --git a/lib/Arch/SPARC32/Semantics/LOGICAL.cpp b/lib/Arch/SPARC32/Semantics/LOGICAL.cpp deleted file mode 100644 index b1ad772c1..000000000 --- a/lib/Arch/SPARC32/Semantics/LOGICAL.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2020 Trail of Bits, Inc. - */ - -namespace { - -template -ALWAYS_INLINE void SetFlagsLogical(State &state, T lhs, T rhs, T res) { - FLAG_ICC_CF = false; - FLAG_ICC_ZF = ZeroFlag(res, lhs, rhs); - FLAG_ICC_NF = SignFlag(res, lhs, rhs); - FLAG_ICC_VF = false; -} - -template -DEF_SEM(AND, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = UAnd(lhs, rhs); - Write(dst, res); - return memory; -} - -template -DEF_SEM(ANDcc, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = UAnd(lhs, rhs); - Write(dst, res); - SetFlagsLogical(state, lhs, rhs, res); - return memory; -} - -template -DEF_SEM(ANDN, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = UAnd(lhs, UNot(rhs)); - WriteZExt(dst, res); - return memory; -} - -template -DEF_SEM(ANDNcc, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = UAnd(lhs, UNot(rhs)); - WriteZExt(dst, res); - SetFlagsLogical(state, lhs, rhs, res); - return memory; -} - -template -DEF_SEM(OR, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = UOr(lhs, rhs); - Write(dst, res); - return memory; -} - -template -DEF_SEM(ORcc, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = UOr(lhs, rhs); - Write(dst, res); - SetFlagsLogical(state, lhs, rhs, res); - return memory; -} - -template -DEF_SEM(ORN, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = UOr(lhs, UNot(rhs)); - WriteZExt(dst, res); - return memory; -} - -template -DEF_SEM(ORNcc, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = UOr(lhs, UNot(rhs)); - WriteZExt(dst, res); - SetFlagsLogical(state, lhs, rhs, res); - return memory; -} - -template -DEF_SEM(XOR, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = UXor(lhs, rhs); - WriteZExt(dst, res); - return memory; -} - -template -DEF_SEM(XORcc, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = UXor(lhs, rhs); - WriteZExt(dst, res); - SetFlagsLogical(state, lhs, rhs, res); - return memory; -} - -template -DEF_SEM(XNOR, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = UXor(lhs, UNot(rhs)); - WriteZExt(dst, res); - return memory; -} - -template -DEF_SEM(XNORcc, S1 src1, S2 src2, D dst) { - auto lhs = Read(src1); - auto rhs = Read(src2); - auto res = UXor(lhs, UNot(rhs)); - WriteZExt(dst, res); - SetFlagsLogical(state, lhs, rhs, res); - return memory; -} - -} // namespace - -DEF_ISEL(AND) = AND; -DEF_ISEL(ANDcc) = ANDcc; -DEF_ISEL(ANDN) = ANDN; -DEF_ISEL(ANDNcc) = ANDNcc; - -DEF_ISEL(AND_I32) = AND; -DEF_ISEL(ANDcc_I32) = ANDcc; -DEF_ISEL(ANDN_I32) = ANDN; -DEF_ISEL(ANDNcc_I32) = ANDNcc; - -DEF_ISEL(OR) = OR; -DEF_ISEL(ORcc) = ORcc; -DEF_ISEL(ORN) = ORN; -DEF_ISEL(ORNcc) = ORNcc; - -DEF_ISEL(OR_I32) = OR; -DEF_ISEL(ORcc_I32) = ORcc; -DEF_ISEL(ORN_I32) = ORN; -DEF_ISEL(ORNcc_I32) = ORNcc; - -DEF_ISEL(XOR) = XOR; -DEF_ISEL(XORcc) = XORcc; -DEF_ISEL(XNOR) = XNOR; -DEF_ISEL(XNORcc) = XNORcc; - -DEF_ISEL(XOR_I32) = XOR; -DEF_ISEL(XORcc_I32) = XORcc; -DEF_ISEL(XNOR_I32) = XNOR; -DEF_ISEL(XNORcc_I32) = XNORcc; - -namespace { - -template -DEF_SEM(SLL, S1 src1, S2 src2, D dst) { - auto value = Read(src1); - auto shift = Read(src2); - auto res = UShl(value, shift); - Write(dst, res); - return memory; -} - -template -DEF_SEM(SRL, S1 src1, S2 src2, D dst) { - auto value = Read(src1); - auto shift = Read(src2); - auto res = UShr(value, shift); - Write(dst, res); - return memory; -} - -template -DEF_SEM(SRA, S1 src1, S2 src2, D dst) { - auto val = Signed(Read(src1)); - auto shift = Read(src2); - auto res = SShr(val, Signed(shift)); - Write(dst, Unsigned(res)); - return memory; -} - -} // namespace - -DEF_ISEL(SLL) = SLL; -DEF_ISEL(SRL) = SRL; -DEF_ISEL(SRA) = SRA; diff --git a/lib/Arch/SPARC32/Semantics/MISC.cpp b/lib/Arch/SPARC32/Semantics/MISC.cpp deleted file mode 100644 index f9b836fe9..000000000 --- a/lib/Arch/SPARC32/Semantics/MISC.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2020 Trail of Bits, Inc. - */ - -namespace { - -DEF_SEM(NOP) { - return memory; -} - -} // namespace - -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_ISEL(WR##op) = WR##op; - -MAKE_SEMANTICS_WR(Y) -MAKE_SEMANTICS_WR(PAUSE) -MAKE_SEMANTICS_WR(STICK_CMPR) -MAKE_SEMANTICS_WR(SOFTINT) -MAKE_SEMANTICS_WR(FPRS) -MAKE_SEMANTICS_WR(GSR) -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_ISEL(RD##op) = RD##op; - -MAKE_SEMANTICS_RD(Y) -MAKE_SEMANTICS_RD(ASI) -MAKE_SEMANTICS_RD(PC) -MAKE_SEMANTICS_RD(FPRS) - -namespace { - -DEF_SEM(IMPDEP1, I32 opf) { - HYPER_CALL_VECTOR = Literal(Read(opf)); - return __remill_sync_hyper_call( - state, memory, - SyncHyperCall::IF_32BIT_ELSE(kSPARC32EmulateInstruction, - kSPARC64EmulateInstruction)); -} - -DEF_SEM(IMPDEP2, I32 opf) { - HYPER_CALL_VECTOR = Literal(Read(opf)); - return __remill_sync_hyper_call( - state, memory, - SyncHyperCall::IF_32BIT_ELSE(kSPARC32EmulateInstruction, - kSPARC64EmulateInstruction)); -} - -} // namespace -DEF_ISEL(IMPDEP1) = IMPDEP1; -DEF_ISEL(IMPDEP2) = IMPDEP2; diff --git a/lib/Arch/SPARC32/Semantics/TRAP.cpp b/lib/Arch/SPARC32/Semantics/TRAP.cpp deleted file mode 100644 index e9475a285..000000000 --- a/lib/Arch/SPARC32/Semantics/TRAP.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2020 Trail of Bits, Inc. - */ - -// Makes an asynchronous and synchronous version of the trap. The asynchronous -// exists during normal control-flow, and introduces its own control flow and -// an async hyper call. The synchronous version exists when the trap instruction -// 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; \ - 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; \ - HYPER_CALL_VECTOR = UAnd(UAdd(Read(vec_a), Read(vec_b)), 0x7fu); \ - return __remill_sync_hyper_call(state, memory, \ - SyncHyperCall::kSPARCTrapCond##cond); \ - } \ - } \ - 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) { - 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) { - 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); -} - -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) { - return memory; -} - -} // namespace - -DEF_ISEL(TA) = TA; -DEF_ISEL(TA_sync) = TA_sync; -DEF_ISEL(TN) = TN; -DEF_ISEL(TN_sync) = TN_sync; - -MAKE_TRAP(NE, icc); -MAKE_TRAP(E, icc); -MAKE_TRAP(G, icc); -MAKE_TRAP(LE, icc); -MAKE_TRAP(GE, icc); -MAKE_TRAP(L, icc); -MAKE_TRAP(GU, icc); -MAKE_TRAP(LEU, icc); -MAKE_TRAP(CC, icc); -MAKE_TRAP(CS, icc); -MAKE_TRAP(POS, icc); -MAKE_TRAP(NEG, icc); -MAKE_TRAP(VC, icc); -MAKE_TRAP(VS, icc); - -#undef MAKE_TRAP - -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. - HYPER_CALL_VECTOR = Read(struct_size); - return __remill_sync_hyper_call( - state, memory, SyncHyperCall::kSPARCUnimplementedInstruction); -} - -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. - HYPER_CALL_VECTOR = Read(struct_size); - HYPER_CALL = AsyncHyperCall::kSPARCUnimplementedInstruction; - return memory; -} - -} // namespace - -DEF_ISEL(UNIMP_SYNC) = UNIMP_SYNC; // In a delay slot. -DEF_ISEL(UNIMP_ASYNC) = UNIMP_ASYNC; // Not in a delay slot. diff --git a/lib/Arch/SPARC32/Semantics/WINDOW.cpp b/lib/Arch/SPARC32/Semantics/WINDOW.cpp deleted file mode 100644 index 977231bf8..000000000 --- a/lib/Arch/SPARC32/Semantics/WINDOW.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2020 Trail of Bits, Inc. - */ - -namespace { - -template -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); - SAVE_WINDOW(memory, state, window, prev_window); - WriteZExt(dst, new_sp); - return memory; -} - -template -DEF_SEM(RESTORE, S1 src1, S2 src2, D dst, RegisterWindow *&prev_window) { - auto rs1 = Read(src1); - auto rs2 = Read(src2); - auto sum = UAdd(rs1, rs2); - RESTORE_WINDOW(memory, state, prev_window); - WriteZExt(dst, sum); - return memory; -} - -} // namespace - -DEF_ISEL(SAVE) = SAVE; -DEF_ISEL(RESTORE) = RESTORE; diff --git a/lib/Arch/SPARC64/CMakeLists.txt b/lib/Arch/SPARC64/CMakeLists.txt index 4618d3438..0aab93493 100644 --- a/lib/Arch/SPARC64/CMakeLists.txt +++ b/lib/Arch/SPARC64/CMakeLists.txt @@ -31,8 +31,6 @@ add_library(remill_arch_sparc64 STATIC Extract.cpp ) -add_subdirectory(Runtime) - set_property(TARGET remill_arch_sparc64 PROPERTY POSITION_INDEPENDENT_CODE ON) target_link_libraries(remill_arch_sparc64 LINK_PUBLIC @@ -44,4 +42,4 @@ if(REMILL_ENABLE_INSTALL_TARGET) TARGETS remill_arch_sparc64 EXPORT remillTargets ) -endif() \ No newline at end of file +endif() diff --git a/lib/Arch/Sleigh/Arch.cpp b/lib/Arch/Sleigh/Arch.cpp index b46dee206..6b79c4169 100644 --- a/lib/Arch/Sleigh/Arch.cpp +++ b/lib/Arch/Sleigh/Arch.cpp @@ -166,7 +166,7 @@ void CustomLoadImage::loadFill(unsigned char *ptr, int size, continue; } - ptr[i] = this->current_bytes[i]; + ptr[i] = this->current_bytes[index]; } } @@ -208,17 +208,21 @@ bool SleighDecoder::DecodeInstruction(uint64_t address, auto res_cat = const_cast(this)->DecodeInstructionImpl( address, instr_bytes, inst, std::move(context)); - if (!res_cat->second && - std::holds_alternative( - res_cat->first)) { - LOG(FATAL) - << "Should always emit branch taken var for conditional instruction"; - } + if (res_cat.has_value()) { + if (!res_cat->second && + std::holds_alternative( + res_cat->first)) { + LOG(FATAL) + << "Should always emit branch taken var for conditional instruction"; + } - inst.SetLifter(std::make_shared( - res_cat->second, std::move(context_values), this->GetLifter())); - CHECK(inst.GetLifter() != nullptr); - return res_cat.has_value(); + inst.SetLifter(std::make_shared( + res_cat->second, std::move(context_values), this->GetLifter())); + CHECK(inst.GetLifter() != nullptr); + return true; + } else { + return false; + } } @@ -244,8 +248,7 @@ SleighDecoder::GetStateRegRemappings() const { return this->state_reg_remappings; } -std::optional< - std::pair> +ControlFlowStructureAnalysis::SleighDecodingResult SleighDecoder::DecodeInstructionImpl(uint64_t address, std::string_view instr_bytes, Instruction &inst, @@ -296,8 +299,10 @@ SleighDecoder::DecodeInstructionImpl(uint64_t address, LOG(ERROR) << "Failed to compute category for inst at " << std::hex << inst.pc; inst.flows = Instruction::InvalidInsn(); - inst.category = Instruction::Category::kCategoryInvalid; - return std::nullopt; + // Do not mark the instruction category as "invalid". Even if we can't determine a control flow + // category, we still want to attempt to lift this instruction. + inst.category = Instruction::Category::kCategoryNormal; + return std::make_pair(inst.flows, std::nullopt); } inst.flows = cat->first; diff --git a/lib/Arch/Sleigh/CMakeLists.txt b/lib/Arch/Sleigh/CMakeLists.txt index f08e2700a..8e480ede2 100644 --- a/lib/Arch/Sleigh/CMakeLists.txt +++ b/lib/Arch/Sleigh/CMakeLists.txt @@ -34,6 +34,10 @@ add_library(remill_arch_sleigh STATIC "${REMILL_INCLUDE_DIR}/remill/Arch/AArch64/Runtime/State.h" "${REMILL_INCLUDE_DIR}/remill/Arch/AArch64/Runtime/Types.h" + "${REMILL_INCLUDE_DIR}/remill/Arch/SPARC32/Runtime/State.h" + "${REMILL_INCLUDE_DIR}/remill/Arch/SPARC32/Runtime/Types.h" + "${REMILL_INCLUDE_DIR}/remill/Arch/SPARC32/SPARC32Base.h" + "${REMILL_INCLUDE_DIR}/remill/Arch/PPC/Runtime/State.h" Arch.h @@ -53,6 +57,10 @@ add_library(remill_arch_sleigh STATIC AArch64Arch.cpp AArch64Arch.h AArch64Base.cpp + + SPARC32Arch.cpp + SPARC32Arch.h + SPARC32Base.cpp ) add_dependencies(remill_arch_sleigh sleigh_custom_specs) diff --git a/lib/Arch/Sleigh/SPARC32Arch.cpp b/lib/Arch/Sleigh/SPARC32Arch.cpp new file mode 100644 index 000000000..83447709e --- /dev/null +++ b/lib/Arch/Sleigh/SPARC32Arch.cpp @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include + +#include "remill/Arch/Instruction.h" +#include "remill/Arch/Name.h" +#include "remill/BC/ABI.h" +#include "remill/BC/Util.h" +#include "remill/BC/Version.h" +#include "remill/OS/OS.h" +// clang-format off +#include + +// clang-format on + +#include // For `ArchImpl`. + +#include "SPARC32Arch.h" + +namespace remill { + +SleighSPARC32Decoder::SleighSPARC32Decoder(const remill::Arch &arch) + : SleighDecoder(arch, "SparcV9_32.sla", "SparcV9.pspec", + sleigh::ContextRegMappings({}, {}), + {}) {} + + +void SleighSPARC32Decoder::InitializeSleighContext( + uint64_t addr, remill::sleigh::SingleInstructionSleighContext &ctxt, + const ContextValues &values) const {} + +llvm::Value *SleighSPARC32Decoder::LiftPcFromCurrPc( + llvm::IRBuilder<> &bldr, llvm::Value *curr_pc, size_t curr_insn_size, + const DecodingContext &context) const { + return bldr.CreateAdd(curr_pc, llvm::ConstantInt::get(curr_pc->getType(), 4)); +} + +SPARC32Arch::SPARC32Arch(llvm::LLVMContext *context_, OSName os_name_, + ArchName arch_name_) + : ArchBase(context_, os_name_, arch_name_), + SPARC32ArchBase(context_, os_name_, arch_name_), + decoder(*this) {} + +SPARC32Arch::~SPARC32Arch(void) {} + +OperandLifter::OpLifterPtr SPARC32Arch::DefaultLifter( + const remill::IntrinsicTable &intrinsics_table) const { + return std::make_shared(this, intrinsics_table); +} + +bool SPARC32Arch::DecodeInstruction(uint64_t address, + std::string_view inst_bytes, + Instruction &inst, + DecodingContext context) const { + inst.pc = address; + inst.next_pc = address + inst_bytes.size(); // Default fall-through. + inst.branch_taken_pc = 0; + inst.branch_not_taken_pc = 0; + inst.has_branch_taken_delay_slot = false; + inst.has_branch_not_taken_delay_slot = false; + inst.arch_name = arch_name; + inst.sub_arch_name = arch_name; + inst.branch_taken_arch_name = arch_name; + inst.arch = this; + inst.category = Instruction::kCategoryInvalid; + inst.operands.clear(); + inst.flows = Instruction::InvalidInsn(); + + return this->decoder.DecodeInstruction(address, inst_bytes, inst, context); +} + +DecodingContext SPARC32Arch::CreateInitialContext(void) const { + return DecodingContext(); +} + + +// TODO(pag): We pretend that these are singletons, but they aren't really! +Arch::ArchPtr Arch::GetSPARC32Sleigh(llvm::LLVMContext *context_, + OSName os_name_, ArchName arch_name_) { + return std::make_unique(context_, os_name_, arch_name_); +} + + +} // namespace remill diff --git a/lib/Arch/Sleigh/SPARC32Arch.h b/lib/Arch/Sleigh/SPARC32Arch.h new file mode 100644 index 000000000..c2a988b86 --- /dev/null +++ b/lib/Arch/Sleigh/SPARC32Arch.h @@ -0,0 +1,46 @@ +#include + +#include "Arch.h" + +namespace remill { + +class SleighSPARC32Decoder final : public remill::sleigh::SleighDecoder { + public: + SleighSPARC32Decoder(const remill::Arch &arch); + + + virtual llvm::Value *LiftPcFromCurrPc(llvm::IRBuilder<> &bldr, llvm::Value *, + size_t curr_insn_size, + const DecodingContext &) const final; + + void + InitializeSleighContext(uint64_t addr, + remill::sleigh::SingleInstructionSleighContext &ctxt, + const ContextValues &context_values) const final; +}; + +class SPARC32Arch final : public SPARC32ArchBase { + public: + SPARC32Arch(llvm::LLVMContext *context_, OSName os_name_, + ArchName arch_name_); + + virtual ~SPARC32Arch(void); + + + virtual DecodingContext CreateInitialContext(void) const override; + + bool DecodeInstruction(uint64_t address, std::string_view instr_bytes, + Instruction &inst, + DecodingContext context) const override; + + + OperandLifter::OpLifterPtr + DefaultLifter(const remill::IntrinsicTable &intrinsics) const override; + + SPARC32Arch(void) = delete; + + private: + SleighSPARC32Decoder decoder; +}; + +} // namespace remill diff --git a/lib/Arch/Sleigh/SPARC32Base.cpp b/lib/Arch/Sleigh/SPARC32Base.cpp new file mode 100644 index 000000000..8cb95629d --- /dev/null +++ b/lib/Arch/Sleigh/SPARC32Base.cpp @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2019 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace remill { +// Returns the name of the stack pointer register. +std::string_view SPARC32ArchBase::StackPointerRegisterName(void) const { + return "SP"; +} + +// Returns the name of the program counter register. +std::string_view SPARC32ArchBase::ProgramCounterRegisterName(void) const { + return "PC"; +} + +uint64_t SPARC32ArchBase::MinInstructionAlign(const DecodingContext &) const { + return 4; +} + +uint64_t SPARC32ArchBase::MinInstructionSize(const DecodingContext &) const { + return 4; +} + +// Returns `true` if memory access are little endian byte ordered. +bool SPARC32ArchBase::MemoryAccessIsLittleEndian(void) const { + return false; +} + +// Returns `true` if a given instruction might have a delay slot. +bool SPARC32ArchBase::MayHaveDelaySlot(const Instruction &inst) const { + return inst.has_branch_taken_delay_slot || + inst.has_branch_not_taken_delay_slot; +} + +// Returns `true` if we should lift the semantics of `next_inst` as a delay +// slot of `inst`. The `branch_taken_path` tells us whether we are in the +// context of the taken path of a branch or the not-taken path of a branch. +bool SPARC32ArchBase::NextInstructionIsDelayed(const Instruction &inst, + const Instruction &next_inst, + bool branch_taken_path) const { + if (inst.delayed_pc != next_inst.pc) { + return false; + } + + if (branch_taken_path) { + return inst.has_branch_taken_delay_slot; + } else { + return inst.has_branch_not_taken_delay_slot; + } +} + +// Maximum number of bytes in an instruction. +uint64_t SPARC32ArchBase::MaxInstructionSize(const DecodingContext &, + bool permit_fuse_idioms) const { + return permit_fuse_idioms ? 8 : 4; // To handle `SET` idioms. +} + +// Default calling convention for this architecture. +llvm::CallingConv::ID SPARC32ArchBase::DefaultCallingConv(void) const { + return llvm::CallingConv::C; +} + +// Populate the table of register information. +void SPARC32ArchBase::PopulateRegisterTable(void) const { + + reg_by_offset.resize(sizeof(SPARC32State)); + +#define OFFSET_OF(type, access) \ + (reinterpret_cast(&reinterpret_cast( \ + static_cast(nullptr)->access))) + +#define REG(name, access, type) \ + AddRegister(#name, type, OFFSET_OF(SPARC32State, access), nullptr) + +#define SUB_REG(name, access, type, parent_reg_name) \ + AddRegister(#name, type, OFFSET_OF(SPARC32State, access), #parent_reg_name) + + auto u8 = llvm::Type::getInt8Ty(*context); + auto u32 = llvm::Type::getInt32Ty(*context); + auto u64 = llvm::Type::getInt64Ty(*context); + auto u128 = llvm::Type::getInt128Ty(*context); + auto f32 = llvm::Type::getFloatTy(*context); + auto f64 = llvm::Type::getDoubleTy(*context); + + REG(PC, pc.dword, u32); + + REG(CWP, cwp.dword, u32); + + REG(I0_1, gpr.i0_1.qword, u64); + REG(I2_3, gpr.i2_3.qword, u64); + REG(I4_5, gpr.i4_5.qword, u64); + REG(FP_7, gpr.fp_7.qword, u64); + REG(L0_1, gpr.l0_1.qword, u64); + REG(L2_3, gpr.l2_3.qword, u64); + REG(L4_5, gpr.l4_5.qword, u64); + REG(L6_7, gpr.l6_7.qword, u64); + REG(O0_1, gpr.o0_1.qword, u64); + REG(O2_3, gpr.o2_3.qword, u64); + REG(O4_5, gpr.o4_5.qword, u64); + REG(SP_7, gpr.sp_7.qword, u64); + REG(G0_1, gpr.g0_1.qword, u64); + REG(G2_3, gpr.g2_3.qword, u64); + REG(G4_5, gpr.g4_5.qword, u64); + REG(G6_7, gpr.g6_7.qword, u64); + + SUB_REG(I0, gpr.i0_1.reg1.dword, u32, I0_1); + SUB_REG(I1, gpr.i0_1.reg2.dword, u32, I0_1); + SUB_REG(I2, gpr.i2_3.reg1.dword, u32, I2_3); + SUB_REG(I3, gpr.i2_3.reg2.dword, u32, I2_3); + SUB_REG(I4, gpr.i4_5.reg1.dword, u32, I4_5); + SUB_REG(I5, gpr.i4_5.reg2.dword, u32, I4_5); + SUB_REG(FP, gpr.fp_7.reg1.dword, u32, FP_7); + SUB_REG(I7, gpr.fp_7.reg2.dword, u32, FP_7); + SUB_REG(L0, gpr.l0_1.reg1.dword, u32, L0_1); + SUB_REG(L1, gpr.l0_1.reg2.dword, u32, L0_1); + SUB_REG(L2, gpr.l2_3.reg1.dword, u32, L2_3); + SUB_REG(L3, gpr.l2_3.reg2.dword, u32, L2_3); + SUB_REG(L4, gpr.l4_5.reg1.dword, u32, L4_5); + SUB_REG(L5, gpr.l4_5.reg2.dword, u32, L4_5); + SUB_REG(L6, gpr.l6_7.reg1.dword, u32, L6_7); + SUB_REG(L7, gpr.l6_7.reg2.dword, u32, L6_7); + SUB_REG(O0, gpr.o0_1.reg1.dword, u32, O0_1); + SUB_REG(O1, gpr.o0_1.reg2.dword, u32, O0_1); + SUB_REG(O2, gpr.o2_3.reg1.dword, u32, O2_3); + SUB_REG(O3, gpr.o2_3.reg2.dword, u32, O2_3); + SUB_REG(O4, gpr.o4_5.reg1.dword, u32, O4_5); + SUB_REG(O5, gpr.o4_5.reg2.dword, u32, O4_5); + SUB_REG(SP, gpr.sp_7.reg1.dword, u32, SP_7); + SUB_REG(O7, gpr.sp_7.reg2.dword, u32, SP_7); + + SUB_REG(G0, gpr.g0_1.reg1.dword, u32, G0_1); + SUB_REG(G1, gpr.g0_1.reg2.dword, u32, G0_1); + SUB_REG(G2, gpr.g2_3.reg1.dword, u32, G2_3); + SUB_REG(G3, gpr.g2_3.reg2.dword, u32, G2_3); + SUB_REG(G4, gpr.g4_5.reg1.dword, u32, G4_5); + SUB_REG(G5, gpr.g4_5.reg2.dword, u32, G4_5); + SUB_REG(G6, gpr.g6_7.reg1.dword, u32, G6_7); + SUB_REG(G7, gpr.g6_7.reg2.dword, u32, G6_7); + + // Ancillary State Register + REG(Y, asr.yreg.dword, u32); + REG(TICK, asr.tick.dword, u32); + REG(CCR, asr.ccr.dword, u32); + REG(PCR, asr.pcr.dword, u32); + REG(PIC, asr.pic.dword, u32); + REG(GSR, asr.gsr.dword, u32); + REG(SOFTINT_SET, asr.softint_set.dword, u32); + REG(SOFTINT_CLR, asr.softint_clr.dword, u32); + REG(SOFTINT, asr.softint.dword, u32); + REG(TICK_CMPR, asr.tick_cmpr.dword, u32); + REG(STICK, asr.stick.dword, u32); + REG(STICK_CMPR, asr.stick_cmpr.dword, u32); + + REG(I_CF, ccr.icc.i_cf, u8); + REG(I_VF, ccr.icc.i_vf, u8); + REG(I_ZF, ccr.icc.i_zf, u8); + REG(I_NF, ccr.icc.i_nf, u8); + + REG(X_CF, ccr.xcc.x_cf, u8); + REG(X_VF, ccr.xcc.x_vf, u8); + REG(X_ZF, ccr.xcc.x_zf, u8); + REG(X_NF, ccr.xcc.x_nf, u8); + + REG(ccf_fcc0, fsr.fcc0, u8); + REG(ccf_fcc1, fsr.fcc1, u8); + REG(ccf_fcc2, fsr.fcc2, u8); + REG(ccf_fcc3, fsr.fcc3, u8); + + REG(fsr_aexc, fsr.aexc, u8); + REG(fsr_cexc, fsr.cexc, u8); + + REG(FQ0, fpreg.v[0], u128); + REG(FQ4, fpreg.v[1], u128); + REG(FQ8, fpreg.v[2], u128); + REG(FQ12, fpreg.v[3], u128); + REG(FQ16, fpreg.v[4], u128); + REG(FQ20, fpreg.v[5], u128); + REG(FQ24, fpreg.v[6], u128); + REG(FQ28, fpreg.v[7], u128); + + SUB_REG(FS0, fpreg.v[0].floats.elems[0], f32, FQ0); + SUB_REG(FS1, fpreg.v[0].floats.elems[1], f32, FQ0); + SUB_REG(FS2, fpreg.v[0].floats.elems[2], f32, FQ0); + SUB_REG(FS3, fpreg.v[0].floats.elems[3], f32, FQ0); + SUB_REG(FS4, fpreg.v[1].floats.elems[0], f32, FQ4); + SUB_REG(FS5, fpreg.v[1].floats.elems[1], f32, FQ4); + SUB_REG(FS6, fpreg.v[1].floats.elems[2], f32, FQ4); + SUB_REG(FS7, fpreg.v[1].floats.elems[3], f32, FQ4); + SUB_REG(FS8, fpreg.v[2].floats.elems[0], f32, FQ8); + SUB_REG(FS9, fpreg.v[2].floats.elems[1], f32, FQ8); + SUB_REG(FS10, fpreg.v[2].floats.elems[2], f32, FQ8); + SUB_REG(FS11, fpreg.v[2].floats.elems[3], f32, FQ8); + SUB_REG(FS12, fpreg.v[3].floats.elems[0], f32, FQ12); + SUB_REG(FS13, fpreg.v[3].floats.elems[1], f32, FQ12); + SUB_REG(FS14, fpreg.v[3].floats.elems[2], f32, FQ12); + SUB_REG(FS15, fpreg.v[3].floats.elems[3], f32, FQ12); + SUB_REG(FS16, fpreg.v[4].floats.elems[0], f32, FQ16); + SUB_REG(FS17, fpreg.v[4].floats.elems[1], f32, FQ16); + SUB_REG(FS18, fpreg.v[4].floats.elems[2], f32, FQ16); + SUB_REG(FS19, fpreg.v[4].floats.elems[3], f32, FQ16); + SUB_REG(FS20, fpreg.v[5].floats.elems[0], f32, FQ20); + SUB_REG(FS21, fpreg.v[5].floats.elems[1], f32, FQ20); + SUB_REG(FS22, fpreg.v[5].floats.elems[2], f32, FQ20); + SUB_REG(FS23, fpreg.v[5].floats.elems[3], f32, FQ20); + SUB_REG(FS24, fpreg.v[6].floats.elems[0], f32, FQ24); + SUB_REG(FS25, fpreg.v[6].floats.elems[1], f32, FQ24); + SUB_REG(FS26, fpreg.v[6].floats.elems[2], f32, FQ24); + SUB_REG(FS27, fpreg.v[6].floats.elems[3], f32, FQ24); + SUB_REG(FS28, fpreg.v[7].floats.elems[0], f32, FQ28); + SUB_REG(FS29, fpreg.v[7].floats.elems[1], f32, FQ28); + SUB_REG(FS30, fpreg.v[7].floats.elems[2], f32, FQ28); + SUB_REG(FS31, fpreg.v[7].floats.elems[3], f32, FQ28); + + SUB_REG(FD0, fpreg.v[0].doubles.elems[0], f64, FQ0); + SUB_REG(FD2, fpreg.v[0].doubles.elems[1], f64, FQ0); + SUB_REG(FD4, fpreg.v[1].doubles.elems[0], f64, FQ4); + SUB_REG(FD6, fpreg.v[1].doubles.elems[1], f64, FQ4); + SUB_REG(FD8, fpreg.v[2].doubles.elems[0], f64, FQ8); + SUB_REG(FD10, fpreg.v[2].doubles.elems[1], f64, FQ8); + SUB_REG(FD12, fpreg.v[3].doubles.elems[0], f64, FQ12); + SUB_REG(FD14, fpreg.v[3].doubles.elems[1], f64, FQ12); + SUB_REG(FD16, fpreg.v[4].doubles.elems[0], f64, FQ16); + SUB_REG(FD18, fpreg.v[4].doubles.elems[1], f64, FQ16); + SUB_REG(FD20, fpreg.v[5].doubles.elems[0], f64, FQ20); + SUB_REG(FD22, fpreg.v[5].doubles.elems[1], f64, FQ20); + SUB_REG(FD24, fpreg.v[6].doubles.elems[0], f64, FQ24); + SUB_REG(FD26, fpreg.v[6].doubles.elems[1], f64, FQ24); + SUB_REG(FD28, fpreg.v[7].doubles.elems[0], f64, FQ28); + SUB_REG(FD30, fpreg.v[7].doubles.elems[1], f64, FQ28); + + REG(DECOMPILE_MODE, decompile_mode, u8); + REG(DIDRESTORE, didrestore, u8); +} + +// Populate a just-initialized lifted function function with architecture- +// specific variables. +void SPARC32ArchBase::FinishLiftedFunctionInitialization( + llvm::Module *module, llvm::Function *bb_func) const { + + auto &context = module->getContext(); + auto u8 = llvm::Type::getInt8Ty(context); + auto u32 = llvm::Type::getInt32Ty(context); + auto addr = llvm::Type::getIntNTy(context, address_size); + + auto zero_u8 = llvm::Constant::getNullValue(u8); + auto zero_u32 = llvm::Constant::getNullValue(u32); + + const auto entry_block = &bb_func->getEntryBlock(); + llvm::IRBuilder<> ir(entry_block); + + ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "g0"), false); + ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "ignore_write_to_g0"), + false); + + // this is for unknown asr to avoid crash. + ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "asr"), 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_RETURN_PC"), + false); + + 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, kNextPCVariableName.data())); + ir.CreateStore( + pc_arg, ir.CreateAlloca(addr, nullptr, kIgnoreNextPCVariableName.data())); + + + ir.CreateStore(pc_arg, + RegisterByName(kPCVariableName)->AddressOf(state_ptr_arg, ir), + false); +} + +llvm::Triple SPARC32ArchBase::Triple(void) const { + auto triple = BasicTriple(); + triple.setArch(llvm::Triple::sparc); + return triple; +} + +llvm::DataLayout SPARC32ArchBase::DataLayout(void) const { + return llvm::DataLayout("E-m:e-p:32:32-i64:64-f128:64-n32-S64"); +} + +} // remill diff --git a/lib/BC/PcodeCFG.cpp b/lib/BC/PcodeCFG.cpp index d9da3bd01..5265d3374 100644 --- a/lib/BC/PcodeCFG.cpp +++ b/lib/BC/PcodeCFG.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,12 @@ std::vector PcodeCFGBuilder::GetBlockStarts() const { for (size_t curr_index = 0; curr_index < linear_ops.size(); curr_index += 1) { auto interproc = GetIntraProcTargets(curr_index); res.insert(res.end(), interproc.begin(), interproc.end()); + if (GetControlFlowExitsForIndex(curr_index) && + curr_index + 1 < linear_ops.size()) { + res.push_back( + curr_index + + 1); // make sure we start a new block after control flow regardless + } } return res; } @@ -77,16 +84,19 @@ std::vector PcodeCFGBuilder::GetIntraProcTargets(size_t index) const { return IntraProcTransferCollector::CollectIntraProcTransfers(ex); } -BlockExit PcodeCFGBuilder::GetBlockExitsForIndex(size_t index) const { + +std::optional +PcodeCFGBuilder::GetControlFlowExitsForIndex(size_t index) const { CHECK(index < linear_ops.size()); const auto &curr_op = linear_ops[index]; - auto build_direct_target_exit = [](VarnodeData target, - size_t curr_ind) -> Exit { + auto build_direct_target_exit = [&](VarnodeData target, + size_t curr_ind) -> Exit { if (isVarnodeInConstantSpace(target)) { // need to treat as signed? return IntrainstructionIndex{curr_ind + target.offset}; } + return InstrExit{}; }; switch (curr_op.op) { @@ -110,15 +120,24 @@ BlockExit PcodeCFGBuilder::GetBlockExitsForIndex(size_t index) const { } case CPUI_CALLIND: case CPUI_BRANCHIND: { - return Exit{InstrExit{}}; + return Exit{build_direct_target_exit(curr_op.vars[0], index)}; } default: { - return Exit{InstrExit{}}; + return std::nullopt; } } } +BlockExit PcodeCFGBuilder::GetBlockExitsForIndex(size_t index) const { + auto res = this->GetControlFlowExitsForIndex(index); + if (res) { + return *res; + } + + return Exit{InstrExit{}}; +} + PcodeBlock::PcodeBlock(size_t base_index) : base_index(base_index), diff --git a/scripts/build.sh b/scripts/build.sh index 3d541ebc7..1ffc2b77a 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -250,7 +250,20 @@ function Build ( set -x - cmake --build . -- -j"${NPROC}" + cmake --build . -- -j"${NPROC}" -v + ) || return $? + + return $? +} + +#Install only +function Install +{ + ( + set -x + cmake --build . \ + --target install + ) || return $? return $? @@ -323,6 +336,7 @@ function Help echo " --build-dir Change the default (${BUILD_DIR}) build directory." echo " --debug Build with Debug symbols." echo " --extra-cmake-args Extra CMake arguments to build with." + echo " --install Just install Remill, do not package it." echo " --dyinst-frontend Build McSema with dyninst frontend as well." echo " -h --help Print help." } @@ -388,6 +402,12 @@ function main echo "[+] Enabling a debug build of remill" ;; + # Only install, do not pakage + --install) + INSTALL_ONLY="yes" + echo "[+] Install only. No packaging will be done." + ;; + --extra-cmake-args) BUILD_FLAGS="${BUILD_FLAGS} ${2}" echo "[+] Will supply additional arguments to cmake: ${BUILD_FLAGS}" @@ -423,11 +443,22 @@ function main mkdir -p "${BUILD_DIR}" cd "${BUILD_DIR}" || exit 1 - if ! (DownloadLibraries && Configure && Build && Package ); then + if ! (DownloadLibraries && Configure && Build ); then echo "[x] Build aborted." exit 1 fi + if [[ "${INSTALL_ONLY}" = "yes" ]] + then + if ! Install; then + echo "[x] Installation Failed" + fi + else + if ! Package; then + echo "[x] Packaging Failed" + fi + fi + return $? }