Post

컴구(1)

컴퓨터구조

risc-v의 instruction에 대해 알아보도록 하겠습니다. 근데 새삼 느낍니다. 문명의 발전이 대단하다는 것을요.

high-level 언어를 컴파일러와 어셈블러가 번역합니다. 이를 메모리에 올리고 CPU가 실행하는 구조가 전반적인 프로그램의 흐름인데, 프로그래밍 언어론에선 컴파일러의 간략한 이론, 운영체제에선 CPU와 OS에 대해, 컴퓨터구조에선 어셈블리어 및 컴퓨터의 전반적인 구조를 배웁니다. 제가 다 수강하는 과목입니다. 컴퓨터는 정말 유기적인 구조체 같습니다. 위대한 학자 폰 노이만이 새삼 대단하게 다시 보입니다.

산술 연산

산술 연산의 기준이 있습니다.

  1. 간단하게
  2. 작게 1.Design Principle 1: Simplicity favors regularity Regularity makes implementation simpler Simplicity enables higher performance at lower cost

함수 호출

함수를 호출하는 상황을 가정해보겠습니다.

1
2
3
4
5
6
1. 먼저, 레지스터에 매개변수를 넣고
2. 호출하고자 하는 함수를 호출합니다. 이 때, 돌아올 주소를 저장해야 합니다.
3. 호출된 함수를 메모리에 올리고,
4. instruction을 차례로 수행합니다.
5. 결괏값을 register에 넣어 반환합니다. 이 때 스택 포인터를 사용했다면, 복원해줘야 합니다.
6. 호출을 시작한 다음 명령어로 이동합니다.

이러한 흐름으로 함수가 호출됩니다. 이 때, risc-v에선 jal(jump and link) 혹은 jalr(jump and link register) instruction을 사용합니다.

jal

jal(jump and link)는

1
jal rd, label 

형태로 작성됩니다. 현재 내가 읽던 명령어의 다음 명령어 주소를 rd에 저장하고, label로 점프합니다. 이름을 직관적으로 잘 지었습니다. rd를 지정하지 않으면, ra 레지스터에 자동으로 다음 명령어 주소가 저장됩니다. 암묵적인 룰입니다.

jalr

jalr(jump and link register)은 label로 바로 접근하는 것이 아닌, 레지스터에 저장된 메모리 주소로 이동합니다.

1
jalr rd, (register) # offset 형태로 (register)을 작성합니다.

rd에 현재 명령어 다음 명령어 주소가 저장됩니다.

함수 호출 후

함수가 호출되면 호출 된 함수(callee)가 연산을 해야합니다. 메모리에서 값을 읽어오고, 이를 레지스터에 저장 후, 연산을 합니다. 하지만 부른 함수(caller)입장에서, 함수 호출 후 자신이 사용하던 레지스터의 값이 바뀌면 이후 연산에 영향을 줍니다. 따라서, callee는 caller가 사용하던 레지스터를 보존해야 할 필요가 있습니다. 그 댓가로, callee에겐 자유롭게 사용할 수 있는 몇 개의 레지스터를 줍니다.

레지스터

그에 앞서, 레지스터에 대해 알아봅시다. 레지스터는 CPU에서 연산을 수행하기 위해 값을 저장해두는 임시저장장치입니다. 레지스터에는 각 번호가 있고, 그 번호에 따라 각자 다른 기능을 합니다. 즉, CPU는 레지스터가 각자 지정된 기능을 수행하도록 만드는 것입니다. 간략하게 레지스터에 대해 알아봅시다.

1
2
3
4
5
6
7
8
9
10
x5~x7, x28~x31 : callee가 마음대로 사용해도 되는 레지스터. caller saved라고 합니다.
x8~x9, x18~x27 : callee가 사용을 한다면, 반드시 복원해야 하는 레지스터. 복원하지 않으면 caller의 연산이 방해받습니다. 
callee saved라고 부릅니다.
x0 : constant zero입니다.
x1 (ra) : return address를 저장합니다. 이는 caller가 saved해야 합니다.
x2 (sp) : stack pointer를 저장합니다. 이는 callee가 saved해야 합니다.
또한, x12~x17번 레지스터는 함수 호출 시, 매개변수로 사용됩니다.
x10~x11은 return 값을 저장합니다.
만약 매개변수가 부족하다면, x10~x11도 사용합니다. 
x5~x7, x28~x31은 temp(임시 저장)로 사용됩니다.

간략하게 살펴보았습니다. 한 번 callee saved(callee가 보존해야 할 레지스터)와 caller saved(caller가 보존해야 할 레지스터)를 정리해봅시다!

1
2
3
caller saved : x1 (ra), x5~x7, x10~x17 , x28~x31 (호출한 함수는 이를 잃어버리면 안됩니다. callee는 이 레지스터를 사용해도 됩니다!)
(왜냐하면 함수 호출 시, 호출하는 함수는 이를 stack에 저장하고, 함수를 호출하기 때문입니다.)
callee saved : x2, x8~x9, x18~x27 (호출된 함수는 이를 복구해야 할 의무가 있습니다.)

로 정리할 수 있습니다. 그리고 현재 risc-v arcitecture를 기반으로 글을 작성하는데, risc-v는 little endian 기반 memory byte addressing입니다.

[링크 : Big과 little Endian에 대한 자세한 설명을 보시려면 클릭하세요!]

image

image

image

https://gofo-coding.tistory.com/entry/2-MIPS-Compile-Link-Run 이 블로그가 야무지네!

심볼 테이블? 변수(심볼)의 scope 타입.. 등 기입함.

다음 포스팅 내용 : 위치 종속성!

This post is licensed under CC BY 4.0 by the author.