アセンブリ言語とCで遊ぶ

x86-64アセンブリ言語とCの呼び出し規約のお勉強のため、アセンブリ言語で書いた関数をCから呼び出してみました。 アセンブルにはnasm、Cのコンパイルにはgccを使っています。

Cのプログラムは以下の通り。 appという関数を実行して結果をprintfするだけです。

// main.c
#include <stdio.h>

int app(int x, int y);

int main(void)
{
  int ret = app(10, 20);
  printf("%d\n", ret);
  return 0;
}

appの実装は以下の通り。appの2つの引数と100とを足し合わせた結果を返すだけです。 呼び出し規約の勉強のためわざと冗長な書き方をしています。

;; app.asm
        bits 64
        global app
        section .text
app:
        ;; 呼び出し時のrbpを保存 (すぐ下でrspの値を保持するのに使用)
        push rbp
        ;; 呼び出し時のrspを保存
        mov rbp, rsp

        push rdi
        push rsi
        push 100
        call add

        ;; push rdi等で変更されたrspを呼び出し時の値に戻す
        mov rsp, rbp
        ;; rspの保存に使われたrbpを呼び出し時の値に戻す
        pop rbp
        ret

add:
        push rbp
        mov rbp, rsp

        ;; 「ret先のアドレス」と「push rbp」の16バイト分以降に引数がある
        mov rax, [rbp+16]
        add rax, [rbp+24]
        add rax, [rbp+32]

        mov rsp, rbp
        pop rbp
        ret

以下のようにコンパイル、リンクして実行できます。

$ nasm -f elf64 -o app.o app.asm
$ gcc main.c app.o
$ ./a.out 
130