アセンブリ言語と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