You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Win64汇编连续调用函数仅执行第一个的问题排查与解决

Windows 10 x64 NASM汇编:连续调用函数仅第一个执行的问题解决

在Windows 10 64位环境下编写NASM汇编代码,尝试连续调用fun1和fun2两个简单函数时,发现只有fun1被执行。疑问:是否需要在调用前后保存/加载寄存器?

原运行结果

hello 1
hello 2
test 1

原代码

segment .data
    hello1 db "hello 1", 0xd, 0xa, 0
    hello2 db "hello 2", 0xd, 0xa, 0
    test1 db "test 1", 0xd, 0xa, 0
    test2 db "test 2", 0xd, 0xa, 0

segment .text
global main
extern ExitProcess
extern printf

main:
    push    rbp
    mov     rbp, rsp
    sub     rsp, 32

    ; Call printf to print the main message
    lea     rcx, [hello1]
    call    printf

    lea     rcx, [hello2]
    call    printf

    call    fun1

    call    fun2

    ; Exit the program
    xor     rax, rax
    call    ExitProcess

; Define additional functions
section .text
fun1:
    lea     rcx, [test1]
    call    printf

    ret

fun2:
    lea     rcx, [test2]
    call    printf

    ret

编译链接命令

nasm -f win64 -g -o main.o main.s
link /LARGEADDRESSAWARE:NO main.o kernel32.lib kernel32legacylib.lib legacy_stdio_definitions.lib legacy_stdio_wide_specifiers.lib ucrt.lib /subsystem:console /entry:main /out:main.exe /DEBUG

问题解决

通过在函数中分配栈空间(阴影空间)解决了问题,更新后代码如下:

更新后代码

segment .data
    hello1 db "hello 1", 0xd, 0xa, 0
    hello2 db "hello 2", 0xd, 0xa, 0
    test1 db "test 1", 0xd, 0xa, 0
    test2 db "test 2", 0xd, 0xa, 0

segment .text
global main
extern ExitProcess
extern printf

main:
    push    rbp
    mov     rbp, rsp
    sub     rsp, 32

    ; Call printf to print the main message
    lea     rcx, [hello1]
    call    printf

    lea     rcx, [hello2]
    call    printf

    call    fun1

    call    fun2

    ; Exit the program
    xor     rax, rax
    call    ExitProcess

; Define additional functions
section .text
fun1:
    sub     rsp, 32       ; 分配阴影空间
    lea     rcx, [test1]
    call    printf
    add     rsp, 32       ; 释放阴影空间

    ret

fun2:
    sub     rsp, 32       ; 分配阴影空间
    lea     rcx, [test2]
    call    printf
    add     rsp, 32       ; 释放阴影空间

    ret

更新后运行结果

hello 1
hello 2
test 1
test 2

问题原因说明

问题核心并非寄存器保存/加载,而是Windows x64调用约定(FastCall)的栈要求:

  1. 调用外部函数(如printf)前,必须保证栈是16字节对齐的;
  2. 调用者需要为被调用函数预留32字节的“阴影空间”(shadow space),用于被调用函数保存RCX/RDX/R8/R9这4个寄存器参数。

原代码中fun1和fun2调用printf前未分配阴影空间,导致栈对齐被破坏,printf执行完毕返回后,栈指针状态错误,使得fun1的ret指令跳转到了错误地址,fun2因此无法被执行。在函数中添加sub rsp,32和add rsp,32后,满足了调用约定的栈要求,函数调用流程恢复正常。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 12:03:31