sp
sp는 스택 포인터로, 변수는 sp를 기준으로 생성, 접근된다.
마지막에는 이렇게, 8바이트를 사용했으니, 그만큼 8바이트를 더해주고,
sp에 더한 값을 넣는다.
보통은 이걸 스택을 정리해준다 라고 한다.
lr, pc
lr은 Return address가 담겨있는 부분이다.
pc는 현재 실행중인 명령어의 위치이다.
1~10000까지 더하는 코드다
11줄의 bl sum 에 bp를 찍고 실행한 disassemble 창이다.
pc는 다음 실행할 명령어인 0x808c를 가리키고,
아직은 main 함수 내여서 돌아갈 주소가 없으니, lr은 0x0이다.
sum 브랜치가 종료되면 loop브랜치를 마저 실행해야 하니, bl sum의 다음 명령어인,
0x8090 (loop+16)의 값을 저장하고,
pc는 그냥 실행할 명령어를 저장하는 거니, 0x809C를 담고 있다.
sum 함수에 있는 sumloop브랜치는 없다 가정하고
mov pc lr부분을 보면, lr 값을 pc에 넣어줘 원래의 loop+16으로 이동하게 한다.
만약 이게 없으면, pc는 계속 +4씩 쭉쭉 올라가서 exit브랜치로 빠지고,
결국 이상한 명령어 주소까지 가버려서 그 유명한 세그 폴트를 뱉어버린다.
(지금 코드야 바로 다음에 exit가 있어서 오류는 안 나는데, exit 지우면 뜬다).
pop { pc } 와 mov pc, lr 차이
별 차이 없다. 먼저 mov pc, lr 부터보면
맨 위, push { r4, r5, lr } 을 해, 리턴 값을 저장한다.
이 때의 스택 상태가 다음과 같다. (lr위치는 loop 브랜치임)
이 상태에서 바로 pople { r4, r5, lr }로 기존 레지스터 값들을 가져온 뒤,
mov pc, lr을 해주면 정상적으로 원래 loop으로 돌아간다.
만약, mov pc, lr을 안 쓰고 pop으로 바로 loop으로 돌아가고 싶다면,
이렇게 하면 된다. loop 브랜치는 똑같으니 fibo만 표시한다.
pop이 스택에서 값을 하나 가져와 해당 레지스터에 저장하는 식이니, push된
lr(return address) 값을 바로 pc에 넣어줘도 된다.
그냥 코드 한 줄 늘어나는 거 외엔 차이 없다.
b, bx, bl 구분
b와 bx는 사실상 같다. 왜냐면 리턴 값을 남기지 않고, 분기를 타기 때문이다.
반대로, bl은 lr에 리턴 주소를 남기기 때문에,(호출하는 부분의 다음 명령어 값)
특정 브랜치를 수행하고 원래 위치로 되돌아가고 싶을 때 쓴다.
다만, b는 브랜치 이름을 적어줘야 하고,
bx는 지정된 레지스터로 분기한다.
만약, bx r0이고, r0이 0x1234면, pc는 0x1234가 된다.
즉, mov pc lr 대신 bx lr을 써도 된다.
만약, bx를 쓰면서 리턴 값을 남기고 싶으면 blx를 쓰면 된다.
'학교 > 시스템 프로그래밍' 카테고리의 다른 글
Control Flow (0) | 2020.12.11 |
---|---|
Signal (0) | 2020.12.05 |
LDR / STR Indexing (0) | 2020.11.17 |
section (0) | 2020.11.13 |
shift 연산자 (0) | 2020.11.11 |