Соглашение о вызовах для динамически создаваемой функции в (Visual) C ++ - PullRequest
5 голосов
/ 26 ноября 2011

Я использую следующие типы для создания новой функции во время выполнения:

typedef int (*pfunc)(int);

union funcptr {
  pfunc x;
  byte* y;
};

Это позволяет мне писать инструкции в y, а затем вызывать функцию следующим образом:

byte* p = (byte*)VirtualAllocEx(GetCurrentProcess(), 0, 1<<16, MEM_COMMIT, PAGE_EXECUTE_READWRITE );

// Write some instructions to p

funcptr func;
func.y = p;

int ret = func.x(arg1); // Call the generated function

Очень важно знать, как C ++ готовит аргументы (соглашение о вызовах), и поэтому я посмотрел свойства проекта (Visual C ++) и вижу, что он использует __cdecl. Он должен помещать аргументы в стек в соответствии с: http://msdn.microsoft.com/en-us/library/aa271989(v=vs.60).aspx и http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl, но когда я смотрю на сгенерированную сборку, аргумент перемещается в регистр EAX.

Я хочу быть абсолютно уверенным в том, как подготовлены аргументы. Итак, я что-то упустил из-за cdecl или Visual C ++ оптимизирует вызов, и если да, как я могу убедиться, что это не произойдет?

С наилучшими пожеланиями, Лассе Эспехолт

Ответы [ 2 ]

5 голосов
/ 26 ноября 2011

Регистр EAX равен и используется для возвращаемого значения функции . В комментариях вы указываете, что компилируете, используя /Gd, и поэтому функция будет использовать __cdecl. Тем не менее, на мой взгляд, имеет смысл пометить объявление типа вашей функции pfunc явным __cdecl, чтобы не было места для путаницы и несоответствия.

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

2 голосов
/ 26 ноября 2011

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

И если вы хотитедля генерации машинного кода во время выполнения рассмотрите возможность использования GNU lightning , DotGnu's libjit , LLVM .LuaJit's dynasm и т. Д. Вы также можете сгенерировать код C в foo.c, скомпилировать его, разветвив команду gcc -fPIC -shared foo.c -o foo.so, и dlopen("./foo.so", RTLD_GLOBAL) (и Windows имеют эквивалентные возможности)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...