无法理解gcc的汇编输出

时间:2009-05-24 02:00:35

标签: c gcc assembly

在编写一些C代码时,我决定将它编译成汇编并阅读它 - 我只是一点点,不时这样做 - 这是一种练习让我每次都在思考机器在做什么我在C中写了一个声明。

无论如何,我在C

中写了这两行
asm(";move old_string[i] to new_string[x]");
new_string[x] = old_string[i];
asm(";shift old_string[i+1] into new_string[x]");
new_string[x] |= old_string[i + 1] << 8;

old_stringchar的数组,new_stringunsigned short的数组,所以给定两个字符42和43,这将把4342放入{ {1}})
其中产生了以下输出:

new_string[x]

(我正在自己评论,所以我可以关注正在发生的事情)。 我用-O3编译它,所以我也可以看看编译器如何优化某些结构。无论如何,我确信这可能很简单,但这是我没有得到的:

第一部分从#move old_string[i] to new_string[x] movl -20(%ebp), %esi #put address of first char of old_string in esi movsbw (%edi,%esi),%dx #put first char into dx movw %dx, (%ecx,%ebx,2) #put first char into new_string #shift old_string[i+1] into new_string[x] movsbl 1(%esi,%edi),%eax #put old_string[i+1] into eax sall $8, %eax #shift it left by 8 bits orl %edx, %eax #or edx into it movw %ax, (%ecx,%ebx,2) #? 复制char,然后将其移动(从old_string[i])到dx。然后在下一部分中,复制(%ecx,%ebx),将其移动或移动,然后将其放入old_string[i+1]的相同位置。它将两个16位值放在同一个地方?这不会起作用吗?

此外,它会将ax转换为old_string[i+1]的高阶双字,然后将eaxedx}转移到其中......然后将{{1}进入记忆! new_string[x]不会只包含ax中已有的内容吗?所以它将同样的东西保存在内存中的同一个地方两次?

有什么我想念的吗?另外,我很确定编译程序的其余部分与这个片段无关......我在前后阅读过,找到每个数组和不同变量的存储位置,以及寄存器的值在达到该代码时会发生这种情况 - 我认为这是对于这些C行而言至关重要的那一部分。

- 哦,结果是GNU汇编注释以#。

开头

3 个答案:

答案 0 :(得分:1)

好的,毕竟这很简单。 我用笔和纸计算出来,写下每一步,它对每个寄存器做了什么,然后写下每个寄存器的内容给出初始起始值......

让我觉得它是使用32位和16位寄存器来处理16位和8位数据类型...... 这就是我的想法:

  • 第一个值被记入内存,比如0001(我在想01)。
  • 第二个值(02)加载到32位寄存器(所以它就像,00000002,我在想,0002)
  • 第二个值向左移8位(00000200,我在想,0200)
  • 第一个值(0000001,我认为0001)xor'd到第二个值(00000201,我认为0201)
  • 16位寄存器放入内存(0201,我在想,再次只是01)。

我不明白为什么它将它写入内存两次,或者为什么它使用32位寄存器(实际上,我的猜测是32位处理器使用32位值比使用32位值更快有8位和16位值,但这是一个完全没有受过教育的猜测),所以我尝试重写它:

movl -20(%ebp), %esi       #gets pointer to old_string
movsbw (%edi,%esi),%dx     #old_string[i] -> dx (0001)
movsbw 1(%edi,%esi),%ax    #old_string[i + 1] -> ax (0002)
salw $8, %ax               #shift ax left (0200)
orw %dx, %ax               #or dx into ax (0201)
movw %ax,(%ecx,%ebx,2)     #doesn't write to memory until end

这完全相同。

我不知道这是否是一个优化(除了一个内存写出,显然是),但如果是,我知道这不值得,并没有得到任何东西。无论如何,我得到了这段代码现在正在做的事情,感谢所有人的帮助。

答案 1 :(得分:0)

我不确定什么是不理解的,除非我遗漏了什么。

前3条指令将old_string中的一个字节加载到dx中,并将其存储到new_string中。

接下来的3条指令利用dx中已有的内容并将old_string [i + 1]与它结合起来,并将其作为16位值(ax)存储到new_string。

答案 2 :(得分:0)

  

此外,它将old_string [i + 1]转换为eax的高阶双字,然后   或者将edx(new_string [x])放入其中......然后将ax放入内存中!岂不   ax只包含已经在new_string [x]中的内容?所以它保存相同   在记忆中两次到同一个地方的东西?

现在你明白为什么优化者是一件好事。这种冗余代码经常出现在未经优化的生成代码中,因为生成的代码或多或少来自那些不“知道”之前或之后发生的事情的模板。