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

如何将x86-64汇编aBin2int宏改写为符合调用约定的标准函数

aBin2int宏改写为标准约定函数适配方案

原始可用宏代码

此前编写的可正常运行的aBin2int宏代码如下:

%macro aBin2int 2
    push rbp
    mov rbp, rsp
    sub rsp, 8
    push rcx
    push rdx

    mov dword [%2], 0
    mov dword [rbp - 4], 0    
    mov dword [rbp - 8], 2    
    mov rax, 0
    mov rdx, 0
    mov rcx, 0
    mov r10, 0

    %%nxtCR:
        movzx eax, byte [%1 + r10]
        cmp eax, NULL
        je %%controlDone
        cmp eax, "0"
        jae %%adding
    %%adding:
        sub eax, "0"
        mov dword [rbp - 4], eax
        mov eax, dword [%2]
        mul dword [rbp - 8]
        add eax, dword [rbp - 4]
        mov dword [%2], eax
        inc r10
        jmp %%nxtCR
    %%completed:

    pop rdx
    pop rcx

    mov rsp, rbp
    pop rbp
%endmacro

需求背景

当前需要实现多层函数调用逻辑,首先编写getIterations()函数,负责参数错误校验、ASCII格式二进制字符串转整数,命令行参数固定格式为"-it <binaryNumber> -rs <binaryNumber>",函数定义如下:

; ******************************************************************
;  Function getIterations()
;   Performs error checking, converts ASCII/binary to integer.
;   Command line format (fixed order):
;     "-it <binaryNumber> -rs <binaryNumber>"

; -----
;  Arguments:
;   1) ARGC, double-word, value
;   2) ARGV, double-word, address
;   3) iterations count, double-word, address
;   4) rotate spped, double-word, address

getIterations()调用字符串转整数函数的约定参考同项目ternary2int:高级语言调用形式为bool = ternary2int(&str, &int);,寄存器传参规则为:1)待转换字符串地址存入rdi,2)整数存储地址存入rsi;返回规则为:通过传入地址回写转换结果,函数本身返回布尔值,转换合法返回TRUE,出错返回FALSE,ternary2int定义如下:

; *******************************************************************************
;  Simple function to convert ternary string to integer.
;   Reads string and converts to intger

; -----
;  HLL Call
;   bool = ternary2int(&str, &int);

; -----
;  Arguments passed:
;   1) string, address, rdi
;   2) integer, address, rsi

; -----
;  Returns
;   1) integer value (via passed address)
;   2) bool, TRUE if valid conversion, FALSE for error

现存问题

aBin2int宏版本运行正常,但改写为符合上述调用约定的独立函数时运行异常。当前已编写的二进制合法性校验、aBin2int调用代码如下:

mov rbx, qword[rsi + 16]
                mov r10, 0
    
        binaryCheck:
            mov rax, 0

            mov al, byte[rbx + r10]
            cmp al, NULL
            je convertBinary
            cmp al, "2"
            jae itsNoBinary

            cmp al, "0"
            jb itsNoBinary
            inc r10
            jmp binaryCheck

        convertBinary:
            mov r15, 0
            mov rdi, rbx
            mov rsi, r15
        call aBin2int

问题定位与修正

核心错误点

  1. 传参逻辑错误:调用aBin2int前执行mov r15, 0再mov rsi, r15,相当于给第二个参数传入了空地址0,函数向0地址写入结果会直接触发段错误,此处必须传入目标整数变量的有效内存地址。
  2. 宏本身存在隐性bug:原宏中cmp eax, "0"后的jae %%adding是无效跳转,无论比对结果如何都会直接进入转换逻辑,没有做字符合法性校验,且循环退出标签%%controlDone未定义,宏版本因为逻辑巧合未触发问题,改写函数时必须修正。
  3. 未遵循x86-64调用约定:独立函数需要保存rbx、rbp、r12-r15这类非易失寄存器,原宏仅保存了rcx、rdx,改写后如果不补全寄存器保存逻辑,会破坏上层函数的寄存器值导致运行异常。
  4. 字符校验逻辑不严谨:现有校验逻辑只判断字符小于"0"、大于等于"2"两种异常,漏了字符为"1"以上、"2"以下的合法判断,会把非0/1的非法字符放过。

修正后的aBin2int函数实现

; 调用约定:rdi = 二进制字符串首地址, rsi = 整数存储内存地址
; 返回值:rax = 1(TRUE)转换成功, rax = 0(FALSE)转换失败
aBin2int:
    push rbp
    mov rbp, rsp
    push rbx
    push rcx
    push rdx
    push r10

    mov dword [rsi], 0    ; 初始化结果为0
    mov r10, 0            ; 字符串遍历索引
    mov ecx, 2            ; 二进制基数

conv_loop:
    movzx eax, byte [rdi + r10]
    cmp eax, NULL
    je conv_success       ; 遍历到字符串结束符,转换完成

    ; 校验当前字符是否为合法二进制位
    cmp eax, "0"
    jb conv_fail
    cmp eax, "1"
    ja conv_fail

    sub eax, "0"          ; ASCII字符转数值0/1
    mov ebx, eax          ; 暂存当前位
    mov eax, dword [rsi]
    mul ecx               ; 结果 = 原结果 * 2
    add eax, ebx          ; 累加当前位
    mov dword [rsi], eax  ; 回写结果

    inc r10
    jmp conv_loop

conv_fail:
    mov rax, 0
    jmp conv_exit
conv_success:
    mov rax, 1
conv_exit:
    pop r10
    pop rdx
    pop rcx
    pop rbx
    pop rbp
    ret

调用逻辑修正

调用aBin2int时,必须将目标变量的地址传入rsi,不能传立即数0,修正后的调用片段示例:

; 此处省略ARGC数量校验、"-it"/"-rs"选项字符串匹配逻辑
; rsi为传入的ARGV数组首地址
mov rbx, qword [rsi + 16]  ; 取argv[2],即-it对应的二进制字符串
mov r10, 0
binaryCheck_it:
    mov al, byte [rbx + r10]
    cmp al, NULL
    je doConv_it
    cmp al, "1"
    ja arg_err
    cmp al, "0"
    jb arg_err
    inc r10
    jmp binaryCheck_it
doConv_it:
    mov rdi, rbx
    mov rsi, qword [rbp + 16]  ; 传入iterations变量的内存地址,而非0值
    call aBin2int
    test rax, rax
    jz arg_err  ; 转换失败跳转错误处理

; -rs参数的校验、转换逻辑与上述逻辑一致,取argv[4]传入即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 23:01:10