No Windows, quando compilo o código C / C ++ em um projeto DLL no MSVC, estou recebendo 2 arquivos:
MyDll.dll
MyDll.lib
onde, tanto quanto eu entendo, MyDll.lib
contém algum tipo de tabela de ponteiros indicando os locais das funções na dll. Ao usar essa dll, digamos em um arquivo exe, MyDll.lib
é incorporada ao arquivo exe durante o vínculo, portanto, em tempo de execução, ele "sabe" onde as funções estão localizadas MyDll.dll
e pode usá-las.
Mas se eu compilar o mesmo código no Linux, estou obtendo apenas um arquivo MySo.so
sem MySo.a
(o equivalente ao lib
arquivo no Linux). Como um arquivo executável no Linux sabe onde as funções estão localizadas MySo.so
se nada estiver incorporado durante a vinculação?
O vinculador do MSVC pode vincular arquivos de objetos (.obj) e bibliotecas de objetos (.lib) para produzir um .EXE ou um .DLL.
Para vincular a uma DLL, o processo no MSVC é usar a chamada biblioteca de importação (.LIB) que atua como uma cola entre os nomes das funções C e a tabela de exportação da DLL (em uma DLL, uma função pode ser exportada por nome ou por ordinal - este último costumava ser usado para APIs não documentadas).
No entanto, na maioria dos casos, a tabela de exportação DLL possui todos os nomes das funções e, portanto, a biblioteca de importação (.LIB) contém informações amplamente redundantes (" função de importação ABC -> função exportada ABC ", etc).
É até possível gerar um .LIB a partir de um .DLL existente.
Os vinculadores em outras plataformas não possuem esse "recurso" e podem vincular-se diretamente às bibliotecas dinâmicas.
fonte
A diferença que você está vendo é mais um detalhe de implementação - sob o capô, Linux e Windows funcionam da mesma forma - o código chama uma função stub que está estaticamente vinculada no seu executável e esse stub carrega DLL / shlib, se necessário (em caso de atraso) carregando , caso contrário, a biblioteca é carregada quando o programa inicia) e (na primeira chamada) resolve o símbolo via
GetProcAddress
/dlsym
.A única diferença é que no Linux essas funções de stub (chamadas de stubs PLT) são geradas dinamicamente quando você vincula seu aplicativo à biblioteca dinâmica (a biblioteca contém informações suficientes para gerá-los), enquanto no Linux elas são geradas quando a própria DLL é criado, em um
.lib
arquivo separado .As duas abordagens são tão semelhantes que é realmente possível imitar as bibliotecas de importação do Windows no Linux (consulte o projeto Implib.so ).
fonte
No Linux, você passa
MySo.so
para o vinculador e ele pode extrair apenas o necessário para a fase do link, colocando uma referênciaMySo.so
necessária no tempo de execução.fonte
.dll
ou.so
são bibliotecas compartilhadas (vinculadas em tempo de execução), enquanto.a
e.lib
é uma biblioteca estática (vinculada em tempo de compilação). Isso não faz diferença entre Windows e Linux.A diferença é como eles são tratados. Nota: a diferença está apenas nos costumes, como eles são usados. Não seria muito difícil criar o Linux no modo Windows e vice-versa, exceto que praticamente ninguém faz isso.
Se usarmos uma dll ou chamarmos uma função mesmo de nosso próprio binário, haverá uma maneira simples e clara. Por exemplo, em C, vemos que:
No entanto, no nível ASM, pode haver muitas diferenças. Por exemplo, em x86, um
call
código de operação é executado e o42
dado na pilha. Ou em alguns registros. Ou em qualquer lugar. Ninguém sabe que antes de escrever a dll , como ela será usada. Ou como os projetos vão querer usá-lo, possivelmente escrito com um compilador (ou em um idioma!) Que nem existe agora (ou é desconhecido para os desenvolvedores da dll).Por exemplo, por padrão, C e Pascal colocam os argumentos (e obtêm os valores de retorno) da pilha - mas eles estão fazendo isso em ordem diferente . Você também pode trocar argumentos entre suas funções nos registradores por alguma otimização - dependente do compilador -.
Como você vê corretamente, o costume do Windows é criar uma dll, também criamos um mínimo
.a
/.lib
com ela. Essa biblioteca estática mínima é apenas um invólucro, os símbolos (funções) dessa dll são alcançados através dela. Isso faz as conversões de chamada no nível asm necessárias.Sua vantagem é a compatibilidade. Sua desvantagem é que, se você tiver apenas uma .dll, poderá ter dificuldade em descobrir como é que suas funções serão chamadas. Isso torna o uso de dlls uma tarefa de hacking, se o desenvolvedor da dll não fornecer a você
.a
. Assim, ele serve principalmente para fins de fechamento, por exemplo, portanto é mais fácil obter dinheiro extra para os SDKs.Outra desvantagem é que, mesmo que você use uma biblioteca dinâmica, é necessário compilar esse pequeno invólucro estaticamente.
No Linux, a interface binária das DLLs é padrão e segue a convenção C. Portanto, não
.a
é necessário e há compatibilidade binária entre as bibliotecas compartilhadas; em troca, não temos as vantagens do costume da microsoft.fonte