IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

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

    FranzKafka95发表于 2024-04-11 03:25:48
    love 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
    0 0 %
    Sad
    Sad
    0 0 %
    Excited
    Excited
    0 0 %
    Sleepy
    Sleepy
    0 0 %
    Angry
    Angry
    0 0 %
    Surprise
    Surprise
    0 0 %

    The post Android C/C++开发嵌入汇编 first appeared on FranzKafka Blog.



沪ICP备19023445号-2号
友情链接