В чем разница между R_386_PC32 и R_X86_64_PC32 в процессе перемещения (GNU ld) - PullRequest
1 голос
/ 03 декабря 2011

При чтении книги «Компьютерная система. Перспектива программиста», раздел 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 (смещение = 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? Это из-за различного набора команд (call vs. callq), или просто GNU ld использует другой алгоритм для перемещения R_X86_64_PC32?

Надеюсь, что вы ответите, большое спасибо.

1 Ответ

0 голосов
/ 03 декабря 2011

Значение не имеет значения, оно будет перезаписано во время процесса перемещения. По-видимому, для i386 компилятор по умолчанию указывает на саму запись перемещения, а для x86-64 он указывает на следующую инструкцию. В любом случае, это просто фиктивное значение.

...