【问题标题】:why is the assembly equivalent of this C code, as such? [closed]为什么这个 C 代码的程序集等同于这样? [关闭]
【发布时间】:2021-11-17 02:42:04
【问题描述】:

我正在使用这本教科书 Randal E. Bryant, David R. O'Hallaron - Computer Systems。程序员的观点 [第 3 版](2016 年,Pearson)。对于这个问题 3.43 我不知道为什么 一些问题会产生如给定答案中所示的汇编代码。

首先,我不确定为什么在&up->t1.w 的情况下在movw 之前增加了10。

其次,当前两个示例要求我们执行以下操作时,我不确定为什么 up->t2.a 在汇编中只产生一行:

movq (%rdi), %rax
movq %rax, (%rsi)

发生了什么变化?

第三,up->t2.a[up->t1.u] 行被翻译成类似的混淆:

movq (%rdi), %rax
movl (%rdi,%rax,4), %eax
movl %eax, (%rsi)

感谢您的任何帮助,谢谢!

【问题讨论】:

  • 请勿发布代码、数据、错误消息等的图片 - 将文本复制或输入到问题中。 How to Ask
  • @Rob 我会将这些视为插图。也许OP没有数字版的书,复制所有这些都是浪费
  • 加10是为了得到struct的偏移量。在 C 程序中尝试sizeof(long) + sizeof(short)
  • @DownloadPizza 要找出答案,请删除“插图”,看看如果没有它们,问题是否仍然可以回答。
  • @DownloadPizza 我希望 OP 投入工作并将书中的相关部分复制到他的问题中。这也会使问题更容易阅读。

标签: c assembly x86


【解决方案1】:

发生了什么变化?

a 只是一个指针; rdi可以直接写到rsi中的地址:

mov    QWORD PTR [rsi],rdi

u 是一个值,它在内存中,因为它是一个结构成员。这需要加载和存储,x86 can't do with a single mov;必须涉及登记册。这里rax是一个tmp变量:

mov    rax,QWORD PTR [rdi]
mov    QWORD PTR [rsi],rax

这相当于一个假设:

mov    QWORD PTR [rsi], QWORD PTR [rdi]   !!! NOT encodeable into machine code

更复杂的寻址方式:

这是 Base-Scale/Index-Displacement

movl (%rdi,%rax,4), ...

rdi 作为基数加上4*rax 作为偏移量,或者在C 语法中:int rdi[rax]。在 Intel 语法 asm 中它看起来像这样(因为 asm 使用字节偏移,没有按操作数大小进行隐式缩放):

mov  ..., [rdi + rax*4]

遗憾的是,AT&T 和 Intel 的语法看起来非常不同...我更喜欢明确的 xWORD PTR [],并且从右到左。

这是 int 数组的 get()

void get_a(u_type *up, int **dest) {
    *dest = up->t2.a;
}

实际上只是强制复制(数组)指针。

【讨论】:

  • 普通 CPU 不能在一条指令中从一个地址移动到另一个地址 - x86 不能 (at least not two explicit addressing modes),m68k 和 VAX 可以。大多数人认为 m68k 和 VAX 是正常的。 (不是common,但就设计而言,m68k 与 x86 一样正常。)实际上,使用 dest、src args 和 x86-64 SysV 调用约定,对于 movsq如果需要,可以在一条指令中执行 *rdi++ = *rsi++ 的指令。编译器这样做,因为它比较慢。
  • movsq 不是mov(数据传输),而是要重复的“字符串”操作。但我的陈述不太准确,感谢这些细节。也许重要的不是指令,而是微操作。如果该字节不通过 CPU,任何 CPU 电路都无法使 RAM 中的字节移动。
  • 是的,我的评论 100% 是选词挑剔,不是不同意你的整体观点,也不是与两个内存操作数无效的 mov 的例子;我已经投了赞成票。为了避免通过提出movsq 或效率来使事情变得过于复杂,也许可以说“这需要加载和存储,因此编译器将使用两个mov 指令,因为它不能使用两个内存操作数进行编码。因为那个 true,如果编译器(和这个问题)不使用它们,movspush/pop [mem] 存在的事实是不相关的。
  • (顺便说一句,movs 确实可以在没有 rep 前缀的情况下工作,顺便说一句,这只是重复“字符串”指令的一个选项。另一个预期用途是将它们放在一个循环中在每次迭代中也一样;不过,lods、stos、scas 和 cmps 比 movs 更常见。8086 ISA 的架构师 Stephen Morse 在他的书中讨论了这种设计意图,这些天免费在线,stevemorse.org/8086/index.html around第 72 页,作为存在 loopjcxz 指令并使用与 rep 相同的 CX 的原因。当然,这对于性能来说已经过时了!)。
  • 由于您没有更正您的答案,我继续为您编辑。现在它在技术上是正确的并且(我希望)仍然像以前一样有用/可读。
猜你喜欢
  • 2016-01-06
  • 2016-04-04
  • 2013-07-28
  • 1970-01-01
  • 2014-09-02
  • 1970-01-01
  • 2015-03-12
  • 2014-02-20
  • 2013-09-06
相关资源
最近更新 更多