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”。
除了上述的这些情况之外,编译器不会为完全汇编例程加入其他多余的代码。
如果需要在例程中加入局部变量,但又不影响堆栈,可以使用在例程中定义类型化常量的方法,来代替变量声明。