Я пишу программу, которая требует одну функцию на ассемблере. Было бы очень полезно инкапсулировать функцию сборки в класс C++, чтобы ее собственные данные были изолированы, и я мог создать несколько экземпляров.
Если я создаю класс и вызываю внешнюю функцию из метода C++, функция является реентерабельной, даже если у нее есть собственный стек и локальные «переменные» в кадре стека.
Есть ли какой-нибудь способ сделать функцию сборки методом C++, возможно, используя изменение имени, чтобы функция была реализована в сборке, но прототип был объявлен внутри класса C++?
Если это невозможно, есть ли способ создать несколько экземпляров (динамически) функции сборки, хотя она не является частью класса? Что-то вроде клонирования функции в памяти и просто ее вызова, очевидно, с использованием перемещаемого кода (при необходимости добавляя дельта-смещение для переменных и данных)...
Почему это требуется одна функция в сборке? Это кажется довольно маловероятным.
Вероятно, проще написать класс в C++ и добавить встроенную сборку в функцию-член, которая в этом нуждается.





Да, ты можешь. Либо определите его как встроенную оболочку, которая передает все аргументы (включая неявный указатель this) внешней функции, либо разберитесь с изменением имени, чтобы определить правильный символ для точки входа функции в ассемблере.
Пример способа обертки:
extern "C" int asm_function(myclass *p, int a, double b);
class myclass {
int q, r, member_array[4];
int my_method(int a, double b) { return asm_function(this, a, b); }
};
Автономное определение my_method для x86-64 будет просто jmp asm_function, хвостовым вызовом, потому что аргументы идентичны. Итак, после встраивания у вас будет call asm_function вместо call _Zmyclass_mymethodZd или что-то в этом роде. (это я выдумал).
В GNU C/C++ также есть asm ключевое слово, чтобы установить имя символа asm для функции, вместо того, чтобы обычные правила изменения имен генерировали его из имени класса и функции-члена, а также типов аргументов. (Или с внешней буквой «C», обычно просто символом подчеркивания в начале или нет, в зависимости от платформы.)
class myclass {
int q, r, member_array[4];
public:
int my_method(int a, double b)
asm("myclass_my_method_int_double"); // symbol name for separate asm
};
Затем в вашем файле .asm (например, синтаксис NASM для соглашения о вызовах x86-64 System V)
global myclass_my_method_int_double
myclass_my_method_int_double:
;; inputs: myclass *this in RDI, int a in ESI, double b in XMM0
cvtsd2si eax, xmm0
add eax, [rdi+4] ;; this->r
imul eax, esi
ret
(Вы можете выбрать любое имя для своей ассемблерной функции; это не имеют для кодирования аргументов. Но это позволит вам перегрузить ее без конфликтующих имен символов.)
Пример на Годболте тестового вызывающего объекта, вызывающего способ asm(""):
void foo(myclass *p){
p->my_method(1, 1.0);
}
компилируется в
foo(myclass*):
movsd xmm0, qword ptr [rip + .LCPI0_0] # xmm0 = mem[0],zero
mov esi, 1
jmp myclass_my_method_int_double # TAILCALL
Обратите внимание, что звонящий издал jmp myclass_my_method_int_double, используя ваше имя, а не искаженное имя.
I am writing a program that requires one function in assembly.
Тогда по определению ваша программа становится намного меньше портативный. И зависит от соглашения о вызовах и АБИ вашей реализации C++ и вашей операционной системы.
Тогда было бы разумно использовать некоторые специфические функции компилятора (которых нет в переносимом стандарте С++ 11, например, в n3337).
Тогда я рекомендую воспользоваться преимуществами расширенной сборки ССАГПЗ. Прочтите главу о используя язык ассемблера с C (она также и, разумеется, применима к C++).
Непосредственно встраивая некоторые расширенные asm внутрь функции-члена C++, вы избегаете проблем с вызов какой-то функции. Вероятно, ваш ассемблерный код действительно короткий и выполняется быстро. Так что лучше встраивать его в функции C или C++, избегая затрат на пролог и эпилог вызова функции.
NB: В 2019 году нет экономического смысла тратить силы на написание большого кода на ассемблере: большинство оптимизирующих компиляторов выдают лучший ассемблерный код, чем может разумный программист (за разумное время). Таким образом, у вас есть стимул использовать фрагменты ассемблерного кода маленький в более крупных функциях C++ или C.
Вы, кажется, разбрасываете много слов, но не имеете смысла. Какой конкретный вариант использования не охватывает бесплатная функция?