Кто (какая функция) установил это значение? (загрузчик устанавливает это значение ..?)
Вы можете ответить на это, установив на нем точку наблюдения:
(gdb) start
Temporary breakpoint 1, main () at t.c:5
5 return 0;
(gdb) info var program_invocation_name
All variables matching regular expression "program_invocation_name":
Non-debugging symbols:
0x00007ffff7dd43b8 program_invocation_name
0x00007ffff7dd43b8 program_invocation_name
(gdb) watch *(char **)0x00007ffff7dd43b8
Hardware watchpoint 2: *(char **)0x00007ffff7dd43b8
(gdb) run
Starting program: /tmp/a.out
Hardware watchpoint 2: *(char **)0x00007ffff7dd43b8
Old value = <unreadable>
New value = 0x7ffff7b9b7a5 ""
0x00007ffff7de4c02 in _dl_relocate_object () from /lib64/ld-linux-x86-64.so.2
(gdb) c
Continuing.
Hardware watchpoint 2: *(char **)0x00007ffff7dd43b8
Old value = 0x7ffff7b9b7a5 ""
New value = 0x7fffffffdfa7 "/tmp/a.out"
0x00007ffff7b22963 in __init_misc () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) bt
#0 0x00007ffff7b22963 in __init_misc () from /lib/x86_64-linux-gnu/libc.so.6
#1 0x00007ffff7a5a134 in _init () from /lib/x86_64-linux-gnu/libc.so.6
#2 0x00007ffff7de886a in call_init.part () from /lib64/ld-linux-x86-64.so.2
#3 0x00007ffff7de89bb in _dl_init () from /lib64/ld-linux-x86-64.so.2
#4 0x00007ffff7dd9c5a in _dl_start_user () from /lib64/ld-linux-x86-64.so.2
#5 0x0000000000000001 in ?? ()
#6 0x00007fffffffdfa7 in ?? ()
ZQ2. Как программа знает, распознает ли она глобальную переменную, хотя это значение находится в стеке?
Переменная является глобальной переменной в разделе .data
:
(gdb) info sym 0x00007ffff7dd43b8
program_invocation_name in section .data of /lib/x86_64-linux-gnu/libc.so.6
Это указатель, который указывает на стек (он указывает на область стека, где ядро передает argv[]
процессу).
Q3. Иногда некоторые двоичные файлы работают без этого значения. В этом случае это проблема загрузчика?
Двоичный файл не может работать без этой переменной. Но переменная может указывать на пустую строку (если, например, родительский процесс не использовал обычное соглашение о вызовах и вместо этого сделал что-то вроде execl("/tmp/a.out", (char*)NULL)
).
Кроме того, программа может «стереть» свой собственный стек (например, из-за переполнения стека или намеренно скрыться от ps
(многие руткиты делают это)), а затем program_invocation_name
продолжит указывать на местоположение стека где имя программы было раньше, но больше нет.