'어셈블러'에 해당되는 글 2건

  1. 2010.03.26 [MASM 강좌] 튜토리얼 2 : MessageBox (1)
  2. 2010.03.07 Visual Studio 2008 에서 MASM 개발하기 (6)

튜토리얼 2: MessageBox

이번 튜토리얼에서는 "Win32 assembly is great!" 을 출력하는 메세지 박스를 보여주는 완전한 Windows 프로그램을 만들 것입니다.
예제파일은 여기에서 받으실 수 있습니다.

이론:

Windows는 윈도우 프로그램을 위해 많은 리소스를 제공합니다. 그 중심에 Windows API(Application Programming Interface)가 있습니다. Windows API 는 매우 유용한 함수들을 한데 모아놓은 것이며, Windows 에 내포되어 있기 때문에 Windows 프로그램에서 바로 사용할 수 있습니다. 이러한 함수들은 kernel32.dll, user32.dll, gdi32.dll 과 같은 동적링크 라이브러리(DLLs)들에 저장되어 있습니다. kernel32.dll 에는 메모리와 프로세스를 관리하는 함수들이 있습니다. user32.dll 은 프로그램 사용자의 인터페이스(user interface) 외관을 관리합니다. gdi32.dll 은 그래픽 연산을 책임집니다. 프로그램은 이 세개의 주요 DLL 이외에도 다른 DLL을 사용 할 수 있습니다. 그리고 그것들은 API 함수들에 대해 충분한 정보를 제공합니다.

Windows 프로그램들은 이들 DLL과 동적으로 연결됩니다. 다시 말해 API 함수들의 코드는 Windows 실행 프로그램에 포함되지 않습니다. 프로그램이 실행시 API 함수를 어디서 찾아야 하는지 알려주기 위해서, 실행파일 안에 정보를 포함시켜야만 합니다. 그 정보는 임포트(import)한 라이브러리 안에 있습니다. 반드시 프로그램에 올바른 import 라이브러리를 링크시키야 하며, 그렇지 않으면 API 함수를 사용 할 수 없습니다.

Windows 프로그램이 메모리에 로딩될 때, Windows 는 프로그램 안에 기록된 정보를 읽습니다. 그 정보는 프로그램이 사용하는 함수들의 이름들과 그 함수가 있는  DLL에 대한 것입니다. Windows 은 프로그램 안에서 이런 정보들을 발견하면, 해당 DLL 을 로드하고 프로그램 안에 그 함수의 주소를 입력합니다. 이런 방식으로 함수 호출시 올바른 함수를 찾아가게 되는 것입니다.

API 함수에는 두 개의 카테고리가 있습니다. 하나는 ANSI 를 위한 것이고, 다른 하나는 unicode 를 위한 것입니다. ANSI 를 위한 API 함수의 이름에는 "A"라는 접미사가 붙습니다. 예를들면 MessageBoxA 가 있습니다. unicode를 위한 함수에는 "W"(제 생각에는 Wide Char 에서 비롯되었다고 생각합니다)라는 접미사가 붙습니다. Windows 95 는 본디 ANSI 를 지원하고, Windows NT는 unicode 를 지원합니다.

일반적으로 우리는 NULL 로 끝나는 문자열인 ANSI 문자열에 친숙합니다. ANSI 문자는 한 문자당 1byte 를 차지합니다. ANSI 코드가 유럽문자를 표현하기 위해서는 적합하지만, 수 천 가지가 넘는 다양한 문자를 사용하는 동양의 언어를 표현하기는 불가능합니다. 이 때문에 UNICODE 가 나온 것입니다. UNICODE 문자 하나는 2 byte 를 차지하며, 65536 개의 문자를 표현 할 수 있습니다.

하지만 대부분의 경우, 플랫폼에 맞는 API 함수들을 결정하고 선택적으로 포함파일(include file)을 사용할 것입니다. API 함수 이름을 조회할 때, 접두사는 빼야합니다.

