Arrays 汇编-输出32位寄存器与16位寄存器的阵列
我正在做一些家庭作业来打印一个数组,因为它从数组中排序一些整数。我的代码运行良好,但决定尝试在代码中使用EAX而不是AL,并遇到了错误。我不明白这是为什么。在这里可以使用EAX吗Arrays 汇编-输出32位寄存器与16位寄存器的阵列,arrays,sorting,assembly,x86,irvine32,Arrays,Sorting,Assembly,X86,Irvine32,我正在做一些家庭作业来打印一个数组,因为它从数组中排序一些整数。我的代码运行良好,但决定尝试在代码中使用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 b
; 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
;这个程序使用
; 气泡排序算法。它调用一个过程来
; 打印之前数组的元素,气泡排序,
; 在循环的每次迭代中,以及在循环结束时,各执行一次。
包括Irvine32.inc
.数据
myArray字节5,1,4,2,8
;myArray DWORD 5,1,4,2,8
currentArray BYTE'这是数组的值:',0
startArray字节“开始数组”,0
最终数组字节“最终数组”,0
空格字节“”,0;字节
.代码
主进程
MOV-EAX,0;清除寄存器,将0移到每个寄存器中,并初始化
MOV-EBX,0;清除寄存器,将0移到每个寄存器中,并初始化
MOV-ECX,0;清除寄存器,将0移到每个寄存器中,并初始化
MOV-EDX,0;清除寄存器,将0移到每个寄存器中,并初始化
推动EDX;保留原始edx寄存器值以供将来的writeString调用
MOV-EDX,偏移星光;用变量的地址加载EDX
通话记录;打印字符串
POP-EDX;将edx返回到上一个堆栈
MOV ECX,myArray的长度;用数组元素的#加载ECX
DEC-ECX;递减计数1
L1:
推动ECX;保存外循环计数
MOV ESI,偏移量myArray;指向第一个值
L2:
MOV AL[ESI];获取数组值
CMP[ESI+1],AL;比较一对值
JGE-L3;如果[esi]如果仍要进行8位存储,则需要使用8位寄存器。(AL是一个8位寄存器。IDK为什么在标题中提到16)
x86具有加宽的负载(movzx
和movsx
),但来自寄存器操作数的整数存储始终采用与内存操作数相同宽度的寄存器。i、 e.存储EAX低位字节的方法是使用mov[esi],al
在printary
中,应使用movzx-eax,字节ptr[esi]
将零扩展到eax。(如果您想将数字视为int8_t
而不是uint8_t
,则可以使用movsx进行扩展签名)这样就避免了EAX的高24位需要归零
顺便说一句,你的代码有很多不必要的指令。e、 g
MOV EAX,0 ; clearing registers, moving 0 into each, and initialize
毫无意义。如果您的第一次使用是只写的,那么在第一次使用寄存器之前不需要“init”或“declare”。您使用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
只有当您实际需要旧值时,才需要保存“Caller saved”寄存器。我更喜欢术语“保留通话”和“取消通话”。如果writeString破坏了它的输入寄存器,那么在函数返回后,EDX会保留一个未知值,但这没关系。无论如何,您不需要该值。(实际上,我认为Irvine32函数最多只能破坏EAX。)
在这种情况下,前一条指令仅将寄存器归零。整个街区可能是:
MOV EDX, OFFSET startArray ; load EDX with address of variable
CALL writeString ; print string
xor edx,edx ; edx = 0
实际上,您也应该省略异或,因为您不需要将其归零。您没有将它用作循环中的计数器或任何东西,所有其他用途都是只写的
还要注意的是,带内存的XCHG
有一个隐式lock
前缀,因此它以原子方式执行读-修改-写操作(使其加载和存储速度比单独的mov
指令慢得多)
您可以使用movzx eax,word ptr[esi]
加载一对字节,并使用一个分支来决定是否使用rol ax,8
交换它们。但是从字节存储转发到字加载的存储转发也不是很好
无论如何,这已经偏离了主题问题,这不是codereview.SE。使用EAX绝对是可能的,事实上你已经做到了。你问“我想看看我是否能把AL转移到EAX,但那给了我一大堆错误。”想想这意味着什么。EAX是扩展AX寄存器,AL是AX的下分区。看看这个图表:
. 如您所见,使用MOVZX指令将AL移动到EAX中只需将AL中的值放入EAX中,并从右向左填充零。将AL移动到AL中,并将EAX的其余部分设置为0。实际上,您可以将所有内容移动到EAX中,并以相同的方式运行程序,不会有任何区别,因为它使用的是相同的内存部分
还有,你为什么要这么频繁地推和弹出EAX?从运行时堆栈中推送/弹出内容的唯一原因是以后恢复它们,但您永远不会这样做,因此您可以让EAX中当时存在的内容消失。显示您实际尝试的代码以及错误。确保在指令集引用中进行交叉检查,以查看您尝试执行的操作是否有效。注意,DWORD的大小为4字节,在某些地方,您将大小硬编码为1
,而不是使用TYPE
运算符。这不是一个很好的图表。AX
标签位于其标记的低位16之外,而AL和AH位于其标记的寄存器内。这可能会让人误以为AX是EAX的高半部,而不是低半部。有关ASCII艺术图表,请参阅。和。这些都是链接的,所以你可以很快找到它们。顺便说一句,没有,即使使用movzx