x86汇编:如何从函数中获取商和余数

时间:2014-03-18 02:55:17

标签: assembly x86 return

以下是我的问题,

  1. 如何将edx中的余数存储回第三个参数的内存地址?
  2. 我是否需要使用子程序才能这样做?
  3. 最有效的方法是什么?
  4. 如果您可以为此显示正确的代码或详细解释如何做到这一点会很棒。如果你能展示两者的组合,那将是非常好的。

    这是我的.asm文件:

    .386
    
    .model flat
    
    public _Divide
    
    .code
    
    _Divide proc
    
            push ebp
            mov ebp, esp
            mov eax, [ebp + 8]
            mov ebx, [ebp + 12]
            cwd
            idiv ebx
            mov ecx, [ebp + 16]
            cmp ecx, 0
            jne remainder
            jmp done
    remainder:
            mov [ebp + 16], edx   ;this is showing as the minimum value for a 
                                  ;long in the cpp(-860,000,000)
    done:
            pop ebp
            ret
    _Divide endp
    
            end
    

    这是我调用_Division函数的.cpp文件:

    #include <iostream>
    
    using namespace std;
    
    extern "C" long Divide (long, long, long *);
    
    void main ()
    {
    long    Result;
    long    Remainder;
    long    Dividend;
    long    Divisor;
    
    do
        {
        cout << "Enter Dividend" << endl; 
        cin >> Dividend;
        cout << "Enter Divisor" << endl;
        cin >> Divisor;
    
        Result = Divide (Dividend, Divisor, &Remainder);
        cout << "Result is " << Result << " and Remainder is " << Remainder << endl;
        } while ((Result >= 0) || (Remainder != 0));
    
    Result = Divide (Dividend, Divisor, 0);
    cout << "Result is " << Result << " and Remainder is not used" << endl;
    }
    

1 个答案:

答案 0 :(得分:4)

您的汇编代码有一些错误:

  • 它是 EBX ,它是x86 ABI中保存的寄存器(即应在函数调用中保留内容)。
  • 您应该使用cdq(双倍到四字)将 EAX 扩展为 EDX:EAX 而不是cwd(word to to双字)签名将 AX 扩展为 DX:AX
  • 对于Remainder out参数,您没有存储到它所指向的位置。

此代码应该有效:

<强> div.asm

.386
.model flat

.code
public _Divide
_Divide proc
    push ebp
    mov ebp, esp
    push ebx
    mov eax, [ebp + 8]
    mov ebx, [ebp + 12]
    cdq
    idiv ebx
    mov ecx, [ebp + 16]
    cmp ecx, 0
    je return
    mov [ecx], edx
return:
    pop ebx
    pop ebp
    ret
_Divide endp
    end

如果我们采用Jester的建议使用带idiv的内存操作数来减少我们的寄存器使用,则代码变为:

_Divide:
    push ebp
    mov ebp, esp
    mov eax, [ebp + 8]
    cdq
    idiv DWORD [ebp + 12]
    mov ecx, [ebp + 16]
    cmp ecx, 0
    je return
    mov [ecx], edx
return:
    pop ebp
    ret