Stack의 Size는 어떻게 정하게 되는 건가요? 그냥 막무가내로 Stack의 Size를 정할 수는 없겠지요. 보통 실무에서 넉넉하게 정해주는 Stack 측정 방법이 있는데 별거 아니에요. 복습 하는 기분으로 함수가 호출 될 때 Stack에 값을 어떻게 쌓았었는지 다시 한번 보는 건 어떨까요. 우선, 아래와 같은 Code가 있다고 치시고요, 현재 PC값이 0x18122C9E인 경우이지요.
addr/line__|code_____|label____|mnemonic________________|comment
ST:18122C90|4010 and r0,r2
ST:18122C92|40C8 lsr r0,r1
ST:18122C94|40CB lsr r3,r1
ST:18122C96|1A18 sub r0,r3,r0
ST:18122C98|2801 cmp r0,#0x1
ST:18122C9A|D103 bne 0x18122CA4
| {
1552| gc_sm (UP_EV);
ST:18122C9C|2002 mov r0,#0x2
ST:18122C9E|FE6BF7FF____________bl______0x18122978_______;_gc_sm
ST:18122CA2|E002 b 0x18122CAA
| }
| else
| {
1556| gc_sm (STAY_EV);
ST:18122CA4|2001 mov r0,#0x1
ST:18122CA6|FE67F7FF bl 0x18122978 ; gc_sm
| }
| #endif /* hieonn #if 0 */
| }
|
|
| /* Check the page status it should be marked erased. */
일단, 위 상태에서의 Context를 보면 R0~R15의 값은 아래와 같습니다요.
N _ R0 2 R8 0 SP> 0000030D
Z _ R1 6 R9 0 -1C 0000030F
C C R2 FFFFFFC0 R10 0 -18 00002842
V _ R3 14 R11 0 -14 01D63EE0
I _ R4 01D64160 R12 01803AD0 -10 00000000
F _ R5 01D63EE0 R13 01803AD0 -0C 0000030D
T T R6 01D64120 R14 18122C5D -08 00000004
J _ R7 18B5E7D4 PC 18122C9E -04 1812434D
usr SPSR CPSR 20000030 FP> 00900C0C
Q _ +04 00000004
이때, Stack Pointer (R13)이 가리키고 있는 곳을 한번 볼까요? 어디에 무엇을 가리키고 있는지..
___address__|________0________4________8________C_0123456789ABCDEF
SD:01803A70| 00000000 00000000 00000000 00000000 ................
SD:01803A80| 00000000 00000000 00000000 00000000 ................
SD:01803A90| 00000000 00000000 00000000 00000000 ................
SD:01803AA0| 00000000 00000000 00000000 00000000 ................
SD:01803AB0| 00000000 00000000 00000000 00000000 ................
SD:01803AC0| 00000000 00000000 00000000 00000000 ................
SD:01803AD0|>0000030D 0000030F 00002842 01D63EE0 ........B(...>..
SD:01803AE0| 00000000 0000030D 00000004 1812434D ............MC..
SD:01803AF0| 00900C0C 00000004 03000004 0000030C ................
SD:01803B00| 0000030E 00000000 00000000 00000000 ................
SD:01803B10| 00000004 00000001 30730000 00000000 ..........s0....
SD:01803B20| 00000200 00000036 00000000 00000000 ....6...........
SD:01803B30| 01D6371C 00901FE8 00901F68 0000081C .7......h.......
SD:01803B40| 01D6381C 01D6379C FFFFFFF1 0000030E .8...7..........
SD:01803B50| 01D6379C 01D6371C 00000A73 01DA6B00 .7...7..s....k..
SD:01803B60| 00000000 18014B03 000004C4 01DA6B00 .....K.......k..
SD:01803B70| 00000A73 180136FD 0000030E 01D63EE0 s....6.......>..
SD:01803B80| 00000025 01D76B00 00000004 01D638E4 %....k.......8..
오호라, 0x1803AD0을 가르키고 있었는데, 0x30D라는 값이 들어 있네요. 자자, 이제부터 함수가 호출되면 어떤 일이 벌어지는 지 다시 한번 슬슬 들여다 보시지요. 우선 PC값이 0x18122C9E였고요, 그 곳의 opcode는 bl 0x18122978 이었지요. 0x18122978에는 무엇이 있는지 한번 살펴 볼까요? void gc_sm(..) 함수의 시작 지점인 push {r14} 지점을 가르키고 있지요. 그곳으로 PC는 Jump를 하고, gc_sm()함수가 호출 되는 겁니다. 물론 돌아 갈 주소인 0x18122CA2을 의미하는 0x18122CA3 (Thumb mode니까요)이 자리 잡겠지요? 자, 한 번 살펴 봅시다.
_addr/line__|code_____|label____|mnemonic________________|comment
|
|void gc_sm (curr_gc_event_type curr_event)
1452|{
ST:18122978|B500 gc_sm: push {r14}
| curr_gc_state next_status;
| curr_gc_state old_status;
|
1456| old_status = curr_status; /* save the current status */
ST:1812297A|4B6E________________ldr_____r3,0x18122B34
ST:1812297C|7819 ldrb r1,[r3]
|
1458| if (curr_status == INIT_ST)
ST:1812297E|2900 cmp r1,#0x0
ST:18122980|D101 bne 0x18122986
1459| curr_status = STAY_ST;
ST:18122982|2101 mov r1,#0x1
ST:18122984|7019 strb r1,[r3]
|
1461| switch (curr_status)
ST:18122986|7819 ldrb r1,[r3]
ST:18122988|2901 cmp r1,#0x1
ST:1812298A|D005 beq 0x18122998
ST:1812298C|2902 cmp r1,#0x2
ST:1812298E|D101 bne 0x18122994
OK 그러면 push {r14}를 하고 나면 무슨 일이 벌어지는 지 Context를 한 번 살펴 보아야 하겠지요. 그 때의 Context를 한번 보시죠. R14의 0x1822CA3은 gc_sm()함수를 실행하고 나서 돌아가야 할 이겠고요, 그리고 push를 한번 했으니까, R13-0x4를 하시어, 0x1803ACC를 가르키고 있을테고, 0x1803ACC에는 R14 값인 0x18122CA3가 들어 있겠네요? 진짜 그런 가 한번 보시죠.
N _ R0 2 R8 0 SP> 18122CA3
Z _ R1 6 R9 0 FP> 0000030D
C C R2 FFFFFFC0 R10 0 +04 0000030F
V _ R3 14 R11 0 +08 00002842
I _ R4 01D64160 R12 01803AD0 +0C 01D63EE0
F _ R5 01D63EE0 R13 01803ACC +10 00000000
T T R6 01D64120 R14 18122CA3 +14 0000030D
J _ R7 18B5E7D4 PC 1812297A +18 00000004
usr SPSR CPSR 20000030 +1C 1812434D
Q _ +20 00900C0C
___address__|________0________4________8________C_0123456789ABCDEF
SD:01803A70| 00000000 00000000 00000000 00000000 ................
SD:01803A80| 00000000 00000000 00000000 00000000 ................
SD:01803A90| 00000000 00000000 00000000 00000000 ................
SD:01803AA0| 00000000 00000000 00000000 00000000 ................
SD:01803AB0| 00000000 00000000 00000000 00000000 ................
SD:01803AC0| 00000000 00000000 00000000>18122CA3 ................
SD:01803AD0| 0000030D 0000030F 00002842 01D63EE0 ........B(...>..
SD:01803AE0| 00000000 0000030D 00000004 1812434D ............MC..
SD:01803AF0| 00900C0C 00000004 03000004 0000030C ................
SD:01803B00| 0000030E 00000000 00000000 00000000 ................
SD:01803B10| 00000004 00000001 30730000 00000000 ..........s0....
SD:01803B20| 00000200 00000036 00000000 00000000 ....6...........
SD:01803B30| 01D6371C 00901FE8 00901F68 0000081C .7......h.......
SD:01803B40| 01D6381C 01D6379C FFFFFFF1 0000030E .8...7..........
SD:01803B50| 01D6379C 01D6371C 00000A73 01DA6B00 .7...7..s....k..
SD:01803B60| 00000000 18014B03 000004C4 01DA6B00 .....K.......k..
SD:01803B70| 00000A73 180136FD 0000030E 01D63EE0 s....6.......>..
SD:01803B80| 00000025 01D76B00 00000004 01D638E4 %....k.......8..
꺄오~ 정말 그르네요. Stack에 돌아 갈 주소인 0x18122CA3를 쌓고서, 일을 시작하네요. 어쨌거나, gc_sm(..) 이 생명을 다하면, 당연히 0x18122CA2로 돌아 오겠지요. 그 때는 당연히 pop {pc}를 이용해서, Stack에 들어 있던, R14 값을 PC에 넣고서 Stack Pointer를 +0x4 하고 빠져 나오겠지요. 한 번 보시죠.
_addr/line__|code_____|label____|mnemonic________________|comment
| {
1552| gc_sm (UP_EV);
ST:18122C9C|2002 mov r0,#0x2
ST:18122C9E|FE6BF7FF bl 0x18122978 ; gc_sm
ST:18122CA2|E002________________b_______0x18122CAA
| }
| else
| {
1556| gc_sm (STAY_EV);
ST:18122CA4|2001 mov r0,#0x1
ST:18122CA6|FE67F7FF bl 0x18122978 ; gc_sm
| }
| #endif /* hieonn #if 0 */
| }
|
|
| /* Check the page status it should be marked erased. */
ST:18122CAA|6A68 ldr r0,[r5,#0x24]
ST:18122CAC|9901 ldr r1,[r13,#0x4]
ST:18122CAE|6843 ldr r3,[r0,#0x4]
ST:18122CB0|2200 mov r2,#0x0
ST:18122CB2|4798 blx r3
N _ R0 2 R8 0 SP> 0000030D
Z _ R1 010E R9 0 -1C 0000030F
C _ R2 18B5E7D4 R10 0 -18 00002842
V _ R3 18B5E7D4 R11 0 -14 01D63EE0
I _ R4 01D64160 R12 01803AD0 -10 00000000
F _ R5 01D63EE0 R13 01803AD0 -0C 0000030D
T T R6 01D64120 R14 18122995 -08 00000004
J _ R7 18B5E7D4 PC 18122CA2 -04 1812434D
usr SPSR CPSR 30 FP> 00900C0C
Q _ +04 00000004
___address__|________0________4________8________C_0123456789ABCDEF
SD:01803A70| 00000000 00000000 00000000 00000000 ................
SD:01803A80| 00000000 00000000 00000000 00000000 ................
SD:01803A90| 00000000 00000000 00000000 00000000 ................
SD:01803AA0| 00000000 00000000 00000000 00000000 ................
SD:01803AB0| 00000000 00000000 00000000 00000000 ................
SD:01803AC0| 00000000 00000000 00000000 18122CA3 ................
SD:01803AD0|>0000030D 0000030F 00002842 01D63EE0 ........B(...>..
SD:01803AE0| 00000000 0000030D 00000004 1812434D ............MC..
SD:01803AF0| 00900C0C 00000004 03000004 0000030C ................
SD:01803B00| 0000030E 00000000 00000000 00000000 ................
SD:01803B10| 00000004 00000001 30730000 00000000 ..........s0....
SD:01803B20| 00000200 00000036 00000000 00000000 ....6...........
SD:01803B30| 01D6371C 00901FE8 00901F68 0000081C .7......h.......
SD:01803B40| 01D6381C 01D6379C FFFFFFF1 0000030E .8...7..........
SD:01803B50| 01D6379C 01D6371C 00000A73 01DA6B00 .7...7..s....k..
SD:01803B60| 00000000 18014B03 000004C4 01DA6B00 .....K.......k..
요요욧! 정말 그렇지요? 0x18122CA2로 돌아온 순간, R13 (SP)는 0x1803AD0을 가르키고 있네요~ 와하~ 복습 한 번 잘했다~ 라고만 할 게 아니고요, 여기에서 배울 점이 한 가지 있어요. 뭔가 하니, 원래 0으로 채워져 있던 순백의 Stack 영역에 push와 pop을 한 번 씩 했는데, push 했던 자리에 다시 0x0으로 지워지는게 아니라, 그냥 SP만 옮기고 그 자리에 있던 값은 Clear 되지 않네요! 오호라. 이런 거라면, 우리가 관심을 가지고 있는 특정 Stack에서 가장 많이 사용된 양은 0x0가 아닌 주소가 바로 Stack을 최대로 많이 사용 했을 때의 값이 겠지요? 그렇습니다~ 바로 그거지요~
여러가지 시나리오에서 System을 마구 사용해 보고서, Stack의 값을 주르륵 모니터링 해 보면 최대로 많이 사용 되었을 때의 Stack의 크기를 알 수 있는거에요. 일단 줄 수 있는 만큼 크게 Stack을 준 후에 Test를 해서, 적당한 Stack 크기를 잡게 되는데요, 보통 여러가지 시나리오를 통해서 Stack이 최대 얼마나 사용되는지 확인하고요, 그 최대 크기를 전체 Stack의 크기의 3/4으로 잡아서 System을 만들면 십중 팔구, Stack이 모자라서 Overflow가 나거나 하는 일은 없답니다. 별 거 아니죠? 예를 들어 Stack의 start 번지가 0x1000이고, 가장 많이 push를 해서 쌓았을 때의 주소가 0x400이라면, 0x2000-0x1400 = 0xC00이므로, 0xC00이 전체 Stack Size의 3/4을 차지하게 하려면 0xC00 X 4/3 = 0x1000이므로, 0x1000부터 ~ 0x2000 까지를 Stack으로 잡으면 문제 없다는 얘기죠.
댓글