1

[我对 CPU 寄存器感到困惑,我还没有在整个互联网上找到任何真正清晰和连贯的解释。如果有人有有用的链接,如果您将其发布在评论或答案中,我将不胜感激。]

我现在在这里的主要原因是因为我一直在查看示例 NASM 程序,[迄今为止徒劳无功] 尝试学习该语言。该程序总是通过放入系统调用代码eax然后调用来结束int 0x80(如果有人也可以解释,我会很高兴)。但是,据我了解,eax是一个 32 位寄存器 - 为什么需要 32 位来存储系统调用(我敢肯定没有 2 32值)。此外,有时我会在程序本身期间看到其他值和字符串移动到 eax 中。这是否意味着eax只有当您最终想要执行系统调用时才有特殊用途,但在其余时间您可以随意使用它?

4

3 回答 3

3

使用所有位,eax因为这就是系统调用接口的实现方式。确实没有 2 32系统调用,甚至没有 2 16。但就是这样。它允许轻松扩展系统调用集。你不需要去想它,只要接受它作为一个事实并继续生活。

eax是一个通用寄存器,您可以随心所欲地使用它。它用于包含系统调用 ID 的事实只是一个既定的约定,仅此而已。eax无论如何都不会被禁止用于其他用途。

于 2013-02-26T05:19:03.323 回答
2

该程序总是通过在 eax 中放置一个系统调用代码然后调用 int 0x80 来结束(如果有人也能解释一下,我会很高兴)。

这是因为您只查看旧的 32 位 Linux 示例,而这正是 Linux 开发人员想做的事情。他们没有理由不能使用不同的寄存器,也没有太多理由不能使用半个寄存器(例如,aax而不是eax,或bx或..)。以类似的方式,他们没有理由不能使用调用门或不同的中断号。当然,一旦 Linux 开发人员做出决定(“内核将期望 EAX 中的函数号并使用 int 0x80”),调用其内核的所有内容都必须遵守他们的决定;并且他们不能在不破坏所有现有软件的情况下轻易改变他们的决定(但可以并且确实支持替代方案 - 例如添加对sysentersyscall当这些指令被发明时,同时确保它int 0x80仍然有效)。

但是,据我了解, eax 是一个 32 位寄存器 - 为什么需要 32 位来存储系统调用(我确定没有 232 个值)

他们并不“需要” 32 位;但是您可以期望函数编号(在“值是否太大”健全性检查之后)最终会在call [table+eax*4]指令中用于调用所选函数,并且因为它使用 32 位寻址,所以需要使用 32-位寄存器。使用寄存器的一半(或四分之一)将涉及零扩展(例如额外and eax,0x0000FFFFmovzx eax,ax指令)以将 16 位值转换为 32 位值。由于其他原因,使用所有 32 位通常也更快(例如mov ax,123,设置 EAX 的最低 16 位并保持最高 16 位不变将取决于最高 16 位的先前值,这可能导致“依赖关系停顿” " 如果它需要等到 EAX 的先前值已​​知,则在 CPU 中)。

这是否意味着 eax 仅在您最终想要执行系统调用时才有特殊用途,而在其余时间您可以随意使用它?

这意味着当你调用别人的代码时,你必须遵守别人的调用约定,不管它们是什么。这可能意味着将其他寄存器(ebx,ecx等)用于他们决定的任何目的,并且可能意味着使用特定的堆栈布局(例如以特定顺序将事物推入堆栈)。

请注意,有各种指令确实希望以特定方式使用特定寄存器 - mul, div, stosd, movsd, loop, in, out, enter,leave等;每个通用寄存器都有“罕见的特殊情况”。尽管如此; 它们仍然是“通用寄存器”,因为它们不是“特定用途寄存器”(例如eip或标志,只能用于一个特定目的,而不能用于其他任何用途)。

于 2020-10-17T05:44:46.040 回答
1

eax 是一个通用寄存器,你可以在里面放任何你想要的东西。int 0x80 是系统调用的中断...该中断查看 eax 中的值并调用该系统例程。

于 2013-02-26T04:52:39.893 回答