c - 在 gcc 的内联 asm 中使用 printf 函数

标签 c gcc assembly segmentation-fault inline-assembly

我想在 gcc 上测试内联 asm 功能。 因此,我在 ubuntu 12.04 64 位上键入并编译了以下代码 但系统在运行时在屏幕上显示“段错误”。 我不知道是什么导致了这个问题。

#include <stdio.h>
char Format[]="Hello world %d\n";
int main()
{
    asm
    (
        "movl $3,4(%esp);"
        "movl $Format,(%esp);"
        "call printf;"
    );
    return 0;
}

谢谢大家帮助我这个程序新手。 我使用 Code::blocks 作为 IDE 来编写这段代码。我曾尝试使用像 %rdx 这样的 64 位寄存器,但是在编译代码时构建消息的日志显示“错误:错误的寄存器名称‘%rdx’”。我认为这意味着 Code::blocks 调用的 gcc 是 32 位版本,因此它无法识别这些寄存器。 我修改代码保留栈空间

#include <stdio.h>
char Format[]="Hello world %d\n";
int main()
{
    asm
    (
        "subl $8,%esp;"         //I  don't know  $4, $8, $12, $16, $20 which is correct
                                        //but I had tried them all but results are still  ''segmentation fault."
        "movl $3,4(%esp);"
        "movl $Format,(%esp);"
        "call printf;"
        "movl %ebp,%esp;"
    );
    return 0;
}

甚至使用 -m32 作为编译器选项,但它仍然显示“段错误”。

再次感谢谁的帮助。

最佳答案

System V ABI for x64 要求函数的前六个整数/指针参数应放入寄存器 %rdi%rsi%rdx%rcx%r8%r9。堆栈用于传递更多参数。它还要求在调用参数数量可变的函数时(如 printf),%rax 应设置为 中传递的浮点参数总数>XMM 寄存器。在您的情况下调用 printf() 的正确顺序是:

xorl %eax, %eax
movl $Format, %edi
movl $3, %esi
call printf

%rax 应设置为 0,因为没有传递浮点参数。该代码还利用了这样一个事实,即初始化数据的 VA 通常位于前 4 GiB 的某个位置,因此使用了更短的 32 位指令。当然 printf 仍将检查 %rdi 的全部内容以确定格式字符串在内存中的位置。

您的代码使用 32 位调用约定,如果使用 -m32 交叉编译为 32 位,理论上应该可以工作,但您应该首先使用 之类的东西为参数保留堆栈空间subl $20, %esp 并在使用 addl %20, %esp 调用后恢复它,否则你要么覆盖 main() 的堆栈,要么 ret 会选择错误的返回地址。这是一个完全有效(经过测试)的 C/asm 代码,可以在 32 位模式下编译和运行:

#include <stdio.h>

char Format[] = "Hello world, %d\n";

int main (void)
{
   asm
   (
      // Make stack space for arguments to printf
      "subl $8, %esp\n"
      "movl $3, 4(%esp)\n"
      "movl $Format, (%esp)\n"
      "call printf\n"
      // Clean-up the stack
      "addl $8, %esp\n"
   );
   return 0;
}

$ gcc -m32 -o test.x test.c
$ ./test.x
Hello world, 3

备注:我在每个 assembly 线的末尾使用\n而不是;只是为了提高编译器 assembly 输出的可读性——它与正确性无关的代码。

关于c - 在 gcc 的内联 asm 中使用 printf 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11378181/

相关文章:

linux - 为什么系统调用会破坏 rcx 和 r11?

c - Varnish 守护进程未启动 : Resource temporarily unavailable

GCC 编译时命令提示符卡住

gcc - 使用较旧的 libc 进行编译(未找到版本 `GLIBC_2.14')

c - DWARF 信息对于 DW_AT_high_pc 与 gcc 4.8.2 似乎是错误的

c - 硬件平方根 gcc

c - 如何使用源代码测量每个节点的 MPI 基准?

c - 初始化char数组的不同方式

c - x++ 的增量操作何时发生?

assembly - FLAGS/EFLAGS 是 clobber 列表的 "CC"(条件控制)的一部分吗?