Как я могу вызвать printf обычно в сборке без @PLT, но просто вызвать printf с опцией -l в gcc со стандартной библиотекой, - PullRequest
0 голосов
/ 01 июня 2019

Я хочу вызвать printf в сборке и связать его, используя опцию gcc -l со стандартной библиотекой, но там написано:

  Symbol `printf' causes overflow in R_X86_64_PC32 relocation
  Segmentation fault (core dumped)

Вот как я компилирую:

   gcc mod.s -l:libc.so -o mod

когда я заменяю libc.so на libc.a, он по-прежнему показывает ошибку сегментации

 .file  "mod.c"
.text
.section    .rodata
.LC0: 
   .string  "%d"
.text
.globl  main
.type   main, @function
main:
pushq   %rbp
movq    %rsp, %rbp
subq    $16, %rsp
movl    $3, -8(%rbp)
movl    $2, -4(%rbp)
movl    -8(%rbp), %eax
cltd
idivl   -4(%rbp)
movl    %edx, -4(%rbp)
movl    -4(%rbp), %eax
movl    %eax, %esi
leaq    .LC0(%rip), %rdi
movl    $0, %eax
call    printf
movl    $0, %eax
leave
ret
.size   main, .-main
.ident  "GCC: (Ubuntu 7.4.0-1ubuntu1~18.04) 7.4.0"
.section    .note.GNU-stack,"",@progbits

Когда я добавляю @PLT после printf, все идет хорошо, но я просто хочу использовать -l в gcc

1 Ответ

2 голосов
/ 01 июня 2019

Вам не нужно -llibc, gcc уже связывает это по умолчанию.

Проблема здесь в том, что современный GCC по умолчанию делает PIE исполняемым (независимым от позиции), который является ELF "разделяемым объектом". Линкер обрабатывает его больше как библиотеку и не создает автоматически заглушки PLT для вызовов неопределенных имен символов. (Я не думаю, что такое поведение необходимо, ld может позволить вам сделать это.)

Простое решение здесь gcc -no-pie -fno-pie -o mod mod.s

Тогда вы можете написать call printf, и это просто работает.

С помощью этой командной строки вы создадите динамически связанный исполняемый файл ELF. Компоновщик переписывает ваш call printf в call printf@plt для вас (разберите его и посмотрите, с помощью objdump -drwC распечатайте перемещения). Смещение между адресом загрузки libc и адресом вашего кода не является константой времени соединения. (И может быть больше 2 ^ 32 в любом случае).

Если вы используете -static, call printf преобразуется в фактический адрес определения printf, скопированный в ваш исполняемый файл из libc.a.


Я предполагаю, что вариант создания статического или динамического исполняемого файла из того же источника - вот почему ld готов переписать вызовы к заглушкам PLT для исполняемых файлов ELF, но не к общим объектам ELF (например, к исполняемым файлам PIE).

См. 32-разрядные абсолютные адреса, более не разрешенные в x86-64 Linux? для получения дополнительной информации о PIE.

Другой способ вызова функций совместно используемой библиотеки - call *printf@GOTPCREL(%rip), как это делает gcc, если вы компилируете с -fno-plt. Это полностью обходит PLT, просто делая вызов через указатель функции в GOT (доступ к которому осуществляется в режиме адресации RIP-относительной).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...