简体   繁体   English

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

[英]convert decimal to ASCII / binary in assembly

I am trying to convert a given decimal number into a 32 character binary number but my code keeps giving me the wrong answer 我试图将给定的十进制数转换为32个字符的二进制数,但我的代码一直给我错误的答案

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 我试图将aLength(21)除以2 32次并叠加所有余数,但它不起作用

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 questions 4 which shown a lack of debugging skills altogether. 现在,你问了很多类似的问题4 ,这些问题完全显示缺乏调试技巧。
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 GDB 1 . 我们将使用GDB 1 I started from your code 2 , made an assemblable version targeting ELF64 and compiled the object file with gcc on Cygwin. 我从你的代码2开始,制作了一个针对ELF64的可组装版本,并在Cygwin上用gcc编译了目标文件。


Lets first check that our values are loaded correctly. 让我们首先检查我们的值是否正确加载。
Step through the first two instructions, the ones that set RAX up. 逐步执行前两条指令,即设置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 shop! Shippity商店! What is happening here? 这里发生了什么?
RCX , RDX look good, but RAX doesn't! RCXRDX看起来不错,但RAX没有! Sure 533 is a lot different from 21. 当然533与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 . 在整整十分钟刮掉头后,我们终于弄清楚第二条指令是从一个字符串加载一个DWORD,这是一个BYTE,所以我们把一些垃圾放到RAX中

So we correct that line 3 : 所以我们纠正第3行:

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. 一切看起来都不错: RAX减半, RCX减少了一半, RDX是21的lsb,这是一个。
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. 正如GDB告诉我们的那样,数字21已正确转换为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! RSI 尚未递增! Also RCX is 1 after just one iteration. 只需一次迭代, RCX就是1。 RAX is fine though. RAX虽然很好。

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! 经过另一整十分钟令人沮丧的思考后,我们意识到我们在循环中使用EBX ,而不是RSI ,我们将RCX设置为2而不是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 其中,考虑到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

confirming the correctness of the program. 确认程序的正确性。


Here again , you program can be simplified using the same trick of using the CF : 在这里 ,您可以使用与使用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. 1因为乞丐不能选择。 This cheatsheet will be useful. 这个备忘单将是有用的。
2 The original one, not the fishy patched one. 2原始的,而不是鱼腥修补的。
3 Implementing the possible ugliest way to load a byte into RAX . 3实现将字节加载到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. 4正如我在评论中所解释的那样,你们其中一个问题基本上是对这一问题的补充,可以非常直接地重复使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM