Указатель на функцию с GCC, присвоение адреса - PullRequest
6 голосов
/ 01 февраля 2012

Я столкнулся с чем-то, чего я полностью не понимаю.Существует прототип функции:

typedef void ( * TMain ) ( void );

и переменная функции:

TMain myFunc = MyFunc;
...
myFunc ();

Конечно, это работает нормально.Почему бы и нет.

Из MAP-файла я знаю, что «MyFunc» находится по адресу 0x20100.А теперь самое смешное.После назначения "myFunc = MyFunc;"переменная "myFunc" не содержит значение 0x20100, а скорее 0x20101!

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

myFunc = ( TMain ) myTable [ 5 ];    // that would be 0x20100
myFunc ();                           // which produces a proper crash

Однако, если я сделаю

myFunc = ( TMain ) ( ( Int8 * ) myTable [ 5 ] + 1 );  
myFunc ();

, тогда это сработает.

Что здесь происходит?Всегда ли мне нужно добавлять смещение в 1 или это более или менее случайно?Или есть лучший (и рабочий) способ выполнить задачу?

Большое спасибо за любую подсказку.Walter

Ответы [ 2 ]

4 голосов
/ 01 февраля 2012

Полагаю, вы нацелены на ARM и создали свою программу в режиме Thumb? (Большой палец по умолчанию используется в ARM Ubuntu или Linaro.)

Нижний бит адреса функции сообщает процессору, в каком наборе команд она должна интерпретировать функцию. 0 режим ARM. 1 - режим большого пальца. Таким образом, все указатели функций режима Thumb будут нечетными.

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

3 голосов
/ 01 февраля 2012

Некоторые архитектуры ЦП резервируют первые байты функции для определенных целей. У VAXen там есть маска регистра сохранения. CDC Cyber ​​помещает туда обратный адрес. Некоторые используют некоторые биты «адреса» для обозначения косвенности адресов (случайно, я не могу вспомнить, какие именно, но они с 1970-х годов).

Если вы действительно не знаете, что делаете, вы не должны писать код, который выполняет такую ​​арифметику указателей. Присвойте переменной имя функции и покончите с этим: она гарантированно будет работать в каждой C реализации.

...