FreeBSD против Linux: производительность соглашений о вызовах ядра

FreeBSD против Linux: производительность соглашений о вызовах ядра

Отint80h.org, учебник по языку ассемблера FreeBSD

Соглашение [Linux Calling] имеет большой недостаток по сравнению с Unix, по крайней мере, в том, что касается программирования на языке ассемблера: каждый раз, когда вы делаете вызов ядра, вы должны нажать регистры, а затем вытащить их позже. Это делает ваш код громоздким и медленным.

Продолжая, мы говорим о том, что FreeBSD поддерживает как Linux Convention, так и "Unix Convention"

Если вы пишете код специально для FreeBSD, вам всегда следует использовать соглашение Unix: это быстрее, вы можете хранить глобальные переменные в регистрах, вам не нужно маркировать исполняемый файл и вам не придется навязывать установку пакета эмуляции Linux на целевой системе.

Мне кажется странным, что Linux-способ будет громоздким и медленным. Кажется, есть два варианта,

  • Сохраните только те регистры, которые вам необходимо сохранить, а именно:
    • те изменчивые регистры, которые могут быть затерты системным вызовом (насколько мне известно ecx)
    • или регистры, необходимые для отправки соответствующих аргументов ядру для выполнения syscall(которые могут быть eax, ecx, edx, esi, edi, ebp)
  • Сохраните 100% аргументов ядра в стеке.

Похоже, что FreeBSD — этохудшийСценарий кейса конвенции Linux. Что я упускаю? Как конвенция FreeBSD (которую они называют "Unix way") менее громоздкая и быстрая?

решение1

По моему мнению, это действительно сводится к мнению автора.

В соглашениях FreeBSD («Unix») вы помещаете аргументы в стек, указываете номер системного вызова в EAXи вызываете прерывание 0x80 (с дополнительным операндом в стеке, поскольку ожидается вызов из отдельной функции).

В соглашении Linux i386 вы помещаете аргументы в соответствующие регистры и вызываете прерывание 0x80.

Аргумент о громоздкости/медленности, вероятно, исходит из того факта, что в соответствии с конвенцией Linux,звонящийнеобходимо разобраться с использованием регистров. Если системному вызову требуются аргументы в регистрах, которые содержат значения, которые интересуют вызывающего, ему необходимо их сохранить, что приводит к дополнительной работе;см. этот пример из библиотеки C. В этом примере системному вызову нужны значения в EAX, EBX, EDX, EDI и ESI; но вызывающий заботится только о сохранении EBX, EDI и ESI, поэтому он помещает в стек только их. Общий случай:немного сложнее(но это также результат работы со смесью языков C и ассемблера, попытки сгенерировать оптимальный код во всех случаях), однако при написании на языке ассемблера, что и является смыслом сайта, на который вы ссылаетесь, это не будет такой уж большой проблемой.

Мне кажется, что их шесть с половиной: в конвенции FreeBSD вы помещаете данные в стек во всех случаях, в конвенции Linux вы помещаете данные в стек (или куда-то еще) в зависимости от того, что вы делаете вокруг места вызова. Вы можете утверждать, что конвенция Linux позволяет выполнять более быстрый код, поскольку вы можете выполнять все свои вычисления в регистрах... КакРобОднако, как отмечает автор, в Linux регистры все равно в конечном итоге передаются (для создания экземпляра struct pt_regs, который используется для предоставления аргументов функциям C, обрабатывающим системные вызовы), поэтому общая стоимость на стороне Linux выше, чем на стороне FreeBSD.

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

Связанный контент