【问题标题】:Understanding/Writing C code for Assembly with single precision floating point numbers使用单精度浮点数理解/编写汇编的 C 代码
【发布时间】:2021-04-10 02:31:02
【问题描述】:

我无法破译这个给定的汇编代码:

1 unknown5:
2    pxor   %xmm0, %xmm0
3    movl   $0, %eax
4    jmp    .L13
5  .L14:
6    movss  (%rdx,%rax,4), %xmm1
7    mulss  (%rsi,%rax,4), %xmm1
8    addss  %xmm1, %xmm0
9    addq   $1, %rax
10 .L13:
11   cmpq   %rdi, %rax
12   jb .L14
13   rep ret

认为正在发生的事情:

  • 1:函数名为 unknown5()
  • 2:设置浮点返回寄存器为0
  • 3:设置32位返回寄存器为0
  • 4:跳转到 10:
  • 11:如果 %rdi > %rax,则转到 5:,否则转到 13:
  • 6: %xmm1 = %rdx+%rax+4
  • 7: %xmm1 *= %rsi+%rax+4
  • 8: %xmm0 += %xmm1
  • 9: %rax += 1
  • 13:返回 %eax、%rax 或 %xmm0??

我不知道函数的可能参数是什么,也不知道每个寄存器代表什么。我知道 %rdi、%rsi 和 %rdx 是第一个、第二个和第三个参数(由于单精度操作可能是浮点指针?),%xmm0、%xmm1 是第一个和第二个浮点参数(或本地变量?)。我也知道 %rax 是 64 位返回寄存器,但我不确定为什么在这里使用它。有人可以详细说明并纠正我的理解吗?谢谢。

【问题讨论】:

  • 程序集没有“局部变量”,您正在考虑“寄存器”。
  • 我知道,我应该澄清一下,我需要将上述程序集转换为 C,因此寄存器将表示函数参数或局部变量,具体取决于
  • 只要有一点经验,您就会认识到这是一个典型的while 循环。
  • 有趣的事实:这似乎是由gcc -O1 编译的(mov $0, %eax 而不是xor %eax,%eax,并且在第一次迭代时跳转到循环而不是提升第一次检查),与一些早于 GCC8 的 GCC 版本(rep ret 因为它的-mtune=generic 默认仍然关心 AMD K8/K10(例如 Phenom II 和更早版本))。也是实际的gcc,而不是g++,因为g++ -O1 / -O0 倾向于制作愚蠢的“while”循环,顶部有一个条件分支(Why are loops always compiled into "do...while" style (tail jump)?

标签: c assembly floating-point x86-64 reverse-engineering


【解决方案1】:

一些提示:

  • %xmm0, %xmm1 用于传递浮点参数,如果函数实际上需要任何参数。但是他们在进入函数时所拥有的值是否真的以任何方式使用过?

  • 不要认为%rax 天生就是“返回寄存器”。这只是一个寄存器。如果该函数旨在返回一个整数或指针,那么是的,%rax(或其子寄存器之一)是该返回值所在的位置,但同时它只是一个寄存器,代码可以随意使用,就像你说的一个局部变量。 %xmm0 也是如此。

  • 考虑到它们在movss/mulss 内存操作数中的使用方式,您对%rdx%rsi 作为指针的猜测是正确的。这些指令究竟是从哪里加载值的?另一方面,%rdi 不会出现在这样的上下文中;它是如何使用的?

    注意movss (%rdx,%rax,4), %xmm1 不会将%xmm1 设置为等于将%rax 乘以4 并加上%rdx 得到的值。相反,它使用%rdx+%rax*4 作为地址,从内存中的该地址获取单精度浮点数,并将其加载到%xmm1。这就是( ) 的含义——间接内存引用。如果您愿意,它大致相当于 C 中的一元 * 取消引用运算符。

    同样,在下面的mulss 中相乘的值也是从内存中获取的。

  • 仅凭代码无法确定它是打算返回int%eax 中的返回值)还是long (%rax) 或float/double (%xmm0)。但你可以做出一个很好的猜测。想想函数返回时每个寄存器的值。对于要为其调用者计算的函数的值,哪个似乎更合理?

    请注意,此函数中没有写入内存的指令,因此它没有“副作用”;它的唯一目的必须是计算并返回一些值。

  • 这个函数似乎在执行一个熟悉的数学运算。你能告诉它是什么吗?

【讨论】:

  • 1) 我感到困惑的是,它们不能也用于 C 代码中的局部变量(例如 float foo = 3.0;)吗?取决于大会如何利用寄存器是如何确定差异的? 2) 啊,这消除了 %rax 的很多困惑,谢谢! 3)所以 %rdi 可能是传入的整数,而其他可能是浮点指针?我完全迷失了他们可能从哪里加载他们的价值。 4)所以我猜它会返回 %xmm0 因为它们是单精度浮点数? 5)直到我弄清楚更多哈哈。
  • 当然,寄存器不过是保存一堆位的地方,CPU 可以从中对这些位执行各种操作。您是否将这些位视为表示函数参数,或局部变量的值,或计算中的某些中间值,或其他一些有用/无用的数据,完全取决于您自己的想象和调用约定。
  • @Pharros:啊,我想你对 6 和 7 感到困惑。movss (%rdx,%rax,4), %xmm1 不会将 %xmm1 设置为等于将 %rax 乘以 4 并加上 @987654347 得到的值@。相反,它使用%rdx+%rax*4 作为地址,从内存中的该地址获取一个单精度浮点数,并将其加载到%xmm1。这就是( ) 的含义——间接内存引用。如果您愿意,它大致相当于 C 中的一元 * 取消引用运算符。
猜你喜欢
  • 1970-01-01
  • 2015-02-24
  • 1970-01-01
  • 2018-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-21
  • 1970-01-01
相关资源
最近更新 更多