.\" -*- coding: UTF-8 -*- '\" t .\" Written by Mike Frysinger .\" .\" %%%LICENSE_START(PUBLIC_DOMAIN) .\" This page is in the public domain. .\" %%%LICENSE_END .\" .\" Useful background: .\" http://articles.manugarg.com/systemcallinlinux2_6.html .\" https://lwn.net/Articles/446528/ .\" http://www.linuxjournal.com/content/creating-vdso-colonels-other-chicken .\" http://www.trilithium.com/johan/2005/08/linux-gate/ .\" .\"******************************************************************* .\" .\" This file was generated with po4a. Translate the source file. .\" .\"******************************************************************* .TH vDSO 7 "3 мая 2023 г." "Linux man\-pages 6.05.01" .SH ИМЯ vdso \- обзор виртуального динамически компонуемого общего объекта ELF .SH СИНТАКСИС .nf \fB#include \fP .PP \fBvoid *vdso = (uintptr_t) getauxval(AT_SYSINFO_EHDR);\fP .fi .SH ОПИСАНИЕ «vDSO» (virtual dynamic shared object, виртуальный динамический общий объект) — это маленькая общая библиотека, которую ядро автоматически отображает в адресное пространство всех приложений пользовательского пространства. Обычно, приложениям она не нужна, так как vDSO, чаще всего, вызывается из библиотеки C. Вы можете использовать стандартные функции как обычно, а библиотека C самостоятельно позаботится об использовании возможностей vDSO. .PP И всё же, зачем нужна vDSO? Есть несколько системных вызовов ядра, которые используются в пользовательском коде настолько часто, что это сильно влияет на общую производительность. Это происходит из\-за частого повторения вызовов, а также затрат на переключение контекста, которые возникают при выходе из пользовательского пространства и входа в ядро. .PP Оставшаяся часть этой документации предназначена для любопытных и/или авторов библиотеки C, а не для обычных разработчиков. Если вы попытаетесь вызвать vDSO в своём приложении не через библиотеку C, то, наиболее вероятно, сделаете это неправильно. .SS "В качестве примера" Выполнение системных вызовов может быть медленным. В 32\-битных системах x86 вы можете использовать программное прерывание (\fIint $0x80\fP), чтобы заставить ядро выполнить системный вызов. Однако, эта инструкция очень затратна: она проходит по полному маршруту обработки прерываний в микрокоде процессора, а также в ядре. Новые процессоры содержат более быстрые инструкции (но обратно совместимые) для запуска системных вызовов. Вместо того, чтобы требовать от библиотеки C выяснения во время выполнения есть ли такая возможность, библиотека C может использовать функции, предоставляемые ядром в vDSO. .PP Заметим, что можно запутаться в терминологии. В системах x86 функция vDSO, используемая для определения предпочтительного метода выполнения системного вызова, называется «__kernel_vsyscall», но в x86\-64 термин «vsyscall» также ссылается на устаревший метод запроса ядра о времени или на каком ЦП выполняется вызывающий. .PP One frequently used system call is \fBgettimeofday\fP(2). This system call is called both directly by user\-space applications as well as indirectly by the C library. Think timestamps or timing loops or polling\[em]all of these frequently need to know what time it is right now. This information is also not secret\[em]any application in any privilege mode (root or any unprivileged user) will get the same answer. Thus the kernel arranges for the information required to answer this question to be placed in memory the process can access. Now a call to \fBgettimeofday\fP(2) changes from a system call to a normal function call and a few memory accesses. .SS "Нахождение vDSO" Базовый адрес vDSO (если есть) передаётся ядром каждой программе во вспомогательном векторе инициализации (смотрите \fBgetauxval\fP(3)) через тег \fBAT_SYSINFO_EHDR\fP. .PP Вы не должны рассчитывать на то, что vDSO отображается в каком\-то определённом месте карты пользовательской памяти. Обычно, базовый адрес во время выполнения выбирается произвольным образом каждый раз при создании нового образа процесса (с помощью \fBexecve\fP(2)). Это делается в целях безопасности для предотвращения атак «возврат в libc». .PP Для некоторых архитектур также существует тег \fBAT_SYSINFO\fP. Он используется только для нахождения точки входа vsyscall и часто отсутствует или равен 0 (то есть недоступен). Этот тег — атавизм первых версий vDSO (смотрите \fIИстория\fP ниже) и не должен использоваться. .SS "Формат файла" Так как vDSO — полноценный образ ELF, вы можете искать в нём символы. Это позволяет добавлять новые символы в новых версиях ядра и библиотеке C находить доступные свойства во время выполнения с различными версиями ядер. Зачастую, библиотека C выполняет обнаружение при первом вызове и затем кэширует результат для последующих вызовов. .PP Все символы имеют версии (в формате версий GNU). Это позволяет ядру обновлять сигнатуру функции без нарушения обратной совместимости. Смена версии означает изменение аргументов функции или возвращаемого значения. Таким образом, при поиске символа в vDSO, вы всегда должны включать версию для нахождения ожидаемого ABI. .PP Обычно, vDSO удовлетворяет соглашению об именовании, начиная все символы с «__vdso_» или «__kernel_», для их выделения среди других стандартных символов. Например, функция «gettimeofday» называется «__vdso_gettimeofday». .PP Для вызова этих функций используйте стандартные соглашения о вызове языка Си. Учитывать поведение регистров и стека не требуется. .SH ЗАМЕЧАНИЯ .SS "Исходный код" Код vDSO автоматически компилируется и компонуется при сборке ядра. Обычно, его можно найти в каталоге соответствующей архитектуры: .PP .in +4n .EX find arch/$ARCH/ \-name \[aq]*vdso*.so*\[aq] \-o \-name \[aq]*gate*.so*\[aq] .EE .in .\" .SS "Имена vDSO" Имя vDSO отличается на разных архитектурах. Часто его можно увидеть в выводе утилит, подобных \fBldd\fP(1) из glibc. Точное имя не должно влиять на код, поэтому жёстко оно нигде не задаётся. .if t \{\ .ft CW \} .TS l l. ABI пользователя vDSO name _ aarch64 linux\-vdso.so.1 arm linux\-vdso.so.1 ia64 linux\-gate.so.1 mips linux\-vdso.so.1 ppc/32 linux\-vdso32.so.1 ppc/64 linux\-vdso64.so.1 riscv linux\-vdso.so.1 s390 linux\-vdso32.so.1 s390x linux\-vdso64.so.1 sh linux\-gate.so.1 i386 linux\-gate.so.1 x86\-64 linux\-vdso.so.1 x86/x32 linux\-vdso.so.1 .TE .if t \{\ .in ^".ft P$ \} .SS "strace(1), seccomp(2) и vDSO" При трассировке системных вызовов с помощью \fBstrace\fP(1), символы (системные вызовы), экспортируемые vDSO, \fIне\fP показываются в результате трассировки. Также данные системные вызовы будут невидимы в фильтрах \fBseccomp\fP(2). .SH "ЗАМЕЧАНИЯ ДЛЯ РАЗЛИЧНЫХ АРХИТЕКТУР" Далее приведены замечания по vDSO для различных архитектур. .PP Заметим, что используемая vDSO основывается на ABI вашего кода пользовательского пространства, а не на ABI ядра. Например, когда вы запускаете 32\-битный исполняемый файл ELF на i386, то вы получаете ту же vDSO независимо от того, выполняете ли вы его под 32\-битном ядром на i386 или под 64\-битном ядром под x86\-64. Таким образом, для определения нужного раздела ниже нужно использовать имя ABI пользовательского пространства. .SS "Функции на ARM" .\" See linux/arch/arm/vdso/vdso.lds.S .\" Commit: 8512287a8165592466cb9cb347ba94892e9c56a5 В таблице ниже перечислены символы, экспортируемые vDSO. .if t \{\ .ft CW \} .TS l l. символ version _ __vdso_gettimeofday LINUX_2.6 (экспортируется начиная с Linux 4.1) __vdso_clock_gettime LINUX_2.6 (экспортируется начиная с Linux 4.1) .TE .if t \{\ .in ^".ft P$ \} .PP .\" See linux/arch/arm/kernel/entry-armv.S .\" See linux/Documentation/arm/kernel_user_helpers.rst Также, перенос ARM содержит страницу кода со вспомогательными функциями. Так как это просто страница с кодом, информация ELF отсутствует и поиск функций невозможен и неизвестны их версии. Хотя в коде есть функции нескольких версий. .PP For information on this code page, it's best to refer to the kernel documentation as it's extremely detailed and covers everything you need to know: \fIDocumentation/arm/kernel_user_helpers.rst\fP. .SS "Функции на aarch64" .\" See linux/arch/arm64/kernel/vdso/vdso.lds.S В таблице ниже перечислены символы, экспортируемые vDSO. .if t \{\ .ft CW \} .TS l l. символ version _ __kernel_rt_sigreturn LINUX_2.6.39 __kernel_gettimeofday LINUX_2.6.39 __kernel_clock_gettime LINUX_2.6.39 __kernel_clock_getres LINUX_2.6.39 .TE .if t \{\ .in ^".ft P$ \} .SS "Функции на bfin (Blackfin) (перенос удалён в Linux 4.17)" .\" See linux/arch/blackfin/kernel/fixed_code.S .\" See http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:fixed-code As this CPU lacks a memory management unit (MMU), it doesn't set up a vDSO in the normal sense. Instead, it maps at boot time a few raw functions into a fixed location in memory. User\-space applications then call directly into that region. There is no provision for backward compatibility beyond sniffing raw opcodes, but as this is an embedded CPU, it can get away with things\[em]some of the object formats it runs aren't even ELF based (they're bFLT/FLAT). .PP Эта страница с кодом хорошо описана в открытой документации: .br http://docs.blackfin.uclinux.org/doku.php?id=linux\-kernel:fixed\-code .SS "Функции на mips" .\" See linux/arch/mips/vdso/vdso.ld.S В таблице ниже перечислены символы, экспортируемые vDSO. .if t \{\ .ft CW \} .TS l l. символ version _ __kernel_gettimeofday LINUX_2.6 (экспортируется начиная с Linux 4.4) __kernel_clock_gettime LINUX_2.6 (экспортируется начиная с Linux 4.4) .TE .if t \{\ .in ^".ft P$ \} .SS "Функции на ia64 (Itanium)" .\" See linux/arch/ia64/kernel/gate.lds.S .\" Also linux/arch/ia64/kernel/fsys.S and linux/Documentation/ia64/fsys.rst В таблице ниже перечислены символы, экспортируемые vDSO. .if t \{\ .ft CW \} .TS l l. символ version _ __kernel_sigtramp LINUX_2.5 __kernel_syscall_via_break LINUX_2.5 __kernel_syscall_via_epc LINUX_2.5 .TE .if t \{\ .in ^".ft P$ \} .PP Перенос на Itanium, в некоторой степени, неоднозначный. Кроме vDSO, показанной выше, также есть «легковесные системные вызовы» (также называемые как «быстрые syscall» или «fsys»). Вы можете вызвать их через вспомогательную функцию vDSO \fI__kernel_syscall_via_epc\fP. Перечисленные здесь системные вызовы имеют ту же семантику, как если бы вызывались напрямую через \fBsyscall\fP(2), поэтому обратитесь к соответствующей документации по каждому из них. В таблице ниже перечислены функции, доступные через этот механизм. .if t \{\ .ft CW \} .TS l. функция _ clock_gettime getcpu getpid getppid gettimeofday set_tid_address .TE .if t \{\ .in ^".ft P$ \} .SS "Функции на parisc (hppa)" .\" See linux/arch/parisc/kernel/syscall.S .\" See linux/Documentation/parisc/registers.rst Перенос parisc содержит страницу кода со вспомогательными функциями, называемую шлюзовой (gateway) страницей. Вместо того, чтобы использовать обычный вспомогательный вектор ELF, передаётся адрес страницы для обработки через регистр SR2. Права на страницу таковы, что простое выполнение этих адресов автоматически выполняется с правами ядра и не в пространстве пользователя. Подобный способ применяется в HP\-UX. .PP Так как это просто страница с кодом, информация ELF отсутствует и поиск функций невозможен и неизвестны их версии. Просто вызывайте функцию по соответствующему смещению через инструкцию ветвления, например: .PP .in +4n .EX ble <смещение>(%sr2, %r0) .EE .in .if t \{\ .ft CW \} .TS l l. offset функция _ 00b0 lws_entry (операции CAS) 00e0 set_thread_pointer (используется в glibc) 0100 linux_gateway_entry (syscall) .TE .if t \{\ .in ^".ft P$ \} .SS "Функции на ppc/32" .\" See linux/arch/powerpc/kernel/vdso32/vdso32.lds.S В таблице ниже перечислены символы, экспортируемые vDSO. Функции, помеченные \fI*\fP, доступны только в ядре PowerPC64 (64\-бита). .if t \{\ .ft CW \} .TS l l. символ version _ __kernel_clock_getres LINUX_2.6.15 __kernel_clock_gettime LINUX_2.6.15 __kernel_clock_gettime64 LINUX_5.11 __kernel_datapage_offset LINUX_2.6.15 __kernel_get_syscall_map LINUX_2.6.15 __kernel_get_tbfreq LINUX_2.6.15 __kernel_getcpu \fI*\fP LINUX_2.6.15 __kernel_gettimeofday LINUX_2.6.15 __kernel_sigtramp_rt32 LINUX_2.6.15 __kernel_sigtramp32 LINUX_2.6.15 __kernel_sync_dicache LINUX_2.6.15 __kernel_sync_dicache_p5 LINUX_2.6.15 .TE .if t \{\ .in ^".ft P$ \} .PP .\" commit 654abc69ef2e69712e6d4e8a6cb9292b97a4aa39 Before Linux 5.6, the \fBCLOCK_REALTIME_COARSE\fP and \fBCLOCK_MONOTONIC_COARSE\fP clocks are \fInot\fP supported by the \fI__kernel_clock_getres\fP and \fI__kernel_clock_gettime\fP interfaces; the kernel falls back to the real system call. .SS "Функции на ppc/64" .\" See linux/arch/powerpc/kernel/vdso64/vdso64.lds.S В таблице ниже перечислены символы, экспортируемые vDSO. .if t \{\ .ft CW \} .TS l l. символ version _ __kernel_clock_getres LINUX_2.6.15 __kernel_clock_gettime LINUX_2.6.15 __kernel_datapage_offset LINUX_2.6.15 __kernel_get_syscall_map LINUX_2.6.15 __kernel_get_tbfreq LINUX_2.6.15 __kernel_getcpu LINUX_2.6.15 __kernel_gettimeofday LINUX_2.6.15 __kernel_sigtramp_rt64 LINUX_2.6.15 __kernel_sync_dicache LINUX_2.6.15 __kernel_sync_dicache_p5 LINUX_2.6.15 .TE .if t \{\ .in ^".ft P$ \} .PP .\" commit 5c929885f1bb4b77f85b1769c49405a0e0f154a1 Before Linux 4.16, the \fBCLOCK_REALTIME_COARSE\fP and \fBCLOCK_MONOTONIC_COARSE\fP clocks are \fInot\fP supported by the \fI__kernel_clock_getres\fP and \fI__kernel_clock_gettime\fP interfaces; the kernel falls back to the real system call. .SS "Функции на riscv" .\" See linux/arch/riscv/kernel/vdso/vdso.lds.S В таблице ниже перечислены символы, экспортируемые vDSO. .if t \{\ .ft CW \} .TS l l. символ version _ __vdso_rt_sigreturn LINUX_4.15 __vdso_gettimeofday LINUX_4.15 __vdso_clock_gettime LINUX_4.15 __vdso_clock_getres LINUX_4.15 __vdso_getcpu LINUX_4.15 __vdso_flush_icache LINUX_4.15 .TE .if t \{\ .in ^".ft P$ \} .SS "Функции на s390" .\" See linux/arch/s390/kernel/vdso32/vdso32.lds.S В таблице ниже перечислены символы, экспортируемые vDSO. .if t \{\ .ft CW \} .TS l l. символ version _ __kernel_clock_getres LINUX_2.6.29 __kernel_clock_gettime LINUX_2.6.29 __kernel_gettimeofday LINUX_2.6.29 .TE .if t \{\ .in ^".ft P$ \} .SS "Функции на s390x" .\" See linux/arch/s390/kernel/vdso64/vdso64.lds.S В таблице ниже перечислены символы, экспортируемые vDSO. .if t \{\ .ft CW \} .TS l l. символ version _ __kernel_clock_getres LINUX_2.6.29 __kernel_clock_gettime LINUX_2.6.29 __kernel_gettimeofday LINUX_2.6.29 .TE .if t \{\ .in ^".ft P$ \} .SS "Функции на sh (SuperH)" .\" See linux/arch/sh/kernel/vsyscall/vsyscall.lds.S В таблице ниже перечислены символы, экспортируемые vDSO. .if t \{\ .ft CW \} .TS l l. символ version _ __kernel_rt_sigreturn LINUX_2.6 __kernel_sigreturn LINUX_2.6 __kernel_vsyscall LINUX_2.6 .TE .if t \{\ .in ^".ft P$ \} .SS "Функции на i386" .\" See linux/arch/x86/vdso/vdso32/vdso32.lds.S В таблице ниже перечислены символы, экспортируемые vDSO. .if t \{\ .ft CW \} .TS l l. символ version _ __kernel_sigreturn LINUX_2.5 __kernel_rt_sigreturn LINUX_2.5 __kernel_vsyscall LINUX_2.5 .\" Added in 7a59ed415f5b57469e22e41fc4188d5399e0b194 and updated .\" in 37c975545ec63320789962bf307f000f08fabd48. __vdso_clock_gettime LINUX_2.6 (экспортируется начиная с Linux 3.15) __vdso_gettimeofday LINUX_2.6 (экспортируется начиная с Linux 3.15) __vdso_time LINUX_2.6 (экспортируется начиная с Linux 3.15) .TE .if t \{\ .in ^".ft P$ \} .SS "Функции x86\-64" .\" See linux/arch/x86/vdso/vdso.lds.S В таблице ниже перечислены символы, экспортируемые vDSO. Все эти символы также доступны без префикса «__vdso_», но вы не должны пользоваться этим, применяйте имена, перечисленные ниже. .if t \{\ .ft CW \} .TS l l. символ version _ __vdso_clock_gettime LINUX_2.6 __vdso_getcpu LINUX_2.6 __vdso_gettimeofday LINUX_2.6 __vdso_time LINUX_2.6 .TE .if t \{\ .in ^".ft P$ \} .SS "Функции на x86/x32" .\" See linux/arch/x86/vdso/vdso32.lds.S В таблице ниже перечислены символы, экспортируемые vDSO. .if t \{\ .ft CW \} .TS l l. символ version _ __vdso_clock_gettime LINUX_2.6 __vdso_getcpu LINUX_2.6 __vdso_gettimeofday LINUX_2.6 __vdso_time LINUX_2.6 .TE .if t \{\ .in ^".ft P$ \} .SS История The vDSO was originally just a single function\[em]the vsyscall. In older kernels, you might see that name in a process's memory map rather than "vdso". Over time, people realized that this mechanism was a great way to pass more functionality to user space, so it was reconceived as a vDSO in the current format. .SH "СМ. ТАКЖЕ" \fBsyscalls\fP(2), \fBgetauxval\fP(3), \fBproc\fP(5) .PP Документация, примеры и исходный код в дереве исходного кода Linux: .PP .in +4n .EX Documentation/ABI/stable/vdso Documentation/ia64/fsys.rst Documentation/vDSO/* (includes examples of using the vDSO) .PP find arch/ \-iname \[aq]*vdso*\[aq] \-o \-iname \[aq]*gate*\[aq] .EE .in .PP .SH ПЕРЕВОД Русский перевод этой страницы руководства был сделан Azamat Hackimov , Dmitriy Ovchinnikov , Dmitry Bolkhovskikh , Katrin Kutepova , Yuri Kozlov и Иван Павлов . .PP Этот перевод является бесплатной документацией; прочитайте .UR https://www.gnu.org/licenses/gpl-3.0.html Стандартную общественную лицензию GNU версии 3 .UE или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ. .PP Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на .MT man-pages-ru-talks@lists.sourceforge.net .ME .