I am trying to convert a given decimal number into a 32 character binary number but my code keeps giving me the wrong answer
Number i am trying to convert to binary
aLength db 21
variables the i used
two dq 2
tempString resb 33
i tried to divide the aLength (21) by 2 32 times and stacking all the remainders but it is not working
here is my code
mov rax,0
mov eax,byte[aLength]
mov rcx,32
lp2:
mov rdx,0
div qword[two]
push rdx
loop lp2
mov rsi,tempString
mov rcx,2
lp3:
pop rax
add al,"0"
mov byte[rbx],al
inc rbx
loop lp3
mov byte[rbx],NULL
Lets debug your code together.
Debugging is something you should must do on your own, because writing code is just half of the story.
Honestly I thought this question would be downvoted, since it is actually the opposite it seems the People want it to be answered.
Now, you are asking a lot of similar questions4 which shown a lack of debugging skills altogether.
So instead of telling the easy to spot and debug mistakes in your code, we will go through debugging, so maybe you'll learn something.
We will use GDB1. I started from your code2, made an assemblable version targeting ELF64 and compiled the object file with gcc on Cygwin.
Lets first check that our values are loaded correctly.
Step through the first two instructions, the ones that set RAX up.
┌───────────────────────────────────────────────────────────────────────────┐
B+ │0x1004010e0 <WinMain> mov $0x0,%eax │
│0x1004010e5 <WinMain+5> mov 0xf25(%rip),%eax # 0x10040201│
│0x1004010eb <WinMain+11> mov $0x20,%ecx │
│0x1004010f0 <lp2> mov $0x0,%edx │
>│0x1004010f5 <lp2+5> divq 0xf15(%rip) # 0x100402011 <tw│
│0x1004010fc <lp2+12> push %rdx │
│0x1004010fd <lp2+13> loop 0x1004010f0 <lp2> │
│0x1004010ff <lp2+15> movabs $0x100407000,%rsi │
│0x100401109 <lp2+25> mov $0x2,%ecx │
│0x10040110e <lp3> pop %rax │
│0x10040110f <lp3+1> add $0x30,%al │
│0x100401111 <lp3+3> mov %al,(%rbx) │
│0x100401113 <lp3+5> inc %rbx │
│0x100401116 <lp3+8> loop 0x10040110e <lp3> │
│0x100401118 <lp3+10> movb $0x0,(%rbx) │
│0x10040111b <lp3+13> retq │
└───────────────────────────────────────────────────────────────────────────┘
native Thread 5100.0x9e4 In: lp2 L?? PC: 0x1004010f5
(gdb) si 4
0x00000001004010f5 in lp2 ()
(gdb) i r rax rcx rdx
rax 0x215 533
rcx 0x20 32
rdx 0x0 0
(gdb)
Shippity shop! What is happening here?
RCX, RDX look good, but RAX doesn't! Sure 533 is a lot different from 21.
After whole ten minutes of scraping out heads we finally figure out that the second instruction is loading a DWORD from aLength which is a BYTE, so we are putting some rubbish into RAX.
So we correct that line3:
mov al, BYTE [aLength]
We than again repeat the previous debugging step:
(gdb) i r rax rcx rdx
rax 0x15 21
rcx 0x20 32
rdx 0x0 0
Good!
Now we execute the first iteration of the loop
┌───────────────────────────────────────────────────────────────────────────┐
│0x1004010e5 <WinMain+5> mov 0xf25(%rip),%al # 0x100402010│
│0x1004010eb <WinMain+11> mov $0x20,%ecx │
>│0x1004010f0 <lp2> mov $0x0,%edx │
│0x1004010f5 <lp2+5> divq 0xf15(%rip) # 0x100402011 <tw│
│0x1004010fc <lp2+12> push %rdx │
│0x1004010fd <lp2+13> loop 0x1004010f0 <lp2> │
│0x1004010ff <lp2+15> movabs $0x100407000,%rsi │
│0x100401109 <lp2+25> mov $0x2,%ecx │
│0x10040110e <lp3> pop %rax │
│0x10040110f <lp3+1> add $0x30,%al │
│0x100401111 <lp3+3> mov %al,(%rbx) │
│0x100401113 <lp3+5> inc %rbx │
│0x100401116 <lp3+8> loop 0x10040110e <lp3> │
│0x100401118 <lp3+10> movb $0x0,(%rbx) │
│0x10040111b <lp3+13> retq │
└───────────────────────────────────────────────────────────────────────────┘
native Thread 4236.0x12e0 In: lp2 L?? PC: 0x1004010f0
rdx 0x0 0
(gdb) si 3
0x00000001004010f0 in lp2 ()
(gdb) i r rax rcx rdx
rax 0xa 10
rcx 0x1f 31
rdx 0x1 1
(gdb)
Everything looks good: RAX has been halved, RCX is one less 32, RDX is the lsb of 21, which is one.
Lets just check that on the stack there effectively is this one.
A syntax error in expression, near `%rsp'.
(gdb) x/1dg $rsp
0xffffcb20: 1
Nice!
Since the loops seems ok, we can now step outside of it and check the partial results.
┌───────────────────────────────────────────────────────────────────────────┐
│0x1004010dc <__gcc_deregister_frame+12> nop │
│0x1004010dd <__gcc_deregister_frame+13> nop │
│0x1004010de <__gcc_deregister_frame+14> nop │
│0x1004010df <__gcc_deregister_frame+15> nop │
B+ │0x1004010e0 <WinMain> mov $0x0,%eax │
│0x1004010e5 <WinMain+5> mov 0xf25(%rip),%al # 0x1│
│0x1004010eb <WinMain+11> mov $0x20,%ecx │
│0x1004010f0 <lp2> mov $0x0,%edx │
│0x1004010f5 <lp2+5> divq 0xf15(%rip) # 0x10040│
│0x1004010fc <lp2+12> push %rdx │
│0x1004010fd <lp2+13> loop 0x1004010f0 <lp2> │
>│0x1004010ff <lp2+15> movabs $0x100407000,%rsi │
│0x100401109 <lp2+25> mov $0x2,%ecx │
│0x10040110e <lp3> pop %rax │
│0x10040110f <lp3+1> add $0x30,%al │
└───────────────────────────────────────────────────────────────────────────┘
native Thread 4236.0x12e0 In: lp2 L?? PC: 0x1004010ff
(gdb) p/u *(unsigned long long (*)[32])$rsp
$3 = {0 <repeats 27 times>, 1, 0, 1, 0, 1}
(gdb)
The register are surely ok, so we only check the pushed values.
As GDB tells us, the number 21 has been correctly converted into 0..010101.
We now again debug the first iteration of the next loop:
┌───────────────────────────────────────────────────────────────────────────┐
>│0x10040110e <lp3> pop %rax │
│0x10040110f <lp3+1> add $0x30,%al │
│0x100401111 <lp3+3> mov %al,(%rbx) │
│0x100401113 <lp3+5> inc %rbx │
│0x100401116 <lp3+8> loop 0x10040110e <lp3> │
│0x100401118 <lp3+10> movb $0x0,(%rbx) │
│0x10040111b <lp3+13> retq │
│0x10040111c <lp3+14> nopl 0x0(%rax) │
│0x100401120 <__cxa_atexit> jmpq *0x6fbe(%rip) # 0x1004080e4 <│
│0x100401126 <__cxa_atexit+6> nop │
│0x100401127 <__cxa_atexit+7> nop │
│0x100401128 <__cxa_atexit+8> nop │
│0x100401129 <__cxa_atexit+9> nop │
│0x10040112a <__cxa_atexit+10> nop │
│0x10040112b <__cxa_atexit+11> nop │
└───────────────────────────────────────────────────────────────────────────┘
native Thread 4236.0x12e0 In: lp3 L?? PC: 0x10040110e
0x0000000100401116 in lp3 ()
(gdb) si
0x000000010040110e in lp3 ()
(gdb) i r rsi rax rbx rcx
rsi 0x100407000 4299190272
rax 0x30 48
rbx 0x285541 2643265
rcx 0x1 1
(gdb)
Oh snap!
RSI has not been incremented! Also RCX is 1 after just one iteration. RAX is fine though.
After another whole ten minutes of frustrating thinking we realize that we are using EBX in the loop, not RSI and we set RCX to 2 not 32!
We fix those:
mov rbx, tempString
mov rcx, 32
Finally we try running the program until the end.
Once done, we examine the string written:
(gdb) x/4xg 0x100407000
0x100407000 <tempString>: 0x3030303030303030 0x3030303030303030
0x100407010 <tempString+16>: 0x3030303030303030 0x3130313031303030
Which, taking endianess into account is
30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 31 30 32 30 31
confirming the correctness of the program.
Here again, you program can be simplified using the same trick of using the CF:
movzx ebx, BYTE [REL aLength] ;EBX = Byte to convert
mov rcx, 32 ;RCX = Bits left to convert
mov rdi, tempString ;RDI = Pointer to output string
xor eax, eax
mov al, '0' ;RAX = Aux value
_convert:
shr eax, 1 ;Get rid of RAX bit 0
shl ebx, 1 ;Set CF to the current msb of EBX
rcl eax, 1 ;Shift into RAX the CF
stosb ;Store ASCII digit
sub rcx, 1 ;Repeat
ja _convert
mov BYTE [rdi], cl ;Write NULL TERM
1 Because beggars can't be choosers. This cheatsheet will be useful.
2 The original one, not the fishy patched one.
3 Implementing the possible ugliest way to load a byte into RAX.
4 As I explained in a comment, one of you question is essentially the complementary of this one and could be reused quite straightforwardly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With