linux - 当我使用 brk 系统调用时,我分配的内存实际上从哪里开始

标签 linux memory x86 nasm brk

我正在尝试在 NASM/x86 程序集中使用 sys_brk 分配一些内存。 sys_break返回break的新地址,这是数据段的末尾,对吧?那么我新分配的内存驻留在哪里?我假设它位于旧中断值和新中断值之间。因此,如果我使用 sys_brk 分配 64 字节内存,我可以使用从调用 sys_brk 之前存储的旧中断值开始的接下来的 64 字节。我说得对吗?

我分配内存的汇编代码看起来有点像这样。 https://gist.github.com/nikAizuddin/f4132721126257ec4345

另一个附带问题是;

我应该在 Assembly 中编写一个函数,该函数返回指向动态分配的内存的指针,并且该函数将从 C 程序中调用。我如何从程序的 C 端释放这 block 内存?只需调用 free() 就足够了吗?

最佳答案

brk(2) 手册页(部分:C 库/内核 ABI 差异)描述了如何在 Linux 系统调用之上实现 glibc 包装器,成功时返回新的 brk,失败时返回旧的 brk。

据我了解,当前中断之后的内存未映射。当前中断下方的地址是数据段的一部分(在数据+bss+堆的意义上)。文档并不清楚中断是否必须页面对齐。 (即,您可以使用 sbrk(64),还是只能使用 sbrk(4096)?)如果启用了 ASLR,则初始中断将是经过 BSS 末尾的某个随机距离。

参见:What does the brk() system call do?该问题的答案有 an example of using sbrk to replace malloc for code-golf 。所以是的,旧的中断是要返回的地址。显然,您可以 sbrk 任何您想要的增量,而不仅仅是页面。

<小时/>

您是编写内存分配器的人。 sbrk 只是让您从操作系统中获得更多信息,如 mmap(MAP_ANONYMOUS) 但灵 active 较差。 它不能帮助您跟踪空闲 block ,因此您可以将它们用于将来的分配,而不是总是从操作系统获取更多。

返回通过 sbrk 获得的内存的方法是使用负参数调用 sbrk。显然,这需要后进先出的使用模式,这就是为什么 glibc 的 malloc 仅使用 sbrk 进行小型分配(释放时可以放入空闲列表,以供将来的 malloc 分发)。大的分配最好立即返回到操作系统,而不是保持映射,因此 glibc 的 malloc 使用 mmap 来实现这些分配。

永远不要对不是从 malloc(3) 获取的内存(或相关函数,如 strdup(3),在文档中说明您可以并且应该 free(3) 内存)调用 free(3)。)不知道如果您在程序中断下方的内存页上调用 munmap 会发生什么。也许它会起作用,但是如果中断减少到那里,您的数据段中就会有一个漏洞,可能会导致问题。

<小时/>

在汇编中,Linux brk 系统调用采用要设置中断的地址。the man page notes ,它要么返回成功,要么返回失败时的旧中断,而不是像 -ENOMEM 这样的 -errno 代码。

参见 Assembly x86 brk() call use 以 x86-64 为例。

可以使用正整数或负整数偏移量的 POSIX API 可以通过始终调用两次来实现,或者像 glibc 一样跟踪全局变量中的当前中断。要初始化该变量,请使用 brk 一次并请求地址 0,这将失败,如下面的 strace 输出所示。

这与使用 POSIX API 执行的操作类似,使用 increment = 0 调用 sbrk

这就是 glibc 的 malloc(3) 内部所做的事情:

$ strace -e brk ls 2>&1 | m
brk(0)                                  = 0x650000
brk(0)                                  = 0x650000
brk(0x671000)                           = 0x671000

brk 手册页提到了 end(3)。显然,全局变量位于文本、数据和 bss 段的末尾。然而,&end只是“接近”程序中断,这就是为什么malloc仍然需要进行系统调用来获得初始中断。我不知道为什么会有多余的 brk(0)。这些是原始系统调用,而不是库函数调用,因此 sbrk(0) 可能无法解释它。

关于linux - 当我使用 brk 系统调用时,我分配的内存实际上从哪里开始,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32885127/

相关文章:

assembly - 如何确定启动设备

c - 在 Linux 机器上获取用户的默认电子邮件

json - 如何将蓝图json文件转换为csv文件?

linux - 有没有Linux命令行环境的网站,可以练习命令?

MySQL 使用 LOAD INFILE 进行批量插入 - MyISAM 仅比 MEMORY 引擎慢

assembly - 当 eip 寄存器达到最大值时会发生什么?

c# - Linux 下 AutoResetEvent 的 C++ 等价物是什么?

c++ - 程序似乎泄漏内存,但未检测到内存泄漏

php - PHP 在不相关的代码上浪费了多少资源(如果有的话)?

带堆栈操作的 GCC 内联汇编