Hex-Rays v1.7 Comparison Page

Welcome to the Hex-Rays Decompiler v1.7 comparison page! Below you will find side-by-side comparisons of Hex-Rays v1.6 and v1.7 outputs. Please maximize the window too see both columns simultaneously. The previous comparison can be found here.

The following original exhibits 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
Print else-if on the same line
else { if ( arg0 == 100 ) { result = 104; } else { if ( arg0 <= 100 ) { if ( arg0 != 1 ) return 0; result = 3; } else { if ( arg0 == 255 ) { result = 261; } else { else if ( arg0 == 100 ) { result = 104; } else if ( arg0 <= 100 ) { if ( arg0 != 1 ) return 0; result = 3; } else if ( arg0 == 255 ) { result = 261; } else {
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.
In conditions, prefer !strcmp(x, y)
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) ) { 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; }
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.

More ternary operators
*v3 = ((v5 - 1) & 0xF1) - 1; *v3 = v5 ? -1 : 240;
The ternary operator is easier to read, isn't it?
Better handling of negative indexes
v5->dword0 = v4[-8].dword0; *(_DWORD *)&v5->word4 = *((_DWORD *)&v4[-7] - 3); v5->dword8 = *((_DWORD *)&v4[-7] - 2); v5->dwordC = *((_DWORD *)&v4[-7] - 1); v5->dword0 = v4[-8].dword0; *(_DWORD *)&v5->word4 = *(_DWORD *)&v4[-8].word4; v5->dword8 = v4[-8].dword8; v5->dwordC = v4[-8].dwordC;
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.
No messy code for byte accesses anymore
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); v5 = sel_showNextMessage; ++dword_11F80; v6 = sel_performSelector_withObject_afterDelay_;
On ARM, when the compiler can not 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.
More patterns for arithmetic operations
int __cdecl int_u_mod_FFFFFFF6u() { unsigned int v0; // [email protected] v0 = u(); return v0 - -10 * (v0 >= 0xFFFFFFF6); } unsigned int __cdecl int_u_mod_FFFFFFF6u() { return u() % 0xFFFFFFF6; }
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.
More LIST_ENTRY related macros
if ( HalpAcpiTableCacheList.Flink->Blink != &HalpAcpiTableCacheList || (v6 = HalpAcpiTableCacheList.Blink, HalpAcpiTableCacheList.Blink->Flink != &HalpAcpiTableCacheList) ) __asm { int 29h ; DOS 2+ internal - FAST PUTCHAR } RtlpCheckListEntry(&HalpAcpiTableCacheList);
We added more LIST_ENTRY related macros but there is still many remaining... This one uses the new "fastfail" macro from Win8.
More "interlocked" intrinsics
_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 } _InterlockedAnd((signed __int32 *)&v2, 0); _InterlockedAnd((signed __int32 *)&v2, 0xFFFFFFFEu); result = -2; _InterlockedAnd((signed __int32 *)&v2, 0xFFFFFFFEu);
We added support for more intrinsic functions, especially the ones used by Visual Studio. There are too many of them to be listed here.
Better comparisions of symbolic constants
Result = CFileInterface::WriteFile(pDirectory, dwStartPosition, &PrimaryEntry, 0x20u); if ( !Result ) Result = CFileInterface::WriteFile(pDirectory, dwStartPosition, &PrimaryEntry, 0x20u); if ( Result == ERROR_SUCCESS )
Above, 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.
Better support for CONTAINING_RECORD
do { if ( *v2 == 3 ) printf("%s %s\n", 3, CONTAINING_RECORD(v2, a, dummy)->key); v2 += 3; } while ( v2 - 1 != v1 ); 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 );
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".

We continue to work on 64-bit arithmetics
int __cdecl func(__int64 a1) { int v1; // [email protected] v1 = 0; if ( SHIDWORD(a1) <= 0 && SHIDWORD(a1) < 0 ) v1 = g(); return v1 + f(); } int __cdecl func(__int64 a1) { int v1; // [email protected] v1 = 0; if ( a1 < 0 ) v1 = g(); return v1 + f(); }
It is a never ending story but we do not give up. More 64-bit patterns - better output.
Support for more compiler helpers
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; } unsigned int __fastcall int_u_mod_FFFFFFFFFFFFFFE0ui64() { return u() % 0xFFFFFFE0; }
Yet one more example of improved output.
Concise representation for calculating booleans
int v2; // [sp+4h] [bp-10h]@2 if ( latencyState ) v2 = 0; else v2 = 1; return v2; return latencyState == 0;
While some readers prefer the code of the left because it is more verbose, our preference is clearly on the right.
Data objects are printed in the output
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" };
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.

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.

This is all for the moment. Please come back for more examples!