
%rsp는 현재 스택의 top을 가리킴.
main()에서 %rsp는 main의 프레임의 끝(최상단)을 가리킴.
호출 이전 상태를 기억해야 하므로, 이후 변경될 주소를 기준 삼음.

호출되면 %rsp는 아래쪽으로 감소(stack grows downward).
새로운 스택 프레임 생성.
함수의 리턴 주소 및 레지스터 저장값 등이 이곳에 저장됨.

foo() 안에서 foo2() 호출 시,
%rsp는 다시 감소하며 foo2의 프레임을 생성.
스택은 계속 아래로 쌓임.

함수가 ret 명령어로 종료되면 -> %rsp는 이전 위치로 복원됨.
해당 함수의 스택 프레임은 사라짐.

핵심 내용
pushq src는 데이터를 스택의 최상단에 저장하며, 동시에 %rsp 값을 감소시킴
스택은 주소가 감소하는 방향(아래 방향) 으로 자람
동작 요약
(1) %rsp를 8 감소시킴 (64비트 기준 → 8바이트 공간 확보)
(2) 확보된 위치(%rsp)에 데이터를 저장

Effective Operations (실제 실행되는 연산)
| 단계 | 명령어 | 설명 |
|---|---|---|
| Step 1 | subq $8, %rsp | 스택 공간 확보 (8바이트 감소) |
| Step 2 | movq src, (%rsp) | 확보된 위치에 src 값 저장 |
즉, pushq src는 위의 두 명령으로 분해됨.
스택 동작 (예: pushq $0x3026)
| 전 상태 | 동작 | 후 상태 |
|---|---|---|
| %rsp = 0xff20 | subq $8, %rsp 실행 | %rsp = 0xff18 |
movq $0x3026, (%rsp) | 0xff18 위치에 저장 |

내용
pop 명령어는 스택 최상단의 데이터를 꺼내어 목적지(dst)에 저장
그리고 %rsp를 8바이트 증가시켜 스택 포인터를 조정
스택에서 값을 “꺼낸다(remove from top of stack)“는 의미
1단계: movq (%rsp), dst // %rsp가 가리키는 값을 목적지에 복사
2단계: addq $8, %rsp // %rsp를 증가시켜 다음 스택 위치로 이동

예시
popq %rdx 는
(1) %rsp가 가리키는 주소(예: 0x3026)의 값을 %rdx에 복사
(2) 그 후 %rsp를 0xff18 → 0xff20으로 8바이트 증가
결과 흐름
값 이동 : 0x3026 → %rdx
스택 포인터 이동 : %rsp = %rsp + 8


Caller: 함수를 호출하는 함수 (ex. main)
Callee: 호출되는 함수 (ex. foo)
하나의 함수는 동시에 caller이자 callee일 수 있음
-> 예: foo()가 foo2()를 호출하면, foo()는 callee이면서 caller.

어셈블리에서 함수를 호출하면 현재 위치로 다시 돌아와야 함
(C 언어의 result = sum(a, b) 이후에 이어서 실행)
이를 위해 CPU는 프로그램 상태(state)를 저장함
저장 위치: Stack, Registers 사용
Caller 함수가 실행 중 Callee 함수를 호출하고, Callee가 끝난 후 돌아올 위치를 기억해야 함
%rip: 다음 실행할 명령어를 가리키는 Instruction Pointer
함수 호출 전 %rip 값을 Stack에 push
Callee 함수 실행 후 pop으로 %rip 복구 → Caller 위치로 복귀
함수 호출 시 기본 절차 (4단계)
(1) push: 호출 이후 돌아올 %rip 주소를 스택에 저장
(2) call: Callee 함수 실행
(3) pop: 완료 후 저장했던 주소를 %rip에 복구
(4) 계속 실행: Caller 함수 이후 명령부터 이어서 실행

내용
main 함수에서 foo 함수를 호출하는 예시.
호출 당시의 %rip 값(0x3021)은 현재 실행 중인 명령의 주소를 가리킨다.
이 주소는 호출 후 다시 돌아와야 하므로 스택에 저장된다.
%rsp는 스택의 top을 가리킴.

