Вызов метода с использованием встроенного ассемблера в gcc

Итак, как я уже сказал, я пытаюсь вызвать метод, используя встроенный asm, используя gcc. Итак, я искал, как работает x86 и каковы соглашения о вызовах, затем я попробовал несколько простых вызовов, которые отлично работали. Затем я попытался встроить v8, что было моей первоначальной целью, но это не сработало так хорошо …
Вот мой код:

v8::Handle<v8::Value> V8Method::staticInternalMethodCaller(const v8::Arguments& args, int argsize, void* object, void* method)
{
int i = 0;
char* native_args;

// Move the ESP to the end of the array (argsize is the array size in byte)
asm("subl %1, %%esp;""movl %%esp, %0;": "=r"(native_args)
: "r"(argsize));// This for loop only converts V8 type to native type,
// and puts them in the array:

for (; i < args.Length(); ++i)
{
if (args[i]->IsInt32())
{
*(int*)(native_args) = args[i]->Int32Value();

native_args += sizeof(int);
}
else if (args[i]->IsNumber())
{
*(float*)(native_args) = (float)(args[i]->NumberValue());

native_args += sizeof(float);
}
}

// Then call the method:

asm("call *%1;" : : "c"(object), "r"(method));

return v8::Null();
}

И вот сгенерированная сборка:

__ZN3srl8V8Method26staticInternalMethodCallerERKN2v89ArgumentsEiPvS5_:
LFB1178:
.cfi_startproc
.cfi_personality 0,___gxx_personality_v0
.cfi_lsda 0,LLSDA1178
pushl   %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl    %esp, %ebp
.cfi_def_cfa_register 5
pushl   %ebx
subl    $68, %esp
.cfi_offset 3, -12
movl    $0, -12(%ebp)
movl    12(%ebp), %eax
/APP
# 64 "method.cpp" 1
subl %eax, %esp; movl %esp, %ebx; addl $4, %esp
# 0 "" 2
/NO_APP
movl    %ebx, -16(%ebp)
jmp L74
L77:
movl    -12(%ebp), %eax
movl    %eax, (%esp)
movl    8(%ebp), %ecx
LEHB25:
call    __ZNK2v89ArgumentsixEi
LEHE25:
subl    $4, %esp
movl    %eax, -36(%ebp)
leal    -36(%ebp), %eax
movl    %eax, %ecx
call    __ZNK2v86HandleINS_5ValueEEptEv
movl    %eax, %ecx
LEHB26:
call    __ZNK2v85Value7IsInt32Ev
LEHE26:
testb   %al, %al
je  L75
movl    -12(%ebp), %eax
movl    %eax, (%esp)
movl    8(%ebp), %ecx
LEHB27:
call    __ZNK2v89ArgumentsixEi
LEHE27:
subl    $4, %esp
movl    %eax, -32(%ebp)
leal    -32(%ebp), %eax
movl    %eax, %ecx
call    __ZNK2v86HandleINS_5ValueEEptEv
movl    %eax, %ecx
LEHB28:
call    __ZNK2v85Value10Int32ValueEv
LEHE28:
movl    %eax, %edx
movl    -16(%ebp), %eax
movl    %edx, (%eax)
movl    -16(%ebp), %eax
movl    (%eax), %ebx
movl    $LC4, 4(%esp)
movl    $__ZSt4cout, (%esp)
LEHB29:
call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl    -16(%ebp), %edx
movl    %edx, (%esp)
movl    %eax, %ecx
call    __ZNSolsEPKv
subl    $4, %esp
movl    $LC5, 4(%esp)
movl    %eax, (%esp)
call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl    %ebx, (%esp)
movl    %eax, %ecx
call    __ZNSolsEi
subl    $4, %esp
movl    $__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, (%esp)
movl    %eax, %ecx
call    __ZNSolsEPFRSoS_E
subl    $4, %esp
addl    $4, -16(%ebp)
jmp L76
L75:
movl    -12(%ebp), %eax
movl    %eax, (%esp)
movl    8(%ebp), %ecx
call    __ZNK2v89ArgumentsixEi
LEHE29:
subl    $4, %esp
movl    %eax, -28(%ebp)
leal    -28(%ebp), %eax
movl    %eax, %ecx
call    __ZNK2v86HandleINS_5ValueEEptEv
movl    %eax, %ecx
LEHB30:
call    __ZNK2v85Value8IsNumberEv
LEHE30:
testb   %al, %al
je  L76
movl    -12(%ebp), %eax
movl    %eax, (%esp)
movl    8(%ebp), %ecx
LEHB31:
call    __ZNK2v89ArgumentsixEi
LEHE31:
subl    $4, %esp
movl    %eax, -24(%ebp)
leal    -24(%ebp), %eax
movl    %eax, %ecx
call    __ZNK2v86HandleINS_5ValueEEptEv
movl    %eax, %ecx
LEHB32:
call    __ZNK2v85Value11NumberValueEv
LEHE32:
fstps   -44(%ebp)
flds    -44(%ebp)
movl    -16(%ebp), %eax
fstps   (%eax)
movl    -16(%ebp), %eax
movl    (%eax), %ebx
movl    $LC4, 4(%esp)
movl    $__ZSt4cout, (%esp)
LEHB33:
call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl    -16(%ebp), %edx
movl    %edx, (%esp)
movl    %eax, %ecx
call    __ZNSolsEPKv
subl    $4, %esp
movl    $LC5, 4(%esp)
movl    %eax, (%esp)
call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl    %ebx, (%esp)
movl    %eax, %ecx
call    __ZNSolsEf
subl    $4, %esp
movl    $__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, (%esp)
movl    %eax, %ecx
call    __ZNSolsEPFRSoS_E
subl    $4, %esp
addl    $4, -16(%ebp)
L76:
incl    -12(%ebp)
L74:
movl    8(%ebp), %ecx
call    __ZNK2v89Arguments6LengthEv
cmpl    -12(%ebp), %eax
setg    %al
testb   %al, %al
jne L77
movl    16(%ebp), %eax
movl    20(%ebp), %edx
movl    %eax, %ecx
/APP
# 69 "method.cpp" 1
call *%edx;
# 0 "" 2
/NO_APP
call    __ZN2v84NullEv
leal    -20(%ebp), %edx
movl    %eax, (%esp)
movl    %edx, %ecx
call    __ZN2v86HandleINS_5ValueEEC1INS_9PrimitiveEEENS0_IT_EE
subl    $4, %esp
movl    -20(%ebp), %eax
jmp L87
L83:
movl    %eax, (%esp)
call    __Unwind_Resume
L84:
movl    %eax, (%esp)
call    __Unwind_Resume
L85:
movl    %eax, (%esp)
call    __Unwind_Resume
L86:
movl    %eax, (%esp)
call    __Unwind_Resume
LEHE33:
L87:
movl    -4(%ebp), %ebx
leave
.cfi_restore 5
.cfi_restore 3
.cfi_def_cfa 4, 4
ret
.cfi_endproc

