Intereting Posts

Инкрементные указатели функций

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

Является ли машинный код сохраненным последовательно в памяти, так что можно «вручную» увеличить указатель до тех пор, пока он не укажет на следующую / предыдущую функцию?

Это то, что делает отладчик? Он позволяет мне «видеть», где счетчик программ указывает на машинный код?

Вывод: можно запрограммировать с указателями функций примитивный отладчик?

Я понял это право, или я ухожу?

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

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

    Фактически, именно так работает компьютер – он имеет специальный регистр, называемый программным счетчиком, который всегда указывает на текущую инструкцию, и увеличивает его на определенную сумму после каждой инструкции (команда GOTO эквивалентна записи значения в счетчик программ) .

    Однако в реальном мире это не так, как работают отладчики – на самом деле, я даже не уверен, возможно ли указать указатель на сегмент кода в памяти на C, кроме указателя функции . Скорее всего, вам нужно будет использовать эту технику, если вам нужно будет имитировать счетчик программ, например, написать эмулятор для другого типа процессора.

    Используя проект стандарта C, который мне удалось отследить (N1124), мы имеем аналогичные правила. В разделе о сложениях (§6.5.6 / 2) говорится, что

    Для добавления оба операнда должны иметь арифметический тип, или один операнд должен быть указателем на тип объекта

    И тип объекта определен в §6.2.5 / 1 как

    Значение значения, хранящегося в объекте или возвращаемого функцией, определяется типом выражения, используемого для доступа к нему. (Идентификатор, объявленный как объект, является самым простым таким выражением, тип указан в объявлении идентификатора.) Типы разделены на типы объектов (типы, которые полностью описывают объекты), типы функций (типы, описывающие функции) и неполные типы (типы, которые описывают объекты, но не содержат информации, необходимой для определения их размеров).

    Поскольку типы функций отличаются от типов объектов, это говорит о том, что арифметика указателя на указателях функций запрещена.

    В C ++ эта операция является незаконной. Определение добавления указателя, приведенное в п. 5.7 / 1, гласит следующее:

    Для добавления оба операнда должны иметь тип арифметики или enums, или один операнд должен быть указателем на полностью определенный тип объекта, а другой должен иметь интегральный или перечисляемый тип.

    Однако в §3.9 / 9 говорится, что

    Тип объекта – это (возможно, cv-квалифицированный) тип, который не является типом функции , а не ссылочным типом, а не типом void.

    В совокупности это означает, что вы не можете увеличивать указатель на функции в C ++.

    Надеюсь это поможет!

    Вы можете (или, по крайней мере, могли ) сделать что-то подобное, но это явно нетривиально. Прежде всего, вы не можете фактически увеличивать или уменьшать указатель на функцию – он указывает на адрес, но математика указателя обычно выполняется с шагом sizeof(pointed to type) – но с функцией, которая не имеет смысла , поэтому вы не можете заниматься математикой.

    Большинство отладчиков работают (в первую очередь), используя отладочную информацию, которая связывает адреса с номерами строк, именами функций, именами переменных и т. Д.

    1. Машинный код может храниться не последовательно. Компилятор чувствует себя свободно, чтобы разделить или объединить некоторые функции (в оптимизации)
    2. Если вы вручную увеличиваете указатель на функцию, вы, вероятно, попадете в середину функции, что неверно.
    3. Уже доступны процедуры отладки: вы можете получить трассировки стека текущей точки выполнения и разрешить имена функций, в которых есть указатели на выполнение в стеке ( man backtrace , man backtrace_symbols ). С помощью addr2line вы можете преобразовать их в номера строк.

    Нет никакой гарантии относительно того, где будут находиться отдельные функции в памяти.

    Сама функция будет непрерывным блоком памяти (поскольку ЦП выполняет инструкции последовательно), но если вы включите оптимизацию кода, она может не похожа на саму функцию (инструкции могут быть сильно переупорядочены). Он может даже взять код очистки из другой функции.

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