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

x86_64汇编与C交互:传递字符数组实现算术运算的方法

C调用x86_64 NASM汇编实现字符串数字加法

我来帮你搞定这个问题!你要实现的是C调用x86_64 NASM汇编函数处理字符串形式的数字算术运算,之前尝试直接遍历[rdi]和[rsi]存rax遇到困难,核心问题是没理清x86_64的调用约定,以及字符串数字的处理逻辑(毕竟char*是多字节的ASCII序列,不是单个数值)。下面我以字符串加法为例,给你完整的实现步骤和代码。

先搞懂x86_64 System V调用约定

在Linux/macOS的x86_64环境下,函数调用遵循System V规范:

  • 第一个参数(char* num1)存在rdi寄存器
  • 第二个参数(char* num2)存在rsi寄存器
  • 函数返回值(char*结果)存在rax寄存器
  • 非易失寄存器(rbx、rbp、r12-r15)如果被修改,必须先保存到栈中,用完再恢复
  • 我们需要动态分配内存(调用malloc)存储结果字符串,最终返回这个内存的指针

核心实现思路(以加法为例)

  1. 计算两个输入字符串的长度,确定结果的最大长度(最长输入长度+1,用来处理最高位进位)
  2. 从字符串末尾开始逐位遍历,把ASCII字符转成数值(减去'0')
  3. 对每一位的数值相加,加上上一位的进位,计算当前位的结果和新的进位
  4. 把当前位的数值转回ASCII(加上'0')存入结果缓冲区
  5. 处理最后剩余的进位,给结果字符串加上结束符
  6. 返回结果缓冲区的指针

完整代码实现

1. C调用代码(main.c)

#include <stdio.h>
#include <stdlib.h>

// 声明汇编函数
extern char* str_add(char* num1, char* num2);

int main() {
    char* num1 = "123456789";
    char* num2 = "987654321";
    char* result = str_add(num1, num2);
    
    printf("%s + %s = %s\n", num1, num2, result);
    
    // 必须释放汇编中malloc的内存,避免泄漏
    free(result);
    return 0;
}

2. NASM汇编代码(str_add.asm)

section .text
global str_add
extern malloc  ; 声明C标准库的malloc函数

; 辅助函数:计算字符串长度
; 输入:rdi = 字符串指针
; 输出:rax = 字符串长度
str_len:
    xor rax, rax        ; 初始化长度计数器为0
.len_loop:
    cmp byte [rdi + rax], 0  ; 检查当前字符是否为结束符'\0'
    je .len_done        ; 是结束符就退出循环
    inc rax             ; 计数器加1
    jmp .len_loop
.len_done:
    ret

; 主函数:字符串数字加法
; 输入:rdi = num1指针, rsi = num2指针
; 输出:rax = 结果字符串指针
str_add:
    ; 保存非易失寄存器到栈(后续要修改这些寄存器)
    push rbx
    push rcx
    push rdx
    push r8
    push r9
    push r10
    push r11
    
    ; 保存原始参数指针到非易失寄存器
    mov rbx, rdi        ; rbx = num1指针
    mov rcx, rsi        ; rcx = num2指针
    
    ; 计算num1的长度
    call str_len
    mov r8, rax         ; r8 = num1长度
    
    ; 计算num2的长度
    mov rdi, rcx
    call str_len
    mov r9, rax         ; r9 = num2长度
    
    ; 确定结果的最大长度:max(len1, len2) + 1(处理进位)
    mov r10, r8
    cmp r10, r9
    jge .max_len_set
    mov r10, r9
.max_len_set:
    inc r10             ; r10 = 结果缓冲区长度
    
    ; 调用malloc分配内存
    mov rdi, r10
    call malloc
    mov rsi, rax        ; rsi = 结果缓冲区指针
    
    ; 初始化循环变量
    xor rdx, rdx        ; rdx = 进位,初始为0
    dec r8              ; r8 = num1最后一个字符的索引
    dec r9              ; r9 = num2最后一个字符的索引
    mov rdi, r10        ; rdi = 结果缓冲区当前写入索引(从末尾开始)
    dec rdi
    
.add_loop:
    ; 获取num1当前位的数值
    xor rax, rax
    cmp r8, -1
    jl .num1_empty
    mov al, byte [rbx + r8]
    sub al, '0'         ; ASCII转数值
    jmp .num1_ready
.num1_empty:
    mov al, 0           ; num1已遍历完,补0
.num1_ready:
    
    ; 获取num2当前位的数值
    xor r11, r11
    cmp r9, -1
    jl .num2_empty
    mov r11b, byte [rcx + r9]
    sub r11b, '0'       ; ASCII转数值
    jmp .num2_ready
.num2_empty:
    mov r11b, 0         ; num2已遍历完,补0
.num2_ready:
    
    ; 计算当前位总和:num1位 + num2位 + 进位
    add al, r11b
    add al, dl
    mov dl, 0           ; 重置进位,准备计算新的进位
    
    ; 处理进位:如果总和>=10,保留个位,进位设为1
    cmp al, 10
    jl .no_carry
    sub al, 10
    mov dl, 1
.no_carry:
    
    ; 数值转ASCII,写入结果缓冲区
    add al, '0'
    mov byte [rsi + rdi], al
    
    ; 移动索引,继续下一位
    dec r8
    dec r9
    dec rdi
    
    ; 检查是否遍历完成:两个字符串都遍历完且无进位
    cmp r8, -1
    jne .add_loop
    cmp r9, -1
    jne .add_loop
    cmp dl, 0
    jne .add_final_carry
    
    ; 给结果字符串添加结束符
    mov byte [rsi + r10 - 1], 0
    jmp .done
    
.add_final_carry:
    ; 还有剩余进位,添加到结果开头
    mov byte [rsi], '1'
    mov byte [rsi + r10 - 1], 0
    
.done:
    ; 恢复栈中的非易失寄存器
    pop r11
    pop r10
    pop r9
    pop r8
    pop rdx
    pop rcx
    pop rbx
    
    ; 返回结果缓冲区指针
    mov rax, rsi
    ret

编译运行命令

在Linux环境下,执行以下命令编译运行:

# 编译汇编代码为64位目标文件
nasm -f elf64 str_add.asm -o str_add.o
# 编译C代码并链接汇编目标文件
gcc main.c str_add.o -o str_add
# 运行程序
./str_add

运行后会输出:123456789 + 987654321 = 1111111110

关键注意事项

  • 内存管理:汇编中调用malloc分配的内存,必须在C代码中用free释放,否则会造成内存泄漏
  • 寄存器保护:修改非易失寄存器前一定要保存到栈,函数返回前恢复,否则会破坏调用者的上下文
  • 字符串边界:必须处理不同长度的输入字符串,短字符串遍历完后用0补位
  • 进位处理:最高位相加后的进位一定要记得添加到结果中
  • ASCII转换:数字字符和数值之间的转换要正确(加减'0')

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:44:04