views:

516

answers:

10

Is there a flag or other reliable method to detect if a compiled C++ binary was compiled with optimizations?

I'm okay with compiler-specific solutions.


Edit: This is for a build deployment system, which could accidentally deploy binaries that were not built properly. A water-tight solution is unlikely, but it will save some pain (and money) if this can be detected some of the time.

The compiler will often be gcc, sometimes sun, and if there's a MSVC solution, I don't want to rule that out for the benefit of the community.

+1  A: 

I'm pretty sure there is no way. Unless you have specific knowledge of a function inside that you can check to see if the code sequence is optimal or not.

Goz
+3  A: 

You don't mention a specific platform, so the answer might be yes. But for most common platforms, the answer is no.


anon
+3  A: 

For Microsoft C++, you may be able to assume that optimization was turned off if the executable is referencing the debug versions of the run-time DLLs. It's not a guarantee, though.

Mark Ransom
+8  A: 

Recent versions of GCC have a way to report which flags were used to compile a binary (third bullet point).

There is a related command line switch (--fverbose-asm) that "only records the information in the assembler output file as comments, so the information never reaches the object file." The --frecord-gcc-switches switch "causes the command line that was used to invoke the compiler to be recorded into the object file that is being created."

Max Lybbert
This looks promising, Max. How would I read that information back?
Shmoopty
Unfortunately the information is stored in a platform-dependant manner. I would start with the objdump command line presented at http://www.nabble.com/How-to-check-compiler-options-being-used-td23187071.html#a23187669 .
Max Lybbert
+1  A: 

In my experience, only reliable way is to examine disassembly itself if you don't know the compiler. First try to dump all strings with your favorite tool and look for clues in the linked library names and exported symbols. Failing that, look for common instruction sequences which are mostly get thrown away after optimizations like stack frame prologue and orderly and easy to understand register usage. If tools like ollydbg get confused about where a function starts and ends, there is a good chance binary is compiled with optimizations on.

Examining a decompiler's output may also help. Last time I checked, they were no better than a disassembler but things may have improved since then.

artificialidiot
+3  A: 

Possible Heuristics Solution

If I would be given this task and it would prove it is a resonable task. I would perform "frequency analysis" of the patterns seen in the executable disassembly. As a programmer I am able to distinguish between optimized and unoptimized (debug) code at first glance. I would try to formalize the decision process, with Visual Studio and x86 platform the typical features seen in unoptimized exe would be:

  • functions with full prologue/epilogue (ebp based stack frames)
  • a lot of mov-s from/into memory (all variables placed in the memory)

This is definitely not 100 %, but with longer exe I would exepect the results to be quite reliable.

I assume for other x86 platforms including GCC the rules will be similar, if not the same, and for other platforms similar rules can be found.

Other heuristics like detection runtime library may work as well, depending on compiler settings.

Task sounds silly

That sad, I think such task "smells" and under most circumstances it would be sensible to avoid it completely. If you will provide the real reason behind such task, it is very likely some sensible solution will be found.

Suma
+1  A: 

I'd be surprised if you're not already doing something like this, but:

If you "trust" the build system, put the options used to build into a string you can extract from a running program. (ie, from --version or an about dialog)

This won't detect problems with non-optimized object files getting into the build due to a broken build system, but it will let you easily differentiate a developer build from a release build.

Your release process can then include checking the version to make sure it isn't debug/nonoptimized.

Captain Segfault
A: 

Perhaps you could use a different indicator to determine if you're deploying the right binary. e.g.

  • Debug info: Maybe your release binaries differ in that they dont have debug info? You could check this with elfdump or gdb.
  • Stripped: If your release binaries are stripped you could use "file" to check this
Nick
+2  A: 

The technique we use is simply to create a symbol that appears in every library only if built debug:

// included_by_everything.h
#ifdef (_DEBUG)
extern "C" __declspec( dllexport ) void WasBuiltInDebug() {}
#else
// nothing!
#endif

And then when loading each module at runtime (or in a Perforce trigger) we can ask the binary if it's debug by simply looking for that symbol:

bool IsDebugDLL( HMODULE DllHandle )
{
  // this system call returns a nonzero address if it can 
  // find the symbol, and NULL otherwise:
  return GetProcAddress( DllHandle , "WasBuiltInDebug" );
}
Crashworks
This was what I was thinking about as well but it doesn't address the question directly. The binary may possibly be compiled in release but without optimization turned on.
shoosh
+1  A: 

On Windows you could check if the debug info is stripped from the binary. If you examine the binary image for COFF header, there's a 2 byte flag block called Characteristics at byte offset 18 from COFF header. If the flag

 IMAGE_FILE_DEBUG_STRIPPED = 0x0200

is set then the debugging information is removed from the image file.

This could be done with a trivial 2 byte read from file offset 0x52 and checking if the flag is set.

Flag could be checked as follows

 short flag_block;

 FILE * p_image_file = fopen (...); 

 fseek(p_image_file,0x52,SEEK_SET);

 fread(&flag_block,2,1,p_image_file);

 if(flag_block & 0x0200 > 0)
    then debug info is stripped

You could find the Windows PE format document from Microsoft which describes it in more detail for you to calculate the byte offset to read from etc...

Indeera