我有以下程序通过 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
的情况下运行?答案 0 :(得分:2)
sub $8...add $8
是否可以正常工作以保持对齐?例如,与执行 push %rbp...pop %rbp
相同。
是的。如果你阅读 push
和 pop
的指令描述,你会发现它们对堆栈指针有相同的影响,除了读/写你不关心的寄存器和堆栈内存.不过,push
和 pop
是较短的指令。
例如,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
。其他都还好。