汇编语言系列文章仅作为实验报告和汇编学习参考,不作为任何技术文章,还望大佬们勿喷。

1. 实验名称

熟悉汇编语言的基本指令和条件指令的使用,理解汇编程序中,如何实现高级语言中的条件语句。

2. 实验要求

编写整数求和程序;运用kip irvine库中的部分过程,并阅读分析其实现源码。

3. 实验内容

  1. 编写多个整数求和的程序:对用户输入的多个整数进行求和,并输出结果。
    阅读然后修改附录A中的求和程序(该程序实现了3个整个求和的功能),使用一个常量决定数组的大小(即程序最大可以求和的整数个数):
    ARRAY_SIZE = 20
    Array DWORD ARRAY_SIZE DUP(?)
    写一个过程提示用户输入需要求和的整数的个数,向promptForIntegers过程传递用户输入的数值。如果用户的输入值大于ARRAY_SIZE(判断的示例代码参见附录B),那么显示一条错误信息并退出程序。提示和错误信息可以如下例所示:
    How many integers will be added? 21
    The array cannot be larger than 20
    精心设计程序,使得在修改了ARRAY_SIZE后,错误提示信息中的ARRAY_SIZE数目值(在上例中是20)也应自动修改。
    提示:
    a). 编程能力一般的同学可以分两步:
    • 弄懂附录A的程序。该程序实现了3个整个求和的功能。
    • 找到附录A的程序需要修改的地方,以实现多个整数求和。

b). 编程能力较强的同学建议直接编写程序实现。

  1. 对上述程序添加功能:除显示多个整数的和外,还分别显示这些整数中正整数的和负整数的和。(区分正数与负数的示例代码参见附录B)
  2. (可选)阅读kip irvine库中的部分过程的源码
    Irvine 32位库的源码在文件Irvine32.asm中(在Irvine32_Library_sourceCode.rar压缩包中)。
    建议阅读源码的过程是:DumpMem,DumpRegs,IsDigit,Random32,RandomRange,ReadChar。

4. 实验步骤或源代码、结果

1. 实验步骤

  1. 编写多个整数求和的程序:对用户输入的多个整数进行求和,并输出结果。
    当输入的数字个数不大于20时可以进行多个整数求和,并正确输出结果。

【汇编语言实验二】多整数求和程序的编写 - 图1

当输入的数字个数大于20时不可以进行多个整数求和,输出错误信息。

  1. mov edx, OFFSET str4 ; "The array cannot be larger than "
  2. call WriteString
  3. mov eax, ARRAY_SIZE
  4. call WriteInt ; 输出最大值

错误提示信息中的ARRAY_SIZE数目值也应自动修改。
【汇编语言实验二】多整数求和程序的编写 - 图2

  1. 对上述程序添加功能:除显示多个整数的和外,还分别显示这些整数中正整数的和负整数的和。

【汇编语言实验二】多整数求和程序的编写 - 图3

【汇编语言实验二】多整数求和程序的编写 - 图4

2. 实验源代码、结果

1. 源代码1

  1. INCLUDE Irvine32.inc
  2. ARRAY_SIZE = 20
  3. .data
  4. str1 BYTE "How many integers will be added? ", 0
  5. str2 BYTE "Enter a signed integer: ", 0
  6. str3 BYTE "The sum of the integer is: ", 0
  7. str4 BYTE "The array cannot be larger than ", 0
  8. str5 BYTE "The array cannot be less than 0 ", 0
  9. array DWORD ARRAY_SIZE DUP(?)
  10. TheArraySize SDWORD ?
  11. .code
  12. main PROC
  13. call Clrscr
  14. mov esi,OFFSET array
  15. call GetArraySize
  16. cmp TheArraySize, ARRAY_SIZE
  17. jg GreaterError
  18. cmp TheArraySize, 0
  19. jng Less0Error
  20. mov ecx, TheArraySize
  21. call PromptForIntegers
  22. call ArraySum
  23. call DisplaySum
  24. jmp ExitProc
  25. GreaterError:
  26. mov edx, OFFSET str4 ; "The array cannot be larger than "
  27. call WriteString
  28. mov eax, ARRAY_SIZE
  29. call WriteInt ; 输出最大值
  30. call Crlf
  31. jmp ExitProc
  32. Less0Error:
  33. mov edx, OFFSET str5 ; "The array cannot be less than 0."
  34. call WriteString
  35. call Crlf
  36. jmp ExitProc
  37. ExitProc:
  38. exit
  39. main ENDP
  40. GetArraySize PROC USES eax edx
  41. mov edx, OFFSET str1
  42. call WriteString
  43. call ReadInt
  44. call Crlf
  45. mov TheArraySize, eax
  46. ret
  47. GetArraySize ENDP
  48. ;----------------------------------------------------
  49. PromptForIntegers PROC USES ecx edx esi
  50. ;
  51. ; Prompts the user for an arbitrary number of integers
  52. ; and inserts the integers into an array.
  53. ; Receive ESI points to the array, ECX = array size
  54. ; Returns: nothing
  55. ;-----------------------------------------------------------
  56. mov edx, OFFSET str2 ; "Enter a signed integer"
  57. L1: call WriteString ; display a string
  58. call ReadInt ; read
  59. call Crlf ; go to next output line
  60. mov [esi], eax ; store in array
  61. add esi, TYPE DWORD ; next integer
  62. loop L1
  63. ret
  64. PromptForIntegers ENDP
  65. ;----------------------------------------------------------
  66. ArraySum PROC USES esi ecx
  67. ;
  68. ; Calculates the sum of an array of 32-bit integers.
  69. ; Receives: ESI points to the array, ECX = number
  70. ; of array elements
  71. ; Returns: EAX = sum of the array elements
  72. ;------------------------------------------------------------
  73. mov eax, 0
  74. L1:
  75. add eax, [esi]
  76. add esi, TYPE DWORD ; point to next integer
  77. loop L1 ; repeat for array size
  78. ret ; sum is in EAX
  79. ArraySum ENDP
  80. ;-------------------------------------------------------------
  81. DisplaySum PROC USES edx
  82. ;
  83. ; Displays the sum on the screen
  84. ; Receives: EAX = the sum
  85. ; Return: nothing
  86. ;-------------------------------------------------------------
  87. mov edx, OFFSET str3 ;"The sum of the .."
  88. call WriteString
  89. call WriteInt ;display EAX
  90. call Crlf
  91. ret
  92. DisplaySum ENDP
  93. END main

