Pergunta

Costumo ouvir os termos 'estaticamente vinculados' e 'vinculados dinamicamente', geralmente em referência ao código escrito em C, C ++ ou C#. O que eles são, do que exatamente eles estão falando e o que estão vinculando?

Foi útil?

Solução

Existem (na maioria dos casos, o desconto do código interpretado) duas etapas para obter do código -fonte (o que você escreve) para o código executável (o que você executa).

O primeiro é a compilação que transforma o código -fonte em módulos de objeto.

O segundo, vinculando, é o que combina módulos de objeto para formar um executável.

A distinção é feita para, entre outras coisas, permitindo que as bibliotecas de terceiros sejam incluídas em seu executável sem que você veja o código -fonte deles (como bibliotecas para acesso ao banco de dados, comunicações de rede e interfaces gráficas de usuário) ou para compilar código em diferentes linguagens ( C e código de montagem, por exemplo) e depois vincular todos eles.

Quando você estatisticamente Link um arquivo em um executável, o conteúdo desse arquivo é incluído no horário do link. Em outras palavras, o conteúdo do arquivo é fisicamente inserido no executável que você executará.

Quando você vincular dinamicamente, um ponteiro para o arquivo que está sendo vinculado (o nome do arquivo do arquivo, por exemplo) está incluído no executável e o conteúdo do referido arquivo não está incluído no horário do link. É só quando você mais tarde corre O executável em que esses arquivos vinculados dinamicamente são comprados e são comprados apenas na cópia da memória do executável, não o do disco.

É basicamente um método de vinculação diferida. Há um uniforme mais O método diferido (chamado de ligação tardia em alguns sistemas) que não trará o arquivo dinamicamente vinculado até que você realmente tente chamar uma função dentro dele.

Os arquivos estaticamente ligados são 'bloqueados' para o executável na hora do link para que eles nunca mudem. Um arquivo dinamicamente vinculado referenciado por um executável pode alterar apenas substituindo o arquivo no disco.

Isso permite que as atualizações da funcionalidade sem precisar re-vincular o código; O carregador re-liga toda vez que você o executa.

Isso é bom e ruim - por um lado, permite atualizações e correções de bugs mais fáceis; por outro A menção, pois os aplicativos podem ser quebrados se você substituir uma biblioteca dinamicamente vinculada por uma que não é compatível (a propósito, os desenvolvedores que fazem isso devem esperar ser caçados e punidos severamente, a propósito).


Como um exemplo, vejamos o caso de um usuário compilar seus main.c Arquivo para vinculação estática e dinâmica.

Phase     Static                    Dynamic
--------  ----------------------    ------------------------
          +---------+               +---------+
          | main.c  |               | main.c  |
          +---------+               +---------+
Compile........|.........................|...................
          +---------+ +---------+   +---------+ +--------+
          | main.o  | | crtlib  |   | main.o  | | crtimp |
          +---------+ +---------+   +---------+ +--------+
Link...........|..........|..............|...........|.......
               |          |              +-----------+
               |          |              |
          +---------+     |         +---------+ +--------+
          |  main   |-----+         |  main   | | crtdll |
          +---------+               +---------+ +--------+
Load/Run.......|.........................|..........|........
          +---------+               +---------+     |
          | main in |               | main in |-----+
          | memory  |               | memory  |
          +---------+               +---------+

Você pode ver no caso estático que o programa principal e a biblioteca de tempo de execução C estão vinculados no horário do link (pelos desenvolvedores). Como o usuário normalmente não pode re-vincular o executável, eles estão presos ao comportamento da biblioteca.

No caso dinâmico, o programa principal está vinculado à biblioteca de importação de tempo de execução C (algo que declara o que está na biblioteca dinâmica, mas na verdade não definir isto). Isso permite que o vinculador vincule mesmo que o código real esteja faltando.

Em seguida, em tempo de execução, o carregador de sistema operacional faz uma ligação tardia do programa principal com a DLL de tempo de execução C (Biblioteca de Link Dynamic ou biblioteca compartilhada ou outra nomenclatura).

O proprietário do tempo de execução C pode cair em uma nova DLL a qualquer momento para fornecer atualizações ou correções de bugs. Como afirmado anteriormente, isso tem vantagens e desvantagens.

Outras dicas

Eu acho que uma boa resposta para esta pergunta deve explicar o que vincular é.

Quando você compila algum código C (por exemplo), ele é traduzido para a linguagem da máquina. Apenas uma sequência de bytes que, quando executada, faz com que o processador adicione, subtrair, comparar, "goto", ler memória, escrever memória, esse tipo de coisa. Esse material é armazenado nos arquivos do objeto (.O).

