ARMGCC内嵌汇编手册

上传人:ni****g 文档编号:456905455 上传时间:2022-11-14 格式:DOC 页数:10 大小:70KB
返回 下载 相关 举报
ARMGCC内嵌汇编手册_第1页
第1页 / 共10页
ARMGCC内嵌汇编手册_第2页
第2页 / 共10页
ARMGCC内嵌汇编手册_第3页
第3页 / 共10页
ARMGCC内嵌汇编手册_第4页
第4页 / 共10页
ARMGCC内嵌汇编手册_第5页
第5页 / 共10页
点击查看更多>>
资源描述

《ARMGCC内嵌汇编手册》由会员分享,可在线阅读,更多相关《ARMGCC内嵌汇编手册(10页珍藏版)》请在金锄头文库上搜索。

1、 . 转自:ARM GCC 嵌inline汇编手册关于这篇文档这篇文章是本人为方便各位业界而翻译,方便大家开发底层代码使用,请注明出处,。要是你E文功底好,本人还是建议阅读E文版的。.ethernut.de/en/documents/arm-inline-asm.html对于基于ARM的RISC处理器,GNU C编译器提供了在C代码中嵌汇编的功能。这种非常酷的特性提供了C代码没有的功能,比方手动优化软件关键局部的代码、使用相关的处理器指令。这里设想了读者是熟练编写ARM汇编程序读者,因为该片文档不是ARM汇编手册。同样也不是C语言手册。这篇文档假设使用的是GCC 4 的版本,但是对于早期的版本

2、也有效。GCC asm 声明让我们以一个简单的例子开场。就像C中的声明一样,下面的声明代码可能出现在你的代码中。/* NOP 例子 */asm(mov r0,r0);该语句的作用是将r0移动到r0中。换句话讲他并不干任何事。典型的就是NOP指令,作用就是短时的延时。请接着阅读和学习这篇文档,因为该声明并不像你想象的和其他的C语句一样。嵌汇编使用汇编指令就像在纯汇编程序中使用的方法一样。可以在一个asm声明中写多个汇编指令。但是为了增加程序的可读性,最好将每一个汇编指令单独放一行。asm(mov r0, r0ntmov r0, r0ntmov r0, r0ntmov r0, r0);换行符和制表

3、符的使用可以使得指令列表看起来变得美观。你第一次看起来可能有点怪异,但是当C编译器编译C语句的是候,它就是按照上面换行和制表生成汇编的。到目前为止,汇编指令和你写的纯汇编程序中的代码没什么区别。但是比照其它的C声明,asm的常量和存放器的处理是不一样的。通用的嵌汇编模版是这样的。asm(code : output operand list: input operand list: clobber list);汇编和C语句这间的联系是通过上面asm声明中可选的output operand list和input operand list。Clobber list后面再讲。下面是将C语言的一个整型变

