LINUX.ORG.RU

вопрос по системным вызовам


0

0

Вот тут у меня вопрос делитанский, так что сразу не бейте сапогами...

если в лине три сис вызова - fork(), vfork(), clone() все три есть не что иное как библиотечные функции реализованный в glibc.В ядре linux есть их ответная часть sys_fork() - 0x3 sys_clone() - 0x78 sys_vfork() - 0x121. Есть несколько вопросов:

Ковыряние в исходниках libc показало что на fork() самом деле вызывает clone()

movl $120, %eax
call *_dl_sysinfo

правда самой инструкции совершающей вызов (типа прерывание int $0x80 или новомодный syscall так и не удалось обнаружить :( Никто не в курсе как происходит вызов ядра в этой мудреной библиотеке? Че такое *_dl_sysinfo я не нашел хотя по логике вещей за ней прячется вход в ядро)

У меня сложилось такое впечатление что vfork() привязан к тойже fork() и следовательно к clone() и как следствие во всех трех случаях вызываются sys_clone(). Вопрос - нахрена в ядре вызовы sys_fork() sys_vfork()? Они для совместимости или используются постоянно из рядовых с программ? если да то где они вызываются в libc?

anonymous

библиотечные вызовы fork(), vfork(), __clone() реализованны через clone()

>movl $120, %eax >call *_dl_sysinfo

/me так и не нашел этот участок когда... ctags спасет вас от мучений, за 2 секунды находится следующее:

# define FORK() \ INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \ &pid, NULL, NULL)

>как происходит вызов ядра в этой мудреной библиотеке? INLINE_SYSCALL

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

>movl $120, %eax
>call *_dl_sysinfo
это дизасемблированный fork.o вернее недокомпиленный fork.c (только не спрашивайте меня как я это сотворил... скомпилил либу нашел строку компиляции нужного файло и выполнил её немного изменив - изврат да и только)

хорошо я не дурак и этот INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \ &pid, NULL, NULL) нашел почти сразу а вот что эта за хуйне понять ен могу до сих пор! Ну ведь в си нет такой команды значит эта макроподстановка должна разворачиваться во что-то законченное так? А законченное это то что передает управление ядру типа int $0x80 (all *_dl_sysinfo ????) но вот её-то как раз и не находится! Где блин вход в ядро вот в чем вопрос?...

И так вопрос остался - если в все через то зачем два других системных вызова? (мало дибилов которые не ассемблере код пишут да еще при этом процессы размножают...)

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

>значит эта макроподстановка

for i386 see sysdeps/unix/sysv/linux/i386/sysdeps.h

>И так вопрос остался - если в все через то зачем два других системных вызова?

они остались для совместимости(?), а вот [источник?] найти не могу...

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

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

anonymous
()

> У меня сложилось такое впечатление что vfork() привязан к тойже fork() и следовательно к clone() и как следствие во всех трех случаях вызываются sys_clone().

в linux > 2.4 клоны - низшие элементы, между которыми квантуется время. именно из клонов получаются треды, кернел треды и форки.

man 'understanding linux kernel'

> Вопрос - нахрена в ядре вызовы sys_fork() sys_vfork()?

эти два сискола имеют различный функционал. почитайте man vfork на досуге.

btw: это всё равно что спросить зачем нужны sys_[v]fork, если есть sys_clone.

p/s:

http://tldp.org/LDP/khg/HyperNews/get/syscall/syscall86.html

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

>http://tldp.org/LDP/khg/HyperNews/get/syscall/syscall86.html

а теперь смотрим на год издания и вспоминаем что на дворе 21 век...

glibc'шные функции fork() и vfork() реализованны через sys_clone(). а последняя реализованна через do_fork()

и вообще vfork - это грязных хак, использовать который не совсем корректно, тем более что после реализации cow, преимуществ у него почти не осталось

поправте, если я не прав...

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

> а теперь смотрим на год издания и вспоминаем что на дворе 21 век...

из этого должно вытеакать, что там предоставленна неверная информация? ткните пальцем, что именно в этой заметке не верно/не актуально.

> glibc'шные функции fork() и vfork() реализованны через sys_clone(). а последняя реализованна через do_fork()

а разве я где-то уверждал обратное?

> и вообще vfork - это грязных хак, использовать который не совсем корректно, тем более что после реализации cow, преимуществ у него почти не осталось

почему грязный хак? всё реализуется чистенько и аккуратно в рамках абстракции "clone". (по крайней мере в 2.6 ветке, где vfork перестал быть "частным случаем клона" засчёт добавления в последний CLONE_VFORK флаг).

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

> из этого должно вытеакать, что там предоставленна неверная информация? ткните пальцем, что именно в этой заметке не верно/не актуально.

каюсь, согрешил

>а разве я где-то уверждал обратное?

>>>это всё равно что спросить зачем нужны sys_[v]fork, если есть sys_clone.

мне не совсем совсем понятно зачем их оставили в ядре, а не повелили "заглушки", ведь теперь их можно реализовать через clone()

>почему грязный хак?

на счет имплементации вопросов нет -- все очень красиво, но хотя бы историческая подоплёка этого вызова уже смущает... а грязный потому, что никто не знает что будет если (чисто гипотетически) после vfork'а не выполнится exec

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

> for i386 see sysdeps/unix/sysv/linux/i386/sysdeps.h

