【发布时间】:2012-06-30 15:38:57
【问题描述】:
我正在尝试学习 x86 汇编。我正在使用的书是Assembly Language - Step by Step, Programming With Linux(我不得不说它非常好)。到目前为止我学到了很多东西,但我觉得我也应该挑战自己,在很多方面保持领先,这样我才能通过实践更快地学习(我可以跟着做,自上而下的学习,但我觉得很乏味慢)。
所以,我认为尝试将两个寄存器(32 位)相乘然后将数据输出到控制台是一个很酷的主意。
问题是,当我执行程序时(我使用的是 NASM,就像本书一样 - 虽然没有 Insight 调试器),我收到了分段错误。我已经用这个小锤子在 gdb 中进行了大量调试,但无论出于何种原因,我似乎无法弄清楚问题所在。
我想知道为什么我会收到分段错误,以及有什么好的方法可以 谴责这个问题。另外,如果我在代码中创建的 cmets 与实际发生的情况不匹配,如果有人能纠正我,我将不胜感激。
这是我目前的代码(注释很好)
谢谢。
codez
section .data
;TODO
section .bss
valueToPrint: resb 4 ;alloc 4 bytes of data in 'valueToPrint'
section .text
global _start
_mul:
mov eax, 0x2A ;store 42 in eax
mov edx, 0x2A ;store 42 in edx
mul eax
ret
_safe_exit:
mov eax, 1 ;initiate 'exit' syscall
mov ebx, 0 ;exit with error code 0
int 0x80 ;invoke kernel to do its bidding
_start:
nop ;used to keep gdb from complaining
call _mul ;multiply the values
mov [valueToPrint], eax ;store address of eax in the contents of valueToPrint
mov eax, 4 ;specify a system write call - aka syswrite
mov ebx, 1 ;direction used to make the syswrite call output to console - i.e. stdout
mov dword [ecx], valueToPrint ;store valueToPrint in ecx: ecx represents the syswrite register
int 0x80 ;invoke kernel based on the given parameters
call _safe_exit
编辑
另外,我正在运行 Arch Linux,如果这有影响的话。
【问题讨论】:
-
在您的 _mul 子例程中,您使用的是
mul eax,它将 eax 与 eax 相乘...因为您在 eax 和 edx 中都使用了 42,所以您得到(嗯,您会得到)正确的答案,但你没有涉及 edx 中的值。 @Adam Rosenfield(下)有正确的答案,但您并没有首先创建要打印的 TEXT/ASCII 字符串。程序集并不会自动为您做任何事情。这就是为什么你有如此多的控制权......但你必须告诉它如何做每一件事。您没有创建 txt 字符串来指向 ecx 以进行打印。 (你还需要一个长度) -
另外,
mul(乘法)将 eax(ax/rax 等)中的值与指定的值相乘,并将生成的 64 位值放入 EDX:EAX... 所以如果你重新寻找完整的答案,记得也要使用 edx 值。 42*42=1764,所以你离 edx 的答案还很远,但你仍然应该知道这就是发生的事情,所以你可以期待 edx 改变并在需要时可用。 -
(天哪,我今晚很健谈!)一些挑剔的东西......你的'_safe_exit'子程序......因为它永远不会返回,你应该
jmp代替它。是的,当程序退出时,系统会转储所有内容......但同样,您应该知道事情是如何工作的。call _save_exit效果很好,但对我来说它在堆栈上留下了一个价值。挑剔的东西。我很抱歉。我开始在一台 16K 机器上组装,当时...内存很昂贵,而且您编写的代码很紧凑。我仍然这么认为,即使有 8G 的内存。通常较小的运行速度更快。 -
太棒了,洛尼克斯。谢谢你。我是如何让 eax 与 edx 相乘的?
-
mul edx。我很抱歉吹毛求疵...组装很棒,但你必须能够兼顾一切,因为它真的对你没有任何帮助,而且不知道事情如何相互作用会咬你。