[4] 어셈블리 명령어 add,sub,mul,div

2017. 10. 18. 19:44SystemHacking/Assembly


 

 

1-1> 덧셈: ADD 

1-2> 뺄셈: SUB


 [ 덧셈 ]

 

[ 코드 설명 ]

main:

    mov     dword [sum], 10         ; sum = 10

    add     dword [sum], 20         ; sum = sum + 20

    push    dword [sum]

    push    argv1

    call    printf                         ; printf("%d",30)


뺄셈은 덧셈과 같은 형식으로 사용한다


1-3> 곱셈

MUL : unsigned(부호가 없는 연산) 

# 부호 없는 al, ax, eax 레지스터 의 값을 피연산자와 곱한다

# 형식 : mul register|memory

# 원리

AL(8) * 8bit x/m   -> AX ( 16bit )

AX(16) * 16bit x/m -> DX:AX ( 16bit 레지스터 2개를 사용한다 )

EAX(32) * 32bit x/m -> EDX:EAX ( 32bit 레지스터 2개를 사용한다


[ 곱셈 ]


 

[ 코드 설명 ]

main:

        ; 25 * 25 ( 8bit 상수 * 8bit 상수) = ax * ( 8bit register | memory )

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

        mov     al,     25                ; al ( 8bit 레지스터 ) 에 25(8bit상수) 입력

        mov     dl,     25               ;  dl ( 8bit 레지스터 ) 에 25(8bit상수) 입력

        mul     dl                        ;  => al * dl


        push    eax                      ; push 는 32bit 해야함 ( push명령어의 특징 )

        push    argv1

        call    printf                      ; printf("%d",25*25)    /    * 8bit 끼리의 곱은 ax레지스터에 저장되어진다



[ 곱셈 심화 ]


[ 코드 설명 ]

main:

        ; 10000 * 10000                    ;    16bit * 16bit => 16bit (dx) : 16bit (ax) 레지스터에 저장된다

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

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

        mov     ax,     10000               ;    16bit 레지스터 ax에 16bit 상수 10000 입력            

        mov     dx,     10000               ;    16bit 레지스터 dx에 16bit 상수 10000 입력      

        mul     dx                             ;    ax의 10000 * dx의 10000 곱한다


        push    eax

        push    edx

        push    argv1

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


16bit * 16bit 의 곱의 결과가 16bit로 표현할 수 없을 때 DX:AX 의 32bit형태로 표현한다


[ 곱셈 결과 ]


dx ( 상위 16bit ) : ax ( 하위 16bit )

결과를 보면 edx레지스터에 1525 , eax레지스터에는 57600 이 들어가 있다

edx register : 00000101 11110101

eax register : 11100001 00000000


edx register의 비트들은 상위 16비트이므로  " << 16bit shift " 연산해야한다 

=> ex register의 값은 99942400 이 된다


결과적으로 두 레지스터의 합은 edx + eax  = 1000000



* 참고로 16bit * 16bit 의 곱이 16bit로 표현할 수 있을 때에는 DX:AX 형식을 사용하지않고 AX에만 저장합니다

아래 그림은 AX register만 사용한 결과입니다

ax register 10000 , dx register 1 을 곱한 값으로 16bit의 상수가 출력되기 때문에 AX레지스터만 사용




1-4> 나눗셈


DIV ( unsigned )


# 형식 1

AX by DIV r/m8 : AX레지스터(16bit)의 값을 8비트 레지스터로 나눈다

AL에 몫, AH에 나머지


# 형식 2

DX:AX by DIV r/m16 : 32bit 레지스터 16bit로 나눈다

AX 에 몫 , DX에 나머지



[ 나눗셈 ]


[ 코드 설명 ]

main:

        mov     eax,    0                            ; eax register 초기화

        mov     ax,     10                           ; 16bit ax register에 상수 10 입력

        mov     dl,     4                             ; 8bit dl register에 상수 4 입력

        div     dl                                      ; 10/4 => 몫: 2, 나머지: 2


        push    eax

        push    eax

        push    argv1

        call    printf                                 ; printf("%d %d", eax register 값, eax register 값 ) ; 귀찬아서 형식을 안바꿧음


[ 나눗셈 결과 ]

 

결과값으로 eax register에 514 상수가 들어가 있음을 확인할 수 있다

514 => 2진수 : 00000010 00000010


# 레지스터 저장 형태 ( AL에 몫, AH에는 나머지 값이 들어간다 )

 00000010

 00000010

 AH

 AL



[ 나머지 심화 ]


DX:AX by DIV r/m16 : 32bit 레지스터를 16bit로 나눈다 ( AX 에 몫 , DX에 나머지 ) 

* 곱셈을 공부할 때 32bit 상수는 16bit register 2개로 나눠서 표현한다고 공부했었다 

원리에 대해서만 알아보고 다음 글에서 제대로 공부해보자 ( 복잡하다 .. )


 


1000000 => 00001111 01000010 01000000 : 16bit를 넘어섰다



 # 1000000 이 상위 16bit DX register 와 하위 16bit AX register에 위치하는 형태 

 00000000 00001111 ( 15 )

 01000010 01000000 ( 16960

 DX

 AX


DX:AX 레지스터에는 백만이라는 값이 들어가있는 것이다

 


DX:AX 레지스터의 값을 div 명령어를 이용해서 bx레지스터의 값으로 나누었다


[ 나눗셈 코드 설명 ]

mov dx, 15

mov ax, 16960

mov bx, 46

div bx                 ; 1000000 / 46


DX에는 나머지가 AX에는 몫이 들어간다


[ 출력 결과 ]

EAX : 21739

EDX : 6