В чем разница между R_386_PC32 и R_X86_64_PC32 в процессе перемещения ссылки (GNU ld)
При чтении книги "Компьютерная система: перспектива программиста", раздел 7.7.1 Записи перемещения: краткое содержание этого раздела - как компоновщик перемещает ссылку в другом объектном файле.
Когда компилировать и objdump пример исходного кода:
void swap();
int buf[2] = {1, 2};
int main()
{
swap();
return 0;
}
Затем gcc -Wall -c -o main.o main.c и objdump -S -r main.o > main.asm; и увидит запись перемещения для свопа:
6: e8 fc ff ff ff call 7 <main+0x7> swap();
7: R_386_PC32 swap relocation entry
Поэтому, когда ld связывает main.o и swap.o, ld будет использовать запись перемещения r из swap(offset=7, type=R_386_PC32) для определения адреса ссылки:
refaddr = ADDR(section .text) + r.offset
*refptr = (unsigned)(ADDR(r.symbol + *refptr - refptr)
И операнд инструкции вызова (fc ff ff ff) -4 идеально подходит для набора 386 команд.
Но когда я повторяю это в Linux X86_64, я обнаружил, что код для вызова:
9: e8 00 00 00 00 callq e <main+0xe>
a: R_X86_64_PC32 swap relocation entry
Тогда Мой вопрос заключается в том, почему операнд вызова (e8) в 386 равен -4((fc ff ff ff), но операнд в X86_64 main.o равен 00 00 00 00? Это из-за другого набора команд (вызов против. callq), или просто GNU ld использует другой алгоритм для перемещения R_X86_64_PC32?
Надеюсь на вас ответят, большое спасибо.
1 ответ
Значение не имеет значения, оно будет перезаписано во время процесса перемещения. По-видимому, для i386 компилятор по умолчанию указывает на саму запись перемещения, а для x86-64 он указывает на следующую инструкцию. В любом случае это просто фиктивная ценность.