繁体   English   中英

使用汇编语言为C程序编写函数

[英]Writing a function for C program using assembly language

我必须实现set_bit函数,该函数应该是原子操作。 我在linux源代码中找到了汇编代码。 (我正在使用sparc),并希望将其更改为可以在C程序中使用的函数。

    static void set_bit(unsigned int nr, unsigned int *addr)
    {
    //  *vec |= 1<<bit;  <== original non-atomic C code
    //set_bit:      /* %o0=nr, %o1=addr */   <== nr is in %o0, addr in %o1 by sparc rule
__asm__ __volatile__ (
    "srlx   %o0, 6, %g1"
    "mov    1, %o2"
    "sllx   %g1, 3, %g3"
    "and    %o0, 63, %g2"
    "sllx   %o2, %g2, %o2"
    "add    %o1, %g3, %o1"
"1: ldx [%o1], %g7"
    "or %g7, %o2, %g1"
    "casx   [%o1], %g7, %g1"
    "cmp    %g7, %g1"
    "bne,pn %xcc, 2f"
     "nop"
    "retl"
    "nop"
    : "=m"(addr) // output
    : "m"(nr) // input
    : );

这个对吗? 我是否在最后一行列出了所有的clobberd寄存器?

我在下面看到错误消息。

../../../../../rtems-4.10.99-src/c/src/libchip/sdmmc/ald-sd-card.c:135:1: error: invalid 'asm': invalid operand output code
 __asm__ __volatile__ (
 ^
../../../../../rtems-4.10.99-src/c/src/libchip/sdmmc/ald-sd-card.c:135:1: error: invalid 'asm': invalid operand output code
../../../../../rtems-4.10.99-src/c/src/libchip/sdmmc/ald-sd-card.c:135:1: error: invalid 'asm': operand number out of range

      ^

我认为您应该只在字符串中的每一行写一条指令(在每条指令的末尾添加\\n\\t )。

    static void set_bit(unsigned int nr, unsigned int *addr)
    {
    //  *vec |= 1<<bit;  <== original non-atomic C code
    //set_bit:      /* %o0=nr, %o1=addr */   <== nr is in %o0, addr in %o1 by sparc rule
__asm__ __volatile__ (
    "srlx   %o0, 6, %g1\n\t"
    "mov    1, %o2\n\t"
    "sllx   %g1, 3, %g3\n\t"
    "and    %o0, 63, %g2\n\t"
    "sllx   %o2, %g2, %o2\n\t"
    "add    %o1, %g3, %o1\n\t"
"1: ldx [%o1], %g7\n\t"
    "or %g7, %o2, %g1\n\t"
    "casx   [%o1], %g7, %g1\n\t"
    "cmp    %g7, %g1\n\t"
    "bne,pn %xcc, 2f\n\t"
     "nop\n\t"
    "retl\n\t"
    "nop\n\t"
    : "=m"(addr) // output
    : "m"(nr) // input
    : );
    }

看来您正在使用GCC。

正如@MikeCAT所说,说明需要在单独的行上。

您需要将寄存器名称中的所有%加倍。 %%在输出部件中变为%

通过sparc规则,nr在%o0中,addr在%o1中

没有这样的规则,您可能会想到函数调用ABI不适用于内联汇编。 GCC期望将addr写入存储位置%0nr在存储位置%1如下所示:

 : "=m"(addr) // output : "m"(nr) // input 

但是addr不是输出。 *addr是输入/输出,或者addr是输入,并且"memory"必须位于“ clobber”列表中。 对于nr注册将是一个更好的地方:

 : "+m"(*addr) // input and output : "r"(nr) // input 

您不应该在其中放置retl ,因为它会跳转到未定义的位置,控制流应该到达末尾。

您必须列出所有已更改的寄存器作为输出或Clobbers。

如果应该将其视为内存屏障,则"memory"必须位于破坏者列表中。

我推荐您参阅GCC手册

编辑:错过了指针取消引用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM