gpt4 book ai didi

assembly - 在汇编代码中查找循环或数字

转载 作者:行者123 更新时间:2023-12-03 06:34:16 25 4
gpt4 key购买 nike

我已将 C++ 代码转换为具有高优化级别的汇编代码

#include <iostream>
using namespace std;

int main()
{
float sum=0;
for(int i = 0; i < 10; i++)
sum += 1.0f/float(i+1);
cout<<sum<<endl;
return 0;
}

通过

g++ -O3 -S main.cpp
g++ -O3 main.cpp && ./a.out

结果是

2.92897

但是当我将它转换成汇编时,我不知道这个数字位于哪里。应该有一个循环或(如果展开)最终结果为 2.92897。但我在下面的代码中找不到它:

    .file   "main.cpp"
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB1561:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $_ZSt4cout, %edi
movsd .LC0(%rip), %xmm0
call _ZNSo9_M_insertIdEERSoT_
movq %rax, %rdi
call _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
xorl %eax, %eax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE1561:
.size main, .-main
.p2align 4,,15
.type _GLOBAL__sub_I_main, @function
_GLOBAL__sub_I_main:
.LFB2048:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $_ZStL8__ioinit, %edi
call _ZNSt8ios_base4InitC1Ev
movl $__dso_handle, %edx
movl $_ZStL8__ioinit, %esi
movl $_ZNSt8ios_base4InitD1Ev, %edi
addq $8, %rsp
.cfi_def_cfa_offset 8
jmp __cxa_atexit
.cfi_endproc
.LFE2048:
.size _GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main
.section .init_array,"aw"
.align 8
.quad _GLOBAL__sub_I_main
.local _ZStL8__ioinit
.comm _ZStL8__ioinit,1,1
.section .rodata.cst8,"aM",@progbits,8
.align 8
.LC0:
.long 0
.long 1074228871
.hidden __dso_handle
.ident "GCC: (Ubuntu 7.2.0-1ubuntu1~16.04) 7.2.0"
.section .note.GNU-stack,"",@progbits

我怀疑是.LC01074228871。但这样的转换是通过another code给我 2.11612,这是一个不同的数字。

那么,汇编代码中的计算或结果在哪里呢?

最佳答案

循环不只是展开,它还通过恒定传播完全优化掉。这就是为什么main除了 call 之外没有其他分支.

movsd .LC0(%rip), %xmm0 (MOV Scalar Double) 将 8 字节 FP arg 加载到 cout<<sum来自 .rodata 中的静态常量,就像大多数编译器处理 FP 常量的正常方式一样。

.LC0 ,我们发现:

.LC0:
.long 0
.long 1074228871

这些伪指令组装成 8 字节的数据。这是位模式的整数表示,表示 2.92897...IEE754 double-precision ( binary64 ) 。 x86 对于 FP 和整数来说都是小端字节序,因此 0前(低)4 个字节是有效数的底部(也称为尾数)。

https://www.h-schmidt.net/FloatConverter/IEEE754.html 有一个交互式单精度转换器,但我不知道 double您可以在其中插入位模式的整数值,然后将其解码为 double .

But such a conversion via another code gives me 2.11612 which is a different number.

您链接到的代码将位模式的上半部分类型双关为 float (违反了 C++ 指针别名规则,顺便说一句。使用 memcpy 进行类型双关)。 如果您选择1074228871ULL << 32,您就会得到正确的答案并将其双关为 double .


clang 在 FP 常量上添加 asm 注释以显示它们的十进制值,但 gcc 没有。例如来自Godbolt compiler explorer :clang5.0 -O3将循环优化为相同的常量,但在 asm 中的表示方式略有不同:

.LCPI0_0:
.quad 4613777869364002816 # double 2.9289684295654297
# exactly equivalent to what gcc emits,
# just different syntax for the same 8 bytes

它只是字节,十进制整数是 gcc 总是对编译器生成的 asm 中的所有常量所做的事情,尽管这对人类来说几乎毫无用处(甚至比十六进制更糟糕)。

我不确定 GAS 语法是否可以处理 FP 常量; NASM 确实如此。但正如我所说,这只是字节。

关于assembly - 在汇编代码中查找循环或数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48849225/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com