原文地址

While implementing the x64 built-in assembler for Delphi 64bit, I got to “know” the AMD64/EM64T architecture a lot more. The good thing about the x64 architecture is that it really builds on the existing instruction format and design. However, unlike the move from 16bit to 32bit where most existing instruction encodings were automatically promoted to using 32bit arguments, the x64 design takes a different approach.

One myth about the x64 instructions is that “everything’s wider.” That’s not the case. In fact many addressing modes which were taken as absolute addresses (actually offsets within a segment, but the segments are 4G in 32bit), are actually now 32bit relative offsets now. There are very few addressing modes which use a full 64bit absolute address. Most addressing modes are 32bit offsets relative to one of the 64bit registers. One interesting addressing mode that is “implied” in many instruction encodings is the notion of RIP-relative addressing. RIP, is the 64bit equivalent of the 32bit EIP, or 16bit IP, or Instruction Pointer. This represents from which address the CPU will fetch the next instruction for execution. Most hard-coded addresses within many instructions are now relative offsets from the current RIP register. This is probably the biggest thing you have to wrap your head around when moving from 32bit assembler.

Even though many instructions will implicitly use the RIP-relative addressing mode, there are some instruction addressing modes that continue to use a 32bit offset, and are not RIP-relative. This can really bite you when doing simple mechanical translations from 32bit to 64bit. These are the SIB form with a 32bit (or even 8bit) offset. What can happen is that you end up forming an address that can only address 32bits, and is thus limited to addressing items below the 4G boundary! And this is a perfectly legal instruction! To demonstration this, consider the following 32bit assembler that we’ll translate to 64bits.

  var
TestArray: array[0..255] of Word; function GetValue(Index: Integer): Word;
asm
MOV AX,[EAX * 2 + TestArray]
end;

Let’s now translate this for use in 64bit using a simple mechanical translation.

  var
TestArray: array[0..255] of Word; function GetValue(Index: Integer): Word;
asm
MOVSX RAX,ECX
MOV AX,[RAX * 2 + TestArray]
end;

Pretty straight forward, right? Not so fast there partner. Let’s see;
I know that I need to use a full 64bit register for the offset but
since Integer is still 32bits, I need to “sign-extend” it to 64bits. The
venerable MOVSX (Move with sign extension) instruction “promotes” the
signed 32bit offset to 64bits while preserving the sign. Nope, that’s
not a problem. The only thing I changed in the next instruction was EAX
to RAX, so how could that be a problem? Well, when you compile this code
you’ll get a rather strange error message:

[DCC Error] Project7.dpr(18): E2577 Assembler instruction requires a 32bit absolute address fixup which is invalid for 64bit

Huh? Remember the little note above about the SIB instruction form?
Because the RAX (or EAX in 32bit) register is being scaled (the * 2),
this instruction must use the SIB (Scale-Index-Base) instruction form.
When using the SIB form RIP isn’t considered when calculating the actual
address. Additionally, the offset encoded in the instruction can still
only be 8 or 32bits. No 64bit offsets.

In 32bit, the compiler would generate a “fixup” to ensure that the
encoding of the instruction offset field to the global “TestArray”
variable was properly “fixed up” at runtime should the image happened to
be relocated to another address. This is a 32bit absolute address. The
64bit version of this instruction, while actually a truly valid
instruction, would only have 32bits in which to place the address of
“TestArray.” The “fixup” generated would have to remain 32bit. This
could lead to creating an image that were it ever relocated above the 4G
boundary, would likely crash at best or read the wrong memory address
at worst!

Ok, so now what? There is a SIB form that we can use to work
around this problem, but it requires burning another register. The good
news is that we now have another 8 registers with which to work. So if
you have a rather complicated chunk of 32bit assembler code that burns
up all the existing usable 32bit registers, you now have another group
of registers that can help solve this problem without having to rework
the code even more. So here’s how to fix this for 64 bit:

  var
TestArray: array[0..255] of Word; function GetValue(Index: Integer): Word;
asm
MOVSX RAX,ECX
LEA R10,[TestArray]
MOV AX,[RAX * 2 + R10]
end;

Here, I used the volatile R10 register (R8 an R9 are used for
parameter passing) to get the absolute address of TestArray using the
LEA instruction. While the “address” portion of this instruction is
still 32bits, it is taken as RIP-relative. In other words, this value is
the “distance” from the next instruction to the variable TestArray in
memory. After this instruction, R10 now contains a true 64bit address of
the TestArray variable. I must still use the SIB form in the next
instruction, but instead of a hard-coded “offset” I use the value in
R10. Yes, there is still an implicit offset of 0, which uses the 8bit
offset form.

You can see that mindless, mechanical translations of assembler code
is likely to cause you some grief due to some of the subtle changes in
instruction behaviors. For this very reason, we strongly recommend you
use all Object Pascal code instead of resorting to assembler when
possible. This will not only better ensure that your code will more
likely move unchanged to other processor architectures (think ARM here
folks), but you’ll not have to worry about such assembler gotchas in the
future. If you’re using assembler code because “it’s faster,” I would
encourage you to look closely at the algorithm used. There are many
cases where the proper algorithm written in Object Pascal will yield
greater gains than a simple translation to assembler using the same
algorithm. Yes there are some things which you simply must do in
assembler (strange, off-beat calling conventions, “LOCK” instructions
for concurrency, etc…), but I would contend that many assembler
functions can be moved back to Object Pascal with little impact on
performance.

