Binary incompatibility between RHEL4 and RHEL5

Binaries built on RHEL5 or FC6 do not work on RHEL4 or FC5!

 

 

There are certain specific changes in ELF  binary format causing this issue.

Lets have a quick look!

The ELF binaries have hash section for runtime symbol lookup to be used by dynamic linker. On RHEL4 and older system with older toolchain set, gcc emits code which has the hash section (SHT_HASH) in standard  'sysv' format for symbol resolution.

However on RHEL5, FC6 or newer systems, this section is absent and the same purpose is achieved by a new section(SHT_GNU_HASH) in format called 'gnu'. This is said to have improved the dynamic linking by 50%.

Which section would be present in the binary is dictated by a new linker switch '--hash-style' with possible values gnu, sysv or both. On systems with new tool-chain set, gcc (esp. v 4.1 onwards) passes '--hash-style=gnu' to the linker, by default  and hence the code generated has just SHT_GNU_HASH section. And when this binary is run on older system, it would fail to run, as the dynamic linker on those machine won't find SHT_HASH section, it is looking for.

While on RHEL5 or newer machines, dynamic linker can handle both types of hash format, 'sysv' with less performance than is capable to deliver with 'gnu'.

'readelf' utility can lets us know about this ....

[avinesh@dodge ~]$ readelf -S hello [ on RHEL5]
There are 28 section headers, starting at offset 0x754:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048114 000114 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048128 000128 000020 00   A  0   0  4
  [ 3] .gnu.hash         GNU_HASH        08048148 000148 000020 04   A  4   0  4
  [ 4] .dynsym           DYNSYM          08048168 000168 000050 10   A  5   1  4
  [ 5] .dynstr           STRTAB          080481b8 0001b8 00004a 00   A  0   0  1
  .......................
  .........................


[root@kilbuck ~]# readelf -S hello [ on RHEL4]
There are 29 section headers, starting at offset 0xa80:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000400200  00000200
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             000000000040021c  0000021c
       0000000000000020  0000000000000000   A       0     0     4
  [ 3] .hash             HASH             0000000000400240  00000240
       0000000000000028  0000000000000004   A       4     0     8
  [ 4] .dynsym           DYNSYM           0000000000400268  00000268
       0000000000000078  0000000000000018   A       5     1     8
  [ 5] .dynstr           STRTAB           00000000004002e0  000002e0
       0000000000000053  0000000000000000   A       0     0     1

So, if you want to make binaries which is compatible to older systems as well, then you need to pass the linker option '--hash-style=(sysv|both)' via gcc switch "-Wl" The advised way over here is to use 'sysv' rather than 'both' due to some issues with some older ld.

[avinesh@dodge ~]$ gcc -o hello -Wl,--hash-style=sysv hello.c