LINUX.ORG.RU

C++ вызов функции класса по адресу


0

0

Есть класс:

class Object {
public:
	bool CheckVar( void );
...
}

В памяти программы есть его экземпляр object, нужно из библиотеки подгруженной к ней через LD_PRELOAD вызвать object->CheckVar().

Вызываю так:

Object* object = GetObjAddrFromMemy();
long CheckVar_addr = GetProgAddrFromMem() + CHECK_VAR_OFFSET;
bool CheckVar_result = false;

asm(
	"movl %1, (%%esp)\n"\
	"call *%2\n"\
	"movb %%al, %0\n"\
	: "=m" (CheckVar_result)\
	: "r" (object), "r" (CheckVar_addr)
	);
	
Хотел бы узнать, можно ли обойтись без асма?

Например так нельзя (не даёт привести тип): 

bool (Object::*CheckVar)() = (bool (Object::*)())(CheckVar_addr);
CheckVar_result = (object->*CheckVar)();
anonymous

Object* object = GetObjAddrFromMemy();
bool (*Object_CheckVar)(Object* o) = (bool (*)(Object* o)(GetProgAddrFromMem() + CHECK_VAR_OFFSET);
bool CheckVar_result = false;

CheckVar_result = Object_CheckVar(object);

имхо ... 

anonymous
()
Ответ на: комментарий от anonymous

Большое спасибо! То что нужно!

anonymous
()
Ответ на: комментарий от anonymous

Одного не пойму. Как g++ понимает, что (Object* o) надо передать в (%esp), а не как параметр к CheckVar? Т.е. что делать если вызываемой функции надо передать ~10 параметров? Где можно об этом почитать?

anonymous
()
Ответ на: комментарий от mv

Спасибо за совет! Больше вопросов нет!

anonymous
()
Ответ на: комментарий от anonymous

в смысле не как параметр ? ... this в случае вызова метода классов просто один из параметров, с точки зрения скомпилированного кода ... скорей всего g++ просто всегда первый параметр передает в регистре ... если будет 10 параметров первые один-два в регистре остальные в стеке ... скорей всего ...

anonymous
()
Ответ на: комментарий от anonymous

Да теперь всё ясно, я вот почитал http://www.delorie.com/djgpp/doc/ug/asm/calling.html

When GCC calls your function, it pushes all its arguments onto the stack, starting with the last one, then issues a call. This means that, on entry to your function, the stack is laid out like this:

          Last argument
          ...
4(%esp)	  First argument
(%esp)    Return address

anonymous
()
Ответ на: комментарий от anonymous

Имей в виду, что для x86-64 это не так. Там первые параметры в регистрах передаются, и лишь только потом, когда регистры кончились, на стек кладутся.

mv ★★★★★
()
Ответ на: комментарий от anonymous

> 4(%esp)	  First argument
> (%esp)    Return address

Ты уже понял, что у тебя в примере movl %1, (%%esp) убило адрес возврата? :)

mv ★★★★★
()

1. проще всего написать враппер

mycheckvar(Object* o) {return o->bool CheckVar();} и вызывать его

2. если прямо хочется производительности, то я *предположу*, что независимо от раскладок по регистрам, две функции: CheckVar и mycheckvar будут вызываться АБСОЛЮТНО одинаково, ибо первая требует this.

Поэтому я опять же предположу, что можно просто привести CheckVar к типу void (*)(Object*) -- я так делал, правда с виртуальными функциями, и у меня все работало.

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

www_linux_org_ru ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.