Intel寄存器的艺术 已翻译 100%

ismdeep 投递于 04/23 21:47 (共 14 段, 翻译完成于 04-26)
阅读 766
收藏 3
1
加载中

我为一本名为Scene Zine的在线杂志写了这篇文章。 Scene Zine 致力于 Demo Scene,它是一个数字艺术社区,致力于通过音乐,艺术和计算机编程的混合推动计算机的极限发展。 一个特殊类别的 demo scene 制作,大概是 4K,专注于最终制作的原始文件大小。 目标是尽可能将高质量的音乐,图形和动画放入只有4096个字节中。 这样做需要高度专业化的大小优化技术,因为4096字节的空间少于两页输入文本或真彩色Windows XP图标。 本文将讨论了其中的一些技巧。

有些人评论说他们希望在 Scene Zine 中看到更多的专业编程文章。 为了纠正这种情况,本文适用于所有汇编语言程序员。 它讨论了你的代码中使用哪些寄存器的技巧。 这些信息会简化你的编码,并帮助你编写更小的程序。


溪边九节
溪边九节
翻译于 04/24 18:56
0

当英特尔的工程师设计了最初的8086处理器时,他们对每个寄存器都有一个特殊的目的。当他们设计指令集时,他们期望根据每个寄存器执行的功能创建了许多优化和特殊的指令。根据Intel最初的计划使用寄存器可以使代码充分利用这些优化。不幸的是,这似乎是一门失传的艺术。很少有程序员知道英特尔的总体设计,大多数编译器都过于简单,或者专注于执行速度来正确使用寄存器。然而,理解寄存器和指令集如何组合在一起,是通向轻松编码道路上的一个重要步骤。
除了尺寸优化外,使用寄存器还具有其他优点。就像使用好的变量名一样,使用一致的寄存器使代码更具可读性。当它们被正确使用时,寄存器的含义几乎和循环计数器一样清晰,我用的是高级语言。事实上,在x86寄存器之后,我偶尔会用C来命名我的变量,因为寄存器是如此的描述性。有了适当的注册使用,x86汇编程序几乎可以作为一种高级语言进行自我记录。

liyue李月
liyue李月
翻译于 04/25 15:09
0

一致的寄存器使用带来的另一个好处是更好的压缩比。在使用压缩器打包最终版本的产品中,例如4K引擎,创建更多冗余代码可导致更小的打包尺寸。当代码一致地使用寄存器时,相同的指令序列开始反复出现。这反过来又提高了压缩比。

总之,所有x86系列CPU都有8个通用寄存器。寄存器的位宽是32位,但16位版本也可通过特殊的单字节指令前缀进行访问。在16位模式下,情况是相反的。低16位默认是可访问的,全部寄存器只能用前缀字节访问。

Tocy
Tocy
翻译于 04/24 14:42
0
每个注册寄存器的名称实际上都是专有缩写。“字母”寄存器EAX,EBX,ECX和EDX也是如此。 以下列表显示了寄存器名称及其含义:

  • EAX - 累加器寄存器
  • EBX - 基础寄存器
  • ECX - 计数器寄存器
  • EDX - 数据寄存器
  • ESI - 源指针
  • EDI - 目的地指针
  • EBP - 基本指针
  • ESP - 堆栈指针

除了通用寄存器外,x86处理器还具有8个字节大小的寄存器。 由于这些寄存器直接映射到EAX,EBX,ECX和EDX,它们是较大寄存器的一部分。 但是,从指令集的角度来看,8位寄存器是独立的实体。 例如,CL和CH寄存器不共享ECX寄存器的属性。 除AL和AH外,8位寄存器在指令集中没有任何特殊含义,因此本文未提及它们。
周其
周其
翻译于 04/26 10:55
0

EAX: 累加器

有三个主要的处理器架构:寄存器、堆栈和累加器。在寄存器体系结构中,在任意两个任意寄存器之间可以发生加法或减法之类的操作。在堆栈体系结构中,操作发生在堆栈顶部和堆栈上的其他项目之间。在一个累加器架构中,处理器有一个称为累加器的计算寄存器。所有的计算都发生在累加器中,而其他寄存器则充当简单的数据存储位置。

