Funções como readdir()
e amigos são implementadas na libc, que é uma biblioteca compartilhada. Como com todas as bibliotecas compartilhadas, isso adiciona algum redirecionamento para poder resolver o endereço de memória da função dentro da biblioteca compartilhada.
Na primeira vez que qualquer chamada de biblioteca particular é executada, o vinculador dinâmico precisa procurar o endereço da chamada de biblioteca dentro de uma tabela de hash. Isso envolve pelo menos uma (mas possivelmente mais) comparações de strings, um método comparativamente caro. O endereço encontrado é salvo na PLT
(tabela de ligação do procedimento), para que na próxima vez que a função for chamada, a sobrecarga de encontrar a função seja reduzida a três instruções (na arquitetura x86, menos que em outra arquiteturas). É por isso que compilar algo como um objeto compartilhado (em vez de um objeto estático) tem alguma sobrecarga. Para obter mais informações sobre a sobrecarga da biblioteca compartilhada e sobre como as bibliotecas compartilhadas funcionam no Linux, consulte a explicação técnica detalhada de Ulrich Drepper sobre o assunto .
A função syscall()
em si é também implementada na libc, então também tem esse redirecionamento. No entanto, desde que você usaria apenas essa função (e nenhum outro), o vinculador dinâmico tem menos trabalho a fazer. Além disso, a implementação de uma função específica, como readdir
, teria que converter os valores de retorno e fazer a verificação de erros, etc. ao sair da função syscall()
, que é uma sobrecarga extra. Um programa que executa syscall()
diretamente funcionaria com os valores de retorno direto da chamada do sistema e não precisaria dessa conversão (ainda seria necessário fazer a verificação de erros, o que complicaria a função significativamente).
A desvantagem de executar syscall()
diretamente é que você passa para uma API menos portável. O syscall()
manpage explica algumas restrições específicas da arquitetura com as quais a libc lida com você; se você usa syscall()
diretamente, sua função pode funcionar na arquitetura que você está lidando, mas falharia, digamos, em uma máquina de braço.
Em geral, eu recomendaria não usar diretamente a syscall()
API, pelo mesmo motivo que eu recomendaria contra a gravação direta do código em linguagem assembly. Sim, isso pode acabar sendo mais rápido no final, mas a carga de manutenção se torna (muito) mais alta. Algumas coisas que você poderia fazer em vez disso:
- Não se preocupe com desempenho. Os sistemas continuam ficando mais baratos e, em muitos casos, "adicionar outro sistema para que as coisas corram mais rápido" é mais barato do que "pagar as taxas por hora de um programador para melhorar o desempenho".
- Compile o software em relação a bibliotecas estáticas em vez de usar bibliotecas compartilhadas, para as poucas pequenas coisas em que o desempenho é crítico (por exemplo,
gcc -static
) - Use um criador de perfil para ver onde as coisas estão indo devagar e concentre-se em essas coisas, em vez de se preocupar em como fazer uma chamada do sistema.