1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 04:47:34 +00:00

LibX86: Disassemble most FPU instructions starting with D9

Some of these don't just use the REG bits of the mod/rm byte
as slashes, but also the R/M bits to have up to 9 different
instructions per opcode/slash combination (1 opcode requires
that MOD is != 11, the other 8 have MODE == 11).

This is done by making the slashes table two levels deep for
these cases.

Some of this is cosmetic (e.g "FST st0" has no effect already,
but its bit pattern gets disassembled as "FNOP"), but for
most uses it isn't.

FSTENV and FSTCW have an extraordinary 0x9b prefix. This is
not yet handled in this patch.
This commit is contained in:
Nico Weber 2020-07-28 11:09:54 -04:00 committed by Andreas Kling
parent 6f12ab3ced
commit c99a3efc5b
5 changed files with 209 additions and 13 deletions

View file

@ -66,7 +66,6 @@ enum IsLockPrefixAllowed {
enum InstructionFormat {
InvalidFormat,
MultibyteWithSlash,
MultibyteWithSubopcode,
InstructionPrefix,
__BeginFormatsWithRMByte,
@ -82,6 +81,8 @@ enum InstructionFormat {
OP_RM8,
OP_RM16,
OP_RM32,
OP_FPU,
OP_FPU_reg,
OP_FPU_RM32,
OP_FPU_RM64,
OP_RM8_reg8,
@ -179,6 +180,11 @@ struct InstructionDescriptor {
bool has_rm { false };
unsigned imm1_bytes { 0 };
unsigned imm2_bytes { 0 };
// Addressed by the 3 REG bits in the MOD-REG-R/M byte.
// Some slash instructions have further subgroups when MOD is 11,
// in that case the InstructionDescriptors in slashes have themselves
// a non-null slashes member that's indexed by the three R/M bits.
InstructionDescriptor* slashes { nullptr };
unsigned imm1_bytes_for_address_size(bool a32)
@ -352,6 +358,7 @@ public:
String to_string_o8(const Instruction&) const;
String to_string_o16(const Instruction&) const;
String to_string_o32(const Instruction&) const;
String to_string_fpu_reg() const;
String to_string_fpu32(const Instruction&) const;
String to_string_fpu64(const Instruction&) const;
String to_string_mm(const Instruction&) const;
@ -864,20 +871,21 @@ ALWAYS_INLINE Instruction::Instruction(InstructionStreamType& stream, bool o32,
m_register_index = m_op & 7;
}
bool hasSlash = m_descriptor->format == MultibyteWithSlash;
if (hasSlash) {
bool has_slash = m_descriptor->format == MultibyteWithSlash;
if (has_slash) {
m_descriptor = &m_descriptor->slashes[slash()];
if ((rm() & 0xc0) == 0xc0 && m_descriptor->slashes)
m_descriptor = &m_descriptor->slashes[rm() & 7];
}
if (!m_descriptor->mnemonic) {
if (has_sub_op()) {
if (hasSlash)
if (has_slash)
fprintf(stderr, "Instruction %02X %02X /%u not understood\n", m_op, m_sub_op, slash());
else
fprintf(stderr, "Instruction %02X %02X not understood\n", m_op, m_sub_op);
} else {
if (hasSlash)
if (has_slash)
fprintf(stderr, "Instruction %02X /%u not understood\n", m_op, slash());
else
fprintf(stderr, "Instruction %02X not understood\n", m_op);