FB内嵌汇编探索2

三、字符串的使用

1、字符串按字节读取

#include Once "crt/stdio.bi"

Function test(ByRef z As ZString) As String
Dim s As ZString * 100 '用来存储返回字符串
Asm
	mov    eax,[z]        '移动参数到eax
	lea    esi,[eax + 4]  '获取字符串指针   从第4个字节开始取字符串 +4(这里只是举例,实际根据需要)
	mov    ecx,0
Start1:
	movzx  eax,Byte Ptr[esi] '读一字节到寄存器
	mov    [s + ecx],eax     '存储到字符变量s里
	inc    esi               '下一个单元
	inc    ecx               '计数加1
	cmp    ecx,6             '取6个字符,所以比较6
	jl     Start1            'ecx < 6 继续循环
End Asm	
Function = s
End Function

'参数里的字符串长度必须大于4,因为程序里从第4个字符开始取
Print test("1234-dabc-")


Sleep 
End 

运行结果如下:

FB内嵌汇编探索2_第1张图片

 2、zstring和Wstring的处理

    zstring和wstring的区别主要是字符所占的大小,zstring是一个字节,而wstring是2个字节,所以汇编处理Wstring的时候需要注意字节大小和指针移动范围就好了。

#define UNICODE
#include Once "crt/stdio.bi"
#include Once "Afx/CWStr.inc"  'CWStr类型

#ifndef UNICODE
Function test(ByRef z As ZString) As String
	Dim s As ZString * 100 '用来存储返回字符串
#else
Function test(ByRef z As WString) As CWstr
	Dim s As WString * 100 '用来存储返回字符串
#endIf 
Asm
	mov    eax,[z]        '移动参数到eax
#ifndef UNICODE
	lea    esi,[eax + 4]  '获取字符串指针   从第4个字符开始取字符串 +4(这里只是举例,实际根据需要)
#else
    lea    esi,[eax + 8]  '获取字符串指针   从第4个字符开始取字符串 +8(这里只是举例,实际根据需要)
#endIf 
	mov    ecx,0
Start1:
#ifndef UNICODE
	movzx  eax,Byte Ptr[esi] '读一字符到寄存器
#else
    movzx  eax,word Ptr[esi] '读一字符到寄存器
#endIf 
	mov    [s + ecx],eax     '存储到字符串变量s里
#ifndef UNICODE
	inc    esi               '下一个单元
	inc    ecx               '计数加1
	cmp    ecx,6             '取6个字符,所以比较6
#else
    Add    esi,2
    Add    ecx,2
    cmp    ecx,12            '取6个字符,所以比较12
#endIf 
	jl     Start1            'ecx < 6 继续循环
End Asm	
Function = s
End Function

'参数里的字符串长度必须大于4,因为程序里从第4个字符开始取
#ifndef UNICODE
  #define text "1234-dabc-"
#else
  #define text WStr("1234-dabc-")
#endIf 
Print test(text)


Sleep 
End 

运行结果如下:

FB内嵌汇编探索2_第2张图片

四、跳转指令

1、or后跳转

   判断寄存器是否小于0(负数)

#include Once "crt/stdio.bi"

Dim Shared SS1 As ZString * 100 = !"负数      - 没跳\r\n"
Dim Shared SS2 As ZString * 100 = !"0或者正数 - 跳了\r\n"


'js,jns 是根据标志寄存器中标志位SF(也称符号位)的值判断是否跳转

'Dim dat As Long = 1   '方便判断 正数 0 负数的跳转情况
'Dim dat As Long = 0
Dim dat As Long = -1

Asm
	mov eax,[dat]
	Or eax,eax
	jns Nx          '如果>=0,则跳转执行
	lea eax,[SS1]   '处理负数
	jmp ex
Nx:	
	lea eax,[SS2]   '处理0或正数
ex:	
    push eax
    Call printf
End Asm


Sleep
End

运行结果如下:

FB内嵌汇编探索2_第3张图片

2、Test指令后跳转

#include Once "crt/stdio.bi"

Dim Shared SS1 As ZString * 100 = !"是0\r\n"
Dim Shared SS2 As ZString * 100 = !"非0\r\n"


'Dim dat As Long = 1   '方便判断 正数 0 负数的跳转情况
Dim dat As Long = 0
'Dim dat As Long = -1

Asm
	mov eax,[dat]
	test eax,eax
	jz Nx           'jz = jmp if zero,jnz = jmp if not zero   如果=0,则跳转执行
	lea eax,[SS2]   '非0 
	jmp ex
Nx:	
	lea eax,[SS1]   '是0 
ex:	
    push eax
    Call printf
End Asm


Sleep
End

运行结果如下:

FB内嵌汇编探索2_第4张图片

 五、32位汇编和64位汇编

    64位汇编增加了rax rbp rbx rcx rdi rdx rsi rsp这些64位的寄存器。使用汇编写32位和64位程序时,要注意指针在32位和64位长度不同,32位可以用eax存,64位得用rax来存。所以基本上有指针的地方修改成64位寄存器,push和pop修改成64位寄存器,基本就可以调试通过了。

