É fácil acompanhar essa inicialização, pois (quase) todo processo strace
mostra um syscall muito suspeito durante o início da execução do processo:
arch_prctl(ARCH_SET_FS, 0x7fc189ed0740) = 0
Isso é o que o man 2 arch_prctl
diz:
ARCH_SET_FS
Set the 64-bit base for the FS register to addr.
Sim, parece que é o que precisamos. Para encontrar quem chama arch_prctl
, vamos procurar um backtrace:
(gdb) catch syscall arch_prctl
Catchpoint 1 (syscall 'arch_prctl' [158])
(gdb) r
Starting program: <program path>
Catchpoint 1 (call to syscall arch_prctl), 0x00007ffff7dd9cad in init_tls () from /lib64/ld-linux-x86-64.so.2
(gdb) bt
#0 0x00007ffff7dd9cad in init_tls () from /lib64/ld-linux-x86-64.so.2
#1 0x00007ffff7ddd3e3 in dl_main () from /lib64/ld-linux-x86-64.so.2
#2 0x00007ffff7df04c0 in _dl_sysdep_start () from /lib64/ld-linux-x86-64.so.2
#3 0x00007ffff7dda028 in _dl_start () from /lib64/ld-linux-x86-64.so.2
#4 0x00007ffff7dd8fb8 in _start () from /lib64/ld-linux-x86-64.so.2
#5 0x0000000000000001 in ?? ()
#6 0x00007fffffffecef in ?? ()
#7 0x0000000000000000 in ?? ()
Portanto, a base do segmento FS é definida pelo ld-linux
, que é uma parte do glibc
, durante o carregamento do programa (se o programa estiver vinculado estaticamente, esse código será incorporado ao binário). É aqui que tudo acontece.
Durante a inicialização, o carregador inicializa o TLS . Isso inclui a alocação de memória e a configuração do valor base FS para apontar para o início do TLS. Isso é feito por meio de arch_prctl
syscall . Após a inicialização do TLS security_init
função é chamada, o que gera o valor do guarda de pilha e grava na localização da memória, que fs:[0x28]
aponta para:
- Inicialização do valor de proteção de pilha
- Escrevemos o valor do protetor de pilha , mais detalhado
E 0x28
é o deslocamento do campo stack_guard
na estrutura que está localizada no início do TLS.