(cf. intel의 x86-64 cpu의 assembly를 기준으로 진행.)

※  Assembly란? 

기계어와 1:1 대응관계를 갖는 명령어의 집합체로 low-level 프로그래밍 언어이다.

- 물론 고급언어의 경우, 안전하고 편리하며 컴파일러를 통해 더 훌륭한 어셈블리 프로그램생성이 가능할지도 모른다.

assembly High-level Language
-대형 프로그램 개발이 불편

-속도가 중요한 응용프로그램, 하드웨어 직접 제어 시 이용

-임베디드 시스템의 초기코드 개발 시 이용

-플랫폼에 따라 새롭게 작성해야 해 이식성이 매우 낮음

-하지만 많은 간접적인 응용이 있음

- 배열이나 구조체 없이 메모리에서 연속적 byte들로 표시
-대형 프로그램 개발하기 매우 편함

-이식성이 높음 (high portability)

-비효율적 실행파일의 생성가능성이 존재

-대형 실용 응용프로그램 개발 시 이용

 

 

※  x86 processor

1978년부터 시작되어 점점 새로운 기능들을 추가하였지만, 예전의 기능들을 그대로 유지해 접근이 가능하다.

이런 intel의 철학은 바로 CICS (Complex Instruction Set Computer)로 다양한 형태의 명령어를 갖는다.

- EIP: 다음 명령어를 fetch해오는 주소 program counter

- Register File: Register의 집합

- Condition Code: 가장 최근 연산의 결과의 상태정보를 저장

- Memory: byte주소 지정가능한 배열로 명령어, data가 저장되며 stack이 존재한다.

 

 

※  x86-64의 정수 register

x86-64 processor(CPU)는 64-bit 값을 저장할 수 있는 16개의 register가 존재한다.

이들은 정수 데이터와 포인터를 저장하는 데, 포인터의 경우 주소를 저장하는데 사용합니다.

rsp, rbp와 같이 p로 끝나는 register의 경우가 바로 포인터를 사용해 주소를 저장하는 register이다.

이 16개의 레지스터는 모두 %r로 시작하는 이름을 갖는다.

위 사진을 보면 %rxx 레지스터의 절반의 크기에 %exx라는이름이 붙어있는 것을 확인할 수 있다.

%exx%rxx의 하위 4바이트에 해당하며 이와 같은 방식으로 아래 사진처럼  2바이트, 1바이트에 각각 접근가능!

이때, esp와 ebp는 모두 pointer로 주소를 저장하는 register이다.

이는 예전에 1바이트 단위 접근방식을 남겨두어 예전 의 기능을 그대로 유지해 하위 호완성을 유지하기 위해 과거의 레지스터들의 이름이 남아있는 것이다.

전체 16개의 레지스터의 하위 바이트들은 바이트, 워드(16비트), 더블워드(32비트), 쿼드워드(64비트)씩 접근할 수 있습니다.

 

 

※  데이터의 이동 (Moving Data):

§  movq  Source, Dest

위의 뜻은 Source를 읽어 Destination에 복사를 한다는 의미이다.

 

§  Operand의 유형 

 

▶ Immediate : $로 시작하는 형태,  상수 정수 data

ex) $0x400,  $-503Register : %로 시작하는 형태,  16개 register지만 %rsp는 stack접근에만 이용한다.

ex) %rax,  %r13

Memory : (%register)의 형태, register로 지정되는 주소에 저장된 8개의 연속적 메모리 byte

  - 이때, Memory주소지정을 다음과 같은 방식으로 할 수 있다.

    i) 일반형 (R)  =  Mem[Reg[R]]                  ex) movq (%rcx) , %rax

   ii) 변위형 D(R)  =  Mem[Reg[R] + D]         ex) movq  8(%rbp) , %rdx 

  iii) 가장 일반적인 형태  D(Rb, Ri, S)  =  Mem[Reg[Rb] + S*Reg[Ri] + D] 

       - D: 상수 변위 (1, 2 or 4 bytes)

       - Rb: base register : 16개 register 모두 가능

       - Ri: index register : %rsp를 제외한 모두 가능

       - S: 배율 (1, 2, 4  or 8 bytes)

이때, Dest에는 Immediate 즉, 상수값은 올 수 없다! (상수값에 대입할 수 없어서)

또한, Source와 Dest 모두 Memory인 memory-memory 데이터 이동은 한개의 명령으로 불가능하다.

 

Ex.  아래 함수에 대해 Assembly과정을 이해해보자.

<C code>

void swap (long *xp, long *yp) {
    long t0 = *xp;
    long t1 = *yp;
    *xp = t1;
    *yp = t0;
}

 

<Assembly>

swap:	
    movq	(%rdi), %rax	# t0 = *xp
    movq	(%rsi), %rdx	# t1 = *yp
    movq	%rdx, (%rdi)	# *xp = t1
    movq	%rax, (%rsi)	# *yp = t0
    ret

 

 

 

 

 

※  주소 계산 명령어 (Load Effective Address):

§  leaq  Src, Dst

- Src: 주소 모드 식 (Memory)

- Dst: 수식으로 표현된 주소값 저장 (Register)

 

용도: 메모리를 참조하지 않고 "주소만 계산"할 때  (C에서 &연산자, 곱셈과 같은 경우)

Ex.  아래 함수에 대해 Assembly과정을 이해해보자.

<C code>

long m12 (long x) {
    return x * 12;
}

<Assembly>

leaq (%rdi, %rdi, 2) , %rax		# t <- x + x*2
salq $2,  %rax				# return t << 2

leaq (%rdi, %rdi, 2) , %rax 부분을 통해 %rdi * 3과 같은 결과를 얻고

salq  $2  (shift  arithmetic  left  2자리)연산을 이용해 (3 * %rdi) * 4로 최종적으로 12가 곱해지는 C code와 동일한 결과를 얻는다.

 

 

 

 

 

 

 

+ Recent posts