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

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

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

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

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

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

3 ответа

Решение

Во-первых, вы можете выполнить 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, я не проверял использование для чего-то более низкого

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

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

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

Другие вопросы по тегам