знаете ничего более внятного чем
#define INLINE_SYSCALL(name, nr, args...) __syscall_##name (args)
я не нашел, но вот куда ведет этот __syscall_##name (args) мне совсем не понятно но крайне интересно! В исследовательских целях.
Ответных макросов с __syscall не нашел. Исправте меня если я не прав.

А вот чем так плохи [v]fork() по отношению к clone если на ответной стороне в ядре sys_[v]fork() и sys_clone() все выполняют do_fork() только с разным набором флагов и параметров. Чем так не понравилась специализация на уровне ядра? (не бейте сапогами за возможную глупость а просвятите)

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

А кто пояснит вот это:
/*
* This is trivial, and on the face of it looks like it
* could equally well be done in user mode.
*
* Not so, for quite unobvious reasons - register pressure.
* In user mode vfork() cannot have a stack frame, and if
* done by calling the "clone()" system call directly, you
* do not have enough call-clobbered registers to hold all
* the information you need.
*/
это на тему vfork()

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

>знаете ничего более внятного чем
>#define INLINE_SYSCALL(name, nr, args...) __syscall_##name (args)
>я не нашел, 

плохо смотрели..

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

ну и дальше пошли варианты, в том числе с использованием int $0x80:

# define INTERNAL_SYSCALL(name, err, nr, args...) \
  ({ \
    register unsigned int resultvar; \
    EXTRAVAR_##nr \
    asm volatile ( \
    LOADARGS_##nr \
    "movl %1, %%eax\n\t" \
    "int $0x80\n\t"	\
    RESTOREARGS_##nr \
    : "=a" (resultvar) \
    : "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc"); \
    (int) resultvar; })

>Чем так не понравилась специализация на уровне ядра?
в стандарте POSIX не оговорено где болжна быть реализованна та или иная его часть, и разработчики стараются сократить число входов в kernel-space

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

Ок недосмотрел согласен, однако проблема решина не до конца. В приведенном мной варианте ассемблерных комманд раскрывается очевидно следующий участок кода:
# define INTERNAL_SYSCALL(name, err, nr, args...) \
({ \
register unsigned int resultvar; \
EXTRAVAR_##nr \
asm volatile ( \
LOADARGS_##nr \
"movl %1, %%eax\n\t" \
"call *_dl_sysinfo\n\t" \
RESTOREARGS_##nr \
: "=a" (resultvar) \
: "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc"); \
(int) resultvar; })

однако я нашел лиш такие определения

#if defined NEED_DL_SYSINFO && !defined __ASSEMBLER__
extern void _dl_sysinfo_int80 (void) attribute_hidden;
# define DL_SYSINFO_DEFAULT (uintptr_t) _dl_sysinfo_int80
# define DL_SYSINFO_IMPLEMENTATION \
asm (".text\n\t" \
".type _dl_sysinfo_int80,@function\n\t" \
".hidden _dl_sysinfo_int80\n" \
CFI_STARTPROC "\n" \
"_dl_sysinfo_int80:\n\t" \
"int $0x80;\n\t" \
"ret;\n\t" \
CFI_ENDPROC "\n" \
".size _dl_sysinfo_int80,.-_dl_sysinfo_int80\n\t" \
".previous");
#endif

как видно _dl_sysinfo_int80 и *_dl_sysinfo не совпадают. Полагаю связь между ними есть но вот какая?

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

Все нашел в elf/dl-support.c есть такое:
#ifdef NEED_DL_SYSINFO
/* Needed for improved syscall handling on at least x86/Linux. */
uintptr_t _dl_sysinfo = DL_SYSINFO_DEFAULT;
#endif
а как видно из предыдущего (nptl/sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h)
# define DL_SYSINFO_DEFAULT (uintptr_t) _dl_sysinfo_int80

теперь остался лишь один вопрос:
Нахрена по факту делается один лишний call *_dl_sysinfo который по факту есть не что иное как int $0x80 который оформлен в виде подпрограммы. Это не отражается на производительности? или наладные расходы на лишний вызов в интеловской архитектуре вдруг стали равны нулю???

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

>который по факту есть не что иное как int $0x80

кто вам сказал что это обязательно int $0x80 ? сейчас есть более оптимальные варианты для вызова syscall

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

Простите за любопытство какие??

насколько я понял в nptl/sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h есть только содержательный код с "int $0x80;\n\t" \ "ret;\n\t" \ который привязывается в elf/dl-support.c к uintptr_t _dl_sysinfo = DL_SYSINFO_DEFAULT; т. е. к предыдущему. В остатке лишь лишний вызов call *_dl_sysinfo. Или я опять чего-то недопонял?? Мне же интересно знать не о мнимых возможностях а о реальном состоянии дел!

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

#ifdef I386_USE_SYSENTER
# ifdef SHARED
#  define ENTER_KERNEL call *%gs:SYSINFO_OFFSET
# else
#  define ENTER_KERNEL call *_dl_sysinfo
# endif
#else
# define ENTER_KERNEL int $0x80
#endif

а вот на счет оптимальности call *%gs:SYSINFO_OFFSET ничего сказать
 не могу (может путаю по поводу более лучших способов с x86_64)

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

Не я не спорю что-то там новое со времен третьего вроде пня появилось и может это (call *%gs:SYSINFO_OFFSET) даже оно и есть но вот call *_dl_sysinfo нахрена вписали??? У кого есть объеснение? Ведь оно в итоге свелось в простой процедуре вызова тогоже прерывания из вложеной функции... а это накладные расходы и так при создании каждого процесса...

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.