반응형
처음에 대부분의 프로그래머는 어셈블러(또는 어셈블리 언어)라고 하면 뒷걸음질을 칩니다.보통어셈블라는배우는것도사용하는것도굉장히어려운언어라고생각이됩니다.게다가 어셈블러의 사용법을 알고 있는 사람은, 주위의 프로그래머로부터 모종의 존경을 모으는 경향에 있습니다.이 튜토리얼은 어셈블러에 대한 이러한 오해를 불식시키기 위한 3회 시리즈 중 첫 번째입니다.이 튜토리얼을 통해서 어셈블라는 사실 어려운 언어가 아니라 오히려 쉬운 언어라는 것을 증명하고 싶습니다.첫 번째 시간에는 어셈블러의 코딩을 대폭 단순화하기 위한 툴을 소개하고 이를 Visual Studio로 통합하는 방법을 설명하겠습니다.어셈블러란 원래, 어셈블러란 도대체 무엇일까요.아주 간단하게 말하면, 어셈블라는 프로세서의 언어입니다.이보다 낮은 레벨로 내려갈 수는 없습니다(각 명령의 실제의 바이트치를 조작하는 경우는 이야기가 다릅니다만).mov, add 이런 명령어들은 전부 다 어셈블러 프로그램에 의해서 수치로 직접 변환되고, 그것이 프로세서에 넘겨져서 실행이 됩니다.어셈블라가 다른 언어보다 뛰어난 것은 처리속도의 빠름입니다.어셈블러에서는 프로세서의 실행 속도를 그대로 이용할 수 있습니다.최신 컴파일러를 사용하여 코드를 최적화했다고 해도 그 코드의 실행 속도는 어셈블러에서 기술하여 최적화한 동등한 코드에는 미치지 못할 것입니다.그러나 어셈블라는 아무것이나 사용할 수 있는 것은 아닙니다.하나의 애플리케이션을 전부 어셈블러로 기술하는 것도 가능하지만, 현재는 C++ 와 같은 고등언어를 이용할 수 있기 때문에, 그런 것을 하는 것은 색다른 일입니다.대다수의 어플리케이션에서는 C++의 속도, 혹은 .NET 의 속도에서도 충분히 허용 범위내입니다.어셈블라가 이용되는 것은, 속도가 중시되는 애플리케이션, 예를 들면 그래픽 애플리케이션 등에서입니다.큰 메모리 블록을 처리하는 작고 매우 빠른 함수를 기술할 경우에는 어셈블러에 맞는 것은 없습니다.비트맵 조작은 어셈블러에 대한 지식이 크게 나타나는 사례의 대표적인 예입니다.어셈블러라고하는언어의개요와장점을이해했다면다음에는어떻게쓰는지한번살펴보도록하겠습니다.Visual C++ 내에서 어셈블러를 사용하는 C++ 내에서 어셈블러를 기술하는 하나의 방법은, __asm 블록을 사용하는 것입니다.DWORD Function ( DWORD dwValue )
{
__ asm
{
mov eax , dwValue
add eax , 100
mov dwValue , eax
}
return dwValue ;
}}이 예에서는 __asm 블록 안에 어셈블러의 명령을 몇 가지 기술했습니다.C++ 컴파일러는 이들 명령을 각각의 머신어 코드로 직접 변환합니다.코드의 의미는 생각하지 않아도 됩니다.add가 값의 가산 명령이고, mov가 값의 이동 명령이라는 것을 알면 충분합니다.상기 코드에서는 건네받은 값에 100을 가산하고 있을 뿐입니다.이게 대체 무슨 일인가, 하고 생각한 사람도 있는 것은 아닐까요.하지만 그렇게 하면 안 되죠.__asm블록 안에 코드를 기술한다고 하는 방법은 짧은 어셈블러 코드의 경우는 문제가 없지만 어느 정도 긴 함수를 기술하려고 하면 조금 번거롭습니다.예를 들어 if..else문은 다음과 같습니다.DWORD Function 2 ( DWORD dwValue 1 , DWORD dwValue 2 )
{
DWORD dwValue 3 = 0 ;
# if 0
// this is the Assembler
if ( dwValue 1 == dwValue 2 )
{
dwValue 3 = 1 ;
}
else
{
dwValue 3 = 2 ;
}
# endif
__ asm
{
mov eax , dwValue 1
; this is the test of the values , i . e . if dwValue 1 == dwValue 2
cmp eax , dwValue 2
; jump to ′ Else ′ if they are not equal
jne Else
mov eax , 1
jmp EndIf
Else :
mov eax , 2
EndIf :
mov dwValue 3 , eax
}
return dwValue 3 ;
}여기서도, 실제 명령에 대해서는 너무 신경쓰지 말아 주세요.그런데 모든 if문에 대해서 이런 코드를 써야 한다면 어떨까요?__asm 코드블록을 사용하는 것은 메모장과 명령어 프롬프트를 사용하여 C++를 기술하는 것과 같습니다.확실히 할 수 없는 것은 아니지만 전용 도구를 사용하는 경우보다 훨씬 시간이 걸립니다.그럼 어셈블러를 기술하기 위한 전용 툴에는 어떤 것이 있을까요.여기에서는 Microsoft Macro Assembler를 소개해 두겠습니다(잘못 들은 것이 아닙니다.Microsoft 도 어셈블러를 제공하고 있습니다).사실 Microsoft는 1980년부터 어셈블러를 제공하고 있습니다만, 별로 알려져 있지는 않습니다.더 중요한 것은 Microsoft Macro Assembler는 Visual C++ 링커와 호환되는 .obj 파일을 생성합니다.디버깅정보를 포함한 .obj파일을 생성하고 코드를 스텝실행할 수도 있습니다.이 기사에서는, MASM 를 사용하기 위한 프리웨어인 「MASM32」라고 하는 어셈블러를 사용합니다.MASM32는 http://www.masm32.com/ 에서 입수할 수 있습니다.앞으로 나아가기 전에, MASM32 를 다운로드해 인스톨 해 주세요.MASM32에는 어떤 메리트가 있을까요?첫째, 방대한 양의 도움말 파일이 들어 있습니다(′msasm32help′ 디렉토리에 수록).두 번째로 개발자가 필요로 할 각종 작업에 대한 매크로가 준비되어 있습니다.게다가 이러한 매크로를 사용하면, 각각의 작업을 실행하는 가장 효율적인 방법을 선택하고 있는 것을 확신할 수 있습니다.예를 들어, 전술의 코드를 MASM32 를 사용해 기술하면 다음과 같이 됩니다.Function proc dwValue 1 : DWORD , dwValue 2 : DWORD
mov eax , dwValue 1
. if eax == dwValue 2
mov eax , 1
. else
mov eax , 2
. endif
ret
Function endp 이게 훨씬 읽기 쉬울 거예요MASM32를 다운로드해 인스톨 했는데, 이후에서는, 어셈블러 파일을 기존의 C++프로젝트에 추가하는 방법과 그것을 컴파일 하기 위한 프로젝트 설정의 설정 방법, 어셈블러로 기술한 함수에 C++ 로부터 액세스 하는 방법에 대해서, 차례로 살펴보도록 하겠습니다.어셈블러 파일을 Visual C++ 에 추가하는 이후의 순서는 Visual Studio.NET 2002(영어판) 의 것입니다만, Visual C++ 6 또는 Visual Studio.NET 2003 에서도 같이 실행할 수 있습니다.우선, 애플리케이션의 검색 디렉토리에 MASM32 의 「bin」폴더를 포함할 필요가 있습니다.[Tools]→[Options]→[Visual C++ Directories]를 선택합니다.MASM을 인스톨 한 경로 아래에 있는 「bin」폴더를 추가합니다.예를 들면, 「C:MASM32」디렉토리에 인스톨 했을 경우는 「C:MASM32in」이 됩니다.이 디렉토리를 목록의 맨 아래로 이동합니다.이게 굉장히 중요합니다.이 폴더에는 link.exe라고 하는 링커 어플리케이션도 포함되어 있는데, 이 링커가 Visual Studio에서 기본 링커 대신에 사용될 수 있기 때문입니다.다음으로 콘솔 어플리케이션용 프로젝트를 생성합니다.만들면 ′test.asm′ 이라는 이름의 파일을 프로젝트에 추가합니다.솔루션 익스플로러내의 「Source Files」폴더를 오른쪽 클릭해,[Add]→[Add New Item]를 선택합니다.test.asm 이라고 입력하고 [Enter]키를 치면 ′test.asm′ 이라고 하는 신규파일이 열립니다.이 파일에 다음의 코드를 입력합니다..486
. model flat , stdcall
option casemap : none
. code
TestProc proc dwValue : DWORD
mov eax , dwValue
add eax , 100
ret
TestProc endp
end 이 코드에서는 입력값(dw Value)에 100을 가산하여 결과를 반환하고 있습니다.다음은 이 파일에 대한 빌드 속성을 설정해야 합니다.디버깅 빌드 상태인 것을 확인해, 솔루션 익스플로러내에서 이 파일을 오른쪽 클릭해,[Properties]를 선택합니다.[Custom Build Step]→[General]을 선택해,[Command Line]에 다음의 커맨드 라인을 입력합니다.ml /c /coff / Zi / Fo′$(Out Dir)$(Input Name). asm.obj ′$(Input File Name)′ 또한 [Outputs]에 다음 경로를 입력합니다.$(Out Dir)$(Input Name). $(Input Name).asm.릴리즈 빌드 설정은 이와 거의 동일하나 명령줄에 /Zi 옵션을 포함하지 않는 점만 다릅니다.이것은 디버깅 정보를 생성하기 위한 옵션이기 때문에 릴리즈 빌드에서는 삭제합니다.따라서 다음과 같습니다.ml /c /coff /Fo′$(OutDir)$(InputName).asm.obj′$(InputFileName)′물론, 이를 매크로나 어드레스로 하여 이 과정을 자동화할 수도 있습니다.여기서는 현재 사용되는 어떤 버전의 Visual Studio에도 응용할 수 있도록 절차를 하나하나 소개해 두었습니다.다음은 어셈블리로 쓰인 함수를 C++에서 호출하는 방법을 설명하겠습니다.C++에서 어셈블러 코드를 호출하는 위의 어셈블러 코드에서는 DWORD(즉 32비트값)의 입력을 받는 Test Proc라고 하는 함수를 정의했습니다.이 함수를 호출하기 위해서는 C++ 내에서 함수를 선언할 필요가 있습니다.application의 main메서드가 기술되어 있는 .cpp파일안에서 첫 번째 #includes뒤에 다음 행을 입력합니다.extern ′C′ unsigned int __stdcall Test Proc(unsigned int dwValue); 또한 main 메서드 내에 다음 코드를 기술합니다.int main ( int argc , _ TCHAR * argv [ ] )
{
unsigned int dwValue = 100;
unsigned int dwReturn = TestProc ( dwValue ) ;
printf ( ′ % d n ′ , dwReturn ) ;
getchar ( ) ;
return 0 ;
}}이 어플리케이션을 실행하면 예상대로 ′200′이라는 결과가 반환됩니다.게다가 Test Proc를 호출하는 행에 브레이크 포인트를 설정하고 있었을 경우는 이 메소드에 스텝 인하고([F11] 키), 어셈블러 코드를 스텝 실행할 수 있습니다.실은, 어셈블러 코드내에 브레이크 포인트를 설정하는 것도 가능합니다.정리 제1회에서는, 어셈블러 파일을 작성해, 컴파일 해, C++코드로부터 호출하는 방법에 대해 설명했습니다.시리즈 제 2회에서는, 어셈블리 언어를 구성하고 있는 실제의 명령에 대해 설명하고, 레지스터등의 토픽에 대해서도 다루기로 합니다.파트2로→
{
__ asm
{
mov eax , dwValue
add eax , 100
mov dwValue , eax
}
return dwValue ;
}}이 예에서는 __asm 블록 안에 어셈블러의 명령을 몇 가지 기술했습니다.C++ 컴파일러는 이들 명령을 각각의 머신어 코드로 직접 변환합니다.코드의 의미는 생각하지 않아도 됩니다.add가 값의 가산 명령이고, mov가 값의 이동 명령이라는 것을 알면 충분합니다.상기 코드에서는 건네받은 값에 100을 가산하고 있을 뿐입니다.이게 대체 무슨 일인가, 하고 생각한 사람도 있는 것은 아닐까요.하지만 그렇게 하면 안 되죠.__asm블록 안에 코드를 기술한다고 하는 방법은 짧은 어셈블러 코드의 경우는 문제가 없지만 어느 정도 긴 함수를 기술하려고 하면 조금 번거롭습니다.예를 들어 if..else문은 다음과 같습니다.DWORD Function 2 ( DWORD dwValue 1 , DWORD dwValue 2 )
{
DWORD dwValue 3 = 0 ;
# if 0
// this is the Assembler
if ( dwValue 1 == dwValue 2 )
{
dwValue 3 = 1 ;
}
else
{
dwValue 3 = 2 ;
}
# endif
__ asm
{
mov eax , dwValue 1
; this is the test of the values , i . e . if dwValue 1 == dwValue 2
cmp eax , dwValue 2
; jump to ′ Else ′ if they are not equal
jne Else
mov eax , 1
jmp EndIf
Else :
mov eax , 2
EndIf :
mov dwValue 3 , eax
}
return dwValue 3 ;
}여기서도, 실제 명령에 대해서는 너무 신경쓰지 말아 주세요.그런데 모든 if문에 대해서 이런 코드를 써야 한다면 어떨까요?__asm 코드블록을 사용하는 것은 메모장과 명령어 프롬프트를 사용하여 C++를 기술하는 것과 같습니다.확실히 할 수 없는 것은 아니지만 전용 도구를 사용하는 경우보다 훨씬 시간이 걸립니다.그럼 어셈블러를 기술하기 위한 전용 툴에는 어떤 것이 있을까요.여기에서는 Microsoft Macro Assembler를 소개해 두겠습니다(잘못 들은 것이 아닙니다.Microsoft 도 어셈블러를 제공하고 있습니다).사실 Microsoft는 1980년부터 어셈블러를 제공하고 있습니다만, 별로 알려져 있지는 않습니다.더 중요한 것은 Microsoft Macro Assembler는 Visual C++ 링커와 호환되는 .obj 파일을 생성합니다.디버깅정보를 포함한 .obj파일을 생성하고 코드를 스텝실행할 수도 있습니다.이 기사에서는, MASM 를 사용하기 위한 프리웨어인 「MASM32」라고 하는 어셈블러를 사용합니다.MASM32는 http://www.masm32.com/ 에서 입수할 수 있습니다.앞으로 나아가기 전에, MASM32 를 다운로드해 인스톨 해 주세요.MASM32에는 어떤 메리트가 있을까요?첫째, 방대한 양의 도움말 파일이 들어 있습니다(′msasm32help′ 디렉토리에 수록).두 번째로 개발자가 필요로 할 각종 작업에 대한 매크로가 준비되어 있습니다.게다가 이러한 매크로를 사용하면, 각각의 작업을 실행하는 가장 효율적인 방법을 선택하고 있는 것을 확신할 수 있습니다.예를 들어, 전술의 코드를 MASM32 를 사용해 기술하면 다음과 같이 됩니다.Function proc dwValue 1 : DWORD , dwValue 2 : DWORD
mov eax , dwValue 1
. if eax == dwValue 2
mov eax , 1
. else
mov eax , 2
. endif
ret
Function endp 이게 훨씬 읽기 쉬울 거예요MASM32를 다운로드해 인스톨 했는데, 이후에서는, 어셈블러 파일을 기존의 C++프로젝트에 추가하는 방법과 그것을 컴파일 하기 위한 프로젝트 설정의 설정 방법, 어셈블러로 기술한 함수에 C++ 로부터 액세스 하는 방법에 대해서, 차례로 살펴보도록 하겠습니다.어셈블러 파일을 Visual C++ 에 추가하는 이후의 순서는 Visual Studio.NET 2002(영어판) 의 것입니다만, Visual C++ 6 또는 Visual Studio.NET 2003 에서도 같이 실행할 수 있습니다.우선, 애플리케이션의 검색 디렉토리에 MASM32 의 「bin」폴더를 포함할 필요가 있습니다.[Tools]→[Options]→[Visual C++ Directories]를 선택합니다.MASM을 인스톨 한 경로 아래에 있는 「bin」폴더를 추가합니다.예를 들면, 「C:MASM32」디렉토리에 인스톨 했을 경우는 「C:MASM32in」이 됩니다.이 디렉토리를 목록의 맨 아래로 이동합니다.이게 굉장히 중요합니다.이 폴더에는 link.exe라고 하는 링커 어플리케이션도 포함되어 있는데, 이 링커가 Visual Studio에서 기본 링커 대신에 사용될 수 있기 때문입니다.다음으로 콘솔 어플리케이션용 프로젝트를 생성합니다.만들면 ′test.asm′ 이라는 이름의 파일을 프로젝트에 추가합니다.솔루션 익스플로러내의 「Source Files」폴더를 오른쪽 클릭해,[Add]→[Add New Item]를 선택합니다.test.asm 이라고 입력하고 [Enter]키를 치면 ′test.asm′ 이라고 하는 신규파일이 열립니다.이 파일에 다음의 코드를 입력합니다..486
. model flat , stdcall
option casemap : none
. code
TestProc proc dwValue : DWORD
mov eax , dwValue
add eax , 100
ret
TestProc endp
end 이 코드에서는 입력값(dw Value)에 100을 가산하여 결과를 반환하고 있습니다.다음은 이 파일에 대한 빌드 속성을 설정해야 합니다.디버깅 빌드 상태인 것을 확인해, 솔루션 익스플로러내에서 이 파일을 오른쪽 클릭해,[Properties]를 선택합니다.[Custom Build Step]→[General]을 선택해,[Command Line]에 다음의 커맨드 라인을 입력합니다.ml /c /coff / Zi / Fo′$(Out Dir)$(Input Name). asm.obj ′$(Input File Name)′ 또한 [Outputs]에 다음 경로를 입력합니다.$(Out Dir)$(Input Name). $(Input Name).asm.릴리즈 빌드 설정은 이와 거의 동일하나 명령줄에 /Zi 옵션을 포함하지 않는 점만 다릅니다.이것은 디버깅 정보를 생성하기 위한 옵션이기 때문에 릴리즈 빌드에서는 삭제합니다.따라서 다음과 같습니다.ml /c /coff /Fo′$(OutDir)$(InputName).asm.obj′$(InputFileName)′물론, 이를 매크로나 어드레스로 하여 이 과정을 자동화할 수도 있습니다.여기서는 현재 사용되는 어떤 버전의 Visual Studio에도 응용할 수 있도록 절차를 하나하나 소개해 두었습니다.다음은 어셈블리로 쓰인 함수를 C++에서 호출하는 방법을 설명하겠습니다.C++에서 어셈블러 코드를 호출하는 위의 어셈블러 코드에서는 DWORD(즉 32비트값)의 입력을 받는 Test Proc라고 하는 함수를 정의했습니다.이 함수를 호출하기 위해서는 C++ 내에서 함수를 선언할 필요가 있습니다.application의 main메서드가 기술되어 있는 .cpp파일안에서 첫 번째 #includes뒤에 다음 행을 입력합니다.extern ′C′ unsigned int __stdcall Test Proc(unsigned int dwValue); 또한 main 메서드 내에 다음 코드를 기술합니다.int main ( int argc , _ TCHAR * argv [ ] )
{
unsigned int dwValue = 100;
unsigned int dwReturn = TestProc ( dwValue ) ;
printf ( ′ % d n ′ , dwReturn ) ;
getchar ( ) ;
return 0 ;
}}이 어플리케이션을 실행하면 예상대로 ′200′이라는 결과가 반환됩니다.게다가 Test Proc를 호출하는 행에 브레이크 포인트를 설정하고 있었을 경우는 이 메소드에 스텝 인하고([F11] 키), 어셈블러 코드를 스텝 실행할 수 있습니다.실은, 어셈블러 코드내에 브레이크 포인트를 설정하는 것도 가능합니다.정리 제1회에서는, 어셈블러 파일을 작성해, 컴파일 해, C++코드로부터 호출하는 방법에 대해 설명했습니다.시리즈 제 2회에서는, 어셈블리 언어를 구성하고 있는 실제의 명령에 대해 설명하고, 레지스터등의 토픽에 대해서도 다루기로 합니다.파트2로→
반응형