FreeBSD vs Linux: desempenho das convenções de chamada do kernel

3

De int80h.org, o tutorial da linguagem de montagem do FreeBSD

[The Linux Calling] convention has a great disadvantage over the Unix way, at least as far as assembly language programming is concerned: Every time you make a kernel call you must push the registers, then pop them later. This makes your code bulkier and slower.

Indo diz sobre o FreeBSD suportando tanto a convenção Linux quanto a "Convenção Unix"

If you are coding specifically for FreeBSD, you should always use the Unix convention: It is faster, you can store global variables in registers, you do not have to brand the executable, and you do not impose the installation of the Linux emulation package on the target system.

Parece estranho para mim que o caminho do Linux seja mais volumoso e lento. Parece que há duas opções,

  • Salve apenas os registros que você precisa preservar, que são
    • esses registros voláteis que podem ser destruídos pela chamada do sistema (que eu saiba ecx )
    • ou, os registros necessários para enviar os argumentos apropriados ao kernel para tornar o syscall (que pode ser eax , ecx , edx , esi , edi , ebp )
  • Salve 100% dos argumentos para o kernel na pilha.

Parece que o caso do FreeBSD é o pior cenário da convenção Linux. o que estou perdendo? Como a convenção do FreeBSD (que eles chamam de "caminho Unix") é menos volumosa e mais rápida?

    
por Evan Carroll 30.05.2018 / 03:02

1 resposta

9

Isso realmente se resume à opinião do autor, na minha opinião.

Na convenção do FreeBSD (“Unix”), você empurra os argumentos na pilha, especifica o número da chamada do sistema em EAX e invoca a interrupção 0x80 (com um operando extra na pilha porque espera ser chamado de uma função separada).

Na convenção do Linux i386, você coloca os argumentos nos registros apropriados e invoca a interrupção 0x80.

O argumento volumoso / lento, presumivelmente, vem do fato de que, com a convenção do Linux, o chamador precisa lidar com o uso de registros. Se a chamada do sistema precisar de argumentos em registros que contenham valores com os quais o chamador se preocupa, será necessário preservá-los, o que resulta em legwork adicional; veja este exemplo da biblioteca C . Neste exemplo, a chamada do sistema precisa de valores em EAX, EBX, EDX, EDI e ESI; mas o chamador só se preocupa em preservar o EBX, o EDI e o ESI, de modo que ele só os empurra para a pilha. O caso geral é um pouco mais complexo (mas também é o resultado de lidar com uma mistura de C e linguagem assembly, tentando gerar código ótimo em todos os casos), no entanto, ao escrever em assembly, que é o ponto do site que você está se referindo, isso não seria um grande problema.

Parece-me que são seis e meia dúzia: na convenção do FreeBSD, você empurra para a pilha em todos os casos, na convenção do Linux, você empurra para a pilha (ou em outro lugar) dependendo do que você está fazendo em torno do site de chamadas. Você poderia argumentar que a convenção do Linux permite um código mais rápido, já que você pode realizar todos os seus cálculos nos registros ... Como Rob No entanto, no Linux os registradores ainda acabam sendo empurrados (para construir a instância struct pt_regs que é usada para fornecer os argumentos para as funções C que lidam com as chamadas do sistema), então o custo total é maior no lado do Linux do que no lado do FreeBSD.

Em qualquer caso, argumentar sobre desempenho quando se fala em pilha ou código baseado em registro em torno de uma chamada de sistema parece um tanto pedante, dado o custo de realizar a própria chamada do sistema. Qualquer ciclo salvo é bom em termos absolutos, mas a melhora relativa será pequena.

    
por 30.05.2018 / 08:44