외로운 Nova의 작업실

Assembly 언어 공부 - 16(데이터 관련 연산자와 디렉티브 이론 및 실습) 본문

Programming/Assembly

Assembly 언어 공부 - 16(데이터 관련 연산자와 디렉티브 이론 및 실습)

Nova_ 2022. 8. 1. 13:02

안녕하세요, 오늘은 데이터 관련 연산자와 디렉티브 이론 및 실습을 해보겠습니다.

 

OFFSET 연산자

OFFSET 연산자는 변수의 주소를 반환하는 연산자 입니다. 정확히 말하면 데이터 세그먼트 시작으로부터의 레이블의 바이트 단위의 거리를 반환해줍니다.

실습으로 한번 알아보겠습니다.

include 	c:\assembly\irvine32.inc
includelib  c:\assembly\irvine32.lib
includelib  c:\assembly\kernel32.lib
includelib  c:\assembly\user32.lib

.data
bVal BYTE ?
wVal WORD ?
dVal DWORD ?
dVal2 DWORD ?

.code
main PROC

mov eax, OFFSET bVal
mov ebx, OFFSET wVal
mov ecx, OFFSET dVal
mov edx, OFFSET dVal2

call DumpRegs

    exit

main ENDP
END main

위 코드를 실행시켜보면,

EAX = 00404000, EBX = 00404001, ECX = 00404003, EDX = 00404007 인것을 확인 할 수 있습니다.

여기서 중요한 것은 항상 데이터 세그먼트로부터 00404000 떨어진 데이터는 첫번째 선언한 데이터라는 점입니다.

bVal은 1Byte이기 때문에 다음 데이터가 00404001부터 시작되고, wVal은 2Byte기 때문에 다음데이터가 00404003부터 시작되고, dVal은 4Byte 이기때문에 다음데이터가 00404007부터 시작되는 것을 알 수 있습니다.

 

ALIGN 디렉티브

ALIGN 디렉티브는 변수들을 저장할때 ~ 배수에만 저장하라는 명령어 입니다.

ALIGN 2 라고 명령하면 2의 배수의 주소에만 변수들을 시작하게 만들며, ALIGN 4라고 명령하면 4의 배수의 주소에만 변수들을 시작하게 만듭니다.

실습을 통해 실제 그러한지 알아봅시다.

include 	c:\assembly\irvine32.inc
includelib  c:\assembly\irvine32.lib
includelib  c:\assembly\kernel32.lib
includelib  c:\assembly\user32.lib

.data
bVal BYTE ?
ALIGN 2
wVal WORD ?
bVal2 BYTE ?
ALIGN 4
dVal DWORD ?
dVal2 DWORD ?


.code
main PROC

mov eax, OFFSET bVal        ;eax = 00404000
mov ebx, OFFSET wVal        ;ebx = 00404002
mov ecx, OFFSET bVal2       ;ecx = 00404004
mov edx, OFFSET dVal        ;edx = 00404008
mov esi, OFFSET dVal2       ;esi = 0040400C

call DumpRegs

    exit

main ENDP
END main

위 코드를 실행 시켜 보면.

실제로 코드대로 이루어 짐을 알 수 있습니다. 00404001은 아마 아무 값이 없겠죠..?

 

PTR 연산자

PTR 연산자는 피연산자의 크기를 변경 하는 연산자입니다. 사실 컴퓨터는 데이터를 저장 만 할뿐, 읽을때는 어떻게 읽어야 할지 모르기때문에 우리는 WORD, DWORD 라는 디렉티브를 통해서 컴퓨터에게 데이터의 크기를 말해줍니다. 따라서 PTR은 즉시 컴퓨터에게 데이터의 크기를 읽는 방법을 알려줘서 크기를 변경할 수 있습니다. 백문일 불여일견 코드를 한번 봅시다.

include 	c:\assembly\irvine32.inc
includelib  c:\assembly\irvine32.lib
includelib  c:\assembly\kernel32.lib
includelib  c:\assembly\user32.lib

.data
Double DWORD 12345678h

.code
main PROC

;mov ax, Double <- error
mov ax, WORD PTR Double     ;ax = 5678h

call DumpRegs

    exit

main ENDP
END main

위 코드를 실행 시켜보면

