코드를 보면서 공부를 하던 중 우리는 system call을 부르기 위해서 syscall.c에서 sycall_handler를 호출한다고 이해했는데 이 핸들러에서 함수의 인자인 intr_frame f가 어디서 오는지 갑자기 궁금해졌다.
예를 들어, userprogram에서 fork를 사용한다고 가정한다. 그럼 lib/syscall.c에 있는 fork함수가 호출된다.
fork 함수 안에는 syscall1 함수를 바로 호출하여 SYS_FORK, thread_name을 넘겨준다.
syscall1함수를 살펴보면 다음과 같다.
#define syscall1(NUMBER, ARG0) ( \
syscall(((uint64_t) NUMBER), \
((uint64_t) ARG0), 0, 0, 0, 0, 0))
함수의 매개변수인 NUMBER와 ARG0에 각각 SYS_FORK와 ARG0가 들어간다.
위 함수는 다시 syscall함수를 호출한다. 이 syscall 함수가 우리가 중점적으로 봐야하는 함수이다.
크게 박스로 표시해둔 두 부분을 봐야한다.
빨간 네모 박스에 해당하는 부분은 어셈블리 레지스터와 주어진 변수들의 포인터를 등록한다.
- num_은 rax에 등록된다.
- a1은 rdi에 등록된다.
등록 후 각 함수의 매개변수로 들어온 값을 넣어준다.
파란 박스의 부분은 어셈블리어를 실행하는 부분이다.
[!info] 일반 목적 레지스터란?
프로그래머에 의해 여러가지로 활용할 수 있는 레지스터를 의미한다.
ex) 일반 목적 레지스터에 변수 num을 할당하면 나중에 변수 num 값을 레지스터에 로드할 필요가 없어서 레지스터를 사용하여 메모리에서 데이터를 읽는데 드는 시간을 절약할 수 있다.
레지스터를 활용하여 userprogram에서 받아온 함수의 인자들을 kernel에 있는 함수에서도 사용할 수 있도록 레지스터의 값을 넘겨주면서 syscall_handler에서 사용할 수 있게 되는 것이다.