Eu nunca entendi claramente o que é uma ABI. Por favor, não me aponte para um artigo da Wikipedia. Se eu pudesse entender, não estaria aqui postando uma postagem tão longa.
Esta é a minha mentalidade sobre diferentes interfaces:
Um controle remoto da TV é uma interface entre o usuário e a TV. É uma entidade existente, mas inútil (não fornece nenhuma funcionalidade) por si só. Toda a funcionalidade de cada um desses botões no controle remoto é implementada no aparelho de televisão.
Interface: é uma camada de "entidade existente" entre
functionality
econsumer
dessa funcionalidade. Uma interface por si só não faz nada. Apenas invoca a funcionalidade por trás.Agora, dependendo de quem é o usuário, existem diferentes tipos de interfaces.
Os comandos da CLI (Command Line Interface) são as entidades existentes, o consumidor é o usuário e a funcionalidade está por trás.
functionality:
minha funcionalidade de software que resolve algum objetivo para o qual estamos descrevendo essa interface.
existing entities:
comandos
consumer:
do utilizadorJanela da interface gráfica do usuário (GUI) , botões, etc. são as entidades existentes e, novamente, o consumidor é o usuário e a funcionalidade está por trás.
functionality:
minha funcionalidade de software que resolve algum problema para o qual estamos descrevendo essa interface.
existing entities:
janela, botões etc.
consumer:
do utilizadorAs funções da Interface de programação de aplicativos (API) (ou, para ser mais correto), interfaces (na programação baseada em interface) são as entidades existentes, o consumidor aqui é outro programa que não é usuário e, novamente, a funcionalidade está por trás dessa camada.
functionality:
minha funcionalidade de software que resolve algum problema para o qual estamos descrevendo essa interface.
existing entities:
funções, interfaces (matriz de funções).
consumer:
outro programa / aplicativo.Interface Binária de Aplicativo (ABI) Aqui é onde meu problema começa.
functionality:
???
existing entities:
???
consumer:
???
- Escrevi software em idiomas diferentes e forneci diferentes tipos de interfaces (CLI, GUI e API), mas não tenho certeza se já forneci alguma ABI.
As ABIs abrangem detalhes como
- tipo de dados, tamanho e alinhamento;
- a convenção de chamada, que controla como os argumentos das funções são passados e retornam os valores recuperados;
- os números de chamada do sistema e como um aplicativo deve fazer chamadas do sistema para o sistema operacional;
Outras ABIs padronizam detalhes como
- o nome C ++ desconfigurado,
- propagação de exceção e
- convenção de chamada entre compiladores na mesma plataforma, mas não requer compatibilidade entre plataformas.
Quem precisa desses detalhes? Por favor, não diga o sistema operacional. Eu sei programação de montagem. Eu sei como funciona o link e o carregamento. Eu sei exatamente o que acontece por dentro.
Por que o nome C ++ mutilado apareceu? Eu pensei que estávamos conversando no nível binário. Por que os idiomas entram?
De qualquer forma, baixei o [PDF] System V Application Binary Interface Edition 4.1 (18-03-2007) para ver exatamente o que ele contém. Bem, a maior parte não fazia sentido.
Por que contém dois capítulos (4 e 5) para descrever o formato de arquivo ELF ? De fato, esses são os únicos dois capítulos significativos dessa especificação. O restante dos capítulos é "específico do processador". Enfim, eu acho que é um tópico completamente diferente. Por favor, não diga que as especificações de formato de arquivo ELF são a ABI. Não se qualifica para ser uma interface de acordo com a definição.
Eu sei, já que estamos falando em um nível tão baixo, deve ser muito específico. Mas não tenho certeza de como é específica a "arquitetura do conjunto de instruções (ISA)"?
Onde posso encontrar a ABI do Microsoft Windows?
Então, essas são as principais consultas que estão me incomodando.
Respostas:
Uma maneira fácil de entender "ABI" é compará-lo com "API".
Você já está familiarizado com o conceito de uma API. Se você deseja usar os recursos de, digamos, alguma biblioteca ou seu sistema operacional, programa contra uma API. A API consiste em tipos / estruturas de dados, constantes, funções etc. que você pode usar no seu código para acessar a funcionalidade desse componente externo.
Uma ABI é muito semelhante. Pense nisso como a versão compilada de uma API (ou como uma API no nível da linguagem de máquina). Ao escrever o código-fonte, você acessa a biblioteca por meio de uma API. Depois que o código é compilado, seu aplicativo acessa os dados binários na biblioteca através da ABI. A ABI define as estruturas e métodos que seu aplicativo compilado usará para acessar a biblioteca externa (exatamente como a API), apenas em um nível inferior. Sua API define a ordem em que você passa argumentos para uma função. Sua ABI define a mecânica de comoesses argumentos são passados (registros, pilha, etc.). Sua API define quais funções fazem parte da sua biblioteca. Sua ABI define como seu código é armazenado dentro do arquivo da biblioteca, para que qualquer programa que utilize sua biblioteca possa localizar e executar a função desejada.
As ABIs são importantes quando se trata de aplicativos que usam bibliotecas externas. As bibliotecas estão cheias de código e outros recursos, mas seu programa precisa saber como localizar o que precisa dentro do arquivo da biblioteca. Sua ABI define como o conteúdo de uma biblioteca é armazenado dentro do arquivo, e seu programa usa a ABI para pesquisar no arquivo e encontrar o que ele precisa. Se tudo no seu sistema estiver em conformidade com a mesma ABI, qualquer programa poderá trabalhar com qualquer arquivo de biblioteca, independentemente de quem os criou. Linux e Windows usam ABIs diferentes, portanto, um programa Windows não saberá como acessar uma biblioteca compilada para Linux.
Às vezes, as alterações ABI são inevitáveis. Quando isso acontece, qualquer programa que use essa biblioteca não funcionará, a menos que seja recompilado para usar a nova versão da biblioteca. Se a ABI for alterada, mas a API não for alterada, as versões antiga e nova da biblioteca serão denominadas "compatíveis com a origem". Isso implica que, embora um programa compilado para uma versão da biblioteca não funcione com o outro, o código-fonte escrito para um funcionará para o outro se for compilado novamente.
Por esse motivo, os desenvolvedores tendem a tentar manter sua ABI estável (para minimizar as interrupções). Manter uma ABI estável significa não alterar as interfaces de função (tipo e número de retorno, tipos e ordem dos argumentos), definições de tipos de dados ou estruturas de dados, constantes definidas, etc. Novas funções e tipos de dados podem ser adicionados, mas os existentes devem permanecer o mesmo. Se, por exemplo, sua biblioteca usar números inteiros de 32 bits para indicar o deslocamento de uma função e você alternar para números inteiros de 64 bits, o código já compilado que usa essa biblioteca não acessará corretamente esse campo (ou qualquer outro) . O acesso aos membros da estrutura de dados é convertido em endereços e compensações de memória durante a compilação e se a estrutura de dados mudar,
Uma ABI não é necessariamente algo que você fornecerá explicitamente, a menos que esteja executando um trabalho de design de sistemas de nível muito baixo. Também não é específico do idioma, já que (por exemplo) um aplicativo C e um aplicativo Pascal podem usar a mesma ABI após serem compilados.
Editar:Em relação à sua pergunta sobre os capítulos sobre o formato de arquivo ELF nos documentos do SysV ABI: A razão pela qual essas informações estão incluídas é porque o formato ELF define a interface entre sistema operacional e aplicativo. Quando você instrui o sistema operacional a executar um programa, ele espera que o programa seja formatado de uma certa maneira e (por exemplo) espera que a primeira seção do binário seja um cabeçalho ELF contendo certas informações com desvios de memória específicos. É assim que o aplicativo comunica informações importantes sobre si mesmo ao sistema operacional. Se você criar um programa em um formato binário que não seja ELF (como a.out ou PE), um SO que espere aplicativos formatados em ELF não poderá interpretar o arquivo binário ou executar o aplicativo.
IIRC, o Windows atualmente usa o formato Portable Executable (ou, PE). Existem links na seção "links externos" dessa página da Wikipedia com mais informações sobre o formato PE.
Além disso, em relação à sua observação sobre a troca de nomes em C ++: Ao localizar uma função em um arquivo de biblioteca, a função geralmente é procurada por nome. O C ++ permite sobrecarregar os nomes das funções, portanto, somente o nome não é suficiente para identificar uma função. Os compiladores C ++ têm suas próprias maneiras de lidar com isso internamente, chamado de manipulação de nomes . Uma ABI pode definir uma maneira padrão de codificar o nome de uma função para que os programas criados com um idioma ou compilador diferente possam localizar o que precisam. Ao usar
extern "c"
em um programa C ++, você está instruindo o compilador a usar uma maneira padronizada de gravar nomes que seja compreensível por outro software.fonte
Se você conhece montagem e como as coisas funcionam no nível do SO, está em conformidade com uma determinada ABI. A ABI governa coisas como a passagem de parâmetros, onde os valores de retorno são colocados. Para muitas plataformas, há apenas uma ABI para escolher e, nesses casos, a ABI é apenas "como as coisas funcionam".
No entanto, a ABI também governa coisas como o modo como as classes / objetos são dispostos em C ++. Isso é necessário se você deseja passar referências de objeto através dos limites do módulo ou se deseja misturar código compilado com diferentes compiladores.
Além disso, se você tiver um sistema operacional de 64 bits que possa executar binários de 32 bits, terá ABIs diferentes para código de 32 e 64 bits.
Em geral, qualquer código vinculado ao mesmo executável deve estar em conformidade com a mesma ABI. Se você deseja se comunicar entre códigos usando ABIs diferentes, use algum tipo de RPC ou protocolos de serialização.
Eu acho que você está se esforçando demais para espremer diferentes tipos de interfaces em um conjunto fixo de características. Por exemplo, uma interface não precisa necessariamente ser dividida em consumidores e produtores. Uma interface é apenas uma convenção pela qual duas entidades interagem.
As ABIs podem ser (parcialmente) independentes de ISA. Alguns aspectos (como convenções de chamada) dependem do ISA, enquanto outros (como o layout da classe C ++) não.
Uma ABI bem definida é muito importante para as pessoas que escrevem compiladores. Sem uma ABI bem definida, seria impossível gerar código interoperável.
EDIT: Algumas notas para esclarecer:
fonte
Você realmente não precisa de uma ABI, se--
Um resumo simplificado:
A ABI é um conjunto de regras que os compiladores e vinculadores seguem para compilar seu programa para que funcione corretamente. As ABIs abrangem vários tópicos:
Examinando mais profundamente a convenção de convocação, que considero o núcleo de uma ABI:
A própria máquina não tem conceito de "funções". Quando você escreve uma função em uma linguagem de alto nível como c, o compilador gera uma linha de código de montagem como
_MyFunction1:
. Este é um rótulo , que acabará sendo resolvido em um endereço pelo assembler. Este rótulo marca o "início" da sua "função" no código de montagem. No código de alto nível, quando você "chama" essa função, o que realmente está fazendo é fazer com que a CPU salte para o endereço desse rótulo e continue executando lá.Em preparação para o salto, o compilador deve fazer um monte de coisas importantes. A convenção de chamada é como uma lista de verificação que o compilador segue para fazer todas essas coisas:
_MyFunction1:
). Neste ponto, você pode considerar a CPU "na" sua "função".Existem muitas ABIs / convenções de chamada diferentes. Alguns principais são:
Aqui está uma ótima página que mostra as diferenças na montagem gerada ao compilar ABIs diferentes.
Outra coisa a mencionar é que uma ABI não é relevante apenas dentro do módulo executável do seu programa. É também usado pelo vinculador para garantir que seu programa chama funções de biblioteca corretamente. Você tem várias bibliotecas compartilhadas em execução no seu computador e, desde que seu compilador saiba qual ABI cada um usa, ele poderá chamar suas funções corretamente, sem explodir a pilha.
Seu compilador entender como chamar funções de biblioteca é extremamente importante. Em uma plataforma hospedada (ou seja, onde o sistema operacional carrega programas), seu programa não pode nem piscar sem fazer uma chamada ao kernel.
fonte
Uma interface binária de aplicativo (ABI) é semelhante a uma API, mas a função não está acessível ao chamador no nível do código-fonte. Somente uma representação binária está acessível / disponível.
As ABIs podem ser definidas no nível da arquitetura do processador ou no nível do SO. As ABIs são padrões a serem seguidos pela fase gerador de código do compilador. O padrão é fixado pelo sistema operacional ou pelo processador.
Funcionalidade: Defina o mecanismo / padrão para fazer chamadas de função independentes da linguagem de implementação ou de um compilador / vinculador / cadeia de ferramentas específico. Forneça o mecanismo que permite JNI, ou uma interface Python-C, etc.
Entidades existentes: Funções no formato de código de máquina.
Consumidor: Outra função (incluindo uma em outro idioma, compilada por outro compilador ou vinculada por outro vinculador).
fonte
Funcionalidade: um conjunto de contratos que afetam o compilador, gravadores de montagem, o vinculador e o sistema operacional. Os contratos especificam como as funções são dispostas, onde os parâmetros são passados, como os parâmetros são passados, como o retorno da função funciona. Geralmente são específicos para uma tupla (arquitetura do processador, sistema operacional).
Entidades existentes: layout de parâmetros, semântica de funções, alocação de registros. Por exemplo, as arquiteturas ARM têm inúmeras ABIs (APCS, EABI, GNU-EABI, não importa muitos casos históricos) - o uso de uma ABI mista resultará em seu código simplesmente não funcionando ao chamar além-fronteiras.
Consumidor: O compilador, gravadores de montagem, sistema operacional, arquitetura específica da CPU.
Quem precisa desses detalhes? O compilador, gravadores de montagem, vinculadores que geram código (ou requisitos de alinhamento), sistema operacional (manipulação de interrupções, interface syscall). Se você fez a programação de montagem, estava em conformidade com uma ABI!
A identificação de nomes C ++ é um caso especial - é um problema centrado no vinculador e no vinculador dinâmico - se a identificação de nomes não for padronizada, a vinculação dinâmica não funcionará. Daí em diante, o C ++ ABI é chamado apenas isso, o C ++ ABI. Não é um problema no nível do vinculador, mas um problema de geração de código. Depois de ter um binário em C ++, não é possível torná-lo compatível com outro C ++ ABI (manipulação de nomes, manipulação de exceções) sem recompilar a partir da fonte.
ELF é um formato de arquivo para o uso de um carregador e vinculador dinâmico. ELF é um formato de contêiner para código e dados binários e, como tal, especifica a ABI de um trecho de código. Eu não consideraria o ELF um ABI no sentido estrito, pois os executáveis do PE não são um ABI.
Todas as ABIs são específicas do conjunto de instruções. Uma ARI ABI não fará sentido em um processador MSP430 ou x86_64.
O Windows possui várias ABIs - por exemplo, fastcall e stdcall são duas ABIs de uso comum. O syscall ABI é diferente novamente.
fonte
Deixe-me pelo menos responder uma parte da sua pergunta. Com um exemplo de como a ABI do Linux afeta as chamadas do sistema e por que isso é útil.
Uma chamada de sistema é uma maneira de um programa do espaço do usuário solicitar algo ao kernelspace. Ele funciona colocando o código numérico da chamada e o argumento em um determinado registro e acionando uma interrupção. Em seguida, ocorre uma troca no kernelspace e o kernel consulta o código numérico e o argumento, manipula a solicitação, coloca o resultado novamente em um registro e aciona a troca no espaço do usuário. Isso é necessário, por exemplo, quando o aplicativo deseja alocar memória ou abrir um arquivo (syscalls "brk" e "open").
Agora, os syscalls têm nomes abreviados "brk" etc., e códigos de operação correspondentes, eles são definidos em um arquivo de cabeçalho específico do sistema. Enquanto esses opcodes permanecerem os mesmos, você poderá executar os mesmos programas compilados do usuário com kernels diferentes e atualizados, sem precisar recompilar. Então você tem uma interface usada por binários pré-compilados, daí a ABI.
fonte
Para chamar o código em bibliotecas compartilhadas ou entre as unidades de compilação, o arquivo de objeto precisa conter rótulos para as chamadas. O C ++ gerencia os nomes dos rótulos dos métodos para forçar a ocultação de dados e permitir métodos sobrecarregados. É por isso que você não pode misturar arquivos de diferentes compiladores C ++, a menos que eles suportem explicitamente a mesma ABI.
fonte
A melhor maneira de diferenciar entre ABI e API é saber por que e para que é usada:
Para x86-64, geralmente há uma ABI (e para x86 de 32 bits, há outro conjunto):
http://www.x86-64.org/documentation/abi.pdf
https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/140-x86-64_Function_Calling_Conventions/x86_64.html
http://people.freebsd.org/~obrien/amd64-elf-abi.pdf
Linux + FreeBSD + MacOSX seguem-no com algumas pequenas variações. E o Windows x64 tem sua própria ABI:
http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/
Conhecendo a ABI e assumindo que outro compilador a segue também, os binários, teoricamente, sabem como se chamar (API de bibliotecas em particular) e passar parâmetros pela pilha ou por registradores etc. Ou quais registradores serão alterados ao chamar as funções, etc. Essencialmente, esse conhecimento ajudará o software a se integrar. Conhecendo a ordem dos registros / layout da pilha, posso facilmente montar diferentes softwares escritos em montagens sem muito problema.
Mas as API são diferentes:
É um nome de funções de alto nível, com argumento definido, de modo que, se diferentes partes de software constroem usando essa API, PODEM ser capazes de se conectar. Mas um requisito adicional da mesma ABI deve ser respeitado.
Por exemplo, o Windows costumava ser compatível com a API POSIX:
https://en.wikipedia.org/wiki/Windows_Services_for_UNIX
https://en.wikipedia.org/wiki/POSIX
E o Linux também é compatível com POSIX. Mas os binários não podem ser movidos e executados imediatamente. Mas como eles usaram os mesmos NOMES na API compatível com POSIX, você pode pegar o mesmo software em C, recompilar nos diferentes sistemas operacionais e executá-lo imediatamente.
As APIs visam facilitar a integração do software - estágio de pré-compilação. Então, após a compilação, o software pode parecer totalmente diferente - se as ABI forem diferentes.
A ABI visa definir a integração exata do software no nível binário / de montagem.
fonte
SYS_execve
é 11 no Linux de 32 bits, mas 59 no FreeBSD.personality(2)
pode definirPER_BSD
. Eu acho que eu lembro de ter vistopersonality(PER_LINUX)
nastrace
saída o tempo todo, mas moderno de 64 bits binários Linux não mais fazer isso.Exemplo de ABI mínimo executável da biblioteca compartilhada Linux
No contexto de bibliotecas compartilhadas, a implicação mais importante de "ter uma ABI estável" é que você não precisa recompilar seus programas após a alteração da biblioteca.
Então, por exemplo:
se você estiver vendendo uma biblioteca compartilhada, poupe aos usuários o incômodo de recompilar tudo o que depende da sua biblioteca para cada nova versão
se você estiver vendendo um programa de código-fonte fechado que depende de uma biblioteca compartilhada presente na distribuição do usuário, poderá liberar e testar menos pré-compilações se tiver certeza de que a ABI é estável em determinadas versões do sistema operacional de destino.
Isso é especialmente importante no caso da biblioteca padrão C, à qual muitos programas do seu sistema se vinculam.
Agora, quero fornecer um exemplo executável concreto mínimo disso.
main.c
mylib.c
mylib.h
Compila e executa bem com:
Agora, suponha que, para a v2 da biblioteca, desejemos adicionar um novo campo ao
mylib_mystruct
chamadonew_field
.Se adicionamos o campo antes,
old_field
como em:e reconstruiu a biblioteca, mas não
main.out
, a declaração falha!Isso ocorre porque a linha:
gerou um assembly que está tentando acessar o primeiro
int
da estrutura, que agora está emnew_field
vez do esperadoold_field
.Portanto, essa mudança quebrou a ABI.
Se, no entanto, adicionarmos
new_field
depoisold_field
:então o antigo assembly gerado ainda acessa o primeiro
int
da estrutura e o programa ainda funciona, porque mantivemos a ABI estável.Aqui está uma versão totalmente automatizada deste exemplo no GitHub .
Outra maneira de manter essa ABI estável seria tratá-la
mylib_mystruct
como uma estrutura opaca e acessar apenas seus campos por meio de auxiliares de método. Isso facilita a manutenção da ABI estável, mas acarreta uma sobrecarga de desempenho, pois faríamos mais chamadas de função.API vs ABI
No exemplo anterior, é interessante notar que a adição do
new_field
anteriorold_field
quebrou apenas a ABI, mas não a API.O que isso significa é que, se tivéssemos recompilado nosso
main.c
programa contra a biblioteca, ele teria funcionado independentemente.No entanto, também teríamos quebrado a API se tivéssemos alterado, por exemplo, a assinatura da função:
pois nesse caso,
main.c
pararia de compilar completamente.API semântica vs API de programação
Também podemos classificar as alterações da API em um terceiro tipo: alterações semânticas.
A API semântica, geralmente é uma descrição da linguagem natural do que a API deve fazer, geralmente incluída na documentação da API.
Portanto, é possível quebrar a API semântica sem interromper a criação do programa.
Por exemplo, se tivéssemos modificado
para:
então isso não teria quebrado nem a API de programação nem a ABI, mas
main.c
a API semântica seria interrompida.Há duas maneiras de verificar programaticamente a API do contrato:
verificação formal . Mais difícil de fazer, mas produz provas matemáticas de correção, unificando essencialmente a documentação e os testes de maneira "humana" / verificável por máquina! Contanto que não exista um bug em sua descrição formal, é claro ;-)
Esse conceito está intimamente relacionado à formalização da própria matemática: /math/53969/what-does-formal-mean/3297537#3297537
Lista de tudo o que quebra as ABIs da biblioteca compartilhada C / C ++
TODO: encontre / crie a lista definitiva:
Exemplo de Java mínimo executável
O que é compatibilidade binária em Java?
Testado no Ubuntu 18.10, GCC 8.2.0.
fonte
A ABI precisa ser consistente entre o chamador e o chamado para garantir que a chamada seja bem-sucedida. Uso de pilha, uso de registro, pop de pilha de fim de rotina. Todas essas são as partes mais importantes da ABI.
fonte
Sumário
Existem várias interpretações e opiniões fortes da camada exata que define uma ABI (interface binária do aplicativo).
Na minha opinião, uma ABI é uma convenção subjetiva do que é considerado um dado / plataforma para uma API específica. A ABI é o "resto" de convenções que "não serão alteradas" para uma API específica ou que serão tratadas pelo ambiente de tempo de execução: executores, ferramentas, vinculadores, compiladores, jvm e SO.
Definindo uma interface : ABI, API
Se você deseja usar uma biblioteca como joda-time, deve declarar uma dependência
joda-time-<major>.<minor>.<patch>.jar
. A biblioteca segue as práticas recomendadas e usa o Semantic Versioning . Isso define a compatibilidade da API em três níveis:Para você usar uma nova versão principal da mesma biblioteca, muitas outras convenções ainda devem ser respeitadas:
Exemplos
Estudo de caso Java
Por exemplo, Java padronizou todas essas convenções, não em uma ferramenta, mas em uma especificação formal da JVM. A especificação permitiu que outros fornecedores fornecessem um conjunto diferente de ferramentas que podem gerar bibliotecas compatíveis.
O Java fornece outros dois estudos de caso interessantes para a ABI: versões Scala e máquina virtual Dalvik .
Máquina virtual Dalvik quebrou a ABI
A VM do Dalvik precisa de um tipo de bytecode diferente do bytecode Java. As bibliotecas Dalvik são obtidas convertendo o bytecode Java (com a mesma API) para Dalvik. Dessa forma, você pode obter duas versões da mesma API: definidas pelo original
joda-time-1.7.2.jar
. Nós poderíamos me ligarjoda-time-1.7.2.jar
ejoda-time-1.7.2-dalvik.jar
. Eles usam um ABI diferente para os Java vms padrão orientados a pilha: o Oracle, o IBM, o Java aberto ou qualquer outro; e o segundo ABI é o de Dalvik.As versões sucessivas do Scala são incompatíveis
O Scala não tem compatibilidade binária entre versões secundárias do Scala: 2.X. Por esse motivo, a mesma API "io.reactivex" %% "rxscala"% "0.26.5" possui três versões (mais no futuro): para Scala 2.10, 2.11 e 2.12. O que mudou? Por enquanto não sei , mas os binários não são compatíveis. Provavelmente, as versões mais recentes adicionam coisas que tornam as bibliotecas inutilizáveis nas máquinas virtuais antigas, provavelmente coisas relacionadas às convenções de vinculação / nomeação / parâmetro.
Os releases sucessivos Java são incompatíveis
O Java também tem problemas com os principais releases da JVM: 4,5,6,7,8,9. Eles oferecem apenas compatibilidade com versões anteriores. A Jvm9 sabe como executar o código compilado / direcionado (
-target
opção do javac ) para todas as outras versões, enquanto a JVM 4 não sabe como executar o código direcionado para a JVM 5. Tudo isso enquanto você tem uma biblioteca joda. Essa incompatibilidade voa abaixo do radar graças a diferentes soluções:Por que comecei com a definição da API?
API e ABI são apenas convenções sobre como você define compatibilidade. As camadas inferiores são genéricas em relação a uma infinidade de semânticas de alto nível. É por isso que é fácil fazer algumas convenções. O primeiro tipo de convenções são sobre alinhamento de memória, codificação de bytes, convenções de chamada, codificações big e little endian, etc. Além disso, você obtém convenções executáveis como as descritas, convenções de vinculação, código de byte intermediário , como o usado por Java ou LLVM IR usado pelo GCC. Terceiro, você obtém convenções sobre como encontrar bibliotecas, como carregá-las (consulte Java Classloaders). À medida que você avança cada vez mais nos conceitos, você tem novas convenções que considera um dado. É por isso que eles não chegaram ao versionamento semântico .versão. Poderíamos alterar o versionamento semântico com
<major>-<minor>-<patch>-<platform/ABI>
. Isto é o que é, na verdade, já está acontecendo: plataforma já é umrpm
,dll
,jar
(JVM bytecode),war
(JVM + servidor web),apk
,2.11
(específico versão Scala) e assim por diante. Quando você diz APK, você já fala sobre uma parte específica da ABI da sua API.A API pode ser portada para diferentes ABI
O nível superior de uma abstração (as fontes gravadas na API mais alta podem ser recompiladas / portadas para qualquer outra abstração de nível inferior.
Digamos que eu tenha algumas fontes para o rxscala. Se as ferramentas Scala forem alteradas, posso recompilá-las para isso. Se a JVM mudar, eu poderia ter conversões automáticas da máquina antiga para a nova sem me preocupar com os conceitos de alto nível. Embora a transferência seja difícil, ajudará qualquer outro cliente. Se um novo sistema operacional for criado usando um código de montador totalmente diferente, um tradutor poderá ser criado.
APIs portadas em vários idiomas
Existem APIs portadas em vários idiomas, como fluxos reativos . Em geral, eles definem mapeamentos para idiomas / plataformas específicos. Eu argumentaria que a API é a especificação principal formalmente definida em linguagem humana ou mesmo em uma linguagem de programação específica. Todos os outros "mapeamentos" são ABI em certo sentido, mais uma API do que a ABI usual. O mesmo está acontecendo com as interfaces REST.
fonte
Em resumo e em filosofia, apenas coisas desse tipo podem se dar bem, e a ABI pode ser vista como o tipo de material de software que funciona em conjunto.
fonte
Eu também estava tentando entender a resposta da ABI e JesperE foi muito útil.
De uma perspectiva muito simples, podemos tentar entender a ABI considerando a compatibilidade binária.
O wiki do KDE define uma biblioteca como compatível com binários "se um programa vinculado dinamicamente a uma versão anterior da biblioteca continuar sendo executado com versões mais recentes da biblioteca sem a necessidade de recompilar". Para obter mais informações sobre links dinâmicos, consulte Link estático vs link dinâmico
Agora, vamos tentar examinar apenas os aspectos mais básicos necessários para uma biblioteca ser compatibilidade binária (supondo que não haja alterações no código fonte da biblioteca):
Claro, existem muitos outros detalhes, mas isso é principalmente o que a ABI também cobre.
Mais especificamente, para responder à sua pergunta, pelo exposto, podemos deduzir:
Espero que isto ajude!
fonte
Interface binária de aplicativo (ABI)
Funcionalidade:
Entidades existentes:
consumidor:
Eles são necessários para quem precisa garantir que as cadeias de ferramentas de construção funcionem como um todo. Se você escreve um módulo em linguagem assembly, outro em Python, e em vez de seu próprio gerenciador de inicialização deseja usar um sistema operacional, os módulos "aplicativos" estão funcionando além dos limites "binários" e exigem o consentimento dessa "interface".
Manipulação de nome do C ++ porque pode ser necessário vincular arquivos de objeto de diferentes idiomas de alto nível no seu aplicativo. Considere usar a biblioteca padrão do GCC para fazer chamadas do sistema para o Windows criadas com o Visual C ++.
ELF é uma expectativa possível do vinculador de um arquivo de objeto para interpretação, embora a JVM possa ter alguma outra idéia.
Para um aplicativo da Windows RT Store, tente procurar pelo ARM ABI se você realmente deseja que algumas cadeias de ferramentas de compilação funcionem juntas.
fonte
O termo ABI é usado para se referir a dois conceitos distintos, mas relacionados.
Ao falar sobre compiladores, refere-se às regras usadas para converter de construções no nível de origem em construções binárias. Qual o tamanho dos tipos de dados? como funciona a pilha? como passo parâmetros para funções? quais registros devem ser salvos pelo chamador vs o chamado?
Ao falar sobre bibliotecas, refere-se à interface binária apresentada por uma biblioteca compilada. Essa interface é o resultado de vários fatores, incluindo o código fonte da biblioteca, as regras usadas pelo compilador e, em alguns casos, as definições obtidas de outras bibliotecas.
Alterações em uma biblioteca podem interromper a ABI sem interromper a API. Considere, por exemplo, uma biblioteca com uma interface semelhante.
e o programador de aplicativos escreve código como
O programador de aplicativos não se importa com o tamanho ou o layout do FOO, mas o binário do aplicativo acaba com um tamanho de foo codificado. Se o programador da biblioteca adicionar um campo extra a foo e alguém usar o novo binário da biblioteca com o binário antigo do aplicativo, a biblioteca poderá acessar a memória fora dos limites.
OTOH se o autor da biblioteca tiver projetado sua API como.
e o programador de aplicativos escreve código como
Então o binário do aplicativo não precisa saber nada sobre a estrutura do FOO, que pode estar oculta dentro da biblioteca. O preço que você paga por isso é que as operações de heap estão envolvidas.
fonte
ABI
-Application Binary Interface
trata-se de uma comunicação de código de máquina em tempo de execução entre duas partes binárias do programa, como - aplicativo, biblioteca, SO ...ABI
descreve como os objetos são salvos na memória e como as funções são chamadas (calling convention
)Um bom exemplo de API e ABI é o ecossistema iOS com linguagem Swift .
Application
- Quando você cria um aplicativo usando idiomas diferentes. Por exemplo, você pode criar aplicativos usandoSwift
eObjective-C
[Mixing Swift and Objective-C]Application - OS
- tempo de execução -Swift runtime
estandard libraries
são partes do sistema operacional e não devem ser incluídos em cada pacote (por exemplo, aplicativo, estrutura). É o mesmo que usa o Objective-CLibrary
-Module Stability
case - tempo de compilação - você poderá importar uma estrutura que foi criada com outra versão do compilador do Swift. Isso significa que é seguro criar um binário de código fechado (pré-compilação) que será consumido por uma versão diferente do compilador (.swiftinterface
usada com.swiftmodule
) e você não obteráLibrary
-Library Evolution
caso[API vs ABI]
fonte