一些汇编练习

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一些汇编练习相关的知识,希望对你有一定的参考价值。

一些汇编练习

一些汇编练习,代码可能有有些bug,不是太完美,更多请见
https://lartpang.github.io/myasm/

习题4:

  1. 从屏幕上输入大写字母,转换为小写字母并输出(生成.com文件)
    要求:程序具有可读性、容错性

思路:

由于要生成.com文件,所以需要将文件代码设置到一个代码段里。本问题涉及到读入与显示,这里可以使用21h中断的1,2,9号子功能。
读入字符后,将al中存放的字符通过判断其是否为大写字母来保证程序的正确性。利用大小写ascii码上的对应关系,实现了大小写的转化。

代码如下:

  1. code segment para 
  2. assume cs:code, ds:code, ss:code 
  3. org 0100h 
  4. main proc near 
  5. again: 
  6. lea dx, str_dis 
  7. mov ah, 9 
  8. int 21h ;显示初始字符串,提示输入 
  9. mov ah, 1 
  10. int 21h ;获得输入字符,存到al里 
  11. cmp al, ‘A‘ ;判断输入字符是否是A~Z的字符 
  12. jb error 
  13. cmp al, ‘Z‘ 
  14. ja error ;保证输入合法 
  15. add al, 20h ;大写+20h=小写 
  16. mov str_num, ax ;将ax保存 
  17. lea dx, str_res 
  18. mov ah, 9 
  19. int 21h ;显示结果提示字符串 
  20. mov ax, str_num ;将ax恢复 
  21. mov dl, al 
  22. mov ah, 2 
  23. int 21h ;显示最终结果 
  24. mov ax, 4c00h 
  25. int 21h 
  26. error: 
  27. lea dx, str_err 
  28. mov ah, 9 
  29. int 21h 
  30. jmp again 
  31. main endp 
  32. str_num dw 0000h 
  33. str_dis db 0dh, 0ah, ‘Please input(A~Z):$‘ 
  34. str_res db 0dh, 0ah, ‘The result is:$‘ 
  35. str_err db 0dh, 0ah, ‘The data of input is invalid!$‘ 
  36. code ends 
  37. end main 
  38.  
  1. 编写一子程序 asc2bin ,将 ASCII 转换为二进制数
    要求:
    输入参数:AL 中存放需要转换的 ASCII
    输出参数:AL 中存放转换后的二进制数并返回

思路:

对于ascii码,先都当做数字来处理,即都减30h,在与9比大小,大于9的说明是10~15,再减7即可。

代码如下:

  1. asc2bin proc 
  2. sub al, 30h ;先都当做表示数字的acsii 
  3. cmp al, 9 ;与9比较,小于等于9的,直接跳转,大 
  4. ;于9的,仍然需要处理 
  5. jbe asc2bin_sub ;跳转子程序 
  6. sub al, 7 ;继续减7 
  7. asc2bin_sub: 
  8. ret ;返回主程序 
  9. asc2bin endp 
  1. 内存中存放8个16位有符号数,求8个数值之和,并将结果存放在内存变量SUM中
    注:程序中应用到字扩展为双字的指令CWD

思路:

通过使用循环加法,扩展双字的指令,转化为双字的计算加和。

