アセンブリでのsyscallとint 0x80の違い

thumbnail

アセンブリ、難しいですね。正直何も理解しないまま書いてます。

というわけで、今回はタイトル通りです。アセンブリでLinuxのシステムコールを呼び出す時、syscallとint 0x80の違いは何なのかメモしておきます。

環境

  • nasm 2.15.05
  • ld 2.36.1

以下のコードを、nasm -f elf64 a.s -o a.o && ld -m elf_x86_64 a.oとしてビルドしています。

global _start
_start:
  mov		ax, 0x05
  mov		bx, 0x03
  add		ax, bx
  push		ax
  jmp		exit_syscall
exit_int:
  mov		rax, 0x01
  mov		rdi, 0
  int			0x80
exit_syscall:
  mov		rax, 0x3c
  mov		rdi, 0
  syscall

レジスタをちょっといじるだけで、なんにもしないプログラムです。このままだとsyscallで、jmpがある行をコメントアウトするとint 0x80で、システムコールを呼び出します。

呼び出すのはsys_exitです。ちなみに、この呼び出しを忘れるとセグフォするので注意しましょう(1敗)。

違い

syscall はx86_64でカーネルモードに入る(システムコールによって?)方法であるのに対し、int 0x80はx86で用いられる方法です。古いから使わないほうが良いらしいです(しらんけど)。

以上の特徴があるため、以下のような違いが出てきます。

syscallはx86で使えない?

未検証ですが、参考サイトにはこんな感じのことが書いてありました。

システムコール番号が違う

システムコール番号は/usr/include/asm/unistd_(32|64).hに記載されています。

今回使ったexitは、x86では0x01番です。それに対し、x86_64は0x3c (60) 番です。
他にも、例えばwriteなんかは、x86では0x04番、x86_64は0x01 番です。

おわりに

参考サイトの丸パクリみたいになってしまいました。どうでしょうか。

int 0x80は互換性のために残されているだけで、基本的にsyscallが推奨されている、ということなのかな~とおもいました(こなみ)。

アセンブリぜんぜんわからないのでがんばりたいとおもいます。

参考サイト