예:

아래는 완전한 프로그램의 뼈대입니다. 살을 붙여나가 봅시다.

.386
.model flat, stdcall 
.data 
.code 
start: 
end start

실행은 end 지시자 바로 다음에 나오는 라벨의 명령부터 시작됩니다. 위의 뼈대에서는 start 다음 명령부터 실행이 시작 됩니다. 실행은 jmp, jne, je, ret 등 처럼 흐름제어(flow-control) 명령어을 만나기전까지는 명령에서 다음 명령으로 순차적으로 수행될 것입니다. 이런 흐름제어(flow-control) 명령들은 실행의 흐름을 다른 명령이 있는 곳으로 바꾸어 버립니다. 프로그램을 종료하여 Windows 로 빠져 나오려면, ExpitProcess 라는 API 함수를 호출해야 합니다.

ExitProcess proto uExitCode:DWORD

이 행(line)을 함수 프로토타입(prototype)이라고 합니다. 함수 프로토타입은 어셈블러/링커에게 함수의 속성들을 정의하여 타입 체크가 가능하도록 만듭니다. 함수 프로토타입의 형식은 다음과 같습니다.

FunctionName PROTO [ParameterName]:DataType,[ParameterName]:DataType,...

간단히 말하자면, 함수 이름 다음에 PROTO 키워드가 나오고, 그 다음 파라미터의 데이타 타입들이 콤마로 구분되어 나오게 됩니다. 위의 ExitProcess 예제에서는 ExitProcess 함수가 DWORD 타입의 파라미터 하나만 갖는다고 정의되었습니다. 함수 프로토타입은 invoke 라는 고급 호출(high-level call)을 사용할 때, 매우 유용합니다. invoke 를 타입검사(type-checking)이 되는 호출정도로 생각하시면 됩니다. 예를 들어, 다음과 같이 했다고 가정합시다.

call ExitProcess

dword 크기의 값을 스택에 넣지(push) 않았지만, 어셈블러/링커는 이 오류를 잡아내지 못 합니다. 하지만 나중에 프로그램 충(crash)돌이 발생하면, 잘못 되었다는 것을 알게 되겠지요. 만약 다음처럼 했다고 해 봅시다.

invoke ExitProcess

링커(linker)는 스택에 dword 크기의 값을 넣지(push) 않은 것을 잡아 낼 것이고, 에러를 피할 수 있게 됩니다. 저는 여러분이 단순한 call 보다는 invoke 를 사용하길 권장합니다. invoke 의 문법은 다음과 같습니다.

INVOKE  expression [,arguments]

expression 에는 함수 이름 또는 함수 포인터가 올 수 있습니다. 함수 파라미터들은 콤마로 구분합니다.

대부분의 API 함수 프로토타입은 include 파일들 안에 들어 있습니다.  만약 여러분이 hutch 의 MASM32 를 사용한다면, MASM32/include 폴더 안에 있을 것입니다. include 파일들은 .inc 확장자를 가지고 있으며, DLL 파일의 함수 프로토타입은 해당 DLL과 동일 이름의 .inc 파일 안에 있습니다. 예를 들어, ExitProcess 는 kernel32.lib 안에 있습니다. 그러므로 함수의 프로토타입은 kernel32.inc 안에 있습니다.
 
또한 여러분이 만든 함수의 프로토타입도 만들 수 있습니다.
저는 예제 전반에 걸쳐, http://win32asm.cjb.net 에서 받을 수 있는 hutch의 windows.inc 를 사용할 것입니다.

자, 그럼 ExitProcess 로 다시 돌아와 봅시다, uExitCode 파라미터는 프로그램이 종료 될 때, Windows 에게 반환(return)할 값입니다.

invoke ExitProcess, 0

