KDOC 141: Cのポインタ操作をアセンブリで見る

この文書のステータス

  • 作成
    • 2024-04-29 貴島
  • レビュー
    • 2024-05-06 貴島

概要

ポインタ型の引数に代入すると、関数をまたいで変更を反映できる(参照渡し)。C言語では返り値を複数返せないので、複数必要なときはこれを使う。

#include <stdio.h>

void inc(int *a) { // アドレスを受け取る
  *a = *a+1; // アドレスが参照する値を反映する
}

int main(void){
  int a = 0;
  inc(&a); // アドレスを渡す
  inc(&a);
  printf("%d",a); // 2
}

何が起きているのか、生成されたアセンブリを見て確かめる。

アセンブリで見ると

↓こうなっている。即値の代入とじつはあまり変わらない。スタックに入っている値を使うか、スタックのアドレスを使うかだけの違い。

// ↓新しいスタック割当。sp -> スタックの底
addi sp,sp,-32
// ↓元々のレジスタの値をスタックに退避する
sw ra,28(sp)
sw s0,24(sp)
// ↓退避したのでs0を上書きして新しいスタックフレームに移動させる。s0: スタックの一番上、開始アドレス
addi s0,sp,32

// ↓積んだスタックの一番上の**アドレスを**計算してa5に格納
addi a5,s0,-24
// ↓a5(アドレスが入ってる)をスタックに保存
sw a5,-20(s0)
// ↓a5をスタックからロード(storeとloadで、結果としてa5の値は変わらない)
lw a5,-20(s0)
// ↓即値41をa4にロード
li a4,41
// ↓41番地にa5を保存
sw a4,0(a5)
nop

;; レジスタを元に戻す
lw ra,28(sp)
lw s0,24(sp)
addi sp,sp,32
;; 呼び出し先に戻る
jr ra

関連

Backlinks