ARM GCC内联汇编

通用的内嵌汇编模板

__asm volatile (
code
:output operand list
:input operand list
:clobber list
);

Example

C内联汇编:
// __attribute__((naked))
__attribute__((noinline))
uint8_t asm_test(uint8_t a, uint8_t b)
{
uint8_t c; __asm volatile (
"adds %[res], %[src0], %[src1]\n\t"
:[res] "=r" (c)
:[src0] "r" (a), [src1] "r" (b)
:
); return c;
} 反汇编代码:
0040a350 <asm_test>:
40a350: 1840 adds r0, r0, r1
40a352: b2c0 uxtb r0, r0
40a354: 4770 bx lr
  • 使用__attribute__((naked)可以使函数开头和结尾没有保存和恢复的指令(由编译器自动添加),使用__attribute__((noinline))可以使函数不被优化为嵌入某个函数的汇编指令,而是保持一个函数的形式。
  • 使用operand list与C函数的变量和入参进行交互,格式为[alias] "修饰符" (C variable),使用[]和()绑定变量的语法很像超链接,比如[browser](https://google.com)。
  • operand list中的各项以逗号,分隔
  • 对于早期gcc,不支持使用alias标识变量,而是使用%0,%1...这种根据变量出现的顺序编号,这样的缺陷在于一旦中间加一个操作符,所有的编号都变了
  • 使用volatile可以禁止编译器优化,用于将咱写的汇编指令都编译出来,比如mov r0, r0就不会再被优化

Operand List中修饰符

  • 定义数据类型

  • 输入输出类型
Modifier 含义
= write-only,仅用于output operand list
+ read-write,定义操作数可读可写,仅用于output operand list
& 指示编译器将变量绑定到特定的寄存器,避免与其它寄存器冲突,引发输出值被改变的问题,&只能放在+/=之后

没有=,+修饰的操作符都是read-only的,input operand list都是read-only,所以想对同一变量又读又写,那只能将它放在output operand list并用+修饰。

Example

  1. 立即数搭配宏进行使用,因为内联汇编里的东西没法被预处理
#define A 20

void demo(void)
{
__asm volatile (
"mov r0, %[imm]\n\t"
:
:[imm] "I" (A)
:
);
} /* -------------------对应汇编----------------------- */
0040a364 <demo>:
40a364: f04f 000a mov.w r0, #10
40a368: 4770 bx lr
  1. &的作用
/* ---------------------正确写法带&----------------------- */
uint32_t tab[2];
uint8_t asm_test(uint8_t a, uint8_t b)
{
uint32_t rdv, wdv=1; __asm volatile (
"ldr %[rd], [%[tab]]\n\t"
"str %[wr], [%[tab], #4]\n\t"
:[rd] "=&r" (rdv)
:[tab] "r" (tab),[wr] "r" (wdv)
:
); return 1;
}
/* ---------------------对应汇编----------------------- */
0040a350 <asm_test>:
40a350: 2001 movs r0, #1
40a352: 4b02 ldr r3, [pc, #8] @ (40a35c <asm_test+0xc>)
40a354: 681a ldr r2, [r3, #0]
40a356: 6058 str r0, [r3, #4]
40a358: 4770 bx lr
40a35a: bf00 nop
40a35c: 200023fc .word 0x200023fc /* ---------------------错误写法无&----------------------- */
uint32_t tab[2];
uint8_t asm_test(uint8_t a, uint8_t b)
{
uint32_t rdv, wdv=1; __asm volatile (
"ldr %[rd], [%[tab]]\n\t"
"str %[wr], [%[tab], #4]\n\t"
:[rd] "=r" (rdv)
:[tab] "r" (tab),[wr] "r" (wdv)
:
); return 1;
}
/* ---------------------对应汇编----------------------- */
0040a350 <asm_test>:
40a350: 2001 movs r0, #1
40a352: 4b02 ldr r3, [pc, #8] @ (40a35c <asm_test+0xc>)
40a354: 681b ldr r3, [r3, #0]
40a356: 6058 str r0, [r3, #4]
40a358: 4770 bx lr
40a35a: bf00 nop
40a35c: 200023fc .word 0x200023fc

在错误的写法中,由于不带&,造成rd和tab共用了寄存器r3;加上&后,rd用的r2,没有受到干扰,这些行为和编译器类型及版本有关系,为了避免出错,直接将output operand list都加上&修饰

Clobber List

破坏列表,告诉编译器我在这段汇编代码中改变了什么,比如改变了寄存器,内存等等,这样编译器会在执行这段汇编代码之前保存一下将被改变的数据。

类型 含义
r0, r1... 表示寄存器将被改变,在执行汇编之前将push对应的寄存器,并在执行完汇编之后pop出来
memory 告诉编译器内存将会被改变,在执行汇编之前,将那些还未写入内存的值赶紧写入
cc 告诉编译器condition code状态寄存器将改变

Example

对于memory和cc没构建出好的例子,只有关于寄存器的了。

/*--------------------------C--------------------------*/
uint8_t asm_test(uint8_t a, uint8_t b)
{ __asm volatile (
"mov r0, r0\n\t"
:
:
:"r4"
); return 0;
} /*--------------------------汇编--------------------------*/
0040a350 <asm_test>:
40a350: b510 push {r4, lr}
40a352: 4600 mov r0, r0
40a354: 2000 movs r0, #0
40a356: bd10 pop {r4, pc}

果然编译器对咱指定的"r4"做了保存恢复的操作。

ARM GCC内联汇编的更多相关文章

  1. 推荐一篇讲arm架构gcc内联汇编的文章

    这是来自ethernut网站的一篇文章,原文链接: http://www.ethernut.de/en/documents/arm-inline-asm.html 另外,据说nut/os是个不错的开源 ...

  2. ARM体系下的GCC内联汇编

    转:http://andyhuzhill.github.io/arm/gcc/asm/2012/09/25/gcc-inline-assemly/ 在操作系统级的编程中,有时候,C语言并不能完全的使用 ...

  3. ARM嵌入式开发中的GCC内联汇编__asm__

    在针对ARM体系结构的编程中,一般很难直接使用C语言产生操作协处理器的相关代码,因此使用汇编语言来实现就成为了唯一的选择.但如果完全通过汇编代码实现,又会过于复杂.难以调试.因此,C语言内嵌汇编的方式 ...

  4. 最牛X的GCC 内联汇编

    导读 正如大家知道的,在C语言中插入汇编语言,其是Linux中使用的基本汇编程序语法.本文将讲解 GCC 提供的内联汇编特性的用途和用法.对于阅读这篇文章,这里只有两个前提要求,很明显,就是 x86 ...

  5. GCC内联汇编入门

    原文为GCC-Inline-Assembly-HOWTO,在google上可以找到原文,欢迎指出翻译错误. 中文版说明 由于译者水平有限,故译文出错之处,还请见谅.C语言的关键字不译,一些单词或词组( ...

  6. [翻译] GCC 内联汇编 HOWTO

    目录 GCC 内联汇编 HOWTO 原文链接与说明 1. 简介 1.1 版权许可 1.2 反馈校正 1.3 致谢 2. 概览 3. GCC 汇编语法 4. 基本内联 5. 扩展汇编 5.1 汇编程序模 ...

  7. 汇编语言---GCC内联汇编

    转:http://www.cnblogs.com/taek/archive/2012/02/05/2338838.html GCC支持在C/C++代码中嵌入汇编代码,这些代码被称作是"GCC ...

  8. GCC 内联汇编(GCC内嵌ARM汇编规则)

    转:http://smileleeboo.howbbs.com/posts/list/3127/81062.html 更多文档参见:http://pan.baidu.com/s/1eQ7nd8Q 有时 ...

  9. ARM GCC 内嵌汇编手册

    转自:http://blogold.chinaunix.net/u2/69404/showart_1922655.html ARM GCC 内嵌(inline)汇编手册 关于这篇文档这篇文章是本人为方 ...

  10. gcc 内联汇编简介

    啊 啊 在内联汇编中,标识寄存器的一个%变成了两个% 啊 如图是内联汇编的模板 assembler template 是汇编代码 output operands TODO input operands ...

随机推荐

  1. jmeter使用:解决压测时获取token问题

    在执行压测过程中,首先要执行登录接口来获取token.如果并发数比较大只需要一个用户的登录token,可以使用setup线程组.如果是模拟多个用户登录获取token,需要使用仅一次控制器. 一.添加s ...

  2. Yuque Rich Text(语雀富文本编辑器)

    Yuque Rich Text(语雀富文本编辑器) 由于本人觉得语雀编辑器非常好用,很符合我的使用习惯,然后发现语雀的Chrome浏览器插件实现了编辑器的功能,所以将其富文本的功能拆分位一个单独的Vu ...

  3. 微信支付功能的设计实现与关键实践(UniApp+Java)全代码

    感觉本篇对你有帮助可以关注一下我的微信公众号(深入浅出谈java),会不定期更新知识和面试资料.技巧!!! 温馨提醒:阅读时可打开导航栏 概述 在移动互联网时代,支付功能已成为应用开发的核心能力之一. ...

  4. crypto14解题思路

    crypto14解题思路 ##二进制 001100110011001100100000001101000011010100100000001101010011000000100000001100100 ...

  5. scrcpy - Android手机投屏操作神器

    推荐一个Genymotion推出的投屏工具,跨平台,自定义码率,最重要的是开源,简直良心. Github:https://github.com/Genymobile/scrcpy 下载地址: http ...

  6. 【记录】IDA和Ollydbg查看指令地址及地址对应的指令

    文章目录 在IDA中查看指令地址 在Ollydbg中查看指令地址 在Ollydbg中查看地址对应的指令 在IDA中查看指令地址 在Ollydbg中查看指令地址 ollydbg在对应指令处,右键-查看- ...

  7. Notepad++之"常用技术"

    一.^ 前面 数据准备 二.$ 后面 准备 结果

  8. GPT 1-3 简单介绍

    GPT-1 简介 2018年6月,OpenAI公司发表了论文"Improving Language Understanding by Generative Pretraining" ...

  9. Android Studio 虚拟机一直黑屏原因及解决办法

    虚拟机一直黑屏原因: android模拟器在创建时,一般默认设置为热启动,所以每次关闭模拟器时,会提示保存当前运行界面状态,若选择取消,则下一次启动会以最近一次保存的状态启动显示.如果某次关闭时保存的 ...

  10. 安卓手机上部署nodejs服务器

    一.准备软件 Termux 下载地址:  链接:https://pan.baidu.com/s/1J3OQITWc34uT-Mc8B-moPA?pwd=ug9j        提取码:ug9j KSW ...