2012-02-01 12 views
6

He encontrado algo que completamente no entiendo. Hay un prototipo de función:Puntero de función con GCC, asignando una dirección

typedef void (* TMain) (void); 

y una variable de función:

TMain myFunc = MyFunc; 
... 
myFunc(); 

Esto funciona bien, por supuesto. ¿Por qué no debería?

Desde el MAP-archivo que he saben que "MyFunc" está en la localización 0x20100. Y ahora lo gracioso. Después de la asignación "myFunc = MyFunc;" la variable "myFunc" no contiene contiene el valor 0x20100, sino 0x20101!

Mi problema es que tengo que llamar a una función de la que sé que la dirección de una tabla. Así que pensé que podría hacerlo así

myFunc = (TMain) myTable [ 5 ]; // that would be 0x20100 
myFunc();       // which produces a proper crash 

Sin embargo Si hago

myFunc = (TMain) ((Int8 *) myTable [ 5 ] + 1); 
myFunc(); 

entonces funciona.

¿Qué sucede aquí? ¿Siempre tengo que agregar un desplazamiento de 1 o esto es más o menos accidental? ¿O existe una forma mejor (y funcional) para realizar la tarea?

Gracias mucho por cualquier indicio. Walter

+2

No estoy seguro, pero esto podría depender de la arquitectura. Por lo tanto, podría querer decir cuál es la arquitectura de destino. – phimuemue

+1

¿La matriz 'myTable' del tipo' TMain [] '? Supongo que no es así porque lo estás lanzando. –

+1

Algunas preguntas para usted: ¿Qué plataforma está usando (ARM, x86 ...)? ¿Alguna vez ha comprobado la dirección real de la función con un depurador? ¿Puedes ver cómo el compilador genera la llamada indirecta "myFunc()"? –

Respuesta

3

Varias arquitecturas de CPU reservan los primeros bytes de una función para fines específicos. VAXen tiene una máscara de guardar registro allí. CDC Cyber ​​pone la dirección de retorno allí. Algunos usan algunos bits de la "dirección" para indicar direccionamiento indirecto (por fuera no recuerdo cuáles, pero son de la década de 1970).

A menos que realmente sabe lo que está haciendo, no se debe escribir código que hace ese tipo de aritmética de punteros. Asigne a la variable el nombre de la función y finalícela: se garantiza que funciona en cada implementación de C.

3

Mi conjetura es que estás en un objetivo ARM y que se ha construido el programa en modo pulgar? (El pulgar es el predeterminado en ARM Ubuntu o Linaro).

El bit inferior de la dirección de una función indica a la CPU en qué instrucción se debe interpretar la función. 0 es el modo ARM. 1 es el modo Thumb. Por lo tanto, todos los punteros de función del modo Thumb serán impares.

Otras arquitecturas usan este idioma también, de una manera u otra. Por lo general, es seguro simplemente poner a cero los dos últimos bits de una dirección (por lo que es de 4 bytes alineados) y asumir que esa es la verdadera ubicación de la función.

Cuestiones relacionadas