Android 下内联汇编,Android Studio 汇编开发

版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/

内联汇编

Android 内联汇编非常适用于 ARM 架构的性能优化和底层操作,通常用于加密、解密、特定指令优化等领域。

1. 基础语法

内联汇编在 C/C++ 代码中通过 asm 或 asm 关键字进行声明,格式如下
asm (“汇编指令” : 输出操作数 : 输入操作数 : 破坏描述符);

详细说明:

  • 汇编指令:这是我们想要执行的汇编代码,通常是 ARM 或 ARM64 指令。

  • 输出操作数:指定汇编代码的输出结果如何映射到 C++ 变量。

  • 输入操作数:指定传递给汇编代码的输入。

  • 破坏描述符:用于告诉编译器哪些寄存器或内存位置将被汇编代码修改,以避免编译器优化引起的问题。

2. 占位符

占位符用于在汇编指令中插入 C++ 变量,格式为 %0、%1 等,对应输出和输入操作数的顺序。

例如

int x = 10, y = 20, result;
asm("add %0, %1, %2" : "=r"(result) : "r"(x), "r"(y));

上面的代码将 x 和 y 相加并将结果存入 result。

3. 输出操作数和输入操作数

=r 表示输出操作数是一个通用寄存器类型。

r 表示输入操作数是一个寄存器类型。

例如

int a = 5, b = 3, result;
asm("mul %0, %1, %2" : "=r"(result) : "r"(a), "r"(b));

这段代码在 ARM 架构中将 a 和 b 相乘,结果存入 result。

4. 破坏描述符

破坏描述符(clobber)用于告诉编译器哪些寄存器或内存位置将被汇编代码修改,以避免编译器优化引起的问题。

常用的描述符包括:

  • “cc”:表示汇编代码将更改条件代码寄存器。

  • “memory”:表示汇编代码可能更改内存内容。

例如

asm("mov %0, #0\n""cmp %1, %2\n""moveq %0, #1": "=r"(result): "r"(a), "r"(b): "cc");

这里 cc 表示条件标志寄存器会被更改,编译器需要考虑这一点。

5. 使用 volatile

在汇编指令前添加 volatile 关键字,确保编译器不会优化或重新排序该段汇编代码。

例如

asm volatile ("nop"); // 表示这是一个空操作,编译器不会优化掉

6. 指针操作

内联汇编还可以使用指针操作对内存内容进行直接操作。例如

int value = 42;
int* ptr = &value;
asm("ldr %0, [%1]" : "=r"(value) : "r"(ptr) : "memory");

这里 ldr 从 ptr 指向的内存地址加载值到 value 中。

7. 示例:简单加法操作

以下是一个在 Android ARM 架构中使用内联汇编执行加法的示例

int a = 10, b = 20, sum;
asm("add %0, %1, %2" : "=r"(sum) : "r"(a), "r"(b));

这段代码执行 a + b 并将结果存储在 sum 中。

多行汇编可以使用反斜杠 \n 进行换行。例如,计算两个数的平方和

int x = 3, y = 4, result;
asm("mul %0, %1, %1\n"   // result = x * x"mla %0, %2, %2, %0" // result += y * y (multiply-accumulate): "=r"(result): "r"(x), "r"(y)
);

Android Studio 汇编开发

首先创建 Native C++ 工程
image.png

创建 Activity,声明 native 函数,点击按钮调用 native 层用汇编实现的加密/解密方法并打印返回结果。

package com.cyrus.example.assemblyimport android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.cyrus.example.R/*** 内联汇编*/
class AssemblyActivity : AppCompatActivity() {// 加载 native 库init {System.loadLibrary("assembly-lib");}// 通过内联汇编实现的加密函数external fun encryptString(input: String?): String// 通过内联汇编实现的解密函数external fun decryptString(input: String?): Stringoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_assembly) // 更新布局文件名// 原始字符串val input = "Hello, 内联汇编!"// 加密按钮val encryptButton = findViewById<Button>(R.id.button_encrypt)encryptButton.setOnClickListener { view: View? ->// 调用 C++ 方法获取加密后的字符串val encrypted = encryptString(input)// 打印原字符串和加密后的字符串val message = "Original: $input\nEncrypted: $encrypted"Toast.makeText(this@AssemblyActivity, message, Toast.LENGTH_LONG).show()}// 解密按钮val decryptButton = findViewById<Button>(R.id.button_decrypt)decryptButton.setOnClickListener { view: View? ->// 调用 C++ 方法获取加密后的字符串val encrypted = encryptString(input)val decrypted = decryptString(encrypted)// 打印加密字符串和解密后的字符串val message = "Encrypted: $encrypted\nDecrypted: $decrypted"Toast.makeText(this@AssemblyActivity, message, Toast.LENGTH_LONG).show()}}
}

