sub rsp, <size>
RSP の下で 128 バイト以上を使用している場合は、スタック スペースを確保してからアクセスしてください。
クラッシュしたら、プロセス メモリ マップを確認します。カーネルがスタック マッピングを拡大しないほど RSP よりもはるかに低いメモリを使用している可能性があります。したがって、マップされていないページへの通常のアクセス =無効なページ フォールト => カーネルが SIGSEGV を配信します。
(ABI は 128 バイトのレッド ゾーンしか定義していませんが、実際にそのメモリを破壊できる唯一のものは、シグナル ハンドラー (インストールしていません) または print some_func()
を実行している GDB だけです) プログラムのスタックを使用して、プログラム内の関数を呼び出します。)
通常、Linux は介在するページに触れずにスタック マッピングを大きくしようとしますが、明らかに RSP の値をチェックします。通常は、スタック ポインターのはるか下にあるメモリを使用する代わりに、RSP を移動します (安全であるという保証がないため)。 「push」または「sub」x86 命令を使用する場合、スタック メモリはどのように割り当てられるかを参照してください。
別の重複:ESP または RSP レジスタを減算するときに生成される例外はどれですか? (スタックの成長) sub rsp, 5555555
を使用する場所 新しいスタック メモリに触れる前で十分でした。
スタック ASLR は、ページ境界に対して異なる場所で RSP を開始する可能性があります 、そのため、時々それをかろうじて回避できるかもしれません。 Linux は最初に 132kiB のスタック スペースをマップします 、および _start
へのエントリのスタック上の環境と引数のためのスペースが含まれます .あなたの 128kiB はそれに非常に近いので、時々ランダムに動作することは完全にもっともらしいです.
ところで、特に一度に 1 バイトではなく、実際にユーザー空間にメモリをコピーする理由はありません。同じアドレスを write
に渡すだけです .
または、可能であれば少なくともその場でフィルタリングして、キャッシュのフットプリントを小さくしてください。
また、バイトをロードする通常の方法は movzx eax, byte [mem]
です . mov al, [mem]
のみを使用してください 具体的にマージしたい場合 RAX の古い値を使用します。一部の CPU では、mov
al
まで 完全なレジスターを書き込むことによって壊すことができる古い値に誤った依存関係があります。
ところで、あなたのプログラムが常に がこのスペースを使用する場合は、BSS で静的に割り当てることもできます。これにより、位置依存 (非 PIE) 実行可能ファイルをアセンブルすることを選択した場合、より効率的なインデックス付きアドレス指定が可能になります。
amd64 のレッド ゾーンの長さはわずか 128 バイトですが、rsp の下で 131072 バイトを使用しています。スタック ポインターを下に移動して、スタックに格納するバッファーを囲みます。