LINUX.ORG.RU

Вопрос новичка: где найти исходный код вызова __libc_errno? Можно написать свой?

 ,


0

1

Возвращаясь к проблеме отсутствия __libc_errno вызова при сборке своей shared библиотеки с несколькими системными вызовами типа xstat() возникла идея написать самому некую замену этому вызову взамен отсутствующего. Может это конечно и глупая идея но других идей нет. Пока собрать свою shared library полноценно не получается.

Подробнее. Собираю код __xstat() и еще __lxstat(), __fxstat() в отдельном исходнике c глобальными переменными для обмена и своими доработками, компилирую их той же командой что и при сборке GLIBC и ошибок компиляции нет. Однако при использовании библиотеки не находится __libc_errno. Хотя она явно есть внутри libc.so и пути к ней указаны.

$ LD_PRELOAD=./xstat.so date
date: symbol lookup error: ./xstat.so: undefined symbol: __libc_errno

Вызова этой процедуры нет явно в коде xstat(), есть только __set_errno().

int
__xstat (int vers, const char *name, struct stat *buf)
{
  if (vers == _STAT_VER_KERNEL || vers == _STAT_VER_LINUX)
    return INLINE_SYSCALL (stat, 2, name, CHECK_1 (buf));

  __set_errno (EINVAL); // <<<<<<<<<<<<<<<<<
  return -1;
}

когда я закомментарил этот вызов, это не помогло.

  //__set_errno (EINVAL); // <<<<<<<<<<<<<<<<<

По прежнему он кем-то используется и его так и нет в моей shared библиотеке.

date: symbol lookup error: ./xstat.so: undefined symbol: __libc_errno

Корректная отработка ошибок при системных вызовах мне не требуется, так как shared библиотека работает с отлаженными программами и там весь код уже написан правильно. Отсюда и идея написать свою процедуры-пустышку для сборки библиотеки. При это она уже не будет extern.

Просмотрел всю инсталляцию GLIBC-2.17 и не обнаружил нигде каких-либо исходников этого вызова. Хотя его название в внутри libc.so есть, может только название а не код.

0000000000000010 b __libc_errno
0000000000000054 b __libc_h_errno

Сам вызов упоминается всего в нескольких местах

../include/errno.h:#   define errno __libc_errno
../ports/sysdeps/unix/sysv/linux/ia64/nptl/sysdep-cancel.h:#  define SYSDEP_CANCEL_ERRNO __libc_errno
../ports/sysdeps/unix/sysv/linux/m68k/sysdep.h:#   define SYSCALL_ERROR_ERRNO __libc_errno
../sysdeps/unix/sysv/linux/sparc/sparc64/sysdep.h:#   define SYSCALL_ERROR_ERRNO __libc_errno
../sysdeps/unix/sysv/linux/sparc/sparc32/sysdep.h:#   define SYSCALL_ERROR_ERRNO __libc_errno
../sysdeps/unix/sysv/linux/i386/sysdep.h:#   define SYSCALL_ERROR_ERRNO __libc_errno
../sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h:#   define SYSCALL_ERROR_ERRNO __libc_errno
../sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h:#   define SYSCALL_ERROR_ERRNO __libc_errno
../sysdeps/unix/sysv/linux/x86_64/sysdep.h:#   define SYSCALL_ERROR_ERRNO __libc_errno
../sysdeps/unix/sysv/linux/sh/sysdep.h:#   define SYSCALL_ERROR_ERRNO __libc_errno

Есть даже некий код связанный с обработкой ошибок в ../sysdeps/unix/sysv/linux/x86_64/sysdep.h где используется определение SYSCALL_ERROR_ERRNO

# if defined PIC && defined RTLD_PRIVATE_ERRNO
#  define SYSCALL_SET_ERRNO			\
  lea rtld_errno(%rip), %RCX_LP;		\
  neg %eax;					\
  movl %eax, (%rcx)
# else
#  ifndef NOT_IN_libc
#   define SYSCALL_ERROR_ERRNO __libc_errno
#  else
#   define SYSCALL_ERROR_ERRNO errno
#  endif
#  define SYSCALL_SET_ERRNO			\
  movq SYSCALL_ERROR_ERRNO@GOTTPOFF(%rip), %rcx;\
  neg %eax;					\
  movl %eax, %fs:(%rcx);
# endif

Там же для обработки ошибок используется опять другая процедура __set_errno

# define INLINE_SYSCALL(name, nr, args...) \
  ({									      \
    unsigned long int resultvar = INTERNAL_SYSCALL (name, , nr, args);	      \
    if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (resultvar, ), 0))	      \
      {									      \
	__set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, ));		      \
	resultvar = (unsigned long int) -1;				      \
      }									      \
    (long int) resultvar; })

Она в одном месте описана как присвоение кода ошибки

./include/errno.h

# define __set_errno(val) (errno = (val))

