!단위 (암기좀 하자)


byte unit C

1 (b)yte char

2 (w)ord short

4 (d)word int, float, pointer, ...

8 (q)word long long,double..

10 (t)enbyte



1. 연산자


1). 사칙연산: +,-,*,/


[주소+] ->주소 표현 내에서만 사용이 가능하다 


1-1). add 더하기

기본 사용법 



ModRM:reg (r, w) ModRM:r/m (r)

값을 둘다 읽어서 더한값을 r 앞에 쓴다

올림수 처리를 생각해 줘야한다


ex)

extern printf


segment         .data

prompt_int  db  '%d',10,00

a           dd   10

b           dd   20


segment         .bss


segment         .text


global main


main:

        mov     eax,    dword [a] //메모리값[a]를 eax에 저장한다

        add     eax,    dword [b] //메모리 값 [b]와 eax를 더해준다 


        push    eax

        push    prompt_int

        call    printf



덧셈에 대한 결과값 



1-2). sub 뺄셈


덧셈과 같은 방식으로 계산 해주면 된다


extern printf


segment         .data

prompt_int  db  '%d',10,00

a           dd   10

b           dd   20


segment         .bss


segment         .text


global main


main:

        mov     eax,    dword [a]

        sub     eax,    dword [b]


        push    eax

        push    prompt_int

        call    printf



1-3).mul 곱하기

피 연산자의 비트에 따라서 계산하는 방식이 달라진다

레지스터 구조와 mul 계산 방식 두가지를 참고해야하는데

mul 계산 방식은 각 비트에 맞게 아래 설명이 잘나와있다.



레지스터 구조를 한번더 확인해보면


16비트 일때는 AH,AL로 나눠서 쓰는걸 볼수있다.


피연산자가 8비트 일때는 

AX<-AL * r/m8 

extern printf


AL에 메모리,레지스터 피연산자 8비트를 곱해서 AX(16비트) 에 저장한다



segment         .data

prompt_int  db  '%d',10,00

a           db   2



segment         .bss


segment         .text


global main


main:


        mov     eax, 0 

        mov     al,  5  

        mul     byte [a]


        push    eax

        push    prompt_int

        call     printf


정확하게 확인할려면 eax를 0으로 초기화하고 한다


피연산자가 16비트 인 경우에는

Unsigned multiply (DX:AX ← AX ∗ r/m16).

AX에 16비트를 곱하면 DX와 AX에 값이 나누어 저장된다. 


9876 * 4500=4442000

  =0000 0010 1010 0110 0010 0001 1001 0000


dx:678        0000 00010 1010 0110

ax:8592       0010 0001 1001 0000



extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dw      9876


segment         .bss

result          resd    1


segment         .text


global main


main:

        mov     eax,0

        mov     edx,0


        mov     ax, 4500

        mul     word [a]


        push    eax

        push    edx

        push    prompt_int_int

        call    printf



곱셈에 대한 결과값



imul(부호가 있는)

피연산자가 2개인 경우에는 add랑 동일 

ModRM:reg (r, w) ModRM:r/m (r)


extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dd      9876




segment         .bss


segment         .text


global main


main:


        mov     eax, 10

        imul    eax, dword [a]


        push    eax

        push    prompt_int

        call    printf

               


피연산자가 3개인 경우에는 


ModRM:reg (r, w) ModRM:r/m (r) imm8/16/32


extern printf

segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dd      9876


segment         .bss


segment         .text


global main


main:


        mov     eax, 0

        imul    eax, dword [a], 10


        push    eax

        push    prompt_int

        call    printf

             


1-3).Div 나누기               

div -> 4바이트 / 4바이트 = 2바이트


피연산자가 8비트 나눗셈

Unsigned divide AX by r/m8, with result

stored in AL ← Quotient, AH ← Remainder.

AX에 있는 값을 r/m8 비트로 나눠준다 

몫은 AL 나머지는 AH에 저장한다


Unsigned divide AX by r/m8, with result

stored in AL ← Quotient, AH ← Remainder.


extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               db      7




segment         .bss


segment         .text


global main


main:


        mov     eax, 0

        mov     ax, 10

        cwd  ;convert word to byte

        ;cdw ;convert double word to word

        ;cdq ;convert double word to quad word

        div     byte [a]


        push    eax

        push    prompt_int

        call    printf



16비트 나눗셈은

Unsigned divide DX:AX by r/m16, with result

stored in AX ← Quotient, DX ← Remainder.


  44442000 / 7412

=0000 0010 1010 0110 0010 0001 1001 0000

=dx:678, ax:8592

extern printf

segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dw      7412


segment         .bss

segment         .text

