0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

中古ノート、買ってみた。 その109

0
Last updated at Posted at 2025-12-05

概要

中古ノート買ってみた。
wsl1のubuntu18.04にnasm入れてみた。
push popをtestしたら、セグメンテーションフォルトになるので、copilotに聞いてみた。

サンプルコード


.intel_syntax noprefix
.global main

.text
main:
	push 	rbp
	mov 	rbp, rsp

	mov		rsi, 255
	lea 	rdi, fmt[rip]
	mov 	rax, 0
	push	rax
	call 	printf@PLT
	pop 	rax
	mov		rax, 0
	mov 	rsp, rbp
	pop 	rbp
	ret

.data
	fmt:  .string "value = %lX\n"




回答

なるほど、「何故セグフォルトになるのか」をもっと根本的に説明しますね。

🧩 原因の本質
あなたのコードでは printf を呼び出す前に 不要な push rax / pop rax を入れています。
このせいで スタックポインタ (rsp) がずれてしまい、関数呼び出し後のスタックフレームが壊れる のです。
呼び出し規約 (System V AMD64 ABI)

  • 引数はレジスタで渡す (rdi, rsi, rdx, …)。
  • 可変引数関数では rax に「浮動小数点引数の数」を入れる。整数だけなら rax=0。
  • スタックは 16 バイト境界に揃えた状態で call しなければならない。
    あなたのコードの流れ
  • push rbp → スタックが 8 バイト減る
  • mov rbp, rsp
  • mov rsi, 255 (第2引数)
  • lea rdi, fmt[rip] (第1引数)
  • mov rax, 0 (浮動小数点引数なし)
  • push rax → スタックがさらに 8 バイト減る
  • call printf@PLT
    この時点で、スタックのアラインメントが 16 バイト境界からずれてしまう。
    printf 内部では SSE 命令などでスタックが 16 バイト境界にあることを前提にしているため、ずれた状態で呼び出すと不正アクセスが起きてセグフォルトになります。

✅ 修正ポイント

  • push rax / pop rax は不要。
  • 呼び出し前にスタックを 16 バイト境界に揃えることが重要。
    修正版ではこうなります:
.intel_syntax noprefix
.global main

.text
main:
    push    rbp
    mov     rbp, rsp

    mov     rsi, 255              # 第2引数
    lea     rdi, fmt[rip]         # 第1引数
    mov     rax, 0                # 浮動小数点引数の数
    call    printf@PLT

    mov     eax, 0                # return 0
    mov     rsp, rbp
    pop     rbp
    ret

.data
fmt:    .string "value = %lX\n"

🎯 まとめ

  • セグフォルトの原因は スタックアラインメント違反。
  • push rax が余計で、printf 呼び出し時にスタックが 16 バイト境界からずれていた。
  • 修正すれば正常に "value = FF" が表示される。

スタックアラインメントのルールは「関数呼び出し直前の rsp が 16 の倍数であること」です。
このルールを守らないと、printf のようなライブラリ関数が内部で SSE 命令を使った時にクラッシュします。
👉 次は「なぜ 16 バイト境界が必須なのか」について、CPU の仕組みまで掘り下げて説明しましょうか?

なので、対応策

動いた。

.intel_syntax noprefix
.global main

.text
main:
	push 	rbp
	mov 	rbp, rsp

	mov		rsi, 255
	lea 	rdi, fmt[rip]
	mov 	rax, 0
	push	rax
	push	rax
	call 	printf@PLT
	pop 	rax
	pop 	rax
	mov		rax, 0
	mov 	rsp, rbp
	pop 	rbp
	ret

.data
	fmt:  .string "value = %lX\n"

以上。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?