gpt4 book ai didi

c - 理解 C 中的 printf

转载 作者:IT王子 更新时间:2023-10-29 00:22:12 26 4
gpt4 key购买 nike

我试图了解 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 系统调用。所以用

运行它
gdb catch syscall brk
gdb catch syscall write

显示在我的例子中,当前中断等于 0x555555756000,但随后设置为 0x555555777000。当 write 出现时格式化字符串

x/s $rsi
0x555555756260: "Test rr\n"

位于“旧”和"new"中断之间。写入发生后,程序退出。

问题: 为什么我们分配了这么多页,为什么在 write 系统调用发生后 break 没有返回到前一个?是否有任何理由使用 brk 而不是 mmap 来进行这种格式化?

最佳答案

brk()(及其配套的 sbrk())是某种专门用于操纵堆大小的 mmap()。由于历史原因,libc 也可以直接使用 mmap()mremap()

随着分配额外的内存,堆会扩展,例如使用 malloc(),这在 libc 内部发生,例如有足够的空间从格式字符串创建实际的字符串和参数或许多其他内部事物(即,将缓冲 io 与 f* 函数系列一起使用时的输出缓冲区)。

如果堆的某些部分不再使用,它​​通常不会自动释放,主要有两个原因:堆可能是碎片化的,和/或未使用的堆没有低于某个阈值,这证明操作是合理的,因为可能很快会再次需要它。

附带说明:格式字符串本身肯定不会从 ro-section 复制到堆中,这将完全没有用。但是结果字符串(通常)是建立在堆上的。

关于c - 理解 C 中的 printf,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54090408/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com