程序集x86转换为ARM函数调用,并向ARM调用不同数量的参数 我继承了一个x86 MSVC汇编件,它调用C++类函数,传递了不同数量的参数,从0到16个参数。这些参数保证为int、float或char*。同样,对于返回,它总是这三种类型之一

程序集x86转换为ARM函数调用,并向ARM调用不同数量的参数 我继承了一个x86 MSVC汇编件,它调用C++类函数,传递了不同数量的参数,从0到16个参数。这些参数保证为int、float或char*。同样,对于返回,它总是这三种类型之一,c++,assembly,arm,inline-assembly,C++,Assembly,Arm,Inline Assembly,这是针对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 thr

这是针对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)
}
我得到了意想不到的代币,到处都是注册问题。我查阅了一些文章,但根据数据,函数调用因设备而异,并且因参数数量而异,这两个都是一个问题


NDK DLL可以经常调用,所有通信最终都会通过该ASM进行。所以这是一个成败攸关的问题。

几年前我解决了一个类似的问题。但我的任务是调用C函数而不是C++方法。但是更新我的代码应该不会有问题

所以,我的代码在这里。请随意更改和使用它

const int ARGC = 32;
const int ARGC_BOUNDS = 4;

HRESULT er = S_OK;

int argv[ARGC] = {0};       
int arg_pointer = 0;
int arg_stack_count = 0;

//////
//
// ..... fill argv with arguments
//
//////

// how many arguments will be placed on stack
if (arg_pointer > 4) {
    arg_stack_count = arg_pointer - 4;
}

// build stack, fill registers and call functions  
// ! volatile ... otherwise compiler "optimize out" our ASM code
__asm__ volatile (
    "mov r4, %[ARGV]\n\t"   // remember pointers (SP will be changed)
    "ldr r5, %[ACT]\n\t"    
    "ldr r0, %[CNT]\n\t"    // arg_stack_count  => R0
    "lsl r0, r0, #2\n\t"    // R0 * 4           => R0
    "mov r6, r0\n\t"        // R4               => R6           
    "mov r1, r0\n"          // arg_stack_count  => R1           
"loop: \n\t"
    "cmp r1, #0\n\t"
    "beq end\n\t"           // R1 == 0      => jump to end
    "sub r1, r1, #4\n\t"    // R1--
    "mov r3, r4\n\t"        // argv_stack   => R3
    "add r3, r3, #16\n\t"
    "ldr r2, [r3, r1]\n\t"  // argv[r1]
    "push {r2}\n\t"         // argv[r1] => push to stack
    "b loop\n"              //          => repeat
"end:\n\t"
    "ldr r0, [r4]\n\t"      // 1st argument
    "ldr r1, [r4, #4]\n\t"  // 2nd argument
    "ldr r2, [r4, #8]\n\t"  // 3rd argument
    "ldr r3, [r4, #12]\n\t" // 4th argument
    "blx r5\n\t"            // call function
    "add sp, sp, r6\n\t"    // fix stack position
    "mov %[ER], r0\n\t"     // store result
: [ER] "=r"(er)
: [ARGV] "r" (argv),
  [ACT] "m"(Action),
  [CNT] "m" (arg_stack_count)
: "r0", "r1", "r2", "r3", "r4", "r5", "r6");

return er;

请记住,从2019年8月开始,谷歌将要求所有Android应用程序均为64位。因此,更明智的做法是重写应用程序,因为一年后您将不得不再次重写它。

