FB语言支持内嵌汇编,使用的是GAS格式汇编,可以通过VFB工程菜单里的保存为独立的GAS格式源码来查看FB与GAS汇编的转换方式。以此摸索内嵌汇编的使用方式。
图1-1 FB源码转汇编源码
一、变量赋值(MOV等指令)
需要将变量用 [] 符号包含,即可转移或者赋值,例子如下:
Print "内嵌汇编测试"
Dim a As Long = 10,b As Long = 20
Dim c As Long = 0
'1、操作变量需要加[]
'2、注释必须使用FB的注释符号,使用汇编的注释编译出错
Asm
mov eax,[a] '变量a赋值到eax
Add eax,[b] 'a + b
mov [c],eax '将eax赋值到变量c
End Asm
Print a & " + " & b & " = " & c '打印到控制台
Sleep '暂停观察
End
显示效果如下:
二、函数调用
函数调用需要使用push先把参数压入栈里(如果有参数),根据调用约定不同,压入栈的顺序也有区别,FB里默认有3种调用约定 cdecl、pascal、stdcall,默认是stdcall,可以不用声明。过程不
需要管返回ret,如果是函数,则需要返回,但不能直接在内嵌汇编里返回,需要使用return返回。
Print "内嵌汇编测试"
Print "1、过程的调用"
'1 stdcall - 这个是默认的调用约定,可以不写
Sub add_print1(ByVal a As Long,ByVal b As Long)
Dim r As Long
Asm
mov eax,[a]
Add eax,[b]
mov [r],eax
End Asm
Print "stdcall方式[默认]"
Print a & " + " & b & " = " & r '打印到控制台
End Sub
'2 cdecl - c语言调用约定,使用C语言库时需要声明
Sub add_print2 Cdecl(ByVal a As Long,ByVal b As Long)
Dim r As Long
Asm
mov eax,[a]
Add eax,[b]
mov [r],eax
End Asm
Print "cdecl - c语言格式"
Print a & " + " & b & " = " & r '打印到控制台
End Sub
'3 pascal - pascal语言调用约定
Sub add_print3 Pascal(ByVal a As Long,ByVal b As Long)
Dim r As Long
Asm
mov eax,[a]
Add eax,[b]
mov [r],eax
End Asm
Print "pascal - pascal语言格式"
Print a & " + " & b & " = " & r '打印到控制台
End Sub
'4 函数调用及返回
Function dec_return(ByVal a As Long,ByVal b As Long) As Long
Dim r As Long '返回变量
If a > b Then
Asm
mov eax,[a]
Sub eax,[b]
mov [r],eax
End Asm
Else
Asm
mov eax,[b]
Add eax,[a]
mov [r],eax
End Asm
EndIf
Return r '返回数据
End Function
'过程调用,先用push把参数压入栈中,然后用call调用函数
Dim r As Long
Asm
'过程
push 10 '参数b = 10
push 20 '参数a = 20
Call add_print1 '调用过程
push 10 '参数b = 10
push 20 '参数a = 20
Call add_print2 '调用过程
push 10 '参数a = 10
push 20 '参数b = 20
Call add_print3 '调用过程
'函数
push 10 '参数a = 10
push 20 '参数b = 20
Call dec_return '调用过程
mov [r],eax
End Asm
Print "2、函数的调用与返回"
Print "20 - 10 = " & r '打印到控制台
Sleep '暂停观察
End
显示效果如下:
三、字符串的使用
#include Once "crt/stdio.bi" 'printf函数
Print "内嵌汇编测试"
Dim sz As ZString * 20 = !"hello word!\r\n" '定义一个字符串
Dim psz As ZString Ptr = @!"test value is %x\r\n" 'printf格式化字符串
Asm
lea eax,[sz] '将字符串指针载入eax,需要用lea命令
push eax '将字符串指针压入栈中
Call printf '调用printf函数 即printf(sz)
mov eax,[psz] '如果是指针,则直接用mov命令
push &HAA '第二个参数
push eax '第一个参数
Call printf '调用print函数,即printf("test value is %x\r\n",&HAA)
End Asm
Sleep
显示效果如下:
四、跳转指令
1、or后跳转
#include Once "crt/stdio.bi" 'printf函数
Print "内嵌汇编测试"
'
Dim EaxEqu As ZString * 10 = "eax = 0"
Dim EaxNotEqu As ZString * 10 = "eax <> 0"
'or后判断,jne,不为0则跳转,为0则顺序执行,如果是je,跳转条件于jne相反
Dim a As Long = 0 '测试a = 0
'Dim a As Long = 1 ' a = 正数
'Dim a As Long = -1 ' a = 负数
Asm
mov eax,[a]
Or eax,eax '
jne nx '不相等跳转指令 eax <> 0,则跳转;eax = 0,则顺序执行
lea eax,[EaxEqu]
jmp ex '无条件跳转指令
nx:
lea eax,[EaxNotEqu]
ex:
push eax
Call printf
End Asm
Sleep
运行效果如下:
2、cmp命令跳转
#Define UNICODE
#Include Once "crt/stdio.bi"
Dim ss1 As WString * 10 = WStr(!"相等\r\n")
Dim ss2 As WString * 10 = WStr(!"不相等\r\n")
Dim ss3 As WString * 10 = WStr(!"大于\r\n")
Dim ss4 As WString * 10 = WStr(!"大于等于\r\n")
Dim ss5 As WString * 10 = WStr(!"小于\r\n")
Dim ss6 As WString * 10 = WStr(!"小于等于\r\n")
'Dim a As Long = -1
Dim a As Long = 0
'Dim a As Long = -1
Asm
'je,jne 相等,不相等
mov eax,[a]
cmp eax,0
je nx
lea eax,[ss2]
jmp ex
nx:
lea eax,[ss1]
ex:
push eax
Call wprintf
'jg,jge,jng,jnge 大于,大于等于,不大于,不大于等于
mov eax,[a]
cmp eax,0
jg nx1 'jg >,jge >=,jng <=,jnge <
lea eax,[ss6]
jmp ex1
nx1:
lea eax,[ss3]
ex1:
push eax
Call wprintf
'jl,jle,jnl,jnle 小于,小于等于,不小于,不小于等于
mov eax,[a]
cmp eax,0
jl nx2 'jl <,jle <=,jnl >=,jnle >
lea eax,[ss4]
jmp ex2
nx2:
lea eax,[ss5]
ex2:
push eax
Call wprintf
End Asm
Sleep
运行效果如下: