libc
系统调用、符号版本与数据结构演进:FreeBSD 如何处理兼容性
操作系统在演进过程中经常会碰到一个很现实的问题:一方面,内核和基础系统不可能几十年保持原样, 数据结构会变,系统调用会增加,某些早期设计也迟早需要推倒重来;另一方面,一个已经发布出去的 ABI 又不能想改就改。如果几十年间内核里的数据结构换了一批又一批,这艘船究竟还是不是当年那艘船? 保证它在用户态眼里仍然是同一艘船的关键,就在于 ABI 的稳定性。 否则系统每升级一次,过去编译好的程序都有可能需要重新编译,整个生态很快就会变得难以维护。
FreeBSD 在这方面有一个比较有利的条件:内核和基础用户态程序都在同一个源代码树中开发, 因此,一次涉及 kernel/userland ABI 的修改,通常可以同时修改系统调用、libc、 头文件以及基础系统中的调用者。
不过,这并不意味着兼容性会自动得到保证;恰恰相反,大多数兼容性最终仍然要靠一些相当具体、 甚至有些繁琐的工程手段来维持。
FreeBSD 对稳定分支上的用户态 ABI 非常重视,并将其视为一项核心特性。
项目的架构支持政策明确提到,对于 Tier 1 平台上的 userland ABI 变化,
通常应当提供兼容层,使针对任一稳定分支编译的程序无需重新编译或修改,
仍然能够正确运行(不过,某些兼容层可能并不在默认安装中启用)。
换句话说,ABI 稳定并不是一句抽象的承诺,它最终会落实成 libc 里的版本符号、
内核里的旧系统调用入口,以及各种名字里带着 freebsd11、freebsd12 的兼容代码。
这些代码单独看往往并不复杂,真正麻烦的是它们一旦成为 ABI 的一部分,就很难轻易删除。
阅读全文…C main() 的 exit() 和 return
这里讨论一个犀利而无用的细节问题。事情的缘起是有人在 GitHub 上提了一个 pull request 要求把许多程序的
main() 的终结部分从 exit(X) 改为 return X;,我反对了这一变动。
值得注意的是,在实践上,从 main 中 return 和调用 exit(3) 几乎等效的(此处还是有细微差别,
后面将会讨论),原因是 C 运行环境库的启动部分(这部分会在连接过程中嵌入到可执行文件中,
FreeBSD 的实现中,这部分位于 lib/libc/csu/libc_start1.c
的 __libc_start1:
| |
Moving toward a standarized qsort_r(3)
History of qsort_r(3)
First introduced in Research Unix V3 and eventually standardized as part of C Standard Library as of ANSI/ISO C89, qsort(3) provided an abstract interface where programmers can perform sort operation over an array of objects, by supplying a pointer to that array, the total number of the member objects, the size of individual member object, as well as a compare function. The compare function is expected to take two parameters, both pointers to a member object, and it shall return a negative number, 0, or a positive number, if the first object is considered smaller, equal, or greater respectively.
阅读全文…