assembler 几个小程序

? 书中前几章的几个小程序,基本的运算操作,使用了作者的库 Irvine32 和 Irvine64(一开始以为作者网站过期了,各网站上找到的文件大小都不一样,最后发现是要搭* Orz,顺利下载)

● 代码,整数数组求和

 1 .386
 2 .model flat,stdcall
 3 .stack 4096
 4 
 5 ExitProcess PROTO, dwExitCode: dword
 6 
 7 .data
 8     array DWORD 10000h, 20000h, 30000h, 40000h,
 9 
10 .code
11 main PROC
12     mov edi, OFFSET array   ; 变址寄存器获得 array 首元素地址
13     mov ecx, LENGTH array   ; 循环计数器获得 array 元素个数
14     mov eax, 0
15 
16 L1:
17     add eax, [edi]          ; 将 array 每个元素加到 eax 中
18     add edi, TYPE array     ; 递增变址寄存器
19     loop L1                 ; 循环直到 ecx 减为 0
20 
21     INVOKE ExitProcess, 0
22 main ENDP
23 
24 END main

● 代码,整数数组求和,64位版本

 1 ExitProcess PROTO
 2 
 3 .data
 4     array QWORD 1000000000000h, 2000000000000h, 3000000000000h, 4000000000000h,
 5 
 6 .code
 7 main PROC
 8     mov rdi, OFFSET array   ; 用到的寄存器都改成 64 位的版本
 9     mov rcx, LENGTH array
10     mov rax, 0
11 
12 L1:
13     add rax, [rdi]
14     add rdi, TYPE array
15     loop L1
16 
17     mov ecx, 0              ; 还是使用 ecx 作为返回值
18     call ExitProcess
19 main ENDP
20 
21 END

● 代码,复制字符串

 1 .386
 2 .model flat,stdcall
 3 .stack 4096
 4 
 5 ExitProcess PROTO, dwExitCode: dword
 6 
 7 .data
 8     source BYTE "Something to be copied 2333.",0
 9     target BYTE SIZEOF source DUP(0)
10 
11 .code
12 main PROC
13     mov esi, OFFSET source
14     mov ecx, LENGTH source
15 
16 L1:
17     mov al, source[esi]
18     mov target[esi], al
19     inc esi
20     loop L1
21 
22     INVOKE ExitProcess, 0
23 main ENDP
24 
25 END main

● 涨姿势,代码中间有一个块段注释没有封口(直到代码结尾都是注释),报错信息是 END directive required at end of file。

● 代码,翻转字符串

 1 .386
 2 .model flat,stdcall
 3 .stack 4096
 4 
 5 ExitProcess PROTO, dwExitCode: dword
 6 
 7 .data
 8     source BYTE "Something to be copied 2333.", 0
 9     nameSize = ($ - source) - 1 ; 使用常量来存储字符串的长度
10 
11 .code
12 main PROC
13     mov esi, 0
14     mov ecx, LENGTH source
15 
16 L1:
17     movzx eax, source[esi]      ; 获取字符,压栈,递增指针,循环
18     push eax
19     inc esi
20     loop L1
21 
22     mov esi, 0                  ; 相同的赋值
23     mov ecx, LENGTH source
24 L2:
25     pop eax                     ; 吐栈,放入字符,递增指针,循环
26     mov source[esi], eax
27     inc esi
28     loop L2
29 
30     INVOKE ExitProcess, 0
31 main ENDP
32 
33 END main

● 代码,使用子过程计算数组的和

 1 .386
 2 .model flat,stdcall
 3 .stack 4096
 4 ExitProcess proto,dwExitCode:dword
 5 
 6 .data
 7     array dword 10000h,20000h,30000h,40000h,50000h
 8     sum   dword ?
 9 
10 .code
11 sumArray proc uses esi ecx  ; 定义子过程,uses 在栈中备份 esi 和 ecx,并在 ret 前还原
12     ;push esi                ; 用栈备份用到的寄存器,与 uses 作用等效
13     ;push ecx
14     mov eax, 0
15 
16 L1:                         ; 使用循环将和放入 eax 中
17     add eax, [esi]
18     add esi, type dword
19     loop L1
20 
21     ;pop ecx                 ; 从栈中还原寄存器的状态
22     ;pop esi
23     ret                     ; 从子过程中返回
24 sumArray endp
25 
26 main proc    
27     mov esi, offset array
28     mov ecx, length array
29 
30     call sumArray
31     mov sum, eax
32     
33     invoke ExitProcess, 0
34 main endp
35 
36 end main

