2011-02-10 82 views
3

在Linux i386上,int $0x80系統調用ABI使得在沒有有效用戶空間堆棧的情況下輕鬆執行系統調用。另一方面,vdso/vsyscall接口需要訪問堆棧。其他Linux端口在這方面的表現如何,特別是x86_64?他們有沒有辦法讓系統調用沒有堆棧?是否有可用的系統調用每個拱門的方法?在沒有堆棧的情況下在Linux上進行系統調用

回答

4

一般:不知道。即使在i386上,如果有第6個參數,它也必須在堆棧上傳遞(例如mmap)。

對於x86_64的具體爲:把系統調用編號在%rax(小心:系統調用號碼被分配完全不同,以32位的),直至在%rdi 6個參數,%rsi%rdx%r10%r8%r9(其幾乎與通常的ABI參數傳入寄存器相同,但不完全相同 - 請注意使用%r10而不是%rcx),並使用syscall指令。結果返回%rax%rcx%r11被破壞。

x86_64 ABI信息可在http://www.x86-64.org/documentation/abi.pdf找到; Linux ABI記錄在附錄中。 (如果環顧其他地方x86_64的ABI的信息,要知道,64位Windows使用它自己的不同的ABI)。


我不相信有用戶堆棧幀爲syscall工作的任何要求正常。在被信號中斷的情況下,處理程序顯然需要一個理智的堆棧;但下面的實驗,使用備用信號棧和故意象垃圾一樣清除%rspsyscall左右,正常工作對我來說:

$ cat syscall_sig.c 
#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <signal.h> 
#include <time.h> 
#include <unistd.h> 

#define __NR_nanosleep 35 

static sig_atomic_t alrm = 0; 

void handler(int sig) 
{ 
    if (sig == SIGALRM) 
     alrm = 1; 
} 

int main(void) 
{ 
    stack_t ss; 
    struct sigaction sa; 
    struct timespec req, rem; 
    long ret; 

    ss.ss_flags = 0; 
    ss.ss_size = SIGSTKSZ; 
    ss.ss_sp = malloc(ss.ss_size); 
    sigaltstack(&ss, NULL); 

    memset(&sa, 0, sizeof(sa)); 
    sa.sa_handler = handler; 
    sa.sa_flags = SA_ONSTACK; 
    sigaction(SIGALRM, &sa, NULL); 

    alarm(1); 

    req.tv_sec = 5; 
    req.tv_nsec = 0; 
    asm("xorq $0x12345678, %%rsp ; syscall ; xorq $0x12345678, %%rsp" 
     : "=a" (ret) 
     : "0" (__NR_nanosleep), "D" (&req), "S" (&rem) 
     : "rcx", "r11", "memory"); 

    printf("syscall return code %ld, alarm flag %d\n", ret, alrm); 

    return 0; 
} 

$ gcc -Wall -o syscall_sig syscall_sig.c 
$ ./syscall_sig 
syscall return code -4, alarm flag 1 
$ 
+0

這是我在做什麼(間接通過別人因爲我沒有直接訪問到x86_64系統進行移植)。其實現在我有一個堆棧,但我知道後面我將不得不面對一個我不會的情況,但我已經遇到了麻煩。你所描述的方法是有效的,除非系統調用被一個信號中斷,但如果它被中斷並且試圖恢復,它會在`syscall`指令上發生段錯誤...'syscall`是否需要一個特定的棧幀來設置它,中斷/恢復? – 2011-02-11 04:08:50

相關問題