4、量传递给汇编,逻辑左移一位后在传递给C语言的另外一个整型变量。/* Rotating bits example */asm(mov %result, %value, ror #1:result=r(y):valuer(x);每一个asm语句被冒号:分成了四个局部。l汇编指令放在第一局部中的“中间。mov %result, %value, ror #1l接下来是冒号后的可选择的output operand list,每一个条目是由一对方括号和被他包括的符号名组成,它后面跟着限制性字符串,再后面是圆括号和它括着的C变量。这个例子中只有一个条目。result=r(y)l接着冒号后面是输入操作符列表,

5、它的语法和输入操作列表一样valuer(x)l破坏符列表,在本例中没有使用就像上面的NOP例子,asm声明的4个局部中,只要最尾部没有使用的局部都可以省略。但是有有一点要注意的是,上面的4个局部中只要后面的还要使用,前面的局部没有使用也不能省略,必须空但是保存冒号。下面的一个例子就是设置ARM Soc的CPSR存放器,它有input但是没有output operand。asm(msr cpsr,%ps:psr(status)即使汇编代码没有使用,代码局部也要保存空字符串。下面的例子使用了一个特别的破坏符,目的就是告诉编译器存被修改正了。这里的破坏符在下面的优化局部在讲解。asm(:memory

6、);为了增加代码的可读性,你可以使用换行,空格,还有C风格的注释。asm(mov %result, %value, ror #1:result=r(y) /* Rotation result.*/:valuer(x) /* Rotated value.*/: /* No clobbers */);在代码局部%后面跟着的是后面两个局部方括号中的符号,它指的是一样符号操作列表中的一个条目。%result表示第二局部的C变量y,%value表示三局部的C变量x;符号操作符的名字使用了独立的命名空间。这就意味着它使用的是其他的符号表。简单一点就是说你不必关心使用的符号名在C代码中已经使用了。在早期的C

7、代码中,循环移位的例子必须要这么写:asm(mov %0, %1, ror #1:=r(result):r(value)在汇编代码中操作数的引用使用的是%后面跟一个数字,%1代表第一个操作数,%2代码第二个操作数,往后的类推。这个方法目前最新的编译器还是支持的。但是它不便于维护代码。试想一下,你写了大量的汇编指令的代码,要是你想插入一个操作数,那么你就不得不从新修改操作数编号。优化C代码有两种情况决定了你必须使用汇编。1st,C限制了你更加贴近底层操作硬件,比方,C中没有直接修改程序状态存放器PSR的声明。2nd就是要写出更加优化的代码。毫无疑问GNU C代码优化器做的很好,但是他的结果和我们

8、手工写的汇编代码相差很远。这一局部有一点很重要,也是被别人无视最多的就是:我们在C代码过嵌汇编指令添加的汇编代码,也是要被C编译器的优化器处理的。让我们下面做个试验来看看吧。下面是代码实例。bigtreejust:/embedded/basic-C$ arm-linux-gcc -c test.cbigtreejust:/embedded/basic-C$ arm-linux-objdump -D test.o编译器选择r3作为循环移位使用。它也完全可以选择为每一个C变量分配存放器。Load或者store一个值并不显式的进展。下面是其它编译器的编译结果。E420A0E1 mov r2, r4,

9、ror #1 y, x编译器为每一个操作数选择一个相应的存放器,将操作过的值cache到r4中,然后传递该值到r2中。这个过程你能理解不?有的时候这个过程变得更加糟糕。有时候编译器甚至完全抛弃你嵌入的汇编代码。C编译器的这种行为,取决于代码优化器的策略和嵌入汇编所处的上下文。如果在嵌汇编语句中不使用任何输出局部,那么C代码优化器很有可能将该嵌语句完全删除。比方NOP例子,我们可以使用它作为延时操作,但是对于编译器认为这影响了程序的执行速速,认为它是没有任何意义的。上面的解决方法还是有的。那就是使用volatile关键字。它的作用就是禁止优化器优化。将NOP例子修改正后如下:/*NOP exam

10、ple, revised */asm volatile(mov r0, r0);下面还有更多的烦恼等着我们。一个设计精细的优化器可能重新排列代码。看下面的代码:i+;if(j = 1)x +=3;i+;优化器肯定是要从新组织代码的,两个i+并没有对if的条件产生影响。更进一步的来讲,i的值增加2,仅仅使用一条ARM汇编指令。因而代码要重新组织如下:if(j = 1) x += 3;i += 2;这样节省了一条ARM指令。结果是:这些操作并没有得到许可。这些将对你的代码产生很到的影响,这将在下面介绍。下面的代码是c乘b,其中c和b中的一个或者两个可能会被中断处理程序修改。进入该代码前先禁止中断,

11、执行完该代码后再开启中断。asm volatile(mrs r12, cpsrntorr r12, r12, #0xC0ntmsr cpsr_c, r12nt:r12,cc);c *= b; /*This may fail.*/asm volatile(mrs r12, cpsrnbic r12, r12, #0xC0nmsr cpsr_c, r12:r12,cc);但是不幸的是针对上面的代码,优化器决定先执行乘法然后执行两个嵌汇编,或相反。这样将会使得我们的代码变得毫无意义。我们可以使用clobber list帮助。上面例子中的clobber list如下:r12,cc上面的clobber

12、list将会将向编译器传达如下信息,修改了r12和程序状态存放器的标志位。Btw,直接指明使用的存放器,将有可能阻止了最好的优化结果。通常你只要传递一个变量,然后让编译器自己选择适合的存放器。另外存放器名,cccondition registor 状态存放器标志位,memory都是在clobber list上有效的关键字。它用来向编译器指明,嵌汇编指令改变了存中的值。这将强迫编译器在执行汇编代码前存储所有缓存的值,然后在执行完汇编代码后重新加载该值。这将保存程序的执行顺序,因为在使用了带有memory clobber的asm声明后,所有变量的容都是不可预测的。asm volatile(mrs

13、r12, cpsrntorr r12, r12, #0xC0ntmsr cpsr_c, r12nt:r12,cc,memory);c *= b; /*This is safe.*/asm volatile(mrs r12, cpsrnbic r12, r12, #0xC0nmsr cpsr_c, r12:r12,cc,memory);使所有的缓存的值都无效,只是局部最优suboptimal。你可以有选择性的添加dummy operand 来人工添加依赖。asm volatile(mrs r12, cpsrntorr r12, r12, #0xC0ntmsr cpsr_c, r12nt:=X(b

14、):r12,cc);c *= b; /*This is safe.*/asm volatile(mrs r12上面的第一个asm试图修改变量先b,第二个asm试图修改c。这将保存三个语句的执行顺序,而不要使缓存的变量无效。理解优化器对嵌汇编的影响很重要。如果你读到这里还是云里雾里,最好是在看下个主题之前再把这段文章读几遍_。Input and output operands前面我们学到,每一个input和output operand,由被方括号中的符号名,限制字符串,圆括号中的C表达式构成。这些限制性字符串有哪些,为什么我们需要他们?你应该知道每一条汇编指令只承受特定类型的操作数。例如:跳转指

15、令期望的跳转目标地址。不是所有的存地址都是有效的。因为最后的opcode只承受24位偏移。但矛盾的是跳转指令和数据交换指令都希望存放器中存储的是32位的目标地址。在所有的例子中,C传给operand的可能是函数指针。所以面对传给嵌汇编的常量、指针、变量,编译器必须要知道怎样组织到汇编代码中。对于ARM核的处理器,GCC 4 提供了一下的限制。ConstraintUsage in ARM stateUsage in Thumb statefFloating point registers f0 . f7Not availablehNot availableRegisters r8.r15GImmediate floating point constantNot availableHSame a G, but negatedNot availabl

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 建筑/环境 > 施工组织

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号