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

64位x86汇编:函数返回字符串存入数组失败问题排查

64位汇编字符串存储数组问题排查与解决

我正在用64位汇编开发,分为两个文件:一个负责生成带随机新字符的字符串,另一个包含数组。当前遇到的问题是:用打印函数输出数组中的字符串时显示为空,尝试多种修改方式均未解决——要么触发段错误,要么所有数组元素指向同一内容。


现有代码片段

字符串编辑文件的返回代码

returnString:
    mov rax, newString
    ret

数组初始化代码

section .bss
    array: resq 4
    allocString: resb 128

section .text
_start:
   mov qword[array], defaultMes0
        xor r8,r8
        add r8, 8

        mov qword[array + r8], defaultMes1
        add r8, 8

        mov qword[array + r8], defaultMes2
        add r8, 8

        mov qword[array + r8], defaultMes3
        add r8, 8

存储函数返回字符串到数组的rev函数代码

rev:
        mov rax, 8
        movzx rdx, byte [index] ; Clear rdx to avoid issues with imul

        imul rdx ; Multiply index by 8

        mov rdi, qword [array + rax]

        call stringEdit

        lea rbx, [allocString]
        
        translateLoop:
            mov dl, [rax]
            mov [rbx], dl

            ;both incremented and counter also incremented
            inc rax
            inc rbx

            ;comparison, if less than bl then done until it is equal to enterNum (place of split)
            cmp byte[rax], 0x0
            jne translateLoop
        
        mov rax, 8
        movzx rdx, byte [index] ; Clear rdx again

        imul rdx ; Multiply index by 8

        mov qword [array + rax], rbx

已尝试的无效方案

  • 修改返回代码为:

    returnString:
        mov rax, [newString]
        ret
    

    修改后打印仍为空。

  • 直接将函数返回值存入数组:

    call stringEdit
    mov qword [array + rax], rdi ;;moved it to the rdi before
    

    解引用newString打印触发段错误;不解引用时,所有数组元素指向同一内容,导致每次调用函数后所有索引共享相同结果。


解决方案

核心问题分析

  1. 共享缓冲区冲突:rev函数复用全局的allocString作为目标缓冲区,所有数组元素最终指向同一块内存,后续调用会覆盖之前的内容。
  2. 返回值含义混淆:若newString是字符串数组的直接地址,mov rax, newString是正确的;若newString是指针变量,则需解引用mov rax, [newString]才能拿到字符串地址。
  3. 数组索引计算错误:rev开头的偏移计算逻辑混乱,mov rax,8后做乘法,导致array + rax的偏移指向错误位置。

修复步骤

  1. 分配独立缓冲区
    放弃全局共享的allocString,在.bss为每个数组元素预留独立的字符串空间:

    section .bss
        array: resq 4                ; 存储字符串指针
        arrayStrings: resb 4*128     ; 4个128字节的独立缓冲区
    

    在rev中计算当前索引对应的缓冲区地址:

    movzx rdx, byte [index]
    imul rdx, 128                   ; 每个缓冲区占128字节
    lea rbx, [arrayStrings + rdx]   ; 指向当前索引的独立缓冲区
    
  2. 修正返回值逻辑

    • 若newString是直接定义的字符数组(如在.data/.bss中),保留mov rax, newString,返回字符串首地址。
    • 若newString是指针变量(如newString: resq 1),则用mov rax, [newString]返回它指向的字符串地址。
  3. 修正数组索引计算
    重新整理索引偏移逻辑,确保正确指向数组元素:

    movzx rdx, byte [index]
    imul rdx, 8                     ; 每个数组元素是8字节指针
    mov rdi, qword [array + rdx]    ; 获取原字符串指针
    

    存储新指针时同样使用正确的偏移:

    mov qword [array + rdx], rbx    ; 将独立缓冲区地址存入数组
    
  4. 优化字符串复制循环
    用已读取的dl判断终止符,减少内存访问:

    translateLoop:
        mov dl, [rax]
        mov [rbx], dl
        inc rax
        inc rbx
        cmp dl, 0x0                 ; 直接用dl判断,避免重复访问[rax]
        jne translateLoop
    

修复后的rev函数示例

rev:
        movzx rdx, byte [index]
        imul rdx, 8                 ; 计算数组指针偏移(每个元素8字节)
        mov rdi, qword [array + rdx] ; 获取原字符串指针

        call stringEdit             ; rax = 新字符串首地址

        movzx rdx, byte [index]
        imul rdx, 128               ; 计算独立缓冲区偏移
        lea rbx, [arrayStrings + rdx] ; 指向当前索引的缓冲区
        
        translateLoop:
            mov dl, [rax]
            mov [rbx], dl
            inc rax
            inc rbx
            cmp dl, 0x0
            jne translateLoop
        
        movzx rdx, byte [index]
        imul rdx, 8
        mov qword [array + rdx], rbx ; 保存缓冲区地址到数组
        ret

内容的提问来源于stack exchange,提问作者SeaNemi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 18:02:43