¿Cuál es la diferencia entre R_386_PC32 y R_X86_64_PC32 en el proceso de reubicación del enlace (GNU LD)
-
27-10-2019 - |
Pregunta
Al leer el sistema informático del libro: la perspectiva de un programador Sección 7.7.1 Entradas de reubicación: el contenido breve de esta sección es cómo un enlazador reubica la referencia en un archivo de objeto diferente.
Cuando compile y objdump el código fuente de ejemplo:
void swap();
int buf[2] = {1, 2};
int main()
{
swap();
return 0;
}
Luego gcc -wall -c -o main.o main.c, y objdump -s -r main.o> main.asm; y verá la entrada de reubicación para intercambiar:
6: e8 fc ff ff ff call 7 <main+0x7> swap();
7: R_386_PC32 swap relocation entry
Entonces, cuando LD enlace el main.o y swap.o, el LD usará la entrada de reubicación r de swap (offset = 7, type = r_386_pc32) para determinar la dirección del enlace:
refaddr = ADDR(section .text) + r.offset
*refptr = (unsigned)(ADDR(r.symbol + *refptr - refptr)
Y el operando de la instrucción de llamadas (FC FF FF) -4 es perfectamente adecuada para 386 Conjunto de instrucciones.
Pero cuando repito esto en un Linux x86_64, encontré que el código para la llamada es:
9: e8 00 00 00 00 callq e <main+0xe>
a: R_X86_64_PC32 swap relocation entry
Entonces, mi pregunta es por qué el operando de llamada (E8) en 386 es -4 ((fc ff ff ff), pero el operando en x86_64 main.o es 00 00 00 00? ¿Es por el conjunto de instrucciones de diferentes instrucciones (llame vs . Callq), o simplemente el GNU LD usa un algoritmo diferente para la reubicación R_X86_64_PC32?
Espero que responda, muchas gracias.
Solución
El valor no importa, se sobrescribirá durante el proceso de reubicación. Aparentemente, para i386 el compilador predeterminado apunta a la entrada de reubicación en sí, mientras que para x86-64 apunta a la siguiente instrucción. De todos modos, es solo un valor ficticio.