● 代码,库 Irvine32 测试 1,简单的输入输出。记得在 “属性,配置属性,链接器,输入” 中加上 Irvine32.lib,并在工作目录下添加 Irvine32.inc,Irvine32.lib,SmallWin.inc,VirtualKeys.inc。

 1 INCLUDE Irvine32.inc                    ; 包含库
 2 .data
 3 array     DWORD 1000h,2000h,3000h
 4 message    BYTE "Enter a 32-bit signed integer: ", 0
 5 dwordVal   DWORD ?
 6 
 7 .code
 8 main PROC
 9     mov     eax,    yellow + (blue * 16)
10     call    SetTextColor
11     call    Clrscr                      ; 清屏为背景色
12     call    DumpRegs                    ; 显示当亲寄存器状态
13 
14     mov     esi,    OFFSET array        ; 三个寄存器分别存储数组的信息
15     mov     ecx,    LENGTHOF array    
16     mov     ebx,    TYPE array    
17     call    DumpMem                     ; 调用库函数,输出数组所有元素
18     call    Crlf                        ; 换行
19 
20     mov     edx,    OFFSET message
21     call    WriteString                 ; 输出字符串
22     call    ReadInt                     ; 输入整数
23     mov     dwordVal,   eax             ; 输入的整数存储到 eax 中
24     call    Crlf            
25     call    WriteInt                    ; 用十进制、十六进制、二进制输出 eax
26     call    Crlf
27     call    WriteHex        
28     call    Crlf
29     call    WriteBin        
30     call    Crlf    
31     call    WaitMsg                     ; 显示 "Press any key to cintinue" 并等待
32 
33     mov     eax,    lightGray + (black * 16)    ; 恢复终端颜色
34     call    SetTextColor
35     call    Clrscr
36     call    WaitMsg
37     
38     exit
39 main ENDP
40 END main

● 输出结果

; 清屏为蓝色

  EAX=0000001E  EBX=00436000  ECX=00961055  EDX=00961055
  ESI=00961055  EDI=00961055  EBP=0075FE18  ESP=0075FE08
  EIP=00963674  EFL=00000202  CF=0  SF=0  ZF=0  OF=0  AF=0  PF=0


Dump of offset 00966000
-------------------------------
00001000  00002000  00003000

Enter a 32-bit signed integer: 65536    ; 输入

+65536
00010000
0000 0000 0000 0001 0000 0000 0000 0000
Press any key to continue...

; 清屏恢复黑色

Press any key to continue...

● 代码,库 Irvine32 测试 2,随机数

 1 INCLUDE Irvine32.inc
 2 
 3 TAB = 9        ; ASCII code for Tab
 4 
 5 .code
 6 main PROC
 7     call    Randomize   ; 随机数种子
 8     call    Rand1       ; 无符号随机数
 9     call    Rand2       ; 有符号随机数
10     call    WaitMsg
11     exit
12 main ENDP
13 
14 Rand1 PROC
15     mov    ecx, 10
16 L1:
17     call    Random32    ; 生成随机整数用于输出
18     call    WriteDec
19     mov     al, TAB     ; 给一个水平制表符用于输出
20     call    WriteChar
21     loop    L1
22 
23     call    Crlf
24     ret
25 Rand1 ENDP
26 
27 Rand2 PROC
28     mov    ecx, 10
29 
30 L1:
31     mov     eax, 100
32     call    RandomRange ; 生成给定范围内的随机数
33     sub     eax, 50
34     call    WriteInt
35     mov     al,TAB
36     call    WriteChar
37     loop    L1
38 
39     call    Crlf
40     ret
41 Rand2 ENDP
42 
43 END main

● 代码,库 Irvine32 测试 3,计时器

 1 INCLUDE Irvine32.inc
 2 
 3 .data
 4 OUTER_LOOP_COUNT = 3
 5 startTime DWORD ?
 6 msg1 BYTE "Start", 0dh, 0ah, 0          ; 等价于 "Start\r\n\0"
 7 msg2 BYTE "End", 0dh, 0ah, "Time(ms): ", 0
 8 
 9 .code
10 main PROC
11     mov     edx,    OFFSET msg1
12     call    WriteString
13 
14     call    GetMSeconds                 ; 计时器1
15     mov     startTime,  eax
16 
17     mov     ecx,    OUTER_LOOP_COUNT    ; 外层循环
18 L1:    
19     call    innerLoop
20     loop    L1
21 
22     call    GetMSeconds                 ; 计时器2
23     sub     eax,    startTime           ; 直接在 eax 中计算耗时
24         
25     mov     edx,    OFFSET msg2         ; 显示
26     call    WriteString
27     call    WriteDec
28     call    Crlf
29     
30     call WaitMsg
31     exit
32 main ENDP
33 
34 innerLoop PROC uses ecx             
35     mov     ecx,    0FFFFFFFh           ; 内层循环
36 L1:
37     mul     eax                         ; 无符号乘法
38     mul     eax
39     mul     eax
40     loop    L1
41         
42     ret
43 innerLoop ENDP
44 
45 END main

