2009-06-03 16 views
10

He escrito un programa "peligroso" en C++ que salta de un marco de pila a otro. El objetivo es pasar del nivel más bajo de la pila de llamadas a la persona que llama, hacer algo y luego volver a saltar hacia abajo, omitiendo todas las llamadas entremedio.¿Qué hace el registro PIC (% ebx)?

Lo hago cambiando manualmente la dirección base de la pila (configuración %ebp) y saltando a una dirección de etiqueta. Funciona totalmente, con gcc e icc ambos, sin ningún tipo de corrupción en la pila. El día en que esto funcionó fue un día genial.

Ahora tomo el mismo programa y lo vuelvo a escribir en C, y no funciona. Específicamente, no funciona con gcc v4.0.1 (Mac OS). Una vez que salto al nuevo marco de la pila (con el puntero de la base de la pila establecido correctamente), se ejecutan las siguientes instrucciones, justo antes de una llamada al fprintf. La última instrucción que aparece aquí se estrella, eliminación de referencias a NULL:

lea 0x18b8(%ebx), %eax 
mov (%eax), %eax 
mov (%eax), %eax 

He hecho algunas depuración, y he descubierto que al establecer el registro %ebx manualmente cuando cambio de marcos de pila (usando un valor observé antes de salir la función en primer lugar), soluciono el error. He leído que este registro trata sobre el "código independiente de posición" en gcc.

¿Qué es el código de posición independiente? ¿Cómo funciona el código de posición independiente? ¿A qué apunta este registro?

+0

Puede considerar setjmp/longjmp para obtener esta funcionalidad sin necesidad de eliminar% ebx directamente. –

+2

En general, sí, tienes razón. En este caso, necesito poder saltar a la persona que llama, ejecutar alguna otra función y luego volver a bajar al destinatario. Con setjmp/longjmp, la otra función sobrescribirá la pila del llamado. –

Respuesta

6

PIC es un código que se reubica dinámicamente cuando se carga. El código que no es PIC tiene direcciones de salto y llamada establecidas en el tiempo del enlace. PIC tiene una tabla que hace referencia a todos los lugares donde existen tales valores, al igual que un .dll.

Cuando se carga la imagen, el cargador actualizará dinámicamente esos valores. Otros esquemas hacen referencia a un valor de datos que define una "base" y la dirección de destino se decide realizando cálculos en la base. La base generalmente la establece el cargador de nuevo.

Finalmente, otros esquemas utilizan varios trampolines que llaman a compensaciones relativas conocidas. Los desplazamientos relativos contienen código y/o datos que son actualizados por un cargador.

Existen diferentes motivos por los que se eligen diferentes esquemas. Algunos son rápidos cuando se corren, pero tardan en cargarse. Algunos son rápidos de cargar, pero tienen menos rendimiento en el tiempo de ejecución.

13

EBX apunta a la tabla de compensación global. Ver this reference about PIC on i386. El enlace explica qué PIC es como se usa EBX.

+0

GOT - Tabla de compensación global. –

+0

Eso fue un buen recurso; vale la pena la lectura. –