Eu vejo muitas pessoas online referenciando
arch/x86/entry/syscalls/syscall_64.tbl
para a tabela syscall, isso funciona bem. Mas muitos outros fazem referência
/include/uapi/asm-generic/unistd.h
que é comumente encontrado no pacote headers. Como assim syscall_64.tbl
shows,
0 common read sys_read
A resposta certa, e unistd.h
mostra,
#define __NR_io_setup 0
__SC_COMP(__NR_io_setup, sys_io_setup, compat_sys_io_setup)
E então mostra __NR_read
como
#define __NR_read 63
__SYSCALL(__NR_read, sys_read)
Por que isso é 63 e não 1? Como faço para entender /include/uapi/asm-generic/unistd.h
? Ainda /usr/include/asm/
há
/usr/include/asm/unistd_x32.h
#define __NR_read (__X32_SYSCALL_BIT + 0)
#define __NR_write (__X32_SYSCALL_BIT + 1)
#define __NR_open (__X32_SYSCALL_BIT + 2)
#define __NR_close (__X32_SYSCALL_BIT + 3)
#define __NR_stat (__X32_SYSCALL_BIT + 4)
/usr/include/asm/unistd_64.h
#define __NR_read 0
#define __NR_write 1
#define __NR_open 2
#define __NR_close 3
#define __NR_stat 4
/usr/include/asm/unistd_32.h
#define __NR_restart_syscall 0
#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4
Alguém poderia me dizer a diferença entre esses unistd
arquivos. Explique como unistd.h
funciona? E qual o melhor método para encontrar a tabela syscall?
Quando estou investigando esse tipo de coisa, acho útil perguntar diretamente ao compilador (consulte Imprimindo macros predefinidas padrão C/GCC no terminal para obter detalhes):
Isso mostra que os cabeçalhos envolvidos (no Debian) são
/usr/include/x86_64-linux-gnu/sys/syscall.h
,/usr/include/x86_64-linux-gnu/asm/unistd.h
,/usr/include/x86_64-linux-gnu/asm/unistd_64.h
, e/usr/include/x86_64-linux-gnu/bits/syscall.h
, e imprime o número de chamada do sistema pararead
, que é 0 em x86-64.Você pode encontrar os números de chamada do sistema para outras arquiteturas se tiver os cabeçalhos de sistema apropriados instalados (em um ambiente de compilador cruzado). Para x86 de 32 bits, é muito fácil:
que envolve
/usr/include/asm/unistd_32.h
entre outros arquivos de cabeçalho, e imprime o número 3.Portanto, da perspectiva do espaço do usuário, as chamadas do sistema x86 de 32 bits são definidas em
asm/unistd_32.h
, as chamadas do sistema x86 de 64 bits emasm/unistd_64.h
.asm/unistd_x32.h
é usado para x32 ABI .uapi/asm-generic/unistd.h
lista as chamadas de sistema padrão, que são usadas em arquiteturas que não possuem uma tabela de chamadas de sistema específica da arquitetura.No kernel, as referências são ligeiramente diferentes e são específicas da arquitetura (novamente, para arquiteturas que não usam a tabela genérica de chamada do sistema). É aqui que entram os arquivos como
arch/x86/entry/syscalls/syscall_64.tbl
(e acabam produzindo os arquivos de cabeçalho que são usados no espaço do usuário,unistd_64.h
etc.). Você encontrará muito mais detalhes sobre chamadas de sistema no par de artigos LWN sobre o tópico Anatomia de uma chamada de sistema parte 1 e Anatomia de uma chamada de sistema parte 2 .Arcos diferentes têm números de syscall diferentes definidos em arquivos diferentes
Os números do syscall são diferentes para cada arquitetura, por exemplo:
x86_64:
arch/x86/entry/syscalls/syscall_64.tbl
: lido é 0x86:
arch/x86/entry/syscalls/syscall_32.tbl
: lido é 3arm64:
include/uapi/asm-generic/unistd.h
: read é 63, consulte também: https://reverseengineering.stackexchange.com/questions/16917/arm64-syscalls-table/18834#18834braço:
arch/arm/tools/syscall.tbl
, leia-se 3include/uapi/asm-generic/unistd.h
vsarch/*
definiçõesAcho que
include/uapi/asm-generic/unistd.h
é uma tentativa mais recente de unificar os números do syscall em todos os arcos.Mas como os números do syscall não podem mudar para não quebrar a API do syscall, os arcos mais antigos antes desse esforço de unificação (incluindo x86, x86_64 e arm) mantiveram os números antigos definidos em
arch/
. arm64 é mais recente e, nounistd.h
entanto, recebeu a nova API.Esta questão relacionada solicita uma maneira automatizada de obter a lista completa de syscall, incluindo parâmetros: https://stackoverflow.com/questions/6604007/how-can-i-get-a-list-of-linux-system-calls-and -number-of-args-they-take-automati
strace
Código fonteEu confio nessa ferramenta e eles mantêm seus dados organizados em
linux/
, por exemplo:Observe que o aarch64
#include
é o arch agnóstico64/syscallent.h
ao qual me referi anteriormente.Essas tabelas contêm o número de argumentos, mas não os tipos de argumentos reais, gostaria de saber onde
strace
os codifica.glibc
Código fonteEu tenho uma página que lista todas as chamadas do sistema para cada arquitetura suportada pelo Linux:
https://marcin.juszkiewicz.com.pl/download/tables/syscalls.html
Para adicionar todas as ótimas respostas, existe um utilitário
ausyscall
que pode ser usado para listar todas as syscalls e seus mapeamentos inteiros para a arquitetura específica.por exemplo:
Esta resposta não abordará a
asm-generic
versão deunistd.h
, porque nada a inclui. 1Conforme observado em
syscalls(2)
:Ou seja, os números corretos do syscall serão encontrados em
/usr/include/asm/unistd.h
. Agora, em um sistema x86 típico, isso simplesmente incluirá um dosasm/unistd_*.h
arquivos dependendo do destino.Os números de syscall apropriados para um programa de 64 bits estão em
asm/unistd_64.h
, e os de um programa de 32 bits em (ou a varianteasm/unistd_32.h
quase equivalente )._x32.h
Os dois são diferentes porque as arquiteturas de 32 e 64 bits são, efetivamente, sistemas operacionais completamente diferentes. Eles compartilham o mesmo conjunto de syscalls, mas não na mesma ordem, por vários motivos.A maioria deles também possui wrappers em linguagem C, portanto, raramente você precisará usá-los
syscall(2)
diretamente.1 E porque não sei para que serve.