这里举一个例子:VFB里有一个ReplaceASM函数,之前只有32位的汇编,这里修改一下增加64位。

#include Once "crt/stdio.bi"
'#include Once "windows.bi"

Function ReplaceASM(TiStr As String, TiFind As String, TiRep As String) As String
    '1、判断字符串是否为空,如果为空,则直接返回需要替换的字符串
    If TiStr = "" OrElse TiFind = "" OrElse TiRep = "" Then
        Function = TiStr
        Exit Function
    EndIf
    '定义指向字符串的指针
    Dim iStr As ZString Ptr = StrPtr(TiStr)
    Dim iFind As ZString Ptr = StrPtr(TiFind)
    Dim iRep As ZString Ptr = StrPtr(TiRep)
   
    Dim iSize As Integer = Len(TiStr) - Len(TiFind)
    Dim dStr As ZString Ptr = Callocate(Len(TiStr) * 20) '开辟一个足够大的内存(原字符串的20倍)用来存储替换后的字符串
#ifndef __FB_64BIT__
Asm
    mov    esi,[iStr]
    Add    [iSize], esi
    mov    ebx, [iFind]
    inc    dword Ptr[iSize]
    mov    edi, [dStr]
    Sub    esi, 1
    jmp    Start1
Start2 : 
    Add    esi, ecx
Start1 : 
    Add    esi, 1
    cmp    [iSize], esi
    jle    Done
    movzx  eax, Byte Ptr[esi]
    cmp    al, [ebx]
    je     Match
    mov    [edi], al
    Add    edi, 1
    jmp    Start1
Match : 
    mov    ecx, -1
    mov    edx, ebx
B1 : 
    Add    ecx, 1
    movzx  eax, Byte Ptr[edx]
    Test   eax, eax
    jz     Change
    Add    edx, 1
    cmp    [esi + ecx], al
    je     B1
    movzx  eax, Byte Ptr[esi]
    mov    [edi], al
    Add    edi, 1
    jmp    Start1
Change : 
    mov    edx,[iRep]
saute : 
    Sub    ecx, 1
B2 : 
    movzx  eax, Byte Ptr[edx]
    Test   eax, eax
    jz     Start2
    Add    edx, 1
    mov    [edi], al
    Add    edi, 1
    jmp    B2
Done : 
    mov    ecx, -1
B3 : 
    Add    ecx, 1
    movzx  eax, Byte Ptr[esi + ecx]
    mov    [edi + ecx], al
    Test   eax, eax
    jnz    B3
End Asm 
#else
Asm
    mov    rsi,[iStr]
    Add    [iSize],rsi
    mov    rbx, [iFind]
    inc    dword Ptr[iSize]
    mov    rdi,[dStr]
    Sub    rsi, 1
    jmp    Start1
Start2 : 
    Add    rsi,rcx
Start1 : 
    Add    rsi, 1
    cmp    [iSize],rsi
    jle    Done
    movzx  eax, Byte Ptr[rsi]
    cmp    al,[rbx]
    je     Match
    mov    [rdi], al
    Add    rdi, 1
    jmp    Start1
Match : 
    mov    rcx, -1
    mov    rdx,rbx
B1 : 
    Add    rcx, 1
    movzx  eax, Byte Ptr[rdx]
    Test   eax, eax
    jz     Change
    Add    rdx, 1
    cmp    [rsi + rcx], al
    je     B1
    movzx  eax, Byte Ptr[rsi]
    mov    [rdi], al
    Add    rdi, 1
    jmp    Start1
Change : 
    mov    rdx,[iRep]
saute : 
    Sub    rcx, 1
B2 : 
    movzx  eax, Byte Ptr[rdx]
    Test   eax, eax
    jz     Start2
    Add    rdx, 1
    mov    [rdi], al
    Add    rdi, 1
    jmp    B2
Done : 
    mov    rcx, -1
B3 : 
    Add    rcx, 1
    movzx  eax, Byte Ptr[rsi + rcx]
    mov    [rdi + rcx], al
    Test   eax, eax
    jnz    B3
End Asm 
#endif 
    Function = *dStr '返回字符串
    Sleep(1)
    DeAllocate dStr  '释放内存
End Function


Dim s As String = "123abc123abc123abc123abc"
Print "替换前:"
Print s
Print "替换后"
Print ReplaceASM(s,"12","=+")


Sleep
End

运行结果如下:

FB内嵌汇编探索2_第5张图片

六、函数里调用子函数

    汇编可以在函数里方便的包含一个子函数,这里是使用示例。

Sub test()
	Dim r As Long
Asm
	mov eax,10       '参数a
	mov ebx,10       '参数b
	Call funcAdd     '调用函数                            
	jmp Endd         '调到结尾                             
	'ret             '在sub或者function中不能直接ret返回   
funcAdd:	         '内部子函数                           
	Add eax,ebx
	ret
Endd:	             '
	mov [r],eax
End Asm
    Print r
End Sub

test()

Sleep 
End

运行结果如下:

FB内嵌汇编探索2_第6张图片

你可能感兴趣的:(FreeBASIC学习笔记,汇编,freebasic)