Как правило, исполняемые файлы сохраняют только начальный адрес функции, так как это все, что требуется для вызова функции. Вы должны будете вывести конечный адрес, а не просто искать его.
Вы можете попытаться найти начальный адрес следующей функции, но это не всегда будет работать. Представьте себе следующее:
void func_a() {
// do something
}
static void helper_function() {
// do something else
}
void func_b() {
// ...
helper_function();
// ...
}
Вы можете получить адрес func_a
и func_b
, но helper_function
не показывать вверх, потому что ничего не нужно ссылаться на него. Если вы попытались использовать func_b
в качестве конца func_a
(при условии, что порядок в скомпилированном коде эквивалентен порядку в исходном коде, что не гарантируется), вы попадете случайно, включая код, который вам не нужен включите - и, возможно, не найдете код, который вам нужно найти при встраивании других функций в func_b
.
Итак, как мы находим эту информацию? Ну, если вы думаете об этом - информация есть существует - все пути в пределах func_a
в конечном итоге заканчиваются (в цикле, возврате оператора, хвостовом вызове и т. Д.), Вероятно, до начала helper_function
.
Вам нужно будет разобрать код func_a
и создать карту всех возможных путей кода внутри него. Конечно, вам все равно нужно сделать это, чтобы встроить в него другие функции, поэтому не должно быть слишком сложным, чтобы просто не заботиться о конечном адресе функции.
Последнее примечание: в этом примере у вас возникли бы проблемы с поиском helper_function
, чтобы знать его встроенный, поскольку символ не будет отображаться в kallsyms
. Решение состоит в том, что вы можете отслеживать инструкции call
в отдельных функциях, чтобы определить, какие скрытые функции существуют, о которых вы не знали.
TL; DR: Вы можете найти только конечный адрес, проанализировав скомпилированный код. Вы все равно должны разбирать это, так что просто сделайте это один раз.
Зачем вам нужно знать «конечный адрес» функции? –
Мне нужно это знать, потому что я хочу сделать «функцию inlining» во время выполнения. После этого я могу построить Control Flow Graph, который включает в себя базовые блоки заинтересованной функции и всех ее вызываемых лиц. – user2571676