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. 多年后再做Web开发,AI帮大忙

    最近在AI辅助下做一个简单的网站开发,真是感叹AI的强大呀! 虽然多年前我做过Web前端和后端开发,但是那时候的开发没有现在这么容易入门.上手. 之前SSH(Structs2+Spring+Hiber ...

  2. TypeScript+Vue3

    TypeScript Any 类型 和 unknown 顶级类型 1.没有强制限定哪种类型,随时切换类型都可以 我们可以对 any 进行任何操作,不需要检查类型 2.声明变量的时候没有指定任意类型默认 ...

  3. Java--通过jdbc访问mysql数据库(mysql v8.0.11)

    由于mysql的更新,原来的连接数据库方法改变了 参考:http://www.cnblogs.com/rainbow70626/p/9005852.html package demo; import ...

  4. 【经验】Win11的Ubuntu虚拟机启动虚拟化|此平台不支持虚拟化的 Intel VT-x/EPT(方案汇总+自己的解决方案)

    我开虚拟化是为了在虚拟机中运行VirtualBox,如果不开CPU虚拟化,会报错VBoxManage error: VT-x is not available (VERR_VMX_NO_VMX). 文 ...

  5. 信息资源管理文字题之“航空集团从哪些方面改变企业的IT服务”

    一.材料:某航空集团公司拥有一个地域分散.多厂商.多平台.多系统的复杂IT环境.IT系统运行复杂,业务系统故障多,技术人员的被动工作方式难以适应企业IT服务需要. 要求:是运用IT服务管理关联只是为该 ...

  6. C++ lambda匿名函数

    Lambda 表达式完整的格式如下: [捕获列表] (形参列表) mutable 异常列表-> 返回类型 { 函数体 } 各项的含义: 捕获列表:捕获外部变量,捕获的变量可以在函数体中使用,可以 ...

  7. 航空货运系统总结性Blog

    前言 本次题目集以航空运送货物为背景,设计航空货物管理系统,主要考察对类设计的把握是否合理还有对继承和多态的使用,能否设计出符合标准的类,是否充分理解对面向对象六大设计原则(SRP,OCP,LSP,D ...

  8. Java 实现文件和base64字符串互转

    项目中遇到需要将图片转成base64编码的字符串的需求,但是,考虑到扩展性,写了一个可以转换任务类型文件的方法.需要引入的包: <dependency> <groupId>co ...

  9. Guava中的常见集合操作用法

    本文主要介绍Guava中几种处理字符串和Map的方法,包括Joiner(连接).FluentIterable(过滤.转换集合)和Splitter(分割).本文基于Java 8进行测试,Guava 版本 ...

  10. mysql中compact行的存储结构

    mysql中行的格式类型包括:Compact.redundant.dynamic.compressed这四种,行和行之间是通过一个单向链表的形式来连接的,而我在实际工作中最常用到的是compact类型 ...