__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
). Оба способа предоставят вам функции, в которых генерируются вызовы (и, если вы знаете, как читать сборку, общее представление о том, где внутри функции происходит деление).