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

x86 16位汇编函数参数寄存器使用最佳实践问询

x86 16位汇编中函数参数的寄存器选择与最佳实践

x86 16位汇编没有现代架构那样统一的标准ABI(应用二进制接口),参数传递的方式更多是自定义约定,但有一些被广泛认可的模式和可用寄存器:

可用作参数传递的寄存器

  • 通用寄存器:AX、BX、CX、DX是最常用的选择。比如DOS系统调用(如int 21h)就大量使用CX、DX传递参数,比如打印字符串时用DS:DX指向字符串首地址。
  • 索引寄存器:SI、DI也常用于传递内存指针类参数,比如字符串操作指令(movsb、movsw)默认用SI作源偏移、DI作目的偏移,很多自定义函数会沿用这个逻辑传递地址参数。
  • 段寄存器:DS、ES、SS这类段寄存器很少单独传参数,通常和通用/索引寄存器配对使用,用来指定内存地址的段部分(比如DS:BX表示数据段中的某一偏移地址)。

参数传递的最佳实践

  • 参数数量多?优先用栈传递:如果函数需要3个及以上参数,寄存器数量不够用,栈传递会更易维护。调用时按顺序把参数压栈,函数内部通过BP(基址指针)访问参数(比如mov ax, [bp+4]取第一个入栈的参数)。这种方式不受参数数量限制,调用栈结构清晰,调试更方便。
  • 少参数场景用寄存器提升效率:1-2个参数的话,直接用AX、CX、DX这类通用寄存器传递更高效,无需额外的栈操作。比如写一个两数求和函数,把第一个数放AX、第二个放CX,函数内部直接相加后把结果存回AX返回即可。
  • 全程保持约定一致:自制OS的核心是代码一致性,必须给自己定一套固定的参数传递规则,比如“前两个参数用CX、DX传递,第三个及以后压栈”,或者“所有参数都通过栈传递”。混乱的约定会导致函数调用频繁出错,后期维护成本极高。
  • 记得保存寄存器上下文:如果函数内部会修改用来传参的寄存器,一定要先把寄存器值压栈保存,函数结束前再恢复。比如函数用BX传参数,但内部要修改BX,就得先执行push bx,用完后pop bx,避免破坏调用者的寄存器状态。
  • 段寄存器配对要明确:如果传递跨段内存地址,必须明确段寄存器和偏移寄存器的配对规则,比如约定“内存地址参数用DS:SI传递”,不要随意混用段寄存器,否则会出现寻址错误。

示例代码

寄存器传递参数的函数

; 函数add_two:参数AX=第一个数,CX=第二个数,返回结果存AX
add_two:
    add ax, cx
    ret

; 调用示例
mov ax, 5
mov cx, 3
call add_two
; 此时AX的值为8

栈传递参数的函数

; 函数add_three:参数依次压栈(第三个、第二个、第一个),返回结果存AX
add_three:
    push bp          ; 保存基址指针
    mov bp, sp       ; 用BP定位栈上的参数
    mov ax, [bp+4]   ; 取第一个参数(栈顶+4字节,因为BP和返回地址各占2字节)
    add ax, [bp+6]   ; 取第二个参数
    add ax, [bp+8]   ; 取第三个参数
    pop bp           ; 恢复基址指针
    ret 6            ; 清理栈上的3个参数(每个2字节,共6字节)

; 调用示例
push 4
push 3
push 2
call add_three
; 此时AX的值为9

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 12:15:32