代码如下:

  1. data segment para 
  2. buf dw -1, 2, -33, 44, -555, 666, -7777, 8888 
  3. sum dd 0 
  4. data ends 
  5. ss_seg segment stack 
  6. dw 100 dup(0
  7. ss_seg ends 
  8. code segment para 
  9. assume cs:code, ds:data, ss:ss_seg 
  10. main proc far 
  11. mov ax, data 
  12. mov ds, ax ;指定数据位置 
  13. lea bx, buf ;bx指向buf首地址 
  14. mov cx, 8 ;指定循环次数 
  15. w2d: 
  16. mov ax, [bx
  17. cwd ;有符号数字扩展为双字,默认使用{dx,ax} 
  18. add word ptr sum, ax ;32 位数相加 
  19. adc word ptr sum + 2, dx 
  20. inc bx 
  21. inc bx 
  22. loop w2d ;循环 8 次 
  23. mov ax, 4c00h 
  24. int 21h 
  25. main endp 
  26. code ends 
  27. end main 
  1. 内存中存放 8 个 8 位有符号数,请按从大到小顺序排列

思路:

利用冒泡排序,设置两个循环,将相邻的数字进行比较,大的放在低位地址,小的放在高位地址。
对于循环的次数的设置这里有些需要注意的地方。一般而言,n个数的问题,外层循环需要n-1次,而内层循环也是需要n-1次比较,所以可以设置使用相同的循环计数器。只需要内层循环计数的时候将之前的压栈保存即可。

代码如下:

  1. ;低地址到高地址,大数到小数。 
  2. data segment para 
  3. buf db -1, 2, -33, 44, -55, 66, -77, 88 
  4. data ends 
  5. stack segment stack 
  6. dw 100 dup(0
  7. stack ends 
  8. code segment para 
  9. assume cs:code, ds:data, ss:stack 
  10. main proc far 
  11. ;将ds:bx指向存放数据的位置 
  12. mov ax, data 
  13. mov ds, ax 
  14. mov cx, 7 ;主循环仅需要7次 
  15. loop_main: 
  16. lea bx, buf 
  17. push cx ;cx=n, 子循环正好也要循环n次 
  18. ;压栈保存外循环循环次数 
  19. mov si, 0 ;标志是否有交换,当后面检测si==0时,说明 
  20. ;内部已经排序完毕 
  21. loop_sub: 
  22. ;取得第一个数据到ax里,将之与第二个数据比较大小 
  23. ;ax大等于[bx]的话,保留原样 
  24. ;ax小的话,就得将两个数据进行交换位置 
  25. mov al, [bx
  26. cmp al, [bx+1
  27. jge not_xchg ;>=不交换 
  28. ;ax小,进行交换 
  29. xchg al, [bx+1
  30. mov [bx], al 
  31. mov si, 1 ;标志有交换 
  32. not_xchg: 
  33. ;第一步交换完成,需要依次进行一遍 
  34. inc bx 
  35. loop loop_sub 
  36. ;完毕后,只完成了初步的重排,这时数据段中的情况是,高地址存放最小的数 
  37. ;还需要继续执行,之后每次都减少一次 
  38. cmp si, 0 
  39. je done_xchg 
  40. ; 仍有交换,还需重复  
  41. pop cx ;出栈,恢复cx 
  42. loop loop_main 
  43. done_xchg: 
  44. mov ax, 4c00h 
  45. int 21h 
  46. main endp 
  47. code ends 
  48. end main 
  1. 内存中有8个16位数,请编写程序将8个数倒序排放
    例:定义内存中8个数 buf dw 100, 3, 1, 20, 40, -2, 7, 10
    程序运行后,buf 开始应为: buf dw 10, 7, -2, 40, 20, 1, 3, 100

思路:

要实现倒序存放,利用栈的入栈出栈,或者反复循环交换。但是使用栈,更为便捷。

代码如下:

  1. data segment para 
  2. buf dw -1, 2, -33, 44, -555, 666, -7777, 8888 
  3. data ends 
  4. stack segment stack 
  5. dw 100 dup(0
  6. stack ends 
  7. code segment para 
  8. assume cs:code, ds:data, ss:stack 
  9. main proc far 
  10. mov ax, data 
  11. mov ds, ax 
  12. lea bx, buf 
  13. mov cx, 8 
  14. stack_push: 
  15. push [bx
  16. add bx, 2 
  17. loop stack_push 
  18. lea bx, buf 
  19. mov cx, 8 
  20. stack_pop: 
  21. pop [bx
  22. add bx, 2 
  23. loop stack_pop 
  24. mov ax, 4c00h 
  25. int 21h 
  26. main endp 
  27. code ends 
  28. end main 
  1. 从键盘输入 4 位十进制数,然后以 16 进制形式显示在屏幕上
    例:键盘输入:1024 屏幕上应显示:0400H
    要求:键盘输入和显示结果时均应有提示

思路:

输入四位十进制数,将ascii码利用中断功能,读入(此处会对输入字符做出合法性判断),转换为十进制数并以二进制的形式存在内存里,最后,转换为十六进制,并拆分各个数字,显示ascii码输出。具体流程详见注释。

代码如下:

  1. ;具体流程:ASCII码输入->十进制->十六进制->ASCII码显示 
  2. ;故需要子函数完成进制转换、ascii转换 
  3. data segment para 
  4. buf db 4 dup(0
  5. var_10 dw 0 
  6. str_input db 0dh, 0ah, ‘Please input four numbers(0-9):$‘ 
  7. str_error db 0dh, 0ah, ‘The input is error, please try again.$‘ 
  8. str_output db 0dh, 0ah, ‘The hex result is:$‘ 
  9. data ends 
  10. stack segment stack 
  11. dw 100 dup(0
  12. stack ends 
  13. code segment para 
  14. assume cs:code, ds:data, ss:stack  
  15. main proc far 
  16. mov ax, data 
  17. mov ds, ax 
  18. loop_again: ;输入有错误需要重新读取输入 
  19. lea dx, str_input ;显示数据输入提示信息 
  20. mov ah, 9 
  21. int 21h 
  22. lea bx, buf ;用bx来作为buf的指代 
  23. mov cx, 4 ;循环输入4个数 
  24. loop_input:  
  25. mov ah, 1 ;输入数据 
  26. int 21h 
  27. cmp al, ‘0‘ ;判断输入字符是否为‘0’~‘9’ 
  28. jb error 
  29. cmp al, ‘9‘ 
  30. ja error ;非法字符,进行错误处理 
  31. ;直接输入一个字符,处理一个字符 
  32. sub al, 30h ;ASCII转换为二进制,得到 0-9 
  33. mov [bx], al ;存入缓冲区 
  34. inc bx 
  35. loop loop_input 
  36. jmp input_valid ;数据输入正确后 ,跳转到后续处理 
  37. error:  
  38. lea dx, str_error ;显示错误提示信息 
  39. mov ah, 9 
  40. int 21h 
  41. jmp loop_again ;跳转到重新输入 
  42. input_valid: ;现在数据以二进制的形式存储 
  43. mov ax, 0 ;以(((0*10+dl3)*10+dl2)*10+dl1)*10+dl0计算 
  44. ;十进制数据结果存放到ax中 
  45. mov dx, 0 ;因为ax可以满足存放四位十进制数的需求 
  46. mov si, 10  
  47. mov bx, 0 
  48. mov cx, 4 
  49. loop_mul10:  
  50. mul si ;相乘后dx仍然保持 0 
  51. mov dl, [bx] ;将buf数据取到dl中 
  52. mov dh, 0 
  53. add ax, dx 
  54. inc bx 
  55. loop loop_mul10 ;循环4次乘10 
  56. mov var_10, ax ;得到的 4 位十进制数存放到 var_10 中 
  57. ;var_10共16位,存放十进制数对应的二进制 
  58. lea dx, str_output 
  59. mov ah, 9 
  60. int 21h ;显示输出提示符 
  61. mov ch, 4 ;以16进制显示输入的数据,循环四次 
  62. mov cl, 4 
  63. loop_display:  
  64. rol var_10, cl ;循环左移4位,因为要先显示高位 
  65. mov ax, var_10 
  66. and ax, 000fh ;仅保留最低四位 
  67. call bin2asc ;二进制转换为 ASCII 
  68. call pchar ;显示一个十六进制字符 
  69. dec ch 
  70. jnz loop_display 
  71. mov al, ‘H‘ ;显示十六进制‘H’记号 
  72. call pchar 
  73. mov ax, 4c00h 
  74. int 21h 
  75. main endp 
  76.  
  77. ;功能: 将一个二进制数字转换为ASCII 
  78. ;输入参数 : AL中存放二进制数(有效位只有低四位) 
  79. ;输出参数 : AL中存放ASCII 
  80. bin2asc proc 
  81. and al, 0fh 
  82. add al, 30h 
  83. cmp al, 39h 
  84. jbe done_b2a 
  85. add al, 07h ;是A~Z 
  86. done_b2a:  
  87. ret ;返回 
  88. bin2asc endp 
  89.  
  90. ;功能:显示单个字符 
  91. ;输入参数:AL中存放ASCII 
  92. ;输出参数:无 
  93. pchar proc 
  94. mov dl, al 
  95. mov ah, 2 
  96. int 21h 
  97. ret ;返回 
  98. pchar endp 
  99. code ends 
  100. end main 
  1. 数据段从100H开始存放字符串str1,从200H开始存放str2,二者均以NULL字符为结束符,编写程序将str2拷贝到str1末尾,形成一个完整字符串
    例:
    ORG 100H
    str1 db 0dh, 0ah, ‘Hello ’, 0
    ORG 200H
    str2 db ‘Automation!’, 0
    程序运行后结果应为:
    str1 db 0dh, 0ah, ‘Hello Automation!’, 0

思路:

利用repnz scasb指令,将扫描的字符与al中预存的0比较,即查找str_first的结束位置,找到后,利用mov cx, count & rep movsb两条命令,以及count equ ($-str_second),将str_secon复制到str_first之后。
最后再利用lodsb,配合中断功能,显示最终的合并字符串。

代码如下:

  1. data segment para 
  2. ORG 100H 
  3. str_first db 0dh, 0ah, ‘Hello ‘, 0 
  4. ORG 200H 
  5. str_second db ‘Automation! ‘, 0 
  6. count equ ($-str_second) 
  7. data ends 
  8. ss_seg segment stack 
  9. dw 100 dup(0
  10. ss_seg ends 
  11. code segment para 
  12. assume cs:code, ds:data, ss:ss_seg 
  13. main proc far 
  14. mov ax, data 
  15. mov ds, ax 
  16. mov es, ax 
  17. lea di, str_first ;es:di 指向str_first首地址 
  18. mov al, 0 
  19. repnz scasb ;查找到str_first结束符NULL,最后di会多加一次 
  20. dec di ;让es:di指向该位置 
  21. lea si, str_second ;ds:si指向str_second首地址 
  22. cld ;DF置零,右移 
  23. mov cx, count 
  24. rep movsb ;重复搬移 
  25. lea si, str_first ;ds:si 指向拷贝后的 str_first 首地址 
  26. display:  
  27. lodsb ;显示拷贝后的 str_first 字符串 
  28. cmp al, 0 
  29. jz exit ;显示完毕 
  30. call pchar 
  31. jmp display 
  32. exit:  
  33. mov ax, 4c00h 
  34. int 21h 
  35. main endp 
  36.  
  37. ;功能:显示单个字符 
  38. ;输入参数:AL中存放ASCII 
  39. ;输出参数:无 
  40. pchar proc 
  41. mov dl, al 
  42. mov ah, 2 
  43. int 21h 
  44. ret 
  45. pchar endp 
  46. code ends 
  47. end main 
  1. 以 10 进制形式显示 内存中一有符号字节数据
    例:var db 0ffH
    屏幕应显示:The result is: -1
    代码如下:

思路:

主要是二进制转化为十进制后拆分成单个数字,在将之处理为ascii码。
首先需要与0比较,利用jg/jl等有符号数比较指令实现跳转处理。分别将第一个字符设置为对应的符号。
再将实际数值部分进行处理,转换为ascii码,进行显示。

代码如下:

  1. ;思路:二进制->十进制->ascii码 
  2. data segment para 
  3. var_signed db 0ffH 
  4. str_result db 0dh, 0ah, ‘The result is: ‘ 
  5. num_signed db 4 dup(‘ ‘);因为有符号字节数,最多就是三位十进制 
  6. db ‘$‘ 
  7. data ends 
  8. stack segment stack 
  9. dw 100 dup(0
  10. stack ends 
  11. code segment para 
  12. assume cs:code, ds:data, ss:stack 
  13. main proc far 
  14. mov ax, data 
  15. mov ds, ax 
  16. mov num_signed, ‘+‘ 
  17. cmp var_signed, 0 ;判断 var_signed 是正数 ,还是负数 
  18. jge is_pos ;>= 为正数 
  19. mov num_signed, ‘-‘ ;< 为负数 
  20. neg var_signed ;若 var_signed 为负,则补码的相反数 
  21. is_pos:  
  22. mov al, var_signed 
  23. mov cx, 3 
  24. mov dl, 10 ;进制 
  25. lea bx, num_signed+3;倒着放数据 
  26. again:  
  27. mov ah, 0 ;高八位置零 
  28. div dl 
  29. add ah, 30h ;余数 ah 
  30. mov [bx], ah 
  31. dec bx 
  32. loop again ;循环 3 次,分别得到百、十、个位 
  33. done: 
  34. lea dx, str_result ;显示 10 进制数 
  35. mov ah, 9 
  36. int 21h 
  37. exit:  
  38. mov ax, 4c00h 
  39. int 21h 
  40. main endp 
  41. code ends 
  42. end main 
  1. 将一个16位的无符号数var,转换为非压缩格式BCD码,存放在内存中buf开始的单元中。(按高位在 前、低位在后的顺序存放)

思路:

利用二进制转换十进制:((0*2 + B15)*2 + B14)*2 + ? + )*2 + B0
在运算过程中利用非压缩格式bcd码调整指令aaa,处理为非压缩格式bcd码,使得最终结果即为非压缩格式bcd码。

代码如下:

  1. ;二进制数 0FFFH,十进制 4095,非压缩BCD 4 0 9 5 各一个字节的低四位 
  2. ;二进制转换十进制:((0*2 + B15)*2 + B14)*2 + ? + )*2 + B0 
  3. data segment para 
  4. buf db 4 dup(0
  5. var dw 0FFFH  
  6. data ends 
  7. stack segment stack 
  8. dw 100 dup(0
  9. stack ends 
  10. code segment para  
  11. assume cs:code, ds:data, ss:stack 
  12. main proc far 
  13. mov ax, data 
  14. mov ds, ax 
  15. mov cx, 16 ;要进行十六次移位,利用adc获得 
  16. loop_wai:  
  17. shl var, 1 ;得到 var 的 Bi 位 
  18. mov bx, 3 
  19. push cx 
  20. mov cx, 4 
  21. loop_nei:  
  22. mov al, [bx] ;执行 buf*2 + Bi 操作 
  23. adc al, al 
  24. aaa ;非压缩格式 BCD 码调整 
  25. mov [bx], al 
  26. dec bx 
  27. loop loop_nei ;内循环为 4 次 
  28. pop cx 
  29. loop loop_wai ;外循环为 16 次 
  30. exit:  
  31. mov ax, 4c00h 
  32. int 21h 
  33. main endp 
  34. code ends 
  35. end main 
  1. 内存中有两个32位有符号数,请编写完整汇编语言程序,将二者相乘,结果保存在64位有符号数RESULT中

思路:

两个32位与符号数相乘,只要处理好符号位,就可以转化为无符号数相乘。

代码如下:

  1. data segment para 
  2. num_1 dd 80000002h 
  3. num_2 dd 80005000h 
  4. result dw 4 dup (?) 
  5. data ends 
  6. ss_seg segment stack 
  7. dw 100 dup (0
  8. ss_seg ends 
  9. code segment para 
  10. assume cs:code, ds:data, ss:ss_seg 
  11. main proc far 
  12. mov ax, data 
  13. mov ds, ax 
  14. shl byte ptr [num_1+3], 1 ;处理符号位 
  15. jc num_1_l0 ;num_1<0 
  16. xor ax, ax  
  17. shr byte ptr [num_1+3], 1 ;剥离符号位 
  18. mov bh, 0h ;用bh存放符号位 
  19. jmp next ;符号位被置零 
  20. num_1_l0:;num_1<0 
  21. mov bh, 1h ;用bh存放符号位 
  22. next: 
  23. shl byte ptr [num_2+3], 1 ;对num_2做相同处理 
  24. jc num_2_l0 
  25. xor ax, ax 
  26. shr byte ptr [num_2+3], 1 
  27. mov bl, 0h 
  28. jmp continue 
  29. num_2_l0:;num_2<0 
  30. mov bl, 1h 
  31. continue: ; 当做无符号数处理,计算相乘 
  32. lea si, num_1 
  33. lea di, num_2 
  34. mov ax, [si
  35. mov dx, [di
  36. mul dx 
  37. mov [result],ax 
  38. mov [result+2],dx 
  39. mov ax, [si+2
  40. mov dx, [di
  41. mul dx 
  42. add [result+2],ax 
  43. adc [result+4],dx 
  44. mov ax, [si
  45. mov dx, [di+2
  46. mul dx 
  47. add [result+2],ax 
  48. adc [result+4],dx 
  49. adc [result+6],0 
  50. mov ax, [si+2
  51. mov dx, [di+2
  52. mul dx 
  53. add [result+4],ax 
  54. adc [result+6],dx 
  55. sub bh, bl ;处理符号 
  56. jnz bh_nz_bl ;num_1 num_2异号 
  57. and [result+7], 01111111b ;同号就将结果最高位置0 
  58. jmp exit 
  59. bh_nz_bl:;不同号 
  60. or [result+7], 10000000b ;异号就将结果最高位置1 
  61. exit: 
  62. mov ah, 4ch 
  63. int 21h 
  64. main endp 
  65. code ends 
  66. end main 
  1. 将一个 8 位压缩 BCD 码转换为二进制数

思路:

对于四位压缩bcd码的过程比较简单,可以利用不断循环左移四位,将高位字节的两个bcd码置于字单元的最后位置,整体赋给寄存器,现在寄存器里存放的是一位压缩bcd码,乘以10再加上下一位如此获得的bcd码,反复如此,就可以获得四位的压缩bcd对应的十进制,存放到内存中,就变为了二进制。
而对于八位压缩bcd码,则可以拆成高四位对应的十进制,乘以10000,加上低四位对应的十进制数。这里就是这样处理的。
高四位低四位分别求出了对应的十进制,按上述规则相加,得到了最终结果。

代码如下:

  1. data segment para 
  2. BCD_num dd 12345678h 
  3. bin_num db 4 dup(0
  4. loop_num db 2 
  5. data ends 
  6. ss_seg segment stack 
  7. dw 100 dup(0
  8. ss_seg ends 
  9. code segment para  
  10. assume cs:code, ds:data, ss:ss_seg 
  11. main proc far 
  12. mov ax, data 
  13. mov ds, ax 
  14. mov si, 10 
  15. mov ax, 0 
  16. mov dl, 2 ;分两段 
  17. mov di, 2 
  18. again_loop: 
  19. mov cx, 0404h ;ch 乘法循环计数器; cl 移位计数器 
  20. again_mul: 
  21. mul si 
  22. rol word ptr [BCD_num+di], cl 
  23. mov bx, word ptr [BCD_num+di
  24. and bx, 000fh 
  25. add ax, bx 
  26. dec ch 
  27. jnz again_mul 
  28. mov word ptr [bin_num+di], ax 
  29. xor di, di 
  30. xor ax, ax 
  31. sub [loop_num], 1 
  32. jnz again_loop 
  33. ; 高四位对应的十进制乘以10,加上低四位对应的十进制 
  34. mov ax, word ptr [bin_num+2
  35. mov bx, 10000 
  36. mul bx 
  37. add ax, word ptr [bin_num] 
  38. adc dx, 0 
  39. mov word ptr [bin_num], ax 
  40. mov word ptr [bin_num+2], dx 
  41. mov ax, 4c00h 
  42. int 21h 
  43. main endp 
  44. code ends 
  45. end main 

选作题:

  1. 内存中从str开始存放一字符串,结束符为NULL字符,请编写程序统计该字符串中单词的个数
    例:str1 db 0dh, 0ah, ‘Hello world, welcome to DUT. CPU is central
    processing unit!’, 0h
    统计 ’….’ 中的单词个数,结果为10

思路:

如题所述,主要统计空格。通过扫描字符串,统计空格,但是有效的空格前一个字符是有效的字符,只有这样的空格才会统计。

代码如下:

  1. data segment para 
  2. jj string db 0dh, 0ah, ‘Hello world, welcome to DUT. CPU is central ‘ 
  3. db ‘processing unit!‘, 0h 
  4. words dw 0 
  5. data ends 
  6. stack segment stack 
  7. db 256 dup(0
  8. stack ends 
  9. code segment para 
  10. assume cs:code, ds:data, ss:stack 
  11. main proc far 
  12. mov ax, data 
  13. mov ds, ax 
  14. mov cx, 0 ;用 cx 存放单词数 
  15. lea si, string 
  16. mov bl, ‘ ‘ ;bl 总保存当前字符的前一个字符 
  17. cld ;保证右移 
  18. load_al:  
  19. lodsb ;从ds:si中以字节为单位获取数据,al只判断0以及空格 
  20. and al, al ;判断 al 是否为结束符 0,al=0 zf=1,al!=0,zf=0 
  21. jz al_0 
  22. cmp al, ‘ ‘ ;比较是否是空格,只对空格计数 
  23. jnz bl_new 
  24. al_douhao: ;处理重复计数:计数只是根据空格的个数来计算。 
  25. ;重复计数主要是因为多个空格以及逗号空格连续所致。 
  26. cmp bl, ‘ ‘ ;比较前一个字符是否为空格,如果是则此空格 
  27. ;不能算一个单词,即为了防止多个空格的情况 
  28. jz bl_new 
  29. inc cx ;只有当前字符为 ‘ ‘或‘,‘ 而且前一个字符为有 
  30. ;效字符时,才对单词数加 1 
  31. jmp bl_new 
  32. bl_new:  
  33. mov bl, al ;进入这里表明此时 al 中内容不是 0 或者 ‘ ‘ 
  34. ;符号 ,保存 al 到 bl 
  35. jmp load_al 
  36. al_0: ;判断结束符前面是否有‘ ‘,删掉多余的计数 
  37. cmp bl, ‘ ‘  
  38. jz done 
  39. inc cx ;若结束符前是一个有效字符,那么单词数应该加 1 
  40. done:  
  41. mov words, cx 
  42. mov ax, 4c00h 
  43. int 21h 
  44. main endp 
  45. code ends 
  46. end main 

以上是关于一些汇编练习的主要内容,如果未能解决你的问题,请参考以下文章

从汇编代码和骨架 C 导出数组的大小

汇编语言之加法练习程序

手把手教你学习汇编语言——从入门到起飞

用不到 4 行汇编编写这个练习 AT&T

86/88汇编代码的执行调试

汇编实验三