Pull to refresh

Comments 7

Вообще, конечно, это не самое корректное сравнение: jit и динамическая линковка. В первом случае происходит компиляция и постепенная оптимизация (для тех, кто в неё верит) кода, во втором — импорт кода из общего хранилища, где основной смысл — общее. Для полноты картины стоило бы сравнить jit и самомодифицирующийся код, целиком копирующий нужные функции из модулей в своё виртуальное пространство.

С другой стороны — это вполне стандартный сценарий разработки приложений: готовая библиотека против скриптов. Оба метода вполне используются в высоконагруженных системах, например, в играх. И на длинной дистанции jit теоретически может дать несколько долей процентов прироста скорости. Мы, конечно, столько не проживём, сколько нужно будет ждать, но саму теорию отметать нельзя.

А с третьей стороны, чаще всего смотрят не на это, а на простоту разработки и степень защищённости продукта. Кому нужно первое, те даже на обфускации не заморачиваются. А кому нужно второе, делают такие финты ушами, что только диву даёшься, сколько сил и энергии выпущено в свисток «нас ещё не взломали».
Я не поленился, почитал тред по ссылке. Так вот: при компиляции с -fno-plt внезапно разница исчезает. Заодно мануал гласит: Alternatively, the function attribute noplt can be used to avoid calls through the PLT for specific external functions, например.
In position-dependent code, a few targets also convert calls to functions that are marked to not use the PLT to use the GOT instead.
В общем, по-традиции, уровень оптимизации зависит от того, чем мы готовы пожертвовать. Кроме того, как правило, тысячи вызовов функции в теле цикла решаются линчеванием коллеги, который их туда вставил.
Согласен, особенно, по второй части. Но, опять же, мы нарушаем стандартные сценарии использования. Отказываясь от plt или got мы уменьшаем универсальность, так как накладываем более сильные условия на ABI библиотек. С таким подходом можно дойти до статической линковки, которую ни один jit точно не сможет переплюнуть, но которая совершенно не позволяет модифицировать поведение приложения без полной перекомпиляции и перезапуска. (Или через такую любовь, за какую без лишних разговоров выдадут пермабан даже на порнхабе.)

Интересно, конечно, но не совсем жизненно. Как часто вы в своём коде вызываете пустую функцию?)
Я понимаю, что автор хотел показать сравнение скорости именно вызова. Но это вроде не так критично в 201x. Из плюсов — защищённость конечно, но "сломать можно всё"

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


По поводу пустых вызовов — а как вы ещё измерите разницу, когда счёт идёт на доли наносекунд?

А точно ли важны доли наносекунд в ущерб универсальности? В этом случае, лучше оптимизировать код, мне кажется…

Ничего не мешает лениво патчить место вызова: (по аналогии с PLT)


  • заглушка получает адрес димамической функции,
  • берет адрес возврата из стека (адрес после точки вызова заглушки в основной программе),
  • отключает защиту памяти,
  • патчит точку вызова,
  • включает защиту памяти,
  • восстанавливает регистры/стек,
  • и прыгает на целевую динамическую функцию.

При следующем вызове динамической функции из пропатченой точки произойдет прямой вызов.

Sign up to leave a comment.

Articles

Change theme settings