2. 源代码2

  1. INCLUDE Irvine32.inc
  2. ARRAY_SIZE = 20
  3. .data
  4. str1 BYTE "How many integers will be added? ", 0
  5. str2 BYTE "Enter a signed integer: ", 0
  6. str3 BYTE "The sum of the integer is: ", 0
  7. str4 BYTE "The array cannot be larger than ", 0
  8. str5 BYTE "The array cannot be less than 0 ", 0
  9. str6 BYTE "The sum of the positive integer is: ", 0
  10. str7 BYTE "The sum of the negative integer is: ", 0
  11. array DWORD ARRAY_SIZE DUP(?)
  12. TheArraySize SDWORD ?
  13. .code
  14. main PROC
  15. call Clrscr
  16. mov esi,OFFSET array
  17. call GetArraySize
  18. cmp TheArraySize, ARRAY_SIZE
  19. jg GreaterError
  20. cmp TheArraySize, 0
  21. jng Less0Error
  22. mov ecx, TheArraySize
  23. call PromptForIntegers
  24. call ArraySum
  25. call DisplaySum
  26. jmp ExitProc
  27. GreaterError:
  28. mov edx, OFFSET str4 ; "The array cannot be larger than "
  29. call WriteString
  30. mov eax, ARRAY_SIZE
  31. call WriteInt ; 输出最大值
  32. call Crlf
  33. jmp ExitProc
  34. Less0Error:
  35. mov edx, OFFSET str5 ; "The array cannot be less than 0."
  36. call WriteString
  37. call Crlf
  38. jmp ExitProc
  39. ExitProc:
  40. exit
  41. main ENDP
  42. GetArraySize PROC USES eax edx
  43. mov edx, OFFSET str1
  44. call WriteString
  45. call ReadInt
  46. call Crlf
  47. mov TheArraySize, eax
  48. ret
  49. GetArraySize ENDP
  50. ;----------------------------------------------------
  51. PromptForIntegers PROC USES ecx edx esi
  52. ;
  53. ; Prompts the user for an arbitrary number of integers
  54. ; and inserts the integers into an array.
  55. ; Receive ESI points to the array, ECX = array size
  56. ; Returns: nothing
  57. ;-----------------------------------------------------------
  58. mov edx, OFFSET str2 ; "Enter a signed integer"
  59. L1: call WriteString ; display a string
  60. call ReadInt ; read
  61. call Crlf ; go to next output line
  62. mov [esi], eax ; store in array
  63. add esi, TYPE DWORD ; next integer
  64. loop L1
  65. ret
  66. PromptForIntegers ENDP
  67. ;----------------------------------------------------------
  68. ArraySum PROC USES esi ecx
  69. ;
  70. ; Calculates the sum of an array of 32-bit integers.
  71. ; Receives: ESI points to the array, ECX = number
  72. ; of array elements
  73. ; Returns: EAX = sum of the array elements
  74. ;------------------------------------------------------------
  75. mov eax, 0
  76. mov ebx, 0
  77. mov edx, 0
  78. L1: cmp [esi], edx
  79. jnl positive_zero
  80. add ebx, [esi]
  81. jmp loopL1
  82. positive_zero:
  83. add eax, [esi]
  84. jmp loopL1
  85. loopL1:
  86. add esi, TYPE DWORD ; point to next integer
  87. loop L1 ; repeat for array size
  88. ret ; sum is in EAX
  89. ArraySum ENDP
  90. ;-------------------------------------------------------------
  91. DisplaySum PROC USES edx ecx
  92. ;
  93. ; Displays the sum on the screen
  94. ; Receives: EAX = the sum
  95. ; Return: nothing
  96. ;-------------------------------------------------------------
  97. mov ecx, eax
  98. add eax, ebx
  99. mov edx, OFFSET str3 ;"The sum of the .."
  100. call WriteString
  101. call WriteInt ;display EAX
  102. call Crlf
  103. mov edx, OFFSET str6 ;"The sum of the positive integers"
  104. mov eax, ecx
  105. call WriteString
  106. call WriteInt ;display EAX
  107. call Crlf
  108. mov edx, OFFSET str7 ;"The sum of the negative integers"
  109. mov eax, ebx
  110. call WriteString
  111. call WriteInt ;display EAX
  112. call Crlf
  113. ret
  114. DisplaySum ENDP
  115. END main

5. 实验结论和心得体会

  • 学会了多整数求和的汇编代码;
  • 学会了2个数比较大小的汇编代码,要注意有符号比较和无符号比较;
  • 在实验中遇到了随机性的问题,发现是使用了被保护的eax,导致错误,将eax的值赋给一个常量后用常量去比较;
  • 对于几个寄存器的用法要牢记,多写程序就可以熟练;
  • 调用ReadInt时会默认读取eax寄存器的值;
  • 在分别求正整数和以及负整数和时,先将数字和0比较,然后分别加到两个寄存器中,最后再将2个寄存器的值加起来就是总的和。