[我对CPU寄存器感到困惑,我没有在整个互联网上找到任何真正清晰和连贯的解释。如果有人链接到有用的东西我会非常感激,如果你发表评论或回答。]
我现在在这里的主要原因是因为我一直在寻找样本NASM程序[迄今为止徒劳]尝试学习该语言。程序总是通过在eax
中放置一个系统调用代码然后调用int 0x80
来结束(如果有人可以解释,我会很喜欢)。但是,根据我的理解,eax
是一个32位寄存器 - 为什么你需要32位存储系统调用(我确定没有2 ^ 32值)。此外,有时我会在程序本身看到其他值和字符串移入eax。这是否意味着eax
只有在您最终想要执行系统调用时才有特殊用途,但在其余时间您可以随意使用它?
答案 0 :(得分:2)
使用eax
的所有位,因为这是系统调用接口的实现方式。确实没有2 32 系统调用,甚至2 16 。但就是这样。它允许轻松扩展系统调用集。你不需要仔细思考它,只需接受它作为一个事实并继续存在。
eax
是一个通用注册表,您可以随意使用它。它用于包含系统调用ID的事实只是一个既定的约定而不是其他任何东西。 eax
绝不会被禁止用于其他用途。
答案 1 :(得分:2)
程序始终以在eax中放置系统调用代码,然后调用int 0x80(如果有人也能解释的话,我会很高兴)来结束。
这是因为您仅查看Linux的旧32位示例,这就是Linux开发人员的想法。他们没有理由不能使用其他寄存器,也没有太多理由不能使用一半寄存器(例如,用ax
而不是eax
或bx
或..)。以类似的方式,没有理由他们不会使用呼叫门或其他中断号。当然,一旦Linux开发人员做出了决定(“内核将期望EAX中的函数号并使用int 0x80”),所有调用其内核的东西都必须遵守他们的决定。而且他们不能轻易改变他们的决定而不破坏所有现有软件(但是可以并且确实支持替代方法-例如,在发明了这些说明后,增加对sysenter
和syscall
的支持,同时确保{{ 1}}的工作原理相同)。
但是,据我了解,eax是一个32位寄存器-为什么需要32位来存储系统调用(我确定没有232价值)
他们不需要“ 32位”。但您可以预期该函数号(在“值是否太大”的健全性检查之后)最终会在int 0x80
指令内使用以调用所选函数,并且因为该函数需要使用32位寻址使用32位寄存器。使用寄存器的一半(或四分之一)会涉及零扩展(例如,额外的call [table+eax*4]
或and eax,0x0000FFFF
指令)以将16位值转换为32位值。由于其他原因,使用所有32位通常也更快(例如movzx eax,ax
设置EAX的最低16位,而保留最高的16位不变,这取决于最高16位的先前值,并且如果需要等待直到知道EAX的先前值,就会在CPU中造成“依赖关系停止”。
这是否意味着eax仅在您最终想要执行系统调用时才有特殊用途,而在其余时间中,您可以随意使用它?
这意味着当您调用别人的代码时,无论它们是什么,都必须遵守别人的调用约定。这可能意味着出于他们决定的目的而使用其他寄存器(mov ax,123
,ebx
等),并且可能意味着使用特定的堆栈布局(例如,以特定的顺序将内容压入堆栈)。
请注意,有多种指令确实希望以特定方式使用特定寄存器-ecx
,mul
,div
,stosd
,{{1} },movsd
,loop
,in
,out
等;每个通用寄存器都有“罕见的特殊情况”。尽管如此;它们仍然是“通用寄存器”,因为它们不是“特定目的寄存器”(例如enter
或标志,它们只能用于一种特定目的,而不能用于任何其他用途)。
答案 2 :(得分:1)
eax是一个通用寄存器,你可以在其中放入任何你想要的东西。 int 0x80是系统调用的中断...该中断查看eax中的值并调用该系统例程。