Все немного сложнее.Вы должны использовать расширенную сборку GCC с ограничениями.Кроме того, использование temp
для сохранения указателя стека является плохой идеей, поскольку адреса локальных переменных зависят от значения указателя стека.Лучше создать стандартный кадр стека.
Также вы забыли вычесть 1 из указателя.В качестве бонуса, в GCC нет необходимости во временной переменной для последнего указателя в массиве.
Что-то вроде:
double evaluationHelper(double* arguments, unsigned numDoubles, double(*mFunction)())
{
double res;
asm(
/* set up the frame pointer */
"push ebp" "\n"
"mov ebp, esp" "\n"
"label_loop:" "\n"
"sub esp, 8" "\n"
"fld qword ptr [%2]" "\n"
"fstp qword ptr [esp]" "\n"
"sub %1, 1" "\n"
"sub %2, 8" "\n"
"test %1, %1" "\n"
"jnz label_loop" "\n"
"call %3" "\n"
"fstp qword ptr [%0]" "\n"
"mov esp, ebp" "\n"
"pop ebp" "\n"
: /* no output */
:"b"(&res), "a"(numDoubles), "c"(arguments + (numDoubles - 1)), "d"(mFunction) /* input */
:"cc" /* clobber */);
return res;
}
Переменная res
не может бытьиспользуется в качестве вывода, потому что инструкция fstp требует указатель, который является входом.Вы можете использовать ограничение m
, если вы не делали смешных вещей со стеком (см. Мое исправление ниже).
ДРУГОЕ ИСПРАВЛЕНИЕ : И вы можете использовать ограничение r
если вам не нужно было перечислять EAX, ECX и EDX в закрытом списке, потому что они не сохраняются посредством вызовов функций (и вы вызываете функцию).Но вы не можете перечислить засоренный регистр, который используется в качестве ввода / вывода.
Обратите внимание, что &res
использует ограничение "b", что является , сохраненным при вызове функции, и поэтомуfstp
будет работать как положено.
Наконец, только «cc» указан в списке «засечек», потому что вы изменяете регистр флагов (с test
) и с вызовом функции.
Запустив gcc -masm=intel -save-temps
мы можем проверить сгенерированную сборку:
; Before the asm
mov eax, DWORD PTR [ebp+12] ; numDoubles
sub eax, 1
sal eax, 3
mov ecx, eax
add ecx, DWORD PTR [ebp+8] ; arguments + 8*(numDoubles - 1)
lea ebx, [ebp-16] ; res
mov eax, DWORD PTR [ebp+12] ; numDoubles
mov edx, DWORD PTR [ebp+16] ; mFunction
; The asm
push ebp
mov ebp, esp
label_loop:
sub esp, 8
fld qword ptr [ecx]
fstp qword ptr [esp]
sub eax, 1
sub ecx, 8
test eax, eax
jnz label_loop
call edx ; clobbers eax, ecx, edx and flags
fstp qword ptr [ebx]
mov esp, ebp
pop ebp
; After the asm
fld QWORD PTR [ebp-16] ; return res
Это мне кажется наиболее правильным.
ИСПРАВЛЕНИЕ : Не совсем.Указатель на функцию и переменная res
должны храниться в регистрах, потому что вы создаете стековый фрейм, о котором компилятор ничего не знает, и поэтому он не может вычислить адреса этих локальных переменных.Так что мои последние исправления хороши, но бесполезны.
Также указатель на переменную res
должен быть в ECX.
Обращено.