본문 바로가기
CS 지식/시스템 프로그래밍

Assembly(어쌤블리어)의 기초

by 코딩하는 동현😎 2024. 10. 18.
  • Machine Code:
    • 머신 코드는 프로세서가 실행하는 바이트 수준의 프로그램입니다. 이는 0과 1로 구성된 이진 형식으로, CPU가 직접 이해하고 수행할 수 있는 명령어들로 구성되어 있습니다. 각 명령어는 특정 작업을 수행하도록 설계되어 있으며, 메모리에서 특정 위치에 저장됩니다.
  • Assembly Code:
    • 어셈블리 코드는 머신 코드를 텍스트 형식으로 표현한 것입니다. 이는 인간이 읽고 쓰기 쉬운 형태로, 각 머신 코드 명령어에 대해 기억하기 쉬운 기호(레지스터, 메모리 주소, 명령어 이름 등)를 사용합니다. 어셈블리 코드는 어셈블러라는 프로그램에 의해 머신 코드로 변환됩니다.

 

 

“Integer” data of 1, 2, 4, or 8 bytes:

  • 정수 데이터는 1, 2, 4 또는 8 바이트 크기로 표현되며, 이는 시스템에서 사용되는 기본 데이터 타입입니다.
  • Data values:
    • 메모리에 저장된 실제 정수 값들.
  • Addresses (untyped pointers):
    • 주소는 특정 타입이 없는 포인터로 메모리의 특정 위치를 가리킴.

 

Floating point data of 4, 8, or 10 bytes:

  • 부동 소수점 데이터는 4, 8 또는 10 바이트 크기로 표현됩니다.

 

Code:

  • 바이트 시퀀스는 일련의 명령어를 인코딩한 것으로, 실행할 수 있는 프로그램의 기본 구성 요소입니다.
  • 메모리의 연속적으로 할당된 바이트로만 구성되며, 배열이나 구조체와 같은 집합형 데이터 타입은 없음.

 

Arithmetic Operations and Data Transfer

레지스터나 메모리 데이터를 사용하여 산술 연산을 수행합니다.

 

메모리와 레지스터 간의 데이터 전송.

  • 메모리에서 레지스터로 데이터를 로드합니다.
  • 레지스터의 데이터를 메모리에 저장합니다.

프로그램의 실행 흐름을 제어합니다.

  • 조건 없이 절차로 점프합니다.
  • 조건에 따라 분기합니다.

 

Programmer-Visible State

  • PC: Program Counter:
    • 프로그램 카운터는 다음 명령어의 주소를 저장합니다.
    • x86-64에서 “RIP”(Instruction Pointer Register)라고도 불립니다.
  • Register File:
    • 프로그램에서 사용되는 데이터가 저장되는 레지스터 파일.

Condition Codes

  • 가장 최근의 산술 연산에 대한 상태 정보를 저장합니다.
  • 조건부 분기에서 사용됩니다.

 

 

 

 

Memory

  • 메모리는 바이트 단위로 주소 지정됩니다.
  • 메모리에는 코드, 사용자 데이터 및 일부 운영 체제 데이터가 포함됩니다.
  • 절차를 지원하기 위해 스택을 사용합니다.

데이터 이동 명령어 movq

  • movq Source, Dest:
    • 데이터를 이동하는 명령어의 형식.
  • Operand Types:
    • Immediate: 상수 정수 데이터
      • 예: $0x400, $-533
      • C 상수와 유사하지만 앞에 '$' 기호가 붙음.
      • 1, 2 또는 4 바이트로 인코딩됨.
    • Register: 16개의 정수 레지스터 중 하나
      • 예: %rax, %r13
      • %rsp는 특별한 용도로 예약됨.
      • 나머지 레지스터는 특정 명령어에 대해 특별한 용도로 사용됨.
    • Memory: 특정 주소에 있는 8바이트 연속 메모리
      • 가장 간단한 예: (%rax)
      • 다양한 "주소 모드"가 존재합니다.

 

 

 


 

 

Most General Form

  • D(Rb,Ri,S): 메모리 주소 계산의 일반적인 형식
    • Mem[Rb + S * Ri + D]
      • D: 상수 "displacement", 1, 2 또는 4 바이트 크기.
      • Rb: 베이스 레지스터, 16개의 정수 레지스터 중 하나.
      • Ri: 인덱스 레지스터, %rsp를 제외한 모든 레지스터.
      • S: 스케일, 1, 2, 4, 또는 8.

Special Cases

  • D(Rb): 메모리 주소의 특별한 경우
    • Mem[Rb + D]
  • (Rb,Ri): 두 레지스터의 조합으로 메모리 주소를 계산
    • Mem[Rb + Ri]
  • D(Rb,Ri): 베이스와 인덱스 레지스터를 함께 사용하는 경우
    • Mem[Rb + Ri + D]
  • (Rb,Ri,S): 스케일을 포함한 조합
    • Mem[Rb + S * Ri]

이항 산술 연산자

  • addq Src, Dest:
    • Dest = Dest + Src
  • subq Src, Dest:
    • Dest = Dest - Src
  • imulq Src, Dest:
    • Dest = Dest * Src

단항 연산자

  • incq Dest:
    • Dest = Dest + 1 (Dest의 값을 1 증가)
  • decq Dest:
    • Dest = Dest - 1 (Dest의 값을 1 감소)
  • negq Dest:
    • Dest = -Dest (Dest의 부호를 바꿈)
  • notq Dest:
    • Dest = ~Dest (Dest의 비트를 반전)

