我正在做一些家庭作业打印出一个数组,因为它从数组中排序了一些整数。我的代码工作正常,但我决定在我的代码中尝试使用EAX而不是AL并遇到错误。我无法弄清楚为什么会这样。是否有可能在这里使用EAX?
; This program sorts an array of signed integers, using
; the Bubble sort algorithm. It invokes a procedure to
; print the elements of the array before, the bubble sort,
; once during each iteration of the loop, and once at the end.
INCLUDE Irvine32.inc
.data
myArray BYTE 5, 1, 4, 2, 8
;myArray DWORD 5, 1, 4, 2, 8
currentArray BYTE 'This is the value of array: ' ,0
startArray BYTE 'Starting array. ' ,0
finalArray BYTE 'Final array. ' ,0
space BYTE ' ',0 ; BYTE
.code
main PROC
MOV EAX,0 ; clearing registers, moving 0 into each, and initialize
MOV EBX,0 ; clearing registers, moving 0 into each, and initialize
MOV ECX,0 ; clearing registers, moving 0 into each, and initialize
MOV EDX,0 ; clearing registers, moving 0 into each, and initialize
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET startArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
MOV ECX, lengthOf myArray ; load ECX with # of elements of array
DEC ECX ; decrement count by 1
L1:
PUSH ECX ; save outer loop count
MOV ESI, OFFSET myArray ; point to first value
L2:
MOV AL,[ESI] ; get array value
CMP [ESI+1], AL ; compare a pair of values
JGE L3 ; if [esi] <= [edi], don't exch
XCHG AL, [ESI+1] ; exchange the pair
MOV [ESI], AL
CALL printArray ; call printArray function
CALL crlf
L3:
INC ESI ; increment esi to the next value
LOOP L2 ; inner loop
POP ECX ; retrieve outer loop count
LOOP L1 ; else repeat outer loop
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET finalArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
CALL printArray
L4 : ret
exit
main ENDP
printArray PROC uses ESI ECX
;myArray loop
MOV ESI, OFFSET myArray ; address of myArray
MOV ECX, LENGTHOF myArray ; loop counter (5 values within array)
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET currentArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
L5 :
MOV AL, [ESI] ; add an integer into eax from array
CALL writeInt
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET space
CALL writeString
POP EDX ; restores the original edx register value
ADD ESI, TYPE myArray ; point to next integer
LOOP L5 ; repeat until ECX = 0
CALL crlf
RET
printArray ENDP
END main
END printArray
; output:
;Starting array. This is the value of array: +1 +5 +4 +2 +8
;This is the value of array: +1 +4 +5 +2 +8
;This is the value of array: +1 +4 +2 +5 +8
;This is the value of array: +1 +2 +4 +5 +8
;Final array. This is the value of array: +1 +2 +4 +5 +8
正如您所看到的那样,输出将数组从最小到最大排序。我试图看看我是否可以将AL移动到EAX,但这给了我一堆错误。有没有解决这个问题所以我可以使用32位寄存器并获得相同的输出?
答案 0 :(得分:1)
如果您仍想进行8位存储,则需要才能使用8位寄存器。 (AL是一个8位寄存器.IDK为什么你在标题中提到16)。
x86具有加宽加载(movzx
和movsx
),但来自寄存器操作数的整数存储总是使寄存器与内存操作数的宽度相同。即存储EAX的低字节的方式是mov [esi], al
。
在printArray
中,您应使用movzx eax, byte ptr [esi]
零延伸到EAX 。 (或者,如果您希望将数字视为int8_t
而不是uint8_t
,则可以使用movsx进行符号扩展。)这样可以避免将EAX的高24位置零。
MOV EAX,0 ; clearing registers, moving 0 into each, and initialize
完全没有意义。如果您的第一次使用是只写的,那么在第一次使用它之前,您不需要“初始化”或“声明”寄存器。你用EDX做什么很有趣:
MOV EDX,0 ; clearing registers, moving 0 into each, and initialize
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET startArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
如果您实际上想要旧值,则只需保存“来电者保存”寄存器。我更喜欢“呼叫保留”和“呼叫破坏”这两个术语。如果writeString破坏了它的输入寄存器,那么EDX在函数返回后保持一个未知值,但这没关系。你无论如何都不需要这个价值。 (实际上我认为Irvine32的功能最多会破坏EAX。)
在这种情况下,前一条指令仅将寄存器(inefficiently)归零。整个块可能是:
MOV EDX, OFFSET startArray ; load EDX with address of variable
CALL writeString ; print string
xor edx,edx ; edx = 0
实际上你应该省略xor
- 归零,因为你不需要将它归零。你不是在循环或任何东西中使用它作为计数器,所有其他用途都是只写的。
另请注意,带内存的XCHG
具有隐式lock
前缀,因此它以原子方式执行read-modify-write(使其 比单独{{1}慢加载和存储的说明。)
您可以使用mov
加载一对字节,并使用分支来决定是否movzx eax, word ptr [esi]
交换它们。但是,从字节存储转发到字加载的存储转发停顿也不是很好。
无论如何,这与标题问题的主题相关,这不是codereview.SE。
答案 1 :(得分:1)
使用EAX绝对是可能的,事实上你已经是。你问&#34;我试图看看我是否可以将AL移入EAX,但这给了我一堆错误。&#34;想想这意味着什么。 EAX是扩展的AX寄存器,AL是AX的下层分区。看一下这个图表:image of EAX register 。正如您所看到的,使用MOVZX指令将AL移动到EAX只会将AL中的值放入EAX并从右到左填充零。您正在将AL移动到AL,并将EAX的其余部分设置为0.您实际上可以将所有内容移动到EAX中并运行相同的程序,因为它使用了没有区别记忆的同一部分。
另外,你为什么这么推动和弹出EAX?从运行时堆栈中推送/弹出东西的唯一原因是稍后要恢复它们,但是你永远不会这样做,所以你可以放弃EAX当时的任何东西。