x86-64汇编小程序malloc时出现段错误,求解析原因
重实现strdup时malloc段错误的原因分析
问题描述
函数定义:char* _ft_strdup(const char* s);
尝试重实现strdup函数,但调用malloc时出现段错误。将pop rdi指令移到malloc调用上方后,段错误消失,想了解原因。
对应的汇编代码:
.intel_syntax extern malloc extern _ft_strlen section .text global _ft_strdup _ft_strdup: push rbp ; prologue mov rbp, rsp ; prologue push rdi ; save rdi value (string src) call _ft_strlen ; compute length of string src mov rdi, rax ; set number of bytes to allocate call malloc ; allocate x bytes cmp rax, 0 je exit_prog pop rdi ; retrieve string src pop rbp ; epilogue ret exit_prog: xor rax, rax pop rbp ret
原因分析
问题核心是栈平衡被破坏,违反了x86-64 System V调用约定的栈对齐要求:
x86-64的System V调用约定明确要求:调用函数前,栈必须保持16字节对齐。每次
call指令会把8字节的返回地址压入栈,所以调用函数后栈的偏移会增加8字节。原代码的错误流程:
- 进入函数后,
push rbp+mov rbp, rsp完成栈帧初始化,此时栈是对齐的。 push rdi压入8字节数据,此时栈相对于rbp的偏移是16字节,仍然对齐。- 调用
_ft_strlen:call指令压入8字节返回地址,栈偏移变为24字节;_ft_strlen执行完毕返回后,返回地址被弹出,栈回到16字节偏移的对齐状态。 - 此时栈上还留着之前
push rdi的8字节数据,直接调用malloc时,call又压入8字节返回地址,导致malloc执行时的栈偏移是24字节——不满足16字节对齐要求,这就是触发段错误的原因。
- 进入函数后,
移动
pop rdi到malloc调用上方的作用:
在调用malloc前执行pop rdi,弹出之前压入的8字节数据,此时栈相对于rbp的偏移回到8字节。调用malloc时,call压入8字节返回地址,栈偏移变为16字节,刚好符合对齐要求,malloc就能正常执行,不会触发段错误。原代码还有额外隐患:
如果malloc返回NULL进入exit_prog分支,只会pop rbp,但之前push rdi的8字节数据还留在栈上,函数返回时会导致栈不平衡,后续代码可能出现未知错误。正确做法是在exit_prog分支里也弹出该8字节数据。
内容的提问来源于stack exchange,提问作者user18129922
相关产品推荐
相关产品推荐

