admin管理员组

文章数量:1418706

I wrote a code in ASM to calculate the reverse number. For example: input: 123, the result should be 321. The ebx register should have the result, but it aways shows 0. Also, I have an exception "Privileged instruction". I attached an image with the exception. Here is the code:

#include<iostream>
#include<stdlib.h>
#include<stdio.h>

using namespace std;

int main() {


int nb;
cout << "nb=";
cin >> nb;

_asm {

    mov eax, nb;
    mov ebx, 0;
    mov ecx, 10;
_check_while:

    cmp eax, 0;

    je _outside_while;

    mov edx, 0;
    div ecx;
    xchg eax, ebx;
    mul ecx;
    add eax, edx;
    xchg eax, ebx;

    jmp _check_while;


_outside_while:
    mov nb, ebx;


}
cout << "Result is" << " " << nb;
return 0;
}

I wrote a code in ASM to calculate the reverse number. For example: input: 123, the result should be 321. The ebx register should have the result, but it aways shows 0. Also, I have an exception "Privileged instruction". I attached an image with the exception. Here is the code:

#include<iostream>
#include<stdlib.h>
#include<stdio.h>

using namespace std;

int main() {


int nb;
cout << "nb=";
cin >> nb;

_asm {

    mov eax, nb;
    mov ebx, 0;
    mov ecx, 10;
_check_while:

    cmp eax, 0;

    je _outside_while;

    mov edx, 0;
    div ecx;
    xchg eax, ebx;
    mul ecx;
    add eax, edx;
    xchg eax, ebx;

    jmp _check_while;


_outside_while:
    mov nb, ebx;


}
cout << "Result is" << " " << nb;
return 0;
}
Share Improve this question edited Jan 29 at 19:49 Peter Cordes 368k49 gold badges717 silver badges982 bronze badges asked Jan 29 at 19:23 Alex544Alex544 354 bronze badges 4
  • 2 When you use a debugger, what is the first instruction that doesn't do what you expected? – Scott Hunter Commented Jan 29 at 19:47
  • None of those instructions are privileged. Where is EIP pointing when the debugger reports a privileged-instruction exception? div ecx can't #DE fault with ECX=10, and none of your instructions modify ECX. (And that wouldn't be a #GP(0) privileged instruction problem anyway.) – Peter Cordes Commented Jan 29 at 19:52
  • Note that mul ecx overwrites edx. You might want to use imul eax, ecx. – Jester Commented Jan 29 at 19:56
  • 1 You're not using the EDX high-half output of mul so I think you could simplify by removing the xchgs and do imul ebx, ecx. Oh wait, you are reading EDX after mul? Probably you were expecting it to still hold the remainder from div. But actually it will be zero for small inputs where the high half of the 32x32 => 64-bit widening mul ecx is zero. – Peter Cordes Commented Jan 29 at 19:56
Add a comment  | 

2 Answers 2

Reset to default 1

Your fot that mul ecx leaves the widened product in EDX:EAX. Because of it, the remainder that you got before, from div ecx, is no longer available. Just change the order of the operations. This will also save you from having to zero the EDX register before doing the division. Next code assumes that the reversed number never exceeds the unsigned dword range [0,4GB-1]:

_asm {
    push ebx;
    mov  eax, nb;
    xor  ebx, ebx;
    test eax, eax;
    jz   _done;
    mov  ecx, 10;
_more:
    xchg eax, ebx;
    mul  ecx;
    xchg eax, ebx;      <<<< EDX is 0
    div  ecx;
    add  ebx, edx;
    test eax, eax;
    jnz  _more;
_done:
    mov  nb, ebx;
    pop  ebx;
}

What is missing is a check for overflow. Consider eg. a number like 2,000,000,009 that once reversed can not fit in a 32-bit register. Next code checks for this and just doesn't update the nb variable. You pick whatever action you need in this case:

_asm {
    push ebx;
    mov  eax, nb;
    xor  ebx, ebx;
    test eax, eax;
    jz   _done;
    mov  ecx, 10;
_more:
    xchg eax, ebx;
    mul  ecx;
    jc   _fail;
    xchg eax, ebx;      <<<< EDX is 0
    div  ecx;
    add  ebx, edx;
    jc   _fail;
    test eax, eax;
    jnz  _more;
_done:
    mov  nb, ebx;
_fail:
    pop  ebx;
}

Your nb variable is an int, so there's also signed overflow to consider! Take eg. a positive number like 1,000,000,004 that once reversed does fit in a 32-bit register, but that will not really reveal itself as 4,000,000,001.

This code should work:

__asm {
    mov     eax, dword ptr [nb]
    mov     ebx, 10
    xor     ecx, ecx
    test    eax, eax
    je      bail_out
while_loop:
    xor     edx, edx
    imul    ecx, ecx, 10
    div     ebx
    add     ecx, edx
    test    eax, eax
    jne     while_loop
bail_out:
    mov     dword ptr [nb], ecx
}

If you are in doubt, then just write it in C and let the compiler generate it for you by adding the /FAs command line switch or setting the option to generate assembly with source code to and read it to understand how it works.

Note that this code is not fully optimized for demonstration purposes (it was generated with /O1 optimization level and it even used a stack location in the loop but I switched it to use ebx instead). At /O2 and above compiler will use mul, shr, and lea to avoid costly div instruction.

If you want to learn assembler then you need to learn the various forms of each instruction and their parameters. I suggest grabbing a copy of Intel SDM.

本文标签: assemblyAssembler code doesn39t workreverse numberStack Overflow