ASSEMBLY - 输出一个32位寄存器与16位寄存器的数组

时间:2017-11-06 23:42:07

标签: 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 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位寄存器并获得相同的输出?

2 个答案:

答案 0 :(得分:1)

如果您仍想进行8位存储,则需要才能使用8位寄存器。 (AL是一个8位寄存器.IDK为什么你在标题中提到16)。

x86具有加宽加载(movzxmovsx),但来自寄存器操作数的整数存储总是使寄存器与内存操作数的宽度相同。即存储EAX的低字节的方式是mov [esi], al

printArray中,您应使用movzx eax, byte ptr [esi]零延伸到EAX 。 (或者,如果您希望将数字视为int8_t而不是uint8_t,则可以使用movsx进行符号扩展。)这样可以避免将EAX的高24位置零。

顺便说一句,你的代码有很多不必要的指令。 e.g。

    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当时的任何东西。