Почему номера системных вызовов Linux в x86 и x86_64 отличаются?


35

Я знаю, что интерфейс системных вызовов реализован на низком уровне и, следовательно, зависит от архитектуры / платформы, а не от «общего» кода.

Тем не менее, я не могу ясно увидеть причину, по которой системные вызовы в 32-битных ядрах Linux x86 имеют числа, которые не сохраняются одинаковыми в аналогичной архитектуре Linux 64-битной x86_64? Какова мотивация / причина этого решения?

Мое первое предположение состояло в том, что основной причиной было сохранение 32-разрядных приложений в системе x86_64, чтобы через разумное смещение номера системного вызова система знала, что пространство пользователя является 32-разрядным или 64-разрядным. соответственно. Это, однако, не тот случай. По крайней мере, мне кажется, что read (), являющийся системным вызовом номер 0 в x86_64, не может быть согласован с этой мыслью.

Другое предположение состояло в том, что изменение номеров системных вызовов может иметь безопасность / усиление фона, что я не смог подтвердить сам.

Будучи неосведомленным о проблемах реализации зависящих от архитектуры частей кода, я все еще задаюсь вопросом, как изменить номера системных вызовов , когда кажется, что в этом нет необходимости (поскольку даже 16-разрядный регистр будет хранить значительно больше, чем в настоящее время ~ 346 чисел, чтобы представлять все вызовы), поможет достичь чего угодно, кроме нарушения совместимости (хотя использование системных вызовов через библиотеку libc смягчает ее).


3
Я думаю, что вы задаете неправильный вопрос. Правильный вопрос: почему они должны быть одинаковыми? Ответьте на совместимость. Так что, если x86 и x86_64 несовместимы, то нет никаких сил, чтобы не дать им измениться. Теперь все силы последних 20 лет, которые хотели перемен, будут доминировать (у нас есть шанс изменить их). [Обратите внимание, что это просто мнение, а не основанное на внутреннем сознании разработчиков новой системы.]
— Ctrl-Alt-Delor

Ответы:


34

Что касается обоснования конкретной нумерации, которая не соответствует какой-либо другой архитектуре [кроме «x32», которая на самом деле является просто частью архитектуры x86_64]: в самые первые дни поддержки x86_64 в ядре linux, до того, как появились Из-за серьезных ограничений обратной совместимости все системные вызовы были перенумерованы, чтобы оптимизировать их на уровне использования кеш-линии .

Я не знаю достаточно о разработке ядра, чтобы знать конкретную основу для этих выборов, но, очевидно, есть некоторая логика выбора перенумеровать все с этими конкретными числами, а не просто копировать список из существующей архитектуры и удалять неиспользуемые. Похоже, что порядок может быть основан на том, как часто они называются - например, чтение / запись / открытие / закрытие. Выход и ответвление могут показаться «фундаментальными», но каждый из них вызывается только один раз за процесс.

Также может происходить что-то, что хранит системные вызовы, которые обычно используются вместе, в одной строке кэша (эти значения являются просто целыми числами, но в ядре есть таблица с указателями на функции для каждого, поэтому каждая группа из 8 системных вызовов занимает 64-байтовая строка кэша для этой таблицы)


1
fork may seem "fundamental", but [...] called only once per process.А что? Я понимаю, что вы можете ожидать вызова exit один раз, но вы можете fork()
— кошка

5
@cat, если вы считаете, forkчто он учитывается дочерним процессом (то есть рассматриваете его как вызов создания процесса), а не родительским процессом, тогда предложение Random832 является правильным.
— Икар

4
@cat Хорошо, вы можете вызвать fork () два или три раза, может быть, еще несколько. Но вы можете вызывать read () миллионы или даже миллиарды раз.
— Майкл Хэмптон

1
Да, это то, что я имел в виду. Количество вызовов fork и количество процессов за время жизни системы будет одинаковым, игнорируя такие детали, как init, clone [который может создавать процессы или потоки] и т. Д.
— Random832

15

Посмотрите ответ на вопрос «Почему номера системных вызовов отличаются в amd64 linux?» Переполнение стека.

Подводя итог: ради совместимости список системных вызовов стабилен и может только расти. Когда появилась архитектура x86 64, ABI (передача аргументов, возвращаемое значение) стал другим, поэтому разработчики ядра воспользовались возможностью внести изменения, которые давно ожидались.


Круто, мое предположение было верным.
— ctrl-alt-delor

2
Тот другой ответ, на который вы ссылаетесь, является умозрительным: он говорит, что «парни из Linux, скорее всего, решили ...» (выделение добавлено). Я думаю, что было бы полезно, если бы ваш ответ содержал некоторые признаки того, что он, по-видимому, основан на предположениях, а не на доказательствах. Между прочим, более поздний комментарий, размещенный под связанным ответом, свидетельствует о том, что истинная причина заключается не в общей очистке фрейта (как предполагает этот ответ), а именно в «использовании кешлайна», как объяснено в другом ответе здесь .
— DW

-3

Короче говоря, потому что кто-то думал, что «совершенно N+1несовместимые способы сделать это лучше, чем Nспособы». Для исторических арок номера системных вызовов обычно выбирались так, чтобы они соответствовали некоторому устаревшему проприетарному Unix. Но для x86_64 разработчики ядра могли сами выбирать любую нумерацию. Вместо того, чтобы сделать простой выбор и повторно использовать существующую нумерацию, они решили изобрести новый стандарт. Затем они сделали это снова для aarch64 и множества других. Это часто повторяемая модель в разработке ядра Linux.


3
Изменение не было безвозмездным. Есть веские технические причины. Если бы не требования обратной совместимости, аналогичные изменения были бы применены и к существующим архитектурам.
— Йорг Миттаг,

Разница в нумерации составляет 100% безвозмездно. Там нет никаких технических преимуществ для какой-либо конкретной нумерации.
— Р.

2
Как объясняется в этом другом ответе , системные вызовы сгруппированы таким образом, что системные вызовы, которые обычно используются вместе, совместно используют одну и ту же строку кэширования в таблице системных вызовов. И номера системных вызовов выбираются так, чтобы они были простыми индексами в этой таблице. Теоретически, мы могли бы использовать слой косвенности, чтобы отделить позицию системного вызова в таблице системных вызовов от номера системного вызова, но это, возможно, съело бы часть прироста производительности, которую мы получаем от помещения горячих системных вызовов в одну и ту же кэш-строку.
— Йорг Миттаг

@ JörgWMittag: И это явно преждевременная оптимизация, а не измеримое улучшение. Просто посмотрите, сколько циклов занимает системный вызов и сколько строк кэша они вытесняют. Сохранение в лучшем случае одной строки кэша от упорядочения таблицы не будет иметь значения.
— Р.

2
@R .. "Я выбрал нумерацию в функции информации о профилировании ядра tpcc с помощью популярной СУБД и прямого вывода некоторых сетевых и настольных приложений." конечно звучит так, как будто были измерения. Однако автор не предоставил никаких цифр или адекватно объяснил методологию.
— user45891
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.