让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。
正如我在评论中解释的那样,你们其中一个人的问题基本上是这个问题的补充,可以很直接地重复使用。
第一件事发现:当'aLength'是一个字节时'mov eax,DWORD [aLength]'。 'rbx'指向...?第二个循环只有2次迭代。我已经回答了您的补充问题(bin - > dec),您可以完全重复使用这些概念。如果你想简化你的代码。 –
我看到代码已被编辑,但假设'rax'已被清零,不应该是'mov al,[aLength]'?您希望转换的数字保存在一个字节中,由'aLength db 21'定义。 –
汇编器将十进制数字'21'自动转换为二进制*。所有你需要做的就是将数据从'eax'的一端滚出(而不是'rax',因为你只需要32位)。不需要划分。 –