__udivdi3 undefined - как найти код, который его использует?

Компиляция модуля ядра в 32-разрядном ядре Linux приводит к

"__udivdi3" [mymodule.ko] undefined!
"__umoddi3" [mymodule.ko] undefined!

Все в порядке на 64-битных системах. Насколько мне известно, причиной этого является то, что 64-битное целочисленное деление и модуль не поддерживаются внутри 32-разрядного ядра Linux.

Как я могу найти код, выдающий 64-битные операции. Их трудно найти вручную, потому что я не могу легко проверить, является ли "/" 32-битным или 64-битным. Если "нормальные" функции undefined, я могу их grep, но здесь это невозможно. Есть ли еще хороший способ поиска ссылок? Какой-то "машинный код grep"?

Модуль состоит из нескольких тысяч строк кода. Я действительно не могу проверить каждую строку вручную.

Ответы

Ответ 1

Во-первых, вы можете выполнить деление на 64 бит с помощью макроса do_div. (обратите внимание, что прототип uint32_t do_div(uint64_t dividend, uint32_t divisor) и что "dividend" может быть оценен несколько раз.

{
    unsigned long long int x = 6;
    unsigned long int y = 4;
    unsigned long int rem;

    rem = do_div(x, y);
    /* x now contains the result of x/y */
}

Кроме того, вы можете либо найти использование типов long long int (или uint64_t) в своем коде, либо поочередно вы можете создать свой модуль с помощью флага -g и использовать objdump -S, чтобы получить исходная аннотированная разборка.

Примечание: это относится к 2.6 ядрам, я не проверял использование для чего-либо более низкого

Ответ 2

После этапа компиляции вы сможете получить документальную сборку и посмотреть, вызываются ли эти функции. Попытайтесь возиться с CFLAGS и добавить флагов -S. Компиляция должна останавливаться на этапе сборки. Затем вы можете выполнить grep для вызова функции нарушения в файле сборки.

Ответ 3

Собственно, 64-битное целочисленное divison и modulo поддерживаются в 32-битном ядре Linux; однако для этого вы должны использовать правильные макросы (какие из них зависят от вашей версии ядра, так как в последнее время были созданы новые лучшие версии IIRC). Макросы сделают правильную вещь наиболее эффективным способом для любой архитектуры, которую вы компилируете.

Самый простой способ найти, где они используются (как упоминалось в ответе @shodanex) для генерации кода сборки; IIRC, способ сделать это - это что-то вроде make directory/module.s (вместе с любыми параметрами, которые вы уже должны передать на make). Следующий самый простой способ - дизассемблировать файл .o (с чем-то вроде objdump --disassemble). Оба способа предоставят вам функции, в которых генерируются вызовы (и, если вы знаете, как читать сборку, общее представление о том, где внутри функции происходит деление).