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

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:

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.


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.

const message = "hello world";
console.log(message);

PSEDUDOCODE V1.6else { 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.7else 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.6if ( 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.7if ( !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.6v5->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.7v5->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.6v5 = &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.7v5 = 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.6int __cdecl int_u_mod_FFFFFFF6u() { unsigned int v0; // eax@1 v0 = u(); return v0 - -10 * (v0 >= 0xFFFFFFF6); }PSEUDOCODE V1.7unsigned 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.6if ( HalpAcpiTableCacheList.Flink->Blink != &HalpAcpiTableCacheList || (v6 = HalpAcpiTableCacheList.Blink, HalpAcpiTableCacheList.Blink->Flink != &HalpAcpiTableCacheList) ) __asm { int 29h ; DOS 2+ internal - FAST PUTCHAR }PSEUDOCODE V1.7RtlpCheckListEntry(&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.6Result = CFileInterface::WriteFile(pDirectory, dwStartPosition, &PrimaryEntry, 0x20u); if ( !Result )PSEUDOCODE V1.7Result = 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.6do { if ( *v2 == 3 ) printf("%s %s\n", 3, CONTAINING_RECORD(v2, a, dummy)->key); v2 += 3; } while ( v2 - 1 != v1 );PSEUDOCODE V1.7do { 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.6int __cdecl func(__int64 a1) { int v1; // esi@1 v1 = 0; if ( SHIDWORD(a1) <= 0 && SHIDWORD(a1) < 0 ) v1 = g(); return v1 + f(); }PSEUDOCODE V1.7int __cdecl func(__int64 a1) { int v1; // esi@1 v1 = 0; if ( a1 < 0 ) v1 = g(); return v1 + f(); }

Support for more compiler helpers

Yet one more example of improved output.

PSEDUDOCODE V1.6int __fastcall int_u_mod_FFFFFFFFFFFFFFE0ui64() { unsigned int v0; // r4@1 bool v1; // r2@2 v0 = u(); v1 = (unsigned int)_aeabi_ulcmp() < 0xFFFFFFFF; return v0 - -32 * v1; }PSEUDOCODE V1.7unsigned 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.6int v2; // [sp+4h] [bp-10h]@2 if ( latencyState ) v2 = 0; else v2 = 1; return v2;PSEUDOCODE V1.7return 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.6PSEUDOCODE V1.7float _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" };

Last updated