[5] 어셈블리 계산기 , scanf , printf

2017. 10. 19. 21:34SystemHacking/Assembly


 

 

 

어셈블리 ( NASM ) 언어로 간단한 계산 작업을 할 수 있는 계산기 코드를 작성해보도록 하겠습니다

 

[ 계산기 작성 코드 ]

 

 

 extern printf            ; printf 라이브러리 가져온다

 extern scanf            ; scanf 라이브러리 가져온다

 section .data           

 argv:    db    '%d\n', 10, 00

 argv1:    db    '%d %d', 10, 00

 argv2:    db    '%d %d', 10, 00

 argv3:    db    'q:%d, r:%d', 10, 00

 

 section .bss

 num_1:    resd    1            ; 레이블 num_1 : 0x85858585 같은 메모리의 주소값

 num_2:    resd    1            ; 레이블 num_2 : 0x85858585 같은 메모리의 주소값

 

 section .text

 global main

 main:

        push num_2

        push num_1

        push argv2

        call scanf            ; C언어 표현 :scanf("%d %d",&num_1,&num_2)

                                ; 어셈블리에서는 num_1, num_2 를 인자로 push하면 된다

 

 

scanf 함수를 작성하는 어셈블리 코드를 이해하기 어려울 수도 있지만 레이블이라는 개념을 잘 이해하고 있으면 된다

레이블이라는 것은 메모리의 주소를 문자로 바꿔서 불러주는 것이다

즉, num_1 과 num_2 는 주소값이다. 따라서 scanf의 인자로 넣어주자

프로그램 실행시 우리가 입력하는 숫자 2개는 num_1 과 num_2 주소로 입력되어 질 것이다

그럼 해당 값을 [ ] 을 사용해서 우리는 사용할 수 있다 아래 그림에서 사용하는 방법에 대해서 알아보자

 

* 어셈블리 ( NASM ) 단위와 레지스터

 단위

 byte (1byte=8bit)

 word (2byte=16bit)

 dword (4byte=32bit)

 register

 AH | AL

 AX

 EAX

 

 

[ 덧셈 ]

 

 

mov    eax,    0                           ; 레지스터 초기화

mov    ebx,    0                          ; 레지스터 초기화

mov    eax,    dword [num_1]        ; dword 크기의 num_1에 있는 값을 eax 레지스터에 저장

mov    ebx,    dword [num_2]        ; dword 크기의 num_2에 있는 값을 ebx 레지스터에 저장

add    eax,    ebx                        ; eax 레지스터에 ebx 레지스터 값을 더한다

push    eax

push    argv    

call    printf                               ; printf( "%d\n", 상수 )

 

 

 

[ 뺄셈 ]

덧셈과 마찬가지로 해도 되지만, res라는 새로운 메모리를 사용해서 뺄셈할 수 있다

 

 

[ 곱셈 ]

 

* eax 레지스터는 연산을 위한 레지스터이고, edx 레지스터는 eax레지스터를 도와주는 역할을 한다

 

 

mov    eax,    0                            ; 레지스터 초기화

mov    edx,    0                            ; 레지스터 초기화

mov    eax,    dword [num_1]          ; eax레지스터에 num_1값 입력

mov    edx,    dword [num_2]          ; ebx레지스터에 num_2값 입력

mul    edx                                   ; eax = eax 레지스터 * edx 레지스터

push    eax

push    argv

call    printf                                ; printf( "%d\n", eax레지스터값 )

 

 

 

[ 나눗셈 ]

 

mov    eax,    0

mov    edx,    0

mov    ax,    word [num_1]            ;   ax 는 16bit 레지스터이고 word는 16bit의 데이터단위

mov    bx,    word [num_2]            ;  단위를 맞춰서 mov 시켜야 한다

cwd                                          ; Change Word To Dword ( word단위를 dword단위로 자동 형 변환 )

div     bx                                   ; ax 레지스터의 값을 bx 값으로 나눈다

push    edx                                ; push명령어는 32bit 레지스터를 사용해야 하므로 edx를 push해야한다

push    eax                                ;

push    argv3                             ;

call    printf                               ; printf("q:%d, r:%d', eax 레지스터 값 , edx 레지스터 값 ) 

 

 

32bit 의 나눗셈 결과는 DX:AX 레지스터에 각각 나뉘어서 들어가게된다

DX 레지스터에는 나눗셈의 나머지, AX 레지스터에는 나눗셈의 몫이 들어가게 된다