// (Assuming that int 80 works,) test that syscall32/sysenter32 works // // i686-gcc -Os -Wall -static #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> #include <sys/select.h> #include <sys/time.h> #include <sys/types.h> #include <elf.h> long syscall_addr; long get_syscall(char **envp) { Elf32_auxv_t *auxv; while (*envp++ != NULL) continue; for (auxv = (void *)envp; auxv->a_type != AT_NULL; auxv++) if( auxv->a_type == AT_SYSINFO) return auxv->a_un.a_val; fprintf(stderr, "AT_SYSINFO not supplied, can't test\n"); exit(0); /* this is not a failure */ } int nfds; fd_set rfds; fd_set wfds; fd_set efds; struct timespec timeout; sigset_t sigmask; struct { sigset_t *sp; int sz; } sigmask_desc; char RES[] = "Result:0\n"; void prep_args() { nfds = 42; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); FD_SET(0, &rfds); FD_SET(1, &wfds); FD_SET(2, &efds); timeout.tv_sec = 0; timeout.tv_nsec = 123; sigemptyset(&sigmask); sigaddset(&sigmask, SIGINT); sigaddset(&sigmask, SIGUSR2); sigaddset(&sigmask, SIGRTMAX); sigmask_desc.sp = &sigmask; sigmask_desc.sz = 8; /* bytes */ } #define PSELECT 308 // pselect(nfds,rfds,wfds,efds,timeout,sigmask) int main(int argc, char **argv, char **envp) { // This only works for non-static builds: //syscall_addr = dlsym(dlopen("linux-gate.so.1", RTLD_NOW), "__kernel_vsyscall"); syscall_addr = get_syscall(envp); prep_args(); asm("\n" // Try 6-arg syscall: pselect. It should return quickly " mov $308,%eax\n" // PSELECT " mov nfds,%ebx\n" // ebx arg1 " mov $rfds,%ecx\n" // ecx arg2 " mov $wfds,%edx\n" // edx arg3 " mov $efds,%esi\n" // esi arg4 " mov $timeout,%edi\n" // edi arg5 " mov $sigmask_desc,%ebp\n" // %ebp arg6 " std\n" " call *syscall_addr\n" // Check that registers are not clobbered " pushf\n" " pop %eax\n" " cmp nfds,%ebx\n" // ebx arg1 " movb $0x32,RES+7\n" " jne end\n" " cmp $rfds,%ecx\n" // ecx arg2 " movb $0x33,RES+7\n" " jne end\n" " cmp $wfds,%edx\n" // edx arg3 " movb $0x34,RES+7\n" " jne end\n" " cmp $efds,%esi\n" // esi arg4 " movb $0x35,RES+7\n" " jne end\n" " cmp $timeout,%edi\n" // edi arg5 " movb $0x36,RES+7\n" " jne end\n" " cmpl $sigmask_desc,%ebp\n" // %ebp arg6 " movb $0x37,RES+7\n" " jne end\n" // This fails (DF is not preserved) // on 32-bit kernels. 64-bit ones worked: " bt $10,%eax\n" //flags.DF still set? " movb $0x31,RES+7\n" " jnc end\n" " movb $0x30,RES+7\n" "end:\n" " mov $4,%eax\n" // WRITE " mov $1,%ebx\n" // ebx arg1 " mov $RES,%ecx\n" // ecx arg2 " mov $9,%edx\n" // edx arg3 " int $0x80\n" // Error if result is not 0 or 1 // (result:1 means DF was clobbered) " mov $1,%eax\n" // EXIT " xor %ebx,%ebx\n" // ebx arg1 " cmpb $0x31,RES+7\n" " ja 1f\n" " int $0x80\n" "1: inc %ebx\n" " int $0x80\n" ); return 42; /* not reached */ }