如何在Delphi中跨内联汇编块访问已声明的标签?
解决Delphi内联汇编跨块访问标签的问题
汇编语言通常比高级语言更快。比如我在Delphi里测试过一个重复10亿次的空循环:Delphi编写的循环耗时60亿个x64 CPU周期,而汇编实现的相同循环仅耗时20亿个周期。
当需要高性能操作时,我会优先用汇编编码,但有时不得不插入高级语言代码。我尝试把汇编块拆分,中间执行高级代码后再回到汇编循环,结果报错了。
测试代码如下:
program Test; {$APPTYPE CONSOLE} {$R *.res} uses Sysutils; var f, i: int64; begin asm rdtsc mov dword ptr f[0], eax mov dword ptr f[4], eax mov eax, 1000 @loop: sub eax, 1 end; WriteLn('Hello, World!'); asm; jnz @loop rdtsc mov dword ptr i[0], eax mov dword ptr i[4], eax end; ReadLn; // Allow user to read output end.
预期是打印1000次Hello, World!,但编译时报错:
E2003: Undeclared identifier: '@loop' at line 23 (23:1)
问题本质是:Delphi的内联汇编中,单个@开头的局部标签仅在当前asm块内有效,无法跨块访问。
解决方案
利用Delphi的全局标签机制,在Pascal代码中声明全局标签,即可在多个汇编块之间共享引用:
修改后的代码:
program Test; {$APPTYPE CONSOLE} {$R *.res} uses Sysutils; // 声明全局Pascal标签 label loop_label; var f, i: int64; begin asm rdtsc mov dword ptr f[0], eax mov dword ptr f[4], edx // 修正rdtsc的使用:高32位存在edx中 mov eax, 1000 @loop_label: // 在汇编中用@+标签名定义全局标签的位置 sub eax, 1 end; WriteLn('Hello, World!'); asm jnz @loop_label // 跨汇编块引用全局标签 rdtsc mov dword ptr i[0], eax mov dword ptr i[4], edx // 同样修正此处的rdtsc存储错误 end; ReadLn; end.
说明
- 在Pascal代码段中用
label关键字声明全局标签,标签名可自定义; - 在汇编块中定义标签时,需要在标签名前加
@前缀,格式为@标签名:; - 在其他汇编块中引用该标签时,同样使用
@标签名的格式,即可实现跨块访问; - 顺便修正了原代码中
rdtsc指令的使用错误:该指令将时间戳低32位存入eax,高32位存入edx,原代码两次存储eax会导致时间戳数据错误。
内容的提问来源于stack exchange,提问作者JOrE
相关产品推荐
相关产品推荐

