shift 연산

SHR para1, para2 ;(오른쪽으로 비트 이동)
    - para1 : 작업할 장소 (레지스터나 메모리)
    - para2 : 오른쪽으로 이동할 비트 수 (주로 4의 배수로 사용)
    
SHL para1, para2 ;(왼쪽으로 비트 이동)
    - para1 : 작업할 장소 (레지스터나 메모리)
    - para2 : 왼쪽으로 이동할 비트 수 (주로 4의 배수로 사용)

대부분의 경우는 4bit의 배수로 이동이 필요하다.

이동 시 밀려가는 숫자는 버려지고, 빈 숫자는 0으로 채워진다.

 

AND OR XOR NOT 연산

AND para1, para2 ;(para1 = para1 AND para2)
    - para1, para2 : 연산 대상으로 레지스터, 메모리, 상수 모두 가능
    - 연산 결과는 para1에 저장된다.
    - para1, para2 모두 메모리인 경우는 연산이 불가능하다.
    - OR, XOR도 AND 연산과 동일하다
    
NOT para ;(para = not para, 0은 1로, 1은 0으로 변경)
    - para : 연산대상으로 레지스터, 메모리 상수 모두 가능
    - 연산결과는 para에 저장

 

곱하기 연산 (2byte)

MUL para(2byte)
    - para가 2byte 일 때 : DX : AX = AX * para
    - para는 레지스터만 허용된다.
    - 연산결과는 무조건 지정된 레지스터로만 들어온다. (DX:AX)
    
