Chamadas de Sistema (syscalls) no Mac OS X
Rudá Moura
Outubro de 2009
O Mac OS X segue o estilo de chamadas do FreeBSD. Os parâmetros da chamada do sistema são postos na pilha, o número da syscall é gravado no registrador EAX e então chama-se a instrução int $0x80. O valor de retorno da syscall vem através do registrador EAX.
Para facilitar o uso da instrução int $0x80 – que na verdade exige mais um elemento na pilha – faremos uso de uma subrotina _syscall.
.text
_syscall:
int $0x80
ret
O próximo passo é conhecer quais são as chamadas de sistema disponíveis e os seus parâmetros. Estas chamadas são definidas em um arquivo de template do componente XNU do Mac (o núcleo BSD do Mac), no arquivo syscalls.master.
Vamos fazer uso das chamadas write
e exit, que possuem as seguintes assinaturas:
1 AUE_EXIT ALL { void exit(int rval); }
4 AUE_NULL ALL { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); }
O exemplo abaixo escreve a mensagem Hello World! na saída padrão (STDOUT) e retorna ao shell o valor 42. Os parâmetros são empilhados pegando os parâmetros da direita para a esquerda.
.globl start start: # user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte) pushl len # nbyte = len pushl $msg # cbuf = msg pushl $1 # fd = STDOUT movl $4,%eax # syscall = SYS_write call _syscall addl $12,%esp # restore stack # void exit(int rval) pushl $42 # rval = 42 movl $1,%eax # syscall = SYS_exit call _syscall .data msg: .ascii "Hello World!\n" len: .long . - msg
Compile com informações de debug para ver passo a passo a execução com o GDB.
$ as -g sc.s -o sc.o $ ld sc.o -o sc
Testando o nosso exemplo…
$ ./sc Hello World! $ echo $? 42
Para os programadores C, é possível fazer chamadas do sistema diretamente através da API, para isto é preciso incluir os cabeçalhos sys/syscall.h e unistd.h e chamar a função syscall().
Chama SYS_exit (ver syscall.h) e retorna 42 ao shell.
#include <sys/syscall.h>
#include <unistd.h>
main()
{
syscall(SYS_exit, 42);
}
O estilo de chamadas por int $0x80 está sendo gradualmente(?) substituído por sysenter, que não explico nesse artigo, até porque não sei como funciona.
Dump da libSystem para _syscall e __systenter_trap.
_syscall: 00033514 popl %ecx 00033515 popl %eax 00033516 pushl %ecx 00033517 int $0x80 00033519 movl (%esp),%edx 0003351c pushl %ecx 0003351d jae 0x0003352d 0003351f calll 0x00033524 00033524 popl %edx 00033525 movl 0x001733a4(%edx),%edx 0003352b jmp *%edx 0003352d ret __sysenter_trap: 00000ab8 popl %edx 00000ab9 movl %esp,%ecx 00000abb sysenter 00000abd nopl (%eax)
Referências
© MMIX