주소지정·스택·호출
즉시·직접·간접·레지스터·상대 주소지정을 계산하고 스택과 반환 주소의 역할을 추적합니다.
명령에 숫자 100이 써 있어도 “값 100을 더하라”와 “주소 100의 값을 더하라”는 다릅니다. 주소지정 방식은 피연산자의 값을 어디서 어떻게 찾을지 정한 규칙입니다. 먼저 값 자체와 값의 위치를 분리하세요.
유효 주소 계산
아래에서는 R1=100, R2=3, M[100]=40, M[40]=9, PC=200입니다. 유효 주소(EA)는 최종적으로 접근할 데이터 주소입니다. 모든 명령이 아래의 모든 방식을 지원하는 것은 아닙니다.
| 방식 | 교육용 표기·규칙 | 얻는 값 |
|---|---|---|
| 즉시 | #100: 명령의 값 자체 | 100 |
| 직접 | [100]: EA=100 | M[100]=40 |
| 간접 | [[100]]: EA=M[100]=40 | M[40]=9 |
| 레지스터 | R1 | 100 |
| 레지스터 간접 | [R1]: EA=R1 | 40 |
| 베이스+변위 | [R1+4]: EA=104 | M[104]의 값 |
| 인덱스 | [base+index×크기] | 배열 원소의 값 |
| PC 상대 | EA=정의된 PC 기준+변위 | 기준에 따른 목적지 |
PC 상대의 기준이 현재 명령인지 다음 명령인지는 ISA마다 확인해야 합니다. 여기서는 현재 명령 주소 200에 변위 -12를 더해 188이라고 정의합니다. 앞 절의 모델은 인출 후 PC를 증가시키므로 같은 변위 규칙을 무심코 섞으면 한 명령 차이 오류가 생깁니다.
배열·스택으로 주소지정이 필요한 이유 이해하기
4바이트 원소 배열이 주소 100부터 있으면 index=3의 주소는 100+3×4=112입니다. index 자체를 3바이트로 더하지 않습니다. 스택은 나중에 넣은 것을 먼저 꺼내는 LIFO 저장 방식입니다. CPU 호출에서는 인수·지역 변수·보존 값·반환 주소 등을 저장하는 데 사용할 수 있습니다.
이 교육용 스택은 빈 상태 SP=64, 4바이트 항목 하나를 push할 때 SP를 4 감소시킨 뒤 그 주소에 쓰고, pop할 때 읽은 뒤 SP를 4 증가시킵니다. 실제 ABI의 스택 방향·정렬·호출 규약은 별도로 확인합니다.
| 동작 | SP | 관련 상태 |
|---|---|---|
| push 10 | 60 | M[60]=10 |
| push 20 | 56 | M[56]=20 |
| pop | 60 | 꺼낸 값 20 |
| pop | 64 | 꺼낸 값 10 |
함수를 호출하려면 함수로 이동하는 것뿐 아니라 어디로 돌아올지도 저장해야 합니다. 반환 주소는 호출 뒤 이어서 실행할 위치입니다. 중첩 호출에서 하나의 전역 반환 주소만 덮어쓰면 바깥 호출의 복귀 위치를 잃습니다. 스택이나 규약에 따른 레지스터 보존이 필요합니다.
독립 문제: 한 번 읽기와 두 번 읽기
R1=24, M[24]=40, M[40]=7입니다. R1·[R1]·[[R1]] 각각의 값을 구하고 데이터 메모리를 몇 번 읽는지 쓰세요. 2바이트 원소 배열의 시작 주소가 80일 때 인덱스가 5인 원소(index=5)의 주소도 계산하세요.
힌트
대괄호가 한 겹 늘 때마다 주소를 따라갑니다. 원소 번호와 바이트 주소는 단위가 다릅니다.
풀이
R1=24는 메모리 읽기 0회, [R1]=40은 1회, [[R1]]=7은 2회입니다. index=5 주소는 80+5×2=90입니다. “레지스터 안에는 언제나 데이터 값”도 맞지 않습니다. 레지스터의 24를 주소로 사용하면 포인터 역할을 합니다.
호출 흐름이 헷갈리면 PC·저장 대상을 다시 추적하세요. 다음 메모리 계층에서는 같은 주소 접근이라도 데이터가 어느 계층에 있는지에 따라 비용이 달라지는 이유를 봅니다.