指定 GCC 输出二进制文件的预期 Linux 版本

Posted

技术标签:

【中文标题】指定 GCC 输出二进制文件的预期 Linux 版本【英文标题】:Specify the expected Linux version of the output binary of GCC 【发布时间】:2019-08-23 14:49:31 【问题描述】:

我正在帮助其他人进行“操作系统概念”课程的实验室实验。实验任务是编译Linux 2.6.26并在QEMU中运行。

编译完 Linux 内核后,我们被告知要编写一个最小的程序作为init 程序。我们提供的(我们遵循的)示例是:

#include <stdio.h>

int main() 
    while (1) 
        puts("Hello!");
        sleep(2);
    

编译命令为:

root@ubuntu:/home/vmware/oslab# gcc --version
gcc (Ubuntu 4.8.4-2ubuntu1~14.04.4) 4.8.4
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

root@ubuntu:/home/vmware/oslab# gcc -static -o init hello.c

主机环境应该是全新安装的 Ubuntu 14.04.6 (i386)。


问题是,我的一位同学仔细地按照说明进行操作,但 init 程序未能执行。我向他询问了他的整个initrd.img,并注意到他的init 程序看起来不同:

vmware@ubuntu:~/oslab$ file mnt/init
mnt/init: ELF 32-bit LSB  executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=7365ac494ef1d924c171899c169dbd3195d2d209, not stripped

对我来说,这显然不能在 Linux 2.6.26 上运行。使用 Ubuntu APT 存储库中提供的 GCC 4.8(值得信赖),如何让 GCC 输出在 Linux 2.6.26 上运行的内容?

仅供参考:在我自己的测试虚拟机上(也是 Ubuntu 14.04.6、Linux 4.4,截至 2019 年 4 月 2 日,来自 Ubuntu APT 存储库的最新 GCC 版本相同),编译后的程序显示 Linux 2.6.24 file 输出中。此外,他的二进制文件在我新编译的 2.6.32.37 内核的 QEMU 中运行良好。

【问题讨论】:

这是 glibc 的东西,而不是 gcc 的东西:***.com/questions/12236159/… @Shawn 当二进制文件是静态链接时,glibc 有什么作用? 它静态链接到特定版本的 glibc,而后者又被配置为需要特定的最低内核版本。 @Shawn 为什么是 glibc 而不是 binutils(asld 等)? 【参考方案1】:

提供的实验室环境是 Ubuntu 14.04,其中软件包 libc6 的版本为 2.19-0ubuntu6.14

教学助手提供的实验指令包含一条通过手动编辑/etc/apt/sources.list来更改APT源的指令,其中有一个严重的灾难:编辑示例中的“版本”字符串是 xenial 而不是 trusty,如果遵循它,实际上会将您的系统更新到 Xenial (Ubuntu 16.04)。 libc6 的新版本是2.23-0ubuntu11,这将导致asld(来自binutils,与GCC 无关)输出ELF,最低Linux 版本为2.6.32。

使用 glibc 2.19 版本,输出 ELF 与 Linux 2.6.24 兼容,但使用 glibc 2.23,输出仅与 Linux 2.6.32 兼容。

我通过在 Ubuntu 14.04 下编译测试程序并检查 ELF 信息来测试和验证这一点,然后将所有 trusty 替换为 xenial,做了 apt-get update 并且 更新了 binutils及其依赖项(包括libc6),并编译程序并再次检查。

【讨论】:

【参考方案2】:

指定预期的 GCC 输出二进制文件的 Linux 版本

在您的问题中,您谈到了 libc C 的版本,但这也可能涉及许多其他库,并且您可能还希望生成 32b 和/或 64b 可执行文件。

对我来说最安全的方法是使用 pbuilder,我用它为 Ubuntu Cosmic (18.10) Bionic (18.04)、Artful ( 17.10) Zesty (17.04) Yakkety (16.10) Xenial (16.04) Trusty (14.04) 和 Precise (12.04) 以及在 32b 和 64b 中,我从我的 Ubuntu Xenial 64b 中完成所有这些,只需执行适当的 pbuilder 命令(在每个 Linux 版本中无需重新启动)

这需要时间来生成一个版本,但是因为这是在相应的 Linux 版本中制作的,所以您可以确定结果。

【讨论】:

以上是关于指定 GCC 输出二进制文件的预期 Linux 版本的主要内容,如果未能解决你的问题,请参考以下文章

gcc编译过程中的各种参数含义

支持windows linux下将指定内存段转为16进制与ascii码的日志输出类

(Linux)gcc进行优化编译的参数是啥?

Linux GCC常用命令总结

Linux下文件加密解密简单版(支持压缩加密解密)

精细控制 GCC 的输出