Hex-Rays v1.7 vs. v1.6 Decompiler Comparison Page

Below you will find side-by-side comparisons of v1.6 and v1.7 decompilations. Please maximize the window too see both columns simultaneously.

The following examples are displayed on this page:

  1. Print else-if on the same line
  2. In conditions, prefer !strcmp(x, y)
  3. More ternary operators
  4. Better handling of negative indexes
  5. No messy code for byte accesses anymore
  6. More patterns for arithmetic operations
  7. More LIST_ENTRY related macros
  8. More "interlocked" intrinsics
  9. Better comparisions of symbolic constants
  10. Better support for CONTAINING_RECORD
  11. We continue to work on 64-bit arithmetics
  12. Support for more compiler helpers
  13. Concise representation for calculating booleans
  14. Data objects are printed in the output

NOTE: these are just some selected examples that can be illustrated as a side-by-side difference. Hex-Rays Decompiler v1.7 includes are many other improvements and new features that are not mentioned on this page - simply because there was nothing to compare them with. Also, some improvements have already been illustrated in the previous comparisons. Please refer to the news page for more details.


Print else-if on the same line

A sequence of else-if's was getting indented to the right, but now the decompiler shows them nicely, aligned one below the other. A simple improvement, yet makes the output more readable.

Psedudocode v1.6
else { if ( arg0 == 100 ) { result = 104; } else { if ( arg0 <= 100 ) { if ( arg0 != 1 ) return 0; result = 3; } else { if ( arg0 == 255 ) { result = 261; } else {
Pseudocode v1.7
else if ( arg0 == 100 ) { result = 104; } else if ( arg0 <= 100 ) { if ( arg0 != 1 ) return 0; result = 3; } else if ( arg0 == 255 ) { result = 261; } else {

In conditions, prefer !strcmp(x, y)

After a string comparison we usually are interested in the case when the strings are equal. The listing on the right is more readable because the actions for each keyword immediately follow comparisions. However, the old listing (on the left) was too long that the actions just did not fit this web page.

By default the decompiler applies this logic to strcmp, memcmp, and similar functions, but the list of functions is configurable.

Psedudocode v1.6
if ( strncmp(v31, "IOT", 4) ) { if ( strncmp(v31, "EMT", 4) ) { if ( strncmp(v31, "FPE", 4) ) { if ( strncmp(v31, "KILL", 5) ) { if ( strncmp(v31, "BUS", 4) ) {
Pseudocode v1.7
if ( !strncmp(v31, "IOT", 4) ) { *(_DWORD *)v19 = "IOT"; v18 = 6; } else if ( !strncmp(v31, "EMT", 4) ) { *(_DWORD *)v19 = "EMT"; v18 = 7; } else if ( !strncmp(v31, "FPE", 4) ) { *(_DWORD *)v19 = "FPE"; v18 = 8; } else if ( !strncmp(v31, "KILL", 5) ) { *(_DWORD *)v19 = "KILL"; v18 = 9; } else if ( !strncmp(v31, "BUS", 4) ) { *(_DWORD *)v19 = "BUS"; v18 = 10; }

More ternary operators

The ternary operator is easier to read, isn't it?

Psedudocode v1.6
*v3 = ((v5 - 1) & 0xF1) - 1;
Pseudocode v1.7
*v3 = v5 ? -1 : 240;

Better handling of negative indexes

Both v4 and v5 point to the same structure type. However, references made by v4 were not represented nicely because of a negative index. Now the decompiler can handle that nicely.

Psedudocode v1.6
v5->dword0 = v4[-8].dword0; *(_DWORD *)&v5->word4 = *((_DWORD *)&v4[-7] - 3); v5->dword8 = *((_DWORD *)&v4[-7] - 2); v5->dwordC = *((_DWORD *)&v4[-7] - 1);
Pseudocode v1.7
v5->dword0 = v4[-8].dword0; *(_DWORD *)&v5->word4 = *(_DWORD *)&v4[-8].word4; v5->dword8 = v4[-8].dword8; v5->dwordC = v4[-8].dwordC;

No messy code for byte accesses anymore

On ARM, when the compiler cannot prove that a pointer is properly aligned, it resorts to copying the data byte by byte. The decompiler could not represent it nicely because it lacked special logic to handle that. Now we do it.

Psedudocode v1.6
v5 = &sel_dismissCurrentPopover[14]; HIWORD(v5) = 0; v6 = (int)sel_dismissCurrentPopover; HIWORD(v6) = 0; v7 = (void *)*((_DWORD *)v5 + 3148); ++dword_11F80; v8 = *(const char **)(v6 + 12602);
Pseudocode v1.7
v5 = sel_showNextMessage; ++dword_11F80; v6 = sel_performSelector_withObject_afterDelay_;

More patterns for arithmetic operations

Adding a new pattern to recognize a code sequence always helps to reduce the output. Above is a nice example of that. Both code snippets do the same, it is only a matter of representation.

Psedudocode v1.6
int __cdecl int_u_mod_FFFFFFF6u() { unsigned int v0; // [email protected] v0 = u(); return v0 - -10 * (v0 >= 0xFFFFFFF6); }
Pseudocode v1.7
unsigned int __cdecl int_u_mod_FFFFFFF6u() { return u() % 0xFFFFFFF6; }

More LIST_ENTRY related macros

We added more LIST_ENTRY related macros but there is still many remaining... This one uses the new "fastfail" macro from Win8.

Psedudocode v1.6
if ( HalpAcpiTableCacheList.Flink->Blink != &HalpAcpiTableCacheList || (v6 = HalpAcpiTableCacheList.Blink, HalpAcpiTableCacheList.Blink->Flink != &HalpAcpiTableCacheList) ) __asm { int 29h ; DOS 2+ internal - FAST PUTCHAR }
Pseudocode v1.7
RtlpCheckListEntry(&HalpAcpiTableCacheList);

More "interlocked" intrinsics

We added support for more intrinsic functions, especially the ones used by Visual Studio. There are too many of them to be listed here.

Psedudocode v1.6
_ECX = 0; _EAX = (int *)&v6; __asm { lock and [eax], ecx } _EDX = -2; __asm { lock and [eax], edx } _EDI = (int *)&v6; result = -2; __asm { lock and [edi], eax }
Pseudocode v1.7
_InterlockedAnd((signed __int32 *)&v2, 0); _InterlockedAnd((signed __int32 *)&v2, 0xFFFFFFFEu); result = -2; _InterlockedAnd((signed __int32 *)&v2, 0xFFFFFFFEu);

Better comparisions of symbolic constants

Here, the Result variable is HRESULT. Instead of logically negating it, it is better to compare against ERROR_SUCCESS, so the meaning of the code is clearer.

Psedudocode v1.6
Result = CFileInterface::WriteFile(pDirectory, dwStartPosition, &PrimaryEntry, 0x20u); if ( !Result )
Pseudocode v1.7
Result = CFileInterface::WriteFile(pDirectory, dwStartPosition, &PrimaryEntry, 0x20u); if ( Result == ERROR_SUCCESS )

Better support for CONTAINING_RECORD

It seems that CONTAINING_RECORD will be our method of representing structure pointers with a delta. When we have a pointer that points not to the beginning of a structure object but somewhere in the middle (this occurs much more frequently that you might think!), we need to represent it nicely. The CONTAING_RECORD macro suits this need quite well.

In the new version we improved support for it very much, now it can handle virtually all cases. Above, v2 points to the middle of a structure type "a", to the field named "key".

Psedudocode v1.6
do { if ( *v2 == 3 ) printf("%s %s\n", 3, CONTAINING_RECORD(v2, a, dummy)->key); v2 += 3; } while ( v2 - 1 != v1 );
Pseudocode v1.7
do { if ( CONTAINING_RECORD(v2, a, key)->key == 3 ) printf("%s %s\n", 3, CONTAINING_RECORD(v2, a, key)->string); v2 += 3; } while ( v2 - 1 != v1 );

We continue to work on 64-bit arithmetics

It is a never ending story but we do not give up. More 64-bit patterns - better output.

Psedudocode v1.6
int __cdecl func(__int64 a1) { int v1; // [email protected] v1 = 0; if ( SHIDWORD(a1) <= 0 && SHIDWORD(a1) < 0 ) v1 = g(); return v1 + f(); }
Pseudocode v1.7
int __cdecl func(__int64 a1) { int v1; // [email protected] v1 = 0; if ( a1 < 0 ) v1 = g(); return v1 + f(); }

Support for more compiler helpers

Yet one more example of improved output.

Psedudocode v1.6
int __fastcall int_u_mod_FFFFFFFFFFFFFFE0ui64() { unsigned int v0; // [email protected] bool v1; // [email protected] v0 = u(); v1 = (unsigned int)_aeabi_ulcmp() < 0xFFFFFFFF; return v0 - -32 * v1; }
Pseudocode v1.7
unsigned int __fastcall int_u_mod_FFFFFFFFFFFFFFE0ui64() { return u() % 0xFFFFFFE0; }

Concise representation for calculating booleans

While some readers prefer the code of the left because it is more verbose, our preference is clearly on the right.

Psedudocode v1.6
int v2; // [sp+4h] [bp-10h]@2 if ( latencyState ) v2 = 0; else v2 = 1; return v2;
Pseudocode v1.7
return latencyState == 0;

Data objects are printed in the output

Previous versions of the decompiler were not displaying data objects in the output listing at all. Now we print them in the output file. This makes the output more complete - less work if you want to recompile it.

Psedudocode v1.6
Pseudocode v1.7
float _real = 4.0; // weak const unsigned __int16 s_fifoLookup[4] = { 8u, 16u, 32u, 64u }; int g_oalIoCtlTable[2] = { 16846848, 0 }; // weak _STRING CheckRunAppProcedureName = { 18u, 19u, "ApphelpCheckRunApp" }; char *off_6205310C[6] = { "16:18:06", "Jan 29 2012", 300, "m0", "x9338" };