티스토리 뷰

 

보안 분야로 준비를 하면서 수업시간의 내용을 개인적으로 내용을 정리해 보겠습니다.
아래의 내용을 처음부터 하나 하나 공부해 가면 많은 내용 학습을 필요할 수도 있습니다. 
저는 이 글의 목표를 어셈블리어를 이용한 Hello World를 출력하는 것으로 목표로 합니다. 
상세한 내용을 담기에는 너무 글이 길어지고 저도 또한 시간상의 부족한 부분이 있기에 이해해 주시기를 바라며.... 

 
기본 지식

레지스터

레지스터를 간단히 말하면 컴퓨터의 프로세서(CPU, DSP, GPU)가 내부에 유지하는 적은 영역의 기억장치입니다. 대부분의 프로세서는메인 메모리에서 레지스터로 옮겨와 데이터를 처리한 후 그 내용을 다시 레지스터에서 메모리로 저장하는 로드-스토어설계를 사용하고 있습니다.

 

레지스터의 종류

레지스터는 용도에 따라 몇 가지 종류가 있다. 그 중에 몇가지를 간단히 알아보겠습니다.


데이터 레지스터 : 정수 값을 저장할 수 있는 레지스터

주소 레지스터 : 메모리 주소를 저장하여 메모리 접근에 사용되는 레지스터  

범용 레지스터 : 데이터와 주소를 모두 저장할 수 있는 레지스터

부동 소수점 레지스터: 부동소수점 값을 저장하기 위한 레지스터

상수 레지스터 : 0이나 1과같은 고정된 값을 저장하고 있는 레지스터

특수 레지스터 : 프로그램의 상태를 저장하는 레지스터, 프로그램 카운터, 스택 포인터, 상태레지스터 등이 있습니다.

 

포인터와 인덱스 레지스터

32비트 일반 주소 레지스터는 4개가있으며, 일반 레지스터에 속하지 않는 주소 레지스터 EIP도 있습니다.
세그먼트 내에서의 옵셋 값을 기억하며 메모리의 위치를 지적하는데 사용됩니다.
ESP(stack pointer) : 스택의 꼭대기 주소를 포함합니다.
EBP(base pointer) : 현재 스택 프레임의 주소를 담습니다. 주소 스택의 자료를 액세스하기 위해 사용됩니다.
ESI(source index) : 문자열 연산에서 사용되는 원본주소를 포함합니다.
EDI(destination index) : 문자열 연산에서 사용되는목적 주소를 포함합니다.
EIP(instruction pointer) : 현재 실행되는 명령의주소를 포함합니다.

 
세그먼트 레지스터
CS(Code Segment register)  : 명령어 코드를 기억시킨다.
DS(Data Segment register)   : 자료를 기억시킨다.
SS(Stack Segment register)  : 스택 영역으로 사용한다.
ES(Extra Segment register)   : 데이터 세그먼트를 한 가지 더 추가할 때 둘째 번 데이터 세그먼트

 

범용 레지스터란?

특수한 목적을 가지지 않은 명령에 의해 각종 기능을 수행하는 레지스터,

데이터를 계산하는 회로와 어드레스의 계산하는 회로를 함께 가지고 있고, 명령의종류를 줄이는것이 가능하므로 대부분의 프로세서가 가지고 있는 레지스터입니다. 프로그래밍의 자유도가 크게증가하고, 특별히 컴파일러 실행 효율이 좋으므로 오브젝트를 생성하는 것이 쉽습니다. RISC계 프로세서는 범용 레지스터가 동일한 기능을 가지고 있는 것이 많습니다.

EAX(Accumulator) : 워드 단위의 곱셈, 나눗셈, 입출력  
EBX(Base Register) : 주소의 기저, XLAT명령 등에 사용
ECX(Counte Register) : 스트링 조작, REP, Loop등에서 사용
EDX(Data Register) : 곱셈, 나눗셈 및 입출력 명령에 이용

간단한 레지스터의 역사(비트의 확장)
처음에는 우리는 8bit프로세서를 사용하다가 지금은 32bit, 64bit의 사용하고 있습니다.
레지스터도 명칭이 이에 따라 변경되어 왔습니다.


CPU

범용 레지스터

8bit CPU(8086)

“a”, “b”, “c”,"d"

확장 CPU(8086)

“ax”, “bx”, “cx”, "dx"

32bit CPU(80386)

“eax”, “ebx”, “ecx”, “edx” (e extend의 약자)

64bit AMD64

“rax”, “rbx”, “rcx”

 

실습

 

먼저 C언어를이용하여 hello world을 출력해 보겠습니다. 아래에서 이를 구현하는 어셈블리어를 작성하고 실행시켜 볼 것입니다.

 int main() {

  write(1, “hello world\n”,14);

  return 0;

} 

 

컴파일하고 출력해 보면 다음과 같습니다.
 





위의 것을 그대로 어셈블리어로 구현해 보겠습니다..

 .data

   hello :

    .string “hello world”

 

.globl main:

   main:

    mov $4, %eax

    mov $1, %ebx

    mov $hello, %ecx

    mov $14, %edx

    int $0x80

 

 

코드 설명

.data                                 // 영역을 지정합니다.

   hello :                            //  변수 선언

    .string “hello world\n”      //  변수에 문자열 “hello world\n” 넣기

 

.globl main:                       // main 함수 작성

   main:                             // main함수의 내용 적기

    mov $4, %eax               // eax레지스터에 4 넣기(write() 의미하는 System call no)

    mov $1, %ebx               // ebx레지스터에 1 넣기(Standard_out 의미)

    mov $hello, %ecx          // string(hello) 주소

    mov $14, %edx             // string size

    int $0x80                      // 인터럽트 수행

 
  write(1, “hello world\n”,14); 의 한줄은 어셈블리어에서는 다음으로 표현됩니다.
==========================================================================

    mov $4, %eax           // eax레지스터에 4 넣기(write() 의미하는 System call no)

    mov $1, %ebx           // ebx레지스터에 1 넣기(Standard_out 의미)

    mov $hello, %ecx      // string(hello) 주소

    mov $14, %edx         // string size

    int $0x80                  // 인터럽트 수행

 ==========================================================================

이를 컴파일 하고 다시 결과를 확인해 보겠습니다.

여기서 저장하는 파일의 확장명은 ‘[파일명].s’입니다그리고 컴파일 하는 방법은 C와 동일합니다.

 

# gcc [파일명].s

# ./a.out




자 다음과 같이 write()함수를 system call하여 문자를 출력했습니다하지만

자 여기서 한가지 에러가 발생했네요.

‘Segmentation fault’

이 에러는 자원을 릴리즈하는 별도의 루틴을 설정하지 않았기 때문이다이를 해결하기 위해 exit(0) 시스템 콜을 호출합니다다음의 행을 추가합니다.

 

이를 해결해 보도록 하겠습니다.

mov $1, %eax

mov $0, %ebx

int $0x80

이 코드의 의미는  ‘exit(0);’의 의미와 동일한 의미를 갖습니다.

 

자 그럼 코드를 추가한 후최종 결과를 확인해 볼까요~~~


 
 
정상적으로 실행이 확인되었습니다. 자 출력하는 것을 실습해 보았습니다. ^^

이론을 많이 보는 것보다 한번 해보는 것이 저는 이해가 빠른 것 같네요.

혹시라도 내용중에 추가나 수정해야할 부분이 있다면 지적을 부탁드립니다. 더 나은 지식 나눔을 추구합니다.
그러면 좋은 하루 되세요.

<위키 백과 참조>