C调用自实现64位汇编strcmp/strcpy传参与结果错误排查
问题根因与修复方案
你的strcpy和strcmp两个汇编函数存在同一个核心逻辑错误,同时strcpy的越界写直接破坏了栈数据,导致所有异常现象。
核心错误说明
两个函数都错误使用64位寄存器执行内存读写:mov r14, [addr] 是一次读取/写入8个连续字节,但C字符串是按字节存储、逐字节比较/复制的序列,这个错误直接引发两个问题:
strcpy每次复制1字节内容时,会连带读写后面7字节的无关内存,写越界直接覆盖栈上保存的局部变量、函数传参、返回地址等数据,这就是你执行完strcpy后栈上s数组被篡改、调用strcmp时rdi拿到无效地址的直接原因。strcmp每次比较1字节字符时,会连带比较后面7字节的无关内存垃圾,只要两个字符串不是同一个地址(后面的垃圾数据不同),就会误判字符串不等,这也是你传相同字符串字面量时能正常返回、传不同地址的相同内容字符串就失败的原因。
修复后的代码
strcpy 修复版
把内存读写改为字节操作,使用64位寄存器的低8位(r14b)存单个字符,避免8字节越界访问:
; strcpy- ; takes rdi = dest buffer, rsi = source string ; you can keep returning 0 in rax as your original design BITS 64 section .text global strcpy strcpy: push r15 push r14 mov r15, 0 strcpy_loop: mov r14b, [rsi+r15] ; 单次只读1字节 mov [rdi+r15], r14b ; 单次只写1字节 cmp r14b, 0 ; 直接判断读入的字符是否为结束符 je exit inc r15 jmp strcpy_loop exit: mov rax, 0 pop r14 pop r15 ret
strcmp 修复版
同样改为逐字节读取比较:
; strcmp- ; takes rdi = s1, rsi = s2 ; returns 0 if equal, 1 if not equal in rax BITS 64 section .text global strcmp strcmp: push r15 push r14 mov r15, 0 strcmp_loop: mov r14b, [rdi+r15] ; 读s1的1字节 cmp r14b, [rsi+r15] ; 和s2对应位置的1字节比较 jne exit_fail cmp r14b, 0 ; 判断是否到字符串结束 je exit_success inc r15 jmp strcmp_loop exit_success: mov rax, 0 jmp exit exit_fail: mov rax, 1 exit: pop r14 pop r15 ret
其他注意事项
- 你的
test缓冲区长度为14字节,刚好能存下"Hello World!\n"(含末尾\0共14字节),修复strcpy后不会再出现越界踩栈的问题。 - 如果后续要适配标准C的
strcmp返回值约定(返回小于0/0/大于0表示第一个不同字节的大小关系),只需要修改exit_fail的逻辑,计算两个字节的差值存入rax即可,当前你自定义的0/1返回值在自己的测试代码里可以正常工作。
内容的提问来源于stack exchange,提问作者Lakshay Rohila
相关产品推荐
相关产品推荐

