在程序集中将十进制转换为ASCII /二进制

时间:2016-06-15 16:52:03

标签: assembly binary decimal ascii

我正在尝试将给定的十进制数转换为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

1 个答案:

答案 0 :(得分:2)

让您的代码debug在一起。

调试是 必须自己做的事情,因为编写代码只是故事的一半。
老实说,我认为这个问题会被贬低,因为它实际上正好相反,似乎人们希望它得到回答。

现在,您提出了很多类似的问题 4 ,这些问题表明完全缺乏调试技巧。
因此,我们不会告诉代码中的容易发现和调试错误,而是进行调试,所以也许你会学到一些东西。

我们将使用GDB 1 。我从您的代码 2 开始,制作了一个针对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)

Shippity商店!这里发生了什么事? RCX RDX 看起来不错,但 RAX 却没有!肯定的533与21相比有很多不同

在整个十分钟刮掉头后,我们终于发现第二条指令正在从 aLength 加载一个DWORD,这是一个BYTE,所以我们是把一些垃圾放入 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    $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 是21的lsb,即1。
让我们在堆栈上检查一下这个问题。

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 虽然很好。

又经过了整整十分钟令人沮丧的想法,我们意识到我们在循环中使用了 EBX ,而不是 RSI ,我们设置了 RCX 到2而不是32!

我们解决了这些问题:

mov rbx, tempString
mov rcx, 32

最后我们尝试运行程序直到结束 完成后,我们检查写的字符串:

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

其中,考虑到endianess是

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

1 因为乞丐不能选择。 This cheatsheet会很有用 2 原来的那个,而不是腥修补的 3 实现将字节加载到 RAX 中的最可能的最简单方法。
4 正如我在评论中所解释的那样,你们中的一个问题基本上是对这一问题的补充,可以非常直接地重复使用。