问题:
我的理解是寄存器EAX,EBX,ECX,EDX
是"通用"根据{{3}}或多或少可互换。link。那么为什么当我在下面的代码中交换操作数/值时,它不再打印"Hello World!"
。
测试
切换mov
后面的寄存器edx
和ecx
下面的值/操作数。
mov edx,13
mov ecx,msg
到
mov edx,msg
mov ecx,13
结果:
打破代码。我显然误解了它是如何工作的,所以会赞赏一些指导。最终,我试图更好地理解为什么以及如何使用某些寄存器。
代码示例:
取自here的原始工作代码:
section .text
global _start ;must be declared for linker (ld)
_start: ;tells linker entry point
mov edx,13 ;message length
mov ecx,msg ;message to write
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg db 'Hello, world!', 0xa ;string to be printed
len equ $ - msg ;length of the string
答案 0 :(得分:2)
寄存器可以平等使用,但它们不一定具有相同的含义。系统调用每个为它们分配不同的含义:
int 0x80
要求eax
用于确定您正在调用的系统调用。sys_write
(eax
为4)要求ebx
持有文件描述符,ecx
保留字符缓冲区,edx
保持长度。 如果你交换这些值,你肯定会得到正确的结果,因为它与将错误位置的值传递给函数的情况相同;它不会得到它所期望的。
在您自己的代码中,您可以随意使用它们(这就是“可互换”在该介绍页面上的真正含义),但是当您调用其他代码时,您必须遵循其他代码可能设置的任何规则。
答案 1 :(得分:2)
程序中断了,因为这些寄存器是可以互换的:它们的含义是写入它们的代码部分与从中读取的部分之间的协议。
在您的情况下,int 0x80
控制内核进程,该进程希望从这些寄存器中读取某些值。正如对原始代码的评论所说,它希望阅读:
eax
的系统电话号码(4 = sys_write)ebx
(1 = stdout)ecx
edx
如果您交换周围的值,它无法知道您已经这样做了;所以它从ecx
读取值13,并假设你的字符串开始的地方,然后从edx
读取一个内存地址,并假设你的字符串长度。
就高级语言而言,就像你改变了这一点:
sys_call(sys_write, stdout, msg_address, 13);
到此:
sys_call(sys_write, stdout, 13, msg_address);