JUNGLE 240405 ~ 240406 (W03)

KRAFTON JUNGLE Week 03

1. CS:APP

기계수준 코드

  1. 프로그램 카운터
    • 실행 할 다음 인스트럭션의 메모리 주소를 가리킨다.
  2. 정수 레지스터 파일
    • 64비트 값을 저장하기 위한 16개의 이름을 붙인 위치를 가짐
    • 이 레지스터는 주소나 정수 데이터를 저장할 수 있음
  3. 조건코드 레지스터
    • 가장 최근에 실행한 산술 또는 논리 인스트럭션에 관한 상태 정보 저장
    • 이들은 ifwhile문을 구현할 때 필요한 제어나 조건에 따른 데이터 흐름의 변경을 구현하기 위해 사용
  4. 백터 레지스터
    • 하나 이상의 정수나 부동 소수점 값들을 각각 저장할 수 있음

어셈블리어 코드 & 기계어 코드

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)