Decompiler Desquirr Test

Program-Transformation.Org: The Program Transformation Wiki
These Fibonacci (286) and Palindrome results are from David's masters theses, Figure 5.2. The other tests are using the 20030507 binary of the desquirr plugin, as downloaded from the Sourceforge page.

Fibonacci (286)

David apparently used one of the dcc test programs. The original C source code is:

int main()
{ int i, numtimes, number;
  unsigned value, fib();

    printf("Input number of iterations: ");
    scanf ("%d", &numtimes);
    for (i = 1; i <= numtimes; i++)
    {
        printf ("Input number: ");
        scanf ("%d", &number);
        value = fib(number);
        printf("fibonacci(%d) = %u\n", number, value);
    }
    exit(0);
}

unsigned fib(x)                 /* compute fibonacci number recursively */
int x;
{
    if (x > 2)
        return (fib(x - 1) + fib(x - 2));
    else
        return (1);
}

The decompiled output is as follows:

sub 10291:
  _printf("Input number of iterations: ");
  ax = _scanf("%d", & var_2);
  si = 1;
  goto loc_102DD;

loc 102AF:
  _printf("Input number: ");
  scanf("%d", & var_4);
  var_6 = sub_102EB(var_4);
  ax = _printf("fibonacci(%d) = %u\n", var_4, var_6);
  si = si + 1;

loc 102DD:
  if (si <= var_2) goto loc_102AF;

  _exit(0);
  return ax;


sub_102EB:
  if (arg 0 <= 2) goto loc_10313;

  dx = sub_102EB(arg_0 - 1);
  ax = sub_102EB(arg_0 + 0xfffe);
  ax = dx + ax;
  goto loc 10318;

  goto loc 10318;

loc_10313:
  ax = 1;
  goto loc_10318;

loc_10318:
  return ax;

Registers are visible; variables, procedures and parameters are not declared. Control flow is limited to if (...) goto label; Actual parameters are recovered well.

Note: I tried to reproduce these results with the original 80286 binaries, and get much worse results. Presumably, David compiled the test program with a different compiler. It's impressive that Desquirr can handle 80286 code at all, though perhaps IDA is handling most of the 286 uglinesses.

Fibonacci (ELF/386)

Original source code (slightly different to the above Fibonacci program):

#include < stdio.h >
int fib (int x)
{
    if (x > 1)
        return (fib(x - 1) + fib(x - 2));
    else return (x);
}
int main (void)
{   int number, value;

    printf ("Input number: ");
    scanf ("%d", &number);
    value = fib(number);
    printf("fibonacci(%d) = %d\n", number, value);
    return (0);
}

Decompiled output:

main:
  _printf("Input number: ");
  _scanf("%d", & var_4);
  sp = sp + 12;
  if (bx <= 1) goto loc_8048814;

  fib(bx + -1);
  ax = fib(bx + -2) + si;
  goto loc_8048816;

loc_8048814:
  ax = bx;

loc_8048816:
  _printf("fibonacci(%d) = %d\n", var_4, ax);
  /* pop  */
  /* pop  */
  return 0;

fib:
  if (bx <= 1) goto loc_80487C0;

  fib(bx + -1);
  ax = fib(bx + -2) + si;
  goto loc_80487C2;

loc_80487C0:
  ax = bx;

loc_80487C2:
  /* pop  */
  /* pop  */
  return ax;
Some code is missing, e.g. near the top of main, bx = var4. Parameters and returns are missing from fib().

Palindrome test

The original source code is:

#include <stdio.h>
#include <string.h>
#include <malloc.h>

void rev(char* source, char* destination)
{
  char* tmp = destination + strlen(source);
  for (*tmp-- = 0; *source; *tmp-- = *source++)
    ;
}

int main(int argc, char**argv)
{
  char* original = NULL;
  char* reverse = NULL;

  if (argc < 2)
  {
    original = "nitalarbralatin";

  }
  else
  {
    original = argv[1];
  }

  reverse = malloc(strlen(original)+1);

  rev(original, reverse);
  if (0 == strcmp(original, reverse))
  {
    printf("%s is a palindrome\n", original);
  }
  else
  {
    printf("Try again!\n");
  }

  free(reverse);

  return 0;
}

The decompiled output is:

