汇编调用printf打印ASCII字符触发段错误的原因及解决方法
错误原因
- 不符合x86-64 System V ABI的
printf传参规则:printf的第一个入参(对应rdi寄存器)必须是指向格式化字符串的合法内存地址,你当前直接将待打印的ASCII字符值存入rdi,相当于把ASCII编码的数值当作内存指针访问,该地址几乎都属于不可读的非法地址,直接触发段错误。 - 其余逻辑中,可变参数函数调用前将
%rax置0的操作是正确的,无需修改。
修复方案
打印单个字符需要先定义对应格式化字符串,再按规则传参:
- 在数据段定义打印字符用的格式化字符串,示例:
.data fmt_char: .string "%c" # 如需打印后自动换行可改为 .string "%c\n"
- 调整传参逻辑:
rdi存格式化字符串地址,第二个参数rsi存待打印的ASCII字符,调用前保证栈16字节对齐,示例代码:
# 假设待打印字符已存储在 %al 中 mov $fmt_char, %rdi # 第一个参数:格式化字符串地址 movzbl %al, %rsi # 第二个参数:待打印字符,movzbl用于清除%rsi高位的垃圾值 mov $0, %rax # 可变参数无向量寄存器传参,%rax置0 sub $8, %rsp # 对齐栈到16字节(若当前栈已对齐可省略) call printf add $8, %rsp # 恢复栈指针
如果不想单独在数据段定义格式化字符串,也可以将字符串常量压入栈中临时使用,不过可读性和可维护性更低,不推荐。
内容的提问来源于stack exchange,提问作者user16806508
相关产品推荐
相关产品推荐

