のぴぴのメモ

自分用のLinuxとかの技術メモ

(linux)x86(32bit)でアセンブラでシステムコールを呼び出す方法。

はじめに

標準Cライブラリ(Linuxではglibc)に頼らず、システムコールを呼びして見たいなとの思いから、勉強がてらアセンブラシステムコールを呼びだす方法をまとめてみました。

2015.12.28追記

x86(32bit)とx86_64(64bit)はシステムコールの呼び方が全然違いますし、レジスタx86の32bit長のものでした。

詳細はこちら→--Syscall Number for x86-64 linux (A)
そのようなわけで、この記事は32bitアプリ前提で書き直しました。

アセンブラシステムコールを呼びだす方法

まとめると、以下の通りです。

  1. eaxレジスタに呼び出したいシステムコールの番号を登録する。
  2. システムコールに指定する番号は、"/usr/include/asm/unistd.hを参照。
    • asm/unistd.hから、
      • 32bitコンパイル時はasm/unistd_32.hが取り込まれる。(今回はこちら)
      • (参考までに)、64bit時は、asm/unistd_64.hが取り込まれる。
  3. システムコールに渡す引数は順番に、ebx, ecx, edxレジスタにコピーする。
  4. "int 0x80"で0x80割り込みを発生させることで、システムコールを発行する。
  5. リターンコードは、exaに格納されるので、そのレジスターをmovでコピーする。

サンプルコードです。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
	pid_t pid;

	/* call by assembly language */
	pid=0;
	__asm__("mov $20,  %%eax;"  //"$20"がgetpidのシステムコール番号
		"int $0x80;"        //80番で割り込みを発生させる
                "mov %%eax, %0;"    //返り値をpid変数にコピー
		:"=r"(pid)
	);
	printf("assembly: pid=%d\n",pid);

	/* call by glibc getpid function */
	pid=0;
	pid=getpid();
	printf("glibc   : pid=%d\n",pid);

	return(EXIT_SUCCESS);
}

実行結果です。

$ gcc -m32 -o test syscall_test.c 
$ ./test 
assembly: pid=3970
glibc   : pid=3970