2011-02-27 127 views
8

我试图使用内联汇编... 我读了此页http://www.codeproject.com/KB/cpp/edujini_inline_asm.aspx但我无法理解传递给我函数的参数。在C/C++中使用内联汇编

我正在写一个C写的例子..这是我的函数头:

write2(char *str, int len){ 
} 

这是我的汇编代码:

global write2 
write2: 
    push ebp 
    mov ebp, esp 
    mov eax, 4  ;sys_write 
    mov ebx, 1  ;stdout 
    mov ecx, [ebp+8] ;string pointer 
    mov edx, [ebp+12] ;string size 
    int 0x80  ;syscall 
    leave 
    ret 

什么我必须做的传递代码到C函数...我正在做这样的事情:

write2(char *str, int len){ 
    asm ("movl 4, %%eax;" 
      "movl 1, %%ebx;" 
      "mov %1, %%ecx;" 
      //"mov %2, %%edx;" 
      "int 0x80;" 
      : 
      : "a" (str), "b" (len) 
    ); 
} 

这是因为我没有输出变量,所以我怎么做处理? 此外,使用此代码:

global main 
main: 
    mov ebx, 5866  ;PID 
    mov ecx, 9  ;SIGKILL 
    mov eax, 37  ;sys_kill 
    int 0x80  ;interruption 
    ret 

我怎样才能把这些代码嵌入在我的代码..所以我可以要求PID给用户..这样的.. 这是我的预编码

void killp(int pid){ 
    asm ("mov %1, %%ebx;" 
      "mov 9, %%ecx;" 
      "mov 37, %%eax;" 
      : 
      : "a" (pid)   /* optional */ 
    ); 
} 
+0

你想传递一个输出参数,以及str,len?,或者你的意思是你想发送一个文件描述符,你想写str? – Zimbabao 2011-02-27 05:55:36

+0

我只是想传递我的字符串指针和我的字符串长度......就像它在程序集代码中看起来一样......所以,只使用系统调用,我可以将我的字符串打印到标准输出。 – RodrigoCR 2011-02-27 06:07:22

回答

10

嗯,你没有具体说,但通过你的文章,它看起来像你使用gcc和它的内联asm与约束语法(其他C编译器具有非常不同的内联语法)。也就是说,您可能需要使用AT & T汇编语法,而不是Intel,因为这是gcc所使用的。

所以和上面说的一样,让我们​​来看看你的write2函数。首先,你不想创建一个堆栈帧,因为gcc会创建一个,所以如果你在asm代码中创建一个,你最终会得到两个帧,事情可能会非常困惑。其次,由于gcc正在布置堆栈框架,因此您不能使用“[ebp + offset]”广告访问变量,您不知道它是如何布局的。这就是约束条件 - 你说什么样的地方你希望gcc把值(任何寄存器,内存,特定的寄存器)和在代码中使用“%X”。最后,如果你在asm代码中使用显式寄存器,你需要在第三部分中列出它们(在输入约束之后),以便gcc知道你正在使用它们。否则,它可能会在其中一个寄存器中放置一些重要的值,并且会打破该值。

因此,所有的是,你写2函数看起来像:

void write2(char *str, int len) { 
    __asm__ volatile (
     "movl $4, %%eax;" 
     "movl $1, %%ebx;" 
     "movl %0, %%ecx;" 
     "movl %1, %%edx;" 
     "int $0x80" 
     :: "g" (str), "g" (len) 
     : "eax", "ebx", "ecx", "edx"); 
} 

注意AT & T语法 - SRC,DEST而非DEST,寄存器名前src和%

现在,这将工作,但效率低下,因为它将包含大量额外的mov。一般来说,你绝不应该在asm代码中使用mov指令或显式寄存器,因为使用约束条件来说明你想要的东西的位置并让编译器确保它们在那里更好。这样,优化器可能会摆脱大部分movs,特别是如果它内联函数(如果指定-O3,它将执行此操作)。方便的是,i386的机型有特定的寄存器约束,这样你就可以代替做:

void write2(char *str, int len) { 
    __asm__ volatile (
     "movl $4, %%eax;" 
     "movl $1, %%ebx;" 
     "int $0x80" 
     :: "c" (str), /* c constraint tells the compiler to put str in ecx */ 
      "d" (len) /* d constraint tells the compiler to put len in edx */ 
     : "eax", "ebx"); 
} 

甚至更​​好

void write2(char *str, int len) { 
    __asm__ volatile ("int $0x80" 
     :: "a" (4), "b" (1), "c" (str), "d" (len)); 
} 

还请注意这是需要使用volatile告诉编译器,这即使没有使用它的输出(其中没有),也不能被淘汰。

编辑

最后一个音符 - 这个功能是做一个写系统调用,这并在EAX返回值 - 写入的字节数或错误代码。所以,你可以得到与输出的制约条件:

int write2(char *str, int len) { 
    __asm__ ("int $0x80" : "=a" (len) : "a" (4), "b" (1), "c" (str), "d" (len)); 
    return len; 
} 

与真正的输出,你可能会或可能不希望挥发 - 没有它可以让编译器死代码消除写如果返回值未使用。但是你总是检查返回值的错误,对不对?

+1

转换为AT&T时,你错过了一件事:常量需要一个$在他们面前。否则,它们是内存引用,我敢肯定你不想执行地址为0x80的任何中断。 – ughoavgfhw 2011-02-27 06:44:44

+0

非常感谢那个很有帮助的答案。我意识到AT&T的sintax,所以我修改了我的代码......但是你看不到:P,altought现在我理解优化了...所以,我需要把int $ 0x80正确吗? – RodrigoCR 2011-02-27 06:47:36

+0

void write2(char * str,int len){ __asm__ volatile(“int $ 0x80” ::“a”(4),“b”(1),“c”(str),“d”(len )); } 注意:这是正确的答案!交换数值并使用$。谢谢你们两位! – RodrigoCR 2011-02-27 07:19:04