我正在尝试在这里学习一些组装,我需要专业人士的帮助!
测试.s:
.data
helloworld:
.asciz "printf test! %i\n"
.text
.globl main
main:
push $0x40
push $helloworld
call printf
mov $0, %eax
ret
测试.工作.s:
.data
helloworld:
.asciz "printf test! %i\n"
.text
.globl main
main:
mov $0x40, %esi
mov $printf_test, %edi
mov $0x0, %eax
call printf
mov $0, %eax
ret
编译.sh:
rm test
gcc test.s -o test -lc
chmod 777 test
./test
test.s 立即出现段错误。我通过使用 Eclipse 中的反汇编窗口制作了 test.working.s,并编写了一个小的 C 程序来使用 printf 打印一些东西。
所以,问题!
为什么
test.s
不起作用在我的 C 程序中,main 被定义为 main(int argc, char ** argv) 不是吗?因此,
pop
如果我不需要这些论点,我不应该在开始时需要两次吗?在 x86-64 中,我在某处读到 %rax 是 64 位寄存器,%eax 是 32 位寄存器,而 %ax 是 16 位寄存器。那么寄存器看起来像这样:
XX XX EE EE RR RR RR RR
(R = RAX 的 4 位,E = EAX 的 4 位,X = AX 的 4 位)在 little-endian 系统上(1 表示为 0x01000000,我认为......)?GCC 不会让我输入
pop %eax
orpush %eax
。它只会让我输入 64 位版本或 16 位版本。那么如何将 RAX 的 32 个 EAX 位推入堆栈呢?如何仅弹出 32 位?test.working.s (我想这在 1 中得到了回答,但如果不是......)通过更改寄存器调用 printf,而不是通过将东西压入堆栈。我想这是因为它更快?在调用 c 函数时,您如何知道何时执行此操作以及按什么顺序执行此操作?
这也适用于 Windows x86-64 吗?我知道printf的操作可能会有所不同,但是如果我在printf之后清理并恢复寄存器,我应该可以吧?
你应该如何清理和恢复寄存器?根据http://www.cs.uaf.edu/2005/fall/cs301/support/x86/,它说我“必须保存 %esp, %ebp, %esi, %edi”。那是指当我编写一个函数时,这些寄存器必须以它们进入的方式返回,或者我应该在调用函数之前自己保存它们。可能是前者,因为 %esp,但只是检查!
很明显,我不需要 x86-64,尤其是因为我刚刚开始,那么我该如何更改 compile.sh 只为 x86 呢?
.asciz
仅仅意味着.ascii
+吗"\0"
?我可以返回驻留在 C 中的堆栈上的大型结构(>64 位)。这是如何在汇编中实现的?
为任何帮助干杯!