Добрый день!
Есть необходимость сделать свою версию системного вызова __xstat() в отдельной shared библиотеке, чтобы посмотреть как она работает внутри. Добавить туда печать внутренних данных и использовать с помощью LD_PRELOAD. На машине стоит CentOS 7 с GLIBC-2.17, поэтому взял за основу исходники GLIBC-2.17. Архив отлично собрался и установился в отдельное место.
Сначала сделал свою версию вызова stat() но оказалось что ее не заменить в GLIBC динамически и надо подменять вызов __xstat(), только он динамически линкуется. Стал смотреть как собирался xstat.c при сборке библиотеки GLIBC. Вижу последовательность команд которыми make собирает всю GLIBC и исходник вызова xstat.c. У него много вариантов но собирается один
gcc ../sysdeps/unix/sysv/linux/wordsize-64/xstat.c .....
Сам исходник очень короткий, в десяток строк, но использует переменные и внутренние вызовы библиотеки, которые задаются где-то в конфигурации и h-файлах. Подтягивается целая лавина h-файлов, define, переменных, внутренних вызовов. Для начала хотел просто распечатать все переменные и параметры при вызове. Добавил печать параметров и переменных прямо в тело xstat.c и пытался пересобрать GLIBC. Исходник и вся библиотека перестала собираться совсем. Тогда решил скомпилировать только xstat.c в свою библиотеку xstat.so и использовать динамически. В версии 2.37 появляется несколько веток внутри вызова - не понятно какая ветка работает. В 2.17 ветка одна к счастью.
Хочу собрать из этого xstat.c свою xstat.so библиотеку с отладочной печатью которую использовать следующим образом
$ LD_PRELOAD=xstat.so <программа cо stat()>
Вот исходник __xstat
/* xstat using old-style Unix stat system call.
Copyright (C) 1991, 1995, 1996, 1997, 1998, 2000, 2002, 2003, 2004
Free Software Foundation, Inc.
This file is part of the GNU C Library.
......
/* Ho hum, since xstat == xstat64 we must get rid of the prototype or gcc
will complain since they don't strictly match. */
#define __xstat64 __xstat64_disable
#include <errno.h>
#include <stddef.h>
#include <sys/stat.h>
#include <sysdep.h>
#include <sys/syscall.h>
#include <bp-checks.h>
/////////////////////////////////////////////////////////////////////////
// added for printf
#include <stdio.h>
#include <stdlib.h>
/////////////////////////////////////////////////////////////////////////
/* Get information about the file NAME in BUF. */
int
__xstat (int vers, const char *name, struct stat *buf)
{
/////////////////////////////////////////////////////////////////////////
// added printf
printf("\n__xstat: vers: %d name: %s _STAT_VER_KERNEL: %d _STAT_VER_LINUX: %d\n",
vers,name,_STAT_VER_KERNEL,_STAT_VER_LINUX);
/////////////////////////////////////////////////////////////////////////
if (vers == _STAT_VER_KERNEL || vers == _STAT_VER_LINUX)
return INLINE_SYSCALL (stat, 2, name, CHECK_1 (buf));
__set_errno (EINVAL);
return -1;
}
В локальном sys/stat.h закомментарил объявление __xstat внешней функцией.
//extern int __xstat (int __ver, const char *__filename, struct stat *__stat_buf) __THROW __nonnull ((2, 3));
И читаю свою версию
#include "./sys_stat.h"
Пытаюсь cкомпилировать свою версию xstat.c у себя с этими же опциями gcc как при сборке чтобы все необходимое было найдено в области сборки GLIBC.
При сборке библиотеки
$ cd glibc-2.17; cd build; make configure; make
видно что нужный мне исходник компилируется ТРИ раза, последний раз для librtld.so
make[4]: Entering directory `libc/glibc-2.17/io'
gcc ../sysdeps/unix/sysv/linux/wordsize-64/xstat.c -c -std=gnu99 -fgnu89-inline -O2 -Wall -Winline \
-Wwrite-strings -fmerge-all-constants -frounding-math -g -Wstrict-prototypes \
-I../include -I/home/xxx/libc/glibc-2.17/buildnew/io -I/home/xxx/libc/glibc-2.17/buildnew \
-I../sysdeps/unix/sysv/linux/x86_64/64/nptl -I../sysdeps/unix/sysv/linux/x86_64/64 \
-I../nptl/sysdeps/unix/sysv/linux/x86_64 -I../nptl/sysdeps/unix/sysv/linux/x86 \
-I../sysdeps/unix/sysv/linux/x86 -I../sysdeps/unix/sysv/linux/x86_64 -I../sysdeps/unix/sysv/linux/wordsize-64 \
-I../nptl/sysdeps/unix/sysv/linux -I../nptl/sysdeps/pthread -I../sysdeps/pthread -I../ports/sysdeps/unix/sysv/linux \
-I../sysdeps/unix/sysv/linux -I../sysdeps/gnu -I../sysdeps/unix/inet -I../nptl/sysdeps/unix/sysv \
-I../ports/sysdeps/unix/sysv -I../sysdeps/unix/sysv -I../sysdeps/unix/x86_64 -I../nptl/sysdeps/unix \
-I../ports/sysdeps/unix -I../sysdeps/unix -I../sysdeps/posix -I../nptl/sysdeps/x86_64/64 \
-I../sysdeps/x86_64/64 -I../sysdeps/x86_64/fpu/multiarch -I../sysdeps/x86_64/fpu -I../sysdeps/x86/fpu \
-I../sysdeps/x86_64/multiarch -I../nptl/sysdeps/x86_64 -I../sysdeps/x86_64 -I../sysdeps/x86 \
-I../sysdeps/ieee754/ldbl-96 -I../sysdeps/ieee754/dbl-64/wordsize-64 -I../sysdeps/ieee754/dbl-64 \
-I../sysdeps/ieee754/flt-32 -I../sysdeps/wordsize-64 -I../sysdeps/ieee754 -I../sysdeps/generic \
-I../nptl -I../ports -I.. -I../libio -I. -D_LIBC_REENTRANT -include ../include/libc-symbols.h \
-o /home/xxx/libc/glibc-2.17/buildnew/io/xstat.o -MD -MP \
-MF /home/xxx/libc/glibc-2.17/buildnew/io/xstat.o.dt \
-MT /home/xxx/libc/glibc-2.17/buildnew/io/xstat.o
make[4]: Entering directory `libc/glibc-2.17/io'
gcc ../sysdeps/unix/sysv/linux/wordsize-64/xstat.c -c -std=gnu99 -fgnu89-inline -O2 -Wall -Winline \
-Wwrite-strings -fmerge-all-constants -frounding-math -g -Wstrict-prototypes -fPIC \
-I../include -I/home/xxx/libc/glibc-2.17/buildnew/io -I/home/xxx/libc/glibc-2.17/buildnew \
-I../sysdeps/unix/sysv/linux/x86_64/64/nptl -I../sysdeps/unix/sysv/linux/x86_64/64 \
-I../nptl/sysdeps/unix/sysv/linux/x86_64 -I../nptl/sysdeps/unix/sysv/linux/x86 \
-I../sysdeps/unix/sysv/linux/x86 -I../sysdeps/unix/sysv/linux/x86_64 -I../sysdeps/unix/sysv/linux/wordsize-64 \
-I../nptl/sysdeps/unix/sysv/linux -I../nptl/sysdeps/pthread -I../sysdeps/pthread \
-I../ports/sysdeps/unix/sysv/linux -I../sysdeps/unix/sysv/linux -I../sysdeps/gnu -I../sysdeps/unix/inet \
-I../nptl/sysdeps/unix/sysv -I../ports/sysdeps/unix/sysv -I../sysdeps/unix/sysv -I../sysdeps/unix/x86_64 \
-I../nptl/sysdeps/unix -I../ports/sysdeps/unix -I../sysdeps/unix -I../sysdeps/posix \
-I../nptl/sysdeps/x86_64/64 -I../sysdeps/x86_64/64 -I../sysdeps/x86_64/fpu/multiarch -I../sysdeps/x86_64/fpu \
-I../sysdeps/x86/fpu -I../sysdeps/x86_64/multiarch -I../nptl/sysdeps/x86_64 -I../sysdeps/x86_64 \
-I../sysdeps/x86 -I../sysdeps/ieee754/ldbl-96 -I../sysdeps/ieee754/dbl-64/wordsize-64 \
-I../sysdeps/ieee754/dbl-64 -I../sysdeps/ieee754/flt-32 -I../sysdeps/wordsize-64 -I../sysdeps/ieee754 \
-I../sysdeps/generic -I../nptl -I../ports -I.. -I../libio -I. -D_LIBC_REENTRANT \
-include ../include/libc-symbols.h -DPIC -DSHARED \
-o /home/xxx/libc/glibc-2.17/buildnew/io/xstat.os -MD -MP \
-MF /home/xxx/libc/glibc-2.17/buildnew/io/xstat.os.dt \
-MT /home/xxx/libc/glibc-2.17/buildnew/io/xstat.os
make[4]: Entering directory `libc/glibc-2.17/io'
gcc ../sysdeps/unix/sysv/linux/wordsize-64/xstat.c -c -std=gnu99 -fgnu89-inline -O2 -Wall -Winline \
-Wwrite-strings -fmerge-all-constants -frounding-math -g -Wstrict-prototypes -fPIC \
-I../include -I/home/xxx/libc/glibc-2.17/buildnew/io -I/home/xxx/libc/glibc-2.17/buildnew \
-I../sysdeps/unix/sysv/linux/x86_64/64/nptl -I../sysdeps/unix/sysv/linux/x86_64/64 \
-I../nptl/sysdeps/unix/sysv/linux/x86_64 -I../nptl/sysdeps/unix/sysv/linux/x86 \
-I../sysdeps/unix/sysv/linux/x86 -I../sysdeps/unix/sysv/linux/x86_64 -I../sysdeps/unix/sysv/linux/wordsize-64 \
-I../nptl/sysdeps/unix/sysv/linux -I../nptl/sysdeps/pthread -I../sysdeps/pthread \
-I../ports/sysdeps/unix/sysv/linux -I../sysdeps/unix/sysv/linux -I../sysdeps/gnu -I../sysdeps/unix/inet \
-I../nptl/sysdeps/unix/sysv -I../ports/sysdeps/unix/sysv -I../sysdeps/unix/sysv -I../sysdeps/unix/x86_64 \
-I../nptl/sysdeps/unix -I../ports/sysdeps/unix -I../sysdeps/unix -I../sysdeps/posix \
-I../nptl/sysdeps/x86_64/64 -I../sysdeps/x86_64/64 -I../sysdeps/x86_64/fpu/multiarch -I../sysdeps/x86_64/fpu \
-I../sysdeps/x86/fpu -I../sysdeps/x86_64/multiarch -I../nptl/sysdeps/x86_64 -I../sysdeps/x86_64 \
-I../sysdeps/x86 -I../sysdeps/ieee754/ldbl-96 -I../sysdeps/ieee754/dbl-64/wordsize-64 \
-I../sysdeps/ieee754/dbl-64 -I../sysdeps/ieee754/flt-32 -I../sysdeps/wordsize-64 -I../sysdeps/ieee754 \
-I../sysdeps/generic -I../nptl -I../ports -I.. -I../libio -I. -D_LIBC_REENTRANT \
-include ../include/libc-symbols.h -DPIC -DSHARED \
-o /home/xxx/libc/glibc-2.17/buildnew/io/rtld-xstat.os -MD -MP \
-MF /home/xxx/libc/glibc-2.17/buildnew/io/rtld-xstat.os.dt \
-MT /home/xxx/libc/glibc-2.17/buildnew/io/rtld-xstat.os \
-DNOT_IN_libc=1 -DIS_IN_rtld=1 -DIN_LIB=rtld
Трудно сказать какой сеанс компиляции более мне подходит, взял первый, где создается xstat.o
Не уверен, стоило ли оставлять параметры
-D_LIBC_REENTRANT -include ${GLIBC_PATH}/include/libc-symbols.h
может они нужны только при сборке полной GLIBC а здесь нет.
Моя команда компиляции выглядит следующим образом.
#!/bin/sh
export GLIBC_PATH=/home/xxx/libc/glibc-2.17
gcc -fPIC -shared ./xstat.c -std=gnu99 -fgnu89-inline -O2 -Winline -Wwrite-strings -fmerge-all-constants \
-frounding-math -Wstrict-prototypes -I${GLIBC_PATH}/include -I${GLIBC_PATH}/build/io -I${GLIBC_PATH}/build \
-I${GLIBC_PATH}/sysdeps/unix/sysv/linux/x86_64/64/nptl -I${GLIBC_PATH}/sysdeps/unix/sysv/linux/x86_64/64 \
-I${GLIBC_PATH}/nptl/sysdeps/unix/sysv/linux/x86_64 -I${GLIBC_PATH}/nptl/sysdeps/unix/sysv/linux/x86 \
-I${GLIBC_PATH}/sysdeps/unix/sysv/linux/x86 -I${GLIBC_PATH}/sysdeps/unix/sysv/linux/x86_64 \
-I${GLIBC_PATH}/sysdeps/unix/sysv/linux/wordsize-64 -I${GLIBC_PATH}/nptl/sysdeps/unix/sysv/linux \
-I${GLIBC_PATH}/nptl/sysdeps/pthread -I${GLIBC_PATH}/sysdeps/pthread \
-I${GLIBC_PATH}/ports/sysdeps/unix/sysv/linux -I${GLIBC_PATH}/sysdeps/unix/sysv/linux \
-I${GLIBC_PATH}/sysdeps/gnu -I${GLIBC_PATH}/sysdeps/unix/inet -I${GLIBC_PATH}/nptl/sysdeps/unix/sysv \
-I${GLIBC_PATH}/ports/sysdeps/unix/sysv -I${GLIBC_PATH}/sysdeps/unix/sysv -I${GLIBC_PATH}/sysdeps/unix/x86_64 \
-I${GLIBC_PATH}/nptl/sysdeps/unix -I${GLIBC_PATH}/ports/sysdeps/unix -I${GLIBC_PATH}/sysdeps/unix \
-I${GLIBC_PATH}/sysdeps/posix -I${GLIBC_PATH}/nptl/sysdeps/x86_64/64 -I${GLIBC_PATH}/sysdeps/x86_64/64 \
-I${GLIBC_PATH}/sysdeps/x86_64/fpu/multiarch -I${GLIBC_PATH}/sysdeps/x86_64/fpu \
-I${GLIBC_PATH}/sysdeps/x86/fpu -I${GLIBC_PATH}/sysdeps/x86_64/multiarch -I${GLIBC_PATH}/nptl/sysdeps/x86_64 \
-I${GLIBC_PATH}/sysdeps/x86_64 -I${GLIBC_PATH}/sysdeps/x86 -I${GLIBC_PATH}/sysdeps/ieee754/ldbl-96 \
-I${GLIBC_PATH}/sysdeps/ieee754/dbl-64/wordsize-64 -I${GLIBC_PATH}/sysdeps/ieee754/dbl-64 \
-I${GLIBC_PATH}/sysdeps/ieee754/flt-32 -I${GLIBC_PATH}/sysdeps/wordsize-64 -I${GLIBC_PATH}/sysdeps/ieee754 \
-I${GLIBC_PATH}/sysdeps/generic -I${GLIBC_PATH}/nptl -I${GLIBC_PATH}/ports -I${GLIBC_PATH} \
-I${GLIBC_PATH}/libio -I${GLIBC_PATH}/build -D_LIBC_REENTRANT -include ${GLIBC_PATH}/include/libc-symbols.h \
-L/lib64 -lc -o xstat.so
$ file xstat.so
xstat.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=b5f3154c730e812b14426f4eeb943c973d8ef363, not stripped
$ ldd xstat.so
linux-vdso.so.1 => (0x00007fff420ec000)
libc.so.6 => /lib64/libc.so.6 (0x00007f564f6bb000)
/lib64/ld-linux-x86-64.so.2 (0x00007f564fc8d000)
Компиляция завершается без ошибок. Однако при использовании новой библиотеки есть сообщение об отсутствии системного вызова __libc_errno, который должен быть в GLIBC
$ LD_PRELOAD=./xstat.so date
date: symbol lookup error: ./xstat.so: undefined symbol: __libc_errno
его действительно нет в моей библиотеке, но он есть в системной библиотеке libc-2.17.so
$ nm -D ./xstat.so | grep ' U '
U ctime
U ftime
U getenv
U gmtime
U __libc_errno
U printf
U puts
U sscanf
U strcpy
U timegm
$ nm /lib64/libc-2.17.so | grep __libc_errno
0000000000000010 b __libc_errno
Как подцепить недостающие вызовы к xstat.so и проверить что там еще не хватает? Как правильно скомпилировать отдельный исходник из GLIBC в отдельную shared библиотеку?
Буду благодарен за любой совет!