新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 混合使用C、C++和汇编语之:内联汇编和嵌入型汇编的使用

混合使用C、C++和汇编语之:内联汇编和嵌入型汇编的使用

作者:时间:2013-09-30来源:网络收藏

本文引用地址:http://www.eepw.com.cn/article/257034.htm

②中断使能

下面的例子通过读取程序状态寄存器PSR并设置它的中断使能位bit[7]来禁止/打开中断。需要注意的是,该例只能运行在系统模式下,因为用户模式是无权修改程序状态寄存器的。

__inlinevoidenable_IRQ(void)

{

inttmp;

__asm

{

MRStmp,PSR

BItmp,tmp,#0x80

MSRCPSR_c,tmp

}

}

__inlinevoiddisable_IRQ(void)

{

inttmp;

__asm

{

MRStmp,CPSR

ORRtmp,tmp,#0x80

MSRCPSR_c,tmp

}

}

intmain(void)

{

disable_IRQ();

enable_IRQ();

}

③分隔符的计算

下面的例子计算两个整数数组中分隔符“,”的个数。该例子显示了如何在中访问C或语言中的数据类型。该例中的函数mlal()被编译器优化为一条SMLAL指令,可以使用-S–interleave编译选项使编译器输出汇编结果。

#includestdio.h>

/*changewordorderifbig-endian*/

#definelo64(a)(((unsigned*)a)[0]) /*longlong型的低32位*/

#definehi64(a)(((int*)a)[1]) /*longlong型的高32位*/

__inline__int64mlal(__int64sum,inta,intb)

{

#if!defined(__thumb)defined(__TARGET_FEATURE_MULTIPLY)

__asm

{

SMLALlo64(sum),hi64(sum),a,b

}

#else

sum+=(__int64)a*(__int64)b;

#endif

returnsum;

}

__int64dotprod(int*a,int*b,unsignedn)

{

__int64sum=0;

do

sum=mlal(sum,*a++,*b++);

while(--n!=0);

returnsum;

}

inta[10]={1,2,3,4,5,6,7,8,9,10};

intb[10]={10,9,8,7,6,5,4,3,2,1};

intmain(void)

{

printf(Dotproduct%lld(shouldbe%d)n,dotprod(a,b,10),220);

return0;

}

2.中的限制

可以在内联汇编代码中执行的操作有许多限制。这些限制提供安全的方法,并确保在汇编代码中不违反C和代码编译中的假设。

①不能直接向程序计数器PC赋值。

②内联汇编不支持标号变量。

③不能在程序中使用“.”或{PC}得到当前指令地址值。

④在16进制常量前加“0x”代替“”。

⑤建议不要对堆栈进行操作。

⑥编译器可能会使用r12和r13寄存器存放编译的中间结果,在计算表达式值时可能会将寄存器r0~r3、r12及r14用于子程序调用。另外在内联汇编中设置程序状态寄存器CPSR中的标志位NZCV时,要特别小心,内联汇编中的设置很可能会和编译器计算的表达式的结果冲突。

⑦用内联汇编代码更改处理器模式是可能的。然而,更改处理器模式会禁止使用C或操作数或禁止对已编译C或C++代码的调用,直到将处理器模式更改回原设置之后之前的函数库才可正常使用。

⑧为Thumb状态编译C或C++时,内联汇编程序不可用且不汇编Thumb指令。

⑨尽管可以使用通用协处理器指令指定VFP或FPA指令,但内联汇编程序不为它们提供直接支持。

不能用内联汇编代码更改VFP向量模式。内联汇编可包含浮点表达式操作数,该操作数可使用编译程序生成的VFP代码求出操作数值。因此,仅由编译程序修改VFP状态很重要。

⑩内嵌汇编不支持的指令有BX、BLX、BXJ和BKPT指令。而LDM、STM、LDRD和STRD指令可能被等效为LDR或STR指令。

3.内联汇编中的虚拟寄存器

内联汇编程序提供对处理器物理寄存器的非直接访问。如果在内联汇编程序指令中将某个寄存器用作操作数,它就成为相同名称的虚拟寄存器的引用,而不是对实际物理ARM寄存器的引用。例如内联汇编指令中使用了寄存器r0,但对于C编译器,指令中出现的r0只是一个变量,并非实际的物理寄存器r0,当程序运行时,可能是由物理寄存器r1来存放r0所代表的值。

下面的例子显示了编译器如何对内联汇编指令的寄存器进行分配。

程序的源代码如下。

#includestdio.h>

voidtest_inline_register(void)

{

inti;

intr5,r6,r7;

__asm

{

MOVi,#0

loop:

MOVr5,#0

MOVr6,#0

MOVr7,#0

ADDi,i,#1

CMPi,#3

BNEloop

}

}

intmain(void)

{

test_inline_register();

printf(testinlineregistern);

return0;

}

由C编译器编译出的汇编码如下所示。

test_inline_register:

0000807CE3A00000MOVr0,#0

>>>TEST_INLINE_REGISTER#12loop:

00008080E1A00000NOP

>>>TEST_INLINE_REGISTER#13MOVr5,#0

00008084E3A01000MOVr1,#0

>>>TEST_INLINE_REGISTER#14MOVr6,#0

00008088E3A02000MOVr2,#0

>>>TEST_INLINE_REGISTER#15MOVr7,#0

0000808CE3A03000MOVr3,#0

>>>TEST_INLINE_REGISTER#16ADDi,i,#1

00008090E2800001ADDr0,r0,#1

>>>TEST_INLINE_REGISTER#17CMPi,#3

00008094E3500003CMPr0,#3

000080980A000000BEQ0x80a0TEST_INLINE_REGISTER#21>

>>>TEST_INLINE_REGISTER#18BNEloop

0000809CEAFFFFF8B0x8084TEST_INLINE_REGISTER#13>

>>>TEST_INLINE_REGISTER#21}

000080A0E12FFF1EBXr14

>>>TEST_INLINE_REGISTER#25{

c语言相关文章:c语言教程


c++相关文章:c++教程




评论


相关推荐

技术专区