Agora, há muito tempo, os cientistas da computação inventaram essa coisa de "sub -rotina". Execute-se esse corte de código e retorno-rastrear-se. Não demorou muito para que eles percebessem que as sub -rotinas mais úteis poderiam ser armazenadas em um local especial e usadas por qualquer programa que precisasse delas.

Agora, nos primeiros dias, os programadores teriam que perfurar o endereço da memória em que essas sub -rotinas estavam localizadas. Algo como CALL 0x5A62. Isso foi tedioso e problemático, caso esses endereços de memória precisem ser alterados.

Então, o processo foi automatizado. Você escreve um programa que liga printf(), e o compilador não conhece o endereço de memória de printf. Então o compilador apenas escreve CALL 0x0000, e adiciona uma nota ao arquivo de objeto dizendo "deve substituir este 0x0000 pelo local da memória de printf".

Link estático significa que o programa de ligação (o GNU é chamado LD) adicionar printfo código da máquina diretamente para o seu arquivo executável e altera o 0x0000 para o endereço de printf. Isso acontece quando seu executável é criado.

A ligação dinâmica significa que a etapa acima não acontece. O arquivo executável ainda tem uma nota que diz "deve substituir 0x000 pelo local da memória do printf". O carregador do sistema operacional precisa encontrar o código printf, carregá -lo na memória e corrigir o endereço de chamada, Cada vez que o programa é executado.

É comum os programas chamarem algumas funções que serão estaticamente vinculadas (funções de biblioteca padrão como printf geralmente estão estaticamente vinculados) e outras funções que são dinamicamente vinculadas. Os estáticos "se tornam parte" do executável e dos dinâmicos "ingressam" quando o executável é executado.

Existem vantagens e desvantagens nos dois métodos, e existem diferenças entre os sistemas operacionais. Mas como você não perguntou, eu terminarei isso aqui.

As bibliotecas estaticamente vinculadas estão vinculadas no momento da compilação. Bibliotecas dinamicamente vinculadas são carregadas no tempo de execução. Estático vincular as bolas da biblioteca no seu executável. A ligação dinâmica apenas assa em uma referência à biblioteca; Os bits para a biblioteca dinâmica existem em outros lugares e podem ser trocados mais tarde.

Porque nenhuma das postagens acima realmente mostre como Para vincular algo estaticamente e ver que você fez corretamente, para resolver este problema:

Um programa C simples

#include <stdio.h>

int main(void)
{
    printf("This is a string\n");
    return 0;
}

Vincular dinamicamente o programa C

gcc simpleprog.c -o simpleprog

E corra file no binário:

file simpleprog 

E isso mostrará que está dinamicamente vinculado a algo como:

"simpleprog: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0xf715572611a8b04f686809d90d1c0d75c6028f0f, not stripped"

Em vez disso, vamos vincular estaticamente o programa desta vez:

gcc simpleprog.c -static -o simpleprog

A execução do arquivo neste binário estaticamente vinculado será exibido:

file simpleprog 

"SimpleProg: ELF 64 bits LSB Executável, x86-64, versão 1 (GNU/Linux), estaticamente vinculado, para GNU/Linux 2.6.26, BuildID [sha1] = 0x8c0b12250801c5a7c7434647b7dc65a644d61213banbdc65a62501213s,)

E você pode ver que está feliz estaticamente ligado. Infelizmente, no entanto, nem todas as bibliotecas são simples de vincular -se estaticamente dessa maneira e podem exigir um esforço prolongado usando libtool ou vincular o código do objeto e as bibliotecas C manualmente.

Felizmente, muitas bibliotecas C incorporadas como musl oferecer opções de vinculação estática para quase todos se não todos de suas bibliotecas.

Agora strace O binário que você criou e pode ver que não há bibliotecas acessadas antes do início do programa:

strace ./simpleprog

Agora compare com a saída de strace No programa dinamicamente vinculado e você verá que a Strace da versão estaticamente vinculada é muito mais curta!

(Eu não sei C#, mas é interessante ter um conceito de vinculação estática para uma linguagem VM)

A ligação dinâmica envolve saber como encontrar uma funcionalidade necessária que você possui apenas uma referência do seu programa. Você é o tempo de execução do idioma ou o sistema operacional pesquise um código no sistema de arquivos, rede ou cache de código compilado, correspondendo à referência e, em seguida, toma várias medidas para integrá -lo à imagem do programa na memória, como a realocação. Todos eles são feitos no tempo de execução. Isso pode ser feito manualmente ou pelo compilador. Há capacidade de atualizar com o risco de bagunçar (a saber, DLL HELL).

A ligação estática é feita no momento da compilação que você informa ao compilador onde estão todas as peças funcionais e instrui -as a integrá -las. Não há pesquisa, ambiguidade, nenhuma capacidade de atualizar sem recompile. Todas as suas dependências são fisicamente uma com a imagem do seu programa.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top