start 라벨 바로 다음 줄에 위 코드(line)를 넣어봅시다. 아마도 실행하자마자 종료되어 Windows로 돌아오는 Win32 프로그램이 만들어 질 것입니다. 그렇다고 해도 이것 역시 온전한 프로그램입니다.

.386 
.model flat, stdcall 
option casemap:none 
include \masm32\include\windows.inc 
include \masm32\include\kernel32.inc 
includelib \masm32\lib\kernel32.lib 
.data 
.code 
start: 
        invoke ExitProcess,0 
end start


option casemap:none 은 MASM 에게 대소문자를 구분하여 ExitProcess 와 exitprocess 를 다르게 인식하라는 것 입니다.  include 에 주목하세요. 이 지시자 바로 뒤에는 그  위치에 삽입하고 싶은 파일의 이름이 나옵니다. 위의 예제에서는, MASM 이 include \masm32\include\windows.inc행을 실행할 때, 마치 여러분이 windows.inc 파일 안에 내용을 붙여 넣은 것 처럼, \MASM\include 폴더에 있는 windows.inc 를 열어 실행할 것입니다. hutch 의 windows.inc 안에는 win32 프로그래밍에 필요한 상수와 구조체들이 정의되어 있습니다. 함수의 프로토타입은 없는게 없습니다. 그렇기에 windows.inc 는 말할 필요도 없이 방대합니다. hutch 와 저는 가능하면 많은 상수들과 구조체를 넣으려고 하고 있지만, 아직도 포함해야 할 것들이 많이 남아 있습니다. 계속해서 업데이트 할 것입니다. hutch 와 저의 홈페이지에서 업데이트를 확인하세요.
windows.inc 를 통해 여러분의 프로그램은 상수와 구조체 정의를 얻을 것입니다. 앞으로 함수 프로토타입을 위해서는,  include 파일들을 포함시키면 됩니다.. 이것들은 모두 \masm32\include 폴더 안에 있습니다.

위에 예제에서는 kernel32.dll 안에 있는 함수를 사용했기 때문에, kernel32.dll 에  있는 함수 프로토타입들을 포함시켜야만 했습니다. 그 파일은 kernel32.dll 입니다. 이 파일을 문서 편집기로 열어보면, kernel32.dll 을 위한 함수 프로토타입들로 가득한 것을 확인하실 수 있습니다. kernel32.inc 를 포함시키지 않더라도, 단순히 call 문법을 사용해서 ExitProcess 함수를 호출 할 수는 있습니다. 하지만 invoke 로 함수를 호출 할 수는 없습니다. 요점은 이렇습니다. invoke 로 함수를 호출하려면, 그 함수의 프로토타입을 소스 코드 어디엔가 넣어야 합니다.  위 예제에서, kernel32.inc 를 include 하지 않더라도, invoke 를 사용하기 전에 소스코드 어디든 ExitProcess 의 함수 프로토타입만 넣어주면 이상없이 작동됩니다. include 파일들은 프로토타입을 일일이 타이핑하지 않도록 해 주며, 필요할 때 사용하시면 됩니다.
이제 다음으로 includelib 지시자를 살펴 봅시다. includelib 는 include 와 같지는 않습니다. 이것은 어셈블러에게 프로그램에서 사용하고 있는 포함 라이브러리(import library)가 무엇인지 알려주는 방법입니다. 어셈블러가 includelib 지시자를 만나면, 링커 명령(linker command)를 object 파일에 넣어, 링커가 링크시 프로그램이 필요로 하는 포함 라이브러리가 무엇인지 알게 해 줍니다. 그렇다고 해서 includelib 를 반드시 사용해야만 하는것은 아닙니다. 링커의 커맨드 라인(command line)에 포함시켜야 하는 라이브러리의 이름을 적어 주어도 됩니다. 하지만 그렇게 하는 것은 매우 귀찮은 일일 뿐더러, 커맨드 라인은 128 문자를 초과할 수 없습니다.

