我试图了解printf
在C中的工作原理,这很简单。我编写了以下程序:
#include "stdio.h"
int main(int argc, char const *argv[])
{
printf("Test %s\n", argv[1]);
return 0;
}
在二进制文件上运行
objdump
我注意到Test %s\n
驻留在.rodata
中objdump -sj .rodata bin
bin: file format elf64-x86-64
Contents of section .rodata:
08e0 01000200 54657374 2025730a 00 ....Test %s..
因此,格式化的打印似乎会执行从
rodata
到其他地方的其他模式复制。在使用
stare ./bin rr
编译并运行它之后,我注意到在实际写入之前有一个brk
syscall。所以用gdb catch syscall brk
gdb catch syscall write
显示在我的情况下,当前中断等于
0x555555756000
,但随后将其设置为0x555555777000
。当write
出现时,格式化的字符串x/s $rsi
0x555555756260: "Test rr\n"
驻留在“旧”和"new"之间。写发生后,程序退出。
问题:为什么我们分配了这么多页面,为什么在发生写入系统调用后中断不返回上一页?是否有任何理由使用
brk
而不是mmap
进行此类格式化? 最佳答案
brk()
(和它的伴随sbrk()
)是一种专用于操纵堆大小的mmap()
。出于历史原因,它在那里,libc也可以直接使用mmap()
或mremap()
。
堆会随着分配的额外内存而扩展,例如使用malloc()
,它在libc内部发生,例如有足够的空间从格式字符串和参数或许多其他内部对象(即输出缓冲区)创建实际的字符串当将带缓冲的io与f *函数系列一起使用时)。
如果不再使用堆的某些部分,则通常由于以下两个主要原因而不会自动将其自动释放:堆可能会碎片化,和/或未使用的堆不会低于证明该操作合理的某个阈值,因为它可能是很快需要。
附带说明:格式字符串本身当然不会从ro节复制到堆中,这将是完全无用的。但是结果字符串(通常)是建立在堆上的。
关于c - 了解C语言中的printf,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54090408/