내용
foo 함수 호출 직전 다음 명령어의 주소인 0x3026을 스택에 push하여 저장함.
이때 %rsp는 8 바이트 감소하고, 해당 주소가 스택 top에 저장됨.

내용
%rip가 0x4058로 바뀌며 foo() 함수 실행 시작.
이전 복귀 주소 0x3026은 여전히 스택에 남아 있고 %rsp는 이를 가리키고 있음.

내용
foo()가 종료되면 스택에 있던 0x3026을 pop하여 %rip에 복원함. 이는 원래 main() 함수의 다음 실행 지점.

내용
%rip가 0x3026으로 복원되어 main()의 이어지는 명령어를 수행하게 됨. 함수 복귀가 정상적으로 이루어진 것.

내용
%rip는 이제 0x302B를 가리키며 함수 호출 이후의 main() 코드가 실행됨. 이는 함수 호출 전체 흐름이 정상적으로 완료되었음을 뜻함.
call 명령어는 다음 명령어의 주소를 스택에 push하고,
%rip을 호출할 함수의 시작 주소로 설정해 해당 함수로 점프한다.
즉, 현재 위치 저장 + 함수 진입이라는 두 단계를 수행.
ret 명령어는 스택의 최상단에서 주소를 pop하여
%rip에 넣고, 저장된 주소로 점프함으로써
호출자 함수로 복귀한다.
즉, 함수 실행을 마치고 호출했던 위치로 돌아감.

설명
%rip에는 401156 주소가 들어감 → 이는 foo() 함수의 첫 번째 명령어 주소
스택에는 401138 주소가 push 됨 → 이는 callq 다음 명령어(mov %eax, %edx)의 주소
결과
call 명령어는 복귀할 주소(다음 명령)를 스택에 저장하고,
%rip 값을 호출된 함수의 첫 명령어 주소로 바꾼다.
이후 retq가 실행되면 스택에서 주소(0x401138)를 pop하여 %rip에 복원한다.
따라서 foo() 실행 후 다시 mov %eax, %edx로 복귀하게 된다.

배열 a[100], 정수형 변수 i, n이 선언되어 있고, i = 3, n = a[i]가 실행됨.
이는 n = a[3]을 의미하며, 배열 인덱스 접근의 의미를 어셈블리로 구현하려는 목적

변수 i에 3을 저장하고, 이를 movslq 명령어로 %rax에 sign-extension을 포함해 64비트로 이동시킴.
즉 %rax = 3이 된다.

배열 요소의 크기인 4바이트를 고려하여, %rax 값을 왼쪽으로 2비트 시프트.
이는 3 * 4 = 12 바이트 offset이 계산된 것이다.
-> %rax = 12

배열 a의 시작 주소 1000에 offset 12를 더해 a[3]의 주소인 1012를 계산.
-> %rax = 1012

메모리 주소 1012 (a[3])에 저장된 값을 가져와 %r10d에 저장.
→ %r10d = a[3] = 123

%r10d에 있는 값을 메모리 상의 변수 n의 주소에 저장.
→ 메모리 주소 1404 (n)에 123 저장

%r10d에 있는 값을 메모리 상의 변수 n의 주소에 저장.
→ 메모리 주소 1404 (n)에 123 저장
Indirect Access mode

movl i, %eax
변수 i의 값을 %eax에 저장함
이 예제에서 i = 3이므로 %eax = 3

sall $2, %eax
%eax 값을 왼쪽으로 2비트 시프트함 → 곱하기 4
즉, i 4 = 3 4 = 12가 되어, 배열 인덱스 바이트 주소 계산됨
%eax = 12

movl a(,%eax), %r10d
a는 배열의 시작 주소 (0x1000)
a(,%eax)는 a + %eax → 1000 + 12 = 1012
a[3]의 값인 123을 %r10d에 저장
%r10d = 123

movl %r10d, n
%r10d 값을 변수 n에 저장함
n = 123

메모리 주소 1404 (변수 n)에 123이 저장됨
전체 흐름: n = a[i] 수행 완료됨
일단, 중간고사 범위 끝...