Lecture/24-2 시스템SW실습

MIPS 함수 호출 규약 이해하기

selfdevelop 2024. 10. 14. 22:14

핵심1. Stack의 구조를 이해한다. (Feat. $sp, $fp)

핵심2. Return address에 대해 이해한다.

핵심3. jal 명령어를 이해한다.


핵심1: Stack의 구조를 이해한다. (Feat. $sp, $fp)

 

명제1: Stack은 높은 주소에서 낮은 주소로 자란다. 

데이터를 할당할 때는 $sp를 낮은 주소로 이동시킨다 (-)

데이터를 삭제할 때(엄밀히 말하여, 덮어쓸 수 있도록 만들 때)는 $sp를 높은 주소로 이동시킨다 (+)

 

명제2: $sp는 가장 최근에 삽입한 stack의 위치를 저장하는 레지스터이다. 즉, 계속 변화한다. PC 레지스터와 대응하는 개념이다

(단, $sp는 dynamic-stack 영역에, pc는 code(text) 영역에 위치한다)

stack에 값이 저장되는 모습


 

핵심2: Return address에 대해 이해한다.

 

가정1: A 함수가 B함수를 호출하였다. 이때, A함수는 caller고 B함수는 callee이다.

 

명제1: return address, 즉 어떤 함수의 복귀 주소는 어떤 함수가 실행 완료된 후, 다시 돌아가야할 주소이다.

B가 실행 완료된 후, 실행되야할 코드는 A함수가 B함수를 호출한 명령어의 바로 다음 명령어이다.

따라서 B함수의 retrun address는 A함수 내부의 명령어를 가리킨다.


핵심3. jal 명령어를 이해한다.

 

명제1: A함수는 B함수를 호출할 때, jal(jump and link) instruction을 수행한다.

jump - PC 레지스터가 B함수가 시작하는 주소를 가르키게 한다

link - 현재 PC 레지스터가 가리키는 주소(=B함수를 호출하는 명령어)에 + 4bytes를 한 값, 즉 다음 명령어의 주소를 $ra에 저장

 

핵심 2의 명제 1에 따라, 이 주소는 B함수가 실행 완료된 후에 돌아가야 할 주소이다.

 

가정2: 가정 1에 이어, B함수가 C함수를 호출한다. 

만약, B함수가 jal 명령어를 수행할 경우, $ra에 저장되어있던 B의 복귀 주소는 overwritten되어 사라진다.

이를 방지하기 위해, Non-leaf 함수의 경우, $ra를 Stack에 저장해야한다. (아닐 경우, 저장하지 않는다)

저장 시점은 B함수가 호출된 직후이며, $ra에 저장된 B의 복귀 주소를  Stack에 저장한다.


(핵심 1에 이어...)

*Stack Frame: 임의의 함수에서 선언된 Stack 공간

 

핵심 2, 3에서 다룬 함수의 복귀 주소는 code(text) 영역에서의 PC 레지스터 값의 보존을 다루고 있다.

$sp 레지스터는 PC 레지스터와 대응하므로, $sp 레지스터의 값 역시 함수의 호출 과정에서 보존되어야함을 이해할 수 있다.

(PC 레지스터가 이동하기 위해서는 Stack 영역에 저장된 복귀 주소를 알아야하는데, 이를 위해 $sp 값의 보존이 필요하다)

현재 위치 PC $sp
보존값 $ra = pc + 4 $fp = $sp (함수 호출 직후., 스텍 프레임의 시작 위치)
저장하는 값 명령어의 위치 stack의 위치
non-leaf의 경우 stack stack

Chat GPT: MIPS에서 함수를 호출할 때 스택영역에 저장되는 값들을 순서대로 설명한다

스택에 저장되는 값의 순서 (함수 호출 시)

  1. ra (Return Address 레지스터)
    • 함수 호출 이후 복귀할 주소를 보존합니다.
    • jal(Jump And Link) 명령어는 호출된 함수가 끝나면 되돌아올 주소를 ra 레지스터에 저장합니다.
    • 함수가 재귀적으로 호출되거나 다른 함수에서 또 다른 함수를 호출할 때, 이전 복귀 주소를 스택에 저장해야 합니다.
    • 스택에 저장: sw $ra, 0($sp)
  2. fp (Frame Pointer 레지스터)
    • 프레임 포인터는 현재 스택 프레임의 시작 위치를 가리킵니다.
    • 여러 함수 호출이 중첩될 경우, 각 함수의 스택 프레임을 쉽게 추적하기 위해 fp 값을 스택에 저장합니다.
    • 스택에 저장: sw $fp, -4($sp)
  3. 저장할 레지스터들 (s0 ~ s7)
    • 만약 함수 내부에서 **저장 레지스터($s 계열)**를 사용한다면, 원래 값이 덮어쓰이지 않도록 스택에 저장합니다.
    • 스택에 저장: 예를 들어, $s0 레지스터는 sw $s0, -8($sp)에 저장합니다.
      (필요한 모든 저장 레지스터들을 동일한 방식으로 보관합니다.)
  4. 함수의 매개변수
    • 함수에 전달된 인자는 첫 4개가 $a0 ~ $a3 레지스터에 저장됩니다. 만약 4개를 초과하는 인자가 있으면, 스택에 저장합니다.
    • 스택에 저장: sw $a4, -12($sp) (4번째 이후 인자)
  5. 지역 변수(Local Variables)
    • 함수 내부에서 선언된 지역 변수들도 스택에 저장됩니다. 크기에 따라 스택의 적절한 위치에 배치합니다.
    • 예: sw $t0, -16($sp) (임시로 사용되는 지역 변수)

스택 프레임 구조

|----------------------|
|  지역 변수           |  -> 더 아래쪽 (낮은 주소)
|----------------------|
|  초과 매개변수       |
|----------------------|
|  저장된 s0~s7        |
|----------------------|
|  이전의 fp (frame pointer) |
|----------------------|
|  ra (return address) |
|----------------------|