Post

2. ISA

2. ISA

Compiling C program

C-code는 다음의 순서로 메모리에 올라간다.

  1. Compile

→ Compiler가 C코드를 최적화 후 어셈블리어로 변환한다. (*.s)

  1. Assemble

→ Assembler가 어셈블리어를 기계어 (object file)로 변환한다. 이 때부터 ISA에 따라 달라진다.

  1. Linker

→ object file에는 군데군데 값들이 비어있다. 외부 코드라든지 라이브러리 Object는 빈칸으로 assemble되었는데 이를 linker가 link해준다. exe 파일이 만들어진다.

  1. Loader

→ 이렇게 만든 binary file을 program-visible memory에 loader가 올려주는 역할을 한다.

ISA

Instruction Set Architecture는 하드웨어와 소프트웨어 사이의 인터페이스이며다. 레지스터, instruction set, data type, memory address model 등이 주요 구성요소이며, RISC기반과 CISC기반으로 나뉘며 x86, ARM, MIPS등이 이에 해당한다.

Object file and Static Linking

C코드가 어셈블리어로 각각 변환되고, 이 코드가 어셈블러에 의해 각각 object file로 변환된다.

object file은 이때 relocatable object files라고 불리며 .text와 .data, (와 .bss 등등…)을 만든다.

이렇게 여러개로 만들어진 object file은 다음과 같은 특성을 가짐

(1) Separately compiled: 각 c code는 파일 따로따로 컴파일된 후 link됨

(2) Relocatable: 각 object file은 순서가 바뀌어도 됨. 독립적인 주소 공간을 가지지 않고 상대적 주소를 가지기 때문에, 순서가 아직 정해지지 않음. 이름으로 써있음. (Linker에 의해 정해짐) 이는 주소충돌 방지 및 OS가 적절히 메모리에 로드하기 위해서임.

If 백만 entries array → object file이 엄청 커진다. (data 파일)

Loading (실행, 그런데 가짜 컴퓨터를 곁들인…)

가짜 컴퓨터, 즉 아키텍쳐에 따라 virtual memory 상에 text, data룰 넣고 stack과 heap 영역을 할당한다.

만약 32-bit 컴퓨터 ⇒ address space가 32-bit ⇒ 2^32 개의 address.

⇒ 2^32 * 1byte = 4GB 가상 메모리.

Stack

내가 쓴 코드가 모두.text에 있도록하면 깔끔. 우리는 같은 코드가 돌아도 보고 있는 데이터가 다를 수 있기 때문에, function call, return은 이와 같이 구현할 수 없다. Stack을 이용하여 함수가 stack 구조로 call되고 return 되는 것을 구현한다.

함수를 call하고 return할때 순서는 다음과 같다.

  1. esp를 키우기 전에 return address를 push한다. (CPU가 알아서 다음 instruction의 주소를 저장)
  2. 현재 ebp 주소를 push한다.
  3. ebp를 esp의 값으로 같게 만든다.
  4. esp의 크기를 stack function frame 크기만큼 늘린다.
  5. stack frame내에서 local variable 등등을 쓰며 함수를 실행

  1. esp를 ebp로 옮긴다.
  2. old ebp 값을 ebp로 바꾼다.
  3. pop을 하여 return address만큼의 주소를 eip (PC)에 넣는다.

그 외에도 100개 array 등 동적 할당을 위한 공간이 있는데 이것을 Heap이라고 한다. Heap도 Malloc, free를 통해 이용할 수 있으며, 이는 시스템 프로그래밍에서 자세히 배웠으니 지금은 넘어가도록 한다.


Architecture

가짜 컴퓨터를 정의해놓고 프로그래머에게 보이는 특성들을 설명해놓은 것이다.

conceptual structure (virtual memory, stack, register 등), functional behavior (이렇게 작동한다는 서술한 것. 빠르다 X) 를 정의해놓고 어떻게 사용할지 프로그래머에게 보여지는 회로. 밑에 부분은 알 필요 없음

→ Microarchitecture와 architecture을 정의해놓는다. 작동방식을 잘 정의해서 운전자에게 오른쪽으로 가는 법. 엑셀 밟는 법 등을 알려준다. 마이크로아키텍쳐는 메모리가 파워를 덜 먹는다, 빠르다 등 프로그래머가 알 필요 없는 부분이다.

캐시는 성능을 올리기 위해 만들어진 것이므로 마이크로아키텍쳐. OS와 컴파일러는 모른다.


Programmer Visible State

프로그래머에게 보이는, 아키텍쳐 상의 상태 (architectural state)

PC: 현재 실행되고 있는 instruction의 주소

Instruction은 각 programmer visible state에 있는 값들을 어떻게 바꿀지 알려주는 역할을 한다.

→ 가짜 컴퓨터가 정의만 되면, 내 프로그램이 컴파일되고 어셈블되어 object가 되고 linking되고 load되어 메모리 상에 올라가고 PC를 바꿔가며 하나씩 실행할 수 있을 것이다!


Stored Program Architecture (von Neumann)

  • Instructions는 메모리에 linear하게 memory array에 저장된다.
  • Instruction도 데이터와 같이 메모리 상에 올라간다.
  • Insturction도 data처럼 수정될 수 있다.

