मैं विंडोज के तहत असेंबली में कुछ बुनियादी लिखना चाहता था, मैं एनएएसएम का उपयोग कर रहा हूं, लेकिन मुझे कुछ भी काम नहीं मिल रहा है।
विंडोज पर सी फ़ंक्शन की मदद के बिना हैलो दुनिया कैसे लिखें और संकलित करें?
मैं विंडोज के तहत असेंबली में कुछ बुनियादी लिखना चाहता था, मैं एनएएसएम का उपयोग कर रहा हूं, लेकिन मुझे कुछ भी काम नहीं मिल रहा है।
विंडोज पर सी फ़ंक्शन की मदद के बिना हैलो दुनिया कैसे लिखें और संकलित करें?
जवाबों:
एफसीडी स्टैडियो को कॉल करना printf
, लागू करनाint main(){ return printf(message); }
; ----------------------------------------------------------------------------
; helloworld.asm
;
; This is a Win32 console program that writes "Hello, World" on one line and
; then exits. It needs to be linked with a C library.
; ----------------------------------------------------------------------------
global _main
extern _printf
section .text
_main:
push message
call _printf
add esp, 4
ret
message:
db 'Hello, World', 10, 0
फिर भागो
nasm -fwin32 helloworld.asm
gcc helloworld.obj
a
सी लाइब्रेरी के उपयोग के बिना Nasm में हैलो वर्ल्ड के लिए Clueless Newbies गाइड भी है । तब कोड इस तरह दिखेगा।
MS-DOS सिस्टम कॉल के साथ 16-बिट कोड: DOS एमुलेटर में या NTVDM समर्थन के साथ 32-बिट विंडोज में काम करता है । किसी भी 64-बिट विंडोज के तहत "सीधे" (पारदर्शी रूप से) नहीं चलाया जा सकता है, क्योंकि x86-64 कर्नेल vm86 मोड का उपयोग नहीं कर सकता है।
org 100h
mov dx,msg
mov ah,9
int 21h
mov ah,4Ch
int 21h
msg db 'Hello, World!',0Dh,0Ah,'$'
.com
इसे एक निष्पादन योग्य में बनाएँ ताकि यह cs:100h
एक दूसरे (छोटे मेमोरी मॉडल) के बराबर सभी सेगमेंट रजिस्टर के साथ लोड हो जाए ।
सौभाग्य।
यह उदाहरण दिखाता है कि सीधे विंडोज एपीआई पर कैसे जाएं और सी स्टैंडर्ड लाइब्रेरी में लिंक न करें।
global _main
extern _GetStdHandle@4
extern _WriteFile@20
extern _ExitProcess@4
section .text
_main:
; DWORD bytes;
mov ebp, esp
sub esp, 4
; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
push -11
call _GetStdHandle@4
mov ebx, eax
; WriteFile( hstdOut, message, length(message), &bytes, 0);
push 0
lea eax, [ebp-4]
push eax
push (message_end - message)
push message
push ebx
call _WriteFile@20
; ExitProcess(0)
push 0
call _ExitProcess@4
; never here
hlt
message:
db 'Hello, World', 10
message_end:
संकलन करने के लिए, आपको NASM और LINK.EXE की आवश्यकता होगी (विज़ुअल स्टूडियो मानक संस्करण से)
nasm -fwin32 hello.asm लिंक / सबसिस्टम: कंसोल / नोडफ़ॉल्टलिब / एंट्री: मुख्य हेल्लो.बॉज
gcc hello.obj
विंडोज एपीआई कॉल का उपयोग करके ये Win32 और Win64 उदाहरण हैं। वे NASM के बजाय MASM के लिए हैं, लेकिन उन पर एक नज़र है। आप इस लेख में अधिक जानकारी पा सकते हैं ।
यह स्टडआउट के लिए मुद्रण के बजाय MessageBox का उपयोग करता है।
;---ASM Hello World Win32 MessageBox
.386
.model flat, stdcall
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
.data
title db 'Win32', 0
msg db 'Hello World', 0
.code
Main:
push 0 ; uType = MB_OK
push offset title ; LPCSTR lpCaption
push offset msg ; LPCSTR lpText
push 0 ; hWnd = HWND_DESKTOP
call MessageBoxA
push eax ; uExitCode = MessageBox(...)
call ExitProcess
End Main
;---ASM Hello World Win64 MessageBox
extrn MessageBoxA: PROC
extrn ExitProcess: PROC
.data
title db 'Win64', 0
msg db 'Hello World!', 0
.code
main proc
sub rsp, 28h
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx, msg ; LPCSTR lpText
lea r8, title ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
call MessageBoxA
add rsp, 28h
mov ecx, eax ; uExitCode = MessageBox(...)
call ExitProcess
main endp
End
MASM का उपयोग करके इन्हें इकट्ठा और लिंक करने के लिए, इसे 32-बिट निष्पादन योग्य के लिए उपयोग करें:
ml.exe [filename] /link /subsystem:windows
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Main
या 64-बिट निष्पादन योग्य के लिए यह:
ml64.exe [filename] /link /subsystem:windows
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main
X64 विंडोज को एक से पहले स्टैक स्पेस के 28h बाइट्स को आरक्षित करने की आवश्यकता क्यों है call
? वह 32 बाइट्स (0x20) छाया स्थान उर्फ होम स्पेस है, जैसा कि कॉलिंग कन्वेंशन द्वारा आवश्यक है। और एक और 8 बाइट्स 16 से स्टैक को फिर से संरेखित करने के लिए, क्योंकि कॉलिंग कन्वेंशन के लिए आरएसपी को 16-बाइट से पहले संरेखित करने की आवश्यकता होती है call
। (हमारे main
कॉल करने वाले (CRT स्टार्टअप कोड में) ने ऐसा किया है। 8-बाइट रिटर्न एड्रेस का मतलब है कि RSP किसी फ़ंक्शन में प्रवेश पर 16-बाइट सीमा से 8 बाइट दूर है।)
शैडो स्पेस का उपयोग एक फंक्शन द्वारा किया जा सकता है, जहां कोई स्टैक आर्गन्स (यदि कोई हो) के बगल में उसका रजिस्टर आर्गन्स डंप होगा। एक system call
करने के लिए पहले से 4 रजिस्टरों उल्लेख अलावा R10 और R11 के लिए भी आरक्षित स्थान के लिए 30h (48 बाइट्स) की आवश्यकता है। लेकिन DLL कॉल केवल फ़ंक्शन कॉल हैं, भले ही वे syscall
निर्देशों के आसपास रैपर हों ।
मजेदार तथ्य: गैर-विंडोज, यानी x86-64 सिस्टम V कॉलिंग कन्वेंशन (जैसे लिनक्स पर) छाया स्थान का उपयोग बिल्कुल भी नहीं करता है, और 6 पूर्णांक / पॉइंटर रजिस्टर आर्ग तक, और एक्सएमएम रजिस्टरों में 8 एफपी तक का उपयोग करता है ।
MASM के invoke
निर्देश (जिसे कॉलिंग कन्वेंशन पता है) का उपयोग करते हुए, आप इसका एक संस्करण बनाने के लिए एक ifdef का उपयोग कर सकते हैं जिसे 32-बिट या 64-बिट के रूप में बनाया जा सकता है।
ifdef rax
extrn MessageBoxA: PROC
extrn ExitProcess: PROC
else
.386
.model flat, stdcall
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
endif
.data
caption db 'WinAPI', 0
text db 'Hello World', 0
.code
main proc
invoke MessageBoxA, 0, offset text, offset caption, 0
invoke ExitProcess, eax
main endp
end
मैक्रो वैरिएंट दोनों के लिए समान है, लेकिन आप इस तरह से असेंबली नहीं सीखेंगे। आप इसके बजाय C- शैली asm सीखेंगे। invoke
के लिए है stdcall
या fastcall
जबकि cinvoke
है cdecl
या चर तर्क के लिए है fastcall
। कोडांतरक जानता है कि किसका उपयोग करना है।
आप आउटपुट को कैसे अलग कर सकते हैं, यह देखने के लिए अलग कर सकते हैं invoke
।
title
लेबल नाम के रूप में उपयोग करता हूं, तो मैं त्रुटियों में चला जाता हूं। हालांकि जब मैं लेबल नाम के रूप में कुछ और उपयोग करता हूं mytitle
, तो सब कुछ ठीक काम करता है।
फ्लैट असेंबलर को अतिरिक्त लिंकर की आवश्यकता नहीं होती है। इससे असेंबलर प्रोग्रामिंग काफी आसान हो जाती है। यह लिनक्स के लिए भी उपलब्ध है।
यह hello.asm
फेसम उदाहरणों से है:
include 'win32ax.inc'
.code
start:
invoke MessageBox,HWND_DESKTOP,"Hi! I'm the example program!",invoke GetCommandLine,MB_OK
invoke ExitProcess,0
.end start
फ़ासम एक निष्पादन योग्य बनाता है:
> फ़ासला hello.asm फ्लैट कोडांतरक संस्करण 1.70.03 (1048575 किलोबाइट मेमोरी) 4 पास, 1536 बाइट्स।
और यह आईडीए में कार्यक्रम है :
आप तीन कॉल देख सकते हैं: GetCommandLine
, MessageBox
और ExitProcess
।
NASM'compiler और Visual Studio के लिंक के साथ .exe प्राप्त करने के लिए यह कोड ठीक काम करता है:
global WinMain
extern ExitProcess ; external functions in system libraries
extern MessageBoxA
section .data
title: db 'Win64', 0
msg: db 'Hello world!', 0
section .text
WinMain:
sub rsp, 28h
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx,[msg] ; LPCSTR lpText
lea r8,[title] ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
call MessageBoxA
add rsp, 28h
mov ecx,eax
call ExitProcess
hlt ; never here
यदि यह कोड "test64.asm" पर सहेजा गया है, तो संकलन करने के लिए:
nasm -f win64 test64.asm
उत्पादन "test64.obj" फिर कमांड प्रॉम्प्ट से लिंक करने के लिए:
path_to_link\link.exe test64.obj /subsystem:windows /entry:WinMain /libpath:path_to_libs /nodefaultlib kernel32.lib user32.lib /largeaddressaware:no
जहाँ path_to_link C हो सकता है: \ Program Files (x86) \ Microsoft Visual Studio 10.0 \ VC \ बिन या जहाँ भी आपके मशीन में link.exe प्रोग्राम है, path_to_libs C: \ Program Files (x86) Windows Kits \ 8.1 \ _ हो सकता है। Lib \ winv6.3 \ um \ x64 या जहाँ भी आपके पुस्तकालय हैं (इस मामले में कर्नेल32.lib और user32.lib दोनों एक ही स्थान पर हैं, अन्यथा आपके लिए आवश्यक प्रत्येक पथ के लिए एक विकल्प का उपयोग करें) और / largaddressaware: कोई विकल्प नहीं है लिंकर्स के बारे में लंबे (इस मामले में user32.lib के लिए) पते से बचने के लिए आवश्यक है। साथ ही, जैसा कि यहां किया गया है, यदि विजुअल का लिंकर कमांड प्रॉम्प्ट से मंगवाया गया है, तो पहले से पर्यावरण को सेटअप करना आवश्यक है (एक बार vcvarsall.bat चलाएं और / या एमएस सी ++ 2010 और mspdb100.dll देखें)।
default rel
आपकी फ़ाइल के शीर्ष पर उपयोग करने की सलाह देता हूं ताकि वे पते वाले मोड ( [msg]
और [title]
) 32-बिट निरपेक्ष के बजाय RIP- सापेक्ष पते का उपयोग करें।
जब तक आप कुछ फ़ंक्शन को कॉल नहीं करते हैं यह बिल्कुल तुच्छ नहीं है। (और, गंभीरता से, प्रिंटफ़ को कॉल करने और एक win32 एपीआई फ़ंक्शन को कॉल करने के बीच जटिलता में कोई वास्तविक अंतर नहीं है।)
यहां तक कि डॉस इंट 21 एच वास्तव में सिर्फ एक फ़ंक्शन कॉल है, भले ही इसका एक अलग एपीआई हो।
यदि आप इसे बिना मदद के करना चाहते हैं तो आपको सीधे अपने वीडियो हार्डवेयर से बात करने की आवश्यकता है, "हेलो वर्ल्ड" के अक्षरों के बिटमैप को एक फ्रेमबफ़र में लिखने की संभावना है। फिर भी वीडियो कार्ड उन मेमोरी वैल्यू को वीजीए / डीवीआई सिग्नल में बदलने का काम कर रहा है।
ध्यान दें कि, वास्तव में, इस सामान में से कोई भी हार्डवेयर के नीचे का सब कुछ ASM के सी। ए। से अधिक दिलचस्प नहीं है। एक "हैलो वर्ल्ड" प्रोग्राम एक फंक्शन कॉल के लिए उबलता है। एएसएम के बारे में एक अच्छी बात यह है कि आप किसी भी एबीआई का उपयोग कर सकते हैं जिसे आप काफी आसान चाहते हैं; आपको बस यह जानना होगा कि एबीआई क्या है।
सबसे अच्छा उदाहरण झल्लाहट के साथ हैं, क्योंकि झल्लाहट एक लिंकर का उपयोग नहीं करता है, जो जटिलता की एक और अपारदर्शी परत द्वारा विंडोज़ प्रोग्रामिंग की जटिलता को छुपाता है। यदि आप एक प्रोग्राम के साथ संतुष्ट हैं जो एक gui विंडो में लिखता है, तो इसके लिए एक उदाहरण है fasm के उदाहरण निर्देशिका में।
यदि आप एक कंसोल प्रोग्राम चाहते हैं, जो मानक और मानक आउट के पुनर्निर्देशन की अनुमति देता है जो संभव भी है। एक हील (अत्यधिक गैर-तुच्छ) उदाहरण कार्यक्रम उपलब्ध है जो एक gui का उपयोग नहीं करता है, और कंसोल के साथ सख्ती से काम करता है, जो कि स्वयं फ़ासम है। इससे जरूरी चीजों को पतला किया जा सकता है। (मैंने आगे कंपाइलर लिखा है जो एक और गैर-गिनी उदाहरण है, लेकिन यह गैर-तुच्छ भी है)।
इस तरह के एक कार्यक्रम में 32-बिट निष्पादन योग्य के लिए एक उचित हेडर उत्पन्न करने के लिए निम्नलिखित कमांड है, जो आमतौर पर एक लिंकर द्वारा किया जाता है।
FORMAT PE CONSOLE
'.Idata' नामक एक खंड में एक तालिका होती है जो स्टार्टअप के दौरान विंडोज़ को फंक्शन के दो नामों के लिए रनटाइम्स एड्रेस में मदद करती है। इसमें KERNEL.DLL का संदर्भ भी है जो विंडोज ऑपरेटिंग सिस्टम है।
section '.idata' import data readable writeable
dd 0,0,0,rva kernel_name,rva kernel_table
dd 0,0,0,0,0
kernel_table:
_ExitProcess@4 DD rva _ExitProcess
CreateFile DD rva _CreateFileA
...
...
_GetStdHandle@4 DD rva _GetStdHandle
DD 0
टेबल प्रारूप खिड़कियों द्वारा लगाया जाता है और इसमें ऐसे नाम शामिल होते हैं जिन्हें सिस्टम फ़ाइलों में देखा जाता है, जब प्रोग्राम शुरू किया जाता है। FASM, rva कीवर्ड के पीछे कुछ जटिलता छिपाता है। तो _ExitProcess @ 4 एक फ़ेसम लेबल है और _exitProcess एक स्ट्रिंग है जिसे विंडोज द्वारा देखा जाता है।
आपका कार्यक्रम '.text' अनुभाग में है। यदि आप उस खंड को पठनीय और निष्पादन योग्य घोषित करते हैं, तो यह एकमात्र खंड है जिसे आपको जोड़ने की आवश्यकता है।
section '.text' code executable readable writable
आप .idata अनुभाग में घोषित सभी सुविधाओं को कॉल कर सकते हैं। एक सांत्वना कार्यक्रम के लिए आपको मानक और मानक के लिए दर्जकर्ता को खोजने के लिए _GetStdHandle की आवश्यकता होती है (एसटीडी_INPUT_HANDLE जैसे प्रतीकात्मक नामों का उपयोग करते हैं, जो शामिल फ़ाइल win32a.inc में फ़ासम पाता है)। एक बार जब आपके पास फाइल डिस्क्रिप्टर होता है तो आप WriteFile और ReadFile कर सकते हैं। सभी कार्यों को कर्नेल 32 प्रलेखन में वर्णित किया गया है। आप शायद इसके बारे में जानते हैं या आप कोडांतरक प्रोग्रामिंग की कोशिश नहीं करेंगे।
सारांश में: एक तालिका है जिसमें एससीआई नाम हैं जो कि विंडोज़ ओएस के लिए युगल हैं। स्टार्टअप के दौरान इसे कॉल करने योग्य पतों की तालिका में बदल दिया जाता है, जिसे आप अपने प्रोग्राम में उपयोग करते हैं।
यदि आप andMstornvig के Hello World उदाहरण के साथ NASM और Visual Studio के लिंकर (link.exe) का उपयोग करना चाहते हैं, तो आपको प्रिंट रन () फ़ंक्शन वाले C रनटाइम लिबरी के साथ मैन्युअल रूप से लिंक करना होगा।
nasm -fwin32 helloworld.asm
link.exe helloworld.obj libcmt.lib
आशा है कि यह किसी की मदद करता है।