JUNGLE 240405 ~ 240406 (W03)
KRAFTON JUNGLE Week 03
1. CS:APP
기계수준 코드
- 프로그램 카운터
- 실행 할 다음 인스트럭션의 메모리 주소를 가리킨다.
- 정수 레지스터 파일
- 64비트 값을 저장하기 위한 16개의 이름을 붙인 위치를 가짐
- 이 레지스터는 주소나 정수 데이터를 저장할 수 있음
- 조건코드 레지스터
- 가장 최근에 실행한 산술 또는 논리 인스트럭션에 관한 상태 정보 저장
- 이들은
if
나while
문을 구현할 때 필요한 제어나 조건에 따른 데이터 흐름의 변경을 구현하기 위해 사용
- 백터 레지스터
- 하나 이상의 정수나 부동 소수점 값들을 각각 저장할 수 있음
어셈블리어 코드 & 기계어 코드
code.c
- C 코드
#include <stdio.h>
int sum(int x, int y)
{
int t = x + y;
return t;
}
int main()
{
return sum(2, 5);
}
code.s
- 어셈블리어 코드
✔ sum
함수
.globl _sum ## -- Begin function sum
.p2align 4, 0x90 ## 코드를 16byte 경계에 맞춤 -> 메모리 엑세스 성능 향상
_sum: ## @sum 함수 시작
.cfi_startproc ## CFI 시작!!
## %bb.0:
pushq %rbp ## 베이스 포인터 레지스터인 %rbp를 스택에 저장
.cfi_def_cfa_offset 16 ## 현재의 CFA 오프셋을 16byte로 설정
.cfi_offset %rbp, -16 ## 레지스터의 오프셋을 -16으로 설정
movq %rsp, %rbp ## 스택 포인터 레지스터(%rsp)의 값으로 베이스 포인터 레지스터(%rbp) 설정
.cfi_def_cfa_register %rbp ## CFA 레지스터를 %rbp로 설정
## kill: def $esi killed $esi def $rsi
## kill: def $edi killed $edi def $rdi
leal (%rdi,%rsi), %eax ## 인자로 받은 두 개의 정수를 더하여 결과를 %eax 레지스터에 저장
popq %rbp ## 스택에 저장된 베이스 포인터 레지스터의 값을 복원
retq ## 함수를 반환하고 호출자로 돌아감
.cfi_endproc ## CFI 종료
## -- End function
✔ main
함수
.globl _main ## -- Begin function main
.p2align 4, 0x90 ## 코드를 16byte 경계에 맞추도록 함
_main: ## @main 함수 시작
.cfi_startproc ## CFI 시작!!
## %bb.0:
pushq %rbp ## 베이스 포인터 레지스터인 %rbp를 스택에 저장
.cfi_def_cfa_offset 16 ## 현재의 "CFA:L Canonical Frame Address" 오프셋을 16byte로 설정
.cfi_offset %rbp, -16 ## 레지스터의 오프셋을 -16으로 설정
movq %rsp, %rbp ## 스택 포인터 레지스터(%rsp)의 값으로 베이스 포인터 레지스터(%rbp) 설정
.cfi_def_cfa_register %rbp ## CFA 레지스터를 %rbp로 설정
movl $7, %eax ## 상수값 7을 %eax 레지스터에 저장
popq %rbp ## 스택에 저장된 베이스 포인터 레지스터의 값을 복원
retq ## 함수를 반환하고 호출자로 돌아감
.cfi_endproc ## CFI 종료
## -- End function
code2.c
- C 코드
#include <stdio.h>
int main()
{
int x = 2;
int y = 5;
int t = x + y;
return t;
}
code2.s
- 어셈블리어 코드
✔ main
함수
.globl _main ## -- Begin function main (함수 전역 선언)
.p2align 4, 0x90 ## 16바이트 경계로 정렬
_main: ## @main 함수 시작
.cfi_startproc ## CFI 시작!!
## %bb.0:
pushq %rbp ## 스택에 현재 베이스 포인터 레지스터를 저장
.cfi_def_cfa_offset 16 ## 현재의 CFA 오프셋을 16byte로 설정 (스택 프레임 크기 지정)
.cfi_offset %rbp, -16 ## 레지스터의 오프셋을 -16으로 설정
movq %rsp, %rbp ## 스택 포인터 레지스터의 값으로 베이스 포인터 레지스터 설정
.cfi_def_cfa_register %rbp ## CFA 레지스터를 %rbp로 설정
movl $0, -4(%rbp) ## -4(%rbp) 위치의 지역 변수를 0으로 초기화
movl $2, -8(%rbp) ## -8(%rbp) 위치의 지역 변수를 2로 초기화
movl $5, -12(%rbp) ## -12(%rbp) 위치의 지역 변수를 5로 초기화
movl -8(%rbp), %eax ## -8(%rbp) 위치의 값, 2를 %eax 레지스터에 로드
addl -12(%rbp), %eax ## -12(%rbp) 위치의 값, 5를 %eax 레지스터에 로드
movl %eax, -16(%rbp) ## 레지스터에 저장된 값을 -16(%rbp) 위치에 있는 지역 변수에 저장
movl -16(%rbp), %eax ## -16(%rbp) 위치에 있는 값을 %eax 레지스터로 불러오는 작업
popq %rbp ## 현재 함수의 스택 프레임을 제거하고 이전 스택 프레임으로 복귀
retq ## 함수를 반환하고 호출자로 돌아가는 역할
.cfi_endproc ## CFI 종료
## -- End function
추가 설명
✔ CFI (Call Frame Information)
- 디버깅 및 예외 처리와 관련된 정보를 포함하는 메타 데이터
- 스택 프레임의 구조와 함수 호출 및 복귀에 대한 정보 제공
- 보통 디버거나 예외 처리 런타임과 같은 도구들이 사용하는 데 도움이 됨
✔ CFA (Canonical Frame Address)
- 현재 함수의 스택 프레임(함수가 호출될 때 생성되는 메모리 공간)의 시작을 가리키는 값
- 스택 프레임의 위치를 정확히 지정하기 위해 사용
- CFI에서 CFA를 사용하여 함수 호출 및 복귀에 필요한 스택 프레임의 구조를 정의
✔ 스택 프레임 설정 과정
pushq %rbp
:%rbp
- 스택 프레임의 시작을 표시.cfi_def_cfa_offset 16
: 스택 프레임의 크기 설정.cfi_offset %rbp, -16
:%rbp
가 스택의 상대적 위치에서 16byte 떨어져 있음movq %rsp, %rbp
:%rbp
에 현재 스택의 상단을 가리키는%rsp
의 값을 복사하여 새로운 스택 프레임의 위치 설정.cfi_def_cfa_register %rbp
: 스택 프레임의 위치를 가리키는 값을%rbp
로 설정
✔ 함수 반환 과정
leal (%rdi,%rsi), %eax
:leal
(Load Effective Address) - 주소를 계산하고 해당 주소에서 값을 로드하는 명령어popq %rbp
: 이전에 설정된 스택 프레임으로 돌아가는 과정 (스택에 저장된%rbp
값을 스택에서 꺼내어 레지스터에 복원)retq
: 이전에 함수를 호출한 곳에 저장된 복귀 주소를 사용하여 반환.cfi_endproc
: 해당 함수의 CFI 정보가 종료되었음을 나타냄
어셈블리 언어
접미사
b
(바이트): 8비트w
(워드): 16비트l
(더블 워드): 32비트q
(쿼드 워드): 64비트
주요 레지스터들
- 확장 누산기 레지스터
%eax
: 일반적으로 정수 연산에 사용되며, 함수의 반환값을 저장하는 데 사용 (32bit) - 누산기 레지스터
%rax
: 일반적인 계산, 특히 64비트 연산에 사용되며, 시스템 호출의 반환값 처리에도 사용 (64bit) - 스택 포인터 레지스터
%rsp
: 현재 스택의 최상단을 가리키며, 함수 호출과 반환, 로컬 변수 할당 등에 사용 (64bit) - 데이터 레지스터
%rdx
: 특히 나눗셈 연산에서 나머지를 저장하거나 시스템 호출에서 추가 인자 전달에 사용 (64bit) - 데이터 레지스터의 하위
%dx
: 특정 상황에서 16비트 연산에 사용되며, 호환성을 위해 남아있음 (16bit) - 데이터 레지스터의 하위
%dl
: 주로 8비트 데이터 처리와 논리 연산에 사용 (8bit) - 베이스 레지스터
%rbx
: 데이터 저장 및 연산에 사용되며, 메모리 주소 지정에 주로 사용 (64bit) - 베이스 레지스터의 하위
%bl
: 주로 데이터 처리와 논리 연산에 사용 (8bit)