在 linux 中如何在不使用 libc 的情况下在堆上分配内存
How do you allocate memory on the heap without using libc in linux
我试图在不使用 libc 和使用 linux 系统调用的情况下在堆上分配内存。我试过使用 mmap 和 brk,但是 brk 不像我读过的大多数系统那样 return 堆的末尾,sbrk 不会工作,因为它不作为系统调用存在,而 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(如果我不知道如何做,显然不是一个称职的人,它主要是一个学习 exercise/fun 项目)我需要弄清楚如何在堆上实际分配。我找了一段时间,但我仍然不知道它是如何工作的。
syscalls.s
.text
.global mmap
mmap:
mov , %rax
syscall
ret
.global exit
exit:
mov , %rax
syscall
ret
我使用的编译命令是gcc -nostdlib _start.c syscalls.s
.
就像我说的,我是 运行 Linux。具体来说:Ubuntu 20.04 LTS with kernel 5.11.0-43-generic.
好吧,这是使用 strace
和调试器的好机会。来自 man 2 syscall
:
Arch/ABI arg1 arg2 arg3 arg4 arg5 arg6 arg7 Notes
──────────────────────────────────────────────────────────────
x86-64 rdi rsi rdx r10 r8 r9 -
gdb a.out
:
(gdb) b syscalls.s:5
Breakpoint 1 at 0x1050: file syscalls.s, line 5.
(gdb) r
Starting program: /dev/shm/.1000.home.tmp.dir/a.out
Breakpoint 1, mmap () at syscalls.s:5
5 syscall
(gdb) info registers
rax 0x9 9
rbx 0x0 0
rcx 0x22 34 # here it is
rdx 0x3 3
rsi 0x1000 4096
rdi 0x0 0
rbp 0x7fffffffd968 0x7fffffffd968
rsp 0x7fffffffd950 0x7fffffffd950
r8 0xffffffffffffffff -1
r9 0x0 0
r10 0x555555554000 93824992231424 # WRONG!
r11 0x206 518
r12 0x555555555000 93824992235520
r13 0x7fffffffd970 140737488345456
r14 0x0 0
r15 0x0 0
rip 0x555555555050 0x555555555050 <mmap+7>
eflags 0x202 [ IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
我们看到 r10 中的值是一些垃圾,而 0x22
在 rcx
中。咨询https://uclibc.org/docs/psABI-x86_64.pdf.
你必须做 https://github.com/numactl/numactl/blob/master/syscall.c#L160 一些旋转。 mov %rcx, %r10
就够了。
总体而言,使用 https://github.com/lattera/glibc/blob/master/sysdeps/unix/sysv/linux/x86_64/syscall.S#L29 .
我试图在不使用 libc 和使用 linux 系统调用的情况下在堆上分配内存。我试过使用 mmap 和 brk,但是 brk 不像我读过的大多数系统那样 return 堆的末尾,sbrk 不会工作,因为它不作为系统调用存在,而 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(如果我不知道如何做,显然不是一个称职的人,它主要是一个学习 exercise/fun 项目)我需要弄清楚如何在堆上实际分配。我找了一段时间,但我仍然不知道它是如何工作的。
syscalls.s
.text
.global mmap
mmap:
mov , %rax
syscall
ret
.global exit
exit:
mov , %rax
syscall
ret
我使用的编译命令是gcc -nostdlib _start.c syscalls.s
.
就像我说的,我是 运行 Linux。具体来说:Ubuntu 20.04 LTS with kernel 5.11.0-43-generic.
好吧,这是使用 strace
和调试器的好机会。来自 man 2 syscall
:
Arch/ABI arg1 arg2 arg3 arg4 arg5 arg6 arg7 Notes
──────────────────────────────────────────────────────────────
x86-64 rdi rsi rdx r10 r8 r9 -
gdb a.out
:
(gdb) b syscalls.s:5
Breakpoint 1 at 0x1050: file syscalls.s, line 5.
(gdb) r
Starting program: /dev/shm/.1000.home.tmp.dir/a.out
Breakpoint 1, mmap () at syscalls.s:5
5 syscall
(gdb) info registers
rax 0x9 9
rbx 0x0 0
rcx 0x22 34 # here it is
rdx 0x3 3
rsi 0x1000 4096
rdi 0x0 0
rbp 0x7fffffffd968 0x7fffffffd968
rsp 0x7fffffffd950 0x7fffffffd950
r8 0xffffffffffffffff -1
r9 0x0 0
r10 0x555555554000 93824992231424 # WRONG!
r11 0x206 518
r12 0x555555555000 93824992235520
r13 0x7fffffffd970 140737488345456
r14 0x0 0
r15 0x0 0
rip 0x555555555050 0x555555555050 <mmap+7>
eflags 0x202 [ IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
我们看到 r10 中的值是一些垃圾,而 0x22
在 rcx
中。咨询https://uclibc.org/docs/psABI-x86_64.pdf.
你必须做 https://github.com/numactl/numactl/blob/master/syscall.c#L160 一些旋转。 mov %rcx, %r10
就够了。
总体而言,使用 https://github.com/lattera/glibc/blob/master/sysdeps/unix/sysv/linux/x86_64/syscall.S#L29 .