【问题标题】:Inline assembly in C program on x86_64 linuxx86_64 linux上C程序中的内联汇编
【发布时间】:2025-12-12 06:20:05
【问题描述】:

我在我的 linux x86_64 上构建了一个用 C 和内联汇编编写的简短程序。它应该将一个字符串写入标准输出。我是在网上的一篇文章中找到的:

int write_call( int fd, const char * str, int len ){
    long __res;
    __asm__ volatile ( "int $0x80":
        "=a" (__res):"0"(__NR_write),"b"((long)(fd)),"c"((long)(str)),"d"((long)(len)) );
    return (int) __res;
}

void do_write( void ){
    char * str = "Paragon output string.\n";
    int len = strlen( str ), n;
    printf( "string for write length = %d\n", len );
    n = write_call( 1, str, len );
    printf( "write return : %d\n", n );
}

int main( int argc, char * argv[] ){
    do_write();
    return EXIT_SUCCESS;
}

但是当我运行它时,它工作不正确,产生输出

"写返回:-14"

如果我在 32 位 linux 上构建并运行它,它会达到预期的效果。

经过一番研究,我发现指令“int $0x80”是一条 x86 指令,如果在 x86_64 上调用,它会截断寄存器中的参数。

但我找不到 x86_64 架构的“int $0x80”的适当替换。我的组装经验为零。

我应该输入什么而不是“int $0x80”来获得预期的结果?

【问题讨论】:

  • 使用 glibc 中的 write() 函数。如果你想知道它是如何工作的,可以反汇编glibc中的write()函数。

标签: c linux x86-64 inline-assembly


【解决方案1】:

对于 amd64,您需要使用“syscall”——并使用不同的寄存器——而不是“int 0x80”:

http://cs.lmu.edu/~ray/notes/linuxsyscalls/

http://blog.rchapman.org/post/36801038863/linux-system-call-table-for-x86-64

http://crypto.stanford.edu/~blynn/rop/

这是一个很好的例子:

How to invoke a system call via sysenter in inline assembly (x86/amd64 linux)?

#include <unistd.h>

int main(void)
{
    const char hello[] = "Hello World!\n";
    const size_t hello_size = sizeof(hello);
    ssize_t ret;
    asm volatile
    (
        "movl $1, %%eax\n\t"
        "movl $1, %%edi\n\t"
        "movq %1, %%rsi\n\t"
        "movl %2, %%edx\n\t"
        "syscall"
        : "=a"(ret)
        : "g"(hello), "g"(hello_size)
        : "%rdi", "%rsi", "%rdx", "%rcx", "%r11"
    );
    return 0;

【讨论】: