일단 strace 실행
strace ls
execve("/usr/bin/ls", ["ls"], 0xffffd2497820 /* 62 vars */) = 0
brk(NULL) = 0xc63a27921000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xe8c8d6ac7000
faccessat(AT_FDCWD, "/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=66659, ...}) = 0
mmap(NULL, 66659, PROT_READ, MAP_PRIVATE, 3, 0) = 0xe8c8d6ab6000
close(3) = 0
openat(AT_FDCWD, "/lib/aarch64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0\267\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=198800, ...}) = 0
mmap(NULL, 337472, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_DENYWRITE, -1, 0) = 0xe8c8d6a3b000
mmap(0xe8c8d6a40000, 271936, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0xe8c8d6a40000
munmap(0xe8c8d6a3b000, 20480) = 0
munmap(0xe8c8d6a83000, 42560) = 0
mprotect(0xe8c8d6a6c000, 77824, PROT_NONE) = 0
mmap(0xe8c8d6a7f000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2f000) = 0xe8c8d6a7f000
mmap(0xe8c8d6a81000, 5696, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xe8c8d6a81000
close(3) = 0
openat(AT_FDCWD, "/lib/aarch64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0\267\0\1\0\0\0\360\206\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1722920, ...}) = 0
mmap(NULL, 1892240, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_DENYWRITE, -1, 0) = 0xe8c8d6872000
mmap(0xe8c8d6880000, 1826704, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0xe8c8d6880000
munmap(0xe8c8d6872000, 57344) = 0
munmap(0xe8c8d6a3e000, 8080) = 0
mprotect(0xe8c8d6a1a000, 77824, PROT_NONE) = 0
mmap(0xe8c8d6a2d000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19d000) = 0xe8c8d6a2d000
mmap(0xe8c8d6a32000, 49040, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xe8c8d6a32000
close(3) = 0
openat(AT_FDCWD, "/lib/aarch64-linux-gnu/libpcre2-8.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0\267\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=592328, ...}) = 0
mmap(NULL, 721536, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_DENYWRITE, -1, 0) = 0xe8c8d67cf000
mmap(0xe8c8d67d0000, 656000, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0xe8c8d67d0000
munmap(0xe8c8d67cf000, 4096) = 0
munmap(0xe8c8d6871000, 57984) = 0
mprotect(0xe8c8d6858000, 94208, PROT_NONE) = 0
mmap(0xe8c8d686f000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x8f000) = 0xe8c8d686f000
close(3) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xe8c8d6a8c000
set_tid_address(0xe8c8d6a8c0f0) = 2446818
set_robust_list(0xe8c8d6a8c100, 24) = 0
rseq(0xe8c8d6a8c740, 0x20, 0, 0xd428bc00) = 0
mprotect(0xe8c8d6a2d000, 12288, PROT_READ) = 0
mprotect(0xe8c8d686f000, 4096, PROT_READ) = 0
mprotect(0xe8c8d6a7f000, 4096, PROT_READ) = 0
mprotect(0xc63a25a9e000, 8192, PROT_READ) = 0
mprotect(0xe8c8d6acc000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0xe8c8d6ab6000, 66659) = 0
statfs("/sys/fs/selinux", 0xffffda5b90a0) = -1 ENOENT (No such file or directory)
statfs("/selinux", 0xffffda5b90a0) = -1 ENOENT (No such file or directory)
getrandom("\xd4\xa1\x6b\x89\x50\x53\x8f\x5f", 8, GRND_NONBLOCK) = 8
brk(NULL) = 0xc63a27921000
brk(0xc63a27942000) = 0xc63a27942000
openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(3, "nodev\tsysfs\nnodev\ttmpfs\nnodev\tbd"..., 1024) = 400
read(3, "", 1024) = 0
close(3) = 0
faccessat(AT_FDCWD, "/etc/selinux/config", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=4407424, ...}) = 0
mmap(NULL, 4407424, PROT_READ, MAP_PRIVATE, 3, 0) = 0xe8c8d6200000
close(3) = 0
ioctl(1, TCGETS, {c_iflag=ICRNL|IXON|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=36, ws_col=126, ws_xpixel=0, ws_ypixel=0}) = 0
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
fstat(3, {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
getdents64(3, 0xc63a27928740 /* 9 entries */, 32768) = 280
getdents64(3, 0xc63a27928740 /* 0 entries */, 32768) = 0
close(3) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
write(1, "fact factorial.c simple simpl"..., 83fact factorial.c simple simple.c stack_syscall.c syscall_test syscall_test.c
) = 83
close(1) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++
엄청나게 뭐가 많이 나오는데..
아무튼 이런 시스템 콜 실행 흐름을 가진다.
호출한 시스템콜의 호출 목록
- int execve(const char *pathname, char *const _Nullable argv[], char *const _Nullable envp[])
- 성공: 리턴 없음
- 실패: -1
- int brk(void *addr)
- 성공: 0
- 실패: -1
- void mmap(void addr[.length], size_t length, int prot, int flags)
- 성공: 매핑된 곳의 포인터 리턴
- 실패: MAP_FAILED (-1)
- int faccessat(int dirfd, const char *pathname, int mode, int flags)
- 성공: 0
- 실패: -1
- int openat(int dirfd, const char *pathname, int flags, ...)
- 성공: new file descriptor
- 실패: -1
- int fstat(int fd, struct stat *statbuf)
- 성공: 0
- 실패: -1
- int close(int fd)
- 성공: 0
- 실패: -1
- ssize_t read(int fd, void buf[.count], size_t count)
- 성공: 읽은 바이트 수
- 실패: -1
- int munmap(void addr[.length], size_t length)
- 성공: 0
- 실패: -1
- int mprotect(void addr[.len], size_t len, int prot)
- 성공: 0
- 실패: -1
- set_tid_address(SYS_set_tid_address, int *tidptr)
- 항상 성공: caller's thread ID
- set_robust_list()
- 성공: 0
- 실패: error code
- rseq
- int prlimit64(pid_t pid, int resource, const struct rlimit *Nullable new limit, struct rlimit *_Nullable old_limit)
- 성공: 0
- 실패: -1
- int statfs(const char *path, struct statfs *buf)
- 성공: 0
- 실패: -1
- ssize_t getrandom(viod buf[.buflen], size_t buflen, unsigned int flags)
- 성공: 버퍼에서 읽은 바이트 수
- 실패: -1
- int ioctl(int fd, unsigned long op, ...)
- 성공: 0
- 실패: -1
- ssize_t getdents64(int fd, void dirp[.count], size_t count)
- 성공: 읽은 바이트 수, 디렉토리의 끝이면 0리턴
- 실패: -1
- ssize_t write(int fd, const void buf[.count], size_t count)
- 성공: 쓴 바이트 수
- 실패: -1
- exit_group
종류별 시스템콜 총 호출 횟수
| 호출 횟수 | 시스템콜 |
| 15 | mmap |
| 1 | execve |
| 8 | mprotect |
| 9 | close |
| 7 | openat |
| 8 | fstat |
| 7 | munmap |
| 5 | read |
| 2 | statfs |
| 3 | brk |
| 1 | set_robust_list |
| 2 | faccessat |
| 2 | getdents64 |
| 1 | set_tid_address |
| 2 | ioctl |
| 1 | prlimit64 |
| 1 | rseq |
| 1 | write |
| 1 | getrandom |
ls 명령어에서 읽기 성공한 모든 파일의 경로
- /etc/ld.so.cache
- /lib/aarch64-linux-gnu/libselinux.so.1
- /lib/aarch64-linux-gnu/libc.so.6
- /lib/aarch64-linux-gnu/libpcre2-8.so.0
- /proc/filesystems
- /usr/lib/locale/locale-archive
- . (현재 디렉토리)
자주 나오는 시스템 콜
- openat : 특정 디렉토리를 기준으로 상대경로로 파일을 연다.
- read : 특정 바이트 수 만큼 파일에서 읽어서 버퍼에 넣는다.
- write : 특정 바이트 수만큼 버퍼에서 파일로 쓴다.
- close : 파일 디스크립터를 닫는다. 다른 곳에서 접근할 수 없다.
- execve : 특정 경로에 있는 프로그램을 실행한다.
ls 명령어 원리
이부분이 핵심이라고 생각됨
차근차근 분석해보자
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
fstat(3, {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
getdents64(3, 0xc63a27928740 /* 9 entries */, 32768) = 280
getdents64(3, 0xc63a27928740 /* 0 entries */, 32768) = 0
close(3) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
write(1, "fact factorial.c simple simpl"..., 83fact factorial.c simple simple.c stack_syscall.c syscall_test syscall_test.c
) = 83
close(1) = 0
close(2) = 0
exit_group(0)
- 현재 디렉토리를 열고 fd(파일 디스크립터) 3을 할당 -> openat
- fd=3이 가리키고있는 파일의 정보 획득 -> fstat
- 해당 디렉토리의 엔트리를 가져온다 -> getdent
- fd=1의 정보를 가져온다 -> fstat
- 가져온 정보를 fd=1에 쓴다 -> write
fd=1은 표준 출력으로 사용자 화면에 출력하는 용도
파일 디스크립터
- 0번 : stdin
- 1번 : stdout
- 2번 : stderr
'Linux' 카테고리의 다른 글
| 디바이스 드라이버 (0) | 2025.08.01 |
|---|---|
| 커널 모듈 (insmod, lsmod, rmmod) 커널 API (5) | 2025.07.30 |
| Kernel 및 System call 디버그 with GDB (0) | 2025.07.28 |
| 커널 시스템콜 추가 (3) | 2025.07.25 |
| Makefile (2) | 2025.07.24 |