MUL para(4byte0
    - para가 4byte 일 때 : EDX : EAX = EAX * para
    - para는 레지스터만 허용된다.
    - 연산결과는 무조건 지정된 레지스터로만 들어온다. (EDX:EAX)

상위 숫자는 DX 레지스터에, 하위 숫자는 AX 레지스터에 들어와서 DX:AX를 연결해서 4byte롤 해석해서 읽어야한다.

하지만 인텔 CPU에서는 이것을 물리적으로 연결해 한 번에 읽어주는 명령어가 없다.

그래서 논리적으로 레지스터에 이동시켜야 한다.

%include "io64.inc"

section .text
global CMAIN
CMAIN:
    ;write your code here
    mov dx, 0x1234
    mov ax, 0x5678
    PRINT_HEX 2, dx
    NEWLINE
    PRINT_HEX 2, ax
    NEWLINE
    
    shl edx, 16
    PRINT_HEX 4, edx
    NEWLINE
    and eax, 0x0000ffff
    PRINT_HEX 4, eax
    NEWLINE
    
    or eax, edx
    PRINT_HEX 4, eax
    NEWLINE
    xor rax, rax
    ret

수행 결과

1234
5678
12340000
5678
12345678

 

나누기 연산 (2byte)

DIV para(2byte)
    - para가 2byte 일 때 : DX:AX / para(2byte) : AX(몫), DX(나머지)
    - para는 레지스터만 허용된다.
    - 나누어지는 값은 무조건 DX:AX 레지스터에만 넣어야 한다.
    - 결과는 AX, DX의 레지스터에서만 얻을 수 있다.

4byte 숫자를 나누기 우해 DX, AX 레지스터로 분리한 후 계산을 해야 올바른 결과를 얻을 수 있다.

%include "io64.inc"

section .text
global CMAIN
CMAIN:
    ;write your code here
    mov eax, 0x12345678
    PRINT_HEX 4, eax
    NEWLINE
    
    mov edx, eax
    shr edx, 16
    
    and eax, 0x0000ffff
    
    PRINT_HEX 2, dx
    NEWLINE
    PRINT_HEX 2, ax
    xor rax, rax
    ret

수행 결과

12345678
1234
5678

 

플래그 레지스터

다양한 산술 연산 결과의 상태를 알려주는 플래그 비트들이 모인 레지스터이다.

플래그 레지스터는 프로그램에서 다른 레지스터처럼 명시적으로 사용되지 않고 각각의 플래그 상태 값을 이용하는 다른 명령어들에서 비 명시적으로 사용된다.

플래그 레지스터의 값을 변경시키는 명령어들은 주로 산술, 논리 연산자들이다.

 

대표적인 플래그 2개

ZF (Zero Flag) : 연산 결과가 Zero이면 설정됨
CF (Carry Flag) : 연산에서 캐리가 발생하면 설정됨

연산의 결과를 레지스터에 반영하지 않고, 플래그 레지스터에만 반영하는 TEST 연산 명령어가 있다.

TEST para1, para2
    - para1과 para2의 and 연산을 행하고 결과를 프랠그 레지스터에 반영한다.
    - 단, para1에는 연산 결과를 반영하지 않는다.

 

section .text에서 라벨

어셈블리 언어 section .text에서 사용되는 라벨(label)이라는 개념은 실행명령어가 시작되는 곳의 주소를 의미한다.

라벨이 필요한 이유는 데이터의 흐름을 순차적이 아니고 앞이나 뒤쪽으로 이동해야 하는 경우가 있기 때문이다.

 

라벨 사용시 유의할 점

- 한 프로그램 내에서 동일한 이름의 라벨은 2개 이상 정의하지 않는다.
- 필요에 따라서는 동일한 주소에 여러 개의 라벨을 붙여 사용하는 것이 가능하다.

 

IF 문의 구현

어셈블리 언어에서는 if문이 없어 좀 더 저차원 레벨에서 구현해야 한다.

먼저 if 문을 구현하기 위해서는 CMP와 JMP 계열 명령어를 이해해야 한다.

CMP dst, src
    - dst를 중심으로 src와 비교 연산을 수행한다.
    - 연산 결과는 플래그 레지스터에 저장된다.
    - 결과는 JMP 명령문과 연결되어 사용된다.
    
JMP 계열 명령어(플래그 레지스터의 플래그를 보고 수행됨)
    - JE/JNE label : 같거나 / 같지 않다면 label로 jump (dst == src, dst != src)
    - JG/JGE label : 크거나 / 크거나 같으면 label로 jump (dst > src, dst >= src)
    - JL/JLE label : 작거나 / 작거나 같은면 label로 jump (dst < src, dst <= src)
    - JMP label : label로 무조건 jump

 

3개의 숫자 중 가장 큰 수를 선택하는 알고리즘

%include "io64.inc"

section .text
global CMAIN
CMAIN:
    ;write your code here
    mov al, [a]
    mov bl, [b]
    cmp al, bl
    jle NEXT1
    mov [max], al
    jmp NEXT2
NEXT1:
    mov [max], bl
NEXT2:
    
    mov al, [max]
    mov bl, [c]
    cmp al, bl
    jle next3
    jmp next4
next3:
    mov [max], bl
next4:

    PRINT_HEX 1, [max]
    NEWLINE
    xor rax, rax
    ret
    
section .data
    a db 0x12
    b db 0x56
    c db 0x34

section .bss
    max resd 1

 

수행 결과

56

 

[퀘스트] 로직 연산 계산기

요구 조건

사용자로부터 세 개의 숫자(2byte)를 입력받아 메모리에 저장하고,
가장 큰 숫자와 가장 작은 숫자를 선택해서 각각 max, min이라는 변수에 저장하라
max * min을 계산하여 total이라는 변수에 저장하고 total을 출력하라

코드 작성

%include "io64.inc"

section .text
global CMAIN
CMAIN:
    mov rbp, rsp; for correct debugging
    ;write your code here
    GET_DEC 2, [input1]
    GET_DEC 2, [input2]
    GET_DEC 2, [input3]
    
    mov ax, [input1]
    mov bx, [input2]
    cmp ax, bx
    jle label1
    mov [max], ax
    mov [min], bx
    jmp label2
label1:
    mov [min], ax
    mov [max], bx
label2:
    
    
    mov ax, [max]
    mov bx, [input3]
    cmp ax, bx
    jg label3
    mov [max], bx
label3:

    mov ax, [min]
    mov bx, [input3]
    cmp ax, bx
    jl label4
    mov [min], bx
label4:

    PRINT_STRING msg1
    PRINT_DEC 2, [max]
    NEWLINE
    PRINT_STRING msg2
    PRINT_DEC 2, [min]
    NEWLINE

    mov eax, 0
    mov ebx, 0
    mov ax, [max]
    mov bx, [min]
    mul bx
    shl edx, 16
    and eax, 0x0000ffff
    or eax, edx
    
    PRINT_STRING msg3
    PRINT_DEC 4, eax
    NEWLINE
    
    
    

    xor rax, rax
    ret
    
section .bss
    input1 resw 1;
    input2 resw 1;
    input3 resw 1;
    max resw 1;
    min resw 1;
    total resb 1;
    
section .data
    msg1 db "input1 : ", 0x00
    msg2 db "input2 : ", 0x00
    msg3 db "total : ", 0x00

수행 결과

입력값
2
3
1000

출력값
input1 : 1000
input2 : 2
total : 2000

'어셈블리' 카테고리의 다른 글

모듈 프로그래밍  (0) 2021.10.12
반복  (0) 2021.10.11
사칙 연산  (0) 2021.10.09
어셈블리 기본 개념  (0) 2021.10.08
어셈블리 언어 기초  (0) 2021.10.07

+ Recent posts