Итак, этот статический метод является обратным вызовом (я проверяю сигнатуру раньше), который должен вызывать определенный метод, предоставляющий допустимые собственные аргументы C ++. Чтобы немного ускорить работу и избежать копирования аргументов, я пытаюсь загрузить все параметры в локальный массив, а затем изменить ESP, чтобы сделать этот массив аргументом.

Вызов метода работает хорошо, но я не получаю правильных аргументов … Я провел много исследований о вызове функции, соглашении о вызовах и большом количестве тестов (которые все были успешными), но я не понимаю, что такое происходит … Есть что-то, что я пропустил?

По сути, вызываемый объект должен получить свои аргументы наверху esp, в моем случае — массива … (я уточняю, что массив допустим)

Я использую GCC.

0

Решение

Есть много проблем с тем, что вы пытаетесь.

  • Вы не можете изменить %esp используя встроенную сборку, потому что компилятор
    вероятно использует %esp ссылаться на его локальные переменные и аргументы. это может работать, если компилятор использует %ebp вместо этого, но нет никакой гарантии.

  • Вы никогда не отменяете %esp модификация до возвращения.

  • В вашей встроенной сборке вы должны заявить, что %esp побочный эффект.

  • Вам, вероятно, нужно пройти object в качестве молчаливого первого аргумента. method такое метод экземпляра, а не статический метод?

  • все это зависит от того, какое соглашение о вызовах вы используете: cdecl, stdcall, так далее.

2

Другие решения

Я бы порекомендовал не пытаться сделать это самостоятельно, есть много досадных мелких деталей, которые должны быть получены правильно. Я бы предложил вместо этого использовать Библиотека FFCALL, конкретно avcall набор методов, чтобы сделать это.

Я полагаю, что что-то вроде этого будет делать то, что вы хотите:

v8::Handle<v8::Value> V8Method::staticInternalMethodCaller(const v8::Arguments& args, int argsize, void* object, void* method)
{
// Set up the argument list with the function pointer, return type, and
// pointer to value storing the return value (assuming int, change if
// necessary)
int return_value;
av_alist alist;
av_start_int(alist, method, &return_value);

for(int i = args.Length() - 1; i >= 0; i--)
{
// Push the arguments onto the argument list
if (args[i]->IsInt32())
{
av_int(alist, args[i]->Int32Value());
}
else if (args[i]->IsNumber())
{
av_double(alist, (float)(args[i]->NumberValue());
}
}

av_call(alist);  // Call the function

return v8::Null();
}
0