Я делаю бинарные инструменты с DynamoRIO использование клиента C в программе C ++ хотя вам, вероятно, не нужно знать о DynamoRIO, чтобы ответить на мой вопрос. В настоящее время я обертываю функцию, которая имеет подпись:
virtual void foo(Klass& s)
И тогда в функции wrap я могу получить аргумент вызова этой функции (Klass& s
) к пустому указателю (void *arg1
). Мне нужно использовать этот аргумент (то есть доступ к полям, вызов методов), однако я не могу привести его к соответствующему указателю как Klass
это класс C ++, и клиент, который я использую, находится в чистом C.
Когда я пытаюсь распечатать содержимое void*
бросив его в size_t
такие как:
printf("%zd\n", (size_t)arg1);
это дает мне 8-значный номер, такой как 25102856
Я думаю, это адрес памяти.
У меня вопрос, как я могу получить доступ к этому объекту в моей программе?
Просьба просить всю необходимую информацию, я открыт для всех идей.
Чтобы заставить это работать — определите обертки стиля C для методов получения и установки, как в этом примере:
Для вашего класса
class Klass {
public:
int getA() const;
void setA(int);
virtua int getB() const;
};
Определите структуры C, которые обертывают этот класс:
typedef int (*GetInt)(void*);
typedef void (*SetInt)(void*,int);
// and similar for other typesstruct KlassCInterface {
void* object;
GetInt getA;
SetInt setA;
GetInt getB;
};
extern "C" int getA(void* obj)
{
return static_cast<Klass*>(klassObj)->getA();
}
...
KlassCInterface* getCInterface(Klass* obj)
{
// malloc just in case your client want to use free()
KlassCInterface* retVal = (KlassCInterface*)malloc(sizeof(KlassCInterface));
retVal->object = obj;
retVal->getA = &getA;
...
return retVal;
}
Когда вы передаете данные void *, передайте их как структуру интерфейса C:
Klass* obj = new Klass(...);
KlassCInterface* objC = getCInterface(obj);
registerData(objC);
В вашем коде C — используйте этот интерфейс C:
void doSthWihtKlass(void* data)
{
KlassCInterface* objC = (KlassCInterface*)data;
printf("%d\n", objC->getA(objC->object));
}
Это должно быть трудно сделать. Вы должны будете знать о базовом C ++ ABI. G ++ реализует этот.
Обычно класс C ++ реализуется во многом аналогично структуре в C. Грубо говоря, объекты базового класса идут первыми в порядке их объявлений. Затем все другие подобъекты класса идут в следующем порядке, в порядке их объявлений. Это правило применяется рекурсивно к каждому вложенному объекту. Полиморфные объекты будут иметь разную компоновку, поскольку необходимо хранить больше информации; в частности, указатели на виртуальные методы или указатель на структуру, содержащую эти указатели, должны храниться где-то рядом с объектом.
Обратите внимание, что ничего из этого не решается в соответствии с ISO 14882. Возникновение этого, безусловно, вызывает неопределенное поведение.
Что касается вызова виртуальных методов, вам придется искать v-таблицу. Еще раз, изучите ABI у вашего компилятора.
Вам нужно больше узнать о семантике указателя (и это то, что, я думаю, имел в виду @Alek).
Прежде всего, вы можете использовать %p
спецификатор формата printf для прямой печати указателей. Это обычно приводит к некоторому полезному значению, такому как место в памяти, на которое указывает указатель.
Вы можете привести указатель к char *
и использовать его для чтения байтов непосредственно из памяти. Или вы можете привести его к unsigned char *
и сделать «шестнадцатеричный дамп», используя %x
, Вы можете привести его к int *
и прочитайте целое число, как представлено вашей реализацией C — например, возможно, 4-байтовое 2 дополняет целое число со знаком с прямым порядком байтов в 8-битных байтах без неиспользуемых битов, например.
((unsigned long *)(((short *) ptr) + 7))[4]
например, пропустит количество байтов, равное размеру 7 шорт плюс 4 длинных без знака, и прочитает длинный без знака из ячейки памяти. Предполагая правильное представление (как ожидает реализация C) unsigned long
был записан в эту точную ячейку памяти, вы получите его значение.
Вы не только должны быть уверены, что именно написано, где в памяти указано ptr
(именно поэтому был упомянут ABI), но и получающаяся в результате программа будет непереносимой и может изменяться / прерываться по желанию.
Вам также могут понадобиться целочисленные типы с точной шириной, как указано в <inttypes.h>
заголовок.