Por que e como algumas bibliotecas compartilhadas são executáveis, como se fossem executáveis?

53

Em sistemas Linux de 32 bits, invocando isto

$ /lib/libc.so.6

e em sistemas de 64 bits,

$ /lib/x86_64-linux-gnu/libc.so.6

em um shell, fornece uma saída assim:

GNU C Library stable release version 2.10.1, by Roland McGrath et al.
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.4.0 20090506 (Red Hat 4.4.0-4).
Compiled on a Linux >>2.6.18-128.4.1.el5<< system on 2009-08-19.
Available extensions:
    The C stubs add-on version 2.1.2.
    crypt add-on version 2.1 by Michael Glad and others
    GNU Libidn by Simon Josefsson
    Native POSIX Threads Library by Ulrich Drepper et al
    BIND-8.2.3-T5B
    RT using linux kernel aio
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.

Por que e como isso acontece e como é possível fazer o mesmo em outras bibliotecas compartilhadas?

Eu olhei para /usr/lib para encontrar executáveis e encontrei /usr/lib/libvlc.so.5.5.0 . A execução levou a uma falha de segmentação . : - /

    
por Ho1 15.08.2015 / 15:32

2 respostas

48

Essa biblioteca possui uma função main() ou ponto de entrada equivalente e foi compilada de tal maneira que é útil tanto como um executável quanto como um objeto compartilhado.

Aqui está uma sugestão sobre como fazer isso, embora isso não aconteça trabalhe para mim.

Aqui está outra em uma resposta a uma pergunta semelhante sobre o SO , que vou plagiar, ajustar e adicionar descaradamente um pouco de explicação.

Primeiro, fonte de nossa biblioteca de exemplos, test.c :

#include <stdio.h>                  

void sayHello (char *tag) {         
    printf("%s: Hello!\n", tag);    
}                                   

int main (int argc, char *argv[]) { 
    sayHello(argv[0]);              
    return 0;                       
}                   

Compile isso:

gcc -fPIC -pie -o libtest.so test.c -Wl,-E

Aqui, estamos compilando uma biblioteca compartilhada ( -fPIC ), mas dizendo ao vinculador que é um executável regular ( -pie ), e para tornar sua tabela de símbolos exportável ( -Wl,-E ), de modo que possa ser útilmente ligado.

E, embora file diga que é um objeto compartilhado, ele funciona como um executável:

> ./libtest.so 
./libtest.so: Hello!

Agora precisamos ver se realmente pode ser dinamicamente vinculado. Um programa de exemplo, program.c :

#include <stdio.h>

extern void sayHello (char*);

int main (int argc, char *argv[]) {
    puts("Test program.");
    sayHello(argv[0]);
    return 0;
}

Usar extern nos poupa de criar um cabeçalho. Agora compile isso:

gcc program.c -L. -ltest

Antes de podermos executá-lo, precisamos adicionar o caminho de libtest.so para o carregador dinâmico:

export LD_LIBRARY_PATH=./

Agora:

> ./a.out
Test program.
./a.out: Hello!

E ldd a.out mostrará a vinculação a libtest.so .

Note que duvido que a glibc seja realmente compilada, já que provavelmente não é tão portável quanto a própria glibc (veja man gcc em relação às opções -fPIC e -pie ), mas ela demonstra o mecanismo básico . Para os detalhes reais você teria que olhar para o makefile de origem.

    
por 15.08.2015 / 19:13
20

Vamos mergulhar para obter uma resposta no repositório glibc aleatório no github. Esta versão fornece um "banner" no arquivo version.c : link

No mesmo arquivo, há alguns pontos interessantes: __libc_print_version a função que fornece a impressão para stdin mesmo texto e símbolo __libc_main (void) que é documentado como um ponto de entrada. Então, esse símbolo é chamado ao executar a biblioteca.

Então, como o linker / compilador sabe que esta é exatamente a função de ponto de entrada?

Vamos mergulhar no makefile. Em sinalizadores de vinculação, há um sinalizador interessante: link

# Give libc.so an entry point and make it directly runnable itself.
LDFLAGS-c.so += -e __libc_main

Portanto, este é o sinalizador de vinculador para definir o ponto de entrada na biblioteca. Ao criar uma biblioteca, você pode fornecer -e function_name para o comportamento executável da criação do vinculador. O que isso realmente faz? Vamos olhar em manual (um pouco datado, mas ainda válido): link

The linker command language includes a command specifically for defining the first executable instruction in an output file (its entry point). Its argument is a symbol name:

ENTRY(symbol)

Like symbol assignments, the ENTRY command may be placed either as an independent command in the command file, or among the section definitions within the SECTIONS command--whatever makes the most sense for your layout.

ENTRY is only one of several ways of choosing the entry point. You may indicate it in any of the following ways (shown in descending order of priority: methods higher in the list override methods lower down).

the '-e' entry command-line option;
the ENTRY(symbol) command in a linker control script;
the value of the symbol start, if present;
the address of the first byte of the .text section, if present;
The address 0. 

For example, you can use these rules to generate an entry point with an assignment statement: if no symbol start is defined within your input files, you can simply define it, assigning it an appropriate value---

start = 0x2020;

The example shows an absolute address, but you can use any expression. For example, if your input object files use some other symbol-name convention for the entry point, you can just assign the value of whatever symbol contains the start address to start:

start = other_symbol ;

Realmente o ld linker cria um executável com a função de ponto de entrada se você fornecer a opção de linha de comando -e (a solução mais prática), fornecer o símbolo de função start ou injetar o endereço de símbolo no montador.

No entanto, por favor note que claramente não é garantido que funcione com outros linkers (eu não sei se a lld do llvm tem o mesmo sinalizador). Por que isso deve ser útil para outros fins que não fornecer informações sobre o arquivo, não sei.

    
por 15.08.2015 / 19:37