Но мне попадался и такой код процедуры

#include <errno.h>

int __set_errno(int n)
{
	errno = n;
	return -1;
}

Возвращаясь к __libc_errno. Хотелось бы написать подобный аналог для __libc_errno. Единственное объявление __libc_errno находится в ../csu/errno.c

__thread int errno;
extern __thread int __libc_errno __attribute__ ((alias ("errno")))
  attribute_hidden;

Вопрос как правильно написать оболочку этого вызова?

Результат - int Имя вызова - __libc_errno Параметр - что такое (alias («errno»))? Что туда передается? По идее тоже код ошибки как и в __set_errno.

К сожалению никаких примеров прямого вызова процедуры _libc_errno нигде не нашел. Только куски ассемблера. Хотелось бы написать что-то вроде этого чтобы вызывать из С.

#include <errno.h>

int __libc_errno (int n)
{
	errno = n;
	return -1;
}

Это вообще возможно написать такую замену __libc_errno не сломав GLIBC? Извините за сумбурное описание проблемы. Спасибо!



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

в гугл не пускают?

https://en.cppreference.com/w/cpp/error/errno

errno это не функция, а переменная, куда коды ошибки пишутся.

чтоб записать в errno, там вроде функция set_errno() должна быть. точно не помню….хорош вообще ерундой заниматься, гугли сам, все ищется в пять минут

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 2)
Ответ на: комментарий от alysnix

Простите, вопрос не про переменную errno, а про глубинную функцию __libc_errno, которая пропала при сборке моей shared library, о которой я не знал раньше. Она не линкуется по-умолчанию при

gcc -fPIC -shared xstate.c ...... -L/lib64 -lc -lgcc -o xstat.so

Первый раз имею с ней дело, отсюда и вопрос как ее подлинковать или написать свою процедуру чтобы просто собрать свою библиотеку. Я уже неделю гуглю интернет и форумы по программированию и много узнал про обработку ошибок с GLIBC, но как ее явно подцепить и что там внутри - не нашел. Все началось с этой недавней темы: Вопрос новичка: как скомпилировать xstat.c из GLIBC-2.17 в свою shared библиотеку?

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

это не глубинная функция, а глубинная переменная. вот пример макроса

https://codebrowser.dev/glibc/glibc/include/errno.h.html

#  undef  errno
#  if IS_IN (libc)
#   define errno __libc_errno
#  else
#   define errno errno		/* For #ifndef errno tests.  */
#  endif

то есть errno есть переименованная __libc_errno

так это и есть сылка на внешнее обьявление переменной __libc_errno, которое вы обыскались, думая что оно функция. а вот самого обьявление вы потеряли где-то. его надо найти и влинковать. или ручками обьявить как int __libc_errno где-нибудь.

__thread int errno;
extern __thread int __libc_errno __attribute__ ((alias ("errno")))
  attribute_hidden;

короче там где-то закопано реальное обьявление int __libc_errno, которое потом перименовывают в errno. вот ищите где

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 3)
Ответ на: комментарий от alysnix

Вот это поворот! Спасибо! Но тогда сообщение при использовании библиотеки

$ LD_PRELOAD=./xstat.so <команда>
date: symbol lookup error: ./xstat.so: undefined symbol: __libc_errno

говорит что на неё ссылаются, но ее нигде нет в библиотеке. Просто не объявлена. Где эта переменная должна находиться? Просто задать глобальную переменную errno, __lic_errno перед моими вызовами? Или мне нужно собирать свои исходники с куском из GLIBC с этими переменными? Чего же у меня не хватает?

Тогда опять возникает вопрос о глобальных переменных в GLIBC. Она вся собирается из отдельных исходников, один исходник - один или несколько вызовов. Как задать глобальную переменную которая доступна из вызовов разных исходников? Это как раз о errno. Задать ее в каждом исходнике _thread static errno, __libc_errno; или как-то еще? Спасибо!

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

Объявление отсутствующей переменной в начале кода решило проблему.

int _thread __libc_errno;

Статическое объявление конфликтует с нестатическим в errno.h поэтому пришлось static убрать. Библиотека собралась и благополучно заработала. Спасибо за разъяснение и толчок в нужном направлении!

Можете ответить по поводу глобальных переменных в GLIBC чтобы они были доступна в разных вызовах, которые собираются из отдельных исходников?

Спасибо!

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

Можете ответить по поводу глобальных переменных в GLIBC чтобы они были доступна в разных вызовах, которые собираются из отдельных исходников?

в языке Цэ обьявляешь нестатическую переменную в любом нехидере, а там где нужно ее использовать, пишешь extern …

например int X=0;

в другом месте пишешь extern int X. можно extern int X положить в некий хидер и его инклудить.

extern … тут говорит компилятору буквально следующее - «существует символ X типа int. но не в данной единице компиляции, а «снаружи» - extern.»

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