Невозможно выполнить прямой и безусловный переход к адресу со смещением более 2 ГБ на любом x86 (32 или 64-разрядном).
Когда я некоторое время назад писал обходную библиотеку, наилучшие варианты, которые я мог придумать для перенаправления потока программы (для x86-64), включали в себя резервное копирование пролога целевой функции на M
байтов и перезапись целиПролог функции с двумя инструкциями.
Я использую регистр % r11 вместо аккумулятора.Согласно AMD64 ABI Draft 0.99.5 , % r11 - это временный регистр, который не сохраняется при вызовах функций.
Первая инструкция, movq $addr, %r11
,делает именно так, как выглядит: загружает указанный адрес в регистр.Вторая инструкция, jmp *%r11
, вызывает безусловный косвенный переход к адресу, хранящемуся в % r11 .
В конце резервных инструкций должен быть добавлен еще один безусловный косвенный переход к исходной функции цели - к адресу сразу после перезаписанных инструкций.Затем, когда вы захотите вызвать оригинал, вы можете вызвать адрес пролога резервной функции, и поток программы продолжится как обычно.
Помните, что число байтов для резервного копирования, M
, должно бытьсумма размера инструкций сохранения / перехода и остатка перезаписанной инструкции.Вы не хотите оставлять какие-либо частичные инструкции после выполнения этого вуду.