Linux sbrk() 作为汇编语言中的系统调用

5
作为一项挑战和性能考虑,我正在用汇编语言编写一个简单的服务器。我知道的唯一方法是通过系统调用(通过int 0x80)。很明显,我需要比在装配或加载时分配的内存更多,因此我阅读了相关资料,并决定使用sbrk(),主要是因为我不理解mmap(): p 无论如何,Linux没有提供sbrk()的中断,只有brk()。
那么...我如何找到当前程序断点以使用brk()呢?我想过使用getrlimit(),但我不知道如何获取资源(我猜想是进程ID)传递给getrlimit()。还是说我应该找到其他实现sbrk()的方法?

1
欢迎来到 Stack Overflow!“我知道的唯一方法是通过系统调用。” 还有库调用,比如sbrk。或者你是指“在没有libc的情况下使用汇编语言”? - Robᵩ
1
我不确定如何进行库调用(现在仍然不太清楚),您认为库调用比系统调用更快吗? - Jon Weldon
mmap很简单。但对于小的分配来说并不好。 - doug65536
2个回答

4
sbrk函数可以通过手动获取当前值并减去所需的数量来实现。一些系统允许您使用brk(0)获取当前值,而其他系统则在变量中跟踪它[该变量的初始化地址为_end的地址,该地址由链接器设置为指向初始断点值]。
这是一个非常特定于平台的事情,因此效果因人而异。
编辑:在Linux上:
但是,实际的Linux系统调用返回成功后的新程序断点。如果失败,则系统调用返回当前断点。 glibc包装器函数会进行一些工作(即检查新断点是否小于addr),以提供上述0和-1返回值。
因此,从汇编语言中,您可以使用类似0或-1这样荒谬的值来调用它以获取当前值。
请注意,您无法通过brk分配的内存“释放” - 您可能只想链接C语言编写的malloc函数。从汇编语言中调用C函数并不难。

或者 OP 可以使用 mmap 系统调用并设置 MAP_ANONYMOUS|MAP_PRIVATE 标志获取内存,并使用 munmap 释放它。这比在用户空间自己管理内存更昂贵,但从汇编语言实现会容易得多。 - R.. GitHub STOP HELPING ICE
2
请注意,您无法通过brk释放分配的内存。但是,man brk说:“增加程序断点会将内存分配给进程;减少断点会释放内存。”那么,为什么您不能通过brk释放分配的内存呢? - automaton
@automaton 这样做是不安全的,因为在分配该内存后,您调用的其他函数可能已经在其上方分配了更多的内存。您需要编写一个完整的内存管理系统。 - Random832

0

源代码:

#include <unistd.h>
#define SOME_NUMBER  8
int main() {
  void *ptr = sbrk(8);
  return 0;
}

使用汇编输出选项进行编译

gcc -S -o test.S test.c

然后看一下汇编代码

_main:
Leh_func_begin1:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    subq    $16, %rsp
Ltmp2:
    movl    $8, %eax
    movl    %eax, %edi
    callq   _sbrk
    movq    %rax, -16(%rbp)
    movl    $0, -8(%rbp)
    movl    -8(%rbp), %eax
    movl    %eax, -4(%rbp)
    movl    -4(%rbp), %eax
    addq    $16, %rsp
    popq    %rbp
    ret
Leh_func_end1:

虽然没有专门的系统调用,但你仍然可以进行调用。


我在fedora16/x86上链接了二进制静态库,并进行了objdump。我看到__sbrk调用__brk,__brk又调用brk系统调用(syscall 45)。 - Marco van de Voort
也许吧,但是你所发布的内容仍然依赖于外部实现的_sbrk被链接进来。 - Chris Stratton
是的,正如我所提到的,在我的机器上没有sbrk系统调用(至少我相当确定它被排除在Unix标准之外作为系统调用),因此要调用sbrk,您需要将其链接到libc中并实现它。 - lukecampbell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接