2016-06-15 61 views
3

我想给定的十进制数转换为32个字符的二进制数,但我的代码一直给我错误的答案转换十进制ASCII /二进制汇编

数我试图转换成二进制

aLength  db 21 

变量第i使用

two   dq  2 
tempString resb 33 

我试图通过2 32倍以划分aLength(21)和层叠所有的余数,但它不工作

这里是我的代码

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 
+0

第一件事发现:当'aLength'是一个字节时'mov eax,DWORD [aLength]'。 'rbx'指向...?第二个循环只有2次迭代。我已经回答了您的补充问题(bin - > dec),您可以完全重复使用这些概念。如果你想简化你的代码。 –

+0

我看到代码已被编辑,但假设'rax'已被清零,不应该是'mov al,[aLength]'?您希望转换的数字保存在一个字节中,由'aLength db 21'定义。 –

+1

汇编器将十进制数字'21'自动转换为二进制*。所有你需要做的就是将数据从'eax'的一端滚出(而不是'rax',因为你只需要32位)。不需要划分。 –

回答

2

debug代码在一起。

调试是你应该必须自己做,因为编写代码只是故事的一半。
老实说,我认为这个问题会被低估,因为它似乎是人们希望它得到回答的反面。

现在,您正在问很多类似的问题,其中显示出缺乏调试技巧。
因此,不要告诉很容易在代码中发现并调试错误,我们将通过调试,所以也许你会学到一些东西。

我们将使用GDB 。我从你的代码开始,制作了一个针对ELF64的可组合版本,并在Cygwin上用gcc编译了目标文件。


让我们首先检查我们的值是否正确加载。
通过前两条指令,即设置RAX的指令。

┌───────────────────────────────────────────────────────────────────────────┐ 
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) 

不孕症店!这里发生了什么?
RCX,RDX看起来不错,但RAX不!当然533是很多不同从21

整个10分钟刮了头后,我们终于搞清楚了第二个指令加载一个DWORD从aLength这是一个字节,所以我们把一些垃圾放入RAX

所以我们纠正线:

mov al, BYTE [aLength] 

我们不是再次重复之前的调试步骤:

(gdb) i r rax rcx rdx 
rax   0x15  21 
rcx   0x20  32 
rdx   0x0  0 

好!
现在我们执行循环的第一次迭代


┌───────────────────────────────────────────────────────────────────────────┐ 
    │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) 

一切看起来不错:RAX已经减半,RCX是少了一个32,RDX是LSB的21,这是一个。
让我们来检查一下堆栈里有没有这个。

A syntax error in expression, near `%rsp'. 
(gdb) x/1dg $rsp 
0xffffcb20:  1 

不错!


因为回路似乎确定,我们现在可以步骤它之外,并检查部分结果

┌───────────────────────────────────────────────────────────────────────────┐ 
    │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) 

寄存器肯定没问题,所以我们只检查推送的值。
正如GDB告诉我们的,数字21已被正确转换为0..010101。


我们现在再次调试第一次迭代的下一个循环的

┌───────────────────────────────────────────────────────────────────────────┐ 
    >│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) 

卡哦!
RSI已有不是已递增!同样RCX只有一次迭代后为1。 RAX虽然不错。

另一个全10分钟令人沮丧的思维我们意识到,我们正在使用EBX的循环,不RSI和我们设定RCX到2不是32后!

我们解决这些:

mov rbx, tempString 
mov rcx, 32 

最后,我们尝试运行该程序,直到结束。
一旦这样做,我们检查所写的字符串:

(gdb) x/4xg 0x100407000 
0x100407000 <tempString>:  0x3030303030303030  0x3030303030303030 
0x100407010 <tempString+16>: 0x3030303030303030  0x3130313031303030 

其中,考虑字节序到的是

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 

确认程序的正确性。


Here again,你的程序可以使用使用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 

因为乞丐不能挑肥拣瘦。 This cheatsheet将会有用。
原来的一个,而不是鱼腥补丁。
实现可能最丑陋的方式将一个字节加载到RAX
正如我在评论中解释的那样,你们其中一个人的问题基本上是这个问题的补充,可以很直接地重复使用。

+0

我喜欢你的“十分钟刮头”和“另一整十分钟令人沮丧的思考”。就个人而言,我不认为在这样一段简单的代码中使用调试器可以简化新手的问题。对于训练有素的眼睛来说,OP代码中的任何错误都只是尖叫!无论发生在审查代码的古代艺术品上? –

+0

@SepRoland确实如此。如果你看看评论,你会发现每个人都已经发现了错误。但是由于OP使用类似这样的问题泛滥网站(本质上,为我调试此代码),我认为引导调试会话将有助于:) –