Sequential Instruction Processing

  • PC가 지금 하고 있는 명령을 저장하고 있다.
  • 각 명령은 메모리로부터 fetch된다
  • PC가 변경된다.

Dataflow..?

폰 노이만 구조는 메모리에서 Insturction을 가져오는 시간에 bottleneck이 생긴다.

즉, 모든 회로를 보고 모든 instruction을 딱 보고 데이터의 흐름을 구현한다.

→ 새로운 프로그램이 나오면 망한다. 유연성이 매우 떨어진다.


Instruction Set Architecture (ISA)

그래서 ISA가 뭔데?

이 아키텍쳐를 쓰려면 이렇게이렇게 써야합니다~ 정리해놓은 매뉴얼

다음을 정의한다.

  • 데이터 포맷, 사이즈 (4 byte is WORD…, Integer is 8 byte…)
  • Programmer visible state: register, PC, memory…
  • Instructions: 어떻게 programmer visible state를 바꿀 것인가.
    • operand가 무엇인지

General Instruction Class

(1) Arithmetic & Logical operations (add, sub, shiftm or…)

  • Fetch operands
  • Compute results
  • Store result to specified location
  • update PC

(2) Data movement operations(move, load, store)

  • Fetch operands and location
  • Store values to location
  • Update PC

(3) Control flow operation

  • Fetch operands
  • Compute branch condition and target address
  • If condition holds, go to target address.

⇒ Defined atomic.


FYI: Early ISA

Single accumulator

  • An : add Mn nto ACC
  • Tn: transfer data (store)
  • En: if ACC>-1, jump
  • In: read next character
  • Z: stop machine

⇒ Register가 ACC하나 밖에 없어서 불편함.

Why we need many registers?

→ To make function work. array access in a loop.

  1. In early tape-based ISA, 한 함수가 여러번 호출되면 다시 돌아갈 return address를 특정하지 못해 무한 루프를 돈다. 매개변수와 지역변수를 메모리에 저장해야함.
  2. 하나의 배열을 여러번 접근하고 싶다. 인덱스 레지스터가 없어서, 매번 인덱스를 불러올때마다 메모리에 접근했어야한다. 매우 느림.
작업현대 CPU (레지스터 활용)EDSAC (레지스터 부족)
Function CallStack Pointer로 Return Address 저장, 빠른 복귀메모리에 Return Address 저장해야 해서 느림
Array AccessIndex Register로 빠른 주소 계산매번 메모리에서 주소 계산해야 해서 느림

명령에 숫자가 박혀있으니 불편.

→ Wee need general purpose register (GPR)

메모리가 멀리 있을수록 느려지기 때문에, 32비트의 작고 빠른 레지스터 32개를 만들어놓는다.


FYI: Architecture for OS

→ 프로그램당 각각 아키텍처 하나가 만들어져야함.

같은 실행파일이라도 다르게 실행하면 OS 입장에서는 독립적으로 돌아가야함.

OS에게는 내가 한번에 실행시킬 수 있는 아키텍쳐의 개수가 주어짐.

→ CPU가 어떻게 만들어졌는지는 모르고, architectural state를 설정한다. 1초 - 1초 - 실행하며 각각 저장한다.

이를 context switching이라고 한다.

즉, context switching은 OS에게 보이는 아키텍쳐의 수를 보고, scheduling하며 동시에 돌리는 것처럼 보이도록 하는 것이다.

넣다 뺐다를 빠르게 하면 프로그램들이 하나의 코어에서 여러개가 동시에 돌아가는 것처럼 보임. → Multitasking


MIPS RISC

  • Number of operands: MIPS는 3개

  • ALU operand가 memory가 될 수 있는가

    • CISC - 가능. 명령어 하나가 파워풀하다.
      • 옛날에는 어셈블리어를 사람이 짜서, 명령어 개수가 적은게 좋았음.
      • 더하기와 곱하기의 명령어 byte 길이가 다르다.
    • RISC - 불가능. Load-Store architecture라 load와 store만 메모리를 건드릴 수 있다.
      • 좀 더 단순하고 책임을 분리할 수 있다.
      • 명령어 개수가 많아진다.
      • 무조건 명령어가 4 byte이다.

    ⇒ 단순한 code, 회로를 단순하게 만들 수 있어 frequency를 올릴 수 있고 빠르게 만들 수 있다.

    • Simple branches
      • limited varieties

    ## Why Intel still CISC?

    (1) Binary compatiblity

    • 게임 등은 이미 컴파일 된 결과
    • 따라서 교차 실행이 가능하게 하기 위해서.

    (2) 왜 빠른가

    • CISC 명령은 하드웨어가 RISC로 바꿔주고 있음.
    • x86도 내부적으로 RISC 머신이다. AMD도 RISC 머신이다. → 물론 이 내부적인 머신은 다르지.

    ### FYI: How to design ISA?

    • General purpose: 하드웨어 낭비
    • Strict program compatiblity: 표준을 지키면 다 쓸 수 있도록 하자. 아키텍쳐의 개념이 처음 등장.

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