Почему мой модуль ядра отлично выполняет деление с плавающей запятой?

Я пытаюсь использовать типы данных float и double внутри модуля ядра. Чтобы удовлетворить свое любопытство, я написал простой LKM. Вот,

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

static int __init hello_start(void)
{
        float x,y,z;
        x = 22.27;
        y = 7.25;
        z = x/y;                                                                

        unsigned int *u;
        u = (unsigned int *)&z;
        printk(KERN_INFO "0x%x\n", *u);

        return 0;
}

static void __exit hello_end(void)
{
        printk(KERN_INFO "Unload...\n");
}

module_init(hello_start);
module_exit(hello_end);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("XYZ");

Поскольку float будет хранить значение в памяти/регистре в формате IEEE754, поэтому я могу присвоить его 32-битным типам данных, таким как unsigned int. И внутри кода то же самое, что и я, и я получил идеальные значения HEX спецификации IEEE754. В этом случае 22,27/7,25 = 3,071724138 и 3,071724138 нормализуют значение IEEE754 в шестнадцатеричном формате 0x40449721. dmesg показывает мне 0x40449721 при загрузке модуля.

Итак, теперь вопросы,

1) Как увидеть разборку моего модуля ядра? поэтому я могу проверить для хранилища данных с плавающей запятой и подразделения, какая инструкция используется. (моя платформа x86_64).

2) Если я могу видеть идеальное шестнадцатеричное значение деления, то какова роль API, такого как kernel_fpu_begin()/kernel_fpu_end(), потому что без его использования я могу выполнять деление с плавающей запятой? разделение выполняется каким оборудованием? как насчет аппаратного FPU?

3) Это разделение выполняется инструкциями SSE2 или чем-то еще (поэтому мне и нужен сборочный файл LKM)


person Bhoomil Chavda    schedule 21.06.2018    source источник
comment
1) objdump -d .../foo.ko. Re: все остальное: это работает, но вы испортили состояние регистра XMM или x87 переключателя контекста пользовательского пространства.   -  person Peter Cordes    schedule 21.06.2018
comment
да! дублирование. но @Peter у меня был еще один вопрос по этому поводу. для x/y видов вещей, какая инструкция используется. Я сделал objdump -D моего файла .ko, и внутри этого нет инструкции типа divsd. какую группу обучения выполняет данное подразделение?   -  person Bhoomil Chavda    schedule 21.06.2018
comment
У вас есть только константы времени компиляции, поэтому, если вы не отключите оптимизацию, не сделаете x и y volatile или не сделаете что-то еще, чтобы предотвратить это, gcc выполнит распространение констант и эффективно превратит ваш код в float z=3.07172413793103448276f (т.е. просто поместите ближайший представимый бит с плавающей запятой шаблон в вашу программу без итераций divsd, divss, fdiv или rcpps + newton.) Оказывается, ваш пример не является дубликатом; на самом деле вы не используете математику FP, просто печатаете 32-битное целое число, поэтому ищите mov esi, 0x???? перед call printk.   -  person Peter Cordes    schedule 21.06.2018
comment
Также обратите внимание, что приведение указателей не является безопасным способом каламбура при включенном строгом псевдониме. Используйте memcpy или союз.   -  person Peter Cordes    schedule 21.06.2018
comment
спасибо за предоставление выше полезной информации. У меня есть еще одно сомнение, что внутри ядра linux src есть куча файлов, которые используют kernel_fpu_begin()/end(). Я заметил, что между этими двумя вызовами... вместо того, чтобы писать обычный код C, разработчик выбирает сборку. почему так?   -  person Bhoomil Chavda    schedule 22.06.2018
comment
потому что не стоит использовать kernel_fpu_begin/end, если вы не собираетесь использовать SIMD, а не только для некоторого расчета FP. Linux, вероятно, даже использует -mno-sse, чтобы запретить ему использовать векторы для копирования структур и так далее. (И gcc не будет использовать x87 сам по себе.)   -  person Peter Cordes    schedule 04.07.2018