Я унаследовал сборочный фрагмент MSVC x86, который вызывает функцию класса C ++, передавая различное количество параметров, от 0 до 16 параметров. Эти параметры гарантированно будут int, float или char *. Аналогично для возвращения, это всегда один из этих трех типов.
Это для общей библиотеки Android NDK, ориентированной на Android API 19 или выше. Я пытаюсь добиться максимальной совместимости в этом отношении.
В настоящее время у меня есть этот код для x86, который я перефразировал:
void * Extension; // Class to call on (of type Extension *)
void * Function; // Class function to invoke on (&Extension::XX)
int ParameterCount; // from 0 through 16
int * Parameters; // Pre-initialised to alloca() array, with parameters already set pre-ASM block
int Result = 0; // Output here
__asm
{
pushad ; Start new register set (do not interfere with already existing registers)
mov ecx, ParameterCount ; Store ParameterCount in ecx
cmp ecx, 0 ; If no parameters, call function immediately
je CallNow
mov edx, Parameters ; Otherwise store Parameters in edx
mov ebx, ecx ; Copy ecx, or ParameterCount, to ebx
shl ebx, 2 ; Multiply parameter count by 2^2 (size of 32-bit variable)
add edx, ebx ; add (ParameterCount * 4) to Parameters, making edx point to Parameters[param count]
sub edx, 4 ; subtract 4 from edx, making it 0-based (ending array index)
PushLoop:
push [edx] ; Push value pointed to by Parameters[edx]
sub edx, 4 ; Decrement next loop`s Parameter index: for (><; ><; edx -= 4)
dec ecx ; Decrement loop index: for (><; ><; ecx--)
cmp ecx, 0 ; If ecx == 0, end loop: for (><; ecx == 0; ><)
jne PushLoop ; Optimisation: "cmp ecx, 0 / jne" can be replaced with "jcxz"
CallNow:
mov ecx, Extension ; Move Extension to ecx
call Function ; Call the function inside Extension
mov Result, eax ; Function`s return is stored in eax; copy it to Result
popad ; End new register set (restore registers that existed before popad)
}
Хотя я понимаю x86, я сейчас портирую его на Android NDK.
Это означает, что armeabi, armeabi-v7a и попытка использовать __asm__ от Clang вместо __asm в Visual Studio. Честно говоря, понятия не имею, с чего начать.
__asm__ volatile("pushad \t\n\
mov %%ecx, %[ParameterCount] \t\n\
cmp %%ecx, $0 \t\n\
je CallNow \t\n\
mov %%edx, %[Parameters] \t\n\
mov %%ebx, %%ecx \t\n\
shl %%ebx, $2 \t\n\
add %%edx, %%ebx \t\n\
sub %%edx, $4 \t\n\
PushLoop: \t\n\
push[%%edx] \t\n\
sub %%edx, $4 \t\n\
dec %%ecx \t\n\
cmp %%ecx, $0 \t\n\
jne PushLoop \t\n\
CallNow: \t\n\
mov %%ecx, %[Extension] \t\n\
call %[Function] \t\n\
mov %[Result], %%eax \t\n\
popad"
// outputs, memory?
: [Result] "=m" (Result)
// inputs, "r" indicates read, [x] indicates the ASM will reference it by %[x]
: [Extension] "r" (Extension), [Parameters] "r" (Parameters), [Function] "r" (Function), [ParameterCount] "r" (ParameterCount));
Я получаю неожиданные токены и регистрирую проблемы повсюду. Я просмотрел несколько статей, но согласно этой статье , вызовы функций различаются для разных устройств - и они различаются в зависимости от количества параметров, что является проблемой.
NDK DLL может вызываться часто, и все коммуникации в конечном итоге проходят через этот ASM. Так что это вещь "сделай или сломай".