Преобразовать литерал с плавающей точкой в ​​представление int в сборке x86? - PullRequest
0 голосов
/ 06 июня 2018

Следующий код C:

int main()
{
    float f;
    f = 3.0;
}

Преобразуется в следующие инструкции по сборке:

main:
  pushl %ebp
  movl %esp, %ebp
  subl $16, %esp
  flds .LC0
  fstps -4(%ebp)
  movl $0, %eax
  leave
  ret
.LC0:
  .long 1077936128

Как правильно рассчитать представление .long / intfloat литерал?

например, 1077936128, сгенерированный из 3.0 для примера, показанного выше


Для этого примера gcc используется с флагами -m32 -S -O0 -fno-stack-protector -fno-asynchronous-unwind-tables с использованием настроек Intel для генерации вывода сборки.

Ссылки :

Compiler Explorer Link с флагами компиляции и другими настройками

1 Ответ

0 голосов
/ 06 июня 2018

x86 аппаратное обеспечение FPU использует двоичные представления IEEE75432 / binary64 для float / double.

Определение представления IEEE 754 числа с плавающей запятой не является тривиальным для человека.В рукописном ассемблерном коде, как правило, лучше использовать вместо этого директивы .float или .double:

.float 3.0    # generates 3.0 as a 32 bit float
.double 3.0   # generates 3.0 as a 64 bit float

Если вы действительно хотите вычислить это вручную, см. объяснения в Википедии .Это может быть интересно сделать в качестве упражнения, но для реального программирования это утомительно и в основном бесполезно.

Компиляторы выполняют преобразование (с округлением до ближайшего представимого значения FP) внутри, потому что значения FP часто не делаютпрямо из буквального источника;они могут прийти от постоянного сворачивания.Например, 1.23 * 4.56 вычисляется во время компиляции, поэтому компилятор уже получает значения FP в формате с плавающей запятой или в двойном двоичном представлении.Вывод их обратно в десятичное число для ассемблера для анализа и повторного преобразования в двоичный файл будет медленнее и может потребовать много десятичных разрядов.


Чтобы вычислить представление 32-разрядного числа с плавающей запятой в виде 32-разрядногоцелое число, вы можете использовать онлайн-конвертер IEEE754 или программу, подобную этой:

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(int argc, char *argv[])
{
    union { uint32_t u32; float f32; } intfloat;

    if (argc != 2) {
        fprintf(stderr, "Usage: %s some-number\n", argv[0]);
        return EXIT_FAILURE;
    }

    intfloat.f32 = atof(argv[1]);

    printf("0x%08" PRIx32 "\n", intfloat.u32);

    return EXIT_SUCCESS;
}
...