三、字符串的使用
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
运行结果如下:
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
运行结果如下:
四、跳转指令
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
运行结果如下:
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
运行结果如下:
五、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
运行结果如下:
六、函数里调用子函数
汇编可以在函数里方便的包含一个子函数,这里是使用示例。
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
运行结果如下: