diff --git a/src/binary_translation/CMakeLists.txt b/src/binary_translation/CMakeLists.txt index 394d4321d..1a548ab53 100644 --- a/src/binary_translation/CMakeLists.txt +++ b/src/binary_translation/CMakeLists.txt @@ -14,6 +14,7 @@ set(SRCS Instructions/Branch.cpp Instructions/Arithmetic.cpp Instructions/Ldr.cpp + Instructions/Str.cpp ) set(HEADERS CodeGen.h @@ -32,6 +33,7 @@ set(HEADERS Instructions/Branch.h Instructions/Arithmetic.h Instructions/Ldr.h + Instructions/Str.h ) create_directory_groups(${SRCS} ${HEADERS}) diff --git a/src/binary_translation/Instructions/Ldr.cpp b/src/binary_translation/Instructions/Ldr.cpp index 79f188e15..8fda9c1a5 100644 --- a/src/binary_translation/Instructions/Ldr.cpp +++ b/src/binary_translation/Instructions/Ldr.cpp @@ -70,8 +70,8 @@ void Ldr::GenerateInstructionCode(InstructionBlock* instruction_block) } else { - auto index = (bool)P; - auto wback = !P || W; + auto index = P == 1; + auto wback = P == 0 || W == 1; auto source_register = instruction_block->Read(rn); auto imm32 = ir_builder->getInt32(add ? imm12 : -imm12); diff --git a/src/binary_translation/Instructions/Str.cpp b/src/binary_translation/Instructions/Str.cpp new file mode 100644 index 000000000..f771b52db --- /dev/null +++ b/src/binary_translation/Instructions/Str.cpp @@ -0,0 +1,70 @@ +#include "Str.h" +#include "Disassembler.h" +#include "InstructionBlock.h" +#include +#include +#include +#include "MachineState.h" + +static RegisterInstruction register_instruction; + +bool Str::Decode() +{ + if (ReadFields({ CondDef(), FieldDef<3>(2), FieldDef<1>(&P), FieldDef<1>(&U), FieldDef<1>(0), FieldDef<1>(&W), FieldDef<1>(0), FieldDef<4>(&rn), + FieldDef<4>(&rt), FieldDef<12>(&imm12) })) + { + form = Form::Immediate; + + if (!P && W) return false; // SEE LDRT; + if ((!P || W) && (rn == rt || rn == Register::PC)) return false; // UNPREDICTABLE; + if (rn == Register::PC) return false; // Currently unimplemented + + return true; + } + if (ReadFields({ CondDef(), FieldDef<6>(0x24), FieldDef<1>(&W), FieldDef<1>(0), FieldDef<4>(&rn), + FieldDef<16>(®ister_list) })) + { + form = Form::MultiReg; + + if (rn == Register::PC || register_list.size() < 1) return false; // UNPREDICTABLE; + if (register_list[(int)Register::PC]) return false; // Currently unimplemented + + return true; + } + return false; +} + +void Str::GenerateInstructionCode(InstructionBlock* instruction_block) +{ + auto ir_builder = instruction_block->IrBuilder(); + + if (form == Form::Immediate) + { + auto add = U == 1; + auto index = P == 1; + auto wback = P == 0 || W == 1; + auto source_register = instruction_block->Read(rn); + auto imm32 = ir_builder->getInt32(add ? imm12 : -imm12); + + auto offset_address = ir_builder->CreateAdd(source_register, imm32); + auto address = index ? offset_address : source_register; + if (wback) + instruction_block->Write(rn, offset_address); + instruction_block->Module()->Machine()->WriteMemory32(address, instruction_block->Read(rt)); + } + else + { + auto wback = W == 1; + auto write_back_address = ir_builder->CreateSub(instruction_block->Read(rn), ir_builder->getInt32(4 * register_list.count())); + auto address = write_back_address; + for (auto i = 0; i < 16; ++i) + { + if (!register_list[i]) continue; + instruction_block->Module()->Machine()->WriteMemory32(address, instruction_block->Read((Register)i)); + address = ir_builder->CreateAdd(address, ir_builder->getInt32(4)); + } + + if (wback) + instruction_block->Write(rn, write_back_address); + } +} \ No newline at end of file diff --git a/src/binary_translation/Instructions/Str.h b/src/binary_translation/Instructions/Str.h new file mode 100644 index 000000000..4b0a36024 --- /dev/null +++ b/src/binary_translation/Instructions/Str.h @@ -0,0 +1,26 @@ +#include "Instruction.h" +#include "Types.h" +#include + +class Str : public Instruction +{ +public: + enum class Form + { + Immediate, Reg, MultiReg + }; + +public: + virtual bool Decode() override; + void GenerateInstructionCode(InstructionBlock* instruction_block) override; + +private: + Form form; + bool U; + Register rt; + u32 imm12; + bool P; + bool W; + Register rn; + std::bitset<16> register_list; +}; \ No newline at end of file diff --git a/src/binary_translation/MachineState.cpp b/src/binary_translation/MachineState.cpp index dc9314dc7..41c62fafb 100644 --- a/src/binary_translation/MachineState.cpp +++ b/src/binary_translation/MachineState.cpp @@ -15,6 +15,8 @@ MachineState::MachineState(ModuleGen *module) : module(module) void MachineState::GenerateGlobals() { + auto ir_builder = module->IrBuilder(); + auto registers_global_initializer = ConstantPointerNull::get(IntegerType::getInt32PtrTy(getGlobalContext())); registers_global = new GlobalVariable(*module->Module(), registers_global_initializer->getType(), false, GlobalValue::ExternalLinkage, registers_global_initializer, "Registers"); @@ -24,11 +26,18 @@ void MachineState::GenerateGlobals() flags_global = new GlobalVariable(*module->Module(), flags_global_initializer->getType(), false, GlobalValue::ExternalLinkage, flags_global_initializer, "Flags"); - auto memory_read_32_signature = FunctionType::get(IntegerType::getInt32Ty(getGlobalContext()), IntegerType::getInt32Ty(getGlobalContext()), false); + auto memory_read_32_signature = FunctionType::get(ir_builder->getInt32Ty(), ir_builder->getInt32Ty(), false); auto memory_read_32_ptr = PointerType::get(memory_read_32_signature, 0); auto memory_read_32_initializer = ConstantPointerNull::get(memory_read_32_ptr); memory_read_32_global = new GlobalVariable(*module->Module(), memory_read_32_ptr, false, GlobalValue::ExternalLinkage, memory_read_32_initializer, "Memory::Read32"); + + llvm::Type *memory_write_32_args[] = { ir_builder->getInt32Ty(), ir_builder->getInt32Ty() }; + auto memory_write_32_signature = FunctionType::get(ir_builder->getVoidTy(), memory_write_32_args, false); + auto memory_write_32_ptr = PointerType::get(memory_write_32_signature, 0); + auto memory_write_32_initializer = ConstantPointerNull::get(memory_write_32_ptr); + memory_write_32_global = new GlobalVariable(*module->Module(), memory_write_32_ptr, + false, GlobalValue::ExternalLinkage, memory_write_32_initializer, "Memory::Write32"); } Value *MachineState::GetRegisterPtr(Register reg) @@ -50,8 +59,9 @@ Value *MachineState::GetRegisterPtr(Register reg) return module->IrBuilder()->CreateConstInBoundsGEP1_32(base, index); } -Value* MachineState::ReadRegiser(Register reg) +Value* MachineState::ReadRegiser(Register reg, bool allow_pc) { + assert(allow_pc || reg != Register::PC); auto load = module->IrBuilder()->CreateAlignedLoad(GetRegisterPtr(reg), 4); module->GetTBAA()->TagRegister(load, reg); return load; @@ -106,4 +116,16 @@ llvm::Value* MachineState::ReadMemory32(llvm::Value* address) call->setOnlyReadsMemory(); module->GetTBAA()->TagMemory(call); return call; +} + +llvm::Value* MachineState::WriteMemory32(llvm::Value* address, llvm::Value* value) +{ + auto ir_builder = module->IrBuilder(); + + auto memory_write_32 = ir_builder->CreateLoad(memory_write_32_global); + module->GetTBAA()->TagConst(memory_write_32); + + auto call = ir_builder->CreateCall2(memory_write_32, address, value); + module->GetTBAA()->TagMemory(call); + return value; } \ No newline at end of file diff --git a/src/binary_translation/MachineState.h b/src/binary_translation/MachineState.h index 603626ecf..78485908a 100644 --- a/src/binary_translation/MachineState.h +++ b/src/binary_translation/MachineState.h @@ -20,10 +20,12 @@ public: MachineState(ModuleGen *module); void GenerateGlobals(); - llvm::Value *ReadRegiser(Register reg); + // allow_pc exists because most of the times reading the PC is not what the instruction meant + llvm::Value *ReadRegiser(Register reg, bool allow_pc = false); llvm::Value *WriteRegiser(Register reg, llvm::Value *value); llvm::Value* ConditionPassed(Condition cond); llvm::Value* ReadMemory32(llvm::Value* address); + llvm::Value* WriteMemory32(llvm::Value* address, llvm::Value* value); private: // Returns the address of a register or a flag llvm::Value *GetRegisterPtr(Register reg); @@ -43,8 +45,14 @@ private: llvm::GlobalVariable *flags_global; /* - * u32 (u32) Memory::Read + * u32 (u32) Memory::Read32 * Reads the memory at address */ llvm::GlobalVariable *memory_read_32_global; + + /* + * void (u32, u32) Memory::Write32 + * Writes the memory at address + */ + llvm::GlobalVariable *memory_write_32_global; }; \ No newline at end of file diff --git a/src/binary_translation/ModuleGen.cpp b/src/binary_translation/ModuleGen.cpp index 1b5eca0d0..8fe0aeec5 100644 --- a/src/binary_translation/ModuleGen.cpp +++ b/src/binary_translation/ModuleGen.cpp @@ -204,7 +204,7 @@ void ModuleGen::GenerateCanRunFunction() auto basic_block = BasicBlock::Create(getGlobalContext(), "Entry", can_run_function); ir_builder->SetInsertPoint(basic_block); - auto block_address = ir_builder->CreateCall(get_block_address_function, machine->ReadRegiser(Register::PC)); + auto block_address = ir_builder->CreateCall(get_block_address_function, machine->ReadRegiser(Register::PC, true)); auto function = ir_builder->CreateExtractValue(block_address, 0); ir_builder->CreateRet(ir_builder->CreateICmpNE(function, ConstantPointerNull::get(cast(function->getType())))); @@ -232,7 +232,7 @@ void ModuleGen::GenerateRunFunction() auto block_not_present_basic_block = BasicBlock::Create(getGlobalContext(), "BlockNotPresent", run_function); ir_builder->SetInsertPoint(run_function_entry); - auto block_address = ir_builder->CreateCall(get_block_address_function, Machine()->ReadRegiser(Register::PC)); + auto block_address = ir_builder->CreateCall(get_block_address_function, Machine()->ReadRegiser(Register::PC, true)); auto function = ir_builder->CreateExtractValue(block_address, 0); auto block_present_pred = ir_builder->CreateICmpNE(function, ConstantPointerNull::get(cast(function->getType()))); diff --git a/src/core/binary_translation/BinaryTranslationLoader.cpp b/src/core/binary_translation/BinaryTranslationLoader.cpp index 217005094..b662050fd 100644 --- a/src/core/binary_translation/BinaryTranslationLoader.cpp +++ b/src/core/binary_translation/BinaryTranslationLoader.cpp @@ -122,8 +122,9 @@ void BinaryTranslationLoader::Load(FileUtil::IOFile& file) auto verify_ptr = static_cast(g_dyld->getSymbolAddress("Verify")); g_instruction_count = static_cast(g_dyld->getSymbolAddress("InstructionCount")); auto memory_read_32_ptr = static_cast(g_dyld->getSymbolAddress("Memory::Read32")); + auto memory_write_32_ptr = static_cast(g_dyld->getSymbolAddress("Memory::Write32")); - if (!g_run_function || !g_can_run_function || !verify_ptr || !g_instruction_count || !memory_read_32_ptr) + if (!g_run_function || !g_can_run_function || !verify_ptr || !g_instruction_count || !memory_read_32_ptr || !memory_write_32_ptr) { LOG_WARNING(Loader, "Cannot load optimized file, missing critical function"); return; @@ -131,6 +132,7 @@ void BinaryTranslationLoader::Load(FileUtil::IOFile& file) g_verify = *verify_ptr; *memory_read_32_ptr = &Memory::Read32; + *memory_write_32_ptr = &Memory::Write32; g_enabled = true;