2011-02-25 6 views
9

Tengo que portar el código fuente desde una plataforma ARM que ejecuta Linux. Lamentablemente me he topado con problemas de acceso a memoria no alineados. La fuente utiliza moldes de puntero y acceso en gran medida.Solución de acceso de memoria no alineada ARM

El código como el siguiente se ha extendido por la base de código como un virus. Puedo identificar las ubicaciones problemáticas gracias a la opción de línea de comandos gcc -Wcast-align, pero hay más de mil instancias por recorrer.

u = (IEC_BOOL); 
(((*(IEC_LINT*)pSP).H < b.H) 
    || (((*(IEC_LINT*)pSP).H == b.H) && ((*(IEC_LINT*)pSP).L < b.L))) ? 1 : 0); 
*(IEC_DWORD OS_SPTR *)pSP = 
    (IEC_DWORD)(*(IEC_DWORD OS_SPTR *)pSP >> u); 
*(IEC_DWORD OS_SPTR *)pSP = 
    (IEC_DWORD)(*(IEC_DWORD OS_SPTR *)pSP << -u); 
u = (IEC_BYTE)((*(IEC_DINT*)pSP != b) ? 1 : 0); 
*(IEC_DWORD*)pSP = (IEC_DWORD)(*(IEC_DWORD*)pSP & w); 
(*(IEC_ULINT*)pSP).H += u.H; 
(((*(IEC_ULINT OS_SPTR *)pSP).H == b.H) 
    && ((*(IEC_ULINT OS_SPTR *)pSP).L > b.L))) ? 1 : 0); 
u = (IEC_BYTE)((*(IEC_REAL*)pSP >= b) ? 1 : 0); 

Usando echo 2 > /proc/cpu/alignment en el Kernel de Linux hace que arreglar los problemas, pero el rendimiento de la aplicación se degrada a un punto que no es aceptable más.

Busqué en la red algo así como una palabra clave __unaligned o __packed para el compilador GCC (v4.4.1), pero aún estaba vacía.

Pensé que muchas de las líneas de código poblemáticas se podían arreglar con una expresión regular/reemplazo más o menos compleja, pero ahora, después de hacer eso por un tiempo, veo que también este enfoque tomará enormes cantidades de trabajo tedioso.

¿Tienen alguna sugerencia de cómo hacer este trabajo? Creo que un plugin de compilador de gcc 4.5 sería exagerado, pero ¿hay algo mejor que las expresiones regulares? ¿Qué otras sugerencias puedes proponer? No necesariamente todas las instancias problemáticas deben ser reparadas, ya que aún puedo confiar en Kernel para algunos casos más raros.

+11

Tengo la tentación de bromear con que esto se debe mover a TheDailyWTF.com. – Crashworks

+2

Continuando con nuestro estudio de la lingüística moderna, aquí tenemos una muestra del dialecto de C comúnmente utilizado por los programadores embebidos. Aproximadamente traducido al inglés, el texto de arriba significa "F *** YOU!", Aunque ningún lenguaje natural puede transmitir la cantidad de rencor, desafío contra todo lo que es sagrado y desprecio general por la humanidad del lector transmitida aquí. – Dmitri

Respuesta

7

Hay __attribute__((__packed__)) que pueden ser útiles en algunos casos, pero realmente creo que este código debe limpiarse más temprano que tarde, porque es probable que pases más tiempo solucionando problemas de lo que tardarías en arreglarlo una vez y para todos.

+1

Creo que esta es una solución viable, pero quien haya escrito el código en primer lugar debe ser despedido. Por cierto, el código probablemente también necesite '-fno-strict-aliasing' o' __attribute __ ((may_alias)) 'en todos estos punteros si es que está roto ... –

+0

No ayudará al caso IEC_DWORD * porque eso es básicamente una typedef uint32_t, tipo POD. En el momento en que se lanza un puntero a esto, se deduce que tiene una alineación de 4 bytes. Cuando el código está roto, es tentador escribir un emulador para el objetivo que funciona :) –

+0

El atributo '__ ((__ packed __))' ya se ha utilizado para los miembros de la estructura, pero dado que el código se convierte en tipos POD en lugar de las estructuras esto es inútil Pero intentaré con un programa de prueba para ver si puedo usar esto. – trenki

0

Podemos suponer que el problema proviene del hecho de que ARM es una máquina de 32 bits y la caja de Linux se ejecuta en modo de 64 bits; alternativamente, el código podría suponer que se está ejecutando en una máquina de 16 bits.

Una forma sería mirar la estructura subyacente a la que se accede. Los miembros "H" y "L" pueden ser tipos de 32 bits a los que se accede como si fueran de 64 bits.

Intente modificar los tipos de L y H para que el código se comporte mejor.

(Es cierto, esta es una puñalada en el aire, como el fragmento de código no revela los detalles de la aplicación, ni de las estructuras subyacentes.)

2

Vaya, eso es un lío profano. Jugar con el compilador no lo llevará a ninguna parte. El código es ilegal en TODAS las arquitecturas, pero sucede que funciona en algunos (por ejemplo, x86). Yo arreglaría el código en sí.

Lamentablemente, no hay una forma bonita de hacerlo. Sin embargo, puede recorrer un largo camino con una larga lista de búsqueda y reemplazo, luego arreglar manualmente el resto. Comenzaría eliminando las declaraciones de esos tipos de datos, por lo que si compila cualquier código que haya omitido, se producirá un error. Luego, busque y reemplace fragmentos como "* (IEC_DWORD OS_SPTR *) pSP =" con "set_dword (pSP,". Realice una función en línea "set_dword" para hacer lo correcto. reemplazos fáciles de reemplazar como se puede imaginar. Todavía habrá una gran cantidad para arreglar a mano.

La única otra manera que puedo pensar de hacer esto sería un complemento de compilación, como usted sugiere, y hacer que todos los punteros toda la unidad de compilación tiene alineación 1.El compilador luego cargará/almacenará todo. Probablemente termine haciendo eso por algo más que el código que pretendía. Esto probablemente no es tan fácil de lograr como suena.

Cuestiones relacionadas