이제 msgbox.asm 이라는 이름으로 예제를 저장해 봅시다. ml.exe 가 있는 경로여야 합니다. msgbox.asm 을 다음과 같이 어셈블합니다.

ml  /c  /coff  /Cp msgbox.asm
  • /c 는 MASM 이 어셈블만 하도록 합니다. link.exe 는 호출하지 말라는 것이죠. 대부분의 경우, 대부분의 경우 link.exe 를 호출하기 전에 몇 가지 작업들을 해야 하기 때문에, link.exe 가 자동으로 호출되는 것을 기피할 것입니다.

    /coff 는 MASM 이 .obj 파일을 COFF 포맷으로 만도록 합니다. MASM은 object 와 실행파일 포맷(format)으로 유닉스에서 사용되는 COFF(Common Object File Format)의 변형을 사용합니다.
     
    /Cp 는 MASM 이 식별자의 대소문자를 구분하도록 합니다. 만약 여러분이 hutch 의 MASM32 를 사용한다면, 동일한 효과를 얻기 위해서 아마도 소스코드 상단 .model 바로 아래에 "option casemap:none" 이라고 했을 것입니다.
msgbox.asm 을 성공적으로 어셈블리 했다면, msgbox.obj 가 생겼을 것입니다. msgbox.obj 는 오브젝트 파일입니다. 오브젝트 파일은 실행파일을 만들기 위한 첫 단계입니다. 이 안에는 명령어/데이타들이 바이너리 형태로 들어 있습니다. 이제 linker 가 주소를 수정할 일이 남아 있습니다.

그럼 이제 링크(link) 를 해 봅시다.

link /SUBSYSTEM:WINDOWS  /LIBPATH:c:\masm32\lib  msgbox.obj

/SUBSYSTEM:WINDOWS 는 Link 에게 이 프로그램의 실행 순서를 알려 줍니다.
/LIBPATH:<path to import library> 는 Link 가 포함시켜야 할 라이브러리들이 어디 있는지 알려 줍니다. 만약  MASM32를 사용한다면, MASM32\lib 폴더에 있을 것입니다.

Link 는 object 파일을 읽고, 포함된 라이브러리로부터 주소를 수정합니다. 이 과정이 끝나고 나면 msgbox.exe 파일이 생성됩니다. 
이제 msgbox.exe 를 얻었습니다.
 
실행 해 보세요. 아무 일도 하지 않을 것 입니다. 아직 여기에 어떤 재미있는 것도 넣지 않았습니다. 하지만 그래도 이것은 Windows 프로그램입니다. 파일 사이즈를 한번 보죠!, 제 PC 에서는 1,536 bytes 입니다.

다음으로 메세지 박스를 넣어 볼 것입니다. 이 함수의 프로토타입은 다음과 같습니다.

MessageBox PROTO hwnd:DWORD, lpText:DWORD, lpCaption:DWORD, uType:DWORD

hwnd 는 부모창의 핸들(handle)입니다. handle 은 참조하고 있는 윈도우를 나타내는 숫자라고 생각하면 됩니다. 이 값은 여러분에게 중요하지 않습니다. 단지 윈도우를 나타내는 숫자라고만 기억하면 됩니다. 여러분이 윈도우를 가지고 어떤 것을 하고 싶을 때, 이 핸들을 통해서 참조해야만 할 것입니다.
lpText 는 메세지 박스의 클라이언트 영역(client area)에 나타낼 문자를 가리키는 포인터(pointer)입니다. 포인터는(pointer) 어떤 것들의 실제 주소값 입니다. 문자열의 포인터 == string 의 주소
lpCaption 은 메세지 박스의 캡션(caption) 을 가리키는 포인터입니다.
uType 은 아이콘과 숫자와 메세지 박스의 버튼 타입을 명시합니다.

msgbox.asm 에 메세지 박스를 넣어 봅시다. 
 
