gcc - warning: stack frame size of xxxx 이해하기
stack frame 은 함수 call이 발생할때 stack 저장공간에 쌓이는 데이터다. Activation record 라고 부르기도한다. stack frame 사이즈는 컴파일 타임에 계산된다. 로컬변수, 리턴addr, 매개변수 등의 사이즈로 계산한다. stack overflow 를 조금 더 예방하기 위해 OS는 stack frame 사이즈에 제약을 가할 수 있다. 예를 들어 리눅스 커널은 CONFIG_FRAME_WARN 에 적절한 값을 지정할 수있다(lib/Kconfig.debug). 컴파일 타임에 함수에서 stack frame사이즈를 줄이고 싶다면 malloc()등을 활용해 heap에 데이터를 저장하는 방법이 있다.
gcc에는 -Wframe-larger-than=
옵션이 있는데 지정된 사이즈를 넘어서면 warning을 생성한다. GCOV_KERNEL config를 사용할때 발생할수 있다. gcov는 함수에 특정코드를 삽입하므로 stack frame이 증가하는 것같다. 아래와 같이 실험 해보자.
- main.c
int main(void) {
char s[1024];
return 0;
}
$ gcc -std=c99 -O0 -Wframe-larger-than=1 main.c
main.c: In function ‘main’:
main.c:4:1: warning: the frame size of 1040 bytes is larger than 1 bytes [-Wframe-larger-than=]
}
^
$ gcc -std=c99 -O0 -Wframe-larger-than=2048 main.c
# No warning.
참고
gcov 관련 옵션이 어떻게 stack frame 사이즈를 증가시키는가?
gcov 는 소스코드 커버리지 분석 도구이며 GCC(GNU Compiler Collection)에 포함되어있다. gcc의 -fprofile-arcs
-ftest-coverage
옵션으로 컴파일하면 커버리지 관련 코드가 instrumentation 되어 컴파일된다. 이때 코드 사이즈가 증가하는데, 실제로 어떻게 바뀌는지 실험 해보자. 먼저 간단하게 아래와같은 코드를 만들었다. func함수가 옵션에 따라 어떻게 달라지는지 확인해보면 될것이다.
- func_call.c
#include <stdio.h>
int func(int val)
{
return val++;
}
int main(int argc, char *argv[])
{
func(11);
return 0;
}
- Makefile
all:
gcc -Wall func_call.c
gcov_test:
gcc -Wall -fprofile-arcs -ftest-coverage func_call.c
clean:
rm -rf a.out *.o *.gcda *.gcno
옵션 없이 컴파일 했을때
objdump -d a.out
로 역어셈블 한것중에 func와 main만 발췌했다. 전체 라인수는 192라인이었다.
00000000004004d6 <func>:
4004d6: 55 push %rbp
4004d7: 48 89 e5 mov %rsp,%rbp
4004da: 89 7d fc mov %edi,-0x4(%rbp)
4004dd: 8b 45 fc mov -0x4(%rbp),%eax
4004e0: 8d 50 01 lea 0x1(%rax),%edx
4004e3: 89 55 fc mov %edx,-0x4(%rbp)
4004e6: 5d pop %rbp
4004e7: c3 retq
00000000004004e8 <main>:
4004e8: 55 push %rbp
4004e9: 48 89 e5 mov %rsp,%rbp
4004ec: 48 83 ec 10 sub $0x10,%rsp
4004f0: 89 7d fc mov %edi,-0x4(%rbp)
4004f3: 48 89 75 f0 mov %rsi,-0x10(%rbp)
4004f7: bf 0b 00 00 00 mov $0xb,%edi
4004fc: e8 d5 ff ff ff callq 4004d6 <func>
400501: b8 00 00 00 00 mov $0x0,%eax
400506: c9 leaveq
400507: c3 retq
400508: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
40050f: 00
옵션 포함 컴파일 했을때
일단 기본적으로 어셈블리 라인수가 엄청나게 늘었다. __gcov
로 시작하는 함수가 엄청많이 생겼다. 전체 라인수가 192라인에서 2610라인으로 늘어났다.
0000000000400cc6 <func>:
400cc6: 55 push %rbp
400cc7: 48 89 e5 mov %rsp,%rbp
400cca: 89 7d fc mov %edi,-0x4(%rbp)
400ccd: 8b 45 fc mov -0x4(%rbp),%eax
400cd0: 8d 50 01 lea 0x1(%rax),%edx
400cd3: 89 55 fc mov %edx,-0x4(%rbp)
400cd6: 90 nop
400cd7: 48 8b 15 82 35 20 00 mov 0x203582(%rip),%rdx # 604260 <__gcov0.func>
400cde: 48 83 c2 01 add $0x1,%rdx
400ce2: 48 89 15 77 35 20 00 mov %rdx,0x203577(%rip) # 604260 <__gcov0.func>
400ce9: 5d pop %rbp
400cea: c3 retq
0000000000400ceb <main>:
400ceb: 55 push %rbp
400cec: 48 89 e5 mov %rsp,%rbp
400cef: 48 83 ec 10 sub $0x10,%rsp
400cf3: 89 7d fc mov %edi,-0x4(%rbp)
400cf6: 48 89 75 f0 mov %rsi,-0x10(%rbp)
400cfa: 48 8b 05 4f 35 20 00 mov 0x20354f(%rip),%rax # 604250 <__gcov0.main>
400d01: 48 83 c0 01 add $0x1,%rax
400d05: 48 89 05 44 35 20 00 mov %rax,0x203544(%rip) # 604250 <__gcov0.main>
400d0c: bf 0b 00 00 00 mov $0xb,%edi
400d11: e8 b0 ff ff ff callq 400cc6 <func>
400d16: ba 00 00 00 00 mov $0x0,%edx
400d1b: 48 8b 05 36 35 20 00 mov 0x203536(%rip),%rax # 604258 <__gcov0.main+0x8>
400d22: 48 83 c0 01 add $0x1,%rax
400d26: 48 89 05 2b 35 20 00 mov %rax,0x20352b(%rip) # 604258 <__gcov0.main+0x8>
400d2d: 89 d0 mov %edx,%eax
400d2f: c9 leaveq
400d30: c3 retq
-
분석
둘다 main에서 func 로 call하기 전에sub $0x10,%rsp
를하는데 (스택포인터(rsp)를 rbp로부터 0x10만큼 늘림). 일단 parameter 사이즈는 늘어나지 않음.
위 내용만 봤을때 스택프레임 자체는 증가하지 않는것 아닌지?. -
결론
더 분석 필요.
References
- x86 stack frame (https://blog.kimtae.xyz/9)
- x86 assembly 시스템별 상이한 규칙
CMD src dst
vsCMD dst src
?
If the registers have a % prefix → AT&T syntax → src, dst order.
Otherwise, unadorned registers → Intel syntax → dst, src order.
Author And Source
이 문제에 관하여(gcc - warning: stack frame size of xxxx 이해하기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@soopsaram/Kernel-warning-stack-frame-size-of-xxxx-이해하기저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)