【发布时间】:2018-03-27 10:10:33
【问题描述】:
所以我正在尝试学习汇编(NASM)。问题是组装的资源非常基础 - 理论和稀有,我无法理解非常基础的东西。我知道汇编寄存器被用作处理器“内存”上的“变量”。但问题是,例如在这个“hello world”类型的程序中:
section .text
global _start ;must be declared for linker (gcc)
_start: ;tell linker entry point
mov edx,len ;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 from assembly!',0xa ;a message
len equ $ - msg ;length of message
我不明白为什么我们保存edx 上的消息长度和ecx 上写入的消息,例如here 在tutorialspoint 中说:
所以在这里我假设由于ECX应该有循环计数器,在一个类似C的程序中:
for(int i = 0; i < 5; i++)
{
printf("Hey!\n");
}
ECX 寄存器应包含i。但是在上面的程序中,我们将消息保存在ECX。
同样,当我们想从程序集中调用 C 函数时,我对保存参数的位置感到困惑,但我认为由于这是更高级的,如果我了解我保存在哪些寄存器中,我会逐渐了解会发生什么如果我想调用 C 函数。
谢谢!
【问题讨论】:
-
int 0x80 的文档告诉您需要使用哪些寄存器。
-
想象一下
int 0x80功能背后有很多代码,打印消息并不是魔法。并且这段代码已经以某种方式编译,期望字符串内存地址在ecx,所以你必须在调用系统服务之前调整你的代码以在期望的寄存器中有期望的参数。服务代码没有机会猜测您确实将哪个参数放入了哪个寄存器,它必须是固定的,因为您不能用它确实持有什么样的值来“标记”寄存器。如果你放入ecx内存地址,或者整数,或者浮点数,它只是32位,没有区别或一些“类型”。 -
寄存器是一种稀疏资源,所以你应该经常三思你的算法,设计使用合理数量的寄存器的代码,例如重新调整你的算法以使用它并不少见与计数器和数组索引相同的值(例如从 -5 计数到 0)等。如果您有
ecx空闲,则将其用作计数器是有意义的,但在您的示例中,如果您想打印消息5 次,使用一些免费寄存器作为计数器会更有意义,例如ebp/esi/edi。 -
你们太棒了!我对你们所有人都投了赞成票,我希望我能接受多个答案。我选择接受来自@kristjank 的那个,因为它是第一个回答的并且因为它很简单。
-
在您的示例中,寄存器的唯一用途是用于将参数传递给系统调用。该程序没有变量。 (嗯,你可以调用
msg一个数组变量。你确实把它放在读/写数据部分,所以C 中的等价物是char msg[] = { 'H', 'e', ..., '\n' };,而不是const char msg[]...(而不是字符串文字初始化器,因为数组不以0字节结尾;它不是 C 隐式长度字符串。)