실제로 ax에 5678h가 저장된 것을 확인 할 수 있습니다. 왜 1234가 아닌 5678이냐면, 우리 컴퓨터는 리틀엔디언 방식으로 숫자를 저장하며, 5678이 1234보다 주소값이 작기때문에(먼저 저장되기 때문에), WORD로 읽을경우 5678먼저 읽어져서 5678을 저장하게됩니다.

 

큰 값을 작게 만들어서 레지스터에 등록해봤습니다. 이번에는 작은 값을 크게 만들어서 레지스터에 등록해보겠습니다. 백문일 불여일견 코드를 봅시다.

include 	c:\assembly\irvine32.inc
includelib  c:\assembly\irvine32.lib
includelib  c:\assembly\kernel32.lib
includelib  c:\assembly\user32.lib

.data
Array WORD 5678h, 1234h

.code
main PROC

mov eax, DWORD PTR Array        ;eax = 12345678h

call DumpRegs

    exit

main ENDP
END main

이 코드를 실행시켜보면

eax 에 12345678이 저장된 것을 확인 할 수 있습니다.

 

TYPE 연산자

TYPE 연산자는 변수가 몇바이트인지 알려주는 연산자입니다. 코드부터 보시죠.

include 	c:\assembly\irvine32.inc
includelib  c:\assembly\irvine32.lib
includelib  c:\assembly\kernel32.lib
includelib  c:\assembly\user32.lib

.data
val1 BYTE ?
val2 WORD ?
val3 DWORD ?
val4 QWORD ?

.code
main PROC

mov al, TYPE val1       ;al = 1
mov ah, TYPE val2       ;ah = 2
mov bl, TYPE val3       ;bl = 4
mov bh, TYPE val4       ;bh = 8

call DumpRegs

    exit

main ENDP
END main

위 코드를 실행시키면

잘 실행이 된 것을 확인 할 수 있습니다.

 

LENGTHOF 연산자

LENGTHOF 연산자는 배열에 있는 원소의 개수를 반환해주는 연산자입니다. 코드를 보시죠.

include 	c:\assembly\irvine32.inc
includelib  c:\assembly\irvine32.lib
includelib  c:\assembly\kernel32.lib
includelib  c:\assembly\user32.lib

.data
array1 BYTE 10, 20, 30
array2 WORD  40 DUP(1), 0, 0
array3 DWORD 3 DUP(4 DUP(2))
array4 BYTE "12345678", 0

.code
main PROC

mov al, LENGTHOF array1      ;al = 3
mov ah, LENGTHOF array2      ;ah = 40+2
mov bl, LENGTHOF array3      ;bl = 3 * 4
mov bh, LENGTHOF array4      ;bh = 8 + 1

call DumpRegs

    exit

main ENDP
END main

위 코드를 실행하면

잘 실행 된 것을 볼 수 있습니다.

 

SIZEOF 연산자

SIZEOF 연산자는 LENGTHOF 와 TYPE을 곱한 값을 반환합니다. 즉, 배열의 바이트의 크기를 반환하는거죠. 코드를 봅시다.

include 	c:\assembly\irvine32.inc
includelib  c:\assembly\irvine32.lib
includelib  c:\assembly\kernel32.lib
includelib  c:\assembly\user32.lib

.data
array WORD  40 DUP(1), 0, 0


.code
main PROC

mov al, SIZEOF array      ;ah = 2 * 40 + 4

call DumpRegs

    exit

main ENDP
END main

이 코드를 실행시켜보면

16진수 54로 10진수 84가 맞습니다. 실제로 잘 되는 것으로 확인됩니다.

 

LABEL 디렉티브

LABEL 디렉티브는 공간을 할당 하는 명령어입니다. 똑같은 정보를 WORD로 보거나 DWORD로 보는 걸 간편하게 하려고 만들어진 디렉티브죠. 코드를 봅시다.

include 	c:\assembly\irvine32.inc
includelib  c:\assembly\irvine32.lib
includelib  c:\assembly\kernel32.lib
includelib  c:\assembly\user32.lib

.data
wVal LABEL WORD
dVal DWORD 12345678h

.code
main PROC

mov ax, wVal        ;ax = 5678h
mov bx, [wVal + 2]  ;bx = 1234h
mov ecx, dVal       ;ecx = 12345678h

call DumpRegs

    exit

main ENDP
END main

코드를 실행시켜보겠습니다.

잘 실행되는 것을 볼 수 있습니다.

Comments