x64汇编字符串反转函数触发SIGSEGV错误求助
问题分析与解决
核心错误原因
- 未初始化的目标缓冲区(
rsi寄存器):你的汇编函数错误地将rsi用作反转后字符串的存储位置,但对应的C函数声明char* asm_func4(char *);仅定义了一个参数。在x86-64 System V调用约定中,rsi对应第二个函数参数,而调用方main只传入了一个参数,导致rsi的值未定义(从gdb调试信息看,它指向了只读内存区域),写入该地址直接触发SIGSEGV内存错误。 - 字符串字面量的只读属性:即使修正参数问题,直接传入字符串字面量(如
"Hello from asm_func4\n")也不可行——这类字面量存储在程序的只读数据段,尝试写入会触发内存保护机制。
修复步骤
1. 修改函数接口,添加目标缓冲区参数
更新头文件prog.h,让函数接收原字符串和可写目标缓冲区两个参数:
#pragma once char* asm_func4(char *src, char *dest);
2. 调整汇编代码适配新接口
修正寄存器使用逻辑,同时优化字符串长度计算(避免原字符串无换行符时的索引错误):
asm_func4: push rbp ; 保存rbp寄存器 mov rbp, rsp ; 建立规范栈帧(可选但更严谨) call _strlen ; 计算源字符串长度(rdi为src参数) mov rdx, rax ; 将长度复制到rdx作为反向计数器 ; 检查末尾是否为换行符,再决定是否调整长度 cmp byte [rdi+rdx-1], 0x0A je .adjust_newline jmp .skip_adjust .adjust_newline: sub rdx, 1 ; 去掉换行符 .skip_adjust: sub rdx, 1 ; 去掉末尾的null终止符 xor rcx, rcx ; 清零目标缓冲区计数器 _reverse_str: mov al, [rdi+rdx] ; 从源字符串读取当前字符 mov byte [rsi+rcx], al ; 写入目标缓冲区 inc rcx ; 目标计数器自增 dec rdx ; 反向计数器自减 jns _reverse_str ; 当rdx >=0时继续循环(避免负数越界) _reverse_end: mov byte [rsi+rcx], 0h ; 给反转后的字符串添加null终止符 mov rax, rsi ; 返回目标缓冲区地址 pop rbp ret
3. 修改调用方代码,提供可写缓冲区
在main中分配足够大小的可写缓冲区(可使用栈数组或动态分配):
#include <stdio.h> #include <stdlib.h> #include "prog.h" #define BUF_SIZE 100 int main(void) { char dest[BUF_SIZE]; // 也可以用动态分配:char *dest = malloc(BUF_SIZE); 记得后续free printf("%s\n", asm_func4("Hello from asm_func4\n", dest)); return 0; }
额外注意事项
- 调用约定匹配:x86-64系统下,函数参数依次存入
rdi、rsi、rdx等寄存器,需确保汇编代码与C声明的参数顺序完全一致。 - 边界检查:目标缓冲区的大小必须足够容纳反转后的字符串,避免缓冲区溢出。
strlen返回值逻辑:strlen返回的是字符串有效长度(不含末尾null终止符),计算索引时需注意不要越界访问源字符串。
内容的提问来源于stack exchange,提问作者Joao Pereira
相关产品推荐
相关产品推荐

