如何在 C 语言中编译我的 Malloc 版本?

How to compile my version of Malloc in C?

提问人:Virgil G. 提问时间:11/17/2023 最后编辑:Virgil G. 更新时间:11/17/2023 访问量:84

问:

我目前正在对函数的实现进行编码,因此我正在使用以下标志进行编译: .malloc()-m64 -fPIC -pedantic -Wall -Wextra -Werror -nostdlib -ggdb3

目前,我编译为可执行文件,而不是共享库。

对于我的实现,我正在使用头文件 ,目前我需要 syscall 。问题是在编译时我收到以下错误:.stddef.hstdint.hunistd.hsbrk()undefined reference to sbrk

我假设如果我使用编译,更普遍地会被禁用,但是我如何在没有 glibc 但使用系统调用的情况下进行编译?sbrk()unistd.h-nostdlib

提前致谢

P.S 我真的需要用我不能用,不要鼓励我这样做。sbrk()mmap()

C Linux malloc 头文件

评论

0赞 Bathsheba 11/17/2023
这里有一个有趣的读物,不可能用标准 C 编写 malloc():stackoverflow.com/questions/38515179/......
0赞 Joshua 11/17/2023
@Bathsheba:其实是的。没有大于的标准基元,因此您始终可以提供对齐的分配。long long
0赞 chux - Reinstate Monica 11/18/2023
@Joshua “no standard primitive larger than long long” --> , , , 指向函数的指针是大于 的候选私有元。问题在于对齐需求,而不是尺寸。的对齐需求是私有的指定最大值。long doublecomplex long doubleuintmax_tlong longmax_align_t
0赞 Joshua 11/18/2023
@chux-ReinstateMonica:哦,很好;足够新的 C 可以使用max_align_t然后。(Long Double 的对齐方式并没有那么糟糕,但哦,好吧)。
0赞 chux - Reinstate Monica 11/18/2023
@Joshua“long double 的对齐方式并不比 long long 更差”——>在某些机器上可能是正确的,但 C 并没有指定它是那样的。IAC,正是它的对齐需求解决了这个问题。max_align_t

答:

2赞 Joshua 11/17/2023 #1

在这种情况下,请勿使用 . 有专门的更换支持-nostdlibglibcmalloc()

这应该能够工作。不要启动多个线程,否则你会头疼。sbrk()

如果找不到,请改为拨打。 已过时,并且不能很好地与现代系统设施交互。sbrk()mmap()sbrk()

评论

3赞 zwol 11/17/2023
请注意,替换 malloc 并非易事;详细说明可在 gnu.org/software/libc/manual/html_node/Replacing-malloc.html 上找到
1赞 Andrew Henle 11/17/2023
sbrk() 已经过时,不能很好地与现代系统设施交互。 由 glibc 自己的实现使用。如果 OP 正在替换整个实现,则工作正常。sbrk()malloc()malloc()sbrk()
2赞 zwol 11/17/2023 #2

如果你正在做听起来像你正在尝试做的事情,那么你最终将不得不编写你自己需要的所有 C 库功能的实现。但是,朝这个方向前进的垫脚石是像这样编译您的半独立程序:

gcc -c -ffreestanding [other options] -o foo.o foo.c
# ... repeat the above for all other object files ...

gcc -ffreestanding -nostdlib -nostartfiles -static -o yourprogram \
    foo.o [other objects] -lc -lgcc

这告诉 C 实现提供您自己实际使用的标准库部分。请注意,许多标准 API 在此模式下无法正常工作;不要使用任何来自 ,也不要使用任何与语言环境相关的内容(因为 C 标准使用该术语),也不要使用任何与线程相关的内容。不过,系统调用包装器应该没问题,大多数 .stdio.hstring.h

评论

0赞 Virgil G. 11/18/2023
感谢您的回复和对半独立环境的解释。我还有另一个想法:在 NASM x64 中编写一个调用 sbrk() 的“系统调用”,但我在此列表中找不到它:blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64 是系统调用还是只是一个 libc 函数?如果它是一个系统调用,是否可以通过将增量放在 RDI 中,将正确的代码放在 RAX 和 SYSCALL 中来轻松调用它。sbrk()
1赞 zwol 11/18/2023
sbrk不是系统调用;实际的系统调用是,正确调用它需要一些技巧。请参阅 sourceware.org/git/?p=glibc.git;a=blob;f=misc/sbrk.c 了解如何完成。brk
1赞 zwol 11/18/2023
一般来说,你可以编写自己的系统调用包装器(最终你必须这样做),但你必须注意手册页中记录的 API 之间的细微差异,即 C 库包装器的行为,以及内核的实际行为。比您想象的更频繁的是,包装器所做的不仅仅是设置寄存器和发出指令。我在另一个窗口中打开 C 库源代码树进行此类工作,以便进行检查。syscall
0赞 Virgil G. 11/18/2023
还行。。。我不知道那不是系统调用,所以这就是为什么它没有编译的原因,感谢源文件,尽管我不确定我是否理解弱别名的原理。sbrk()-nostdlibextern void *__curbrk;
1赞 zwol 11/18/2023
如果你不试图编写一个完全符合标准的 C 库,你可以忽略其中的很多东西,比如与弱别名有关的一切,以及所有名称都无缘无故地带有前导。 只是意味着在不同的文件中定义了一个名为 的变量,其类型为 。__extern void *__curbrk;__curbrkvoid *