sub_401150:
  bx = arg_0;
  ax = _strlen(bx) + arg_4;
  * ax = 0;
  ax = ax - 1;
  goto loc_40116E;

loc_401167:
  dl = * bx;
  bx = bx + 1;
  ax = ax - 1;
  * (ax + 1) = dl;

loc_40116E:
  if ((* bx) != 0) goto loc_401167;

  return ax;


_main:
  if (argc >= 2) goto loc_401188;

  bx = "nitalarbralatin";
  goto loc_40118E;

loc_401188:
  bx = * (argv + 4);

loc_40118E:
  si = _malloc(_strlen(bx) + 1);
  sub_401150(bx, si);
  if (_strcmp(bx, si) != 0) goto loc_4011C7;

  _printf("%s is a palindrome\n", bx);
  goto loc_4011D2;

loc_4011C7:
  _printf("Try again!\n");

loc 4011D2:
  _free(si);
  return 0;

Switch_gcc

This is the boomerang test from test/pentium/switch_gcc. Original source code is:
int main(int argc)
{
    switch(argc)
    {
        case 2: printf("Two!\n"); break;
        case 3: printf("Three!\n"); break;
        case 4: printf("Four!\n"); break;
        case 5: printf("Five!\n"); break;
        case 6: printf("Six!\n"); break;
        case 7: printf("Seven!\n"); break;
        default:printf("Other!\n"); break;
        }
    return 0;
}

Decompiled output:

main:
  switch (arg_0)

off_8048934:

  case 0:
  goto loc_8048981;

  case 1:
  goto loc_8048981;

  case 2:
  goto loc_8048981;

  case 3:
  goto loc_8048981;

  case 4:
  goto loc_8048981;

  case 5:
  goto loc_8048981;

loc_804897C:

loc_8048981:
  _printf("Other!\n", "Seven!\n", "Six!\n", "Five!\n", "Four!\n", "Three!\n", "Two!\n");
  return 0;

Desquirr seems to have ignored the gotos, so that all the push instructions appear to add parameters to the one call to printf. The argument to the switch statement is wrong (should be arg0-2, or the switch values should be increased by 2).

Switch_cc

This is the Boomerang test from test/pentium/switch_cc. It comes from the same source code as the above, but was compiled with a Sun compiler. The compiler has one call to printf in each case of the switch statement. Decompiled output:
08048978 Error! Jump destination is not a Global!
main:
  ax = ax + -2;
  if (ax <= 5) goto loc_8048978;

  return _printf("Other!\n") - ax;

loc_8048914:
  return _printf("Two!\n") - ax;

loc_8048928:
  return _printf("Three!\n") - ax;

loc_804893C:
  return _printf("Four!\n") - ax;

loc_8048950:
  return _printf("Five!\n") - ax;

loc_8048964:
  return _printf("Six!\n") - ax;

loc_8048978:
  goto off_80489E8 + (ax * 4);

loc_804897F:
  return _printf("Seven!\n") - ax;

The switch table is in the .rodata section, not in the .text section as with switch_gcc. This seems to be unexpected. It also seems confused by the sub eax, eax instructions used to return 0.

Sumarray-O4

This is the Boomerang test test/pentium/sumarray-O4. As the name suggests, this test is compiled with the gcc compiler using -O4 optimisation. (Output for the same program compiled with no optimisation is ironically less readable, because local variables are emitted as * (& var_4), and has more errors.) The original source code:
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int main() {
    int sum = 0;
    int i;
    for (i=0; i < 10; i++) {
        sum += a[i];
    }
    printf("Sum is %d\n", sum);
    return 0;
}

Decompiled output:

main:
  sp = sp & -16;
  dx = 0;
  ax = 0;
  cx = a;

loc_804833C:
  dx = dx + (* (cx + (ax * 4)));
  ax = ax + 1;
  if (ax <= 9) goto loc_804833C;

  _printf("Sum is %d\n", dx);
  return 0;
This is not too bad. The array is not declared, and the index operation is as per the X86 instructions. The for loop is not recovered. Other than that, it's fairly readable.

-- MikeVanEmmerik - 20 Mar 2003, updated 20 Jul 2005.
CategoryDecompilation

Transform.DecompilerDesquirrTest moved from Transform.DecompilationDesquirr on 20 Mar 2003 - 03:05 by MikeVanEmmerik - put it back