Как использовать объект VDSO с помощью собственного языка программирования?

Последние ядра Linux (по крайней мере, на amd64) предоставляют волшебный объектный файл с именем linux-vdso.so.1, который абстрагирует интерфейс системных вызовов от ядра, позволяя ядру выбирать оптимальное соглашение о вызовах. Если вы пишете код на C, glibc автоматически использует этот объект.

Теперь, если я хочу написать программу без использования glibc, как я могу использовать этот объект? Интерфейс, который он предоставляет, задокументирован где-нибудь? Как насчет соглашения о вызовах?


person fuz    schedule 24.03.2013    source источник
comment
Из любопытства, какой ваш язык не использует интерфейс C для системных вызовов? Предоставляете ли вы бесплатную программную реализацию для него?   -  person Basile Starynkevitch    schedule 24.03.2013
comment
@Basile Я пытаюсь написать Forth, чтобы узнать, как работает Forth. Я хочу программировать на ассемблере без каких-либо существующих библиотек, подобно jonesforth. Объект VDSO — это просто хороший и эффективный способ реализации системных вызовов.   -  person fuz    schedule 25.03.2013


Ответы (2)


Это зависит от того, использует ли ваша реализация интерфейс C для низкоуровневых утилит или нет.

Если ваша языковая реализация дает прямой доступ к системным вызовам, минуя оболочку C, вам не нужно использовать VDSO (например, вы можете сгенерировать соответствующую машинную инструкцию SYSENTER для выполнения системного вызова), но вы можете решите использовать VDSO, а затем воспользуйтесь этим. В этом случае вашему языку даже не нужно следовать всем соглашениям ABI, а только соглашениям ядра. (например, вам не нужен ABI, предоставляющий caller-safe calle-safe distinguo для регистров, и вы даже можете избежать использования каких-либо стеков).

Примером языковой реализации, даже не использующей libc.so, является Bones Scheme. Вы можете найти несколько других.

Мое понимание VDSO заключается в том, что это абстракция, предоставляемая ядром, чтобы абстрагироваться от различных небольших различий (связанных с переходами между пользователем и ядром) в реализации системных вызовов между различными семействами процессоров x86. Если вы выбрали конкретную цель процессора, вам не нужен VDSO, и вы всегда можете его избежать.

AFAIU, VDSO — это общий объект ELF, расположенный (на моем Debian/AMD64 с недавно скомпилированным ядром 3.8.3) в сегменте ffffffffff600000-ffffffffff601000; проверьте точно с cat /proc/self/maps где он находится). Так что вам просто нужно понять организацию общих объектов ELF и извлечь из них символы. См. это и который ссылается. VDSO использует соглашения C для вызовов, задокументированные в спецификации x86-64 ABI.

То есть, если вы извлечете из пространства вашего процесса VDSO и запишете его в файл на диске, результатом будет правильно сформированный общий объект ELF

ELF — это хорошо задокументированный формат. Таковы и соглашения ABI x86-64 (которые точно определяют соглашения о вызовах C, и как именно запускается образ процесса. См. также execve(2)) справочная страница и, конечно же, документация по ядру, поэтому я не понимаю, в чем ваша проблема. Я согласен, что понимание ELF требует времени (я делал это 10 лет назад, но моя память заржавела). Прочтите также заголовочный файл <elf.h> на вашем компьютере.

Например; работает (под zsh на 64-битном Debian x86-64)

 % file $(which sash)
 /bin/sash: ELF 64-bit LSB executable, x86-64, version 1 (SYSV),
      statically linked, for GNU/Linux 2.6.26,
      BuildID[sha1]=0x0347fcc08fba2f811f58af99f26111d0f579a9f6, stripped

 % ldd $(which sash)
 not a dynamic executable

  % sash
  Stand-alone shell (version 3.7)
  > ps |grep sash
  21635 pts/3    00:00:00 sash
  > cat /proc/21635/maps
  00400000-004da000 r-xp 00000000 08:01 4985590                            /bin/sash
  006da000-006dc000 rw-p 000da000 08:01 4985590                            /bin/sash
  006dc000-006e1000 rw-p 00000000 00:00 0 
  017e3000-01806000 rw-p 00000000 00:00 0                                  [heap]
  7fe4950e5000-7fe4950e7000 rw-p 00000000 00:00 0 
  7fff3f130000-7fff3f151000 rw-p 00000000 00:00 0                          [stack]
  7fff3f173000-7fff3f175000 r-xp 00000000 00:00 0                          [vdso]
  ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

