システムコール番号を使って write システムコールを呼び出す

- C Assembler

概要

背景と目的

方法

  1. まず、syscall 関数とシステムコール番号を使用して標準出力に文字列を出力する C 言語のプログラムを実装します。これにより、システムコール番号とシステムコールの対応関係に対する理解を深めます。

  2. 次に、アセンブリ言語単体でシステムコールを呼び出すプログラムを実装します。これにより、システムコールを呼び出す際に必要な引数をスタックに詰んで、システムコールを呼び出す流れを確認します。

  3. 最後に、アセンブリ言語でシステムコールを呼び出し、標準出力に文字列を出力させる関数を実装し、その関数を C 言語で書いたプログラムから呼び出します。こうして、C 言語で書いたプログラムとアセンブリ言語で書いたプログラムの関係性を確認します。ただし、ここで取り扱うアセンブリ言語のプログラムは 32 bit の実行ファイルを作成するためのプログラムです。


NAME
       syscall - indirect system call

SYNOPSIS
       #define _GNU_SOURCE         /* See feature_test_macros(7) */
       #include <unistd.h>
       #include <sys/syscall.h>   /* For SYS_xxx definitions */

       long syscall(long number, ...);

DESCRIPTION
       syscall()  is  a  small  library  function  that invokes the system call whose assembly language interface has the specified number with the specified arguments.
       Employing syscall() is useful, for example, when invoking a system call that has no wrapper function in the C library.

       syscall() saves CPU registers before making the system call, restores the registers upon return from the system call, and stores any error code returned  by  the
       system call in errno(3) if an error occurs.

       Symbolic constants for system call numbers can be found in the header file <sys/syscall.h>.
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <asm/unistd_32.h>

int main(void) {
    char *buf = "Hi!\n";
    syscall(__NR_write, STDOUT_FILENO, buf, sizeof(buf));
    return 0;
}
gcc -m32 -o test_1 test_1.c
./test_1
Hi!
grep -ilr __NR /usr/include/* 
/usr/include/asm/vsyscall.h
/usr/include/asm/unistd_64.h
/usr/include/asm/unistd_x32.h
/usr/include/asm/unistd_32.h
/usr/include/asm-generic/unistd.h
/usr/include/bits/unistd.h
/usr/include/bits/syscall.h
/usr/include/bits/stdlib.h
...

archsyscall NRreturnarg0arg1arg2arg3arg4arg5
x86eaxeaxebxecxedxesiediebp
global main

main:
  push 0x0a216948
  mov  eax, 0x4
  mov  ebx, 0x1
  mov  ecx, esp
  mov  edx, 0x4
  int  0x80
  add  esp, 0x4
nasm -g -f elf32 -o test_2.o test_2.asm
gcc -m32 -o test_2.out test_2.o
./test_2.out
Hi!

void hi(char *string, int len);

int main () {
    char *string = "Hi!\n";
    hi(string, 4);
    return 0;
}
gcc -m32 -o test_3.o -c test_3.c
bits 32

global hi

hi:
  mov eax, 0x4
  mov ebx, 0x1
  mov ecx, [esp+4]
  mov edx, [esp+8]
  int 0x80
  add esp, 0x4
  ret
nasm -f elf32 -o syscall_test_3.o test_3.asm
gcc -m32 -o test_3.out test_3.o syscall_test_3.o
./test_3.out
Hi!

結果と結論

参考