.386 
.model flat,stdcall 
option casemap:none 
include \masm32\include\windows.inc 
include \masm32\include\kernel32.inc 
includelib \masm32\lib\kernel32.lib 
include \masm32\include\user32.inc 
includelib \masm32\lib\user32.lib
.data 
MsgBoxCaption  db "Iczelion Tutorial No.2",0 
MsgBoxText       db "Win32 Assembly is Great!",0
.code 
start: 
invoke MessageBox, NULL, addr MsgBoxText, addr MsgBoxCaption, MB_OK 
invoke ExitProcess, NULL 
end start

어셈블리하고 실행 해 봅시다. "Win32 Assembly is Great!" 를 출력하는 메세지 박스를 볼 수 있을 것 입니다.

소스코드를 다시 살펴 봅시다.
.data 섹션 안에 zero-terminated(역주:0으로 문자열 끝을 알리는) 문자열을 선언했습니다. Windows 에서 모든 ANSI 문자열은 NULL (16진수 0)로 끝난다는 것을 잊지 마세요.
NULL 과 MB_OK 이렇게 두 개의 상수를 사용하였습니다. 이 상수들은 windows.inc 에 기록되어 있습니다. 그렇기 때문에 값 대신 이름을 사용 할 수 있습니다. 이것은 소스코드의 가독성을 높여 줍니다.
addr 연산자는 라벨의 함수 주소를 전달하기 위해서 사용 되었습니다. 이것은 invoke 지시자 문맥에서만 사용할 수 있습니다. 예를 들어, 레지스터(register)나 변수에게 라벨의 주소를 저장하기 위해서는 사용할 수 없습니다. 이 경우엔 addr 대신 offset 을 사용할 수 있습니다. 이렇듯 둘 사이에는 조금 차이점이 있습니다.

1. addroffset와 달리, 앞에서 참조를 할 수는 없습니다. 예를 들어, 라벨이 소스코드에서 invoke 보다 아래쪽에 선언되어 있다면, addr 을 사용할 수 없습니다..
invoke MessageBox,NULL, addr MsgBoxText,addr MsgBoxCaption,MB_OK 
...... 
MsgBoxCaption  db "Iczelion Tutorial No.2",0 
MsgBoxText       db "Win32 Assembly is Great!",0

MASM 은 에러를 발견할 것입니다. 만약 위의 코드에서 addr 대신 offset 을 사용한다면, 성공적으로 어셈블리 될 것 입니다. 

2. addroffset 과 달리 지역변수를 처리(handle)할 수 있습니다. 지역변수는 단지 스택에 예약된 공간입니다. 이 주소는 실행시간(runtime)에만 알 수 있습니다. offset 은 어셈블러에 의해서 어셈블리 시간에 계산 됩니다. 그렇기 때문에 offset 을 지역변수에 사용 할 수 없는 것은 당연합니다. addr 가 지역변수를 처리(handle)할 수 있는 이유는 어셈블러가 addr 이 참조하는 변수가 전역인지 지역인지를 가장 먼저 확인하기 때문입니다. 만약 전역변수라면, 오브젝트 파일 안에 변수의 주소를 넣습니다. 이것은 offset 과 비슷하게 동작합니다. 만약 이것이 지역변수라면 실제로 함수를 호출 하기 전에 다음과 같은 코드를 생성합니다.

lea eax, LocalVar 
push eax

lea 는 실행시간에 라벨의 주소를 알 수 있기 때문에, 성공적으로 실행됩니다.

신고

Introduction

