Компиляция с -m32 -march=i386 -static
: запускается на всех сравнительно недавних версиях ядра, но дает сбой, если они немного старше с хорошо известным сообщением об ошибке
user@ancient:~ $ ./a.out
FATAL: kernel too old
Segmentation fault
Это ошибка glibc
с минимальной поддерживаемой версией ядра, например ядро 2.6.4 в моей системе:
$ file a.out
a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
statically linked, for GNU/Linux 2.6.4, not stripped
Скомпилируйте glibc
себя с поддержкой самого старого возможного ядра. Этот пост описывает его более подробно, но по сути это выглядит так
wget ftp://ftp.gnu.org/gnu/glibc/glibc-2.14.tar.bz2
tar -xjf glibc-2.14.tar.bz2
cd glibc-2.14
mkdir build; cd build
../configure --prefix=/usr/local/glibc_32 \
--enable-kernel=2.0.0 \
--with-cpu=i486 --host=i486-linux-gnu \
CC="gcc -m32 -march=i486" CXX="g++ -m32 -march=i486"
make -j 4
make intall
Не уверен, что опции --with-cpu
и --host
что-то делают, самое важное - принудительно использовать флаги компилятора -m32 -march=i486
для 32-битных сборок (к сожалению, -march=i386
выдает ошибку через некоторое время) и --enable-kernel=2.0.0
, чтобы сделать библиотеку совместимой со старыми ядрами. Кстати, во время configure
я получил предупреждение
WARNING: minimum kernel version reset to 2.0.10
что все еще приемлемо, я полагаю. Список вещей, которые меняются в разных ядрах, см. ./sysdeps/unix/sysv/linux/kernel-features.h
.
.
Хорошо, давайте сделаем ссылку на только что скомпилированную библиотеку glibc
, немного сумбурную, но здесь все сказано:
$ export LIBC_PATH=/usr/local/glibc_32
$ export LIBC_FLAGS=-nostdlib -L${LIBC_PATH} \
${LIBC_PATH}/crt1.o ${LIBC_PATH}/crti.o \
-lm -lc -lgcc -lgcc_eh -lstdc++ -lc \
${LIBC_PATH}/crtn.o
$ g++ -m32 -static prog.o ${LIBC_FLAGS} -o prog
Поскольку мы выполняем статическую компиляцию, порядок ссылок важен и может потребовать некоторых проб и ошибок, но в основном мы узнаем, какие опции gcc
предоставляет компоновщику:
$ g++ -m32 -static -Wl,-v file.o
Заметьте, crtbeginT.o
и crtend.o
также связаны, которые мне не нужны для моих программ, поэтому я их пропустил. Вывод также включает строку типа --start-group -lgcc -lgcc_eh -lc --end-group
, которая указывает на взаимозависимость между библиотеками, см. этот пост . Я только что упомянул -lc
дважды в командной строке gcc
, которая также решает взаимозависимость.
Правильно, тяжелая работа окупилась, и теперь я получаю
$ file ./prog
./prog: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
statically linked, for GNU/Linux 2.0.10, not stripped
Отлично, подумал я, теперь попробуйте на старой системе:
user@ancient:~ $ ./prog
set_thread_area failed when setting up thread-local storage
Segmentation fault
Это опять-таки сообщение об ошибке glibc
от ./nptl/sysdeps/i386/tls.h
. Я не понимаю деталей и сдаюсь.