No estoy seguro de cuál es una buena línea de asunto para esta pregunta, pero aquí vamos ...x86_64: ¿Es posible "en línea sustituir" referencias PLT/GOT?
Para forzar el código localidad/compacidad para una sección crítica de código, estoy buscando un camino llamar a una función en una biblioteca externa (cargada dinámicamente) a través de un "salto de ranura" (una reubicación ELF R_X86_64_JUMP_SLOT
) directamente en el sitio de la llamada - lo que el enlazador normalmente pone en PLT/GOT, pero tiene estos en línea en el sitio de llamada .
Si imitara a la llamada como:
#include <stdio.h>
int main(int argc, char **argv)
{
asm ("push $1f\n\t"
"jmp *0f\n\t"
"0: .quad %P0\n"
"1:\n\t"
: : "i"(printf), "D"("Hello, World!\n"));
return 0;
}
para obtener el espacio para una palabra de 64 bits, la llamada en sí funciona (por favor, no hay comentarios acerca de este ser coincidencia afortunada ya que esto rompe ciertas reglas ABI - todos estos no son objeto de este pregunta ... y puede, en mi caso, solucionarse/abordarse de otras maneras, intento mantener este ejemplo breve).
Crea el siguiente montaje:
0000000000000000 <main>: 0: bf 00 00 00 00 mov $0x0,%edi 1: R_X86_64_32 .rodata.str1.1 5: 68 00 00 00 00 pushq $0x0 6: R_X86_64_32 .text+0x19 a: ff 24 25 00 00 00 00 jmpq *0x0 d: R_X86_64_32S .text+0x11 ... 11: R_X86_64_64 printf 19: 31 c0 xor %eax,%eax 1b: c3 retqPero (debido al uso de
printf
como lo inmediato, supongo ...?) La dirección de destino aquí sigue siendo el de gancho PLT - el mismo
R_X86_64_64
reubicación. Vincular el archivo de objeto con libc a un ejecutable real da como resultado:
0000000000400428 <[email protected]>: 400428: ff 25 92 04 10 00 jmpq *1049746(%rip) # 5008c0 <_GLOBAL_OFFSET_TABLE_+0x20> [ ... ] 0000000000400500 <main>: 400500: bf 0c 06 40 00 mov $0x40060c,%edi 400505: 68 19 05 40 00 pushq $0x400519 40050a: ff 24 25 11 05 40 00 jmpq *0x400511 400511: [ .quad 400428 ] 400519: 31 c0 xorl %eax, %eax 40051b: c3 retq [ ... ] DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE [ ... ] 00000000005008c0 R_X86_64_JUMP_SLOT printf, es decir, esto todavía da la redirección en dos pasos, la primera ejecución de transferencia al gancho PLT, luego salta al punto de entrada de la biblioteca.
¿Hay alguna manera de cómo puedo ordenar al compilador/ensamblador/vinculador que, en este ejemplo, "en línea" el destino de la ranura de salto en la dirección 0x400511
? Es decir. reemplace el "local" (resuelto en el tiempo del enlace del programa por ld
) R_X86_64_64
reloc con el "control remoto" (resuelto en el tiempo de carga del programa por ld.so
) R_X86_64_JUMP_SLOT
uno (y fuerza la carga no lenta para esta sección de código)? Tal vez los archivos de mapas del enlazador podrían hacer esto posible, de ser así, ¿cómo?
Editar:
Para aclarar esto, la pregunta es acerca de cómo lograr esto en un ejecutable enlazado dinámicamente/a una función externa que sólo está disponible en una biblioteca dinámica. Sí, es cierto vinculación estática resuelve esto de una manera más simple, pero:
- existen sistemas (como Solaris) donde las bibliotecas estáticas generalmente no se envían por el vendedor
- hay bibliotecas que no están disponibles como o bien el código fuente o versiones estáticas
vinculación estática Por lo tanto no es útil aquí :(
Edit2:
he encontrado que en algunas arquitecturas (SPARC, notablemente, vea section on SPARC relocations in the GNU as manual), GNU puede crear ciertos tipos de referencias de reubicación para el enlazador in situ usando modificadores. El SPARC uno citado utilizaría %gdop(symbolname)
para hacer que el ensamblador emita instrucciones al enlazador indicando "crear esa reubicación aquí mismo". El ensamblador de Intel en Itanium conoce el @fptr(symbol)
link-relocation operator para el mismo tipo de cosas (ver también la sección 4 en el Itanium psABI). Pero ¿existe un mecanismo equivalente -algo para instruir al ensamblador que emita un tipo de reubicación de vinculador específico en una posición específica en el código- para x86_64?
También he encontrado que el ensamblador de GNU tiene una directiva .reloc
que supuestamente debe ser utilizada para este propósito; Sin embargo, si lo intento:
#include <stdio.h>
int main(int argc, char **argv)
{
asm ("push %%rax\n\t"
"lea 1f(%%rip), %%rax\n\t"
"xchg %%rax, (%rsp)\n\t"
"jmp *0f\n\t"
".reloc 0f, R_X86_64_JUMP_SLOT, printf\n\t"
"0: .quad 0\n"
"1:\n\t"
: : "D"("Hello, World!\n"));
return 0;
}
consigo un error del enlazador (nótese que 7 == R_X86_64_JUMP_SLOT
):
error: /tmp/cc6BUEZh.o: unexpected reloc 7 in object fileEl ensamblador crea un archivo de objeto para el que
readelf
dice:
Relocation section '.rela.text.startup' at offset 0x5e8 contains 2 entries: Offset Info Type Symbol's Value Symbol's Name + Addend 0000000000000001 000000050000000a R_X86_64_32 0000000000000000 .rodata.str1.1 + 0 0000000000000017 0000000b00000007 R_X86_64_JUMP_SLOT 0000000000000000 printf + 0Esto es lo que quiero - pero el enlazador no lo toma
El vinculador hace acepta simplemente usar
R_X86_64_64
en su lugar arriba; Hacer eso crea el mismo tipo de binario que en el primer caso ... redireccionando a
[email protected]
no al "resuelto" ...
¿qué tal prelinking? http://en.wikipedia.org/wiki/Prelink – JohnTortugo
Ver también: [tratando de evitar indirectamente PLT para llamadas * dentro de * una sola biblioteca compartida] (http://stackoverflow.com/questions/36354247/how-do- i-force-gcc-to-call-a-function-directamente-en-pic-code). –