264 lines
11 KiB
C
264 lines
11 KiB
C
/*
|
|
* Interactive disassembler (IDA)
|
|
* Copyright (c) 1990-2021 Hex-Rays
|
|
* ALL RIGHTS RESERVED.
|
|
|
|
* Floating Point Number Libary.
|
|
* Copyright (c) 1995-2006 by Iouri Kharon.
|
|
* E-mail: yjh@styx.cabel.net
|
|
*
|
|
*/
|
|
|
|
#include <pro.h>
|
|
#ifndef _IEEE_H_
|
|
#define _IEEE_H_
|
|
|
|
/*! \file ieee.h
|
|
|
|
\brief IEEE floating point functions
|
|
|
|
*/
|
|
|
|
struct fpvalue_t; // processor-independent representation of floats
|
|
|
|
#define FPVAL_NWORDS 6 // number of words in fpvalue_t
|
|
|
|
/// Floating value kinds.
|
|
/// They are useful when checking for NaN/Inf
|
|
enum fpvalue_kind_t
|
|
{
|
|
FPV_BADARG, ///< wrong value of max_exp
|
|
FPV_NORM, ///< regular value
|
|
FPV_NAN, ///< NaN
|
|
FPV_PINF, ///< positive infinity
|
|
FPV_NINF, ///< negative infinity
|
|
};
|
|
|
|
/// \name max_exp values
|
|
/// Common values for max_exp (for IEEE floating point values)
|
|
//@{
|
|
const uint32
|
|
MAXEXP_FLOAT = 0x80,
|
|
MAXEXP_DOUBLE = 0x400,
|
|
MAXEXP_LNGDBL = 0x4000;
|
|
//@}
|
|
|
|
/// \defgroup REAL_ERROR_ Floating point/IEEE Conversion codes
|
|
/// Return values for ieee_realcvt and processor_t::realcvt_t request
|
|
enum fpvalue_error_t
|
|
{
|
|
REAL_ERROR_OK = 0, ///< no error
|
|
REAL_ERROR_FORMAT = -1, ///< realcvt: not supported format for current .idp
|
|
REAL_ERROR_RANGE = -2, ///< realcvt: number too big (small) for store (mem NOT modified)
|
|
REAL_ERROR_BADDATA = -3, ///< realcvt: illegal real data for load (IEEE data not filled)
|
|
REAL_ERROR_FPOVER = 1, ///< floating overflow or underflow
|
|
REAL_ERROR_BADSTR = 2, ///< asctoreal: illegal input string
|
|
REAL_ERROR_ZERODIV = 3, ///< ediv: divide by 0
|
|
REAL_ERROR_INTOVER = 4, ///< eetol*: integer overflow
|
|
};
|
|
|
|
/// Standard IEEE 754 floating point conversion function
|
|
/// \param m pointer to data
|
|
/// \param out internal IEEE format data
|
|
/// \param swt operation:
|
|
/// - 000: load trunc. float (DEC ^F) 2 bytes (m->e)
|
|
/// - 001: load float 4 bytes (m->e)
|
|
/// - 003: load double 8 bytes (m->e)
|
|
/// - 004: load long double 10 bytes (m->e)
|
|
/// - 005: load long double 12 bytes (m->e)
|
|
/// - 010: store trunc. float (DEC ^F) 2 bytes (e->m)
|
|
/// - 011: store float 4 bytes (e->m)
|
|
/// - 013: store double 8 bytes (e->m)
|
|
/// - 014: store long double 10 bytes (e->m)
|
|
/// - 015: store long double 12 bytes (e->m)
|
|
/// bit 0x80 forces little endian even for big endian processors
|
|
/// \return fpvalue_error_t
|
|
|
|
idaman THREAD_SAFE fpvalue_error_t ida_export ieee_realcvt(void *m, fpvalue_t *out, uint16 swt);
|
|
|
|
// Helper functions. Better use members of fpvalue_t, they are nicer.
|
|
idaman THREAD_SAFE void ida_export realtoasc(char *buf, size_t bufsize, const fpvalue_t &x, uint mode);
|
|
idaman THREAD_SAFE fpvalue_error_t ida_export asctoreal(const char **sss, fpvalue_t *out);
|
|
idaman THREAD_SAFE void ida_export eltoe(sval_t l, fpvalue_t *vout);
|
|
idaman THREAD_SAFE void ida_export eltoe64(int64 l, fpvalue_t *vout);
|
|
idaman THREAD_SAFE void ida_export eltoe64u(uint64 l, fpvalue_t *vout);
|
|
idaman THREAD_SAFE fpvalue_error_t ida_export eetol(sval_t *out, const fpvalue_t &a, bool roundflg);
|
|
idaman THREAD_SAFE fpvalue_error_t ida_export eetol64(int64 *out, const fpvalue_t &a, bool roundflg);
|
|
idaman THREAD_SAFE fpvalue_error_t ida_export eetol64u(uint64 *out, const fpvalue_t &a, bool roundflg);
|
|
idaman THREAD_SAFE fpvalue_error_t ida_export eldexp(const fpvalue_t &a, int32 pwr2, fpvalue_t *zout);
|
|
idaman THREAD_SAFE fpvalue_error_t ida_export eadd(const fpvalue_t &a, const fpvalue_t &b, fpvalue_t *zout, bool subflg);
|
|
idaman THREAD_SAFE fpvalue_error_t ida_export emul(const fpvalue_t &a, const fpvalue_t &b, fpvalue_t *zout);
|
|
idaman THREAD_SAFE fpvalue_error_t ida_export ediv(const fpvalue_t &a, const fpvalue_t &b, fpvalue_t *zout);
|
|
idaman THREAD_SAFE int ida_export ecmp(const fpvalue_t &a, const fpvalue_t &b);
|
|
idaman THREAD_SAFE fpvalue_kind_t ida_export get_fpvalue_kind(const fpvalue_t &a, uint16 reserved = 0);
|
|
|
|
//------------------------------------------------------------------------
|
|
/// Processor-independent representation of a floating point value.
|
|
/// IDA uses this structure to store and manipulate floating point values.
|
|
struct fpvalue_t
|
|
{
|
|
uint16 w[FPVAL_NWORDS];
|
|
|
|
void clear(void) { memset(this, 0, sizeof(*this)); }
|
|
DECLARE_COMPARISONS(fpvalue_t) { return ecmp(*this, r); }
|
|
|
|
/// Convert to the processor-independent representation.
|
|
fpvalue_error_t from_half(uint16 fpval) { return ieee_realcvt(&fpval, this, sizeof(fpval)/2-1); }
|
|
fpvalue_error_t from_float(float fpval) { return ieee_realcvt(&fpval, this, sizeof(fpval)/2-1); }
|
|
fpvalue_error_t from_double(double fpval) { return ieee_realcvt(&fpval, this, sizeof(fpval)/2-1); }
|
|
|
|
/// Convert from the processor-independent representation.
|
|
fpvalue_error_t to_half(uint16 *fpval) const { return ieee_realcvt(fpval, (fpvalue_t*)this, 8|(sizeof(*fpval)/2-1)); }
|
|
fpvalue_error_t to_float(float *fpval) const { return ieee_realcvt(fpval, (fpvalue_t*)this, 8|(sizeof(*fpval)/2-1)); }
|
|
fpvalue_error_t to_double(double *fpval) const { return ieee_realcvt(fpval, (fpvalue_t*)this, 8|(sizeof(*fpval)/2-1)); }
|
|
|
|
/// Conversions for 10-byte floating point values.
|
|
fpvalue_error_t from_10bytes(const void *fpval) { return ieee_realcvt((void *)fpval, this, 4); }
|
|
fpvalue_error_t to_10bytes(void *fpval) const { return ieee_realcvt(fpval, (fpvalue_t*)this, 8|4); }
|
|
|
|
/// Conversions for 12-byte floating point values.
|
|
fpvalue_error_t from_12bytes(const void *fpval) { return ieee_realcvt((void*)fpval, this, 5); }
|
|
fpvalue_error_t to_12bytes(void *fpval) const { return ieee_realcvt(fpval, (fpvalue_t*)this, 8|5); }
|
|
|
|
/// Convert string to IEEE.
|
|
/// \param p_str pointer to pointer to string. it will advanced.
|
|
fpvalue_error_t from_str(const char **p_str) { return asctoreal(p_str, this); }
|
|
|
|
/// Convert IEEE to string.
|
|
/// \param mode broken down into:
|
|
/// - low byte: number of digits after '.'
|
|
/// - second byte: FPNUM_LENGTH
|
|
/// - third byte: FPNUM_DIGITS
|
|
void to_str(char *buf, size_t bufsize, uint mode) const { realtoasc(buf, bufsize, *this, mode); }
|
|
|
|
/// Convert integer to IEEE
|
|
void from_sval(sval_t x) { eltoe(x, this); }
|
|
void from_int64(int64 x) { eltoe64(x, this); }
|
|
void from_uint64(uint64 x) { eltoe64u(x, this); }
|
|
|
|
/// Convert IEEE to integer (+-0.5 if round)
|
|
fpvalue_error_t to_sval(sval_t *out, bool round=false) const { return eetol(out, *this, round); }
|
|
fpvalue_error_t to_int64(int64 *out, bool round=false) const { return eetol64(out, *this, round); }
|
|
fpvalue_error_t to_uint64(uint64 *out, bool round=false) const { return eetol64u(out, *this, round); }
|
|
|
|
/// Arithmetic operations
|
|
fpvalue_error_t fadd(const fpvalue_t &y) { return eadd(*this, y, this, false); }
|
|
fpvalue_error_t fsub(const fpvalue_t &y) { return eadd(*this, y, this, true); }
|
|
fpvalue_error_t fmul(const fpvalue_t &y) { return emul(*this, y, this); }
|
|
fpvalue_error_t fdiv(const fpvalue_t &y) { return ediv(*this, y, this); }
|
|
|
|
/// Multiply by a power of 2.
|
|
fpvalue_error_t mul_pow2(int32 power_of_2) { return eldexp(*this, power_of_2, this); }
|
|
|
|
/// Calculate absolute value.
|
|
void eabs() { w[FPVAL_NWORDS-1] &= 0x7fff; }
|
|
|
|
/// Is negative value?
|
|
bool is_negative() const { return (w[FPVAL_NWORDS-1] & 0x8000) != 0; }
|
|
|
|
/// Negate.
|
|
void negate()
|
|
{
|
|
if ( w[FPVAL_NWORDS-1] != 0 )
|
|
w[FPVAL_NWORDS-1] ^= 0x8000;
|
|
}
|
|
|
|
/// Get value kind.
|
|
fpvalue_kind_t get_kind() const { return get_fpvalue_kind(*this, 0); }
|
|
};
|
|
|
|
//------------------------------------------------------------------------]
|
|
/// The exponent of 1.0
|
|
#define IEEE_EXONE (0x3fff)
|
|
|
|
/// \name Prototypes
|
|
/// IDP module event prototype -- should be implemented in idp
|
|
//@{
|
|
|
|
/// Floating point conversion function: implemented by \ph{realcvt}.
|
|
/// See ieee_realcvt
|
|
|
|
fpvalue_error_t idaapi realcvt(void *m, fpvalue_t *out, uint16 swt);
|
|
|
|
|
|
/// Little endian
|
|
|
|
fpvalue_error_t l_realcvt(void *m, fpvalue_t *out, uint16 swt);
|
|
|
|
|
|
/// Big endian
|
|
|
|
fpvalue_error_t b_realcvt(void *m, fpvalue_t *out, uint16 swt);
|
|
|
|
//@}
|
|
|
|
/// Exponent in fpvalue_t for NaN and Inf
|
|
#define E_SPECIAL_EXP 0x7fff
|
|
|
|
/// 0.0
|
|
extern const fpvalue_t ieee_ezero;
|
|
#define EZERO { 0, 0000000,0000000,0000000,0000000,0000000 }
|
|
|
|
/// 1.0
|
|
extern const fpvalue_t ieee_eone;
|
|
#define EONE { 0, 0000000,0000000,0000000,0100000,IEEE_EXONE }
|
|
|
|
/// 2.0
|
|
extern const fpvalue_t ieee_etwo;
|
|
|
|
/// 32.0
|
|
extern const fpvalue_t ieee_e32;
|
|
|
|
/// 6.93147180559945309417232121458176568075500134360255E-1
|
|
extern const fpvalue_t ieee_elog2;
|
|
|
|
/// 1.41421356237309504880168872420969807856967187537695E0
|
|
extern const fpvalue_t ieee_esqrt2;
|
|
|
|
/// 2/sqrt(PI) = 1.12837916709551257389615890312154517168810125865800E0
|
|
extern const fpvalue_t ieee_eoneopi;
|
|
|
|
/// 3.14159265358979323846264338327950288419716939937511E0
|
|
extern const fpvalue_t ieee_epi;
|
|
|
|
/// 5.7721566490153286060651209008240243104215933593992E-1
|
|
extern const fpvalue_t ieee_eeul;
|
|
|
|
#if !defined(NO_OBSOLETE_FUNCS) || defined(IEEE_SOURCE) //-[
|
|
#define IEEE_NI (FPVAL_NWORDS+3) // Number of 16 bit words in ::eNI
|
|
#define IEEE_E 1 // Array offset to exponent
|
|
#define IEEE_M 2 // Array offset to high guard word
|
|
/// There is one more internal format used by IDA to store intermediate values.
|
|
/// - 0 : sign (0/1)
|
|
/// - 1 : exponent (based of #IEEE_EXONE). If exp = 0, value = 0.
|
|
/// - 2 : high word of mantissa (always zero after normalize)
|
|
typedef uint16 eNI[IEEE_NI];
|
|
|
|
#ifdef IEEE_SOURCE
|
|
# define IEEE_DEPRECATED
|
|
#else
|
|
# define IEEE_DEPRECATED DEPRECATED
|
|
#endif
|
|
inline IEEE_DEPRECATED void ecleaz(eNI x) { memset(x, 0, sizeof(eNI)); }
|
|
idaman IEEE_DEPRECATED THREAD_SAFE void ida_export emovo(const eNI a, fpvalue_t *vout); /// Move eNI => eNE
|
|
idaman IEEE_DEPRECATED THREAD_SAFE void ida_export emovi(const fpvalue_t &a, eNI vout); /// Move eNE => eNI
|
|
idaman IEEE_DEPRECATED THREAD_SAFE int ida_export eshift(eNI x, int sc); /// Shift NI format up (+) or down
|
|
/// Normalize and round off.
|
|
/// \param s the internal format number to be rounded
|
|
/// \param lost indicates whether or not the number is exact.
|
|
/// this is the so-called sticky bit.
|
|
/// \param subflg indicates whether the number was obtained
|
|
/// by a subtraction operation. In that case if lost is nonzero
|
|
/// then the number is slightly smaller than indicated.
|
|
/// \param exp the biased exponent, which may be negative.
|
|
/// the exponent field of "s" is ignored but is replaced by
|
|
/// "exp" as adjusted by normalization and rounding.
|
|
/// \param rndbase if 0 => is the rounding control.
|
|
/// else is processor defined base (rndprc)
|
|
/// \return success
|
|
idaman IEEE_DEPRECATED THREAD_SAFE bool ida_export emdnorm(eNI s, bool lost, bool subflg, int32 exp, int rndbase);
|
|
|
|
#endif
|
|
|
|
#endif
|