如何确保Delphi例程的16字节代码对齐?

如何确保Delphi例程的16字节代码对齐?,delphi,memory-alignment,Delphi,Memory Alignment,背景: 我有一个优化的Delphi/BASM例程单元,主要用于繁重的计算。其中一些例程包含内部循环,如果循环开始与DQWORD(16字节)边界对齐,我可以实现显著的加速。如果我知道例程入口点的对齐方式,我可以确保所讨论的循环按照需要对齐 据我所见,Delphi编译器将过程/函数与DWORD边界对齐,例如,向单元中添加函数可能会改变后续函数的对齐方式。但是,只要我将例程的末尾填充为16的倍数,我就可以确保后续例程同样对齐——或者不对齐,这取决于第一个例程的对齐方式。因此,我尝试将关键例程放在单元实

背景:

我有一个优化的Delphi/BASM例程单元,主要用于繁重的计算。其中一些例程包含内部循环,如果循环开始与DQWORD(16字节)边界对齐,我可以实现显著的加速。如果我知道例程入口点的对齐方式,我可以确保所讨论的循环按照需要对齐

据我所见,Delphi编译器将过程/函数与DWORD边界对齐,例如,向单元中添加函数可能会改变后续函数的对齐方式。但是,只要我将例程的末尾填充为16的倍数,我就可以确保后续例程同样对齐——或者不对齐,这取决于第一个例程的对齐方式。因此,我尝试将关键例程放在单元实现部分的开头,并在它们前面添加一些填充代码,以便第一个过程与DQWORD对齐

如下所示:

接口
程序一级预处理;
实施
程序uu PadFirstProcTo16;
asm
//此处的NOP指令数量可变,以获得所需的代码长度
结束;
程序一级预处理;
asm//应该从DQWORD边界开始
//做点什么
//填充以将以下标签与DQWORD边界对齐
@一些标签:
//代码,循环回@Some16BAlignedLabel
//做点别的
返回参数
//填充以使代码长度达到16的倍数
结束;
初始化
__padt16//在此处调用此选项,以便不会对其进行优化
ASSERT((NativeUInt(指针(@FirstProcInUnit))和$0F)=0,‘FirstProcInUnit未对齐’;
结束。
这有点让人头疼,但我可以在必要的时候让这类东西发挥作用。问题是,当我在不同的项目中使用这样一个单元,或者对同一项目中的其他单元进行一些更改时,这可能仍然会破坏
\uu PadFirstProcTo16
本身的一致性。同样,使用不同的编译器版本(例如D2009与D2010)重新编译同一项目通常也会破坏对齐。所以,我发现做这类事情的唯一方法是手工,当项目的其余部分都处于最终状态时,这几乎是最后一件要做的事情

问题1:

是否有其他方法可以达到预期效果,确保(至少某些特定的)例程与DQWORD对齐

问题2:

哪些是影响编译器代码对齐的确切因素,以及(如何)我可以使用这些特定的知识来克服这里概述的问题


假设出于这个问题的考虑,“不要担心代码对齐/相关的可能很小的速度优势”不是一个允许的答案。

您可以做的一件事是,在每个例程结束时,在显式ret指令之后添加一个“魔术”签名:

asm
  ...
  ret
  db <magic signature bytes>
end;
asm
...
ret
分贝
结束;

现在,您可以创建一个数组,其中包含指向每个例程的指针,在运行时扫描例程一次,以查找神奇的签名,从而找到每个例程的结尾及其长度。然后,您可以使用PAGE_EXECUTE_READWRITE将它们复制到VirtualAlloc分配的新内存块中,确保这一次每个例程都在16字节边界上启动。

从Delphi XE开始,现在可以使用
$codeAllign
编译器指令轻松解决代码对齐问题(请参阅):


注意:我也在Embarcadero的BASM论坛上发布了这篇文章:这似乎也是一个选择,谢谢。我将进一步研究这种方法。
{$CODEALIGN 16}
procedure MyAlignedProc;
begin
..
end;