diff options
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/DevTools/UserspaceEmulator/SoftCPU.h | 9 | ||||
-rw-r--r-- | Userland/Libraries/LibX86/Disassembler.h | 6 | ||||
-rw-r--r-- | Userland/Libraries/LibX86/Instruction.cpp | 71 | ||||
-rw-r--r-- | Userland/Libraries/LibX86/Instruction.h | 23 |
4 files changed, 98 insertions, 11 deletions
diff --git a/Userland/DevTools/UserspaceEmulator/SoftCPU.h b/Userland/DevTools/UserspaceEmulator/SoftCPU.h index 16982e6337..2206aae73d 100644 --- a/Userland/DevTools/UserspaceEmulator/SoftCPU.h +++ b/Userland/DevTools/UserspaceEmulator/SoftCPU.h @@ -106,8 +106,9 @@ public: return m_gpr[X86::RegisterEDX].reference_to<&PartAddressableRegister::low_u8>(); case X86::RegisterDH: return m_gpr[X86::RegisterEDX].reference_to<&PartAddressableRegister::high_u8>(); + default: + VERIFY_NOT_REACHED(); } - VERIFY_NOT_REACHED(); } ValueWithShadow<u8> const_gpr8(X86::RegisterIndex8 reg) const @@ -129,8 +130,9 @@ public: return m_gpr[X86::RegisterEDX].slice<&PartAddressableRegister::low_u8>(); case X86::RegisterDH: return m_gpr[X86::RegisterEDX].slice<&PartAddressableRegister::high_u8>(); + default: + VERIFY_NOT_REACHED(); } - VERIFY_NOT_REACHED(); } ValueWithShadow<u16> const_gpr16(X86::RegisterIndex16 reg) const @@ -211,8 +213,9 @@ public: case X86::AddressSize::Size16: set_cx(ValueWithShadow<u16>(cx().value() - 1, cx().shadow())); return cx().value() == 0; + default: + VERIFY_NOT_REACHED(); } - VERIFY_NOT_REACHED(); } ALWAYS_INLINE void step_source_index(X86::AddressSize address_size, u32 step) diff --git a/Userland/Libraries/LibX86/Disassembler.h b/Userland/Libraries/LibX86/Disassembler.h index 01cf39a075..1abd5d0ae3 100644 --- a/Userland/Libraries/LibX86/Disassembler.h +++ b/Userland/Libraries/LibX86/Disassembler.h @@ -25,8 +25,12 @@ public: #if ARCH(I386) return Instruction::from_stream(m_stream, OperandSize::Size32, AddressSize::Size32); #else - dbgln("FIXME: Implement disassembly support for x86_64"); +# if ARCH(X86_64) + return Instruction::from_stream(m_stream, OperandSize::Size64, AddressSize::Size64); +# else + dbgln("Unsupported platform"); return {}; +# endif #endif } diff --git a/Userland/Libraries/LibX86/Instruction.cpp b/Userland/Libraries/LibX86/Instruction.cpp index f01468b89f..73cbe8e928 100644 --- a/Userland/Libraries/LibX86/Instruction.cpp +++ b/Userland/Libraries/LibX86/Instruction.cpp @@ -14,8 +14,8 @@ namespace X86 { -InstructionDescriptor s_table[2][256]; -InstructionDescriptor s_0f_table[2][256]; +InstructionDescriptor s_table[3][256]; +InstructionDescriptor s_0f_table[3][256]; InstructionDescriptor s_sse_table_np[256]; InstructionDescriptor s_sse_table_66[256]; InstructionDescriptor s_sse_table_f3[256]; @@ -1307,6 +1307,8 @@ String MemoryOrRegisterReference::to_string_xmm(Instruction const& insn) const String MemoryOrRegisterReference::to_string(Instruction const& insn) const { switch (insn.address_size()) { + case AddressSize::Size64: + return to_string_a64(); case AddressSize::Size32: return to_string_a32(); case AddressSize::Size16: @@ -1455,6 +1457,65 @@ static String sib_to_string(u8 rm, u8 sib) return builder.to_string(); } +String MemoryOrRegisterReference::to_string_a64() const +{ + if (is_register()) + return register_name(static_cast<RegisterIndex32>(m_register_index)); + + bool has_displacement = false; + switch (mod()) { + case 0b00: + has_displacement = rm() == 5; + break; + case 0b01: + case 0b10: + has_displacement = true; + } + if (m_has_sib && (m_sib & 7) == 5) + has_displacement = true; + + String base; + switch (rm()) { + case 0: + base = "rax"; + break; + case 1: + base = "rcx"; + break; + case 2: + base = "rdx"; + break; + case 3: + base = "rbx"; + break; + case 6: + base = "rsi"; + break; + case 7: + base = "rdi"; + break; + case 5: + if (mod() == 0) + base = String::formatted("{:#08x}", m_displacement32); + else + base = "rbp"; + break; + case 4: + base = sib_to_string(m_rm_byte, m_sib); + break; + } + + if (!has_displacement) + return base; + + String displacement_string; + if ((i32)m_displacement32 < 0) + displacement_string = String::formatted("-{:#x}", -(i32)m_displacement32); + else + displacement_string = String::formatted("+{:#x}", m_displacement32); + return String::formatted("{}{}", base, displacement_string); +} + String MemoryOrRegisterReference::to_string_a32() const { if (is_register()) @@ -1541,6 +1602,9 @@ String Instruction::to_string(u32 origin, SymbolProvider const* symbol_provider, case AddressSize::Size32: builder.append("a32"sv); break; + case AddressSize::Size64: + builder.append("a64"sv); + break; } } if (has_operand_size_override_prefix()) { @@ -1551,6 +1615,9 @@ String Instruction::to_string(u32 origin, SymbolProvider const* symbol_provider, case OperandSize::Size32: builder.append("o32"sv); break; + case OperandSize::Size64: + builder.append("o64"sv); + break; } } if (has_lock_prefix()) diff --git a/Userland/Libraries/LibX86/Instruction.h b/Userland/Libraries/LibX86/Instruction.h index 6c0903c92c..87a958d8ef 100644 --- a/Userland/Libraries/LibX86/Instruction.h +++ b/Userland/Libraries/LibX86/Instruction.h @@ -45,11 +45,13 @@ constexpr T sign_extended_to(U value) enum class OperandSize : u8 { Size16, Size32, + Size64, }; enum class AddressSize : u8 { Size16, Size32, + Size64, }; enum IsLockPrefixAllowed { @@ -228,6 +230,8 @@ struct InstructionDescriptor { { if (imm1_bytes == CurrentAddressSize) { switch (size) { + case AddressSize::Size64: + return 8; case AddressSize::Size32: return 4; case AddressSize::Size16: @@ -242,6 +246,8 @@ struct InstructionDescriptor { { if (imm2_bytes == CurrentAddressSize) { switch (size) { + case AddressSize::Size64: + return 8; case AddressSize::Size32: return 4; case AddressSize::Size16: @@ -255,8 +261,8 @@ struct InstructionDescriptor { IsLockPrefixAllowed lock_prefix_allowed { LockPrefixNotAllowed }; }; -extern InstructionDescriptor s_table[2][256]; -extern InstructionDescriptor s_0f_table[2][256]; +extern InstructionDescriptor s_table[3][256]; +extern InstructionDescriptor s_0f_table[3][256]; extern InstructionDescriptor s_sse_table_np[256]; extern InstructionDescriptor s_sse_table_66[256]; extern InstructionDescriptor s_sse_table_f3[256]; @@ -489,6 +495,7 @@ private: String to_string(Instruction const&) const; String to_string_a16() const; String to_string_a32() const; + String to_string_a64() const; template<typename InstructionStreamType> void decode(InstructionStreamType&, AddressSize); @@ -553,15 +560,20 @@ public: u8 imm8() const { return m_imm1; } u16 imm16() const { return m_imm1; } u32 imm32() const { return m_imm1; } + u64 imm64() const { return m_imm1; } u8 imm8_1() const { return imm8(); } u8 imm8_2() const { return m_imm2; } u16 imm16_1() const { return imm16(); } u16 imm16_2() const { return m_imm2; } u32 imm32_1() const { return imm32(); } u32 imm32_2() const { return m_imm2; } + u64 imm64_1() const { return imm64(); } + u64 imm64_2() const { return m_imm2; } u32 imm_address() const { switch (m_address_size) { + case AddressSize::Size64: + return imm64(); case AddressSize::Size32: return imm32(); case AddressSize::Size16: @@ -603,8 +615,8 @@ private: InstructionDescriptor* m_descriptor { nullptr }; mutable MemoryOrRegisterReference m_modrm; - u32 m_imm1 { 0 }; - u32 m_imm2 { 0 }; + u64 m_imm1 { 0 }; + u64 m_imm2 { 0 }; u8 m_segment_prefix { 0xff }; u8 m_register_index { 0xff }; u8 m_op { 0 }; @@ -1137,8 +1149,9 @@ ALWAYS_INLINE LogicalAddress MemoryOrRegisterReference::resolve(const CPU& cpu, return resolve16(cpu, insn.segment_prefix()); case AddressSize::Size32: return resolve32(cpu, insn.segment_prefix()); + default: + VERIFY_NOT_REACHED(); } - VERIFY_NOT_REACHED(); } } |