2

what does this code on IDA? i've found with this a couple of times and i don't have idea what means.

int a5;
int dGainMax;
COERCE_DOUBLE(__PAIR__(a5, dGainMax))
4

__PAIR__() seems to be a macro that computes an unsigned long value from its two arguments, which it interprets as containing the high and low bits of that value.

The topic linked by Guntram - Understanding __PAIR__ macro from IDA PRO Pseudo Decompiler to look better contains a definition for the macro and examples of its use, but no explanation of it.

// The following definition is not quite correct because it always returns
// uint64. The above C++ functions are good, though.
#define __PAIR__(high, low) (((unsigned long)(high)<<sizeof(high)*8) | low)

The macro doesn't make a lot of sense. Either it was transcribed erroneously (with the original containing sizeof(low) instead of sizeof(high)) or the above-mentioned pseudo decompiler uses it only in cases where it works.

If the following conditions hold:

  1. CHAR_BIT == 8
  2. sizeof(high) < sizeof(unsigned long)
  3. sizeof(low) <= sizeof(high)

then the macro can be used to form a value of double register width - like DX:AX - from two register-width values.

Condition 2 is necessary because otherwise the behaviour would be undefined (no-op on Intel chips, for example, since they mask shifts for registers <= 32 bit with 31). Condition 3 is necessary because otherwise 'excess' bits in low could bleed over the bits of high in the resulting value.

The comment and the context (usage example) suggest that

  1. sizeof(unsigned long) == sizeof(uint64_t)
  2. sizeof(int) == sizeof(int32_t)

This implies a compiler of the LP64 variety, like those usually found in 64-bit UNIX (not the LLP64 kind common on Wintel platforms).

The naming of the COERCE_DOUBLE macro is a bit unfortunate since it probably refers to converting the value to a double while 'coercing' might also mean reinterpreting the bits as a floating point value, something which certain programming tricks used to rely on.

Also, there is some ambiguity regarding the conversion. The x86 FPU can load signed integers directly into floating point registers (FILD) but not unsigned ones, which means that x86 compilers have to emit a load of extra code for converting unsigned integers.

This means that the __PAIR__ macro with its implied unsignedness can erroneously suggest major inefficiencies that aren't there, since x86 CPUs tend to interpret double-width register values are as signed whenever signedness matters (see instructions like CDQ, DIV or FILD, for example). The devil is in the details which are hidden and glossed over by the strange macros. Hence it is advisable to consult the disassembly to find out what's really going on, even though the SP simulation of the disassembler can be a bit off on occasion.

| improve this answer | |

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