在汇编中将十进制转换为 ASCII/二进制
convert decimal to ASCII / binary in assembly
我正在尝试将给定的十进制数转换为 32 个字符的二进制数,但我的代码一直给我错误的答案
我正在尝试转换为二进制的数字
aLength db 21
我使用的变量
two dq 2
tempString resb 33
我尝试将 aLength (21) 除以 2 32 次并将所有余数叠加,但它不起作用
这是我的代码
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
让 debug 你的代码在一起。
调试是您应该必须自己完成的事情,因为编写代码只是故事的一半。
老实说,我认为这个问题会被否决,因为它实际上恰恰相反,人们似乎希望它得到回答。
现在,您问了很多类似的问题4,这表明您完全缺乏调试技巧。
因此,我们不会告诉您代码中 易于发现和调试 的错误,我们将进行调试,这样也许您会学到一些东西。
我们将使用 GDB1。我从你的代码2开始,制作了一个针对ELF64的可组装版本,并在Cygwin上用gcc编译了目标文件。
让我们首先检查我们的值是否正确加载。
逐步执行前两条指令,即设置 RAX 的指令。
┌───────────────────────────────────────────────────────────────────────────┐
B+ │0x1004010e0 <WinMain> mov [=10=]x0,%eax │
│0x1004010e5 <WinMain+5> mov 0xf25(%rip),%eax # 0x10040201│
│0x1004010eb <WinMain+11> mov [=10=]x20,%ecx │
│0x1004010f0 <lp2> mov [=10=]x0,%edx │
>│0x1004010f5 <lp2+5> divq 0xf15(%rip) # 0x100402011 <tw│
│0x1004010fc <lp2+12> push %rdx │
│0x1004010fd <lp2+13> loop 0x1004010f0 <lp2> │
│0x1004010ff <lp2+15> movabs [=10=]x100407000,%rsi │
│0x100401109 <lp2+25> mov [=10=]x2,%ecx │
│0x10040110e <lp3> pop %rax │
│0x10040110f <lp3+1> add [=10=]x30,%al │
│0x100401111 <lp3+3> mov %al,(%rbx) │
│0x100401113 <lp3+5> inc %rbx │
│0x100401116 <lp3+8> loop 0x10040110e <lp3> │
│0x100401118 <lp3+10> movb [=10=]x0,(%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 分钟 的搜索,我们终于发现第二条指令 正在从 aLength[=128 加载一个 DWORD =] 这是一个字节,所以我们将一些垃圾放入 RAX.
所以我们更正那行3:
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 [=13=]x20,%ecx │
>│0x1004010f0 <lp2> mov [=13=]x0,%edx │
│0x1004010f5 <lp2+5> divq 0xf15(%rip) # 0x100402011 <tw│
│0x1004010fc <lp2+12> push %rdx │
│0x1004010fd <lp2+13> loop 0x1004010f0 <lp2> │
│0x1004010ff <lp2+15> movabs [=13=]x100407000,%rsi │
│0x100401109 <lp2+25> mov [=13=]x2,%ecx │
│0x10040110e <lp3> pop %rax │
│0x10040110f <lp3+1> add [=13=]x30,%al │
│0x100401111 <lp3+3> mov %al,(%rbx) │
│0x100401113 <lp3+5> inc %rbx │
│0x100401116 <lp3+8> loop 0x10040110e <lp3> │
│0x100401118 <lp3+10> movb [=13=]x0,(%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 是 21 的 lsb,也就是一个。
让我们检查一下堆栈上是否有效地存在这个。
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 [=15=]x0,%eax │
│0x1004010e5 <WinMain+5> mov 0xf25(%rip),%al # 0x1│
│0x1004010eb <WinMain+11> mov [=15=]x20,%ecx │
│0x1004010f0 <lp2> mov [=15=]x0,%edx │
│0x1004010f5 <lp2+5> divq 0xf15(%rip) # 0x10040│
│0x1004010fc <lp2+12> push %rdx │
│0x1004010fd <lp2+13> loop 0x1004010f0 <lp2> │
>│0x1004010ff <lp2+15> movabs [=15=]x100407000,%rsi │
│0x100401109 <lp2+25> mov [=15=]x2,%ecx │
│0x10040110e <lp3> pop %rax │
│0x10040110f <lp3+1> add [=15=]x30,%al │
└───────────────────────────────────────────────────────────────────────────┘
native Thread 4236.0x12e0 In: lp2 L?? PC: 0x1004010ff
(gdb) p/u *(unsigned long long (*)[32])$rsp
= {0 <repeats 27 times>, 1, 0, 1, 0, 1}
(gdb)
寄存器肯定没问题,所以我们只检查推送的值。
正如 GDB 告诉我们的那样,数字 21 已正确转换为 0..010101。
我们现在再次调试下一个循环的第一次迭代:
┌───────────────────────────────────────────────────────────────────────────┐
>│0x10040110e <lp3> pop %rax │
│0x10040110f <lp3+1> add [=16=]x30,%al │
│0x100401111 <lp3+3> mov %al,(%rbx) │
│0x100401113 <lp3+5> inc %rbx │
│0x100401116 <lp3+8> loop 0x10040110e <lp3> │
│0x100401118 <lp3+10> movb [=16=]x0,(%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
正在确认程序的正确性。
,可以使用 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 因为乞丐不能挑剔。 This cheatsheet 会有用。
2原来的那个,不是那个打补丁的。
3 实现将字节加载到 RAX.
的可能最丑陋的方法
4 正如我在评论中解释的那样,你们中的一个问题本质上是这个问题的补充,可以非常直接地重复使用。
我正在尝试将给定的十进制数转换为 32 个字符的二进制数,但我的代码一直给我错误的答案
我正在尝试转换为二进制的数字
aLength db 21
我使用的变量
two dq 2
tempString resb 33
我尝试将 aLength (21) 除以 2 32 次并将所有余数叠加,但它不起作用
这是我的代码
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
让 debug 你的代码在一起。
调试是您应该必须自己完成的事情,因为编写代码只是故事的一半。
老实说,我认为这个问题会被否决,因为它实际上恰恰相反,人们似乎希望它得到回答。
现在,您问了很多类似的问题4,这表明您完全缺乏调试技巧。
因此,我们不会告诉您代码中 易于发现和调试 的错误,我们将进行调试,这样也许您会学到一些东西。
我们将使用 GDB1。我从你的代码2开始,制作了一个针对ELF64的可组装版本,并在Cygwin上用gcc编译了目标文件。
让我们首先检查我们的值是否正确加载。
逐步执行前两条指令,即设置 RAX 的指令。
┌───────────────────────────────────────────────────────────────────────────┐
B+ │0x1004010e0 <WinMain> mov [=10=]x0,%eax │
│0x1004010e5 <WinMain+5> mov 0xf25(%rip),%eax # 0x10040201│
│0x1004010eb <WinMain+11> mov [=10=]x20,%ecx │
│0x1004010f0 <lp2> mov [=10=]x0,%edx │
>│0x1004010f5 <lp2+5> divq 0xf15(%rip) # 0x100402011 <tw│
│0x1004010fc <lp2+12> push %rdx │
│0x1004010fd <lp2+13> loop 0x1004010f0 <lp2> │
│0x1004010ff <lp2+15> movabs [=10=]x100407000,%rsi │
│0x100401109 <lp2+25> mov [=10=]x2,%ecx │
│0x10040110e <lp3> pop %rax │
│0x10040110f <lp3+1> add [=10=]x30,%al │
│0x100401111 <lp3+3> mov %al,(%rbx) │
│0x100401113 <lp3+5> inc %rbx │
│0x100401116 <lp3+8> loop 0x10040110e <lp3> │
│0x100401118 <lp3+10> movb [=10=]x0,(%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 分钟 的搜索,我们终于发现第二条指令 正在从 aLength[=128 加载一个 DWORD =] 这是一个字节,所以我们将一些垃圾放入 RAX.
所以我们更正那行3:
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 [=13=]x20,%ecx │
>│0x1004010f0 <lp2> mov [=13=]x0,%edx │
│0x1004010f5 <lp2+5> divq 0xf15(%rip) # 0x100402011 <tw│
│0x1004010fc <lp2+12> push %rdx │
│0x1004010fd <lp2+13> loop 0x1004010f0 <lp2> │
│0x1004010ff <lp2+15> movabs [=13=]x100407000,%rsi │
│0x100401109 <lp2+25> mov [=13=]x2,%ecx │
│0x10040110e <lp3> pop %rax │
│0x10040110f <lp3+1> add [=13=]x30,%al │
│0x100401111 <lp3+3> mov %al,(%rbx) │
│0x100401113 <lp3+5> inc %rbx │
│0x100401116 <lp3+8> loop 0x10040110e <lp3> │
│0x100401118 <lp3+10> movb [=13=]x0,(%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 是 21 的 lsb,也就是一个。
让我们检查一下堆栈上是否有效地存在这个。
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 [=15=]x0,%eax │
│0x1004010e5 <WinMain+5> mov 0xf25(%rip),%al # 0x1│
│0x1004010eb <WinMain+11> mov [=15=]x20,%ecx │
│0x1004010f0 <lp2> mov [=15=]x0,%edx │
│0x1004010f5 <lp2+5> divq 0xf15(%rip) # 0x10040│
│0x1004010fc <lp2+12> push %rdx │
│0x1004010fd <lp2+13> loop 0x1004010f0 <lp2> │
>│0x1004010ff <lp2+15> movabs [=15=]x100407000,%rsi │
│0x100401109 <lp2+25> mov [=15=]x2,%ecx │
│0x10040110e <lp3> pop %rax │
│0x10040110f <lp3+1> add [=15=]x30,%al │
└───────────────────────────────────────────────────────────────────────────┘
native Thread 4236.0x12e0 In: lp2 L?? PC: 0x1004010ff
(gdb) p/u *(unsigned long long (*)[32])$rsp
= {0 <repeats 27 times>, 1, 0, 1, 0, 1}
(gdb)
寄存器肯定没问题,所以我们只检查推送的值。
正如 GDB 告诉我们的那样,数字 21 已正确转换为 0..010101。
我们现在再次调试下一个循环的第一次迭代:
┌───────────────────────────────────────────────────────────────────────────┐
>│0x10040110e <lp3> pop %rax │
│0x10040110f <lp3+1> add [=16=]x30,%al │
│0x100401111 <lp3+3> mov %al,(%rbx) │
│0x100401113 <lp3+5> inc %rbx │
│0x100401116 <lp3+8> loop 0x10040110e <lp3> │
│0x100401118 <lp3+10> movb [=16=]x0,(%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
正在确认程序的正确性。
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 因为乞丐不能挑剔。 This cheatsheet 会有用。
2原来的那个,不是那个打补丁的。
3 实现将字节加载到 RAX.
的可能最丑陋的方法
4 正如我在评论中解释的那样,你们中的一个问题本质上是这个问题的补充,可以非常直接地重复使用。