● 代码,库 Irvine32 测试 4,对话框

 1 INCLUDE Irvine32.inc
 2 
 3 .data
 4 caption db "Title", 0
 5 HelloMsg    BYTE "This is a pop-up message box.", 0dh, 0ah, 0
 6 
 7 .code
 8 main PROC   
 9     mov    ebx, OFFSET caption  ; 标题,可以为 0
10     mov    edx, OFFSET HelloMsg ; 对话框内容
11     call    MsgBox
12 
13     mov ebx,    OFFSET caption
14     mov edx,    OFFSET HelloMsg
15     call MsgBoxAsk              ; 返回值在 eax 中,6(yes) 或 7(no)
16 
17     call    WaitMsg
18     exit
19 main ENDP
20 
21 END main 

● 代码,库 Irvine32 测试 5,用不同编码输出编号为 1~255 的字符

 1 INCLUDE Irvine32.inc
 2 
 3 SetConsoleOutputCP PROTO, pageNum:DWORD
 4 
 5 .data
 6 divider     BYTE    " - ", 0
 7 codepage    DWORD   1252
 8     ; 1250 - Central Europe
 9     ; 1251 - Cyrillic
10     ; 1252 - Latin I
11     ; 1253 - Greek
12     ; 1254 - Turkish
13     ; 1255 - Hebrew
14     ; 1256 - Arabic
15     ; 1247 - Baltic
16     ; 1258 - Vietnam
17     ; 874  - Thai
18     ; 437  - OEM United States
19     ; 858  - OEM Multilingual Latin and European
20 
21 .code
22 main PROC
23     invoke SetConsoleOutputCP, codePage
24 
25     mov     ecx,    255
26     mov     eax,    1
27     mov     edx,    OFFSET divider
28 L1:    
29     call    WriteDec    ; eax 作为计数器
30     call    WriteString ; edx 指向字符串
31     call    WriteChar   ; al 为得到的字符
32     call    Crlf
33     inc     aL
34     Loop    L1
35 
36     call    WaitMsg
37     exit
38 main ENDP
39 
40 END main

● 代码,库 Irvine64 测试 1,显示 20 个 64 位随机数

 1 ExitProcess PROTO           ; 手动声明需要用到的函数
 2 WriteInt64  PROTO
 3 Crlf        PROTO
 4 Random64    PROTO
 5 RandomRange PROTO
 6 Randomize   PROTO
 7 
 8 .code
 9 main proc
10     sub     rsp,    8       ; 栈指针对其到 16 Byte
11     sub     rsp,    20h     ; 影子空间 32 Byte
12 
13     call  Randomize
14     mov     rcx,    20
15 L1:
16     mov     rax,    234324243242
17     call    RandomRange     ; 返回的 64 位随机数在 eax 中
18     call    WriteInt64
19     call    Crlf
20     loop    L1
21 
22     add  rsp,   28h         ; 恢复 rsp 指针位置,main 中可以不用,子过程中需要
23     mov  ecx,   0
24     call ExitProcess
25 main endp
26 
27 end

● 涨姿势,链接时把 irvine64.obj 加入项目中(添加现有项),然后报错 LNK2017 没有 /LARGEADDRESSAWARE:NO,“ADDR32”到“bufferLHB”的重定位无效 。改正:“属性,配置属性,连接器,系统,启用大地址” 选否(/LARGEADDRESSAWARE:NO),即可正确运行。

 ● 代码,库 Irvine64 测试 2,简单的输入输出

 1 ExitProcess     proto
 2 ReadInt64       proto
 3 ReadString      proto
 4 WriteString     proto
 5 WriteInt64      proto
 6 WriteHex32      proto
 7 WriteHex64      proto
 8 Crlf            proto
 9 
10 .data
11 message BYTE "Test irvine64.lib", 0
12 maxval qword 9223372036854775807
13 minval qword -9223372036854775808
14 inbuf  BYTE  50 dup(0),0
15 inbuf_size = $ - inbuf
16 
17 .code
18 main proc
19 
20     mov     rdx,offset message
21     call    WriteString
22     call    Crlf
23 
24     call    ReadInt64       ; 从键盘读取一个 64 位整数
25     call    Crlf
26     call    WriteInt64
27     call    Crlf
28     
29     mov     rdx,offset inbuf
30     call    WriteString
31     call    Crlf
32 
33     mov     rax,    minVal
34     call    WriteInt64
35     call    Crlf
36 
37     mov     rax,    maxVal
38     call    WriteInt64
39     call    Crlf
40 
41     mov   ecx, 0
42     call  ExitProcess
43 main endp
44 
45 end

 

assembler 几个小程序

上一篇:小程序|页面跳转的方法


下一篇:微信网页中打开网址弹出引导页引导在外部浏览器中打开