在 X86 汇编中定义浮点数 - C 翻译

zev*_*val 0 c floating-point x86 assembly

目前正在学习C。例如,当我定义一个向量时,例如:

float var1[2023] = {-53.3125}
Run Code Online (Sandbox Code Playgroud)

相应的 X86 Assembly 翻译会是什么样的?我正在寻找定义变量的确切代码部分,其中提到了“.type”和“.size”以及对齐值。

我在互联网上看到,在处理浮点数时,X86 程序集转换只会是“.long”。但是,我不确定哪一点是正确的。

Ste*_*edl 5

找出答案的一种简单方法是让编译器向您展示:

// float.c
float var1[2023] = { -53.3125 };
Run Code Online (Sandbox Code Playgroud)

然后编译它:

$ gcc -S float.c
Run Code Online (Sandbox Code Playgroud)

然后研究输出:

        .file   "float.c"
        .globl  var1
        .data
        .align 32
        .type   var1, @object
        .size   var1, 8092
var1:
        .long   3260366848
        .zero   8088
        .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-39)"
        .section        .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)

请注意,这只是 GCC 的实现;clang 的做法不同:

        .file   "float.c"
        .type   var1,@object            # @var1
        .data
        .globl  var1
        .align  16
var1:   
        .long   3260366848              # float -5.331250e+01
        .long   0                       # float 0.000000e+00
        .long   0                       # float 0.000000e+00
        // thousands of these
        .size   var1, 8092

        .ident  "clang version 3.4.2 (tags/RELEASE_34/dot2-final)"
        .section        ".note.GNU-stack","",@progbits
Run Code Online (Sandbox Code Playgroud)

编辑- 为了回答下面的评论,使用long简单地规定了一个特定的位模式,该位模式对编译器的浮点格式思想进行编码。

该值3260366848与 hex 相同0xC2554000,都是11000010010101010100000000000000二进制的,它是 CPU 关心的二进制值。如果你愿意,你可以拿出你的 IEEE 浮点规范并解码它,有符号,那是指数等,但浮点编码的所有细节都是由编译器处理的,而不是汇编器。

我不是编译器专家,但几十年前我正在追踪 C 编译器的浮点支持中的错误,虽然我不记得细节,但在我的脑海里,它让我觉得编译器做了这会很有帮助,因为我不必使用反汇编程序来找出位模式实际编码的内容。

当然,其他人会在这里权衡。

EDIT2位是位,这个小 C 程序(依赖 sizeof int 和 sizeof float 的大小相同)演示了这一点:

// float.c
float var1[2023] = { -53.3125 };
Run Code Online (Sandbox Code Playgroud)

运行它显示位是位:

sizeof int = 4
sizeof flt = 4
float = -53.312500
i     = 0xc2554000
i     = 3260366848   <-- there ya go
Run Code Online (Sandbox Code Playgroud)

这只是 32 位的显示概念,具体取决于您如何看待它们。

现在要回答如何从浮点值中自己确定 3260366848 的问题,您需要根据 IEEE 标准手动提取所有位(推荐浓咖啡),然后将这 32 位读取为整数。

  • GNU 汇编器还可以为您计算二进制表示:只需编写“.float -53.312500”。我不知道是否有特殊原因编译器更喜欢自己做而不是留给汇编器。 (2认同)
  • @NateEldredge:可能是因为,在决定计算编译器中的表示时,汇编器要么没有用于记录浮点值的指令,要么不能保证正确舍入(或者以与编译器相同的方式舍入) )。或者因为在编译器中执行此操作将使将来更容易放入任意汇编器中,而该汇编器可能没有浮点数据指令。 (2认同)
  • 一些编译器可能有 #pragmas 来操作舍入模式之类的东西,这似乎并不是不可能的,并且这将由编译器以具体的方式强制执行,并使用仅位表示,否则需要传递浮点数-point 指令到汇编器? (2认同)
  • @Hasake:是的,手写时通常会使用 `.float` 并让汇编器将 `-53.312500` 转换为 FP 位模式,而不是使用 `.long`。但正如上面评论中所讨论的,编译器选择不这样做(因为他们已经知道位模式和/或其他原因)。 (2认同)
  • @Hasake:什么是“不真实”?`.float` 和 `.long` 是向输出文件发出 4 个字节的两种不同方式,仅此而已。如果您想让汇编器将十进制字符串转换为 IEEE 二进制 32 位模式(大概是舍入到最接近的值),请继续使用“.float”以获得更具可读性的源代码。两者都不是“更正确”,只是对未来的读者更人性化。CPU 对此一无所知;当您访问此静态存储时,您只需使用正确的指令(例如“movss”而不是“movsd”)。 (2认同)