Как 32-битные приложения выполняют системные вызовы в 64-битной Linux? - PullRequest
30 голосов
/ 22 июля 2010

Некоторые (многие? Все?) 64-битные 1 Linux-дистрибутивы позволяют запускать 32-битные приложения, поставляя параллельные коллекции 32-битных и 64-битных библиотек (включая libc). Таким образом, 32-битное приложение может связываться с 32-битными библиотеками и работать под управлением 64-битного ядра.

Я бы хотел знать механизм того, как 32-битные приложения выполняют системные вызовы на 64-битном ядре. Я подозреваю, что ответ находится где-то в libc и / или в исходном коде ядра, но мне потребовалось бы много времени, чтобы погрузиться в исходный код, поскольку я не знаю, где искать.

И еще более важный вопрос, есть ли какие-либо потери производительности? 2 Логически, вызов из 32-разрядного системного вызова приложения должен будет преобразоваться в 64-разрядное внутреннее ядро. среда. Как и где это достигается?

1"32-разрядный" = IA-32 и "64-разрядный" = AMD64
2 В своем ответе сделайте предположение, что оно имеет значение:)

1 Ответ

27 голосов
/ 22 июля 2010

Со стороны пользовательского пространства, механика идентична созданию системного вызова на 32-битном собственном ядре - весь код пользовательского режима, включая 32-битный glibc, работает одинаково.

Со стороны ядра,старые точки входа IA32 из пользовательского пространства (например, int 0x80) настроены для вызова процедуры ассемблера ia32_syscall.(Переход к пространству ядра включает в себя загрузку процессором селектора сегмента кода ядра, что приводит к переходу в 64-битный «длинный» режим).

Затем подпрограмма ia32_syscall перемешивает некоторые аргументы для соответствияСоглашение о вызове системного вызова x86_64:

movl    %edi,%r8d
.if \noebp
.else
movl    %ebp,%r9d
.endif
xchg    %ecx,%esi
movl    %ebx,%edi
movl    %edx,%edx   /* zero extension */

Затем он использует номер системного вызова IA32 для вызова функции через таблицу ia32_sys_call_table.Это, по существу, сопоставляет номера системных вызовов IA32 с собственными реализациями системных вызовов (номера системных вызовов сильно отличаются между IA32 и x86_64).Первая часть этой таблицы выглядит следующим образом:

ia32_sys_call_table:
    .quad sys_restart_syscall
    .quad sys_exit
    .quad stub32_fork
    .quad sys_read
    .quad sys_write

Для большинства системных вызовов реализация x86_64 теперь может вызываться напрямую - как exit().Для других, например fork(), предусмотрена оболочка, которая корректно реализует ожидаемую семантику IA32 (в частности, если требуется расширение знака аргументов с 32-битного до 64-битного).

Как видите,накладные расходы в коде ядра минимальны - несколько тривиальных модификаций для регистрации значений, а для некоторых функций - дополнительный вызов функции.Я не уверен, что загрузка селектора сегмента кода, который вызывает переход из 32-битного режима в 64-битный режим, медленнее для процессора, чем тот, который не выполняет - проверьте руководства по архитектуре процессора для этого.

...