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

35

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

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

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

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

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

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

Ответы:

34

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

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

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

Random832
источник
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 (передача аргументов, возвращаемое значение) стал другим, поэтому разработчики ядра воспользовались возможностью внести изменения, которые давно ожидались.

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

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

Р..
источник
3
Изменение не было безвозмездным. Есть веские технические причины. Если бы не требования обратной совместимости, аналогичные изменения были бы применены и к существующим архитектурам.
Йорг Миттаг,
Разница в нумерации составляет 100% безвозмездно. Там нет никаких технических преимуществ для какой-либо конкретной нумерации.
Р.
2
Как объясняется в этом другом ответе , системные вызовы сгруппированы таким образом, что системные вызовы, которые обычно используются вместе, совместно используют одну и ту же строку кэширования в таблице системных вызовов. И номера системных вызовов выбираются так, чтобы они были простыми индексами в этой таблице. Теоретически, мы могли бы использовать слой косвенности, чтобы отделить позицию системного вызова в таблице системных вызовов от номера системного вызова, но это, возможно, съело бы часть прироста производительности, которую мы получаем от помещения горячих системных вызовов в одну и ту же кэш-строку.
Йорг Миттаг
@ JörgWMittag: И это явно преждевременная оптимизация, а не измеримое улучшение. Просто посмотрите, сколько циклов занимает системный вызов и сколько строк кэша они вытесняют. Сохранение в лучшем случае одной строки кэша от упорядочения таблицы не будет иметь значения.
Р.
2
@R .. "Я выбрал нумерацию в функции информации о профилировании ядра tpcc с помощью популярной СУБД и прямого вывода некоторых сетевых и настольных приложений." конечно звучит так, как будто были измерения. Однако автор не предоставил никаких цифр или адекватно объяснил методологию.
user45891