Как передать строку в качестве аргумента инструкции вызова во встроенном ассемблере?

По сути, я хотел бы иметь возможность сделать что-то вроде этого:

//assume myFunction is defined and takes one argument that is an int
char * functionName = "myFunction";
int arg = 5;

__asm{
    push a
    call functionName
}

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

Редактировать: мы говорим о сборке x86


person Emil D    schedule 18.02.2010    source источник
comment
Перефразируйте вопрос. Что вы подразумеваете под одиночным int в качестве аргумента char *? Вы упустили важную деталь - какой процессор вы ищете? Вам нужна общая идея или реальный ассемблерный код, похожий на x86?   -  person dirkgently    schedule 18.02.2010
comment
Я не понимаю образец. Вызов не может быть строкой, он должен быть указателем на функцию. Вам нужно будет получить указатель на функцию, чтобы вызвать ее. Одна из возможностей — использовать GetProcAddr в вашей собственной DLL.   -  person Steven Sudit    schedule 18.02.2010
comment
Извините за путаницу, я имею в виду, что функция принимает один аргумент типа int: вызываемая функция не важна, я просто объясняю, почему я запихиваю в стек a:.   -  person Emil D    schedule 18.02.2010


Ответы (3)


Вы не можете, по крайней мере, напрямую.

call принимает адрес в качестве параметра. Несмотря на то, что вы пишете «call functionName», компоновщик заменяет имя функции фактическим адресом функции. Вам нужно сначала сопоставить эту строку с ее адресом. В общем, C и C++ не поддерживают какие-либо метаданные времени выполнения о сопоставлениях имен функций, которые позволили бы это сделать. Если функция экспортируется из DLL, вы можете использовать GetProcAddress, чтобы найти ее адрес.

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

Что-то типа:

std:map<string, PVOID> functionMappings;
functionMappings["MyFunction"] = MyFunction;


// Later


PVOID function = functionMappings["MyFunction"];

__asm
{
    push a;
    call [function]
}

Некоторые примечания:

Я считаю, что стандарт говорит, что указатель функции может быть больше, чем PVOID. Это должно работать на платформах Windows x86/x64.

Вы не сказали, какое соглашение о вызовах вы использовали - этот код предполагает stdcall.

Это очень, очень странная вещь — какую проблему вы пытаетесь решить?

person Michael    schedule 18.02.2010
comment
Думаю, тогда мне нужно использовать GetProcAddress. Извините, если это глупый вопрос, но какой точно тип возвращаемого значения этой функции? например, будет ли работать int a = GetProcAddress( dllHandle, "myFunction" );? - person Emil D; 18.02.2010
comment
Кстати, что в коде предполагает __stdcall ? Это просто тот факт, что вызывающая сторона не извлекает аргументы из стека, или есть что-то еще? - person Emil D; 18.02.2010
comment
__stdcall — это соглашение о вызовах. Если вы пишете сборку, которая выполняет вызовы функций, вам необходимо понимать соглашения о вызовах. В сети доступно множество ресурсов по GetProcAddress и соглашениям о вызовах. В MSDN даже есть пример кода, показывающий, как использовать возвращаемое значение для GetProcAddress. - person Michael; 18.02.2010

Это невозможно, вы пытаетесь выполнить операцию вызова по имени. Ассемблер имеет только вызов по значению, где значение — это адрес. Вам нужно преобразовать имя в адрес и передать адрес ассемблеру, что означает, что вам нужна какая-то перекрестная ссылка между именами и адресами. Компилятор может помочь вам здесь, в C и C++ вам нужно искать указатели на функции, чтобы увидеть необходимый синтаксис для получения адреса функции, который затем может быть передан ассемблеру.

Упреждающий: Да, иногда компилятор может встраивать символы в исполняемый файл, который затем можно искать, но этот метод полон проблем. Формат данных может меняться между версиями компилятора, информация может быть удалена компоновщиком и так далее.

person Skizz    schedule 18.02.2010

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

Или вы можете использовать указатели функций, определенные во время компиляции, для хранения адресов интересующих вас функций (хотя вам все равно понадобится какой-то способ перевести вашу строку в указатель функции, предположительно, с помощью поиска таблицы сравнения строк). Если это то, что вам интересно, я бы предложил написать эквивалент C, а затем посмотреть на ассемблерный код, который выводит компилятор, чтобы увидеть, как он обрабатывает указатели функций.

person Andrew O'Reilly    schedule 18.02.2010