2009-06-30 12 views
15

Compilación de un módulo del núcleo de 32 bits produce un núcleo de Linux en__udivdi3 undefined: cómo encontrar el código que lo usa?

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

Todo está bien en sistemas de 64 bits. Hasta donde yo sé, la razón para esto es que la división de enteros de 64 bits y el módulo no son compatibles dentro de un kernel 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 verificar fácilmente si un "/" 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 alguna otra buena manera de buscar las referencias? ¿Algún tipo de "grep de código de máquina"?

El módulo consta de unas mil líneas de código. Realmente no puedo verificar cada línea manualmente.

Respuesta

19

En primer lugar, puede hacer la división de 64 bits utilizando la macro do_div. (Tenga en cuenta el prototipo es uint32_t do_div(uint64_t dividend, uint32_t divisor) y que "dividend" pueden ser evaluados 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, debe ser capaz de encontrar ya sea el uso de long long int (o uint64_t) tipos en el código, o, alternativamente, puede construir su módulo con la bandera -g y utilizar objdump -S conseguir un desmontaje anotada fuente

nota:. uso de esto se aplica a los núcleos 2.6, no he comprobado para nada menor

+9

para agregar un poco de información, do_div() se define en el encabezado . –

+1

Parece bastante ridículo que Linux insista en hacer que use una función fea para dividir, en lugar de simplemente implementar '__udivdi3', etc. Son fáciles de implementar, y si lo hace en asm, serán mucho más eficientes que las versiones de libgcc (quizás 2-3 veces más rápido). –

+0

@WilliBallenthin, incluso después de usar , enfrentan este problema. ¿Alguien me sugiere lo que hay que hacer para resolver este problema? –

2

Después de la etapa de compilación, debería poder conseguir un ensamblaje documentado, y ver cómo se llama a esas funciones. Intenta meterse con CFLAGS y agrega las banderas -S. La compilación debe detenerse en la etapa de montaje. A continuación, puede grep para la llamada a la función ofensiva en el archivo de ensamblaje.

1

En realidad, la división entera de 64 bits y el módulo 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 núcleo, ya que recientemente se crearon mejores IIRC). Las macros harán lo correcto de la manera más eficiente para cualquier arquitectura para la que esté compilando.

La manera más fácil de encontrar dónde se utilizan es (como se menciona en la respuesta de @ shodanex) para generar el código de ensamblado; IIRC, la forma de hacerlo es algo así como make directory/module.s (junto con los parámetros que ya tiene que pasar a make). La siguiente forma más fácil es desensamblar el archivo .o (con algo así como objdump --disassemble). Ambas formas le darán las funciones en las que se generan las llamadas (y, si sabe cómo leer el ensamblaje, una idea general de en qué parte de la función está teniendo lugar la división).

Cuestiones relacionadas