Comments 7
С другой стороны — это вполне стандартный сценарий разработки приложений: готовая библиотека против скриптов. Оба метода вполне используются в высоконагруженных системах, например, в играх. И на длинной дистанции jit теоретически может дать несколько долей процентов прироста скорости. Мы, конечно, столько не проживём, сколько нужно будет ждать, но саму теорию отметать нельзя.
А с третьей стороны, чаще всего смотрят не на это, а на простоту разработки и степень защищённости продукта. Кому нужно первое, те даже на обфускации не заморачиваются. А кому нужно второе, делают такие финты ушами, что только диву даёшься, сколько сил и энергии выпущено в свисток «нас ещё не взломали».
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.
В общем, по-традиции, уровень оптимизации зависит от того, чем мы готовы пожертвовать. Кроме того, как правило, тысячи вызовов функции в теле цикла решаются линчеванием коллеги, который их туда вставил.
Интересно, конечно, но не совсем жизненно. Как часто вы в своём коде вызываете пустую функцию?)
Я понимаю, что автор хотел показать сравнение скорости именно вызова. Но это вроде не так критично в 201x. Из плюсов — защищённость конечно, но "сломать можно всё"
Автор хотел показать, как работает динамический компоновщик, и в качестве примера взял вот такую задачу. Воспринимать информацию проще, когда она в каком-то контексте, пусть даже и не настольные жизненном. Вопроса о применимости данной задачи на практике не стояло. Кому-нибудь эта информация пригодится, и не обязательно именно в такой задаче, как у автора.
По поводу пустых вызовов — а как вы ещё измерите разницу, когда счёт идёт на доли наносекунд?
Ничего не мешает лениво патчить место вызова: (по аналогии с PLT)
- заглушка получает адрес димамической функции,
- берет адрес возврата из стека (адрес после точки вызова заглушки в основной программе),
- отключает защиту памяти,
- патчит точку вызова,
- включает защиту памяти,
- восстанавливает регистры/стек,
- и прыгает на целевую динамическую функцию.
При следующем вызове динамической функции из пропатченой точки произойдет прямой вызов.
Когда вызовы функций через внешний интерфейс быстрее нативных вызовов C