[c언어]지역변수를 위한 로칼스택 할당 사이즈에 대한 문의
예를 들어 다음과 같은 함수를 테스트하는 경우,
void func(void)
{
char buf1[3];
}
x86 기반의 linux 2.6에서 gcc로 컴파일한다면, 제 상식으로는 buf1을 위해서 로칼 스택에 4바이트가 할당될 것이라 생각했습니다. 그런데 gdb로 확인하면
(gdb) disassem func
Dump of assembler code for function func:
0x8048460 <func>: push %ebp
0x8048461 <func+1>: mov %esp,%ebp
0x8048463 <func+3>: sub $0x18,%esp
0x8048466 <func+6>: leave
0x8048467 <func+7>: ret
보다시피 컴파일러는 buf1을 위해서 24바이트(18h) 스택 공간을 할당하는 것을 볼 수 있습니다. 그런데 buf1[4]로 하면 4바이트가 할당이 되더군요. 그리고 buf1[5]로 하면 다시 24바이트가 할당이 됩니다.
이렇게 linux에서 일관적으로 보이지 않게 로칼 스택을 할당하는 이유가 무엇인지 궁금합니다.
gcc 소스를 확인하고 싶지만 그 방대한 소스에서 정확히 어디를 봐야할지 감을 못잡겠습니다. 혹시 linux에서 로칼 변수를 위한 스택 할당 규칙이나 혹은 이에 대한 룰을 gcc 소스서 확인하는 방법을 아시는 분 계시면 조언 부탁드립니다.
음... 설명하려면 길고 인터넷 찾아보시면 관련 문서를 얻으실 수 있을테
음... 설명하려면 길고 인터넷 찾아보시면 관련 문서를 얻으실 수 있을테니 간단히...
우선 저 배열에 16만큼 할당됩니다. 이건 컴파일 옵션으로 조절이 가능합니다. 그러니 넘어가고...
스택에는 저것 외에도 esp ebp도 push되어 있습니다. 각각 4씩..
16+4+4면 24네요.
그런데 효율을 위해 컴파일러는 16씩 정렬을 맞추려고 합니다.
그래서 배열 다음에는 dummy가 8붙어야 합니다. (총합 16을 맞출수는 없고 32를 맞춰야 하니까)
그래서 16+8=24가 함수 내부에서 할당된 것이죠.
성능에 대한 문제 + 오버플로우에 대한 대비 등이 짬뽕된 이유인 것으로 알고 있습니다.
답변 감사드립니다.그런데 제가 잘못 알고 있는게 있었나요. 제가 알기
답변 감사드립니다.
그런데 제가 잘못 알고 있는게 있었나요. 제가 알기론 esp는 스택에 저장되지 않는걸로 아는데... ebp는 calling function의 stack frame의 주소이므로 called function에서 당연히 스택에 push되어야 하겠지만요. 그리고 그것을 차치하더라도 24바이트에는 ebp나 esp가 push되는 공간은 아니지요. 이미 <func> 라인에서 push %ebp 가 실행되었으므로 <func+3>에서 sub $0x18, %esp는 순수하게 local variables를 위한 공간이 아닌가요?
그리고 16씩 정렬이 된다면 buf1[2]나 buf1[4]는 왜 4바이트가 할당되는지는 설명이 되지 않습니다. buf[7]까지는 16씩 할당이 되면서 buf[8]에 와서는 다시 8이 할당이 되는건 word size단위에서는 4씩 정렬을 하면서 word size가 아닌 값에 대해서는 16씩 정렬을 하는 셈이 되는건가요?
제가 잘못 이야기 했네요. esp가 아니라 리턴 어드레스가 들어갑니다.
제가 잘못 이야기 했네요. esp가 아니라 리턴 어드레스가 들어갑니다. 크기는 똑같으니 패스 ;; (참고로 그 뒤에는 함수의 argument? 들이 들어갑니다. 아키텍쳐에 따라 차이가 있기는 하지만)
음 그건 그렇고 실제로 크기를 1씩 늘리면서 실험을 해보면 크기가 들쑥날쑥 할때가 있더라구요. 정확한 이유는 모르겠지만... [2]나 [4]가 그런 경우에 해당하는 것 같습니다. 아마 [16]이상으로 커지면 규칙성 있는 모습을 보일 겁니다. 문서에서는 그렇게 봤는데 직접 실험해 본적은 없네요. :)
아무튼 자세한건 내일 다시 보도록 하겠습니다. 그 사이 고수님이 답변을 주실지도 모르겠네요. 전 지금 윈도거든요. 디아블로1이 갑자기 하고 싶어져서.. 그런데 시디 인식 에러가 자꾸 나는거 있죠. ^^;
네.. 그렇군요.그러나 확실한건 24바이트에는 calling func
네.. 그렇군요.
그러나 확실한건 24바이트에는 calling function의 리턴주소와 ebp가 저장되는 공간이 아닙니다. 그것은 이미 <func+3> 라인 이전에 모두 스택에 저장되어 있으니까요. 리턴 어드레스와 ebp까지 합치면 총 32바이트 공간이 할당되는 셈입니다. gcc 소스에서 확인하는게 가장 확실한 방법같은데 그거참 어느 부분에 쳐박혀있는지 확인할 수가 없으니... --;;;
음... 그런데 저도 갑자기 스타크래프트가 하고 싶어지는군요. ^^;
네 24바이트 안에 저장되는건 아닙니다.간단히버퍼(16)
네 24바이트 안에 저장되는건 아닙니다.
간단히
버퍼(16) + 더미(8 ) + ebp(4) + ret(4)
이런식으로..
ebp와 ret을 언급하지 않으면 더미가 왜 8이 붙어야 하는지 설명할 길이 없어서요.
내일은 윈도98을 설치해봐야겠습니다. 좀처럼 안되네요. ^^;
댓글 달기