C.内联汇编错误的翻译

时间:2014-09-20 16:42:54

标签: c gcc assembly inline-assembly i386

我在C:

中有这个功能
int write(int fd, char *buffer, int size)
{
    int ret;

    __asm__("mov $4, %%eax;"
            "mov %0, %%ebx;"
            "mov %1, %%ecx;"
            "mov %2, %%edx;"
            "int $0x80"
            : "=r"(ret)
            : "g"(fd), "g"(buffer), "g"(size)
            : "eax", "ebx", "ecx", "edx");

    if (ret < 0) {
        return -1;
    } else {
        return 0;
    }
}

在ASM中转换为此代码:

push   %ebp
mov    %esp,%ebp
push   %esi
push   %ebx
mov    $0x4,%eax
mov    %esi,%ebx
mov    0x8(%ebp),%ecx
mov    0xc(%ebp),%edx
int    $0x80
mov    %esi,%eax
sar    $0x1f,%eax
pop    %ebx
pop    %esi
pop    %ebp
ret

作为fd,*缓冲区和大小是函数参数,它们分别是0x8(%ebp),0xc(%ebp)和0x10(%ebp)。为什么GCC在%esi中识别fd的位置,而另外两个变量在堆栈中移位?如何运行此函数(正确获取寄存器中的变量)?

2 个答案:

答案 0 :(得分:1)

这可能是您架构上的调用约定。如果要将其他参数约束到寄存器,则应直接使用寄存器约束:例如。 "a"代表eax注册。

开头的$4对我来说也是错误的。

沿线的东西

     __asm__(
        "int $0x80"
        : "=b"(ret)
        : "c"(fd), "d"(buffer), "a"(size)
        );

应该这样做,如果它们真的是你的系统调用使用的寄存器。

但是,总的来说,我认为你不应该自己这样做。您的操作系统肯定有类似syscall的功能,可以为您提供该功能。

答案 1 :(得分:0)

内联汇编程序的参数从输出开始从零开始编号,因此%0为ret,%1为fd,%2为缓冲区,%3为大小。