núcleo - __udivdi3 undefined-¿Cómo encontrar el código que lo usa?
linux kernel version (3)
Después de la etapa de compilación, debería poder obtener un ensamblado documentado y ver cómo se llaman esas funciones. Intenta meterte con CFLAGS y agrega las banderas -S. La compilación debe detenerse en la fase de montaje. A continuación, puede grep para la llamada a la función ofensiva en el archivo de ensamblaje.
Compilar un módulo del kernel en el kernel de Linux de 32 bits da como resultado
"__udivdi3" [mymodule.ko] undefined!
"__umoddi3" [mymodule.ko] undefined!
Todo está bien en sistemas de 64 bits. Hasta donde sé, la razón de esto es que la división de enteros de 64 bits y el módulo no son compatibles con un kernel de Linux de 32 bits.
¿Cómo puedo encontrar el código que emite las operaciones de 64 bits? Son difíciles de encontrar manualmente porque no puedo comprobar fácilmente si una "/" tiene 32 bits de ancho o 64 bits de ancho. Si las funciones "normales" no están definidas, puedo grep, pero esto no es posible aquí. ¿Hay otra buena manera de buscar las referencias? ¿Algún tipo de "código de máquina grep"?
El módulo consta de unas mil líneas de código. Realmente no puedo comprobar cada línea manualmente.
En realidad, las divisiones y módulos enteros de 64 bits son compatibles con un kernel de Linux de 32 bits; sin embargo, debe usar las macros correctas para hacerlo (cuáles dependen de la versión de su kernel, ya que recientemente se crearon nuevas mejores versiones IIRC). Las macros harán lo correcto de la manera más eficiente para cualquier arquitectura que esté compilando.
La forma más fácil de encontrar dónde se están utilizando es (como se menciona en la respuesta de @ shodanex) generar el código de ensamblaje; IIRC, la forma de hacerlo es algo parecido a make directory/module.s
(junto con cualquier parámetro que ya tenga que pasar para make
). La siguiente forma más fácil es desensamblar el archivo .o
(con algo como objdump --disassemble
). Ambas formas le darán las funciones donde se generan las llamadas (y, si sabe cómo leer el ensamblaje, una idea general de dónde se está llevando a cabo la división dentro de la función).
Primero, puedes hacer una división de 64 bits usando la macro do_div
. (tenga en cuenta que el prototipo es uint32_t do_div(uint64_t dividend, uint32_t divisor)
y que el " dividend
" puede evaluarse varias veces.
{
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 */
}
Además, debería poder encontrar el uso de tipos long long int
(o uint64_t
) en su código, o alternativamente, puede compilar su módulo con el indicador -g
y usar objdump -S
para obtener un desensamblaje anotado en la fuente.
nota: esto se aplica a 2.6 kernels, no he comprobado el uso para nada más bajo