함수가 불렸을 때 일어나는 일.
stack: history 기능, 즉, 선입후출 (가장 최근의 일을 알아 낼 수 있음)
> 함수를 계속 불러 제껴도, 자기 자리로 돌아 올 수 있음
" 함수를 호출하게 되면 실행위치의 이동은 어떻게 되는가요?"
" 함수를 호출한 후, 전달하는 인자들은 어떻게 호출된 함수로 전달되는가요?"
" 호출된 함수가 실행을 끝내고 나면 어떻게 이전에 실행하던 위치로 복귀할 수 있는가요?"
함수 call들
A()
{
............
B();
............ ●
}
B()
{
............
C();
............
}
C()
{
............
D();
............
}
D()
{
............
}
A()는 B()를 부르고, B()는 C()를 부르고, C()는 D()를 부르고,,
> 결국 D()를 실행하고 나서 > ● 지점으로 다시 돌아 와야함.
A()에서 B()를 부를 때,, stack > A()로 돌아갈 수 있는 표식을 넣어둠.
+ B()에서 C()를 부를 때, B()로 돌아갈 수 있는 표식을 stack에 쌓아 둠,
+ C()에서 D()를 부를 때 C()로 돌아갈 표식을 stack에 쌓아둠
stack에 1, 2, 3 순서로 쌓아 둔 다음
> 다시 거꾸로 갈 때 3, 2, 1 순서로 꺼내가면서 돌아감
stack에는 돌아갈 주소 + 전달인자들을 넣기도함
서브 루틴 호출시 수행되는 일
1. 전달 인자와 돌아갈 주소를 스택에 push하는일
2. 함수 호출 (즉, pc를 불리워진 함수의 주소로 jump시킴)
3. 지역변수에 대하여 스택에 저장공간을 할당하는 일
4. 호출된 함수를 수행하는일
5. stack에서 부터 할당된 지역변수 저장공간의 해제
6. 돌아갈 주소를 stack으로 부터 꺼내와 함수로부터의 복귀
7. 전달인자에 의해 사용되던 공간을 해제
. . . .
ex) 메모리 상에서 함수의 호출
main()이 sum()을 부름 > sum()이 display()를 호출
처음 main()영역 0xm1번지에서부터 opcode를 실행
sum()을 호출하는 0xm6번지를 만남
> 0xs1번지로 jump , stack : 돌아올 주소, 전달인자 등 ( 돌아오면 복구해야 할 것들 )
> 또한 sum()을 실행하기 위해
> sum()영역의 0xs1번지로 pc가 jump, 실행
> display()를 호출하는 0xs4번지를 만남
> stack에 이것저것 집어 넣고, jump
main()으로 돌아올 때는 반대의 경우
각각의 함수들 = symbol >자기 고유의 물리적 주소를 가짐
ARM의 R14 - LR의 용법
ARM : 원래 Stack 관련한 CALL이나 RET 명령어를 지원 X,
> Linked Register (R14)를 이용 > Branch하기 전에 돌아올 주소를 R14에 넣어둠
> 복귀할 때 R14를 PC에 넣고 돌아옴
word a_fuct (word arg, word param)
{
int localone, localtwo;
word ret;
localone = (int)(arg<<1);
localtwo = (int)(param>>1);
ret = b_funct ((word)localone, (word)localtwo);
if (ret>100)
message ("too big");
else
message ("appropriate");
return ret;
}
>> asm 변환
addr/line__|code_____|label____|mnemonic________________|comment_________________ |word a_funct(word arg, word param)
3985|{
ST:1E6C1A10|B510 a_funct: push {r4,r14}
| int localone, localtwo;
| word ret;
|
3989| localone = (int)(arg<<1);
ST:1E6C1A12|0040 lsl r0,r0,#0x1 ; arg,arg,#1
3990| localtwo = (int)(param>>1);
ST:1E6C1A14|0849 lsr r1,r1,#0x1 ; param,param,#1
|
3992| ret = b_funct ((word)localone, (word)localtwo);
ST:1E6C1A16|B280 uxth r0,r0 ; localone,localone
ST:1E6C1A18|FFCEF7FF bl 0x1E6C19B8 ; b
ST:1E6C1A1C|4604 cpy r4,r0
|
3994| if (ret>100)
ST:1E6C1A1E|2C64 cmp r4,#0x64 ; ret,#100
ST:1E6C1A20|D903 bls 0x1E6C1A2A
3995| message ("too big");
ST:1E6C1A22|A078 add r0,pc,#0x1E0
ST:1E6C1A24|ED62F0AE blx 0x1E7704EC
ST:1E6C1A28|E002 b 0x1E6C1A30
| else
3997| message ("appropriate");
ST:1E6C1A2A|A078 add r0,pc,#0x1E0
ST:1E6C1A2C|ED5EF0AE blx 0x1E7704EC
|
3999| return ret;
ST:1E6C1A30|4620 cpy r0,r4 ; r0,ret
4000|}
ST:1E6C1A32|BD10 pop {r4,pc}
|
a_funct()함수에 진입할 때 r4,r14 backup.// push {r4,r14}
> 컴파일러는 register를 backup 할 수 있도록 Assembly를 만듬
` 호출 받은 함수가 스크래치 레지스터 이외의 레지스터를 훼손하는 경우
> 가령 함수 내에서 R4, R5를 훼손시키게 된다면, Stack을 이용해 이전 값을 저장하고 복구하여야함
마지막에 pop으로 r4를 복원 > 돌아갈 주소를 pc에 넣어줌
a() 함수가 호출 > bl이라는 명령어로 호출 > Hardware적으로 자동으로 돌아갈 주소 값을 r14 (LR)에 넣음
> 호출된 함수에서는 r14값을 저장만 잘하면됨
//함수호출 : bl (branch with link)
BL function
...
...
function
...
...
MOV PC, LR
Return
> branch 다음다음 instruction으로 return하는 걸까?
질문) PC : 항상 현재 instruction의 address보다 두 개 앞의 값을 갖고 있음
> call할 때 LR : branch 한 곳의 다음다음 instruction의 address가 들어감
why? ) branch 바로 다음 instruction으로 return되는 이유
>> LR에 돌아갈 주소를 적어 넣을 때, BL 다음의 값을 LR에 자동으로 넣어줌 ( PC-4를 넣어주는 operation )
돌아올 때는 branch 명령 바로 다음으로 돌아와야함
branch 명령어 >> branch 명령 바로 다음 값이 lr에 자동 저장!
퀴즈)
" 함수를 호출하게 되면 실행위치의 이동은 어떻게 되는가요?"
→ PC를 함수의 시작주소로 set // 함수 호출 : ( CPU 입장 ) 순차적으로 명령어 실행
> 나 : 함수호출
> 컴파일러 : 함수 시작 주소로 pc set
" 함수를 호출하여 전달하고자 하는 인자들은 어떻게 호출된 함수로 전달되는가요?"
→ AAPCS라는 걸 이용해서 정해진 Register에 값을 전달
" 호출된 함수가 실행을 끝내고 나면 어떻게 이전에 실행하던 위치로 복귀할 수 있는가요?"
→ LR 이용! > bx r14
'임베디드 > 임베디드 레시피' 카테고리의 다른 글
Stack의 Size (0) | 2024.12.07 |
---|---|
stack 메모리 dump (0) | 2024.12.07 |
stack initialization (0) | 2024.12.05 |
Stack , Heap (1) | 2024.12.05 |
struct , packed (1) | 2024.12.05 |