3

Given the program

$ cat main.cpp 
#ifndef WITH_LOCAL_STATIC
static int y = 0;
#endif

class X {
  public:
    void foo() {
#ifdef WITH_LOCAL_STATIC
        static int y = 0;
#endif
        ++y;
    }
};

int main() {
    X().foo();
    return 0;
}

compiled in two different ways:

$ g++ main.cpp -o global
$ g++ main.cpp -DWITH_LOCAL_STATIC -o local

I get two different binary formats:

$ file local
local: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x8d8e998601e44115b5fa6c0e71f3ed97cb13a0bd, not stripped
$ file global
global: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x3481ba7c6969ed9d1bd1c8ce0f052d574023d488, not stripped

Can somebody explain why I get ELFOSABI_LINUX in one case, but ELFOSABI_NONE in the other? Compiler is gcc 4.7.2

The background is that in my environment, the loader rejects executables that are not ELFOSABI_NONE.

Meinersbur
  • 7,881
  • 1
  • 27
  • 29

1 Answers1

0

The GNU/Linux format superseded the System V object file format, and your gcc believes that the minimum OS/ABI where your executable could be run is GNU/Linux.

That usually happens when your program has symbols whose type is STT_GNU_IFUNC (a GNU extensions that denotes an indirect function), and these symbols are typically coming from glibc. When you introduced the local static variable gcc added (more) code to the translation unit to handle its initialisation and destruction (along the lines of _ZZZ__static_initialization_and_destruction_iii), and this is where the relevant parts of glibc likely came into play.

First of all, your best bet is to follow the advice in this question: How to avoid STT_GNU_IFUNC symbols in your binary?

Second, I have to say that on my box, both the old gcc 4.4 and the new clang 3.4 generate the global and local binaries as SYSV standard ELFs, so either your test case is missing more of the relevant bits and pieces, or you are possibly using a custom configured and built gcc, custom linker, or a non-standard glibc.

More avenues that you can pursue to investigate how did you end up with these GNU indirect functions in your binary:

  • Run nm on your binary and identify the indirect symbols, they should have the i type. (See below.)
  • Generate a link map and/or an assembly output and trace these indirect symbols to the specifics of your code.
  • Additionally check if locating glibc with ldd -v $(type -p gcc) points you to a non-standard libc

i - For PE format files this indicates that the symbol is in a section specific to the implementation of DLLs. For ELF format files this indicates that the symbol is an indirect function. This is a GNU extension to the standard set of ELF symbol types. It indicates a symbol > which if referenced by a relocation does not evaluate to its address, but instead must be invoked at runtime. The runtime execution will then return the value to be used in the relocation.

https://sourceware.org/binutils/docs/binutils/nm.html

Community
  • 1
  • 1
mockinterface
  • 14,452
  • 5
  • 28
  • 49