【问题标题】:Trouble understanding this assembly code无法理解此汇编代码
【发布时间】:2018-01-17 12:06:09
【问题描述】:

我要考试了,我正在努力组装。我已经编写了一些简单的 C 代码,得到了它的汇编代码,然后尝试对汇编代码进行评论作为练习。 C代码:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
   int x = 10;
   char const* y = argv[1];

   printf("%s\n",y );

   return 0;
}

它的汇编代码:

   0x00000000000006a0 <+0>: push   %rbp                   # Creating stack
   0x00000000000006a1 <+1>: mov    %rsp,%rbp              # Saving base of stack into base pointer register
   0x00000000000006a4 <+4>: sub    $0x20,%rsp             # Allocate 32 bytes of space on the stack
   0x00000000000006a8 <+8>: mov    %edi,-0x14(%rbp)       # First argument stored in stackframe
   0x00000000000006ab <+11>:    mov    %rsi,-0x20(%rbp)   # Second argument stored in stackframe
   0x00000000000006af <+15>:    movl   $0xa,-0xc(%rbp)    # Value 10 stored in x's address in the stackframe
   0x00000000000006b6 <+22>:    mov    -0x20(%rbp),%rax   # Second argument stored in return value register
   0x00000000000006ba <+26>:    mov    0x8(%rax),%rax     # ??
   0x00000000000006be <+30>:    mov    %rax,-0x8(%rbp)    # ??
   0x00000000000006c2 <+34>:    mov    -0x8(%rbp),%rax    # ??
   0x00000000000006c6 <+38>:    mov    %rax,%rdi          # Return value copied to 1st argument register - why??
   0x00000000000006c9 <+41>:    callq  0x560              # printf??
   0x00000000000006ce <+46>:    mov    $0x0,%eax          # Value 0 is copied to return register
   0x00000000000006d3 <+51>:    leaveq                    # Destroying stackframe
   0x00000000000006d4 <+52>:    retq                      # Popping return address, and setting instruction pointer equal to it

无论我有什么“??”,一个友好的灵魂可以帮助我吗? (意思是我不明白发生了什么或者我不确定)?

【问题讨论】:

  • 如果你的课程是汇编编程,阅读编译器生成的代码不会有帮助。在您的教育的这个阶段,这可能是有害的。
  • 你可以尝试使用gcc -c -S -fverbose-asm file.c - 应该生成带有注释ASM的file.s
  • 它有助于使用调试器单步通过汇编程序,注意寄存器、内存等操作。
  • @StoryTeller 我即将举行的考试将有“用 C 重写上述 X86 汇编程序”之类的问题,所以我想通过反过来练习我可以受益。
  • 您还应该检查编译器的优化输出,您当前的程序集未优化 -O0 在每行源代码之后更新堆栈框架和局部变量,以使 C 源代码中的“每行”调试成为可能,机器代码没有该功能生成将有很大不同(也更短,并且从纯汇编的角度可能更容易理解......并且更难以重写回C源代码,此时您基本上必须执行 asm -> algorithm - > 从头开始​​编写 C,而未优化的代码几乎可以通过 asm->C 反向翻译来重构)。

标签: c assembly x86


【解决方案1】:
   0x00000000000006ba <+26>:    mov    0x8(%rax),%rax     # get argv[1] to rax
   0x00000000000006be <+30>:    mov    %rax,-0x8(%rbp)    # move argv[1] to local variable
   0x00000000000006c2 <+34>:    mov    -0x8(%rbp),%rax    # move local variable to rax (for move to rdi)
   0x00000000000006c6 <+38>:    mov    %rax,%rdi          # now rdi has argv[1]
   0x00000000000006c9 <+41>:    callq  0x560              # it is puts (optimized)

【讨论】:

  • 谢谢!所以第一行是因为 arg[1] 不在 stackframe 中,所以我们必须先把它移到另一个寄存器中,然后才能把它移到 stackframe 中的某个地址中?
  • 是的,因为 x86 和 x64 没有通用的内存到内存指令(有些存在但不用于一般用途)
  • 你不必复制它,它只是未优化的代码。注意它正在将rax 写入内存,然后重新加载它,然后传输到rdi。这 3 条指令可以替换为单个 mov 0x8(%rax), %rdi
【解决方案2】:

我会试着猜测一下:

mov    -0x20(%rbp),%rax   # retrieve argv[0]
mov    0x8(%rax),%rax     # store argv[1] into rax
mov    %rax,-0x8(%rbp)    # store argv[1] (which now is in rax) into y
mov    -0x8(%rbp),%rax    # put y back into rax (which might look dumb, but possibly it has its reasons)
mov    %rax,%rdi          # copy y to rdi, possibly to prepare the context for the printf

当您处理汇编程序时,请指定您使用的架构。英特尔处理器可能使用与 ARM 处理器不同的一组指令,相同的指令可能不同,或者它们可能依赖于不同的假设。您可能知道,优化会更改编译器生成的汇编程序指令的顺序,您可能需要指定是否也使用它(看起来不像?)以及您使用的编译器,因为每个人都有自己的生成汇编程序的策略.

也许我们永远不会知道为什么编译器必须通过从 rax 复制来为 printf 准备上下文,这可能是编译器的选择或特定架构强加的义务。由于所有这些烦人的原因,大多数人更喜欢使用诸如 C 之类的“高级语言”,这样指令集总是正确的,尽管它对人类来说可能看起来很愚蠢(我们知道计算机在设计上是愚蠢的)并不总是最好的选择,这就是为什么仍然有很多编译器。

我可以再给你两个提示:

  1. 您的 IDE 必须有一种方法可以将汇编器指令与 C 代码交错,并在汇编器中单步执行。尝试找出并自己探索它

  2. IDE 还应该具有探索程序内存的功能。如果您发现尝试输入 0x560 地址并查看它会引导您。这很可能是您的 printf 的入口点

希望我的回答能帮到你,祝你好运

【讨论】:

  • 我不清楚为什么mov %rax,%rdi 在那里,谢谢:)
  • OP 在没有优化的情况下编译。禁用优化时看到非常奇怪的东西是很正常的。我建议至少使用-O1 进行编译,以获得最基本的优化。
猜你喜欢
  • 1970-01-01
  • 2015-08-26
  • 1970-01-01
  • 2017-11-13
  • 1970-01-01
  • 1970-01-01
  • 2015-02-24
  • 1970-01-01
相关资源
最近更新 更多