지난 포스팅에서는 어셈블리 언어의 명령어 타입 3가지를 정리해보았다.
의사 명령어 / 기계 명렁어 / 합성 명령어
이렇게 3가지 종류의 명령어가 있었으며,
의사 명령어 = 기계어 번역 x, 어셈블러에게 추가 정보 전달
기계 명령어 = 기계어로 1:1 번역
합성 명령어 = 기계 명령어 형태로 바뀐 뒤 기계어로 번역
이렇게 정리할 수 있었다.
이번에는 SPARC에서 사용하는 메모리 종류에 대해 정리해보겠다.
프로그램에서 사용하는 메모리의 종류
프로그램에서 사용하는 변수는 크게 3가지가 있다.
1. 전역 변수 (Global Variable)
2. 지역 변수 (Local Variable)
3. 동적 할당 변수 (Heap)
전역 변수는 말 그대로 global 한 범위에서 사용이 가능한 변수이다.
전역 변수는 전역 변수를 위한 메모리 공간에 따로 담긴다.
(SPARC 에서 g-register 가 있듯이, 그러나 여기에서 말하는 메모리는 레지스터와 구분되는 점에 주의하자.)
지역 변수는 함수 내 범위에서 사용되는 변수이다.
함수는 그 특성상 '스택' 이라는 종류의 메모리에 존재하므로, 지역변수도 스택에 존재한다.
동적 할당 변수는 영어 이름에 나와있듯 '힙' 이라는 종류의 메모리에 존재한다.
그렇다면 전역변수는 메모리의 어디에 저장되고, 지역변수는 어디에 저장되고, 힙은 어디에 저장되는 것일까?
위 그림은 SPARC 의 Memory Map 을 나타낸다.
메모리를 크게 Static / Heap / Stack 영역으로 구분하며,
메모리의 주소가 낮은 곳부터 차례대로 Static Heap Stack 순으로 영역이 존재한다.
Static 은 정적이라는 말에 맞게, 영역 사이즈가 고정되어 있다.
Static의 text 라는 부분은 프로그램 카운터가 가리키는 곳으로 실행될 명령어가 있는 곳이다.
data 라는 부분은 위에서 말한 전역변수가 주로 담기는 공간이다.
bss 라는 부분은 static 변수가 담기는 공간을 의미한다고 하는데, 별로 볼 일이 없다고 한다.
bss는 0으로 초기화 되는 공간이라고 한다.
(C 언어에서 static 변수는 값을 지정하지 않으면 0으로 자동 저장된다고 배웠던 것 같은데 이것과 관련이 있어보인다.)
그 다음으로 Heap 영역이 나온다.
Heap 영역은 직접 동적 할당을 할 때 사용하는 메모리로, 할당을 할 때마다 사용되는 메모리의 주소가 점점 증가하는 특징이 있다.
Stack 영역은 함수마다 할당되는 영역이다.
지역변수 자체가 함수에서 쓰이다보니, 지역변수는 스택에 할당된다고 볼 수 있다.
정확하게는 지금 보고 있는 것은 '어셈블리'. 즉, 로우레벨인데, 로우레벨에서 표현할 땐 stack 영역은 함수마다 할당을 직접 한다고 표현하는 것이 더 맞다.
Stack 은 초기에 매우 높은 메모리 주소값부터 시작해서 점점 감소하는 방향으로 할당한다.
다음으로 어디에 할당이 되어야 하는지 가리키는 '스택 포인터' 를 이용한다.
이렇게 함수 내에서 함수가 또 호출될 때마다
스택 메모리에 함수에서 필요로 하는 공간만큼 메모리를 할당한다.
A+B+C 를 수행하는 함수가 있다고 하면 이 함수를 어셈블리로 다음과 같이 표현할 수 있다.
A = 10
B = 15
C = 20
.global main
main:
save %sp, -96, %sp ! stack frame 생성
mov A, %o0
add %o0, B, %o0
add %o0, C, %o0
ret
restore
먼저 함수를 사용하기 위한 스택 프레임을 할당하고,
o-register 에 미리 정의해둔 A, B, C 상수값을 하나씩 더한 뒤 리턴한다.
마지막으로 사용했던 스택을 restore 로 반환해주는 코드이다.
이 코드에서 save 명령어는 '스택' 메모리에 공간을 할당하는 명령어인데,
96만큼 스택포인터를 감소시킴으로서 96바이트의 스택 메모리를 할당하고 있다.
중요한 것은 save 명령어로 할당한다는 것, 스택 포인터를 '감소' 시킨다는 것이다.
그리고 save 명령어는 스택 공간을 할당하는 것 뿐만 아니라,
(SPARC 에서는) 32바이트의 레지스터도 새로 할당한다.
그래서 위 코드에서 o-register에 접근해 값을 담을 수 있는 것이다.
그런데 8바이트는 전역이니까 초기에만 할당될 것 같은데,
그렇다면 엄밀하게 save 실행할 때마다 새로운 32바이트 레지스터를 사용할 수 있게 되는건 아니지 않나?
할당한 스택과 레지스터를 다 사용했다면 restore 명령어로 반환해주면 된다.
이 명령어들의 자세한 내용은 나중에 추가적으로 정리하도록 하고,
지금은 이런 것들이 있구나 하는 소개 느낌으로만 정리하려고 한다.
(수업을 그렇게 해주셨기 때문에..)
다음에는 산술 연산과 논리 연산 명령어에 대해 정리하고,
Condition Code 에 대한 내용을 정리할 예정이다.
'CS > 어셈블리' 카테고리의 다른 글
[SPARC] 12. Unsigned/Signed Integer & Carry / Overflow (0) | 2023.10.06 |
---|---|
[SPARC] 11. 산술 연산과 Condition Code (0) | 2023.10.05 |
[SPARC] 9. Assembly Language Programming (0) | 2023.09.30 |
[SPARC] 8. SPARC Regsiter Window & Assembly Instruction Format (0) | 2023.09.27 |
[SPARC] 7. SPARC Architecture & Registers (0) | 2023.09.22 |