从 gcc 调用一个简单的汇编程序

时间:2021-03-25 23:37:28

标签: assembly x86 x86-64

我有以下程序通过 printf 函数打印一个数字:

format: .ascii "Your number is: %d.\n\0"

.globl main
main:

    // printf('%d', 55);
    mov $format, %rdi
    mov $55, %rsi
    mov $0, %eax

    // call printf with 16-byte aligned stack:
    sub $8, %rsp
    call printf
    add $8, %rsp

    // return 0;
    mov $0, %eax
    ret
$ gcc -no-pie int.s -o int; ./int
Your number is: 55.

我在写这篇文章的时候有几个问题:

  • sub $8...add $8 是否可以正常工作以保持对齐?例如,与执行 push %rbp...pop %rbp 相同。
  • 我尝试添加一些 .data.rodata.text 指令/部分,但每次我都会收到警告/错误。为什么在通过 gcc 调用汇编程序时不允许这些?例如,C 如何知道“格式”是 .data 而“main”是在 .text 中?
  • mov $0, %eax; ret 是否是从程序集中退出 C 主函数的正确方法?
  • 最后,我需要做哪些修改才能让这个程序在不执行 -no-pie 的情况下运行?

1 个答案:

答案 0 :(得分:2)

<块引用>

sub $8...add $8 是否可以正常工作以保持对齐?例如,与执行 push %rbp...pop %rbp 相同。

是的。如果你阅读 pushpop 的指令描述,你会发现它们对堆栈指针有相同的影响,除了读/写你不关心的寄存器和堆栈内存.不过,pushpop 是较短的指令。

<块引用>

例如,C 如何知道“格式”是 .data 而“main”是在 .text 中?

除非你告诉它,否则它不会,他们也不会。如果您使用 objdump --full-contents 转储您的可执行文件,您会看到您的字符串已与其他所有内容一起放入 .text 中,因为您从未告诉汇编程序要这样做。

<块引用>

mov $0, %eax; ret 是否是从程序集中退出 C 主函数的正确方法?

是的,虽然 xor %eax, %eax ; ret 效率更高。 What is the best way to set a register to zero in x86 assembly: xor, mov or and?

<块引用>

最后,我需要做哪些修改才能让这个程序在不执行 -no-pie 的情况下运行?

在与位置无关的可执行文件中不允许使用绝对地址作为立即数,因此 mov $format, %rdi 不好。而是使用 RIP 相对寻址:lea format(%rip), %rdi。其他都还好。

相关问题