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

在Linux汇编中获取数据段末尾的方法(实现自定义malloc)

获取x86_64 Linux汇编中数据段/堆起始位置的替代方法

好问题!在Ubuntu x86_64环境下用NASM+LD实现malloc时,除了在数据段末尾手动添加标签,你可以直接通过brk系统调用本身获取当前程序的break位置——这和C语言中sbrk(0)的效果完全一致,因为sbrk(0)底层就是这么实现的。

核心原理

Linux的brk系统调用有个特殊行为:当你传入的参数为0时,它不会修改程序的break地址,而是直接返回当前的break值。这个值就是堆的起始位置(也就是数据段/BSS段的末尾),正好是你实现malloc需要的起点。

x86_64下brk系统调用的使用方式

x86_64 Linux的系统调用规则是:

  • 系统调用号存入rax寄存器,brk的系统调用号是12
  • 参数存入rdi寄存器(brk仅需一个参数:要设置的break地址)
  • 执行syscall指令触发调用,返回值存在rax中(成功返回新的break地址,失败返回-1,错误码在rax低32位)

汇编代码示例

以下是一个极简的示例,展示如何获取当前break地址,以及如何扩展它来分配内存:

section .text
global _start

_start:
    ; 第一步:获取当前break地址(等价于C的sbrk(0))
    mov rdi, 0          ; 传入0,请求返回当前break
    mov rax, 12         ; brk系统调用号
    syscall
    ; 此时rax寄存器中存储的就是当前堆的起始地址(数据段末尾)

    ; 第二步:扩展break,分配1024字节内存
    add rax, 1024       ; 计算新的break地址:当前地址 + 要分配的字节数
    mov rdi, rax        ; 将新地址传入rdi
    mov rax, 12         ; 再次调用brk系统调用
    syscall
    ; 成功的话,rax会返回新的break地址;失败则返回-1

    ; 退出程序
    mov rax, 60         ; exit系统调用号
    mov rdi, 0          ; 退出码0
    syscall

两种方法的对比

  • 数据段标签法:比如在.data段末尾加end_of_data:,通过mov rax, end_of_data获取地址。但这种方法无法覆盖链接器自动添加的BSS段、动态链接相关的隐式数据,结果可能不准确。
  • brk系统调用法:直接从内核获取当前的break位置,是最准确的方式,完全不依赖C库,纯汇编就能实现,更适合手动实现内存分配器的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:02:17