此汇编代码的意义是什么?你是想从C调用C++实例方法吗?另外,您可以将所有错误消息添加到您的问题中吗?您知道ARM汇编与x86完全不同,对吗?这不是我们用几句话就能解释的。如果您做不到,请找人为您编写。这些参数保证为int、float或
char*
。这也不简单,;如果使用
-mfloat abi=hard
构建,则ARM32在寄存器中传递前4个整数/指针参数,但不传递
float
(请注意,当第2个参数为FP时,第3个参数如何进入不同的寄存器)。您需要知道arg的类型才能正确使用它(除非Android使用软件浮点?),或者被调用方知道它是一个可变函数吗?在改变通话习惯的ARM上:@Phi:我建议根本不要这样做,这听起来很可怕。当你知道你想要传递哪些ARG时,你确定你不能把函数指针转换成正确的类型,并从C++中发出一个普通的调用吗?@ PyrCordes,它肯定是可怕的。调用与ID对应的函数并传递这些参数。通过反复查询调用NDK的应用程序以获取下一个参数来加载参数。如果有C++模板魔术,我可以用它来存储函数的向量,而不管它们的签名是什么,那么我很乐意使用它代替ASM。你不需要<代码> MOV R4,%[ARGV] ,你可以只使用<代码> %[ARGV] < /C> >你使用的任何地方>代码> R4< /Cord>。因为你已经要求编译器把它放在一个登记簿中。其他输入也可以是寄存器。(使用
register int arg\u stack\u count asm(“r0”)
确保您从
“+r”
约束中获得它,如果您需要的话。
+r
这样您就可以修改它了。)谢谢zdenek,看起来不错。这个ASM用于NDK共享库,所以我认为64位的东西不适用。(另一个开发人员事先警告过我。)半相关:相当于x86-64 Windows调用约定(您不需要知道类型)。@Phi:这根本不处理FP参数。根据this(),硬浮点ABI没有在任何设备上使用,所以也许您可以不使用它。检查编译器在使用浮点参数编译普通代码时所做的操作,并查看它是否在FP寄存器
s0
r0
integer中传递这些参数。@PeterCordes回避了这一点,这里还会出现其他问题吗?如问题中所述,如果返回类型是float或char*,该怎么办?那会破坏东西吗?
const int ARGC = 32;
const int ARGC_BOUNDS = 4;

HRESULT er = S_OK;

int argv[ARGC] = {0};       
int arg_pointer = 0;
int arg_stack_count = 0;

//////
//
// ..... fill argv with arguments
//
//////

// how many arguments will be placed on stack
if (arg_pointer > 4) {
    arg_stack_count = arg_pointer - 4;
}

// build stack, fill registers and call functions  
// ! volatile ... otherwise compiler "optimize out" our ASM code
__asm__ volatile (
    "mov r4, %[ARGV]\n\t"   // remember pointers (SP will be changed)
    "ldr r5, %[ACT]\n\t"    
    "ldr r0, %[CNT]\n\t"    // arg_stack_count  => R0
    "lsl r0, r0, #2\n\t"    // R0 * 4           => R0
    "mov r6, r0\n\t"        // R4               => R6           
    "mov r1, r0\n"          // arg_stack_count  => R1           
"loop: \n\t"
    "cmp r1, #0\n\t"
    "beq end\n\t"           // R1 == 0      => jump to end
    "sub r1, r1, #4\n\t"    // R1--
    "mov r3, r4\n\t"        // argv_stack   => R3
    "add r3, r3, #16\n\t"
    "ldr r2, [r3, r1]\n\t"  // argv[r1]
    "push {r2}\n\t"         // argv[r1] => push to stack
    "b loop\n"              //          => repeat
"end:\n\t"
    "ldr r0, [r4]\n\t"      // 1st argument
    "ldr r1, [r4, #4]\n\t"  // 2nd argument
    "ldr r2, [r4, #8]\n\t"  // 3rd argument
    "ldr r3, [r4, #12]\n\t" // 4th argument
    "blx r5\n\t"            // call function
    "add sp, sp, r6\n\t"    // fix stack position
    "mov %[ER], r0\n\t"     // store result
: [ER] "=r"(er)
: [ARGV] "r" (argv),
  [ACT] "m"(Action),
  [CNT] "m" (arg_stack_count)
: "r0", "r1", "r2", "r3", "r4", "r5", "r6");

return er;