创建 assembly-lib.cpp,编写内联汇编代码

#include <jni.h>
#include <string>
#include <android/log.h>#define LOG_TAG "assembly-lib.cpp"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)extern "C"
JNIEXPORT jstring JNICALL
Java_com_cyrus_example_assembly_AssemblyActivity_encryptString(JNIEnv *env, jobject /* this */,jstring input) {const char *inputStr = env->GetStringUTFChars(input, nullptr);std::string encryptedStr(inputStr);// 获取输入字符串的 Unicode 码点const jchar *inputChars = env->GetStringChars(input, nullptr);jsize length = env->GetStringLength(input);// 创建加密后的字符串jchar *encryptedChars = new jchar[length];for (jsize i = 0; i < length; i++) {jchar c = inputChars[i];// 使用内联汇编对每个 Unicode 字符的值加 3,实现加密asm volatile ("add %0, %1, #3\n"     // 每个字符的 Unicode 值加 3: "=r"(c)              // 输出到 c: "r"(c)               // 输入 c);encryptedChars[i] = c;}// 释放输入字符串的内存env->ReleaseStringChars(input, inputChars);jstring encryptedString = env->NewString(encryptedChars, length);// 释放加密字符串的内存delete[] encryptedChars;return encryptedString;
}extern "C"
JNIEXPORT jstring JNICALL
Java_com_cyrus_example_assembly_AssemblyActivity_decryptString(JNIEnv *env, jobject /* this */,jstring input) {const char *inputStr = env->GetStringUTFChars(input, nullptr);std::string decryptedStr(inputStr);// 获取输入字符串的 Unicode 码点const jchar *inputChars = env->GetStringChars(input, nullptr);jsize length = env->GetStringLength(input);// 创建解密后的字符串jchar *decryptedChars = new jchar[length];for (jsize i = 0; i < length; i++) {jchar c = inputChars[i];// 使用内联汇编对每个 Unicode 字符的值减 3,实现解密asm volatile ("sub %0, %1, #3\n"     // 每个字符的 Unicode 值减 3: "=r"(c)              // 输出到 c: "r"(c)               // 输入 c);decryptedChars[i] = c;}// 释放输入字符串的内存env->ReleaseStringChars(input, inputChars);jstring decryptedString = env->NewString(decryptedChars, length);// 释放解密字符串的内存delete[] decryptedChars;return decryptedString;
}

配置 CMakeLists.txt

