PureBasic

Встроенный x86 ASM

Введение

PureBasic позволяет вам вставить любые команды ассемблера x86 (включая MMX и FPU) прямо в исходный код, как если бы это был настоящий ассемблер. Она даёт вам даже более того: вы можете прямо использовать любые переменные или указатели в ключевых словах ассемблера, вы можете помещать любые команды ассемблера в одной строке. На Windows и Linux, PureBasic использует Fasm (http://flatassembler.net), так что если Вы хотите больше информации о синтаксисе ассемблера, просто прочитайте руководство по Fasm.
На OS X PureBasic использует yasm (http://yasm.tortall.net/), поэтому если вы хотите больше информации о синтаксисе ассемблера, просто прочитайте руководство по yasm.

Чтобы активировать встроенный ассемблер используйте директивы компилятора EnableASM и DisableASM.
Можно включить подсветку синтаксиса ASM в IDE, с помощью параметра "Подсветка синтаксиса ASM инструкций" в Настройках компилятора .

Правила

Вам придётся строго следовать нескольким правилам, если вы хотите включать ASM в код PureBasic:

- Используемые Переменные и Указатели должны быть объявлены перед использованием их в ключевом слове ассемблера. Их имена в ассемблере - это 'v_variablename' и 'p_pointername', а в процедуре их имена 'p.v_variablename' и 'p.p_pointername'.
- Метки: При использовании встроенного ASM на метки нужно ссылаться в нижнем регистре. Когда вы ссылаетесь на метку, перед её именем вы должны поставить префикс 'l_'. Если метка определена в процедуре, то ее префиксом будет 'll_procedurename_' в нижнем регистре. Когда вы ссылаетесь на элемент модуля, перед элементом вы должны поставить префикс 'module_name.l_' в нижнем регистре. Если метка определена в процедуре внутри модуля, то ее префиксом является 'module_name.ll_procedurename_' в нижнем регистре.

Пример

DeclareModule MyModule
    LabelDeclareModule: ; Её имя: mymodule.l_labeldeclaremodule:
    Declare Init()
EndDeclareModule

Module MyModule
    Procedure Init()
        LabelModuleProcedure: ; Её имя: mymodule.ll_init_labelmoduleprocedure:
        Debug "InitFerrari()"
    EndProcedure

    LabelModule1: ; Её имя: mymodule.l_labelmodule1:
EndModule

Procedure Test(*Pointer, Variable)
    TokiSTART:  ; Его имя: ll_test_tokistart:

    ! MOV dword [p.p_Pointer], 20
    ! MOV dword [p.v_Variable], 30
    Debug *Pointer  ; Его имя: p.p_Pointer
    Debug Variable    ; Его имя: p.v_Variable
EndProcedure

VAR=1                      ; Её имя: v_VAR
*Pointt=AllocateMemory(10)    ; Его имя: p_Pointt

MyModule::Init()
Test(0, 0)

Label1: ; Её имя: l_label1:

!jmp l_labelend ; Инструкция на ассемблере должна использовать приведенные выше правила. Здесь это l_namelabel
;...
LabelEnd: ; Её имя: l_labelend:

- Ошибки в ассемблерной части кода сообщаются не компилятором PureBasic, а компилятором FAsm. Просто проверьте ваш код, если такие ошибки имеют место.
- При включенном встроенном ассемблере вы не сможете использовать ключевые слова ассемблера в качестве имён меток в вашем исходном коде.
- На x86 процессорах доступные энергозависимые регистры: eax, ecx, edx, xmm0, xmm1, xmm2 и xmm3. Все другие должны всегда сохраняться.
- На x64 процессорах доступные энергозависимые регистры: rax, rcx, rdx, r8, r9, xmm0, xmm1, xmm2 и xmm3. Все другие должны всегда сохраняться.
- Только для Windows : справочный файл ASM можно загрузить здесь. Если Вы поместите 'ASM.HLP' в папку 'Help/' PureBasic, Вы можете также получить справку на ключевых словах ASM с F1. Примечание: эта опция работает , только когда Встроенный x86 ASM активирован.

При использовании ассемблера в процедуре Вы должны знать о нескольких важных вещах:

- Чтобы возвратить непосредственно содержимое регистра 'eax' (или 'rax' на x64), просто используйте команду ProcedureReturn без какого-либо выражения. Она позволит содержимому регистра eax (или 'rax' на x64) остаться нетронутым и использует его как возвращаемое значение.

Пример

Procedure.l MyTest()
    MOV eax, 45
    ProcedureReturn  ; Возвращенное значение будет 45
EndProcedure

- Локальные переменные в PureBasic индексируются прямо по указателю стека, это означает, что если указатель стека изменяется посредством инструкции ассемблера (такой как PUSH, POP и т.д..), индексация переменных будет нарушена и прямые ссылки на переменные больше работать не будут.

- Можно передать ассемблерную строку прямо ассемблеру без обработки её компилятором с помощью символа '!' в начале строки. Это позволяет иметь полный доступ к директивам ассемблера. При использовании этого приёма можно ссылаться на локальные переменные с помощью нотации 'p.v_variablename' для обычной переменной или 'p.p_variablename' для указателя.

Пример

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

Test(0, 0)

Пример

AsmInline.pb