You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Win10+Cygwin环境下x64 Windows汇编控制台打印字符串求助

Got it, let's tackle how to print a string to the Windows x64 console using NASM and GCC under Cygwin. Since x64 Windows assembly resources are indeed scarce compared to Linux x64 or 32-bit Windows, I'll walk you through complete, working examples step by step.

First, Understand x64 Windows Calling Conventions

Before diving into code, let's lock in the critical details:

  • x64 Windows uses the fastcall convention: the first 4 arguments are passed in registers RCX, RDX, R8, R9 (in order). Any additional arguments go on the stack.
  • You must reserve 32 bytes of "shadow space" on the stack before calling any WinAPI function (this gives the called function space to save the first 4 register arguments if needed).
  • The stack must be aligned to a 16-byte boundary before making a function call.

Example 1: Standalone Assembly Program

This is a pure NASM program that prints a string directly to the console using WinAPI functions.

Step 1: Write the Assembly Code (print.asm)

section .data
    ; Our message plus Windows-style line ending (CRLF)
    msg db 'Hello, x64 Windows Console!', 0Dh, 0Ah
    ; Calculate message length automatically
    msg_len equ $ - msg

section .text
    ; Declare main as the entry point (GCC expects this)
    global main
    ; Import required WinAPI functions from kernel32.dll
    extern GetStdHandle
    extern WriteConsoleA
    extern ExitProcess

main:
    ; Reserve 64 bytes on stack: 32 bytes shadow space + alignment to 16 bytes
    sub rsp, 40h

    ; 1. Get the standard output handle
    ; GetStdHandle(-11) = STD_OUTPUT_HANDLE
    mov rcx, -11
    call GetStdHandle
    ; Store the handle in RBX (non-volatile register, safe to keep)
    mov rbx, rax

    ; 2. Write the message to console
    ; WriteConsoleA(handle, buffer, length, &bytes_written, NULL)
    mov rcx, rbx                ; 1st arg: stdout handle
    mov rdx, msg                ; 2nd arg: message buffer
    mov r8, msg_len             ; 3rd arg: message length
    lea r9, [rsp + 20h]         ; 4th arg: pointer to track bytes written (uses shadow space)
    mov qword [rsp + 30h], 0    ; 5th arg: NULL (goes on stack, since it's beyond 4 args)
    call WriteConsoleA

    ; 3. Exit the process cleanly
    mov rcx, 0                  ; Exit code 0 (success)
    call ExitProcess

Run these commands in your Cygwin terminal:

# Assemble the NASM code into a Windows object file
nasm -f win64 print.asm -o print.obj

# Link the object file into an executable, linking against kernel32.dll
gcc print.obj -o print.exe -lkernel32

Step 3: Run the Program

Just execute the generated .exe file:

./print.exe

Example 2: C + Assembly Hybrid Program

If you prefer to handle most logic in C but use assembly for low-level tasks like console output, here's a mixed example.

Step 1: Write the Assembly Helper (asm_print.asm)

section .data
    ; Reusable CRLF line ending
    crlf db 0Dh, 0Ah
    crlf_len equ $ - crlf

section .text
    ; Import WinAPI functions
    extern GetStdHandle
    extern WriteConsoleA
    ; Declare the function so C can call it
    global asm_print

; Function signature: void asm_print(const char* str, size_t len)
asm_print:
    ; Reserve shadow space + align stack
    sub rsp, 40h

    ; Save input arguments (RCX = str, RDX = len) to non-volatile registers
    mov r8, rcx
    mov r9, rdx

    ; Get stdout handle
    mov rcx, -11
    call GetStdHandle

    ; Write the input string
    mov rcx, rax                ; Handle
    mov rdx, r8                 ; String buffer
    mov r8, r9                  ; String length
    lea r9, [rsp + 20h]         ; Bytes written pointer
    mov qword [rsp + 30h], 0    ; NULL
    call WriteConsoleA

    ; Write a newline after the string
    mov rcx, rax
    mov rdx, crlf
    mov r8, crlf_len
    lea r9, [rsp + 20h]
    mov qword [rsp + 30h], 0
    call WriteConsoleA

    ; Restore stack and return to C
    add rsp, 40h
    ret

Step 2: Write the C Wrapper (main.c)

#include <stddef.h>

// Declare the assembly function for C
void asm_print(const char* str, size_t len);

int main() {
    const char* msg = "Hello from C calling x64 Windows assembly!";
    // Call our assembly function to print the string
    asm_print(msg, 43);
    return 0;
}
nasm -f win64 asm_print.asm -o asm_print.obj
gcc main.c asm_print.obj -o mixed.exe -lkernel32

Key Notes to Remember

  • The -lkernel32 flag tells GCC to link against kernel32.dll, which contains all the WinAPI functions we use.
  • Stack alignment is non-negotiable in x64 Windows. If you skip it, your program will crash unpredictably.
  • WriteConsoleA is the ANSI version of the function; if you need Unicode support, use WriteConsoleW and wide strings.

内容的提问来源于stack exchange,提问作者Eagterrian Knight

火山引擎 最新活动