x64 assembler fun-facts(转载)的更多相关文章

  1. More x64 assembler fun-facts–new assembler directives(转载)

    原文地址 The Windows x64 ABI (Application Binary Interface) presents some new challenges for assembly pr ...

  2. puppet之自定义fact(转载)

    1.使用环境变量'FACTERLIB'创建fact 1.1.在自定义目录里面定义一个fact,列出当前系统登录的用户数 [root@agent1 ~]# vim /var/lib/puppet/kis ...

  3. X64 Deep Dive

    zhuan http://www.codemachine.com/article_x64deepdive.html X64 Deep Dive This tutorial discusses some ...

  4. Cygwin安装时,选择163的源后出错:Unable to get setup.ini from <http://mirrors.163.com/cygwin/>

    [问题] 折腾: [记录]Cygwin下把make从v3.82换成v3.81 期间,选择了163的源,结果出错: Cygwin Setup Unable to get setup.ini from & ...

  5. VSTO 学习笔记(十)Office 2010 Ribbon开发

    原文:VSTO 学习笔记(十)Office 2010 Ribbon开发 微软的Office系列办公套件从Office 2007开始首次引入了Ribbon导航菜单模式,其将一系列相关的功能集成在一个个R ...

  6. VSTO 学习笔记(十一)开发Excel 2010 64位自定义公式

    原文:VSTO 学习笔记(十一)开发Excel 2010 64位自定义公式 Excel包含很多公式,如数学.日期.文本.逻辑等公式,非常方便,可以灵活快捷的对数据进行处理,达到我们想要的效果.Exce ...

  7. 浅谈OCR之Onenote 2010

    原文:浅谈OCR之Onenote 2010 上一次我们讨论了Tesseract OCR引擎的用法,作为一款老牌的OCR引擎,目前已经开源,最新版本3.0中更是加入了中文OCR功能,再加上Google的 ...

  8. Linux gdb调试器用法全面解析

    GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具,GDB主要可帮助工程师完成下面4个方面的功能: 启动程序,可以按照工程师自定义的要求随心所欲的运行程序. 让被调试的程序在工程师指定的断 ...

  9. 【VS开发】VSTO 学习笔记(十)Office 2010 Ribbon开发

    微软的Office系列办公套件从Office 2007开始首次引入了Ribbon导航菜单模式,其将一系列相关的功能集成在一个个Ribbon中,便于集中管理.操作.这种Ribbon是高度可定制的,用户可 ...

随机推荐

  1. Python撰写mail

    版本1   指定邮箱进行发送 """ 说明:指定账户密码进行邮件发送 由312051952@qq.com-->c4kaichen@163.com "&qu ...

  2. git之sourceTree操作流程

    1x.sourceTree的使用流程  12.Git管理工具对比(GitBash.EGit.SourceTree)  11.SourceTree使用SSH克隆码云项目 ====== 1x.source ...

  3. 变式配置简介 VARIANT CONFIGURATION

    变式物料类型KMAT; ITEM CATEGORY GROUP: main item 0002 sub item 0004 strategy group:25 requirement type: ke ...

  4. SAS PROC PRINT 常用选项和语句说明

    常用选项1.使用选项OBS=修改观测序号标签2.使用NOOBS选项不显示观测序号列3.使用ID语句在输出中取代观测序号列4.使用VAR选择输出的变量5.使用WHERE语句选择输出的观测6.使用数据集选 ...

  5. [二维码开发]二维码开发入门级demo

    最近开发一个项目,涉及到二维码开发,于是乎就到网上找下直接可用的资源,遇到两个问题: 1.网上资源不够完整,找到完整的资源,需要下载分,这个你知道的 2.ThoughtWorks.QRCode版本不对 ...

  6. is,as,类库

    is和as运算符: 所有类型的基类 object类型 - 基类:所有类型的基类,就类似是整个生物圈的生物类,是个大的概念 object o1 = new Random(); //object可以承载R ...

  7. 爬虫:输入网页之后爬取当前页面的图片和背景图片,最后打包成exe

    环境:py3.6 核心库:selenium(考虑到通用性,js加载的网页).pyinstaller 颜色显示:colors.py colors.py  用于在命令行输出文字时,带有颜色,可有可无. # ...

  8. How to solve “Dynamic Web Module 3.1 requires Java 1.7 or newer” in Eclipse

    How to solve “Dynamic Web Module 3.1 requires Java 1.7 or newer” in Eclipse Last updated on June 20t ...

  9. thymeleaf注入springboot

    thymeleaf注入springboot需要引入jar: <dependency> <groupId>org.springframework.boot</groupId ...

  10. js 模拟css3 动画2

    <html> <head> <title> javaScript缓动入门 </title> </head> <body> < ...