首页 文章

装配MASM处理负整数

提问于
浏览
2

我被指示在程序集中编写一个程序,它将执行以下算法:

((A B)/ C)*((D - A)E)

当没有负值发挥作用时,我成功地做了这个,但假设A = 5,B = 4,C = 3,D = 2,E = 1.这给了我们((5 4)/ 3) *((2 - 5)1)或-6 .

这是我需要帮助的地方 . 我已经做了一些研究,并且已经发现2可以成为一种解决方案,但我不确定是否将它实现到我的代码中 .

如果有人能帮助我,我将非常感激!

INCLUDE Irvine32.inc
; ((A + B) / C) * ((D - A) + E)
.data
valA dword 1
valB dword 2
valC dword 3
valD dword 4
valE dword 5

.code
main PROC

    mov ecx, valA
    add ecx, valB
    mov edx, valC
    call Divide
    mov ecx, eax
    mov edx, valD
    sub edx, valA
    add edx, valE
    call Multiply

    exit

main ENDP

*除法和乘法程序分别进行分和 .

2 回答

  • 1

    Irvines的WriteDec应替换为WriteInt,它将参数 EAX 处理为带符号的数字 .

    在CPU内部,负"-2"和正"4294967294"被转换为相同的值:0xFFFFFFFE . DIV正向执行除法6 / -2(6/4294967294)并获得结果0 = 0x00000000,其中IDIV结果正确:-3 = 0xFFFFFFFD .

    MULIMUL在结果的高位部分不同( EDX ) . 由于在这种情况下不需要高部分,因此不必使用IMUL .

    对于有符号和无符号数字,ADDSUB没有不同版本 . 这是引入2 's complement coding. It'只是一个解释的主要原因:如果程序员决定这应该是一个带符号的数字,那么它就是一个带符号的数字 . 如果他/她/它决定这是一个无符号数,那么它是一个无符号数 . CPU不关心这些事情 - 结果总是一样的 .

    这是WriteIntIDIVIMUL的示例:

    ; ((A + B) / C) * ((D - A) + E)
    INCLUDE Irvine32.inc
    
    .DATA
    valA dword 5
    valB dword 4
    valC dword 3
    valD dword 2
    valE dword 1
    
    .CODE
    main PROC
        mov ecx, valA
        add ecx, valB
        mov edx, valC
        call Divide
    
        mov ecx, eax
        mov edx, valD
        sub edx, valA
        add edx, valE
        call Multiply
    
        call WriteInt           ; Write a positive or negative number
    
        exit
    main ENDP
    
    Divide PROC USES ECX EDX    ; EAX = ECX / EDX
        mov eax, ecx
        mov ecx, edx
        xor edx, edx
        idiv ecx                ; Signed division, e.g 6/-3 = -2
        ret
    Divide ENDP
    
    Multiply PROC USES ECX EDX  ; EAX = ECX * EDX
        mov eax, edx
        imul ecx                ; Signed multiplication
        ret
    Multiply ENDP
    
    END main
    

    A 2 's complement calculation is needed to get the absolute value of the number. E.g. the representation of -2 has two parts: a sign (' - ') and an absolute value (' 2') . 获得绝对值的一种简单方法是查看符号位,数字的最左位,并跳转到适当的位置 . 计算本身仅由NEG执行 .

    WriteDecIDIVIMUL的示例:

    ; ((A + B) / C) * ((D - A) + E)
    INCLUDE Irvine32.inc
    
    .DATA
    valA dword 5
    valB dword 4
    valC dword 3
    valD dword 2
    valE dword 1
    
    .CODE
    main PROC
        mov ecx, valA
        add ecx, valB
        mov edx, valC
        call Divide
    
        mov ecx, eax
        mov edx, valD
        sub edx, valA
        add edx, valE
        call Multiply
    
        test eax, eax           ; Set the flags according to (EAX AND EAX)
        jns J1                  ; Skip the next block if EAX is positive (no sign)
    
            ; EAX is negative
            push eax            ; Preserve EAX
            mov al, '-'         ; Write the letter '-'
            call WriteChar      ; http://programming.msjc.edu/asm/help/index.html?page=source%2Firvinelib%2Fwritechar.htm
            pop eax             ; Restore EAX
            neg eax             ; 2's complement
    
        J1:
        call WriteDec           ; Write EAX as positive number
    
        exit
    main ENDP
    
    Divide PROC USES ECX EDX    ; EAX = ECX / EDX
        mov eax, ecx
        mov ecx, edx
        xor edx, edx
        idiv ecx                ; signed division, e.g 6/-3 = -2
        ret
    Divide ENDP
    
    Multiply PROC USES ECX EDX  ; EAX = ECX * EDX
        mov eax, edx
        imul ecx                ; signed multiplication
        ret
    Multiply ENDP
    
    END main
    

    这是一个算法,无需跳转即可获得EAX的绝对值:

    cdq
    xor eax, edx
    sub eax, edx
    
  • 2

    在二进制补码机器上, addsub 操作对于有符号和无符号数量实际上是相同的,因此程序的那些部分不需要更改 . 有标记的除法和乘法的具体指令,因此请确保函数使用它们(或直接使用它们) .

相关问题