x86-64 System V ABIでは、の後ろのスペース$rsp - 128
は、シグナル ハンドラが触れない、いわゆるレッド ゾーンであると指定されています。私のマシンで
$ ulimit -s
8192
スタックには 2 ページしかないと予想していました。そこで、次のプログラムを作成して、どのサイズのレッド ゾーンが拡大できるかをテストしました。
PAGE_SIZE equ 0x1000
SYS_exit equ 0x3C
section .text
global _start
_start:
lea rcx, [rsp - 0x1f * PAGE_SIZE]
mov rax, rsp
loop:
sub rax, PAGE_SIZE
mov qword [rax], -1
cmp rax, rcx
jne loop
mov rax, SYS_exit
mov rdi, 0x20
したがって、プログラムは常に失敗すると予想していました。しかし、プログラムは で失敗することもあればSEGV
、正常に終了することもあります。
MAP_GROWSDOWN
動作は、次のドキュメントとまったく同じです。
このフラグはスタックに使用されます。これは、カーネル仮想メモリ システムに対して、マッピングがメモリ内で下位に拡張する必要があることを示します。戻りアドレスは、プロセスの仮想アドレス空間で実際に作成されるメモリ領域よりも 1 ページ下になります。マッピングの下にある「ガード」ページのアドレスに触れると、マッピングが 1 ページ分大きくなります。この成長は、マッピングが次に低いマッピングの上限のページ内に成長するまで繰り返すことができ、その時点で「ガード」ページに触れると
SIGSEGV
信号が発生します。
この質問で説明したように、作成されたマッピングはそのようには成長MAP_GROWSDOWN
しPROT_GROWSDOWN
ません。
volatile char *mapped_ptr = mmap(NULL, 4096,
PROT_READ | PROT_WRITE | PROT_GROWSDOWN,
MAP_GROWSDOWN | MAP_ANONYMOUS | MAP_PRIVATE,
-1, 0);
mapped_ptr[4095] = 'a'; //OK!
mapped_ptr[0] = 'b'; //OK!
mapped_ptr[-1] = 'c'; //SEGV
質問:上記の理由を組み合わせると、使用する唯一のマッピングがMAP_GROWSDOWN
メイン スレッドの[stack]
マッピングであるというのは本当ですか?