GCC下使用Inline Assembly的初步心得

以前主要手写汇编,今天尝试用了下内联汇编(Inline Assembly),出了点问题,特此做个总结。

=====================================================================

开发环境:Xilinx ISE 14.4 EDK

编译器版本:gcc version 4.6.3 (Sourcery CodeBench Lite 2012.03-83)


用于测试的C源代码:

void dummy1(void)
{
}

unsigned int dummy2(void)
{
}

unsigned int dummy3(void)
{
    return 0x12345678;
}

unsigned int dummy4()
{
    asm (
    "MRC p15,0,r0,c0,c0,5\n\t"
    "AND r0, r0, #3\n\t"
    "BX  lr\n\t"
    );
}

unsigned int dummy5()
{
    register int x, y;

    asm (
    "MRC p15,0,%[value],c0,c0,5\n\t"
    "AND %[result], %[value], #3\n\t": [result] "=r" (y): [value] "r" (x)
    );
    return y;
}


在-O0优化级别下的编译结果:

void dummy1(void)
{
  1003c0:    e52db004     push    {fp}        ; (str fp, [sp, #-4]!)
  1003c4:    e28db000     add    fp, sp, #0
}
  1003c8:    e28bd000     add    sp, fp, #0
  1003cc:    e8bd0800     pop    {fp}
  1003d0:    e12fff1e     bx    lr

001003d4 <dummy2>:

unsigned int dummy2(void)
{
  1003d4:    e52db004     push    {fp}        ; (str fp, [sp, #-4]!)
  1003d8:    e28db000     add    fp, sp, #0
}
  1003dc:    e1a00003     mov    r0, r3
  1003e0:    e28bd000     add    sp, fp, #0
  1003e4:    e8bd0800     pop    {fp}
  1003e8:    e12fff1e     bx    lr

001003ec <dummy3>:

unsigned int dummy3(void)
{
  1003ec:    e52db004     push    {fp}        ; (str fp, [sp, #-4]!)
  1003f0:    e28db000     add    fp, sp, #0
    return 0x12345678;
  1003f4:    e3053678     movw    r3, #22136    ; 0x5678
  1003f8:    e3413234     movt    r3, #4660    ; 0x1234
}
  1003fc:    e1a00003     mov    r0, r3
  100400:    e28bd000     add    sp, fp, #0
  100404:    e8bd0800     pop    {fp}
  100408:    e12fff1e     bx    lr

0010040c <dummy4>:

unsigned int dummy4()
{
  10040c:    e52db004     push    {fp}        ; (str fp, [sp, #-4]!)
  100410:    e28db000     add    fp, sp, #0
    asm (
  100414:    ee100fb0     mrc    15, 0, r0, cr0, cr0, {5}
  100418:    e2000003     and    r0, r0, #3
  10041c:    e12fff1e     bx    lr
    "MRC p15,0,r0,c0,c0,5\n\t"
    "AND r0, r0, #3\n\t"
    "BX  lr\n\t"
    );
}
  100420:    e1a00003     mov    r0, r3
  100424:    e28bd000     add    sp, fp, #0
  100428:    e8bd0800     pop    {fp}
  10042c:    e12fff1e     bx    lr

00100430 <dummy5>:

unsigned int dummy5()
{
  100430:    e92d0810     push    {r4, fp}
  100434:    e28db004     add    fp, sp, #4
    register int x, y;

    asm (
  100438:    ee104fb0     mrc    15, 0, r4, cr0, cr0, {5}
  10043c:    e2044003     and    r4, r4, #3
    "MRC p15,0,%[value],c0,c0,5\n\t"
    "AND %[result], %[value], #3\n\t": [result] "=r" (y): [value] "r" (x)
    );
    return y;
  100440:    e1a03004     mov    r3, r4
}
  100444:    e1a00003     mov    r0, r3
  100448:    e24bd004     sub    sp, fp, #4
  10044c:    e8bd0810     pop    {r4, fp}
  100450:    e12fff1e     bx    lr

注意:

1. 函数dummy4()的编译结果运行时会出问题:首先取到的CP15寄存器的值不会被返回;fp寄存器被改写但是没有恢复;没有和push相匹配的pop,stack会完全乱掉。

2. 函数dummy5()中给两个临时变量声明了register关键字,如果不加,对这两个变量的访问会直接编译成对stack memory的访问。

3. -O0下GCC在函数进入和退出的时候加上固定的wrapper。


在-O3优化级别下的编译结果:
void dummy1(void)
{
}
  1003c0:    e12fff1e     bx    lr

001003c4 <dummy2>:

unsigned int dummy2(void)
{
}
  1003c4:    e12fff1e     bx    lr

001003c8 <dummy3>:

unsigned int dummy3(void)
{
    return 0x12345678;
}
  1003c8:    e3050678     movw    r0, #22136    ; 0x5678
  1003cc:    e3410234     movt    r0, #4660    ; 0x1234
  1003d0:    e12fff1e     bx    lr

001003d4 <dummy4>:

unsigned int dummy4()
{
    asm (
  1003d4:    ee100fb0     mrc    15, 0, r0, cr0, cr0, {5}
  1003d8:    e2000003     and    r0, r0, #3
  1003dc:    e12fff1e     bx    lr
    "MRC p15,0,r0,c0,c0,5\n\t"
    "AND r0, r0, #3\n\t"
    "BX  lr\n\t"
    );
}
  1003e0:    e12fff1e     bx    lr

001003e4 <dummy5>:

unsigned int dummy5()
{
    register int x, y;

    asm (
  1003e4:    e3a00000     mov    r0, #0
  1003e8:    ee100fb0     mrc    15, 0, r0, cr0, cr0, {5}
  1003ec:    e2000003     and    r0, r0, #3
    "MRC p15,0,%[value],c0,c0,5\n\t"
    "AND %[result], %[value], #3\n\t": [result] "=r" (y): [value] "r" (x)
    );
    return y;
}
  1003f0:    e12fff1e     bx    lr

注意:

1. 函数dummy4():执行结果会碰巧对了,但是两条BX指令明显不对。

2. 函数dummy5():功能没有问题,但是不是最有效的,第一条指令完全没有必要。


小结:

1. 使用内联汇编(Inline Assembly)的时候没有必要加返回指令BX

2. 不要在内联汇编中使用指定寄存器,因为编译器在不同的编译选项下对寄存器的处理方式不同。

3. 比较好的办法是在内联汇编中使用临时变量,临时变量前面最好加上register关键字,方便编译器优化。

4. 如果只是写些简单的使用特殊指令的函数,直接写汇编比使用内联汇编(Inline Assembly)方便快捷。

[END]





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值