Assembly调用C库函数执行正常但程序结束后触发段错误问题
问题原因分析
你触发段错误的核心原因是没有完全遵守微软x64调用约定的两个强制要求:
- 调用任意函数前必须预留32字节的影子栈空间
微软x64调用约定要求,不管调用的函数接收几个参数,都需要在栈上预留至少32字节的空间,用于被调用函数临时备份rcx、rdx、r8、r9四个参数寄存器的值。你当前代码没有预留该空间,printf执行时会直接改写栈上未申请的区域,最终破坏了main函数的返回地址,导致ret指令跳转到非法地址触发段错误。
- 调用可变参数函数时需要设置
al寄存器的值
printf是可变参数函数,调用约定要求
al寄存器存储传入的浮点参数数量,你当前没有传递浮点参数,需要将al置为0,部分版本的C库会校验该值,异常值也可能导致运行错误。
修正后的代码
global main extern printf section .text main: push rbp mov rbp, rsp sub rsp, 32 ; 预留32字节影子栈空间,同时保证栈16字节对齐 mov rcx, format xor al, al ; 可变参数无浮点参数,al置0 call printf add rsp, 32 ; 恢复栈空间 mov rax, 0 pop rbp ret section .data format: db "Hello!", 10, 0
补充说明
代码中预留32字节栈空间的操作同时满足了栈16字节对齐的要求:进入main函数时,由于call指令压入了8字节返回地址,rsp为16N-8;执行push rbp后rsp再减8,刚好对齐到16字节边界,减去32(16的倍数)后仍然保持对齐,符合函数调用的前置要求。
内容的提问来源于stack exchange,提问作者Marko Borković
相关产品推荐
相关产品推荐