См. также этот ответ.

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

На самом деле, надежный запуск вашей среды выполнения, вероятно, сложнее, чем проблема с VDSO.

Вы также можете прочитать инструкцию по сборке Linux, которая также объясняет некоторые вещи ( но больше про х86 чем х86-64)

Кстати, код http://musl-libc.org/ (который является альтернативой libc) намного легче читать и понимать (и вы легко узнаете, как они делают динамическую компоновку, pthreads и т.д..)

person Basile Starynkevitch    schedule 24.03.2013
comment
Я пытаюсь реализовать библиотеку времени выполнения для языка программирования, не используя какие-либо части glibc. Мне нужны примитивы для системных вызовов, которые обертывают голые инструкции. Я хотел бы использовать VDSO для скорости, так как он использует самый быстрый доступный метод для выполнения системного вызова. - person fuz; 25.03.2013
comment
Затем сначала спроектируйте и внедрите его, а затем оптимизируйте. VDSO - это оптимизация, и на практике она не очень важна, особенно на новом языке программирования (большинство программ привязаны не к системным вызовам, а к пользовательскому процессору или вводу-выводу), поэтому VDSO не имеет большого значения. Насколько мне известно, статически связанные двоичные файлы (даже на C) не используют VDSO, даже если он остается в их адресном пространстве. - person Basile Starynkevitch; 25.03.2013
comment
Ваш ответ и ваш комментарий не касаются ни одного из моих вопросов. Будет ужасно бесполезно, если я спрошу «Как сделать А», а ответ будет «Сделай А позже». - person fuz; 25.03.2013
comment
VDSO — это волшебная разделяемая библиотека ELF, использующая соглашения C ABI. Единственная проблема заключается в том, чтобы найти там имена, но это, вероятно, стандартные таблицы ELF. Я не понимаю, в чем ваши проблемы, но я считаю, что вы можете избежать использования VDSO, если считаете, что это слишком сложно. - person Basile Starynkevitch; 25.03.2013
comment
Если бы я хотел избежать объекта VDSO, я, вероятно, не задавал этот вопрос. Объект VDSO предназначен для обеспечения самого быстрого соглашения о вызовах ядра для текущего процессора (например, у amd64 есть несколько способов вызова ядра). Я хочу знать, что мне нужно передать компоновщику, чтобы использовать его, какое у него соглашение о вызовах и т. д. - person fuz; 25.03.2013
comment
Как я редактировал в своем ответе, вам необходимо понимать детали формата ELF и соглашений ABI x86-64 (особенно вызов функций C). Все это очень хорошо документировано, но сложно понять. - person Basile Starynkevitch; 25.03.2013
comment
Спасибо за дополнительную информацию. Я понимаю, как работает ELF. Гарантировано ли, что этот объект находится на расстоянии, которое вы мне сказали? Что мне нужно сделать, чтобы мои символы были разрешены для linux-VDSO.so? Как называются символы в этом объекте? Что такое соглашение о вызовах? - person fuz; 25.03.2013
comment
Я отредактировал свой ответ, чтобы ответить. Вам нужно будет прочитать много материала (я читал их 10 лет назад, но забыл подробности). Вы уверены, что это стоит боли? - person Basile Starynkevitch; 25.03.2013
comment
Одним из важных моментов здесь является то, что я действительно хочу понять основные детали работы Linux. Конечно я мазохист! Иначе бы я никогда не задавал этот вопрос. - person fuz; 25.03.2013
comment
Я не понял одного. Вы сказали, что vsdo находится по адресу: 0xffffffffff600000, но /proc/self/maps показывает, что файл elf, расположенный по этому адресу, называется vsyscall. В то время как vsdo находится по адресу 0x7fff3f173000. Какая разница между этими двумя объектами? - person Giuseppe Pes; 17.06.2013
comment
+1 за мусульманскую ссылку. Это определенно намного более очевидно, что они делают. Вы должны objdump glibc понять, что он вообще делает. - person S.S. Anne; 22.03.2019

Я нашел эти файлы в дереве ядра Linux полезными:

Объект vDSO — это виртуальный динамический общий объект, который всегда отображается в адресное пространство процесса amd64 в Linux. Его можно использовать для реализации быстрых системных вызовов. Чтобы получить доступ к функциям внутри объекта vDSO, вам необходимо

  • найти объект
  • извлечь адрес из таблицы символов

И то, и другое можно сделать с помощью CC0 лицензированной эталонной реализации parse_vdso.c.

person fuz    schedule 24.03.2013