Android C/C++开发嵌入汇编代码

Android C/C++开发中嵌入汇编代码的方法
Views: 16
1 0
Read Time:1 Minute, 11 Second

首先需要明确的一点是,为什么我们需要在C/C++中嵌入汇编代码,这通常是出于三个目的:性能优化、特定指令需求以及对资源的精细化管理。

这是因为汇编语言可以实现对CPU寄存器的直接操作,以及对内存的精确控制,无需从C/C++代码进行转译,能够提升我们的软件运行效率从而实现性能优化,同时某些CPU特有的指令集在C/C++中没有相关的支持,此时也只有通过汇编来实现相关操作。

在Android系统C/C++开发中嵌入汇编代码,通常采用两种方式:内嵌汇编、外部汇编文件。

内嵌汇编(Inline Assembly):这是最直接的方式,在C代码中嵌入汇编代码片段。语法和具体实现依赖于编译器,通常使用特定的关键字或者语法来标识汇编代码。例如,在GCC和Clang编译器中,可以使用asm关键字来标识内嵌汇编代码。如下所示:

// frameworks/av/media/libaudioprocessing/AudioResamplerSinc.cpp
static inline
int32_t mulAdd(int16_t in, int32_t v, int32_t a)
{
#if USE_INLINE_ASSEMBLY
    int32_t out;
    asm( "smlawb %[out], %[v], %[in], %[a] \n"
         : [out]"=r"(out)
         : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
         : );
    return out;
#else
    return a + int32_t((int64_t(v) * in) >> 16);
#endif
}

除了内嵌汇编,还经常用到外部汇编文件文件来进行嵌入。

外部汇编文件(External Assembly Files):将汇编代码单独存放在一个汇编文件中,然后通过C语言的函数调用来调用这些汇编函数。在汇编文件中,需要按照特定的调用约定来定义函数接口以及参数传递方式。C语言代码通过函数调用来触发对应的汇编代码执行。如下所示:

void SwapContext(char **src_sp, char **dest_sp)
{
    ctx_swap(reinterpret_cast<void **>(src_sp), reinterpret_cast<void **>(dest_sp));
}

其中ctx_swap的调用对应汇编源文件中提供的symbol,一般我们会将汇编文件以.S或者.asm结尾,如下所示:

//swap_aarch64.S   source code
.globl ctx_swap
.type  ctx_swap, @function
ctx_swap:
      push %edi
      push %ebx
      push %ebp
      movl %esp, (%edi)

      movl (%esi), %esp
      pop %ebp
      pop %ebx
      pop %edi

在编译链接完成后就能实现在C代码中调用汇编代码。

在Android系统中我们一般推荐使用外部汇编文件的方式进行嵌入,这样能够具有更好的灵活性,因为汇编代码与CPU架构是强相关的。为了多平台的适配,我们可以在Android.bp中区分不同的CPU架构从而引入不同的外部汇编文件,如下所示:

//Android.bp
cc_library_shared {
srcs:[
  example.cc
],
…..
arch:{
        arm64:{
            srcs:["croutine/detail/swap_aarch64.S"],
        },
        arm:{
            srcs:["croutine/detail/swap_aarch64.S"],
        },
        x86:{
            srcs:["croutine/detail/swap_x86_32.S"],
        },
        x86_64:{
            srcs:["croutine/detail/swap_x86_64.S"],
        }
},
…..
}

这里我们通过arch字段分别区分了arm64、arm、x86以及x86_64不同的架构,进而导入不同的汇编文件。

如果我们不考虑平台兼容性,可以使用asm内嵌汇编,不过这里有一个小细节是我们的程序默认会编译32+64位的,此时asm内嵌汇编可能会报错,一般我们需要在Android.bp中通过compile_multilib字段进行配置,编译指定类型的产物,如下所示:

cc_library_shared {
   compile_multilib: "64",
}

这里我们通过compile_multilib字段指定仅编译64位程序,从而确保asm嵌入汇编可以正常编译通过。

Happy
Happy
100 %
Sad
Sad
0 %
Excited
Excited
0 %
Sleepy
Sleepy
0 %
Angry
Angry
0 %
Surprise
Surprise
0 %
FranzKafka95
FranzKafka95

极客,文学爱好者。如果你也喜欢我,那你大可不必害羞。

文章: 85

留下评论

您的电子邮箱地址不会被公开。 必填项已用*标注

zh_CNCN