Files
lifting-bits-remill/lib/Arch/AArch32/Semantics/MEM.cpp
T
Sonya 6322f794d1 New arch support (#461)
* This branch contains support for new architectures.

* Initial start to support for AArch 32

* Progress

* Forgot the new files

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

* Updated

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

* UMULL, UMULLS, UMLAL, UMLALS

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

* Correct ops in Binary.cpp

* UMAAL

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

* Updated decoding instructions based on top level encodings

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

* Added appropriate inst.category flags to Multiply and accumulate

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

* Was missing UMAAL DEF_ISEL in Binary.cpp

* AddAddrRegOp

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

* Made DecodeA32ExpandImm much much smaller

* Replaced some imm ops with AddImmOp calls

* Created AddShiftOp

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

* Created EvalPCDest added PC evaluation to Logical Arithmetic Instructions

* AddShiftOp -> AddShiftOp, AddShiftThenExtractOp, AddExtractThenShiftOp

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

* Added comment to EvalPCDest for clarity

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

* Shortened kLogArithEvaluators and fixed a bug

* Updates from testing instructions

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

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

* Logical Arithmetic (two register and immediate)

* Integer Test and Compare (one register and immediate)

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

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

* Code status before refactoring operand types

* This branch contains support for new architectures.

* Initial start to support for AArch 32

* Progress

* Forgot the new files

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

* Updated

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

* UMULL, UMULLS, UMLAL, UMLALS

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

* Correct ops in Binary.cpp

* UMAAL

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

* Updated decoding instructions based on top level encodings

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

* Added appropriate inst.category flags to Multiply and accumulate

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

* Was missing UMAAL DEF_ISEL in Binary.cpp

* AddAddrRegOp

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

* Made DecodeA32ExpandImm much much smaller

* Replaced some imm ops with AddImmOp calls

* Created AddShiftOp

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

* Created EvalPCDest added PC evaluation to Logical Arithmetic Instructions

* AddShiftOp -> AddShiftOp, AddShiftThenExtractOp, AddExtractThenShiftOp

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

* Added comment to EvalPCDest for clarity

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

* Shortened kLogArithEvaluators and fixed a bug

* Updates from testing instructions

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

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

* Logical Arithmetic (two register and immediate)

* Integer Test and Compare (one register and immediate)

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

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

* Code status before refactoring operand types

* Finished updates off master

* Start of operand refactor

* Finished Expression Operand Support

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

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

* Updated ROR in AddShiftRegRegOperand

* Created ExtractAndZExtExpr

* Fixed comment formatting in if else statements

* Created RORExpr

* Small fixes

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

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

* conditional support + Start of Branch instructions

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

* Updates from testing register shifted by register value inst

* Fix to ROR in AddShiftRegCarryOperand

* Corrected negation in DecodeCondition

* DecodeCondition edit

* DecodeCondition and AddShiftRegCarryOperand edits

* Updated arch_for_decode to arch

* Halfword Multiply and Accumulate

* Edits from testing Halfword Multiply and Accumulate

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

* Branch (Imm) & BX/BXL

* Update aarch32 cmake

* cmake update

* CLZ

* Forgot BITBYTE.cpp

* MOVT

* Integer Saturating Arithmetic

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

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

* Load/Store Word, Unsigned Byte (register)

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

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

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

* Finished testing all the Load/store additions

* Signed multiply, Divide

* Cleaned up SExt some

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

* Condensed args in STMDB and LDM semantics

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

* Bitfield Extract

* Extend and Add

* fix

* NOP

* Small fix

* Simplified the bit reps in TryMoveSpecialRegisterAndHintsI

* Moved Bitfield extract semantics out of BINARY and into BITBYTE

* Finished correcting S/ZExt and Trunc use

* Ran scripts/format-files to format

* Smoke Test

* Add false delay slot to kCategoryConditionalDirectFunctionCall

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

* CI: Add tag handler (#492)

* Delay slot fixes to TraceLifter

Co-authored-by: Peter Goodman <peter.goodman@gmail.com>
Co-authored-by: Alessandro Gario <5714290+alessandrogario@users.noreply.github.com>
2021-02-24 14:01:09 -05:00

433 lines
12 KiB
C++

/*
* Copyright (c) 2020 Trail of Bits, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace {
// Offset
DEF_COND_SEM(STR, M32W dst, R32 src1) {
auto src = Read(src1);
Write(dst, src);
return memory;
}
DEF_COND_SEM(STRB, M8W dst, R32 src1) {
auto src = Read(src1);
Write(dst, TruncTo<uint8_t>(src));
return memory;
}
// Pre + Post
DEF_COND_SEM(STRp, M32W dst, R32 src1, R32W dst_reg, R32 src2) {
auto src = Read(src1);
auto new_val = Read(src2);
Write(dst, src);
Write(dst_reg, new_val);
return memory;
}
// Pre + Post
DEF_COND_SEM(STRBp, M8W dst, R32 src1, R32W dst_reg, R32 src2) {
auto src = Read(src1);
auto new_val = Read(src2);
Write(dst, TruncTo<uint8_t>(src));
Write(dst_reg, new_val);
return memory;
}
// Offset
DEF_COND_SEM(LDR, M32 src1, R32W dst) {
auto src = Read(src1);
WriteZExt(dst, src);
return memory;
}
// Offset
DEF_COND_SEM(LDRB, M8 src1, R32W dst) {
auto src = Read(src1);
WriteZExt(dst, src);
return memory;
}
// Pre + Post
DEF_COND_SEM(LDRp, M32 src1, R32W dst, R32W dst_reg, R32 src2) {
auto src = Read(src1);
auto new_val = Read(src2);
WriteZExt(dst, src);
Write(dst_reg, new_val);
return memory;
}
// Pre + Post
DEF_COND_SEM(LDRBp, M8 src1, R32W dst, R32W dst_reg, R32 src2) {
auto src = Read(src1);
auto new_val = Read(src2);
WriteZExt(dst, src);
Write(dst_reg, new_val);
return memory;
}
DEF_COND_SEM(STRT, M32W dst, R32 src1, R32W dst_reg, R32 src2) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
Write(dst, TruncTo<uint32_t>(src));
Write(dst_reg, new_val);
return memory;
}
DEF_COND_SEM(STRTB, M8W dst, R32 src1, R32W dst_reg, R32 src2) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
Write(dst, TruncTo<uint8_t>(src));
Write(dst_reg, new_val);
return memory;
}
DEF_COND_SEM(LDRT, M32 src1, R32W dst, R32W dst_reg, R32 src2) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
WriteZExt(dst, src);
Write(dst_reg, new_val);
return memory;
}
DEF_COND_SEM(LDRTB, M8 src1, R32W dst, R32W dst_reg, R32 src2) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
WriteZExt(dst, src);
Write(dst_reg, new_val);
return memory;
}
} // namespace
DEF_ISEL(STR) = STR;
DEF_ISEL(STRB) = STRB;
DEF_ISEL(STRp) = STRp;
DEF_ISEL(STRBp) = STRBp;
DEF_ISEL(LDR) = LDR;
DEF_ISEL(LDRB) = LDRB;
DEF_ISEL(LDRp) = LDRp;
DEF_ISEL(LDRBp) = LDRBp;
DEF_ISEL(STRT) = STRT;
DEF_ISEL(STRBT) = STRTB;
DEF_ISEL(LDRT) = LDRT;
DEF_ISEL(LDRBT) = LDRTB;
namespace {
// Offset
DEF_COND_SEM(STRH, M16W dst, R32 src1) {
auto src = Read(src1);
Write(dst, TruncTo<uint16_t>(src));
return memory;
}
// Pre + Post
DEF_COND_SEM(STRHp, M16W dst, R32 src1, R32W dst_reg, R32 src2) {
auto src = Read(src1);
auto new_val = Read(src2);
Write(dst, TruncTo<uint16_t>(src));
Write(dst_reg, new_val);
return memory;
}
// Offset
DEF_COND_SEM(LDRH, M16 src1, R32W dst) {
auto src = Read(src1);
WriteZExt(dst, src);
return memory;
}
// Pre + Post
DEF_COND_SEM(LDRHp, M16 src1, R32W dst, R32W dst_reg, R32 src2) {
auto src = Read(src1);
auto new_val = Read(src2);
WriteZExt(dst, src);
Write(dst_reg, new_val);
return memory;
}
// Offset
DEF_COND_SEM(STRD, M64W dst, R32 src1, R32 src2) {
auto lhs = UShl(ZExt<uint64_t>(Read(src2)), 32ul);
auto rhs = ZExt<uint64_t>(Read(src1));
auto src = UOr(lhs, rhs);
WriteTrunc(dst, src);
return memory;
}
// Pre + Post
DEF_COND_SEM(STRDp, M64W dst, R32 src1, R32 src2, R32W dst_reg, R32 src_new) {
auto lhs = UShl(ZExt<uint64_t>(Read(src2)), 32ul);
auto rhs = ZExt<uint64_t>(Read(src1));
auto src = UOr(lhs, rhs);
auto new_val = Read(src_new);
WriteTrunc(dst, src);
Write(dst_reg, new_val);
return memory;
}
// Offset
DEF_COND_SEM(LDRD, M64 src1, R32W dst1, R32W dst2) {
auto src = Read(src1);
Write(dst1, TruncTo<uint32_t>(src));
Write(dst2, TruncTo<uint32_t>(UShr(src, 32ul)));
return memory;
}
// Pre + Post
DEF_COND_SEM(LDRDp, M64 src1, R32W dst1, R32W dst2, R32W dst_reg, R32 src2) {
auto src = Read(src1);
auto new_val = Read(src2);
Write(dst1, TruncTo<uint32_t>(src));
Write(dst2, TruncTo<uint32_t>(UShr(src, 32ul)));
Write(dst_reg, new_val);
return memory;
}
// Offset
DEF_COND_SEM(LDRSB, M8 src1, R32W dst) {
auto src = Read(src1);
WriteSExt(dst, src);
return memory;
}
// Pre + Post
DEF_COND_SEM(LDRSBp, M8 src1, R32W dst, R32W dst_reg, R32 src2) {
auto src = Read(src1);
auto new_val = Read(src2);
WriteSExt(dst, src);
Write(dst_reg, new_val);
return memory;
}
// Offset
DEF_COND_SEM(LDRSH, M16 src1, R32W dst) {
auto src = Read(src1);
WriteSExt(dst, src);
return memory;
}
// Pre + Post
DEF_COND_SEM(LDRSHp, M16 src1, R32W dst, R32W dst_reg, R32 src2) {
auto src = Read(src1);
auto new_val = Read(src2);
WriteSExt(dst, src);
Write(dst_reg, new_val);
return memory;
}
DEF_COND_SEM(STRHT, M16W dst, R32 src1, R32W dst_reg, R32 src2) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
WriteTrunc(dst, src);
Write(dst_reg, new_val);
return memory;
}
DEF_COND_SEM(LDRHT, M16 src1, R32W dst, R32W dst_reg, R32 src2) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
WriteZExt(dst, src);
Write(dst_reg, new_val);
return memory;
}
DEF_COND_SEM(LDRSBT, M8 src1, R32W dst, R32W dst_reg, R32 src2) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
WriteSExt(dst, src);
Write(dst_reg, new_val);
return memory;
}
DEF_COND_SEM(LDRSHT, M16 src1, R32W dst, R32W dst_reg, R32 src2) {
memory = __remill_sync_hyper_call(state, memory,
SyncHyperCall::kAArch32CheckNotEL2);
auto src = Read(src1);
auto new_val = Read(src2);
WriteSExt(dst, src);
Write(dst_reg, new_val);
return memory;
}
} // namespace
DEF_ISEL(STRH) = STRH;
DEF_ISEL(STRHp) = STRHp;
DEF_ISEL(LDRH) = LDRH;
DEF_ISEL(LDRHp) = LDRHp;
DEF_ISEL(STRD) = STRD;
DEF_ISEL(STRDp) = STRDp;
DEF_ISEL(LDRD) = LDRD;
DEF_ISEL(LDRDp) = LDRDp;
DEF_ISEL(LDRSB) = LDRSB;
DEF_ISEL(LDRSBp) = LDRSBp;
DEF_ISEL(LDRSH) = LDRSH;
DEF_ISEL(LDRSHp) = LDRSHp;
DEF_ISEL(STRHT) = STRHT;
DEF_ISEL(LDRHT) = LDRHT;
DEF_ISEL(LDRSBT) = LDRSBT;
DEF_ISEL(LDRSHT) = LDRSHT;
// Load/Store Multiple
namespace {
DEF_COND_SEM(LDM, I16 reg_list, R32W dst, R32 dst_new, M32 src_mem, R32W dst0,
R32W dst1, R32W dst2, R32W dst3, R32W dst4, R32W dst5, R32W dst6,
R32W dst7, R32W dst8, R32W dst9, R32W dst10, R32W dst11,
R32W dst12, R32W dst13, R32W dst14, R32W dst15) {
auto regs = Read(reg_list);
uint32_t index = 0;
if (UAnd(regs, uint16_t(0b1u))) {
Write(dst0, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 1))) {
Write(dst1, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 2))) {
Write(dst2, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 3))) {
Write(dst3, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 4))) {
Write(dst4, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 5))) {
Write(dst5, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 6))) {
Write(dst6, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 7))) {
Write(dst7, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 8))) {
Write(dst8, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 9))) {
Write(dst9, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 10))) {
Write(dst10, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 11))) {
Write(dst11, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 12))) {
Write(dst12, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 13))) {
Write(dst13, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 14))) {
Write(dst14, Read(GetElementPtr(src_mem, index++)));
}
if (UAnd(regs, uint16_t(0b1u << 15))) {
Write(dst15, Read(GetElementPtr(src_mem, index++)));
}
Write(dst, Read(dst_new));
return memory;
}
DEF_COND_SEM(STMDB, I16 reg_list, R32W dst, R32 dst_new, M32W dst_mem, R32 src0,
R32 src1, R32 src2, R32 src3, R32 src4, R32 src5, R32 src6,
R32 src7, R32 src8, R32 src9, R32 src10, R32 src11, R32 src12,
R32 src13, R32 src14, R32 src15) {
auto regs = Read(reg_list);
uint32_t index = 0;
if (UAnd(regs, uint16_t(0b1u))) {
Write(GetElementPtr(dst_mem, index++), Read(src0));
}
if (UAnd(regs, uint16_t(0b1u << 1))) {
Write(GetElementPtr(dst_mem, index++), Read(src1));
}
if (UAnd(regs, uint16_t(0b1u << 2))) {
Write(GetElementPtr(dst_mem, index++), Read(src2));
}
if (UAnd(regs, uint16_t(0b1u << 3))) {
Write(GetElementPtr(dst_mem, index++), Read(src3));
}
if (UAnd(regs, uint16_t(0b1u << 4))) {
Write(GetElementPtr(dst_mem, index++), Read(src4));
}
if (UAnd(regs, uint16_t(0b1u << 5))) {
Write(GetElementPtr(dst_mem, index++), Read(src5));
}
if (UAnd(regs, uint16_t(0b1u << 6))) {
Write(GetElementPtr(dst_mem, index++), Read(src6));
}
if (UAnd(regs, uint16_t(0b1u << 7))) {
Write(GetElementPtr(dst_mem, index++), Read(src7));
}
if (UAnd(regs, uint16_t(0b1u << 8))) {
Write(GetElementPtr(dst_mem, index++), Read(src8));
}
if (UAnd(regs, uint16_t(0b1u << 9))) {
Write(GetElementPtr(dst_mem, index++), Read(src9));
}
if (UAnd(regs, uint16_t(0b1u << 10))) {
Write(GetElementPtr(dst_mem, index++), Read(src10));
}
if (UAnd(regs, uint16_t(0b1u << 11))) {
Write(GetElementPtr(dst_mem, index++), Read(src11));
}
if (UAnd(regs, uint16_t(0b1u << 12))) {
Write(GetElementPtr(dst_mem, index++), Read(src12));
}
if (UAnd(regs, uint16_t(0b1u << 13))) {
Write(GetElementPtr(dst_mem, index++), Read(src13));
}
if (UAnd(regs, uint16_t(0b1u << 14))) {
Write(GetElementPtr(dst_mem, index++), Read(src14));
}
if (UAnd(regs, uint16_t(0b1u << 15))) {
Write(GetElementPtr(dst_mem, index++), Read(src15));
}
Write(dst, Read(dst_new));
return memory;
}
} // namespace
DEF_ISEL(STMDA) = STMDB;
DEF_ISEL(LDMDA) = LDM;
DEF_ISEL(STM) = STMDB;
DEF_ISEL(LDM) = LDM;
//DEF_ISEL(STMu) = STMu;
DEF_ISEL(STMDB) = STMDB;
DEF_ISEL(LDMDB) = LDM;
//DEF_ISEL(LDMu) = LDMu;
DEF_ISEL(STMIB) = STMDB;
DEF_ISEL(LDMIB) = LDM;
//DEF_ISEL(LDMe) = LDMe;