cmake_minimum_required(VERSION 3.4.1)find_library( # Sets the name of the path variable.log-lib# Specifies the NDK library that you want CMake to locate.log)add_library( # 设置库的名称assembly-lib# 设置库的类型SHARED# 设置源文件路径assembly-lib.cpp)target_link_libraries( # 将 log 库链接到目标库assembly-lib${log-lib})

运行测试
image.png

兼容不同的 CPU 架构

在 Android 开发中,编写兼容不同架构的内联汇编代码时,可以通过条件编译来处理不同的指令集。

由于 Android 设备可能使用不同的 CPU 架构(如 ARM、ARM64、x86 和 x86_64),使用条件编译和 NDK 的特性,我们可以让代码适配不同的 CPU 架构。

1. 使用条件编译判断架构

通过 #ifdef 和 #if defined(…) 指令,判断当前编译架构并编写相应的内联汇编代码。

extern "C"
JNIEXPORT jint JNICALL
Java_com_cyrus_example_assembly_AssemblyActivity_addNumbers(JNIEnv *env, jobject, jint a,jint b) {int result;#if defined(__aarch64__)// ARM64 内联汇编版本asm volatile ("add %w[result], %w[val1], %w[val2]\n"  // 执行加法: [result] "=r" (result)               // 输出操作数: [val1] "r" (a), [val2] "r" (b)       // 输入操作数);
#elif defined(__arm__)// ARM 32-bit 内联汇编版本asm volatile ("add %[result], %[val1], %[val2]\n"    // 执行加法: [result] "=r" (result)               // 输出操作数: [val1] "r" (a), [val2] "r" (b)       // 输入操作数);
#elif defined(__i386__)// x86 内联汇编版本asm volatile ("addl %[val1], %[val2]\n""movl %[val2], %[result]\n"           // 使用32位 x86 指令完成加法: [result] "=r" (result): [val1] "r" (a), [val2] "r" (b));
#elif defined(__x86_64__)// x86_64 内联汇编版本asm volatile ("addq %[val1], %[val2]\n""movq %[val2], %[result]\n"           // 使用64位 x86 指令完成加法: [result] "=r" (result): [val1] "r" (a), [val2] "r" (b));
#else// 如果架构不支持,使用 C++ 代码实现result = a + b;
#endifLOGI("Result of addition: %d", result);return result;
}

2. 使用 abiFilters 指定编译目标

使用 abiFilters 来指定不同的 ABI,以便编译每个架构的共享库

// build.gradle
android {defaultConfig {ndk {abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")}}
}

build 出来的 apk 会包含不同 CPU 架构下的 so
image.png

最后,在不同 CPU 架构下的设备下运行测试正常
image.png

源码

https://github.com/CYRUS-STUDIO/AndroidExample

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/470149.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入剖析【C++继承】:单一继承与多重继承的策略与实践,解锁代码复用和多态的编程精髓,迈向高级C++编程之旅

​​​​​​​ &#x1f31f;个人主页&#xff1a;落叶 &#x1f31f;当前专栏: C专栏 目录 继承的概念及定义 继承的概念 继承定义 定义格式 继承基类成员访问⽅式的变化 继承类模板 基类和派⽣类间的转换 继承中的作⽤域 隐藏规则 成员函数的隐藏 考察继承【作⽤…

RHCE的学习(16)(shell脚本编程)

第一章、shell入门基础 1.1 为什么学习和使用Shell编程 对于一个合格的系统管理员来说&#xff0c;学习和掌握Shell编程是非常重要的。通过编程&#xff0c;可以在很大程度上简化日常的维护工作&#xff0c;使得管理员从简单的重复劳动中解脱出来。 Shell程序的特点&#xff…

信号量和线程池

1.信号量 POSIX信号量&#xff0c;用与同步操作&#xff0c;达到无冲突的访问共享资源目的&#xff0c;POSIX信号量可以用于线程间同步 初始化信号量 #include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); sem&#xff1a;指向sem_t类…

docker运行ActiveMQ-Artemis

前言 artemis跟以前的ActiveMQ不是一个产品&#xff0c;原ActiveMQ改为ActiveMQ Classic, 现在的artemis是新开发的&#xff0c;和原来不兼容&#xff0c;全称&#xff1a;ActiveMQ Artemis 本位仅介绍单机简单部署使用&#xff0c;仅用于学习和本地测试使用 官网&#xff1a;…

区块链技术在电子政务中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 区块链技术在电子政务中的应用 区块链技术在电子政务中的应用 区块链技术在电子政务中的应用 引言 区块链技术概述 定义与原理 发…

【AI换装整合包及教程】CatVTON与其他虚拟试衣技术的详细对比

一、概述 虚拟试衣技术近年来发展迅猛&#xff0c;尤其在电商领域的应用备受瞩目。CatVTON作为一种新兴的虚拟试衣技术&#xff0c;凭借其轻量化设计和高效训练策略脱颖而出。本文将从网络结构、训练策略、推理过程及应用场景四个方面详细对比CatVTON与其他主流虚拟试衣技术。…

图论基本术语

图论算法 —— 图论概述-CSDN博客 理论基础 —— 图_依附于顶点v是什么意思-CSDN博客 理论基础 —— 图 —— 图的存储结构_十字链表和链式前向星-CSDN博客 语雀版本 概括&#xff1a;图是计算机中常用的一种存储结构&#xff0c;图论是数学的一个分支&#xff0c;他以图为…

ffmpeg内存模型

文章目录 展示图拷贝packet 重要&#xff01;&#xff01;&#xff01;avpacket.c相关函数av_packet_alloc 简单的赋值 里面的还有没有进行初始化的指针av_packet_ref 展示图 拷贝packet 拷贝packet有两种情况 1&#xff1a; 两个packet的buf引用的是同一个数据缓冲空间&#…

NCC前端调用查询弹框

系统自带的查询模板 弹框 调启使用默认的 查询模板 是在 单据模板的 列表模板中&#xff0c;有个查询区域 &#xff0c;查询区域就是查询模板内容如果在列表页做客开 新增按钮 调启查询模板 无问题&#xff0c;但是目前需求是需要再卡片页面下调启系统标准的调启模板代码 //调…

Python用CEEMDAN-LSTM-VMD金融股价数据预测及SVR、AR、HAR对比可视化

全文链接&#xff1a;https://tecdat.cn/?p38224 分析师&#xff1a;Duqiao Han 股票市场是一个复杂的非线性系统&#xff0c;股价受到许多经济和社会因素的影响。因此&#xff0c;传统的线性或近线性预测模型很难有效、准确地预测股票指数的价格趋势。众所周知&#xff0c;深…

企业如何提高团队管理的能力?

企业如何提高团队管理的能力&#xff1f; 在当前竞争日益激烈的市场环境中&#xff0c;企业的成功不再仅仅依赖于个体的卓越能力&#xff0c;而是越来越多地依赖于团队的整体效能。一个高效、协作、富有创新精神的团队&#xff0c;能够激发员工的潜能&#xff0c;推动企业不断…

场景解决之mybatis当中resultType= map时,因某个字段为null导致返回的map的key不存在怎么处理

1、场景:通过查询数据表将返回结果封装到map当中返回,因某个字段为null,导致map当中key丢失 <select id"queryMyBonus" parameterType"com.cn.entity.student" resultType "map">SELECTb.projectName as "projectName",b.money…

客户案例 | 如何利用Ansys工具提供互联系统(以及系统的系统),从而使“软件定义汽车”成为可能

“我使用Ansys medini进行大量的分析类活动&#xff0c;因此&#xff0c;从危险分析和风险评估开始&#xff0c;我们就使用medini来开展工作。此外&#xff0c;我们也会在产品开发阶段使用该工具……比如当我们试图确定哪些类型的故障&#xff0c;以及哪些类型的条件会导致不必…

Stored procedures in PostgreSQL

select 存储过程&#xff0c;在现了解的情况&#xff0c;还是没有mysql,sqlserver等好写好用。 --postgreSQL 11.0 以下版本 create or replace FUNCTION procInsertSchool (pSchoolId Char(5),pSchoolName VarChar(100),pSchoolTelNo VarChar(8) ) RETURNS void language plp…

搭建监控系统Prometheus + Grafana

公司有个技术分享会&#xff0c;但是业务忙&#xff0c;没时间精心准备&#xff0c;所以就匆匆忙忙准备分享一下搭建&#xff08;捂脸哭&#xff09;。技术含量确实不多&#xff0c;但是分享的知识确实没问题。 以下是搭建过程&#xff1a; 一、讲解 Prometheus Prometheus 最…

字节跳动核心技术:TT推荐系统从0-1落地应用

⭕️以下就是字节跳动TT推荐系统0-1落地应用简单的描述&#xff0c;同时我还整理了其他不同大厂的项目案例拆解以及其他的AI产品项目&#xff0c;都已经脱敏了 ✅在这之前&#x1f236;一位90后产品女生用我分享的项目去面试&#xff0c;上周就已经拿下了一家大厂的offer&…

欧国联的规则,你都了解吗?

昨天威科姆主场2-1击败克劳利&#xff0c;客观来讲&#xff0c;威科姆的确也缺少很重要的球员&#xff0c;因此尽管罚丢了一个点球&#xff0c;但场面优势并不明显。好在有惊无险拿到3分晋级&#xff0c;避开了点球大战。 今天没有比赛&#xff0c;聊聊明天要猜的欧国联相关话…

Mysql 8迁移到达梦DM8遇到的报错

在实战迁移时&#xff0c;遇到两个报错。 一、列[tag]长度超出定义 在mysql中&#xff0c;tag字段的长度是varchar(20)&#xff0c;在迁移到DM8后&#xff0c;这个长度不够用了。怎么解决&#xff1f; 在迁移过程中&#xff0c;“指定对象”时&#xff0c;选择转换。 在“列映…

Ai创作新风标!仅需三步,利用ai工具免费制作抖音爆款的动物融合视频(含完整的步骤)

有位家人想要学习动物融合的视频,群里有人口述分享但是家人还是有点不是很明白。所以本篇就手把手把这个制作教程分享出来。 整体制作流程相对还是比较简单的,难度在于如何写提示词让画面按照预期的方式进行合并,这个就和昨天的烟火秀一样。后面我思考一下如何把这种调整提示词…

常见的噪声模型+图像中噪声模型的估计+常见的滤波方法(C++)

常见空间域噪声模型 1.1 高斯噪声 高斯噪声的概率密度函数表示为&#xff1a; 1.2 瑞利噪声 1.3 伽马噪声 1.4 指数噪声 1.5 均匀分布噪声 1.6 脉冲&#xff08;椒盐&#xff09;噪声 图像中噪声判别 对于上述六种噪声&#xff0c;椒盐噪声与其他噪声图像差别较大&#xf…