LINUX.ORG.RU

Вопрос новичка: как скомпилировать xstat.c из GLIBC-2.17 в свою shared библиотеку?

 ,


0

1

Добрый день!

Есть необходимость сделать свою версию системного вызова __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 библиотеку?

Буду благодарен за любой совет!



Последнее исправление: leave (всего исправлений: 3)

Я не вникал в простыню, но мне кажется ты сильно переусложняешь. Пропатчи glibc как нужно, собери статическую либу родными для glibc автотулзами, прилинкуй статический пропатченный glibc к динамическому so wrapper-у, экспортируя через --export-symbols нужные функции. А там линкер уже сам разберётся – что нужно для работы xstat, а что можно выбросить.

Хотя в таких задачах обычно не нужно ничего патчить, достаточно обернуть вызов.

UPD: Ещё проще. В glibc точно есть свой version script, из которого можно просто выбросить патчем лишнее, и собрать родной системой сборки динамический glibc' с одной экспортируемой функцией – xstat. Результат сборки glibc' подсунуть в LD_PRELOAD.

snizovtsev ★★★★★
()
Последнее исправление: snizovtsev (всего исправлений: 6)

Есть необходимость сделать свою версию системного вызова __xstat() в отдельной shared библиотеке, чтобы посмотреть как она работает внутри.

Кто работает? glibc? Системный вызов? Ещё что-то?

Сам исходник очень короткий, в десяток строк, но использует переменные и внутренние вызовы библиотеки, которые задаются где-то в конфигурации и h-файлах. Подтягивается целая лавина h-файлов, define, переменных, внутренних вызовов. Для начала хотел просто распечатать все переменные и параметры при вызове.

Системные вызовы - в ядре. В glibc только обёртки над ними, вся их суть - передать вызов ядру. Потому она такая и короткая. В связи с этим опять возникает вопрос что ты хочешь сделать.

firkax ★★★★★
()
Ответ на: комментарий от Bass
  1. Спасибо, интересный подход с bear, надо попробовать. На машине стоит CentOS 7.9.2009, glibc-2.17, староватое все. Своего bear конечно нет, надо ставить. Посмотрел странице bear на доступные релизы и не нашел ничего похожего на CentOS. Какой пакет наиболее подходит к моему CentOS? Если он более свежий то могут быть проблемы с версиями всех используемых программ и потребуется серьезное обновление, и не факт что успешное.

  2. Даже если я получу подробные скрипты сборки xstat.c, меня смущает что для glibc он компилируется три раза с разными опциями и не ясно, какие параметры компиляции больше мне подходят. Может для отдельного .so его надо собирать как-то по-другому, чем для полной glibc.

  3. Вариант с встройкой своего xstat() в единую glibc выглядит проще, чем вытянуть один исходник и собрать, но результат glibc.so будет громоздкий, это подмена всей библиотеки целиком. При запуске на другой версии CentOS могут быть проблемы несоответствия версий? Если там более свежая ОС?

  4. Сейчас компиляция xstat.c идет без ошибок, и проблема в отсутствии __libc_errno который выпал по дороге при сборке xstat.so. То есть проблем не так много, скорее какая-то мелочь при линковке .so, чтобы подхватить __libc_errno. Может я и ошибаюсь. Тут главное не уйти совсем в другом направлении.

Спасибо!

igoro
() автор топика
Ответ на: комментарий от firkax

__xstat (stat для пользователя) возвращает структуру параметров для выбранного файла. Хотел бы подправить некоторые параметры после __xstat перед возвращением. В качестве эксперимента.

igoro
() автор топика
Ответ на: комментарий от dataman

Я не слишком опытен в программировании и библиотеках. Просто возникла необходимость и надо поэкспериментировать. Работаю на машине где стоит CentOS и GLIBC-2.17 как данность. Так как разница в коде между версиями может быть существенной, я и взял ту же GLIBC которая уже стоит в системе, чтобы была максимальная совместимость во всём и можно было сравнить поведение своей версии с оригинальной.

igoro
() автор топика
Ответ на: комментарий от igoro

Отвечаю.

  1. bear написан на C++, там буквально несколько файлов, его можно собрать руками либо на целевой системе, либо в контейнере (Docker) той же версии.

  2. Надо смотреть, но я бы выбрал буквально первый вариант, который можно собрать в виде отдельной .so.

  3. Если я правильно понял вопрос, то модифицировать фундамент своего дома не стоит. Это сложнее в развёртывании, и это могут не одобрить многие заказчики.

  4. Надо смотреть, не могу никак прокомментировать.

Bass ★★★★★
()
Ответ на: комментарий от igoro

Вариант с встройкой своего xstat() в единую glibc выглядит проще, чем вытянуть один исходник и собрать, но результат glibc.so будет громоздкий, это подмена всей библиотеки целиком.

Так линкер должен сам выбросить всё ненужное, если экспортировать только xstat.

snizovtsev ★★★★★
()
Ответ на: комментарий от snizovtsev

Если рассматривать выделение нескольких вызовов из GLIBC в отдельную shared библиотеку, и стало быть сборку каждого вызова в рамках сборки GLIBC, то возникает такой вопрос. Я хочу выделить несколько модифицированных вызовов в новую shared библиотеку. Каждый вызов компилируется отдельно как и для GLIBC. Есть необходимость в нескольких глобальных переменных, доступных всем моим вызовам во время работы библиотеки. Первый вызов устанавливает флаг, скажем static int flag1 = 0; и он должен быть доступен для чтения (как минимум) в других вызовах. Такое возможно при сборке библиотеки из отдельных исходников вызовов? В коде остальных вызовов описать stat int flag? Будет ли это один глобальных флаг или локальный у каждого вызова? Как организовать переменную глобальную для многих вызовов? Спасибо.

igoro
() автор топика