zoukankan      html  css  js  c++  java
  • x64 assembler fun-facts(转载)

    原文地址

    在为Delphi 64bit实现x64内置汇编程序时,我更加“了解”了AMD64 / EM64T架构。x64架构的优点在于它真正建立在现有的指令格式和设计之上。但是,与从16位到32位的移动不同,大多数现有指令编码自动升级为使用32位参数,x64设计采用不同的方法。

    关于x64指令的一个神话是“一切都更广泛。”事实并非如此。实际上,许多寻址模式被视为绝对地址(实际上是一个段内的偏移,但段是32位的4G),现在实际上是32位相对偏移。很少有寻址模式使用完整的64位绝对地址。大多数寻址模式相对于64位寄存器之一是32位偏移。在许多指令编码中“暗示”的一种有趣的寻址模式是RIP相对寻址的概念。RIP,是64位等效的32位EIP,或16位IP或指令指针这表示CPU将从哪个地址获取下一条执行指令。许多指令中的大多数硬编码地址现在是与当前RIP寄存器的相对偏移。从32位汇编程序移动时,这可能是你最需要的。

    即使许多指令将隐式使用RIP相对寻址模式,但仍有一些指令寻址模式继续使用32位偏移,并且不是RIP相关的。当从32位到64位进行简单的机械转换时,这真的会让你感到痛苦。这些是具有32位(甚至8位)偏移的SIB形式。可能会发生的是,您最终会形成一个只能寻址32位的地址,因此仅限于寻址低于4G边界的项目!这是一个非常合法的指导!为了演示这一点,请考虑以下32位汇编程序,我们将其转换为64位。

      VAR
    TestArray:阵列 [0..255] 字;

    function GetValue(Index:Integer):Word;
    asm
    MOV AX,[EAX * 2 + TestArray]
    结束 ;

    现在让我们使用简单的机械翻译将其转换为64位。

      VAR
    TestArray:array [0..255] of word;

    function GetValue(Index:Integer):Word;
    asm
    MOVSX RAX,ECX
    MOV AX,[RAX * 2 + TestArray]
    end ;

    挺直的吧?没有那么快的伙伴。让我们来看看; 我知道我需要使用一个完整的64位寄存器作为偏移量,但由于Integer仍为32位,我需要将其“符号扩展”为64位。古老的MOVSX(符号扩展移动)指令“将”带符号的32位偏移“提升”到64位,同时保留符号。不,这不是问题。我在下一条指令中唯一改变的是EAX to RAX,那怎么可能是个问题呢?好吧,当你编译这段代码时,你会收到一条相当奇怪的错误信息:


    [DCC错误] Project7.dpr(18):E2577汇编程序指令需要32位绝对地址修正,对于64位无效

    咦?还记得上面关于SIB指令表格的小注意事项吗?由于RAX(或32位EAX)寄存器正在缩放(* 2),因此该指令必须使用SIB(Scale-Index-Base)指令格式。使用SIB格式时,在计算实际地址时不考虑RIP。另外,指令中编码的偏移量仍然只能是8或32位。没有64位偏移。

    在32位中,编译器将生成“修正”以确保在运行时如果图像恰好被重新定位到另一个地址,则指令偏移字段对全局“TestArray”变量的编码在运行时被正确“修复”。这是一个32位的绝对地址。该指令的64位版本虽然实际上是一个真正有效的指令,但只有32位可以放置“TestArray”的地址。生成的“fixup”必须保持32位。这可能会导致创建一个图像,它曾经重新定位在4G边界之上,最多可能崩溃或者在最坏的情况下读取错误的内存地址!

    好的,现在怎么样?还有就是,我们可以用它来解决此问题SIB形式,但它需要烧另一个寄存器。好消息是我们现在有另外8个寄存器可供使用。因此,如果您有一个相当复杂的32位汇编程序代码块会烧毁所有现有的可用32位寄存器,那么现在您可以使用另一组寄存器来帮助解决此问题,而无需再对代码进行返工。所以这是如何解决这个64位:

      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 ;

    在这里,我使用易失性R10寄存器(R8和R9用于参数传递)来使用LEA指令获取TestArray的绝对地址。虽然该指令的“地址”部分仍为32位,但它被视为RIP相对。换句话说,该值是从下一条指令到内存中变量TestArray的“距离”。在此指令之后,R10现在包含TestArray变量的真实64位地址。我仍然必须在下一条指令中使用SIB表单,但不使用硬编码的“偏移”,而是使用R10中的值。是的,仍然存在0的隐式偏移,它使用8位偏移形式。

    您可以看到汇编代码的无意识的机械翻译可能会因为指令行为的一些细微变化而让您感到悲伤。出于这个原因,我们强烈建议您使用所有Object Pascal代码,而不是在可能的情况下使用汇编程序。这不仅可以更好地确保您的代码更可能不变地转移到其他处理器架构(想想ARM这里的人员),但是您将来不必担心这样的汇编程序陷阱。如果您使用的是汇编代码,因为“它更快”,我建议您仔细查看所使用的算法。在许多情况下,用Object Pascal编写的适当算法将比使用相同算法对汇编器的简单转换产生更大的收益。是的,你必须在汇编程序中做一些事情(奇怪的,

    https://www.cnblogs.com/xalion/p/10052328.html

  • 相关阅读:
    SpringBoot学习:整合shiro(验证码功能和登录次数限制功能)
    SpringBoot学习:整合shiro(rememberMe记住我功能)
    SpringBoot学习:整合shiro(身份认证和权限认证),使用EhCache缓存
    SpringBoot学习:整合Redis
    SpringBoot学习:获取yml和properties配置文件的内容
    SpringBoot学习:使用spring-boot-devtools进行热部署
    SpringBoot学习:添加JSP支持
    SpringBoot学习:整合MyBatis,使用Druid连接池
    DL杂谈
    YOLO3训练widerface数据集
  • 原文地址:https://www.cnblogs.com/findumars/p/10201385.html
Copyright © 2011-2022 走看看