Software Design

Design de software em C, C++, Java, etc…

Linux: Portabilidade de binários / Floating Point Exception (SIGFPE)

Problemas de ‘linkagem‘ utilizando binários compilados por diferentes versões do gcc podem complicar bastante a nossa vida.

Um problema que aconteceu recentemente comigo foi quando compilei um binário que utiliza uma biblioteca proprietária legada. Utilizando o gcc 3.4.5 meu binário conseguiu ‘linkar’ corretamente com todas as bibliotecas na máquina de build, porém ao tentar executar em uma máquina de testes, recebi a seguinte mensagem:

Floating Point Exception

Tentei utilizar o gdb e o strace mas não obtive muito mais informação além do signal SIGFPE.

Acabei descobrindo que isso é causado por uma alteração feita pela RedHat em seus GCC que gera a sessão .gnu.hash ao invés de .hash. Essa alteração foi feita para melhorar o tempo de carregamento do binário ( a performance melhora em torno de 50% segundo benchmarks feitos por eles ) no entanto torna binário incompatível com loaders mais antigos que conhecem apenas a sessão .hash

Para verificar qual das sessões foi adicionada ao seu binário (biblioteca ou executável) utilize:

$ objdump -x libglib-2.0.so | less
Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .gnu.hash     00001b9c  008800d4  008800d4  000000d4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .dynsym       00004690  00881c70  00881c70  00001c70  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

Neste caso, o ELF contém apenas a sessão .gnu.hash, isso vai fazer com que ele funcione corretamente em distribuições mais novas que possuem suporte à essa sessão, no entanto não vai funcionar em linux mais antigos.

Tem duas formas de resolver esse problema:

1) forçar o seu linker a utilizar apenas a sessão .hash. Adicione o seguinte parâmetro ao gcc/g++ -Wl,--hash-style,sysv. Ex.:

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  2 .hash         000102f4  08048168  08048168  00000168  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

2) Também é possível gerar as 2 sessões: -Wl,--hash-style,both. Desta forma o ELF fica da seguinte forma:

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .hash         00000860  000000b4  000000b4  000000b4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .gnu.hash     00000554  00000914  00000914  00000914  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

Eu prefiro a segunda opção porque ela permite a otimização feita pelo linker (.gnu.hash) enquanto mantém compatibilidade com sistemas mais antigos que não conhecem a sessão .gnu.hash

Detalhe: você precisa verificar todas as bibliotecas utilizadas pelo seu binário, se apenas uma delas estiver utilizando a sessão .gnu.hash você precisará recompilar essa biblioteca.

Referências:

  1. http://lwn.net/Articles/192624/
  2. http://www.evanjones.ca/portable-linux-binaries.html
  3. https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

Informação

Publicado às janeiro 7, 2014 por em C++, Linux, Unix e marcado , , , , , .
%d blogueiros gostam disto: