У меня есть следующий фрагмент кода C:
#include <stdio.h>
int main()
{
int i;
for(i=0; i<10; i++)
puts("hello, friend");
return 0;
}
который я скомпилировал следующим образом: gcc firstprog.c -o firstprog
Затем при использовании gdb
для его разборки я вижу:
(gdb) disassemble
Dump of assembler code for function main:
=> 0x0000555555555149 <+0>: endbr64
0x000055555555514d <+4>: push rbp
0x000055555555514e <+5>: mov rbp,rsp
0x0000555555555151 <+8>: sub rsp,0x10
0x0000555555555155 <+12>: mov DWORD PTR [rbp-0x4],0x0
0x000055555555515c <+19>: jmp 0x55555555516e <main+37>
0x000055555555515e <+21>: lea rdi,[rip+0xe9f] # 0x555555556004
0x0000555555555165 <+28>: call 0x555555555050 <puts@plt>
0x000055555555516a <+33>: add DWORD PTR [rbp-0x4],0x1
0x000055555555516e <+37>: cmp DWORD PTR [rbp-0x4],0x9
0x0000555555555172 <+41>: jle 0x55555555515e <main+21>
0x0000555555555174 <+43>: mov eax,0x0
0x0000555555555179 <+48>: leave
0x000055555555517a <+49>: ret
End of assembler dump.
Итак, мой вопрос: что означает rip+0xe9f
в <main+21>?
Если я использую objdump
в том же файле, я получаю следующий результат:
$ objdump -M intel -D firstprog | grep -A16 main.:
0000000000001149 <main>:
1149: f3 0f 1e fa endbr64
114d: 55 push rbp
114e: 48 89 e5 mov rbp,rsp
1151: 48 83 ec 10 sub rsp,0x10
1155: c7 45 fc 00 00 00 00 mov DWORD PTR [rbp-0x4],0x0
115c: eb 10 jmp 116e <main+0x25>
115e: 48 8d 3d 9f 0e 00 00 lea rdi,[rip+0xe9f] # 2004 <_IO_stdin_used+0x4>
1165: e8 e6 fe ff ff call 1050 <puts@plt>
116a: 83 45 fc 01 add DWORD PTR [rbp-0x4],0x1
116e: 83 7d fc 09 cmp DWORD PTR [rbp-0x4],0x9
1172: 7e ea jle 115e <main+0x15>
1174: b8 00 00 00 00 mov eax,0x0
1179: c9 leave
117a: c3 ret
117b: 0f 1f 44 00 00 nop DWORD PTR [rax+rax*1+0x0]
Кажется, это связано с файловыми дескрипторами, но поскольку puts
пишет в стандартный вывод, я не ожидал увидеть IO_stdin.
Посмотрите на вывод GCC asm, например Как бы вы объяснили этот листинг дизассемблирования? — вы ясно увидите, что это RIP-загрузка с локальной метки в .rodata
. Или Какой рип используется здесь в сборке Hello world? . Также по теме: Почему доступ к глобальным переменным в x86-64 осуществляется относительно указателя инструкции? но вас беспокоит то, что на целевом адресе нет метки, а у именованной глобальной char foo[] = "...";
var она будет.
Итак, мой вопрос: на что ссылается rip+0xe9f в <main+21> ?
Можете посмотреть: x/s 0x555555556004
даст вам ответ.
(gdb) x/s 0x555555556004
0x555555556004: "hello, friend"
Он загружает адрес строки
"hello, friend"
вrdi
. Адрес_IO_stdin_used+0x4
, который является двойным словом памяти после_IO_stdin_used
. Скорее всего, ваша строка там (используйтеobjdump -s
, чтобы проверить). Строка не имеет связанного с ней символа, поэтомуobjdump
ошибочно предполагает, что она связана со строкой непосредственно перед этой.