You need to enable JavaScript to run this app. NASM编写修改C指针指向内存的汇编函数运行失败,该如何正确实现?
优惠活动
大模型
产品
解决方案
定价
更多

NASM编写修改C指针指向内存的汇编函数运行失败,该如何正确实现?

程序崩溃的核心原因

你写的内存写入逻辑本身没有问题,程序崩溃的根源是违反了32位Linux System V的函数调用约定,和内存访问方式无关:

  • 按照32位Linux的调用规则,寄存器分为两类:
    • 被调用者保存寄存器:包括ebx、esi、edi、ebp,被调用的汇编函数如果要修改这些寄存器,必须在函数入口把原值压栈保存,返回前恢复原值,不然就会破坏C代码的运行上下文,直接触发段错误。你原来的代码直接修改了ebx,既没保存也没恢复,这就是崩溃的直接原因。
    • 调用者保存寄存器:包括eax、ecx、edx,被调用函数可以随意修改这些寄存器,不需要做保存恢复操作,因为C编译端的代码会默认这些寄存器在函数调用后值可能被覆盖。
正确的实现方式

方案1:使用无需保存的易失寄存器(代码最简洁)

直接换用调用者保存的寄存器做临时存储,完全不需要额外栈操作,代码逻辑和你原来的设计完全一致,但不会破坏程序状态:

section .text
global _mptr
_mptr:
    ; 取两个参数,放到易失寄存器edx、ecx里
    mov edx, [esp + 4]   ; edx存第一个参数:ptr
    mov ecx, [esp + 8]   ; ecx存第二个参数:val
    ; 把val写入ptr指向的内存
    mov [edx], ecx
    ; 返回值放到eax,就是原来的ptr
    mov eax, edx
    ret

这个版本编译运行后,就能正确把225写入i的内存地址,输出符合预期。

方案2:如果一定要用ebx这类非易失寄存器

必须严格按照调用约定保存、恢复寄存器值:

section .text
global _mptr
_mptr:
    ; 先保存ebx原值到栈上
    push ebx
    ; 因为前面push了4字节,栈偏移整体+4,原参数位置整体后移
    mov ebx, [esp + 8]    ; 原第一个参数ptr
    mov ecx, [esp + 12]   ; 原第二个参数val
    mov [ebx], ecx
    mov eax, [esp + 8]    ; 返回值ptr
    ; 恢复ebx原值
    pop ebx
    ret
常见误区澄清

很多新手会误以为是自己的指针访问语法错了——x86下写指针指向内存的标准操作就是:先把指针的32位地址值加载到通用寄存器,再通过mov [寄存器], 要写入的值的格式完成写入,你原来的代码用ebx存指针、往[ebx]写值的语法本身是完全正确的,只要指针指向的是合法可写的用户空间内存,写入操作就不会出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.23 04:54:03