2011-02-22 23 views
10

acabo de aprender acerca de los punteros de función (punteros apuntando a la dirección en la que se almacena el código de máquina de una función). Esto me hizo pensar en el código de máquina y cómo se almacena en la memoria.incrementar los punteros de función

¿El código de la máquina está almacenado consecutivamente en la memoria, por lo que es posible "manualmente" aumentar el puntero hasta que apunte a la siguiente función/anterior?

¿Esto es lo que hace un depurador? ¿Me permite "ver" hacia dónde apunta el contador del programa en el código de máquina?

Conclusión: uno puede programar con punteros a funciones un depurador primitivo?

¿Comprendo esto bien o estoy lejos?

Respuesta

3

tipo de. Está asumiendo que las funciones se presentarán en la memoria de la misma manera que están en el código fuente. Lo más probable es que no lo sean; el compilador generalmente los mueve de todas las maneras.

Lo que podría hacer, sin embargo, es recorrer el código con un puntero a la instrucción actual, e incrementar ese contador en una cierta cantidad para llegar a la siguiente instrucción. Sin embargo, en ese caso ya no lo llamaría un puntero de función , ya que no es simplemente señalando el comienzo de una función; en cambio, lo llamaríamos instruction pointer.

De hecho, esto es exactamente cómo funciona un ordenador - que tiene una especial register llamado el program counter que siempre apunta a la instrucción actual, y lo incrementa en una cierta cantidad después de cada instrucción (un comando GOTO es equivalente a la escritura un valor en el contador del programa).

En el mundo real, sin embargo, esto no es how debuggers work-de hecho, ni siquiera estoy seguro de si es posible tener un punto puntero al código de segmentos en la memoria en C, que no sea un puntero de función . Lo más probable es que solo necesite usar esta técnica si necesita simular un contador de programa, como escribir un emulador para otro tipo de procesador.

2
  1. El código de la máquina se puede almacenar de forma no consecutiva. El compilador se siente libre de dividir o fusionar algunas funciones (en optimización)
  2. Si aumenta manualmente un puntero para funcionar, probablemente se encontrará en medio de la función, lo que es incorrecto.
  3. Las rutinas de depuración ya están disponibles: puede obtener rastros de pila del punto de ejecución actual y resolver nombres de funciones donde los punteros de ejecución de la pila pertenecen (man backtrace, man backtrace_symbols). Con addr2line se puede convertir a los números de línea.
1

No hay garantía de dónde las funciones individuales van a estar en la memoria.

Una función en sí será un bloque continuo de memoria (ya que la CPU ejecuta las instrucciones secuencialmente), pero si habilita la optimización del código, puede no parecerse a la función en sí (las instrucciones pueden reordenarse mucho). Incluso podría tomar prestado el código de limpieza de una función diferente.

Puede escribir un depurador primitivo, pero no será trivial averiguar dónde termina una función.

5

Puede (o al menos podría) hacer algo como esto, pero es decididamente no trivial. En primer lugar, no se puede en realidad aumentar o disminuir un puntero de función - que apunta a una dirección, pero las matemáticas puntero se realiza normalmente en incrementos de sizeof(pointed to type) - pero con una función, que no es significativo, por lo que puede' Hago matemáticas en eso.

La mayoría de los depuradores de trabajo (principalmente) mediante el uso de la información de depuración que se refiere dirección a la línea de números, nombres de función, nombres de variables, etc.

7

Utilizando un borrador del estándar C que he logrado rastrear (N1124), tenemos reglas similares. La sección sobre expresiones de adición (§ 6.5.6/2) dice que

Para la adición, ya sea ambos operandos tendrán tipo aritmético, o un operando deberán ser un puntero a un tipo de objeto

y un tipo de objeto se define en § 6.2.5/1 como

el significado de un valor almacenado en un objeto o devuelto por una función está determinada por el tipo de la expresión utilizada para acceder a ella. (Un identificador declarado como objeto es la expresión más simple, el tipo se especifica en la declaración del identificador). Los tipos se dividen en tipos de objetos (tipos que describen completamente los objetos), tipos de función (tipos que describen funciones) y tipos incompletos (tipos que describen objetos pero carecen de la información necesaria para determinar sus tamaños).

Dado que los tipos de funciones son distintos de los tipos de objeto, esto sugiere que la aritmética del puntero en los punteros de función está prohibida.

En C++, esta operación es ilegal. La definición de la adición de puntero, dados en § 5,7/1, dice lo siguiente:

Para la adición, ya sea ambos operandos tendrán aritmética o tipo de enumeración, o un operando deberán ser un puntero a un tipo de objeto definido completamente y el otro tendrá un tipo integral o de enumeración.

Sin embargo, § 3,9/9 estados que

un tipo de objeto es una (posiblemente cv-cualificada) tipo que es no una función de tipo, no un tipo de referencia, y no un vacío tipo.

En conjunto, esto significa que no puede incrementar un puntero de función en C++.

Espero que esto ayude!

+0

Creo que a esta respuesta le falta el punto: esta era una pregunta conceptual, no una * "¿es posible incrementar los punteros de función en C?" * Pregunta.Simplemente usa mal el término * puntero-función * para referirse a cualquier puntero que apunta al segmento de código. –

+0

@BlueRaja: El título de la pregunta es exactamente eso, y creo que valió la pena trabajar. –

Cuestiones relacionadas