LEA (Load Effective Address)

  • leaq Src, Dst:
    • Src는 주소 계산 표현식
    • Dst는 표현식이 나타내는 주소를 설정하는 레지스터
  • 용도:
    • 메모리 참조 없이 주소 계산
    • 예: p = &x[i] 같은 표현
    • 산술 표현 계산: x + k*y (k = 1, 2, 4, 또는 8)

x *= 12의 예시

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

 

이항 논리 연산자와 시프트 연산

  • salq Src, Dest:
    • Dest = Dest << Src (왼쪽 시프트, shlq라고도 함)
    • 왼쪽으로 시프트할 때는 0이 빈 공간에 채워집니다. 이는 2의 거듭제곱으로 곱하는 것과 같습니다.
    • 논리랑 산술적 시프트 연산이 같기 때문에 shlq와 동작이 같고, 대체 명령어로 알려져 있습니다.
    • Shift Arithmetic Left
  • sarq Src, Dest:
    • Dest = Dest >> Src (산술 오른쪽 시프트)
    • 오른쪽으로 시프트할 때는 가장 왼쪽 비트의 부호 비트(즉, 최상위 비트)가 복사되어 들어옵니다. 이는 부호 있는 수에서의 산술적 이동을 위해서입니다
    • 예를 들어, Dest가 -4(이진수 1100)이고 Src가 1이면, 결과는 -2(이진수 1110)가 됩니다.
    • Shift Arithmetic Right
  • shrq Src, Dest:
    • Dest = Dest >> Src (논리 오른쪽 시프트)
    • 오른쪽으로 시프트할 때는 빈 공간에 항상 0이 채워집니다.
    • 예를 들어, Dest가 -4(이진수 1100)이고 Src가 1이면, 결과는 6(이진수 0110)이 됩니다.
    • Shift Logical Right
  • xorq Src, Dest:
    • Dest = Dest ^ Src
  • andq Src, Dest:
    • Dest = Dest & Src
  • orq Src, Dest:
    • Dest = Dest | Src

현재 실행 중인 프로그램에 대한 정보

  • 임시 데이터: %rax 등
  • 런타임 스택 위치: %rsp
  • 현재 코드 제어 지점 위치: %rip 등
  • 최근 테스트 상태: (CF, ZF, SF, OF)

단일 비트 레지스터

  • CF (Carry Flag): 부호 없는 수에 대해
  • SF (Sign Flag): 부호 있는 수에 대해
  • ZF (Zero Flag): 결과가 0인지 여부
  • OF (Overflow Flag): 부호 있는 오버플로우 발생 여부

 

 

 

암시적 설정

  • 산술 연산에 의해 설정됨. 예를 들어:
    • addq Src, Dest에서:
      • CF: 가장 높은 비트에서 캐리 아웃 발생 시 설정
      • ZF: 결과가 0일 때 설정
      • SF: 결과가 음수일 때 설정
      • OF: 두의 보수 오버플로우 발생 시 설정
  • leaq 명령어는 플래그를 설정하지 않음.

명시적 설정: 비교 명령어에 의해

  • cmpq Src2, Src1:
    • 예를 들어, cmpq b,a는 a-b를 계산하지만 결과를 설정하지 않음.
    • CF: 가장 높은 비트에서 캐리 아웃 발생 시 설정 (부호 없는 비교에 사용)
    • ZF: a == b일 때 설정
    • SF: (a-b) < 0일 때 설정 (부호 있는 경우)
    • OF: 두의 보수 오버플로우 발생 시 설정

SetX Instructions

  • 목적: 조건 코드의 조합에 따라 대상의 낮은 바이트를 0 또는 1로 설정.
  • 나머지 7 바이트는 변경하지 않음.

 

SetX Instructions의 세부 사항

  • 조건 코드의 조합에 따라 단일 바이트 설정.
  • 주소 가능 바이트 레지스터 중 하나에서 설정됨.
  • 나머지 바이트는 변경하지 않음.
  • 보통 movzbl을 사용하여 작업을 마무리함.
  • 32비트 명령어는 상위 32비트를 0으로 설정함.

 

 

jX Instructions

  • 조건 코드에 따라 코드의 다른 부분으로 점프.

 

 

 

 

조건부 이동 명령어

  • 형식: if (Test) Dest = Src
  • 1995년 이후 x86 프로세서에서 지원.
  • GCC는 이를 사용하려고 시도하지만, 안전성이 확인된 경우에만 사용.

왜 조건부 이동을 사용하나요?

  • 브랜치는 명령어 흐름에 파이프라인 중단을 초래하므로 비효율적입니다.
  • 조건부 이동은 제어 전송을 필요로 하지 않으므로 효율적입니다.

계산되는 두 값

  • 두 값이 모두 계산되며, 계산이 매우 간단할 때만 의미가 있습니다.

조건부 이동의 나쁜 사례

  • val = Test(x) ? Hard1(x) : Hard2(x);
  • val = p ? *p : 0;
  • val = x > 0 ? x*=7 : x+=3;

이러한 내용은 x86 아키텍처의 어셈블리 명령어와 프로그래밍에서의 메모리 및 데이터 처리 방법에 대한 이해를 돕기 위한 것입니다.

반응형

댓글