我正在学习x86架构的nasm语法汇编。我发现了 HelloWorld程序的几个例子,还下载了一些其他的 例如Caculator。 - 我对我发现的一些事感到困惑, 例如,下面提到的两个样本之间有什么区别:
mov eax, 4 ; sys_write
mov ebx, 1
mov ecx, string ; string in .data section
mov edx, str_len ; string length
int 80h
现在看另一个例子(关注寄存器):
mov eax, str_len
mov ebx, string
mov ecx, 4
mov edx, 1
int 80h
您可以在上面的两个示例中看到,重点关注regesters。什么是 如果我指定“eax,4”或“edx,4”或者如果我分配了什么,则会有所不同 “ecx,4”。差异是什么?
寄存器是“特定的”特定类型的值,或者我可以分配 任何寄存器的任何价值?
注意:我正在学习NASM,如果你发现这个问题很愚蠢,请不要 咬。我甚至无法理解大会中的这种差异。
注意:我的目标平台是32位Linux。
答案 0 :(得分:2)
特定类型的值的寄存器是“特定的”还是我可以为任何寄存器分配任何值?
在x86上,CPU寄存器主要是“通用”,即在您自己的代码中,您可以非常自由地使用eax
vs edx
,除了少数使用隐式寄存器的指令({{1} })。
然后有特殊寄存器(段,控制,标志,div, mul, stos, movs, ...
)。
因此,您通常可以将任何值分配给任何[general]寄存器。
如果我指定“eax,4”或“edx,4”,或者如果我指定“ecx,4”,会有什么区别。
不同之处在于,值eip
将存储在4
或eax
寄存器中。它们都是32位“通用”x86寄存器,两者都只存储32个0或1个值,仅此而已(它们也不存储任何有关“类型”的信息或该值如何来自寄存器,它是如何在源代码中格式化的...... edx
与mov eax,16
相同,CPU确实只看到最终的二进制机器代码,对于两种变量的源代码都是相同的,并且会加载二进制值{ {1}}(16)进入注册表mov eax,0x10
)。即到目前为止,除了您的个人偏好之外,差别不大。
00..0010000
vs eax
的选择将开始重要的部分是使用这些寄存器(以某种方式解释位值),并且在您的示例中使用{{1 }}
该指令调用32位Linux内核服务,即隐藏在其后面的数千条代码行,为应用程序执行各种操作,并且这些行已经由分发供应商(或您自己)编译,并且它们是内核二进制文件。
Linux开发人员已经决定,eax
包含所请求服务的id-number,其他寄存器包含该特定服务的参数。
edx
为int 80h
,而您的第二个示例eax
将调用其他服务,具体取决于字符串的长度(eax = 4
长度为12个字符,因此linux内核将尝试为sys_write
参数提供eax = str_len
服务。
所以你的第二个例子不输出“Hello world”,并根据上下文判断它只是无效的例子。
当您调用一些不属于您的外部代码时,您必须在文档中搜索调用它的正确方法,以及传递参数的位置和方式以及必须满足的条件(例如,在64位模式下)在调用C函数时,通常还必须将堆栈"Hello world."
地址与16B边界对齐。)
对于32位Linux内核系统服务文档...不确定哪些文档最好和可靠,x86标记信息中的这个链接看起来有关于如何进行此类服务调用的详细和完整信息:https://blog.packagecloud.io/eng/2016/04/05/the-definitive-guide-to-linux-system-calls/
虽然来自Google https://syscalls.kernelgrok.com/的此链接列出了特定服务和预期参数(将其与检查sys_chdir
和其他人的linux手册相结合应该足够了。)
示例中的特定eax = 12
期望参数为: