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