显然,x86处理器没有一个累加器架构。然而,它确实有一个类似于累加器的寄存器:EAX/AL.尽管大多数计算都可能发生在任意两个寄存器之间,但是指令集给了累加器特殊的首选项作为计算寄存器。例如,所有9个基本操作(ADD、ADC、CMP、SBB、SUB、TEST和XOR)都有特殊的单字节操作码,用于在累加器和常量之间进行操作。专门的操作,如乘法、除法、符号扩展和BCD修正只能在累加器中进行。

雪落无痕xdj
翻译于 04/24 20:49
0

由于大多数的计算都发生在累加器中,因此x86架构包含许多用于将数据移入和移出此寄存器的优化指令。首先,处理器具有十六个字节大小的XCHG伪码,用于在累加器和任何其他寄存器之间交换数据。这些并不是非常有用,但它们表明了英特尔工程师多么期望将累加器优先于其他寄存器。对他们来说,最好将数据交换到累加器中,而不是将数据放到原来的位置做处理。将数据移入和移出累加器的其他指令有LODS,STOS,IN,OUT,INS,OUTS,SCAS和XLAT。最后,MOV指令具有一个特殊的单字节伪码,用于将数据从连续内存位置移入累加器中。

在你的代码中,尽可能在累加器中执行尽可能多的工作。如你所见,其余七个通用寄存器的存在主要是用于支持发生在累加器中的计算的。

Tocy
Tocy
翻译于 04/24 15:02
0

EDX: 数据寄存器

在其余七个通用寄存器中,数据寄存器EDX与累加器是最为紧密地联系在一起的。处理超大数据项的指令(如乘法,除法,CWD和CDQ)将最高有效位存储在数据寄存器中,并将最低有效位存储在累加器中。从某种意义上说,数据寄存器是累加器的64位扩展。数据寄存器也在IO指令中起一定作用。在这种情况下,累加器保存要从端口读取或写入的数据,数据寄存器保存端口地址。

在你的代码中,数据寄存器在存储与累加器计算相关的数据时是非常有用的。根据我的经验,如果编写正确,大多数计算仅需要这两个寄存器进行存储。

Tocy
Tocy
翻译于 04/24 14:51
0

ECX: 计数寄存器

计数寄存器,ECX,在x86中等同的无所不在的变量i,在x86上的每一个与计数相关的指令都使用ECX。最明显的计数指令是循环、LOOPZ和LOOPNZ。另一个基于计数的指令是JCXZ,正如其名,当计数器为0时,它就会跳转。计数寄存器也会出现在一些位移操作中,其中包含要执行的位移的次数。最后,计数寄存器通过REP、REPE和REPNE前缀控制字符串指令。在这种情况下,计数寄存器决定了操作重复的最大次数。

特别是在演示中,大多数计算都发生在循环中。在这些情况下,ECX是循环计数器的合理选择,因为没有其他寄存器在它周围有这么多分支操作。唯一的问题是,这个寄存器是向下递减计数的,而不是像高级语言那样。设计一个向下的计数并不困难,所以这只是一个小问题。

雪落无痕xdj
翻译于 04/24 21:11
0

EDI: 目的变址寄存器

每个产生数据的循环都必须将结果存储在内存中,这样做需要一个可移动的指针。目的变址寄存器EDI就是该指针。目的变址寄存器中保存所有字符串操作的默认写入的地址。非常有用的字符串指令,很显然,是很少使用的STOS。STOS将来自累加器的数据复制到内存中并自增目的变址寄存器。这个单字节指令是完美的,因为任何计算的最终结果都应该在累加器中,并且将结果存储在滑动的内存地址中是一项常见任务。

许多编码人员将目的变址寄存器视为不过是额外的存储空间。这是个错误。所有例程都必须存储数据,而某些寄存器必须作为其存储指针。由于目的变址寄存器是为这项工作而设计的,因此将其用于额外存储是一种浪费。使用堆或其他寄存器进行存储,并使用EDI作为全局写入指针。

Tocy
Tocy
翻译于 04/24 16:36
0

ESI: 源变址寄存器

源地址寄存器ESI,与目标变址寄存器具有相同的属性。唯一的区别是源变址寄存器是用于读取而不是写入的。尽管所有的数据处理例程都是写入的,但并不是所有都需要读取,所以源变址寄存器并不普遍有用。但是,当需要使用它时,源变址寄存器与目标变址寄存器一样强大,并且具有相同类型的指令。

在你的代码没有读取任何类型数据的情况下,当然可以使用源变址寄存器来实现便捷的存储空间是可以的。

Tocy
Tocy
翻译于 04/24 14:55
0
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(0)

返回顶部
顶部