어셈블리(Assembly)라고 하면 보통 '너무 오래된 언어', '구닥다리 언어', '배우기 어려운 언어', '외계문자' 등의 생각을 하는 분들이 많이 있습니다. =_= 하지만 어셈블리는 알고보면 정말 재미있고, 흥미로운 언어임에 틀림 없습니다. 그리고 어셈블리는 절대 사라지지 않을 멋진 녀석입니다. O/S를 만들때도, C언어로 만들긴 하지만 kernel 은 아직도 어셈블리로 만든다고 합니다. 그만큼 강력하고 무엇이든 할 수 있는 강한놈이죠. 하지만 처음 언어가 나온지 오랜 시간이 지난만큼, 다른 언어에 비해 정보를 얻기 힘이 듭니다. 오늘은 어셈블러에는 어떤 종류가 있고, Visual Studio 에서 어떻게 개발할 수 있는 지에 대해서 알아보도록 하겠습니다.



어셈블러(Assembler)의 종류

MASM(Microsoft Macro Assembler), NASM(Netwide Assembler), FASM(Flat Assembler), GAS(GNU Assembler), YASM 등 정말 다양한 종류가 있습니다. 그럼 여기서 잠시 질문하나 드리겠습니다. 어셈블리(Assembly)는 무엇이고 어셈블러(Assembler)는 무엇일까요? 그렇습니다. 어셈블리는 언어를 말하는 것이고, 어셈블러는 compiler 를 의미하는 것입니다. 물론 어셈에서는 C언어처럼 컴파일 이라는 용어대신 Assemble 한다고 표현하며, 이 동작을 해 주는 녀석을 Assembler 라고 말합니다.

 자, 그럼 위에서 나열한 것은 Assembler 의 종류입니다. 그런데 왜 각각에 대해서 문법이 다를까요?
Assembler 마다 지원하는 platform 이 다르고, syntax 형태도 차이가 있습니다. 당연히 platform 에 따라 종류를 나누면 상당히 많은 어셈블리가 존재하지요. 인텔(Intel)의 IA-32 Assembly 도 있고, IA-64 Assembly 도 있습니다. 그 이외에 상당히 많은 종류의 어셈블리(Assembly)가 존재하지요. syntax 에는 Intel 방식과 AT&T 방식이 있습니다. 자세한 내용은 아래에서 계속 설명 드리도록 하겠습니다.


GAS(GNU Assembler)

GAS 는 약자 속에 나와 있듯이 GNU Project 에서 사용되고 만들어진 어셈블러입니다. 당연히 GCC 안에 기본적으로 사용되는 녀석이기도 하지요. Linux 에서 인라인 어셈을 해 보신 분은 GAS가 어떤 syntax 를 사용하는지 아실겁니다. 바로 AT&T 입니다. 제가 싫어하는 문법이기도 하지요 =_=; 간단히 예를 들면 MOV EAX, 80 을 MOV $80, %EAX 로 표현합니다. 전자는 AT&T 이외에 다른 syntax 인 Intel syntax 입니다. 여튼 GAS는 Free Software 이고, Cross Platform 을 지원합니다.


MASM(Microsoft Macro Assembler)

가장 많이 들어보셨을 어셈블러(Assemler)라고 생각합니다. Microsoft 에서 만들었으며, 많은 사랑을 받아온 어셈블러입니다. 64-bit 도 지원하며, syntax 는 Intel 방식을 따릅니다. 개인적으로 저는 이 syntax 가 가독성이 좋습니다. MASM 는 초기에 유료로 제공되었으며 사용하기 위해서는 별도로 설치를 해 주어야 합니다. 하지만 이제는 뮤로로 제공되며 고맙게도 Visual Studio 2008 이상 버젼부터는 기본적으로 MASM v9.0이 기본적으로 포함되어 있기 때문에 별도 설치를 해 줄 필요가 없습니다. 더불어 MASM 은 이름에서도 알 수 있듯이, 강력한 Macro 를 지원해줌으로써 프로그래머가 좀 더 편리하게 개발 할 수 있도록 지원해 줍니다. 편리하긴 하지만 때론 Assemly 의 참 모습을 잃어가는 것 같아 조금 아쉽기도 하네요. 참, 아시다시피 cross-platform 은 지원되지 않습니다 ^-^;

참고 사이트
http://www.masm32.com
http://www.movsd.com


