Es una manera de conseguir fixups de código (ajuste de direcciones en función de dónde se encuentra el código en la memoria virtual) sin tener que mantener una copia independiente del código para cada proceso. El PLT es la tabla de vinculación de procedimientos, una de las estructuras que hace que la carga dinámica y los enlaces sean más fáciles de usar.
[email protected]
es en realidad un pequeño trozo que (finalmente) llama a la función real printf
.
Esta función real se puede mapear en cualquier ubicación en un proceso determinado (espacio de direcciones virtuales) como el código que lo llama.
Por lo tanto, con el fin de permitir el intercambio de código apropiado del código de llamada (a la izquierda abajo), que no desea aplicar ningún fixups directamente a ella desde que restringirá donde puede ser localizado en otros procesos.
El PLT
es una pequeña proceso específico área en una dirección fiable calculada en tiempo de ejecución, que no es compartida entre los procesos por lo que cualquier proceso dado puede cambiarlo sin embargo que quiere.
En otras palabras, examinar el siguiente diagrama que muestra tanto su código y el código de la biblioteca asignada a diferentes direcciones virtuales en dos procesos:
Mapped to: 0x1234 0x9000 0x8888
+-----------------+ +----------+ +----------+
| | | Private | | |
ProcA | | | PLT/GOT | | |
| | | area | | |
| Shared | +----------+ | Shared |
========| application |==============| library |==
| code | +----------+ | code |
| | | Private | | |
ProcB | | | PLT/GOT | | |
| | | area | | |
+-----------------+ +----------+ +----------+
Mapped to: 0x2020 0x9000 0x6666
Este ejemplo particular muestra un caso sencillo donde los mapas PLT a una ubicación fija. En su escenario, que está situado en relación con el contador de programa actual como se evidencia por su programa de búsqueda de venta libre-relativa:
<[email protected]+0>: jmpq *0x2004c2(%rip) ; 0x600860 <_GOT_+24>
Un buen artículo se puede encontrar here, que detalla cómo glibc
se carga en tiempo de ejecución.
Básicamente, la forma original en que se creó el código compartido significaba que tenían que cargarse en la misma ubicación de memoria en el espacio de direcciones virtuales de cada proceso que lo usaba. O eso o no se pudo compartir, ya que el acto de arreglar la sola copia compartida de para un proceso podría llenar por completo otro proceso donde se asignó a una ubicación diferente.
Mediante el uso de código independiente de posición, junto con el PLT y una tabla de desplazamiento mundial (GOT), el primera llamada a una función [email protected]
(en el PLT) es una operación de varias etapas, en las que:
- llama al
[email protected]
en el PLT.
- llama a la versión GOT (a través del puntero) que inicialmente indica algún código de configuración en el PLT.
- Este código de configuración carga la biblioteca compartida pertinente si aún no se ha realizado, entonces modifica GOT para que las llamadas posteriores se realicen directamente al
printf
real en lugar del código de configuración.
en llamadas posteriores, debido a que el GOT se ha modificado, el enfoque de múltiples etapas se simplifica:
- se llama
[email protected]
en el PLT.
- llama a la versión GOT (a través del puntero) que apunta al real
printf
.
¿De dónde vino esa primera línea de salida? 'objdump' Imagino? –