성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>Windows 환경에서의 Hello World x64 어셈블리 예제 (NASM 버전)</h1> <p> 윈도우에서의 간단한 어셈블리 예제를 MASM 버전으로 알아봤는데요,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Windows 환경에서의 Hello World x64 어셈블리 예제 (MASM 버전) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13182'>https://www.sysnet.pe.kr/2/0/13182</a> MASM + CRT 함수를 사용하는 경우 발생하는 컴파일 오류 정리 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13183'>https://www.sysnet.pe.kr/2/0/13183</a> ml64.exe와 link.exe x64 실행 환경 구성 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13184'>https://www.sysnet.pe.kr/2/0/13184</a> </pre> <br /> 당연히 <a target='tab' href='https://www.nasm.us/'>NASM(Netwide Assembler)</a> 버전도 <a target='tab' href='https://www.sysnet.pe.kr/2/0/13181'>리눅스만 지원하는 것이 아니고</a> 윈도우도 지원합니다. 게다가 Windows 11을 사용하고 있다면, (이제는 기본 설치된) winget을 이용해 이렇게 쉽게 설치할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > c:\temp> <span style='color: blue; font-weight: bold'>winget install --id=NASM.NASM</span> Found NASM [NASM.NASM] Version 2.15.05 This application is licensed to you by its owner. Microsoft is not responsible for, nor does it grant any licenses to, third-party packages. Downloading https://www.nasm.us/pub/nasm/releasebuilds/2.15.05/win64/nasm-2.15.05-installer-x64.exe ██████████████████████████████ 992 KB / 992 KB Successfully verified installer hash Starting package install... Successfully installed </pre> <br /> nasm 설치는 다음의 디렉터리에 구성되는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > %USERPROFILE%\AppData\Local\bin\NASM </pre> <br /> winget 설치 단계에서 함께 생성되는 바탕화면의 (nasmpath.bat을 가리키는) "nasm" 단축 아이콘을 통해 명령행 환경으로 진입할 수 있습니다. 혹은, 위의 경로를 윈도우의 환경 변수 설정에 PATH로 추가하던지, 아니면 위의 경로에 있는 "nasmpath.bat" 파일을 직접 실행해 명령행 창을 띄우면 됩니다.<br /> <br /> 하지만 그렇게 해서 nasm.exe를 실행해 어셈블리 언어를 컴파일해도, 이후의 링킹 작업은 할 수 없습니다. 이를 위해 link.exe가 필요한데요, 어쩔 수 없이 이것 때문에라도 "Visual Studio 2022 (Community)" 또는 "<a target='tab' href='https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022'>Build Tools for Visual Studio 2022</a>"를 설치해야 합니다. (이때 구성 요소로 "C++을 사용한 데스크톱 개발(Desktop development with C++)"을 선택해야 합니다.)<br /> <br /> 이렇게 nasm과 link가 준비되었으면 <a target='tab' href='https://www.sysnet.pe.kr/2/0/13184'>지난 글에 설명한 PATH와 LIB 환경 변수를 설정</a>하는 것으로 빌드 환경 구성이 마무리됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // Visual Studio 2022 Enterprise 버전인 경우 // 14.34.31933 버전은 "... Command Prompt for VS 2022" 명령행 창에서 VCToolsVersion 환경 변수와 연결돼 있습니다. // 10.0.22000.0 버전은 "... Command Prompt for VS 2022" 명령행 창에서 UCRTVersion 환경 변수와 연결돼 있습니다. c:\temp> <span style='color: blue; font-weight: bold'>SET PATH=%PATH%;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.34.31933\bin\Hostx64\x64</span> c:\temp> <span style='color: blue; font-weight: bold'>SET LIB=C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.34.31933\lib\x64;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22000.0\ucrt\x64;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22000.0\um\x64</span> </pre> <br /> <hr style='width: 50%' /><br /> <br /> 자, 이렇게 해서 환경 구성이 되었으면 이제 지난번 <a target='tab' href='https://www.sysnet.pe.kr/2/0/13182'>MASM으로 했던 실습</a>을 그대로 nasm 문법으로 변환해 컴파일할 수 있습니다. ^^<br /> <br /> 우선, 콘솔 출력을 하는 hello world 예제를 다음과 같이 구성할 수 있습니다.<br /> <a name='nhello_asm'></a><br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ; nhello.asm (nasm) section .data message: db 'Hello, World!', 0 message_length equ $-message section .text global main extern GetStdHandle extern WriteFile extern ExitProcess main: sub rsp, 28h ; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE) mov rcx, -11 call GetStdHandle ; WriteFile( hstdOut, message, length(message), &bytes, 0); mov rcx, rax mov rdx, message mov r8, message_length mov r9, 0 push 0 call WriteFile ; ExitProcess(0) mov rcx, rax call ExitProcess </pre> <br /> 보는 바와 같이 문법 자체만 NASM을 따를 뿐, 내부의 ABI는 윈도우의 x64 체계를 따르기 때문에 Macro Assembler와 비교해 어셈블리 코드 자체는 거의 동일합니다.<br /> <br /> 물론, 빌드 및 실행까지 잘됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > c:\temp> <span style='color: blue; font-weight: bold'>nasm -f win64 nhello.asm</span> // 또는 이렇게 Link // link /subsystem:console /nodefaultlib /entry:main nhello.obj kernel32.lib c:\temp> <span style='color: blue; font-weight: bold'>link /subsystem:console /entry:main nhello.obj kernel32.lib</span> Microsoft (R) Incremental Linker Version 14.12.25835.0 Copyright (C) Microsoft Corporation. All rights reserved. c:\temp> <span style='color: blue; font-weight: bold'>nhello</span> Hello, World! </pre> <br /> <hr style='width: 50%' /><br /> <br /> 그다음 MessageBox 예제는 별다르게 신기할 것이 없고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ; nhello_msgbox.asm section .data msgtitle db 'x64 App', 0 message db 'Hello World!', 0 section .text global main extern ExitProcess extern MessageBoxA main: sub rsp, 28h mov rcx, 0 mov rdx, message mov r8, msgtitle mov r9, 0 call MessageBoxA mov rcx, rax call ExitProcess </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > c:\temp> <span style='color: blue; font-weight: bold'>nasm -f win64 nhello_msgbox.asm</span> // 또는 이렇게 Link // c:\temp> link /subsystem:console /nodefaultlib /entry:main nhello_msgbox.obj kernel32.lib user32.lib c:\temp> <span style='color: blue; font-weight: bold'>link /subsystem:console /entry:main nhello_msgbox.obj kernel32.lib user32.lib</span> Microsoft (R) Incremental Linker Version 14.12.25835.0 Copyright (C) Microsoft Corporation. All rights reserved. c:\temp> <span style='color: blue; font-weight: bold'>nhello_msgbox.exe</span> ...[MessageBox 창]... </pre> <br /> CRT 연결하는 것도,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ; hello_cpp.asm section .data message db 'Hello World!', 0 section .text global main extern ExitProcess extern printf main: sub rsp, 28h mov rcx, message call printf mov rcx, rax call ExitProcess </pre> <br /> 간단하게 해결됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > c:\temp> <span style='color: blue; font-weight: bold'>nasm -f win64 nhello_cpp.asm</span> // 또는 이렇게 Link // link /subsystem:console /nodefaultlib nhello_cpp.obj vcruntime.lib kernel32.lib ucrt.lib libcmt.lib legacy_stdio_definitions.lib legacy_stdio_wide_specifiers.lib /entry:mainCRTStartup c:\temp> <span style='color: blue; font-weight: bold'>link /subsystem:console nhello_cpp.obj kernel32.lib libcmt.lib /entry:mainCRTStartup</span> Microsoft (R) Incremental Linker Version 14.34.31933.0 Copyright (C) Microsoft Corporation. All rights reserved. c:\temp> <span style='color: blue; font-weight: bold'>nhello_cpp</span> Hello World! </pre> <br /> <hr style='width: 50%' /><br /> <br /> 다음과 같은 오류가 발생한다면?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > c:\temp> <span style='color: blue; font-weight: bold'>link /subsystem:console /nodefaultlib /entry:main nhello.obj kernel32.lib</span> Microsoft (R) Incremental Linker Version 14.12.25835.0 Copyright (C) Microsoft Corporation. All rights reserved. nhello.obj : error LNK2017: 'ADDR32' relocation to '.data' invalid without /LARGEADDRESSAWARE:NO LINK : fatal error LNK1165: link failed because of fixup errors </pre> <br /> 메시지에서 알려주는 것처럼 link에 /LARGEADDRESSAWARE:NO 옵션을 주면 오류 없이 깨끗하게 빌드 및 실행이 되긴 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > c:\temp> link /subsystem:console /nodefaultlib /entry:main nhello.obj kernel32.lib <span style='color: blue; font-weight: bold'>/LARGEADDRESSAWARE:NO</span> Microsoft (R) Incremental Linker Version 14.12.25835.0 Copyright (C) Microsoft Corporation. All rights reserved. c:\temp> <span style='color: blue; font-weight: bold'>nhello.exe</span> Hello, World! </pre> <br /> 하지만 이렇게 되면 nhello.exe 프로세스 내의 모든 모듈들이 2GB 내의 주소 공간에 배치가 됩니다. 사실 이게 좀 이해가 안 되는데요, 위의 오류가 발생하는 원인은 <a target='tab' href='https://www.sysnet.pe.kr/2/0/13182#hello_asm'>MASM으로 만들었던 이전 예제 코드(hello.asm)에서는 아무 문제 없이 컴파일이 되었던 아래의 코드</a> 때문입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > section .data message: db 'Hello, World!', 0 section .text ; ...[생략]... <span style='color: blue; font-weight: bold'>lea rdx, [message]</span> </pre> <br /> 아마도 nasm이 멀티 플랫폼을 지원해서 그런 것인지... lea 명령어의 두 번째 operand가 32비트 값으로 취급하는 어떤 제약이 있는 것이 아닌가... 생각됩니다. (혹시 위의 코드가 왜 nasm에서 오류인지 아시는 분은 덧글 부탁드리겠습니다. ^^ )<br /> <br /> 어쨌든, lea가 아닌 (<a href='#nhello_asm'>이번 글의 예제에서는 수정해서 적용한</a>) "mov rdx, message" 명령어를 사용해 대체하면 아무런 오류 없이 빌드가 잘됩니다. 특이하게도 동일한 유형의 lea 코드를 리눅스/WSL에서 실습하면 컴파일/링크 시에 아무런 오류가 없습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // 윈도우와 달리 리눅스/WSL에서 빌드하면, // $ nasm -f elf64 -o app.o app.asm // $ ld app.o -o app // lea의 두 번째 operand에 대한 오류가 없음 section .data message: db "Hello World!", 0x0a message_length equ $-message section .text global _start _start: mov rax, 1 ; sys_write mov rdi, 1 ; stdout ; mov rsi, message ; buf <span style='color: blue; font-weight: bold'>lea rsi, [message]</span> // mov rsi, message를 lea 명령어로 바꿈 mov rdx, message_length ; count syscall mov rax, 60 ; sys_exit mov rdi, 0 ; error code 0 syscall </pre> <br /> <hr style='width: 50%' /><br /> <br /> 다음과 같은 오류가 발생한다면?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > error LNK2001: unresolved external symbol __volatile_metadata </pre> <br /> bufferoverflowu.lib를 함께 링크하면 됩니다.<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
6100
(왼쪽의 숫자를 입력해야 합니다.)