使用内联汇编段错误编程,除非以函数调用为前缀

时间:2013-12-16 04:34:05

标签: c gcc assembly x86 inline-assembly

#include <stdio.h>

static void my_func(char *text) {
    //printf("hello again\n");
    __asm__(
        "push %%ebp\n\t"
        "mov %0, %%ebx\n\t"
        "push %%ebx\n\t"
        "call strlen\n\t"
        "movb (%%ebx), %%al" 
    : : "r"(text));
}

int main() {
    int i;
    for(i = 0; i < 3; ++i)
        my_func("hello");
}

试运行:

$ gcc -v
(...)
gcc version 4.8.1 (Ubuntu/Linaro 4.8.1-10ubuntu9) 
$ gcc test.c
$ ./a.out 
Segmentation fault (core dumped)

为什么我的程序会崩溃,除非我取消注释printf来电?

这是两个函数的反汇编:

确定版本(带printf电话):

0804844d <my_func>:
 804844d:   55                      push   %ebp
 804844e:   89 e5                   mov    %esp,%ebp
 8048450:   83 ec 18                sub    $0x18,%esp
 8048453:   c7 04 24 30 85 04 08    movl   $0x8048530,(%esp)
 804845a:   e8 b1 fe ff ff          call   8048310 <puts@plt>
 804845f:   8b 45 08                mov    0x8(%ebp),%eax
 8048462:   89 c3                   mov    %eax,%ebx
 8048464:   53                      push   %ebx
 8048465:   e8 c6 fe ff ff          call   8048330 <strlen@plt>
 804846a:   8a 03                   mov    (%ebx),%al
 804846c:   c9                      leave  
 804846d:   c3                      ret   

崩溃版本(没有printf电话):

 0804841d <my_func>:
 804841d:   55                      push   %ebp
 804841e:   89 e5                   mov    %esp,%ebp
 8048420:   8b 45 08                mov    0x8(%ebp),%eax
 8048423:   89 c3                   mov    %eax,%ebx
 8048425:   53                      push   %ebx
 8048426:   e8 d5 fe ff ff          call   8048300 <strlen@plt>
 804842b:   8a 03                   mov    (%ebx),%al
 804842d:   5d                      pop    %ebp
 804842e:   c3                      ret    

1 个答案:

答案 0 :(得分:1)

"push %%ebx\n\t"
"call strlen\n\t"
你在堆栈上有PUSH个东西。你希望谁POP从堆栈中删除某些内容(清理你的调用参数)?

Linux使用“caller cleanup”调用约定,并且通过不清理调用堆栈,使my_func返回虚假地址(导致SIGSEGV)。