文章

apue笔记(二)

apue笔记(二)

进程环境

本章中将学习:当程序执行时,其 main 函数是如何被调用的;命令行参数是如何传递给新程序的;典型的存储空间布局是什么样式;如何分配另外的存储空间;进程如何使用环境变量;进程的各种不同终止方式等。另外,还将说明 longjmp 和 setjmp 函数以及它们与栈的交互作用。本章结束之前,还将查看进程的资源限制。

C程序总是从main函数开始执行,内核在调用main之前会调用一个特殊的启动例程,由这个例程去调用main。这个例程如果用C代码来写(一般是用汇编来写),那就是exit(main(argc, argv)),也就是用main的返回值作为程序的结束值。

如图所示,除了exit外,还有_exit和_Exit函数也可以直接退出程序,但是exit总是会先清理一些资源再调用_exit或者_Exit返回到内核,包括调用终止处理程序(由atexit注册的函数)以及关闭文件。

image-20250314224913766

每个程序都会接收到一张环境表,由指针environ指向该表,表中每一项是一个环境变量串。但是我们程序不会通过environ访问环境变量,而是getenv和putenv函数对环境变量进行访问。

image-20250316123507433

C程序的空间布局

  1. 正文段:也就是该程序的代码,由ISA指定的机器代码。
  2. 数据段(初始化数据段):包含程序中任何函数外声明的、已经明确赋值的变量,比如int maxcount = 99;,将该变量以其初值放在数据段中。
  3. bss段(未初始化数据段):包含程序中任何函数外声明的、未明确赋值的变量,比如long sum[1000];,根据约定内核会将这个段中的数据会初始化为0。
  4. 栈:保存函数调用时的上下文、在函数内声明的变量等。
  5. 堆:动态分配的内存。

image-20250316124527003

二进制文件中除了上述的段之外,还有其它类型的段,比如包含符号表的段、包含调试信息的段、包含动态共享库链接表的段等,但这些段都不装载到程序执行的内存中。

共享库使得程序不用包含公共函数,减少二进制可执行文件的大小。当程序第一次调用某个库函数的时候,才会通过动态链接的方式和共享库进行连接。共享库的另一个优点是无需重新编译程序就能替换公共库函数的实现。

本文由作者按照 CC BY 4.0 进行授权