【问题标题】:Definition floating-point numbers in X86 Assembly - C Translation在 X86 汇编中定义浮点数 - C 翻译
【发布时间】:2020-01-07 21:28:10
【问题描述】:

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

float var1[2023] = {-53.3125}

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

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

【问题讨论】:

    标签: c assembly x86 floating-point


    【解决方案1】:

    一个简单的方法是让编译器显示给你:

    // float.c
    float var1[2023] = { -53.3125 };
    

    然后编译它:

    $ gcc -S float.c
    

    然后研究输出:

            .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
    

    请注意,这只是 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
    

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

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

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

    肯定会有其他人在这里权衡。

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

    // float2.c
    #include <stdio.h>
    #include <memory.h>
    
    
    int main()
    {
        float f = -53.3125;
        unsigned int i;
    
        printf("sizeof int = %lu\n", sizeof(i));
        printf("sizeof flt = %lu\n", sizeof(f));
    
        memcpy(&i, &f, sizeof i); // copy float bits into an int
    
        printf("float = %f\n", f);
        printf("i     = 0x%08x\n", i);
        printf("i     = %u\n", i);
    
        return 0;
    }
    

    运行显示位就是位:

    sizeof int = 4
    sizeof flt = 4
    float = -53.312500
    i     = 0xc2554000
    i     = 3260366848   <-- there ya go
    

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

    现在要回答如何根据浮点值自行确定 3260366848 的问题,您需要拿出您的 IEEE 标准并手动提取所有位(推荐浓咖啡),然后阅读那些 32位为整数。

    【讨论】:

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