2016-03-27 272 views
0

我最近进入了gcc的内联汇编,并具有基本的汇编知识,我理解如何使系统调用相当好,直到我试图用一个或多个参数执行一个简单的sys_execve。 如果我没有传递任何附加参数,系统调用execve可以正常工作,并且在尝试传递任何参数时仅运行不带参数的可执行文件。执行内联汇编

#include <stdio.h> 

char *argv[]={"/bin/echo","parameter test", NULL}; 

int main(){ 
    __asm__ volatile ("int $0x80" 
      : 
      :"a"(11), // syscall number (execve) 
      "b"(argv[0]), // filename 
      "c"(argv), // arguments 
      "d"(0)); // env 
    return 0; 
} 

我不知道有什么可以去错了,因为我已经测试这与

execve(argv[0], argv, NULL); 

和它的工作如预期。

+2

查看[sys_execve](http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html)的api,我不确定你的参数是否正确。另外,你正在编译x64?如果是这样,你不应该使用int 0x80。 –

+0

我正在编译x64,并且根据我当前的进度,文件名部分是正确的,因为我尝试执行的任何可执行文件都可以正常工作。我坚持的部分是给它任何参数。我用户[this](http://syscalls.kernelgrok.com/)来确定我必须通过。 – LazyShpee

回答

4

这是32位代码,使用32位约定。编译使用gcc -m32它会工作。可替换地,切换到合适的64位的版本,例如:

#include <stdio.h> 

char *argv[]={"/bin/echo","parameter test", NULL}; 

int main(){ 
    int ret; 
    __asm__ volatile ("syscall" 
      :"=a" (ret) 
      :"a"(59), // syscall number (execve) 
      "D"(argv[0]), // filename 
      "S"(argv), // arguments 
      "d"(0) // env 
      :"rcx","r11","cc"); 
    return 0; 
} 

的实际问题是,你必须在阵列中的64位的指针,但32位兼容中断你使用当然预计,32个poiters。

+2

'= a'值得明确指出:系统调用在'eax'(或'rax')寄存器中返回一个值,因此编译器需要知道发生了这种情况。否则,它会假设asm代码没有修改'eax',并且如果代码后面需要值59,它可能会尝试从'eax'加载它。这会导致问题,因为实际上'eax'已被系统调用的返回值覆盖。这个代码可能不太可能导致问题,但一般来说要注意。 –

+2

顺便说一下,从我读到的amd64 abi中,系统调用可能会破坏'r11'以及'rcx'。 –

+1

@NateEldredge:这是正确的,'syscall' /'sysret'的设计保证'syscall'总是会打破rcx和r11(使用RIP和RFLAGS)。让内核甚至可以看到这些注册表中的内容将需要用户空间的合作(例如将它们放在堆栈上)。 Linux系统调用不会查看用户空间堆栈,所以ABI只是简单地保留它,并且系统调用在amd64上打开这两个regs,不像32bit'int 0x80',只有'eax'被修改(返回值)。 –