当前位置: 首页 > 知识库问答 >
问题:

在Delphi汇编程序中,如何用`. align '协调短条件跳转和分支目标对齐?

管景天
2023-03-14

如何在Delphi汇编程序中协调短条件跳转与分支目标对齐?

我使用Delphi版本10.2 Tokyo,用于32位和64位汇编,完全使用汇编编写一些函数。

如果我不使用.align,编译器会正确编码条件跳转指令(2字节指令,由1字节操作码074h和1字节相对偏移量组成 - 高达07Fh)。但是,如果我放一个.align,甚至小到.align 4 - 所有条件跳转指令都位于.align之前,目标位于.align之后 - 在这种情况下,所有这些指令都变成了6字节指令,而不是它们应该的2字节。只有位于 .align 之后的指令仍保持正确编码为 2 字节短。

Delphi汇编程序不接受'短'前缀。

如何在Delphi汇编器中将短条件跳转与分支目标对齐进行协调?

这是一个示例过程-请注意,中间有一个。对齐

    procedure Test; assembler;
    label
      label1, label2, label3;
    asm
      mov     al, 1
      cmp     al, 2
      je      label1
      je      label2
      je      label3
    label1:
      mov     al, 3
      cmp     al, 4
      je      label1
      je      label2
      je      label3
      mov     al, 5
      .align 4
    label2:
      cmp     al, 6
      je      label1
      je      label2
      je      label3
      mov     al, 7
      cmp     al, 8
      je      label1
      je      label2
      je      label3
    label3:
    end;

以下是它的编码方式:<code>align</code>之前的条件跳转,指向label2和label3(在<code>aling</code>)被编码为6字节指令(这是64位CPU目标):

0041C354 B001          mov al,$01      //   mov     al, 1
0041C356 3C02          cmp al,$02      //   cmp     al, 2
0041C358 740C          jz $0041c366    //   je      label1
0041C35A 0F841C000000  jz $0041c37c    //   je      label2
0041C360 0F8426000000  jz $0041c38c    //   je      label3
0041C366 B003          mov al,$03 //label1: mov al, 3
0041C368 3C04          cmp al,$04      //   cmp     al, 4
0041C36A 74FA          jz $0041c366    //   je      label1
0041C36C 0F840A000000  jz $0041c37c    //   je      label2
0041C372 0F8414000000  jz $0041c38c    //   je      label3
0041C378 B005          mov al,$05      //   mov     al, 5
0041C37A 8BC0          mov eax,eax     //  <-- a 2-byte dummy instruction, inserted by ".align 4" (almost a 2-byte NOP)
0041C37C 3C06          cmp al,$06 //label2: cmp al, 6
0041C37E 74E6          jz $0041c366    //   je      label1
0041C380 74FA          jz $0041c37c    //   je      label2
0041C382 7408          jz $0041c38c    //   je      label3
0041C384 B007          mov al,$07      //   mov     al, 7
0041C386 3C08          cmp al,$08      //   cmp     al, 8
0041C388 74DC          jz $0041c366    //   je      label1
0041C38A 74F0          jz $0041c37c    //   je      label2
0041C38C C3            ret        // label3:

但是如果我删除<code>。align-所有指令的大小都正确-只有2个字节,与以前一样:

0041C354 B001          mov al,$01      //   mov     al, 1
0041C356 3C02          cmp al,$02      //   cmp     al, 2
0041C358 7404          jz $0041c35e    //   je      label1
0041C35A 740E          jz $0041c36a    //   je      label2
0041C35C 741C          jz $0041c37a    //   je      label3
0041C35E B003          mov al,$03 //label1: mov     al, 3
0041C360 3C04          cmp al,$04      //   cmp     al, 4
0041C362 74FA          jz $0041c35e    //   je      label1
0041C364 7404          jz $0041c36a    //   je      label2
0041C366 7412          jz $0041c37a    //   je      label3
0041C368 B005          mov al,$05      //   mov     al, 5
0041C36A 3C06          cmp al,$06 //.align 4 label2:cmp al, 6
0041C36C 74F0          jz $0041c35e    //   je      label1
0041C36E 74FA          jz $0041c36a    //   je      label2
0041C370 7408          jz $0041c37a    //   je      label3
0041C372 B007          mov al,$07      //   mov     al, 7
0041C374 3C08          cmp al,$08      //   cmp     al, 8
0041C376 74E6          jz $0041c35e    //   je      label1
0041C378 74F0          jz $0041c36a    //   je      label2
0041C37A C3            ret             //   je      label3
                                //  label3: 

返回到条件跳转指令:如何使用< code >将短条件跳转与分支目标对齐进行协调。Delphi汇编程序中的align?

我承认在SkyLake和更高版本的处理器上调整分支目标的好处很小,我知道我可以避免使用< code >。align -它还会保存代码大小。但是我想知道如何用Delphi汇编程序生成带有< code>align的短跳转。这个问题不仅在64位目标中存在,在32位目标中也存在。

共有1个答案

苏高峰
2023-03-14

除非您的汇编器可以选择进行更好的分支位移优化(这可能需要重复通过),否则您可能会倒霉。(当然,您可以自己手动完成所有对齐,但每次更改任何内容时都必须重新完成。)

或者,您可以使用其他汇编程序进行组装。但正如我所预料的那样,这是非常不可取的,因为你无法访问Delphi特定的东西,比如在asm之外声明的东西的对象布局。(感谢@Rudy的评论。

您可以在Delphi汇编器中编写一些函数,并在那里尽可能多地执行Delphi特定的内容。在另一个汇编器中编写关键循环部分,hexump将其机器代码输出转储到您放在Delphi程序集中间的db指令中。

如果每个函数的开始至少与函数中的任何内容一样对齐,这可以正常工作,但是您可能最终会浪费指令或将常量放入寄存器中以供NASM部分使用,这可能比只有更长的分支更糟糕。

只有位于。对齐后的指令保持正确编码为2字节短

这不太准确。第一个 je label1 看起来不错,它位于 .align 之前。

它看起来就像任何穿过尚未评估的< code >的分支。align指令为< code>rel32留出了空间,汇编程序再也不会回来修复它。其他情况似乎都没问题:在< code >上向后分支。对齐,并转发不与< code >交叉的分支。对齐。

分支置换优化不是一个简单的问题,尤其是当有< code >时。align指令。然而,这似乎是一个真正的次优实现。

相关:为什么分支位移的“小起点”算法不是最优的?有关汇编器用于分支位移优化的算法的更多信息。即使是优秀的汇编程序也可能不会做出最佳选择,尤其是当存在<code>时。对齐指令。

 类似资料:
  • 本文向大家介绍汇编语言 跳转指令与C语言的条件分支,包括了汇编语言 跳转指令与C语言的条件分支的使用技巧和注意事项,需要的朋友参考一下 跳转指令 跳转指令也是一个组的指令,称为j组。其中jmp为无条件跳转,其余为条件跳转 上图为j组指令,可结合条件码访问指令加深理解 在机器指令水平上理解如何对跳转指令编码 如上图,通过反汇编软件得到机器指令与汇编语言,其中左边为机器指令编码,右边为对应汇编语言含义

  • 这与这个问题有关 想想看,在现代英特尔中央处理器上,证券交易委员会阶段是在微码中实现的,这意味着将有一个检查,通过该检查,一个烧毁的密钥被用来验证PEI ACM上的签名。如果它不匹配,那么它需要做一些事情,如果它匹配,它需要做其他事情。鉴于这是作为MSROM过程实现的,必须有一种分支方式,但鉴于MSROM指令没有RIP。 通常,当分支误预测为被采用时,则当指令失效时,ROB将检查异常代码,并因此将

  • 我正在阅读Jeff Duntemann的汇编语言分步,我对一些条件跳转的工作原理感到困惑。我知道用于使用减法比较两个值,然后丢弃结果以设置标志。 有没有办法确定哪些标志需要设置/取消设置?我了解JE和JNE的情况,它查看是否设置了ZF,但我不确定其他分支操作。 这是我被卡住的部分: 如果EDX,为什么JAE会回环

  • 有时我们需要根据不同条件执行不同的操作。 我们可以使用 if 语句和条件运算符 ?(也称为“问号”运算符)来实现。 if 语句 if(...) 语句计算括号里的条件表达式,如果计算结果是 true,就会执行对应的代码块。 例如: let year = prompt('In which year was ECMAScript-2015 specification published?', '');

  • align-items属性与justify content相同。 但在这里,物品在交叉通道(垂直)上对齐。 Usage - align-items: flex-start | flex-end | center | baseline | stretch; 此属性接受以下值 - flex-start - 弹性项目在容器顶部垂直对齐。 flex-end - 弹性项目在容器底部垂直对齐。 flex-c

  • 问题内容: 我刚刚遇到了一个Codility问题,这给我带来了困难,但我仍在尝试弄清楚如何才能满足空间和时间复杂性的限制。 问题如下:数组中的主要成员是占据数组中一半以上位置的成员,例如: {3,67,23,67,67} 67是主要成员,因为它在数组中以3/5(> 50%)的位置出现。 现在,您将期望提供一种方法,该方法接受一个数组并返回一个占主导地位的成员(如果存在)的索引,如果不存在则返回-1