2009-06-21 24 views
64

Tôi muốn viết một cái gì đó cơ bản trong lắp ráp trong Windows, tôi đang sử dụng NASM, nhưng tôi không thể nhận được bất cứ điều gì làm việc.Làm thế nào để viết hello world trong assembler trong Windows?

Làm cách nào để viết và biên dịch hello world mà không có sự trợ giúp của các chức năng C trên Windows?

+0

Ngoài ra, hãy xem bộ công cụ lắp ráp bộ khởi động [Small Is Beautiful] của Steve Gibson (http://www.grc.com/smgassembly.htm). – Jeremy

+0

Không sử dụng thư viện c là một hạn chế hơi kỳ lạ. Người ta phải gọi một số thư viện trong hệ thống hoạt động MS-Windows. có lẽ là kernel32.dll.Whether Microsoft đã viết điều này trong c hoặc Pascal có vẻ không liên quan. Nó có nghĩa là chỉ có các hàm do OS cung cấp mới có thể được gọi, cái gì trong hệ thống kiểu Unix sẽ được gọi là các cuộc gọi hệ thống? –

+0

Với các thư viện C, tôi cho rằng nó có nghĩa là không sử dụng một thư viện thời gian chạy C như các thư viện đi kèm với GCC hoặc MSVC. Tất nhiên họ sẽ phải sử dụng một số DLL Windows chuẩn, như kernel32.dll. –

Trả lời

29

NASM examples.

; ---------------------------------------------------------------------------- 
; 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 

Sau đó chạy

nasm -fwin32 helloworld.asm 
gcc helloworld.obj 
a 

Ngoài ra còn có The Clueless Newbies Guide to Hello World in Nasm mà không sử dụng một thư viện C. Sau đó, mã sẽ trông như thế này.

org 100h 
mov dx,msg 
mov ah,9 
int 21h 
mov ah,4Ch 
int 21h 
msg db 'Hello, World!',0Dh,0Ah,'$' 

Chúc may mắn.

+13

Câu hỏi đề cập rõ ràng "không sử dụng thư viện C" –

+0

Không có cách nào đáng tin cậy để thực hiện việc này mà không cần gọi hàm C tại một số điểm. Ngoại trừ nếu bằng "hàm C", bạn có nghĩa là "hàm C chuẩn". –

+20

Sai. Các thư viện C chính nó rõ ràng là có thể, vì vậy nó có thể. Nó chỉ hơi khó hơn, trên thực tế. Bạn chỉ cần gọi hàm WriteConsole() với đúng 5 tham số. – MSalters

104

Ví dụ này cho biết cách truy cập trực tiếp vào API Windows và không liên kết trong Thư viện chuẩn C.

global _main 
    extern [email protected] 
    extern [email protected] 
    extern [email protected] 

    section .text 
_main: 
    ; DWORD bytes;  
    mov  ebp, esp 
    sub  esp, 4 

    ; hStdOut = GetstdHandle(STD_OUTPUT_HANDLE) 
    push -11 
    call [email protected] 
    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 [email protected] 

    ; ExitProcess(0) 
    push 0 
    call [email protected] 

    ; never here 
    hlt 
message: 
    db  'Hello, World', 10 
message_end: 

Để biên dịch, bạn sẽ cần NASM và link.exe (từ Visual studio Standard Edition)

 
    nasm -fwin32 hello.asm 
    link /subsystem:console /nodefaultlib /entry:main hello.obj 
+15

bạn có thể cần phải bao gồm kernel32.lib để liên kết này (tôi đã làm). link/subystem: console/nodefaultlib/entry: chính hello.obj kernel32.lib –

+4

Làm thế nào để liên kết obj với ld.exe từ MinGW? – DarrenVortex

+3

@DarrenVortex 'gcc hello.obj' – towry

4

Trừ khi bạn gọi hàm một số đây không phải là ở tất cả tầm thường. (Và, nghiêm túc, không có sự khác biệt thực sự về sự phức tạp giữa việc gọi printf và gọi hàm win32 api.)

Ngay cả khi DOS int 21h thực sự chỉ là một cuộc gọi hàm, ngay cả khi một API khác.

Nếu bạn muốn làm điều đó mà không cần trợ giúp, bạn cần phải nói chuyện trực tiếp với phần cứng video của mình, có khả năng viết bitmap của các chữ cái "Hello world" vào bộ đệm khung. Thậm chí sau đó card màn hình đang làm công việc dịch các giá trị bộ nhớ đó thành tín hiệu VGA/DVI. Lưu ý rằng, thực sự, không có công cụ nào trong số tất cả các công cụ này xuống phần cứng là thú vị hơn trong ASM so với C. Một chương trình "hello world" sôi xuống một cuộc gọi hàm. Một điều tốt đẹp về ASM là bạn có thể sử dụng bất kỳ ABI nào bạn muốn khá dễ dàng; bạn chỉ cần biết ABI đó là gì.

+0

Đây là một điểm tuyệt vời --- ASM và C đều dựa vào chức năng được cung cấp bởi OS (_WriteFile trong Windows). Vậy phép thuật ở đâu? Nó nằm trong mã trình điều khiển thiết bị cho card màn hình. –

+0

Điều này hoàn toàn bên cạnh điểm. Các poster yêu cầu một chương trình lắp ráp chạy "dưới Windows". Điều đó có nghĩa là các tiện ích Windows có thể được sử dụng (ví dụ: kernel32.dll), nhưng không phải các cơ sở khác như libc trong Cygwin. Để khóc to, tấm áp phích nói rõ ràng không có thư viện. –

15

Đây là các ví dụ về Win32 và Win64 sử dụng các cuộc gọi Windows API. Chúng dành cho MASM chứ không phải là NASM, nhưng hãy xem chúng. Bạn có thể tìm thêm chi tiết trong this bài viết.

;---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 

Để lắp ráp và liên kết các sử dụng MASM, sử dụng cho 32-bit thực thi:

ml.exe [filename] /link /subsystem:windows 
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Main 

hay này cho 64-bit thực thi:

ml64.exe [filename] /link /subsystem:windows 
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main 
+1

+1 cho câu trả lời của bạn. Bạn có thể vui lòng thêm mã lắp ráp cho Windows trên ARM (WOA) không? – Annie

+0

Tại sao rsp yêu cầu 0x28 byte và không phải 0x20? Tất cả các tham chiếu về quy ước gọi nói rằng nó phải là 32 nhưng có vẻ như yêu cầu 40 trong thực tế. – douggard

+1

Đã trả lời ở đây: https://stackoverflow.com/a/19128544/1176872 – douggard

4

Nếu bạn muốn sử dụng trình liên kết NASM và Visual Studio (link.exe) với ví dụ Hello World của anderstornvig, bạn sẽ phải liên kết theo cách thủ công với C Runtime Libary chứa hàm printf().

nasm -fwin32 helloworld.asm 
link.exe helloworld.obj libcmt.lib 

Hy vọng điều này sẽ giúp ai đó.

12

Flat Assembler không cần thêm trình liên kết. Điều này làm cho lập trình assembler khá dễ dàng. Nó cũng có sẵn cho Linux.

Đây là hello.asm từ các ví dụ 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 tạo ra một thực thi:

 
>fasm hello.asm 
flat assembler version 1.70.03 (1048575 kilobytes memory) 
4 passes, 1536 bytes. 

Và đây là chương trình trong IDA:

enter image description here

Bạn có thể xem ba cal ls: GetCommandLine, MessageBoxExitProcess.

7

Để có được một .exe với NASM'compiler và mối liên kết Visual Studio của mã này hoạt động tốt:

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 

Nếu mã này được lưu trên ví dụ "Test64.asm", sau đó để biên dịch:

nasm -f win64 test64.asm 

Tạo "test64.obj" Sau đó, để liên kết từ dấu nhắc lệnh:

path_to_link\link.exe test64.obj /subsystem:windows /entry:WinMain /libpath:path_to_libs /nodefaultlib kernel32.lib user32.lib /largeaddressaware:no 

nơi path_to_link có thể C: \ Program Files (x86) \ Microsoft Visual Studio 10.0 \ VC \ bin hoặc bất cứ đâu là chương trình link.exe trong máy của bạn, path_to_libs có thể là C: \ Program Files (x86) \ Windows Kits \ 8.1 \ Lib \ winv6. 3 \ um \ x64 hoặc bất kỳ thư viện nào của bạn (trong trường hợp này cả kernel32.lib và user32.lib đều ở cùng một nơi, nếu không thì hãy sử dụng một tùy chọn cho mỗi đường dẫn bạn cần) và /largeaddressaware: không có tùy chọn để tránh khiếu nại của liên kết về địa chỉ dài (đối với user32.lib trong trường hợp này). Ngoài ra, vì nó được thực hiện ở đây, nếu liên kết của Visual được gọi từ dấu nhắc lệnh, nó là cần thiết để thiết lập môi trường trước đó (chạy một lần vcvarsall.bat và/hoặc xem MS C++ 2010 and mspdb100.dll).

2

Ví dụ tốt nhất là những người bị co thắt, vì co thắt không sử dụng trình liên kết, điều này làm ẩn đi sự phức tạp của các cửa sổ lập trình bởi một lớp phức tạp mờ đục khác. Nếu bạn đang hài lòng với một chương trình viết vào cửa sổ gui, thì có một ví dụ cho chương trình đó trong thư mục ví dụ của fasm.

Nếu bạn muốn một chương trình bảng điều khiển, cho phép chuyển hướng tiêu chuẩn và tiêu chuẩn ra cũng có thể. Có một chương trình ví dụ (helas rất không tầm thường) có sẵn mà không sử dụng một gui, và làm việc chặt chẽ với bàn điều khiển, đó là chính nó. Điều này có thể được làm mỏng ra các yếu tố cần thiết. (Tôi đã viết một trình biên dịch ra đó là một ví dụ không gui, nhưng nó cũng không tầm thường).

Chương trình như vậy có lệnh sau để tạo tiêu đề thực thi phù hợp, thường được thực hiện bởi trình liên kết.

FORMAT PE CONSOLE 

Một phần được gọi là '.idata' chứa bảng giúp các cửa sổ trong khi khởi động để ghép tên các hàm vào địa chỉ thời gian chạy.Nó cũng chứa một tham chiếu đến KERNEL.DLL là hệ điều hành Windows.

section '.idata' import data readable writeable 
... 

Chương trình của bạn nằm trong phần '.text'. Nếu bạn khai báo phần đó có thể đọc được và có thể thực thi được, đó là phần duy nhất bạn cần.

section '.text' code executable readable writable 

Bạn có thể gọi cho tất cả các cơ sở bạn khai báo trong phần .idata. Đối với một chương trình giao diện điều khiển, bạn cần _GetStdHandle để tìm các trình biên dịch cho tiêu chuẩn và tiêu chuẩn (sử dụng các tên biểu tượng như STD_INPUT_HANDLE mà fasm tìm thấy trong tệp win32a.inc bao gồm). Một khi bạn có các bộ mô tả tập tin, bạn có thể thực hiện WriteFile và ReadFile. Tất cả các chức năng được mô tả trong tài liệu kernel32. Bạn có thể nhận thức được điều đó hoặc bạn sẽ không cố gắng lập trình lắp ráp.

Tóm lại: Có một bảng có tên asci mà cặp vợ chồng đến hệ điều hành windows. Trong khi khởi động, công cụ này được chuyển thành một bảng địa chỉ có thể gọi, mà bạn sử dụng trong chương trình của mình.

Các vấn đề liên quan