global main


main:

        mov     eax, 0

        mov     edx, 0

        mov     dx, 678

        mov     ax, 8592

        cdw ;convert double word to word

        div     word [a]


        push    eax

        push    edx

        push    prompt_int_int

        call    printf


나눗셈 결과





idiv



2). 비교연산


3). 논리연산 : and, or, xor 


1 and 0:0

1 or   0:1

xor 값을 초기화 할때 많이 쓴다

xor eax, eax

0으로 초기화 된다


4). 비트 연산: shift


-비트를 왼쪽/오른쪽으로 이동

곱셈

9876 * 4500=4442000

  =0000 0010 1010 0110 0010 0001 1001 0000


dx:678        0000 0010 1010 0110

ax:8592       0010 0001 1001 0000


만약 dx를 왼쪽으로 16비트 이동하고

dx:0000 0010 1010 0110 0000 0000 0000 0000

ax:0000 0000 0000 0000 0010 0001 1001 0000

+ 더해주면


4442000:0000 0010 1010 0110 0010 0001 1001 0000 값이 출력된다


ax와 그 값을 합치면 곱셈을 하지 않아도 결과 값이 출력된다


명령어는 shl,shr


[root@korea /root]# vi basic.asm

extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dw      9876


segment         .bss

result          resd    1


segment         .text


global main


main:

        mov     eax,0

        mov     edx,0


        mov     ax,     4500

        mul     word [a]


        mov     dword [result], edx

        shl     dword [result], 16

        add     dword [result], eax


        push    dword [result]

        push    prompt_int

        call    printf



비트 연산을 할때는 부호를 생각해서 연산을 해주어야 한다.


extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dw      9876


segment         .bss

result          resd    1


segment         .text

global main


main:

        xor     edx,    edx

        mov     dl,     -2

        shl     dl,     2

        shl     dl,     2


        push    edx

        push    prompt_int

        call    printf




결과는 맞지않는 값이 출력된다


산술 시프트인 sar sal 을 이용해서 값을 구하면 정확한 값이 출력된다




extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dw      9876


segment         .bss

result          resd    1


segment         .text

global main


main:

        xor     edx,    edx


        mov     edx,    -2

        sal     edx,    2

        sar     edx,    2


        push    edx

        push    prompt_int

        call    printf




나눗셈

  44442000 / 7412

=0000 0010 1010 0110 0010 0001 1001 0000

  0000 0000 0000 0000 1111 1111 1111 1111 and

=dx:678, ax:8592


extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dw      9876


segment         .bss

result          resd    1


segment         .text


global main


main:

        mov     eax,0

        mov     edx,0


        mov     ax,     4500

        mul     word [a]


        mov     dword [result], edx

        shl     dword [result], 16

        add     dword [result], eax


        push    dword [result]

        push    prompt_int

        call    printf


        mov     edx,    dword [result]

        shr     edx,    16


        mov     eax,    dword[result]

        and     eax,    00000000000000001111111111111111b

        ;and     eax,    0000ffffh

        ;and     eax,    65535

        cdw

        div     word [a]


        push    edx

        push    eax

        push    prompt_int_int

        call    printf



[실습]

-두 수를 입력 받아서 사칙연산 결과를 출력하는 

어셈블리 프로그램 작성


-! 나눗셈은 몫과 나머지를 출력


   - 최대로 받을수 있는 수는 int 형이니까 레지스터는 전부 eax,edx 등을 사용해서 계산하였다.


  - 위에 기본을 배우려고 8비트 일 때16비트일 때 나누어서 생각했지만 일반적으로 계산할 때는 편의성을 위해 eax를 사용해서 32비트로 계산한다. 요즘 cpu가 이 정도 잡는다고 성능이 떨어지거나 하지 않기 때문이다




extern printf

extern scanf


segment .data

string1 db 'a+b:%d',10,00

string2 db 'a-b:%d',10,00

string3 db 'a*b:%d',10,00

string4 db 'a/b:%d %d',10,00

input dd '%d',00


segment .bss

a resd  4

b resd  4


segment .text

global main



main:

        push a

        push input

        call scanf


        push b

        push input

        call scanf


        mov eax,0

        mov eax, dword [a]

        add eax, dword [b]

        push eax

        push string1

        call printf


        mov eax,0

        mov eax,dword [a]

        sub eax,dword [b]

        push eax

        push string2

        call printf


        mov eax,0

        mov eax,dword [a]

        mul dword [b]

        push eax

        push string3

        call printf


        mov eax,0

        mov edx,0

        mov eax,dword [a]

        div dword [b]


        push edx

        push eax

        push string4

        call printf









+ Recent posts