NASM 汇编中的每个变量和寄存器名称都只是一个指针吗?

Is every variable and register name just a pointer in NASM Assembly?

有[]种操作类似于高级语言中的解引用。那么这是否意味着每个变量和寄存器名称都只是一个指针,或者指针是高级语言的想法并且在汇编中没有用处?

指针在 asm 中是一个有用的概念,但我不会说符号名称是真正的 指针。它们是地址,但它们不是指针,因为没有存储它们(元数据除外,并且嵌入到机器代码中),因此您无法修改它们。指针可以递增。


变量 是一个 high-level 概念,在汇编中并不真正存在。 Asm 有标签,您可以将其放在任何部分的任何字节位置,包括 .data.text 或其他任何内容。除了像 dd 这样的指令,您还可以为全局变量保留 space 并为其附加一个符号。 (但是变量的值可以暂时存在于寄存器中,或者如果它是局部变量则可以在其整个生命周期中存在。变量的 high-level 概念不必映射到带有标签的静态存储。)

整数与指针等类型在汇编中也不存在;一切都只是字节,您可以将其加载到整数、XMM 甚至 x87 FP 寄存器中。 (如果你使用 eaxfloat 的字节从一个内存位置复制到另一个内存位置,你实际上不必将其视为 type-punning 到整数并返回,你'只是加载和存储以复制字节。)


但另一方面,指针是一个low-enough级别的概念,在汇编中仍然高度相关。我们有堆栈指针 (RSP),它通常包含一个有效地址,指向我们用作堆栈的一些内存 space。 (不过,你 可以 使用 RSP 寄存器来保存不是有效地址的值。在那种情况下,你不会将它用作指针。但在任何时候你都可以执行push 指令,或 mov eax, [rsp],并导致无效地址异常。)

指针是一个保存另一个对象地址的对象。(我在这里使用 C 术语中的“对象”:您存储的任何字节[s]可以访问,包括像 int 这样的东西。不像 object-oriented 编程那样反对。)所以指针基本上是一种整数数据,特别是在没有多个平面内存模型的汇编中它的组成部分。对于分段内存模型,seg:off 远指针是一对整数。

因此,存储在寄存器或内存中任何位置的任何有效地址都可以有效地视为指针。

但是不,标签定义的符号不是指针。从概念上讲,我认为将其视为标签很重要。 指针本身就是一个对象(一些字节的存储空间),因此可以修改。例如增加一个指针。但是符号只是引用某个固定位置的一种方式。


在 C 术语中,符号类似于 char symbol[],而不是 char *symbol = NULL; 如果您使用裸 symbol,您将得到地址。类似于 NASM 语法中的 mov edi, symbol。 (或 GNU 中的 mov edi, OFFSET symbol。intel_syntax 或 MASM。另请参阅 以了解实际考虑,例如如果 32 位绝对地址不起作用,则使用 RIP-relative LEA。)

您可以取消引用 asm 中的任何符号以访问那里的字节,无论是 mov eax, [main] 加载该函数机器代码的前 4 个字节,还是 mov eax, [global_arr + rdi*8] 索引到数组中,或 . (Caveat: 32-bit absolute addresses no longer allowed in x86-64 Linux? 最后一个例子)。

但是你不能arr++;这是没有意义的。任何地方都没有存储该地址的存储空间。它被嵌入到每个使用它的站点的程序的机器代码中。它不是指针。 (请注意,C arr[4] = 1 编译为不同的 asm,具体取决于 char *arr;char arr[],但在 asm 中,您必须从 [=74] 的任何位置手动加载指针值=] 存储,然后用一些偏移量取消引用它。)

如果你在 asm 中有一个标签,你想在 C 中使用它的地址,但是没有附加到一些存储字节,你通常希望将其声明为 extern const char end_of_data_section[]; 或其他。

因此,例如您可以执行 size_t data_size = data_end - data_start; 并将字节大小作为 link-time 常量,如果您将这些符号安排在 end/start 处10=] 部分。使用链接描述文件或 NASM 源中的 global data_end / data_end:。一开始可能与其他符号位于同一地址。

汇编语言没有变量、指针或类型检查。它有地址和寄存器(没有类型检查)。

变量(例如在 C 语言中)是一种更高层次的东西 - 一种抽象一段数据位置的方法,这样你就不必关心编译器是想把它放在寄存器中还是在记忆。变量也有类型;它用于检测某些类型的错误,并用于允许编译器自动为您将数据转换为不同的类型。

指针(例如在 C 中)是一个变量(见上文)。指针和“非指针”之间的主要区别在于它包含的数据类型 - 对于指针,变量通常包含一个地址,但指针不仅仅是一个地址,它是具有类型的地址。这很重要——如果它只是一个地址,那么编译器将不知道它有多大,无法检测到某些类型的错误,也无法自动转换数据(例如,考虑 int foo = *pointer_to_char; 会发生什么如果编译器不知道指针指向什么类型的数据)。