2

What is the purpose of COERCE_FLOAT and COERCE_UNSIGNED_INT macros in the Hex Rays decompiled code below?

double __cdecl sub_401580(float a1)
{
  unsigned int v1; // eax@1
  double v2; // st7@1
  float v4; // [sp+10h] [bp+4h]@1
  float v5; // [sp+10h] [bp+4h]@1

  v1 = LODWORD(a1) & 0x80000000;
  v4 = 1.273239493370056 * a1 - a1 * 0.4052847325801849 * COERCE_FLOAT(LODWORD(a1) & 0x7FFFFFFF);
  v2 = v4;
  v5 = v4 * v4;
  return (float)(v5
               * ((v5 * COERCE_FLOAT(v1 ^ COERCE_UNSIGNED_INT(-0.0032225901))
                 + COERCE_FLOAT(v1 | COERCE_UNSIGNED_INT(0.015124941)))
                * v5
                + COERCE_FLOAT(v1 | COERCE_UNSIGNED_INT(0.20363937)))
               + v2 * 0.7844448685646057);
}
4
  • What is the question?
    – tmr232
    Commented Dec 25, 2015 at 10:19
  • that is the question :P
    – blabb
    Commented Dec 25, 2015 at 13:58
  • macro doing ? COERCE_FLOAT and COERCE_UNSIGNED_INT
    – Arun
    Commented Dec 26, 2015 at 7:43
  • please help me to simply the code
    – Arun
    Commented Dec 26, 2015 at 7:44

3 Answers 3

6

COERCE_TYPE(x) is the same thing as *(TYPE *)&x. Hex-Rays uses COERCE_... macros when &x is illegal. For example:

COERCE_DOUBLE(__PAIR__(i1,i2))

Is the same as *(double *)&__PAIR__(i1, i2), but since & can not be applied to calls, we end up seeing COERCE.

Its name correctly conveys its meaning.

1
  • Are You The Ilfak Guilfanov ? Welcome to RESE
    – blabb
    Commented Jan 17, 2019 at 10:51
1

I'd read this (and probably it is a mistake) as treating binary content of the variable as a variable of another type, something like this:

  • coerce float is *((float*)&var), where var was of the same size as float, supposedly 4 bytes.
  • coerce unsigned int is *((unsigned int*)&var), where var was of the same size as unsigned int.

As far as I remember 32 bit platforms treating unsigned int and float as a values of 4 bytes length.

3
  • 1
    Thanx for Your Answer, where all these macro defined in ida decompiler, is there any header file
    – Arun
    Commented Jan 21, 2016 at 14:20
  • I don;t know anything about header file where ii is defined. It is only suggestion.
    – w s
    Commented Jan 21, 2016 at 16:19
  • I'm with @Arun, I would love to know where these macros are defined so I can go look them up. Commented Aug 17, 2016 at 18:24
1

coerce_* functions are generally a little more coercive that a simple casting, I would assume their meaning as follows:

   #define VALUE_SIZE (sizeof(int))

struct VALUE_TYPE {
    char contents[VALUE_SIZE];
};

struct VALUE_TYPE COERCE_FLOAT(float arg) {
    struct VALUE_TYPE rv;
    memcpy(&arg, rv.contents, sizeof arg);
    return rv;
}

struct VALUE_TYPE COERCE_INT(int arg) {
    struct VALUE_TYPE rv;
    memcpy(&arg, rv.contents, sizeof arg);
    return rv;
}

struct VALUE_TYPE COERCE_UNSIGNED_INT(unsigned int arg) {
    struct VALUE_TYPE rv;
    memcpy(&arg, rv.contents, sizeof arg);
    return rv;
}

source: https://stackoverflow.com/a/37198532/912236

The reason for their use may relate to how the ABI passes floats vs how it passes integers. There is no difference in Windows 32-bit code (either stdcall or cdecl), but in x64 float's and integers are passed in different registers.

It's possible that those macro may make no difference to compilation of a 32-bit target, and are just there to ensure (or inform the reader/compiler) of the expected type, but that's pure conjecture on my part.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.