From e3a2b4c4183b4eb5b1ade576aeb3c4e7ccc5f20f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 21 Dec 2023 11:05:35 +0100 Subject: [PATCH] Fix broken disassembly of floating point immediates on big endian hosts (#2222) Disassembling single floating points with immediate values currently gives wrong results on big endian hosts (like s390x), e.g.: ./cstool/cstool m68k40 'f2 3c 44 22 40 49 0e 56' 0 f2 3c 44 22 40 49 0e 56 fadd.s #0.000000, fp0 While it should be (like on x86): ./cstool/cstool m68k40 'f2 3c 44 22 40 49 0e 56' 0 f2 3c 44 22 40 49 0e 56 fadd.s #3.141500, fp0 The problem is that these single float values are supposed to be stored in the 32-bit "simm" field of struct cs_m68k_op (see e.g. the printing of M68K_FPU_SIZE_SINGLE in printAddressingMode() in M68KInstPrinter.c), but currently the immediate is only written to the 64-bit "imm" field of the union in cs_m68k_op. This works on little endian systems, since the least significant bytes overlap in the union there. For example, let's assume that the value 0x01020304 gets written to "imm": 04 03 02 01 00 00 00 00 uint64_t imm xx xx xx xx xx xx xx xx double dimm; xx xx xx xx .. .. .. .. float simm; But on big endian hosts, the important bytes do not overlap, so "simm" is always zero there: 00 00 00 00 01 02 03 04 uint64_t imm xx xx xx xx xx xx xx xx double dimm; xx xx xx xx .. .. .. .. float simm; To fix the problem, let's always set "simm" explicitly, this works on both, big endian and little endian hosts. Thanks to Michal Schulz for his initial analysis of the problem (in #1710) and to Travis Finkenauer for providing an easy example to reproduce the issue (in #1931). Closes: https://github.com/capstone-engine/capstone/issues/1710 --- arch/M68K/M68KDisassembler.c | 2 ++ suite/cstest/issues.cs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/arch/M68K/M68KDisassembler.c b/arch/M68K/M68KDisassembler.c index e0a712a51e..a1df81c336 100644 --- a/arch/M68K/M68KDisassembler.c +++ b/arch/M68K/M68KDisassembler.c @@ -41,6 +41,7 @@ #include "../../cs_priv.h" #include "../../utils.h" +#include "../../MathExtras.h" #include "../../MCInst.h" #include "../../MCInstrDesc.h" #include "../../MCRegisterInfo.h" @@ -2077,6 +2078,7 @@ static void d68020_cpgen(m68k_info *info) ext->op_size.type = M68K_SIZE_TYPE_FPU; ext->op_size.fpu_size = M68K_FPU_SIZE_SINGLE; get_ea_mode_op(info, op0, info->ir, 4); + op0->simm = BitsToFloat(op0->imm); op0->type = M68K_OP_FP_SINGLE; break; diff --git a/suite/cstest/issues.cs b/suite/cstest/issues.cs index e19c4e4661..199961a9f8 100644 --- a/suite/cstest/issues.cs +++ b/suite/cstest/issues.cs @@ -247,6 +247,10 @@ 0x33,0xc0 == xor ax, ax 0xba,0x5a,0xff == mov dx, 0xff5a +!# issue 1710 M68K floating point immediates broken on big endian hosts +!# CS_ARCH_M68K, CS_MODE_BIG_ENDIAN | CS_MODE_M68K_040, None +0xf2,0x3c,0x44,0x22,0x40,0x49,0x0e,0x56 == fadd.s #3.141500, fp0 + !# issue 1708 M68K floating point loads and stores generate the same op_str !# CS_ARCH_M68K, CS_MODE_BIG_ENDIAN | CS_MODE_M68K_040, None 0xf2,0x27,0x74,0x00 == fmove.d fp0, -(a7)