programming pelicula app assembly

pelicula - assembly synonym



¿Qué significa @plt aquí? (2)

0x00000000004004b6 <main+30>: callq 0x400398 <printf@plt>

¿Alguien sabe?

ACTUALIZAR

¿Por qué dos disas printf me dan resultados diferentes?

(gdb) disas printf Dump of assembler code for function printf@plt: 0x0000000000400398 <printf@plt+0>: jmpq *0x2004c2(%rip) # 0x600860 <_GLOBAL_OFFSET_TABLE_+24> 0x000000000040039e <printf@plt+6>: pushq $0x0 0x00000000004003a3 <printf@plt+11>: jmpq 0x400388 (gdb) disas printf Dump of assembler code for function printf: 0x00000037aa44d360 <printf+0>: sub $0xd8,%rsp 0x00000037aa44d367 <printf+7>: mov %rdx,0x30(%rsp) 0x00000037aa44d36c <printf+12>: movzbl %al,%edx 0x00000037aa44d36f <printf+15>: mov %rsi,0x28(%rsp) 0x00000037aa44d374 <printf+20>: lea 0x0(,%rdx,4),%rax 0x00000037aa44d37c <printf+28>: lea 0x3f(%rip),%rdx # 0x37aa44d3c2 <printf+98>


Es una forma de obtener correcciones de código (ajustando direcciones en función de dónde se encuentra el código en la memoria virtual) sin tener que mantener una copia separada 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.

printf@plt es en realidad un pequeño trozo que (eventualmente) llama a la función printf real.

Esta función real puede asignarse a cualquier ubicación en un proceso determinado (espacio de direcciones virtuales) como lo puede hacer el código que lo llama.

Por lo tanto, para permitir el uso compartido de código correcto del código de llamada (lado izquierdo a continuación), no desea aplicar correcciones directamente ya que eso restringirá su ubicación en otros procesos.

El PLT es un área específica del proceso más pequeña en una dirección confiablemente calculada en tiempo de ejecución que no se comparte entre los procesos, por lo que cualquier proceso dado puede cambiarla como lo desee.

En otras palabras, examine el siguiente diagrama que muestra tanto el código como el código de la biblioteca asignados 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 simple en el que el PLT se asigna a una ubicación fija. En su escenario, está ubicado en relación con el contador del programa actual, como lo demuestra su búsqueda de contador de programa-pariente:

<printf@plt+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 copia compartida única para un proceso encapsularía por completo otro proceso donde se asignó a una ubicación diferente.

Al utilizar un código de posición independiente, junto con el PLT y una tabla de compensación global (GOT), la primera llamada a una función printf@plt (en el PLT) es una operación de varias etapas, en la cual:

  • llama a printf@plt en el PLT.
  • llama a la versión GOT (a través del puntero) que inicialmente apunta hacia algún código de configuración en el PLT.
  • este código de configuración carga la biblioteca compartida relevante si aún no se ha hecho, luego modifica el GOT para que las llamadas subsiguientes se realicen directamente en el printf real en lugar del código de configuración.

En llamadas posteriores, debido a que se ha modificado GOT, el enfoque de etapas múltiples se simplifica:

  • llama a printf@plt en el PLT.
  • llama a la versión GOT (vía puntero) que apunta al printf real .

No estoy seguro, pero probablemente lo que has visto tiene sentido. La primera vez que ejecuta el comando disas, aún no se llama a printf, por lo que no se resuelve. Una vez que su programa llama al método printf la primera vez que se actualiza el GOT y ahora se resuelve el printf y el GOT apunta a la función real. Por lo tanto, la siguiente llamada al comando disas muestra el ensamblaje printf real.