NASM(Netwide Assembler)

80x86 platform 용으로 개발된 어셈블러입니다. 그리고 open-source 로 시작되었지요. 왜 그랬을까요? 네, 바로 Microsoft 때문입니다 -_-; 당시 Microsoft 의 MASM은 상용으로서 돈을 지불하고 사야만 했기 때문이죠. 그렇기에 MASM과 비슷한 점이 많고, 사람들의 비교 대상도 되곤 합니다. NASM의 장점은 현재는 Cross-Platform 을 지원한다는 것과 Macro(단, x86 platform에서) 를 제공한다는 것입니다. 그렇기에 일반적으로 Kernel 과 같이 O/S를 개발할 경우에 많이 사용되는 Assembler 입니다.

참고 사이트
http://www.nasm.us



이외의 Aseembler

이밖에 어셈블러(Assembler)는 다음 주소를 참고하시기 바랍니다.
JWASM : http://www.japheth.de/JWasm.html
FASM : http://flatassembler.net/
YASM : http://www.tortall.net/projects/yasm/




Visual Studio 2008 & MASM

 MASM 을 사용하기 위해서 꼭 Visual Studio 가 필요한 것은 결코 아닙니다. MASM32 v10 을 설치하면 Quick Editor 라는 IDE 툴이 제공됩니다. 그리고 IDE 없이 console 에서 얼마든지 어셈블이 기능합니다. 하지만 C++ 프로젝트에 ASM을 사용하는 거라면 아무래도 Visual Studio 2008에서 개발하는게 편하겠죠. 저는 IDE 툴을 여러개 나눠서 쓰는것이 싫어서 Visual Studio 을 사용하는 것을 선호합니다.


[ MASM32 v10 의 Quick Editor]

MASM 설치하기

Visual Studio 2005 이하의 버젼이라면 Microsoft 홈페이지에서 별도로 MASM을 다운받아 설치하셔야 합니다. 하지만 Visual Studio 2008 이상의 버젼이라면 고민할 필요가 없습니다. 기본적으로 설치되어 있기 때문이죠. T^T

Program Files\Microsoft Visual Studio 9.0\VC\bin

다음 path 에서 ml.exe 를 실행시키면 다음과 같은 output 을 보실 수 있습니다.

Microsoft (R) Macro Assembler Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.

usage: ML [ options ] filelist [ /link linkoptions]
Run "ML /help" or "ML /?" for more info

하지만 여기서 끝난것이 아닙니다.
Visual Studio 2008 에 MASM 이 있긴 하지만, *.inc 와 *.lib 파일은 포함되어 있지 않습니다. 다시 말해 그냥 어셈블러만 있을 뿐 필요한 몇몇 것들이 없다는 것이죠. *.inc 는 쉽게 설명하자면 함수들(*.lib)의 프로토타입을 정리해 놓은 파일입니다. kernel32.inc 파일안에는 어떤 내용이 있을지 상상이 가시나요~? 그걸 모두 일일이 타이핑 한다는 생각을 하니 끔찍하군요.
그렇습니다. 우린 기존에 있는걸 가져다 써야 합니다. -_-; 그러기 위해서는 보통 http://kipirvine.com/asm/ 에서 irvine이라고 압축된 것을 이용하거나, 저처럼 MASM32 를 다운로드 받아 include 와 lib 를 가져다 사용합니다.(MASM32 v10 의 include 와 lib 만 따로 압축해서 게시물에 올려두었습니다)
Kip Irvine 은 아마도 사람 이름입니다. 그 사람이 압축해 놓은 걸 겝니다~. 이 파일들 경로 설정은 프로젝트 속성에서 해야 하므로 밑에 Sample 설명을 할때  말씀 드리도록 하겠습니다.

Syntax Highlight 설정하기

