0
votes

I'm helping others doing a lab experiment of the "operating systems concepts" course. The experiment task is to compile Linux 2.6.26 and run it in QEMU.

After compiling the Linux kernel, we're told to write a smallest program to serve as the init program. The example we're presented (and we followed) is:

#include <stdio.h>

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

The compilation command is:

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

The host environment should be a freshly-installed Ubuntu 14.04.6 (i386).


The problem is, one of my fellow students followed the instruction carefully, and the init program failed to execute. I asked him for his whole initrd.img, and noticed how his init program looks different:

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

To me, that's clearly not something that can run on Linux 2.6.26. With GCC 4.8 provided in the Ubuntu APT repository (trusty), how can I get GCC to output something that runs on Linux 2.6.26?

FYI: On my own testing VM (also Ubuntu 14.04.6, Linux 4.4, same latest GCC version from Ubuntu APT repo as of April 2, 2019), the compiled program shows Linux 2.6.24 in file output. Also, his binary runs perfectly well in QEMU with my freshly compiled 2.6.32.37 kernel.

2
It's a glibc thing, not a gcc thing: stackoverflow.com/questions/12236159/… - Shawn
@Shawn How can glibc matter when the binary is statically linked? - iBug
It's statically linked to a particular version of glibc, which in turn was configured to require a particular minimum kernel version. - Shawn
@Shawn Why is it glibc instead of binutils (as, ld etc.)? - iBug

2 Answers

1
votes

Specify the expected Linux version of the output binary of GCC

in your question you speak about the version of libc C but that can also concerns a lot of other libs, and may be you want also produce 32b and/or 64b executable(s).

For me the most secure way is to use pbuilder, I use it to produce BoUML debs for Ubuntu Cosmic (18.10) Bionic (18.04), Artful (17.10) Zesty (17.04) Yakkety (16.10) Xenial (16.04) Trusty (14.04) and Precise (12.04) and that in both 32b and 64b, and I do all of that from my Ubuntu Xenial 64b just doing the appropriate sequence of pbuilder commands (without any reboot to go in each Linux release)

That needs time to generate a version but because this is made in the corresponding Linux version you are sure of the result.

0
votes

The provided lab environment was Ubuntu 14.04, where the package libc6 has version 2.19-0ubuntu6.14.

The lab instruction provided by the teaching assistants contained an instruction to change the APT source by editing /etc/apt/sources.list manually, which had a SERIOUS disaster in it: The "version" string in the edited example was xenial instead of trusty, which, if followed, would factually update your system to Xenial (Ubuntu 16.04). The new version of libc6 was 2.23-0ubuntu11, which would cause as and ld (from binutils, not related to GCC) to output ELF with a minimum Linux version of 2.6.32.

With glibc version 2.19, the output ELF is compatible with Linux 2.6.24, but with glibc 2.23, the output is only compatible with Linux 2.6.32.

I tested and verified this by compiling a test program under Ubuntu 14.04 and checking the ELF information, then replaced all trusty with xenial, did apt-get update and only updated binutils and its dependencies (which includes libc6), and compiled the program and checked it again.