Inline x86 ASM

Introduction

PureBasic allows you to include any x86 assembler commands (including MMX and FPU one) directly in the source code, as if it was a real assembler. And it gives you even more: you can use directly any variables or pointers in the assembler keywords, you can put any ASM commands on the same line, ... On Windows and Linux, PureBasic uses fasm (http://flatassembler.net), so if you want more information about the syntax, just read the fasm guide.
On OS X, PureBasic uses yasm (http://yasm.tortall.net/), so if you want more information about the syntax, just read the yasm guide.

To activate the inline assembler use the compiler directives EnableASM and DisableASM.
It's possible to enable the ASM syntax coloring in the IDE with the "enable inline ASM syntax coloring" compiler option.

Rules

You have several rules to closely follow if you want to include ASM in a BASIC code :

- The used variables or pointers must be declared before to use them in an assembler keyword
- When you reference a label, you must put the prefix 'll_' before the name. This is because PureBasic add a 'll_' before a BASIC label to avoid conflict with internal labels. The label need to be referenced in lowercase when using the in-line ASM. If the label is defined in a procedure, then its prefix is 'l_procedurename_', in lowercase.
- When you reference a module item, you must put the prefix 'module_name.' all in lowercase before the item.

Example

  MOV ebx, ll_mylabel
  ...
  MyLabel:
- The errors in an ASM part are not reported by PureBasic but by FASM. Just check your code if a such error happen.
- With enabled InlineASM you can't use ASM keywords as label names in your source.
- On x86 processors, the available volatile registers are: eax, ecx and edx. All others must be always preserved.
- On x64 processors, the available volatile registers are: rax, rcx, rdx, r8, r9, xmm0, xmm1, xmm2 and xmm3. All others must be always preserved.
- Windows only: an ASM help-file could be downloaded here. If you place the 'ASM.HLP' in the 'Help/' folder of PureBasic, you can also get help on ASM keywords with F1. (Note: this feature is only enabled, when InlineASM is enabled).

When using assembler in a procedure, you have to be aware of several important things:

- To return directly the 'eax' (or 'rax' on x64) register content, just use ProcedureReturn, without any expression. It will let the 'eax' (or 'rax' on x64) register content untouched and use it as return-value.

Example

  Procedure.l MyTest()
    MOV eax, 45
    ProcedureReturn  ; The returned value will be 45
  EndProcedure
- Local variables in PureBasic are directly indexed by the stack pointer, which means if the stack pointer change via an ASM instruction (like PUSH, POP etc..) the variable index will be wrong and direct variable reference won't work anymore.

- It's possible to pass directly an assembly line to the assembler without being processed by the compiler by using the '!' character at the line start. This allow to have a full access to the assembler directives. When using this, it's possible to reference the local variables using the notation 'p.v_variablename' for a regular variable or 'p.p_variablename' for a pointer

Example

  Procedure Test(*Pointer, Variable)
    ! MOV dword [p.p_Pointer], 20
    ! MOV dword [p.v_Variable], 30
    Debug *Pointer
    Debug Variable
  EndProcedure
  
  Test(0, 0)

Example

AsmInline.pb