3.6 完全汇编例程与内嵌汇编例程

  BASM在例程中使用时,可以分成完全汇编例程和内嵌汇编例程两种。完全汇编是指用asm关键字替换了例程的begin,从而使例程完全由汇编代码实现。在Begin..End中间任意位置加入asm..end的Delphi例程都称为内嵌汇编例程。
  完全汇编例程中没有例程入口时的begin,因此,Delphi不会形成值参数的复制。这意味着在完全汇编例程中,值参数与常数参数的处理是一致的。
  通常情况下,编译器会自动处理例程的堆栈结构。但是,如果完全汇编例程不是一个子例程(例程嵌套),也没有入口参数(或它们只占用寄存器)和局部变量,则编译器不会为该例程产生堆栈结构。亦即是说,这样的例程不会在堆栈上分配空间。
  完全汇编例程的asm关键字会被编译器解释成例程入口代码。例如:

Unit1. pas.34: asm
0044C86C55 push ebp
0044C86D 8BEC mov ebp, esp

  只要定义了局部变量,或入口参数使用到了栈,则会生成上面的代码。但是,局部变量定义还会导致类似这样的一行代码产生:

0044C86F 83C4D8 add esp,-$28

  这行代码用于在栈上为局部变量分配空间(本例中是$28Bytes)。但是,如果所有变量在栈上分配的总空间不大于4字节,那么编译器会处理成:

0044C86F 51push ecx

  这样实际上也使esp调整了4字节。但效率会比“add esp,-$4”要好得多。如果局部变量是字符串、变体或接口类型,那么这些变量会被初始化为0。因此,这样的情况下,编译器通常采用“push $00”的方式来实现空间分配。而在一些复杂的情况下,编译器会直接写栈来初始化这些变量,例如:

0044C872 33C0 xor eax,eax
0044C874 8945FC mov [ebp-$041,eax

  对应于在入口代码中加入的“push ebp”,代码出口处,编译器会生成“pop ebp”。
  除了上述的这些情况之外,编译器不会为完全汇编例程加入其他多余的代码。
  如果需要在例程中加入局部变量,但又不影响堆栈,可以使用在例程中定义类型化常量的方法,来代替变量声明。

猜你喜欢

转载自www.cnblogs.com/YiShen/p/9881477.html
3.6