Как получить адрес возврата функции? - PullRequest
0 голосов
/ 05 марта 2019

Я пишу библиотеку Rust, содержащую реализацию обратных вызовов для LLVM SanitizerCoverage .Эти обратные вызовы могут использоваться для отслеживания выполнения инструментированной программы.

Распространенным способом создания трассировки является печать адреса каждого исполняемого базового блока.Однако для этого необходимо получить адрес инструкции call, которая вызвала обратный вызов.Примеры C ++, предоставленные LLVM, полагаются на встроенный компилятор __builtin_return_address(0) для получения этой информации.

extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
  if (!*guard) return;
  void *PC = __builtin_return_address(0);
  printf("guard: %p %x PC %p\n", guard, *guard, PC);
}

Я пытаюсь воспроизвести ту же функцию в Rust, но, по-видимому, нет эквивалента __builtin_return_address.Единственная ссылка, которую я нашел, - это старая версия Rust, но описанная функция больше не доступна.Эта функция выглядит следующим образом:

pub unsafe extern "rust-intrinsic" fn return_address() -> *const u8

Мое хакерское решение заключается в том, чтобы в моем ящике был файл C, содержащий следующую функцию:

void* get_return_address() {
  return __builtin_return_address(1);
}

Если яВызвав его из функции Rust, я могу получить адрес возврата самой функции Rust.Это решение, однако, требует компиляции моего кода Rust с -C force-frame-pointers=yes для его работы, поскольку встроенная функция компилятора C зависит от наличия указателей фреймов.

В заключение, есть более простой способ получитьадрес возврата текущей функции в Rust?

edit: Удаление встроенного return_address обсуждается в этом выпуске GitHub.

edit 2: Дальнейшее тестирование показало, что корзина backtrace способна правильно извлечь адрес возврата текущей функции, что позволяет избежать взлома, который я описал ранее.Кредит идет на этот твит.

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

edit 3: Свойство компилятора __builtin_return_address(0) генерирует вызов к свойству LLVM llvm.returnaddress.Соответствующую документацию можно найти здесь .

1 Ответ

0 голосов
/ 25 мая 2019

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

...