Intermixing ASM and BASIC code

There are special conditions with register preservation that apply when writing mixed assembler and BASIC code.  PowerBASIC is a highly optimized compiler and among its optimizations are reductions in the stack overhead between BASIC code statements.  Therefore, compiled PowerBASIC code is designed to expect that the EBX, ESI, and EDI registers will remain unchanged between lines of BASIC code.

This means that if your assembler algorithm uses any of the EBX, ESI, or EDI registers, you must preserve their original state from the last line of BASIC code that precedes the Inline Assembler code.  This is, you must PUSH them before your ASM code, and POP them again right before the BASIC code commences.

This may appear to be more code than is necessary but it must be remembered that the internal structure of PowerBASIC does not duplicate the stack preservation that the application programmer must apply, so in terms of the stack overhead, the code is actually very efficient.

It should be noted that if your ASM code uses the EAX, ECX, or EDX registers, you should also preserve these as the internal execution of BASIC statements can also freely modify any of these three registers too.

The overall approach to preserving the registers around intermixed ASM and BASIC code is demonstrated in the following listing:

SUB TestProc(var1&, var2&)

  #REGISTER NONE    ' Ensure there is no conflict with

                    ' PowerBASIC Register variables

 

  ' Code that uses EAX ECX and EDX goes here

  ...

  ! PUSH EAX        ' Save the scratch registers

  ! PUSH ECX

  ! PUSH EDX

  ...

  ' Call an API function here

  ...

  ! POP EDX         ' Restore the scratch registers

  ! POP ECX

  ! POP EAX

  ...

  ' Other ASM code that uses EAX ECX and EDX goes here

  ...

  ! PUSH EBX        ' Save the volatile registers

  ! PUSH ESI

  ! PUSH EDI

  ...

  ' Other BASIC statements here, for example:

  var1 = var2 + 2^8 - COS(var2)

  ...

  ! POP  EDI        ' Restore from the stack

  ! POP  ESI

  ! POP  EBX

  ...

  ' More ASM code that relies on EBX, etc

 

END SUB

Using this format ensures that you are writing "safe" code and that all of the utilized registers are preserved, because:

With those points in mind, if there are no BASIC statements or API calls after the assembler code, preserving these registers is of no consequence.  In this case, the automatic preservation code will take care of EBX, ESI, and EDI registers before the Sub/Function terminates, and we can be sure that the calling code will also preserve the EAX, ECX, and EDX registers using the same conventions.

PROGRAMMING TIP: As described above, the EBX, ESI, and EDI registers are automatically preserved at the start and exit of a Sub/Function.  Therefore, if you need to use registers for counters or to store other values in your Inline Assembler code, you may use any of the EBX, ESI, or EDI registers for this purpose as they are restored when the Sub/Function terminates.  This helps ensure efficiency and can result in even slightly faster code since we do not have to preserve extra registers each time the Sub/Function is executed.

 

See Also

The Inline Assembler

Registers

Data types in registers

MMX registers

Using ESP and EBP

Saving registers

Saving Registers at the Sub/Function level

Saving the FPU registers

Tricks in preserving registers