You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C调用自实现64位汇编strcmp/strcpy传参与结果错误排查

问题根因与修复方案

你的strcpy和strcmp两个汇编函数存在同一个核心逻辑错误,同时strcpy的越界写直接破坏了栈数据,导致所有异常现象。


核心错误说明

两个函数都错误使用64位寄存器执行内存读写:mov r14, [addr] 是一次读取/写入8个连续字节,但C字符串是按字节存储、逐字节比较/复制的序列,这个错误直接引发两个问题:

  1. strcpy每次复制1字节内容时,会连带读写后面7字节的无关内存,写越界直接覆盖栈上保存的局部变量、函数传参、返回地址等数据,这就是你执行完strcpy后栈上s数组被篡改、调用strcmp时rdi拿到无效地址的直接原因。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 11:06:20