last update 2023.10.21
틀린 내용이 있다면 댓글 또는 슬랙 @kyungjle로 연락 부탁드립니다!!
42 본과정의 ft_printf
는 가변 인자 함수(Variadic Function)를 소개한다. 인자(Parameter)의 개수와 형식이 정해져 있는 일반적인 함수와 달리, 가변 인자 함수는 임의의 인자를 자유롭게 받을 수 있다.
다만, C의 가변 인자 함수에는 몇 가지 제약이 있다. 우선 Callee의 입장에서는 (1) 몇 개의 인자가 있는지와 (2) 각 인자가 무슨 형식인지 알 수 없다. 그렇기에 올바른 개수와 형식의 인자를 넣어 주는 것은 Caller의 책임이다.
이 글은 실제로 가변인자는 어떻게 동작하는지 디버깅하며 살펴본다. 42서울 슬랙의 스레드에도 자세히 나와있지만, 호출 규약(Calling Convention)에 초점을 두고 살펴보려고 한다.
이 글은 x86-64 환경의 WSL 위에 실행중인 Ubuntu 20.04 LTS 기준으로 작성되었습니다.
- ldd v2.35
- gcc v11.4.0
- Ubuntu 20.04 LTS (5.15.90.1-microsoft-standard-WSL2)
우분투 환경에는 llvm 대신 gnu 계열의 컴파일러를 사용하기 때문에 이 글에서는 LLDB가 아닌 GDB를 기준으로 설명합니다.
(GDB와 LLDB의 차이점에 대해서는 이 글에 간단하게 나와 있습니다. GDB에서 사용할 수 있는 기본적인 명령어들은 LLDB에서도 사용 가능합니다.)
컴파일 단계에서 -g
옵션을 이용해 심볼을 남긴 채로 컴파일하면 쉽게 리버스 엔지니어링 할 수 있다. 꼭 심볼을 남기고 디버거에 넣자!
r
프로세스 재시작set disassembly-flavor intel
: 어셈블리어 코드를 AT&T 문법이 아니라 인텔 문법으로 표현한다.b main
b *main + 120
b *0x00004012
: 특정 주소에 bp(break point)를 설정한다.
함수 심볼을 이용하면 함수의 프롤로그 직후로 bp가 설정되는데, 오프셋을 이용해 편하게 bp를 걸 수도 있다.info b
, clear
: bp 정보를 보거나 설정된 bp를 제거할 때 사용한다.