home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / snip9707.zip / DECOMPIL.TXT < prev    next >
Text File  |  1997-07-05  |  7KB  |  143 lines

  1. +++Date last modified: 05-Jul-1997
  2.  
  3. Question:
  4.  
  5.   Is there any hope of a decompiler that would convert an executable program
  6. into C/C++ code?
  7.  
  8. Answer:
  9.  
  10.   Don't hold your breath. Think about it... For a decompiler to work
  11. properly, either 1) every compiler would have to generate substantially
  12. identical code, even with full optimization turned on, or 2) it would have to
  13. recognize the individual output of every compiler's code generator.
  14.  
  15.   If the first case were to be correct, there would be no more need for
  16. compiler benchmarks since every one would work the same. For the second case
  17. to be true would require in immensely complex program that had to change with
  18. every new compiler release.
  19.  
  20.   OK, so what about specific decompilers for specific compilers - say a
  21. decompiler designed to only work on code generated by, say, BC++ 4.52? This
  22. gets us right back to the optimization issue. Code written for clarity and
  23. understandability is often inefficient. Code written for maximum performance
  24. (speed or size) is often cryptic (at best!) Add to this the fact that all
  25. modern compilers have a multitude of optimization switches to control which
  26. optimization techniques to enable and which to avoid. The bottom line is
  27. that, for a reasonably large, complex source module, you can get the compiler
  28. to produce a number of different object modules simply by changing your
  29. optimization switches, so your decompiler will also have to be a deoptimizer
  30. which can automagically recognize which optimization strategies were enabled
  31. at compile time.
  32.  
  33.   OK, let's simplify further and specify that you only want to support one
  34. specific compiler and you want to decompile to the most logical source code
  35. without trying to interpret the optimization. What then? A good optimizer can
  36. and will substantially rewrite the internals of your code, so what you get
  37. out of your decompiler will be, not only cryptic, but in many cases, riddled
  38. with goto statements and other no-no's of good coding practice. At this
  39. point, you have decompiled source, but what good is it?
  40.  
  41.   Also note carefully my reference to source modules. One characteristic of C
  42. is that it becomes largely unreadable unless broken into easily maintainable
  43. source modules (.C files). How will the decompiler deal with that? It could
  44. either try to decompile the whole program into some mammoth main() function,
  45. losing all modularity, or it could try to place each called function into its
  46. own file. The first way would generate unusable chaos and the second would
  47. run into problems where the original source had files with multiple functions
  48. using static data and/or one or more functions calling one or more static
  49. functions. A decompiler could make static data and/or functions global but
  50. only at the expense or readability (which would already be unacceptable).
  51.  
  52.   Also, remember that commercial applications often code the most difficult
  53. or time-critical functions in assembler which could prove almost impossible
  54. to decompile into a C equivalent.
  55.  
  56.   Closely related to the issue of modularity is that of library code.
  57. Consider the ubiquitous "Hello world" program. After compilation it contains
  58. about 10 bytes of compiled source, about a dozen bytes of data, and anywhere
  59. from 5-10K (depending on compiler, target, memory model, etc.) of start up
  60. and library code. This is a great example since printf() also calls *lots* of
  61. other library functions of its own! Once the decompiler has assigned names to
  62. the dozen or so functions in its output, the fun starts when you have to
  63. figure out which arbitrarily-named function is really printf() and which
  64. other functions are library helper functions that it calls. The bottom line
  65. here is that in order to do so, you'd have to know enough about writing C
  66. libraries to be able to recognize the code for printf() when you see it.
  67.  
  68.   Again, the situation with C++ would be orders of magnitude more complex
  69. trying to make sense of the compiled code once the O-O structures and
  70. relationships had been compiled into oblivion. Even if you take the simple
  71. approach and decompile C++ into C, would anyone like to try and trace through
  72. the source to figure out a cout call which adds another 7-10K of overhead
  73. vis-a-vis a printf() call? I sure wouldn't!!!
  74.  
  75.   So what do your have? For a small program, you'd wind up trying to decipher
  76. what is mostly library source. For a large program, you'd wind up with either
  77. 1) one humonguous main(), or 2) lots of arbitrary single-function modules
  78. from which all notions of static data and functions would have been lost
  79. (contributing to a vast pool of global data), which would still include
  80. decompiled source for all the library objects as well. In any scenario, is
  81. any of this useful? Probably not.
  82.  
  83.   While we've touched on the topic of library code, here's yet another reason
  84. that C and C++ are particularly difficult to de-compile: macros.
  85.  
  86. For instance, if I have something like:
  87.  
  88.     while (EOF != ( ch = getchar())) {
  89.         if (isupper(ch))
  90.             putchar(ch);
  91.  
  92. getchar, EOF, putchar and isupper are all typically macros, something like:
  93.  
  94. #define EOF -1
  95. #define isupper(x) (__types[(unsigned char)x+1] && __UPPER)
  96. #define getchar()  (getc(stdin))
  97. #define putchar(c) (putc((c),stdout)
  98.  
  99. #define getc(s) ((s)->__pos<(s)->__len?     \
  100.     (s)->__buf[__pos++]:                    \
  101.       filbuf(s))
  102. #define putc(c,s) ((s)->__pos<(s)->__len?   \
  103.     (s)->__buf[__pos++]=(c):                \
  104.     putbuf((s),(c)))
  105.  
  106. Finally, stdin and stdout are generally just items in an array of FILE
  107. pointers something like:
  108.  
  109. FILE __iobuf[20];
  110.  
  111. FILE *stdin = __iobuf;      // This part is done silently by the
  112. FILE *stdout = __iobuf + 1; // compiler, without actual source code
  113. FILE *stderr = __iobuf + 2;
  114.  
  115.  
  116. Even if you just expand the macros and never actually compile the code at
  117. all, you end up with something that's basically unreadable. However, this is
  118. what actually gets fed to the compiler, so it's also absolute best you could
  119. ever hope for from a perfect de-compiler.
  120.  
  121. C++ of course adds in-line functions and after an optimizer runs across
  122. things, the code from the in-line function may well be mixed in with
  123. surrounding code, making it nearly impossible to extract the function from
  124. the code that calls it.  There are only a few formats in use for vtables,
  125. which would help in preserving virtual functions, but inline functions would
  126. be lost, so you'd typically end up with hundreds of times that code would be
  127. directly accessing variables in other classes.
  128.  
  129.   Like I said, don't hold your breath. As technology improves to where
  130. decompilers may become more feasible, optimizers and languages (C++, for
  131. example, would be a significantly tougher language to decompile than C) also
  132. conspire to make them less likely.
  133.  
  134.   For years Unix applications have been distributed in shrouded source form
  135. (machine but not human readable -- all comments and whitespace removed,
  136. variables names all in the form OOIIOIOI, etc.), which has been a quite
  137. adequate means of protecting the author's rights. It's very unlikely that
  138. decompiler output would even be as readable as shrouded source.
  139.  
  140.   A general purpose decompiler is the Holy Grail of tyro programmers. 
  141.  
  142. [by Bob Stout & Jerry Coffin]
  143.