Bagaimana cara menulis hello world di assembler di bawah Windows?
94
Saya ingin menulis sesuatu yang mendasar dalam perakitan di bawah Windows, saya menggunakan NASM, tetapi saya tidak bisa mendapatkan apa pun yang berfungsi.
Bagaimana cara menulis dan mengkompilasi hello world tanpa bantuan fungsi C di Windows?
Lihat juga starter kit perakitan windows Small Is Beautiful milik Steve Gibson .
Jeremy
Tidak menggunakan pustaka-c adalah kendala yang agak aneh. Seseorang harus memanggil beberapa perpustakaan dalam sistem operasi MS-Windows. mungkin kernel32.dll. Apakah Microsoft telah menulis ini di c atau Pascal tampaknya tidak relevan. Apakah ini berarti bahwa hanya fungsi yang disediakan OS yang dapat dipanggil, apa dalam sistem tipe Unix yang disebut panggilan sistem?
Albert van der Horst
Dengan perpustakaan C saya berasumsi maksudnya tanpa menggunakan perpustakaan runtime C seperti yang disertakan dengan GCC atau MSVC. Tentu saja dia harus menggunakan beberapa DLL Windows standar, seperti kernel32.dll.
Rudy Velthuis
2
Perbedaan antara kernel32.dll dan pustaka runtime gcc tidak dalam format (keduanya dll) dan bukan dalam bahasanya (keduanya mungkin c, tetapi itu tersembunyi.) Perbedaannya adalah antara OS yang disediakan atau tidak.
Albert van der Horst
Saya telah mencari ini juga lol tidak dapat menemukan apa pun dengan fasm tanpa menyertakan
; ----------------------------------------------------------------------------
; helloworld.asm
;
; This is a Win32 console program that writes "Hello, World"on one lineand
; 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
Kode 16-bit dengan panggilan sistem MS-DOS: berfungsi di emulator DOS atau di Windows 32-bit dengan dukungan NTVDM . Tidak dapat dijalankan "secara langsung" (secara transparan) pada Windows 64-bit mana pun, karena kernel x86-64 tidak dapat menggunakan mode vm86.
Pertanyaan tersebut secara eksplisit menyebutkan "tanpa menggunakan perpustakaan C"
Mehrdad Afshari
25
Salah. Perpustakaan C sendiri jelas bisa, jadi mungkin saja. Faktanya, ini hanya sedikit lebih sulit. Anda hanya perlu memanggil WriteConsole () dengan 5 parameter yang tepat.
MSalters
12
Meskipun contoh kedua tidak memanggil fungsi pustaka C, itu juga bukan program Windows. Mesin DOS Virtual akan diaktifkan untuk menjalankannya.
Rômulo Ceccon
7
@Alex Hart, contoh keduanya adalah untuk DOS, bukan untuk Windows. Dalam DOS, program dalam mode kecil (file .COM, di bawah 64Kb total kode + data + tumpukan) mulai dari 0x100h karena 256 byte pertama dalam segmen diambil oleh PSP (baris perintah args dll). Lihat tautan ini: en.wikipedia.org/wiki/Program_Segment_Prefix
zvolkov
7
Ini bukanlah yang diminta. Contoh pertama menggunakan pustaka C dan yang kedua adalah MS-DOS, bukan Windows.
Paulo Pinto
131
Contoh ini menunjukkan bagaimana untuk pergi langsung ke Windows API dan bukan link di C Standard Library.
Anda mungkin perlu menyertakan kernel32.lib untuk menautkan ini (saya lakukan). tautan / subsistem: konsol / nodefaultlib / entri: main hello.obj kernel32.lib
Zach Burlingame
5
Bagaimana cara menghubungkan obj dengan ld.exe dari MinGW?
Ini adalah contoh Win32 dan Win64 yang menggunakan panggilan API Windows. Mereka untuk MASM daripada NASM, tapi lihatlah mereka. Anda dapat menemukan detail lebih lanjut di artikel ini .
Ini menggunakan MessageBox daripada mencetak ke stdout.
Win32 MASM
;---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:
push0 ; uType = MB_OK
push offset title ; LPCSTR lpCaption
push offset msg ; LPCSTR lpText
push0 ; hWnd = HWND_DESKTOP
call MessageBoxA
push eax ; uExitCode = MessageBox(...)
call ExitProcess
End Main
Win64 MASM
;---ASM Hello World Win64 MessageBox
extrn MessageBoxA: PROC
extrn ExitProcess: PROC
.data
title db 'Win64', 0
msg db 'Hello World!', 0
.code
main proc
subrsp, 28hmovrcx, 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
Untuk merakit dan menautkan ini menggunakan MASM, gunakan ini untuk 32-bit yang dapat dieksekusi:
Mengapa x64 Windows perlu mencadangkan 28 jam byte ruang tumpukan sebelum a call? Itu berarti 32 byte (0x20) shadow space alias ruang rumah, seperti yang disyaratkan oleh konvensi pemanggil. Dan 8 byte untuk re-menyelaraskan stack dengan 16, karena konvensi pemanggilan membutuhkan RSP menjadi 16-byte selaras sebelum sebuah call. ( mainPemanggil kami (dalam kode startup CRT) melakukan itu. Alamat pengembalian 8-byte berarti RSP berjarak 8 byte dari batas 16-byte saat masuk ke suatu fungsi.)
Shadow space dapat digunakan oleh sebuah fungsi untuk membuang argumen registernya di sebelah tempat setiap argumen tumpukan (jika ada). A system callmembutuhkan 30 jam (48 byte) untuk juga menyediakan ruang untuk r10 dan r11 selain 4 register yang disebutkan sebelumnya. Tetapi panggilan DLL hanyalah panggilan fungsi, meskipun panggilan tersebut membungkus sekitar syscallinstruksi.
Fakta menarik: non-Windows, yaitu konvensi pemanggilan Sistem V x86-64 (misalnya di Linux) tidak menggunakan spasi bayangan sama sekali, dan menggunakan hingga 6 argumen register integer / pointer, dan hingga 8 argumen FP di register XMM .
Dengan menggunakan invokedirektif MASM (yang mengetahui konvensi pemanggilan), Anda dapat menggunakan salah satu ifdef untuk membuat versi ini yang dapat dibangun sebagai 32-bit atau 64-bit.
Varian makro sama untuk keduanya, tetapi Anda tidak akan belajar perakitan dengan cara ini. Anda akan belajar asm gaya-C sebagai gantinya. invokeadalah untuk stdcallatau fastcallsementara cinvokeuntuk cdeclatau variabel argumen fastcall. Assembler tahu mana yang akan digunakan.
Anda dapat membongkar keluaran untuk melihat seberapa invokeluas.
1 untuk jawaban Anda. Bisakah Anda menambahkan kode assembly untuk Windows di ARM (WOA) juga?
Annie
1
Mengapa rsp membutuhkan 0x28 byte dan bukan 0x20? Semua referensi tentang konvensi pemanggilan mengatakan bahwa itu harus 32 tetapi tampaknya membutuhkan 40 dalam praktiknya.
douggard
Dalam kode kotak pesan 32-bit Anda, untuk beberapa alasan ketika saya menggunakan titlesebagai nama label, saya mengalami kesalahan. Namun ketika saya menggunakan sesuatu yang lain sebagai nama label mytitle, semuanya berfungsi dengan baik.
pengguna3405291
bagaimana melakukannya tanpa termasuk?
bluejayke
13
Flat Assembler tidak membutuhkan linker tambahan. Ini membuat pemrograman assembler cukup mudah. Ini juga tersedia untuk Linux.
Ini hello.asmdari contoh Fasm:
include'win32ax.inc'
.code
start:
invoke MessageBox,HWND_DESKTOP,"Hi! I'm the example program!",invoke GetCommandLine,MB_OK
invoke ExitProcess,0
.end start
di mana path_to_link bisa jadi C: \ Program Files (x86) \ Microsoft Visual Studio 10.0 \ VC \ bin atau di mana pun program link.exe Anda di mesin Anda,
path_to_libs bisa berupa C: \ Program Files (x86) \ Windows Kits \ 8.1 \ Lib \ winv6.3 \ um \ x64 atau di mana pun perpustakaan Anda (dalam hal ini kernel32.lib dan user32.lib berada di tempat yang sama, jika tidak gunakan satu opsi untuk setiap jalur yang Anda butuhkan) dan / largeaddressaware: tidak ada opsi yang diperlukan untuk menghindari keluhan linker tentang alamat ke long (untuk user32.lib dalam kasus ini). Selain itu, seperti yang dilakukan di sini, jika Visual's linker dipanggil dari command prompt, maka lingkungan perlu disiapkan sebelumnya (jalankan sekali vcvarsall.bat dan / atau lihat MS C ++ 2010 dan mspdb100.dll ).
Saya sangat merekomendasikan menggunakan default reldi bagian atas file Anda sehingga mode pengalamatan tersebut ( [msg]dan [title]) menggunakan pengalamatan relatif RIP daripada absolut 32-bit.
Peter Cordes
Terima kasih telah menjelaskan cara menautkan! Anda menyelamatkan kesehatan mental saya. Saya mulai menarik rambut saya karena 'kesalahan LNK2001: simbol eksternal yang belum terselesaikan ExitProcess' dan kesalahan serupa ...
Nik
5
Kecuali jika Anda menelepon suatu fungsi, ini sama sekali tidak sepele. (Dan, sungguh, tidak ada perbedaan nyata dalam kompleksitas antara memanggil printf dan memanggil fungsi api win32.)
Bahkan DOS int 21h benar-benar hanya sebuah pemanggilan fungsi, meskipun itu adalah API yang berbeda.
Jika Anda ingin melakukannya tanpa bantuan, Anda perlu berbicara dengan perangkat keras video Anda secara langsung, kemungkinan besar menulis bitmap dari huruf "Hello world" ke dalam framebuffer. Bahkan kemudian kartu video melakukan pekerjaan menerjemahkan nilai-nilai memori tersebut menjadi sinyal VGA / DVI.
Perhatikan bahwa, sungguh, tidak satu pun dari hal-hal ini sampai ke perangkat keras yang lebih menarik di ASM daripada di C. Program "hello world" bermuara pada pemanggilan fungsi. Satu hal yang menyenangkan tentang ASM adalah Anda dapat menggunakan ABI apa pun yang Anda inginkan dengan cukup mudah; Anda hanya perlu tahu apa itu ABI.
Ini adalah poin yang sangat baik --- ASM dan C keduanya bergantung pada fungsi yang disediakan OS (_WriteFile di Windows). Jadi dimana keajaibannya? Ini ada dalam kode driver perangkat untuk kartu video.
Assad Ebrahim
2
Ini benar-benar di samping intinya. Poster tersebut menanyakan program assembler yang berjalan "di bawah Windows". Itu berarti fasilitas Windows dapat digunakan (misalnya kernel32.dll), tetapi tidak untuk fasilitas lain seperti libc di bawah Cygwin. Untuk menangis dengan keras, poster itu secara eksplisit mengatakan tidak ada perpustakaan-c.
Albert van der Horst
5
Contoh terbaik adalah mereka yang memiliki fasm, karena fasm tidak menggunakan linker, yang menyembunyikan kompleksitas pemrograman windows oleh lapisan kompleksitas buram lainnya. Jika Anda puas dengan program yang menulis ke jendela gui, maka ada contohnya di direktori contoh fasm.
Jika Anda menginginkan program konsol, yang memungkinkan pengalihan standar masuk dan keluar standar yang juga dimungkinkan. Ada program contoh (helas sangat non-sepele) tersedia yang tidak menggunakan gui, dan bekerja secara ketat dengan konsol, yaitu fasm itu sendiri. Ini dapat dikurangi menjadi hal-hal penting. (Saya telah menulis kompiler keempat yang merupakan contoh non-gui lainnya, tetapi juga tidak sepele).
Program semacam itu memiliki perintah berikut untuk menghasilkan header yang tepat untuk 32-bit yang dapat dieksekusi, biasanya dilakukan oleh linker.
FORMAT PE CONSOLE
Sebuah bagian bernama '.idata' berisi tabel yang membantu windows selama startup untuk beberapa nama fungsi ke alamat runtime. Ini juga berisi referensi ke KERNEL.DLL yang merupakan Sistem Operasi Windows.
Format tabel diberlakukan oleh windows dan berisi nama yang dicari di file sistem, saat program dimulai. FASM menyembunyikan beberapa kerumitan di balik kata kunci rva. Jadi _ExitProcess @ 4 adalah label fasm dan _exitProcess adalah string yang dicari oleh Windows.
Program Anda ada di bagian '.text'. Jika Anda menyatakan bahwa bagian itu dapat dibaca dan dapat dieksekusi, itu adalah satu-satunya bagian yang perlu Anda tambahkan.
section '.text' code executable readable writable
Anda dapat memanggil semua fasilitas yang Anda nyatakan di bagian .idata. Untuk program konsol, Anda memerlukan _GetStdHandle untuk menemukan dia mengajukanescriptors untuk standard in dan standardout (menggunakan nama simbolik seperti STD_INPUT_HANDLE yang ditemukan fasm di file include win32a.inc). Setelah Anda memiliki deskriptor file, Anda dapat melakukan WriteFile dan ReadFile. Semua fungsi dijelaskan dalam dokumentasi kernel32. Anda mungkin menyadarinya atau Anda tidak akan mencoba pemrograman assembler.
Singkatnya: Ada tabel dengan nama asci yang berpasangan dengan OS windows. Selama permulaan ini diubah menjadi tabel alamat yang dapat dipanggil, yang Anda gunakan dalam program Anda.
FASM mungkin tidak menggunakan linker tetapi masih harus merakit file PE. Yang berarti bahwa itu sebenarnya tidak hanya mengumpulkan kode tetapi juga mengambil sendiri pekerjaan yang biasanya dilakukan oleh penaut, dan karena itu, menurut pendapat saya, menyesatkan untuk menyebut absensi penaut "menyembunyikan kompleksitas", justru sebaliknya - tugas assembler adalah merakit sebuah program, tetapi serahkan pada linker untuk menanamkan program tersebut ke dalam image program yang mungkin bergantung pada banyak hal. Karena itu, menurut saya pemisahan antara linker dan assembler adalah hal yang baik , yang tampaknya, Anda tidak setuju.
amn
@ amn Pikirkan seperti ini. Jika Anda menggunakan linker untuk membuat program di atas, apakah itu memberi Anda lebih banyak wawasan tentang apa program itu, atau terdiri dari apa? Jika saya melihat dari sumber fasm saya mengetahui struktur program secara lengkap.
Albert van der Horst
Poin yang adil. Di sisi lain, memisahkan penautan dari yang lainnya juga memiliki manfaatnya. Anda biasanya memiliki akses ke file objek (yang memungkinkan seseorang untuk memeriksa struktur program juga, terlepas dari format file gambar program), Anda dapat memanggil linker lain yang Anda sukai, dengan opsi yang berbeda. Ini tentang usabilitas dan komposabilitas. Dengan pemikiran tersebut, FASM melakukan segalanya karena "nyaman" melanggar prinsip-prinsip tersebut. Saya pada dasarnya tidak menentangnya - saya melihat pembenaran mereka untuk itu - tetapi saya, untuk satu, tidak membutuhkannya.
amn
mendapatkan kesalahan untuk isntruction ilegal di baris atas di jendela 64 bit
fasm
@bluejayke Mungkin Anda tidak memiliki dokumentasi tentang fasm. FORMAT PE menghasilkan 32 bit yang dapat dieksekusi, yang tidak dapat dijalankan oleh jendela 64 bit. Untuk program 64 bit Anda menginginkan FORMAT PE64. Juga pastikan Anda menggunakan instruksi 64 bit yang tepat dalam program Anda.
Albert van der Horst
3
Jika Anda ingin menggunakan NASM dan Visual Studio linker (link.exe) dengan contoh Hello World anderstornvig, Anda harus menautkan secara manual dengan C Runtime Libary yang berisi fungsi printf ().
Poster pertanyaan ingin tahu, bagaimana seseorang akan menulis printf berdasarkan fasilitas yang disediakan Windows, jadi ini sekali lagi benar-benar tidak penting.
Jawaban:
Contoh NASM .
Memanggil libc stdio
printf
, mengimplementasikanint 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
Lalu lari
nasm -fwin32 helloworld.asm gcc helloworld.obj a
Ada juga The Clueless Newbies Guide to Hello World di Nasm tanpa menggunakan C library. Maka kodenya akan terlihat seperti ini.
Kode 16-bit dengan panggilan sistem MS-DOS: berfungsi di emulator DOS atau di Windows 32-bit dengan dukungan NTVDM . Tidak dapat dijalankan "secara langsung" (secara transparan) pada Windows 64-bit mana pun, karena kernel x86-64 tidak dapat menggunakan mode vm86.
org 100h mov dx,msg mov ah,9 int 21h mov ah,4Ch int 21h msg db 'Hello, World!',0Dh,0Ah,'$'
Buat ini menjadi
.com
file yang dapat dieksekusi sehingga akan dimuatcs:100h
dengan semua register segmen sama satu sama lain (model memori kecil).Semoga berhasil.
sumber
Contoh ini menunjukkan bagaimana untuk pergi langsung ke Windows API dan bukan link di C Standard Library.
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:
Untuk mengkompilasi, Anda memerlukan NASM dan LINK.EXE (dari Visual studio Standard Edition)
sumber
gcc hello.obj
Ini adalah contoh Win32 dan Win64 yang menggunakan panggilan API Windows. Mereka untuk MASM daripada NASM, tapi lihatlah mereka. Anda dapat menemukan detail lebih lanjut di artikel ini .
Ini menggunakan MessageBox daripada mencetak ke stdout.
Win32 MASM
;---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
Win64 MASM
;---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
Untuk merakit dan menautkan ini menggunakan MASM, gunakan ini untuk 32-bit yang dapat dieksekusi:
ml.exe [filename] /link /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Main
atau ini untuk 64-bit yang dapat dieksekusi:
ml64.exe [filename] /link /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main
Mengapa x64 Windows perlu mencadangkan 28 jam byte ruang tumpukan sebelum a
call
? Itu berarti 32 byte (0x20) shadow space alias ruang rumah, seperti yang disyaratkan oleh konvensi pemanggil. Dan 8 byte untuk re-menyelaraskan stack dengan 16, karena konvensi pemanggilan membutuhkan RSP menjadi 16-byte selaras sebelum sebuahcall
. (main
Pemanggil kami (dalam kode startup CRT) melakukan itu. Alamat pengembalian 8-byte berarti RSP berjarak 8 byte dari batas 16-byte saat masuk ke suatu fungsi.)Shadow space dapat digunakan oleh sebuah fungsi untuk membuang argumen registernya di sebelah tempat setiap argumen tumpukan (jika ada). A
system call
membutuhkan 30 jam (48 byte) untuk juga menyediakan ruang untuk r10 dan r11 selain 4 register yang disebutkan sebelumnya. Tetapi panggilan DLL hanyalah panggilan fungsi, meskipun panggilan tersebut membungkus sekitarsyscall
instruksi.Fakta menarik: non-Windows, yaitu konvensi pemanggilan Sistem V x86-64 (misalnya di Linux) tidak menggunakan spasi bayangan sama sekali, dan menggunakan hingga 6 argumen register integer / pointer, dan hingga 8 argumen FP di register XMM .
Dengan menggunakan
invoke
direktif MASM (yang mengetahui konvensi pemanggilan), Anda dapat menggunakan salah satu ifdef untuk membuat versi ini yang dapat dibangun sebagai 32-bit atau 64-bit.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
Varian makro sama untuk keduanya, tetapi Anda tidak akan belajar perakitan dengan cara ini. Anda akan belajar asm gaya-C sebagai gantinya.
invoke
adalah untukstdcall
ataufastcall
sementaracinvoke
untukcdecl
atau variabel argumenfastcall
. Assembler tahu mana yang akan digunakan.Anda dapat membongkar keluaran untuk melihat seberapa
invoke
luas.sumber
title
sebagai nama label, saya mengalami kesalahan. Namun ketika saya menggunakan sesuatu yang lain sebagai nama labelmytitle
, semuanya berfungsi dengan baik.Flat Assembler tidak membutuhkan linker tambahan. Ini membuat pemrograman assembler cukup mudah. Ini juga tersedia untuk Linux.
Ini
hello.asm
dari contoh Fasm:include 'win32ax.inc' .code start: invoke MessageBox,HWND_DESKTOP,"Hi! I'm the example program!",invoke GetCommandLine,MB_OK invoke ExitProcess,0 .end start
Fasm membuat eksekusi:
Dan inilah program di IDA :
Anda dapat melihat tiga panggilan:
GetCommandLine
,MessageBox
danExitProcess
.sumber
Untuk mendapatkan .exe dengan NASM'compiler dan linker Visual Studio, kode ini berfungsi dengan baik:
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
Jika kode ini disimpan di misalnya "test64.asm", maka untuk mengkompilasi:
nasm -f win64 test64.asm
Menghasilkan "test64.obj" Lalu untuk menautkan dari command prompt:
path_to_link\link.exe test64.obj /subsystem:windows /entry:WinMain /libpath:path_to_libs /nodefaultlib kernel32.lib user32.lib /largeaddressaware:no
di mana path_to_link bisa jadi C: \ Program Files (x86) \ Microsoft Visual Studio 10.0 \ VC \ bin atau di mana pun program link.exe Anda di mesin Anda, path_to_libs bisa berupa C: \ Program Files (x86) \ Windows Kits \ 8.1 \ Lib \ winv6.3 \ um \ x64 atau di mana pun perpustakaan Anda (dalam hal ini kernel32.lib dan user32.lib berada di tempat yang sama, jika tidak gunakan satu opsi untuk setiap jalur yang Anda butuhkan) dan / largeaddressaware: tidak ada opsi yang diperlukan untuk menghindari keluhan linker tentang alamat ke long (untuk user32.lib dalam kasus ini). Selain itu, seperti yang dilakukan di sini, jika Visual's linker dipanggil dari command prompt, maka lingkungan perlu disiapkan sebelumnya (jalankan sekali vcvarsall.bat dan / atau lihat MS C ++ 2010 dan mspdb100.dll ).
sumber
default rel
di bagian atas file Anda sehingga mode pengalamatan tersebut ([msg]
dan[title]
) menggunakan pengalamatan relatif RIP daripada absolut 32-bit.Kecuali jika Anda menelepon suatu fungsi, ini sama sekali tidak sepele. (Dan, sungguh, tidak ada perbedaan nyata dalam kompleksitas antara memanggil printf dan memanggil fungsi api win32.)
Bahkan DOS int 21h benar-benar hanya sebuah pemanggilan fungsi, meskipun itu adalah API yang berbeda.
Jika Anda ingin melakukannya tanpa bantuan, Anda perlu berbicara dengan perangkat keras video Anda secara langsung, kemungkinan besar menulis bitmap dari huruf "Hello world" ke dalam framebuffer. Bahkan kemudian kartu video melakukan pekerjaan menerjemahkan nilai-nilai memori tersebut menjadi sinyal VGA / DVI.
Perhatikan bahwa, sungguh, tidak satu pun dari hal-hal ini sampai ke perangkat keras yang lebih menarik di ASM daripada di C. Program "hello world" bermuara pada pemanggilan fungsi. Satu hal yang menyenangkan tentang ASM adalah Anda dapat menggunakan ABI apa pun yang Anda inginkan dengan cukup mudah; Anda hanya perlu tahu apa itu ABI.
sumber
Contoh terbaik adalah mereka yang memiliki fasm, karena fasm tidak menggunakan linker, yang menyembunyikan kompleksitas pemrograman windows oleh lapisan kompleksitas buram lainnya. Jika Anda puas dengan program yang menulis ke jendela gui, maka ada contohnya di direktori contoh fasm.
Jika Anda menginginkan program konsol, yang memungkinkan pengalihan standar masuk dan keluar standar yang juga dimungkinkan. Ada program contoh (helas sangat non-sepele) tersedia yang tidak menggunakan gui, dan bekerja secara ketat dengan konsol, yaitu fasm itu sendiri. Ini dapat dikurangi menjadi hal-hal penting. (Saya telah menulis kompiler keempat yang merupakan contoh non-gui lainnya, tetapi juga tidak sepele).
Program semacam itu memiliki perintah berikut untuk menghasilkan header yang tepat untuk 32-bit yang dapat dieksekusi, biasanya dilakukan oleh linker.
Sebuah bagian bernama '.idata' berisi tabel yang membantu windows selama startup untuk beberapa nama fungsi ke alamat runtime. Ini juga berisi referensi ke KERNEL.DLL yang merupakan Sistem Operasi Windows.
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
Format tabel diberlakukan oleh windows dan berisi nama yang dicari di file sistem, saat program dimulai. FASM menyembunyikan beberapa kerumitan di balik kata kunci rva. Jadi _ExitProcess @ 4 adalah label fasm dan _exitProcess adalah string yang dicari oleh Windows.
Program Anda ada di bagian '.text'. Jika Anda menyatakan bahwa bagian itu dapat dibaca dan dapat dieksekusi, itu adalah satu-satunya bagian yang perlu Anda tambahkan.
section '.text' code executable readable writable
Anda dapat memanggil semua fasilitas yang Anda nyatakan di bagian .idata. Untuk program konsol, Anda memerlukan _GetStdHandle untuk menemukan dia mengajukanescriptors untuk standard in dan standardout (menggunakan nama simbolik seperti STD_INPUT_HANDLE yang ditemukan fasm di file include win32a.inc). Setelah Anda memiliki deskriptor file, Anda dapat melakukan WriteFile dan ReadFile. Semua fungsi dijelaskan dalam dokumentasi kernel32. Anda mungkin menyadarinya atau Anda tidak akan mencoba pemrograman assembler.
Singkatnya: Ada tabel dengan nama asci yang berpasangan dengan OS windows. Selama permulaan ini diubah menjadi tabel alamat yang dapat dipanggil, yang Anda gunakan dalam program Anda.
sumber
Jika Anda ingin menggunakan NASM dan Visual Studio linker (link.exe) dengan contoh Hello World anderstornvig, Anda harus menautkan secara manual dengan C Runtime Libary yang berisi fungsi printf ().
nasm -fwin32 helloworld.asm link.exe helloworld.obj libcmt.lib
Semoga ini bisa membantu seseorang.
sumber