Я провел несколько экспериментов, в которых я создал локальную переменную типа указатель на функцию, которая указывает на printf
.Затем я регулярно вызывал printf
и использовал эту переменную следующим образом:
#include<stdio.h>
typedef int (*func)(const char*,...);
int main()
{
func x=printf;
printf("%p\n", x);
x("%p\n", x);
return 0;
}
Я скомпилировал ее, посмотрел на разборку main с помощью gdb и получил:
0x000000000000063a <+0>: push %rbp
0x000000000000063b <+1>: mov %rsp,%rbp
0x000000000000063e <+4>: sub $0x10,%rsp
0x0000000000000642 <+8>: mov 0x20098f(%rip),%rax # 0x200fd8
0x0000000000000649 <+15>: mov %rax,-0x8(%rbp)
0x000000000000064d <+19>: mov -0x8(%rbp),%rax
0x0000000000000651 <+23>: mov %rax,%rsi
0x0000000000000654 <+26>: lea 0xb9(%rip),%rdi # 0x714
0x000000000000065b <+33>: mov $0x0,%eax
0x0000000000000660 <+38>: callq 0x520 <printf@plt>
0x0000000000000665 <+43>: mov -0x8(%rbp),%rax
0x0000000000000669 <+47>: mov -0x8(%rbp),%rdx
0x000000000000066d <+51>: mov %rax,%rsi
0x0000000000000670 <+54>: lea 0x9d(%rip),%rdi # 0x714
0x0000000000000677 <+61>: mov $0x0,%eax
0x000000000000067c <+66>: callq *%rdx
0x000000000000067e <+68>: mov $0x0,%eax
0x0000000000000683 <+73>: leaveq
0x0000000000000684 <+74>: retq
Чтодля меня странно, что вызов printf
напрямую использует plt (как и ожидалось) , но вызов его с использованием локальной переменной использует совершенно другой адрес (как вы можете видеть в строке 4 сборки, чтозначение, хранящееся в локальной переменной x, не является адресом записи plt).
Как это может быть?Разве все вызовы функций, не определенных в исполняемом файле, не проходят сначала через plt для повышения производительности и для кода pic?