기본적으로 Visual Studio 에서 .asm 의 확장자로 파일을 생성하면, Syntax Highlight 가 적용되지 않습니다. 상당히 불편하죠. 이를 해결하기 위한 방법은 다음과 같습니다.

1. usertype.dat 파일을 이용하는 방법
Keyword 가 들어있는 usertype.dat 파일을 생성한 뒤, \Program Files\Microsoft Visual Studio 9.0\Common7\IDE 폴더에 집어 넣습니다.(visual studio 2008 은 \Program Files\Microsoft Visual Studio 8.0\Common7\IDE)

usertype.dat 보기

이후, Visual Studio 에서 도구->옵션->텍스트편집기->파일 확장명에 asm 을 추가해 주시면 됩니다.

 


2. Addin 을 설치하는 방법

개인적으로 가장 선호하는 방법입니다. 여러가지 addin 이 있으니 본인이 마음에 드는 것을 설치하시면 됩니다. 저는 http://asmhighlighter.codeplex.com/ 를 이용합니다. MASM 뿐만 아니라 NASM 까지 지원합니다. Syntax는 x86 ASAM 을 지원합니다.


Sample Code!

이제 환경 샘플 코드를 통해서 Assemble 해 보도록 합시다.

1. 프로젝트 생성

먼저 콘솔 응용프로그램을 생성합니다. 빈 프로젝트로 말이죠.

2. 코딩~
위 그림처럼 asm 확장자를 갖는 파일을 하나 생성합니다. 그리고 아래 코드를 타이핑 해 봅시다.

더보기(HelloWitstudio.asm)



3. 빌드규칙 지정하기

코드도 타이핑하였으니, 이제 빌드를 하면 됩니다. 그냥 빌드를 하면 오류가 발생할겁니다. 왜냐면 .asm 에 대해서 빌드 방법을 지정해 주지 않았기 때문이죠. 위 그림처럼 프로젝트를 선택한 뒤, 프로젝트 -> 사용자 지정 빌드규칙 을 선택합니다. 그리고 아래처럼 ASM에 대해서 빌드 방식을 지정해 줍니다. 



5. include 파일과 lib 파일 경로 지정 / 실행

위에서 *.inc 과 *.lib 파일이 필요하다고 했던것 기억나실겁니다. 이제 이 경로를 지정해 주어야 합니다.

프로젝트 -> 속성 -> 구성속성 -> 일반 을 보면 위와 같이 '추가 라이브러리 디렉터리' 라는 곳이 있습니다. 이곳에 lib의 상위 path 를 적어주시면 됩니다. 그림의 경우 D:\masm32\lib 에 라이브러리 파일들이 있으므로 D:\masm32 라고 적어주었습니다.

그리고 Microsoft Macro Assembly -> General 에서 Include path 를 적어줍니다. 이 부분의 본인의 편의에 따라 맞게 적어주시면 됩니다.
저의 경우 D:\masm32\include 안에 *.inc 파일이 있습니다. 만약 위에 그림처럼 D:\masm32 라고 적는다면 코드에서는 "INCLUDE include\windows.inc" 라고 적어주어야 합니다. 같은 이치로 코드에서 include masm32\include\windows.inc 형태로 작성하고 싶다면, 위에 화면에서 D:\ 라고만 적어주시면 됩니다.


이후 F5를 눌러 실행하면 성공적으로 MessageBox를 보실 수 있습니다.



정리

오늘의 포스팅 주제는 사실 'ASM으로 DLL 을 만들어 활용하기' 로 기획했습니다. 하지만 이것저것 주저리 주저리 적다보니 내용이 너무 길어졌군요. ㅠ.ㅜ 항상 이런 식인것 같습니다. 왜 항상 글을 쓰기 시작하면 삼천포로 빠지든가, 쓸모 없는 내용이 길어지나 모르겠습니다. 여튼 각설하고 다음에는 정말 처음 기획한 주제에 대해서 포스팅하도록 하겠습니다. ^-^;



신고