【发布时间】:2022-01-05 04:40:18
【问题描述】:
我试图在不使用 libc 和使用 linux 系统调用的情况下在堆上分配内存。我试过使用 mmap 和 brk 但 brk 不会像我读过的那样返回堆的末尾,因为它不作为系统调用存在,并且 mmap 只会导致段错误.
_start.c
#define PROT_READ 0x1
#define PROT_WRITE 0x2
#define MAP_PRIVATE 0x2
#define MAP_ANONYMOUS 0x20
extern void *mmap(void *addr, unsigned long sz, int prot, int mode, int fd, unsigned long offset);
extern void exit(int exit_code);
int _start()
{
void *mem = mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
*(int*)mem = 4;
exit(*(int*)mem);
}
我尝试这样做的原因是因为我正在开发一个替代 libc(如果我不知道如何做到这一点,显然不是一个称职的 libc,它主要是一个学习练习/有趣的项目),我需要弄清楚如何在堆上实际分配。我已经找了一段时间,但我仍然不知道它是如何工作的。
系统调用.s
.text
.global mmap
mmap:
mov $9, %rax
syscall
ret
.global exit
exit:
mov $60, %rax
syscall
ret
我使用的编译命令是gcc -nostdlib _start.c syscalls.s。
就像我说的,我正在运行 Linux。具体来说:内核 5.11.0-43-generic 的 Ubuntu 20.04 LTS。
【问题讨论】:
-
这是一个很酷的项目。你看过 glibc 本身吗?
-
顺便说一句,
exit()和_exit()在现代 Linux libc 中使用exit_group系统调用mov $__NR_exit_group, %eax。 Syscall implementation of exit()。_exit()以前是__NR_exit,但现在只有pthread_exit()这样做。 -
另外,即使你不使用libc头文件,你仍然可以
#include来自内核的头文件,比如asm/unistd.h定义__NR_exit_group等等。 (是的,您可以在.S文件中执行此操作;GCC 将为您通过 CPP 运行它们,并且这些 asm/ 标头不包含任何 C 声明,只是 CPP 宏。)跨度>
标签: c linux x86-64 system-calls calling-convention