- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
如何在 Delphi 汇编器中协调短条件跳转与分支目标对齐?
我正在使用 Delphi 版本 10.2 Tokyo,用于 32 位和 64 位程序集,完全使用程序集编写一些函数。
如果我不使用.align
,编译器会正确编码short
条件跳转指令(由1字节操作码组成的2字节指令074h
和 1 字节相对偏移量 -+ 直至 07Fh)。但是,如果我放置一个 .align
,即使小到 .align 4
- 所有条件跳转指令都位于 .align 之前,并且目标位于 .align 之后.align
- 在这种情况下,所有这些指令都变成 6 字节指令,而不是应有的 2 字节指令。只有位于 .align 之后的指令仍被正确编码为 2 字节 short
。
Delphi 汇编器不接受“短”前缀。
如何在 Delphi 汇编器中使用 .align
协调短条件跳转和分支目标对齐?
这是一个示例程序 - 请注意中间有一个.align
。
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;
下面是它的编码方式 - 位于 align
之前的条件跳转,指向 label2 和 label3(在 align
之后)被编码为 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:
但是如果我删除 .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:
返回条件跳转指令:如何在 Delphi 汇编器中使用 .align
协调短条件跳转和分支目标对齐?
我承认在 SkyLake 及更高版本的处理器上对齐分支目标的好处很小,并且我知道我可以避免使用 .align
- 它还会节省代码大小。但我想知道如何使用 Delphi 汇编器通过 align
生成短跳转。此问题不仅在 64 位目标中存在,在 32 位目标中也存在。
最佳答案
除非您的汇编器可以选择进行更好的分支位移优化(这可能需要重复传递),否则您可能会运气不好。 (当然,您可以自己手动完成所有对齐,但每次更改任何内容都必须重新完成。)
或者您可以使用不同的汇编器进行汇编。但正如我所料,这是非常不可取的because you lose access to Delphi-specific stuff like object layout for things declared outside of the asm 。 (感谢@Rudy 的评论。)
您可以在 Delphi 汇编器中编写一些函数,并在那里尽可能多地执行 Delphi 特定的操作。在另一个汇编器中编写关键循环部分,hexdump 将其机器代码输出转储到放入 Delphi 程序集中间的 db
伪指令中。
如果每个函数的开头至少与函数内的任何内容一样对齐,那么这可以正常工作,但您可能最终会浪费指令或将常量放入寄存器中供 NASM 部分使用,这可能会更糟而不仅仅是拥有更长的分支。
<小时/>Only the instructions that are located after the .align remain correctly encoded as 2-byte short
这不太准确。第一个 je label1
看起来不错,它位于 .align
之前。
看起来任何跨越尚未评估的 .align
指令的分支都会为 rel32
留下空间,并且汇编程序永远不会回来并修复它。其他所有情况似乎都很好:向后分支跨越 .align
,以及向前分支不跨越 .align
。
分支位移优化不是一个简单的问题,特别是当有 .align
指令时。不过,这似乎是一个真正次优的实现。
相关:Why is the "start small" algorithm for branch displacement not optimal?有关汇编器用于分支位移优化的算法的更多信息。即使优秀的汇编器也可能无法做出最佳选择,尤其是当存在 .align
指令时。
关于delphi - 如何在 Delphi 汇编器中将短条件跳转与分支目标对齐与 `.align` 协调起来?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45112065/
某些 AMD64/x86 命令需要立即值作为操作数(例如 imm8)。是否可以使用存储在某个寄存器中的值(例如 ah)来代替这个硬编码值? 例如: 如果我想移动 xmm 寄存器,可以使用 pslldq
您好,我正在修改汇编级编程。我有以下代码 mov al, 'H' call my_function my_function: mov ah,0x0e ;
x86 汇编程序例程通常以以下序言开始: push ebp ; Save ebp mov ebp, esp ; Set
这个问题已经有答案了: What is the purpose of XORing a register with itself? [duplicate] (7 个回答) 已关闭 2 年前。 我们有时
如果您不了解二进制,我知道 BCD 是更直观的数据类型。但我不知道为什么要使用这种编码,它好像没有多大意义,因为它浪费以 4 位表示(当表示大于 9 时)。 另外,我认为 x86 仅支持直接添加和替换
x86 汇编程序例程通常以以下序言开始: push ebp ; Save ebp mov ebp, esp ; Set
var a int[1]; var aa int[1]; aa = a; 假设我们想在 java jvm 中编译这样的东西。看起来人们只会做一个 ldc 1 newarray int astor
是否有任何编写 MIPS 汇编器的引用指南或教程? 最佳答案 如果您希望实际编写汇编程序,您需要知道您正在编写的平台的可执行文件的格式(例如 ELF ),那么您需要使用 MIPS instructio
我想写一个简单的 M.A.R.I.E.计算表达式 A x B + C x D 的程序. 现在,关于 Marie 汇编语言的信息并不多。我不确定是否有乘法?如果没有,我是否必须循环或其他东西才能使其成倍
我想知道为 NASM 编写汇编代码的格式是什么。有什么地方教的吗?我尝试在 NASM 上运行 MASM32 文件,但我认为它无法识别指令。 最佳答案 总是有 the manual . 关于linux
我想要的是类似 g++ 的东西,我可以在其中输入: compiler_name my_assembly_code.extention ...并让它编译我的汇编代码。它是 32 位还是 64 位并不重要
我正在为 8086 开发一个汇编程序。我的问题是如何将十六进制操作码转换为可执行文件,如 .EXE、.ELF、.COM、a.out 等。为此寻找链接/资源,汇编程序应该执行链接过程还是由操作系统自动?
我想编写 64 位 Windows 程序集(最好使用 NASM)。我在谷歌上看起来很不错,但似乎找不到 64 位 Windows 编译器。一些站点提到了 ml64,但它似乎不再包含在 VC++ 中。我
使用 GNU Binutils 声明汇编代码时,例如: .long MY_Label .long MY_Second_label 即使操作码和其他信息在地址空间中将它们分开,也可以在进行十六进制转储时
似乎单元测试这些天变得风靡一时,我知道你们中的许多人会想:“那么为什么不直接使用语言 X 和框架 Y 呢?”但我提出这个想法更多是为了证明概念,或者是出于对我早年计算机编程的怀念。 我正在研究使用 N
作为编译器项目的一部分,我必须为 x86 编写 GNU 汇编器代码来比较浮点值。我试图找到有关如何在线执行此操作的资源,据我了解,它的工作原理如下: 假设我要比较的两个值是浮点堆栈上的唯一值,则 fc
操作系统:Windows 10 CPU:英特尔酷睿 i5-5300U 架构:x64 我刚刚开始学习汇编语言。我使用了在线编译器,但今天我下载了NASM。我尝试编写这个将 10 乘以 15 的简单代码:
查看以下代码: (ebp-0x8 -> int) (ebp-0x4 -> int*) => 0x80483f3 : mov DWORD PTR [ebp-0x8],0x0 0x80483
我需要编写一个类似 CorFlags 的应用程序。如果我有程序集文件的路径,我该如何读取它的 CorFlags? 我特别需要知道程序集是 Any-CPU 还是仅 x86 我想避免使用反射加载程序集,因
查看以下代码: (ebp-0x8 -> int) (ebp-0x4 -> int*) => 0x80483f3 : mov DWORD PTR [ebp-0x8],0x0 0x80483
我是一名优秀的程序员,十分优秀!