【问题标题】:addressing in assembler在汇编器中寻址
【发布时间】:2010-03-02 15:17:00
【问题描述】:

有些东西我无法消化。我正在学习一些汇编程序,现在我正在处理寻址这一章。我理解用于取消引用的括号的概念,但是当我看到它的用法时,我就是无法理解它的意义。更准确地说,这里是我的困惑开始的地方:

mov al, [L1]

这里我假设 L1 是某种宏,它稍后会替换机器代码中的真实地址,对吧?

所以这条指令的作用是:取消引用al 寄存器(因为您几乎无法更改物理地址)并将值更改为存储在L1 中的值。

如果到目前为止一切正常:

mov [L1], al

类比的意思是,一定已经存储了一个地址(所以这样做是有道理的),你把它改到内存中的其他地方,对吧?

如果您能告诉我,如果您没有发现任何错误,请这样做,这将使我有可能继续学习。

最后一件事,NASM在我的代码下添加了一堆0xAA55(这个序列应该结束程序吧?),为什么会出现这么多次?

【问题讨论】:

  • NASM 增加了一堆 0xAA55。仅当您告诉它使用TIMES (512-($-$$))/2 DW 0xAA55 之类的奇怪东西(或者可能也适用于奇数计数的类似东西)而不是通常使用0 字节填充直到最终@ 512 字节块末尾的 987654329@ 引导扇区签名。正常方式(TIMES 510-($-$$) DB 0/dw 0xAA55)见 NASM 手册:nasm.us/doc/nasmdo12.html#section-12.1.3

标签: assembly nasm addressing


【解决方案1】:

L1 通常/可能是一个标签与内存中的一个特定地址相关联。程序员为方便起见定义了各种标签,这些标签用于象征性地表示内存中的特定位置(L1 是一个糟糕的名称;标签通常表示该位置的潜在用途:例如,PingCounter、ErrorMessage、Login等等)。

1 字节静态存储的标签是 C 编译器在全局范围内实现 char L1; 的方式。


在 NASM 语法中,mov edi, L1 将组装成movmov eax, imm32 形式,即标签地址将成为机器代码中的 32 位立即数。 (汇编器不知道最终的数值,但链接器知道。)请注意,在 MASM 语法中,这将是一个负载,您需要mov edi, OFFSET L1 才能立即获取标签地址。

但是mov al, [L1] 将汇编成不同的指令,将 32 位地址嵌入机器代码中作为要取消引用的地址。该指令从地址 L1 加载 1 个字节,并将其放在 AL 中。

在汇编语言中,这种间接寻址模式是通过将给定指令的源操作数或目标操作数括起来的方括号来表示的。 (但不能两者兼有:x86 每条指令最多只支持一个显式内存操作数。)

mov al, [L1]

使用存储在 L1 中的地址来定位内存中的某个位置,并在该位置读取 1 个字节(= 8 位 = AL 寄存器的大小),并将其加载到 AL 寄存器中。

  mov [L1], al

反过来。即,具体来说,读取存储在L1中的地址,使用该地址找到内存中的特定位置并将AL寄存器的内容存储在那里。


如果您了解以下关于 x86 系列中较新的处理器的信息不完整且有些过时,则此 primer on the 8086 architecture 对于开始使用 x86 系列的汇编语言可能非常有用。
从这种“古老的 CPU”(实际上仍在使用)开始的优点是基本概念都在那里,不受新的寄存器集、花哨的寻址模式、操作模式和其他概念的影响。较新的 CPU 更大的尺寸、功能和模式只是引入了选项的组合爆炸,所有(大多数?)它们都以它们的方式有用,但基本上与启动无关。

【讨论】:

  • 我想我现在明白了。只有一个但是。你说每个标签都代表一个地址,所以在第二条指令中实际存储到 L1 的是 AL 地址..? ?
  • 在第二条指令中,标签L1处的地址被设置为AL寄存器的值。
  • @stupid_idiot(顺便说一句,你似乎也不是)。不,AL(以及 AH、AX 和所有寄存器名称)是 not 内存位置,并且本身没有地址。它们仅引用 CPU 本身内的特定位置。确实,我的意思是“纠正”您在您的问题中使用“取消引用 al register”这一表达;没有关于 AL 的取消引用,在这种情况下,在这种情况下,AL 的寻址模式是“注册”。 (这可能会让人感到困惑,因为有时可以使用寄存器在内存中生成地址,然后取消引用)
  • oh..that ....oh..我刚刚意识到,您可能无法像其他内存空间一样寻址寄存器..但是如何将 AL 转换为机器代码?
  • 关于(= 16 bits = the size of AL register)AL 是一个 8 位寄存器
【解决方案2】:

很难回答你的问题,但我会尽力提供帮助。

在汇编中,符号只是地址的名称。在您的汇编源代码中,L1 是在别处定义的符号,汇编器会将其解析为内存偏移量。

取消引用时(使用 [] 表示法),您可以取消引用寄存器(如“mov al, [esi]”)或地址(如“mov al, [L1]”)。两个语句做同样的事情,唯一的区别是地址来自哪里。

我建议下载Intel CPU Documentation 并浏览说明参考。如果您不想不知所措,请从较旧的 x86 处理器(例如,486 或更早版本)开始阅读,该文档并不完全友好,但手头有它非常有用。

我不知道 NASM 的具体细节,我 15 年前通过 Turbo Assembler 学习了汇编,这些知识今天仍然有用:)

另外,我建议您尝试谷歌搜索“x86 汇编教程”,您会发现大量相关文档可能对您有用。

【讨论】:

    【解决方案3】:

    哦,最后一件事,NASM 添加了一个 我的代码下的一堆 0xAA55(这个 序列应该结束 程序对吗?),为什么会这样 很多次?非常感谢你 读到这里..

    我很确定这仅适用于您创建引导加载程序的情况。它是“引导签名”。假设您将此代码写入软盘(您生成的机器代码是否也正好是 512 字节?),那么当您想使用此引导加载程序代码启动计算机时,BIOS 将查看软盘并确定它是否是实际的引导加载程序。为了做到这一点,它将查看软盘第一个扇区的最后两个字节,这应该是0xAA55,表示它是可引导的。(同样,如果你从硬盘驱动器引导,这也是一样的。 ,或拇指驱动器,或其他任何东西。CD 略有不同,因为它们有 4096 字节扇区)

    在你的源代码中,最后一行是像$(times.. db 0xAA55 还是类似的东西?如果您不打算制作引导加载程序,则可以有效地删除该行。

    【讨论】:

    • 谢谢厄尔兹。我有点困惑,因为我认为这是一个常规指令,出了什么问题.. 现在我知道这只是 NASM 时髦模式,可以更轻松地进行编码,一切对我来说都很清楚。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-16
    相关资源
    最近更新 更多