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

问题描述:

我必须实现应该是原子操作的set_bit函数。我在linux源代码中发现了这个汇编代码。 (我正在使用sparc),并希望将其更改为可在C程序中使用的函数。使用汇编语言编写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 

    ^
+0

如果您不需要汇编,只需让编译器处理它并使用'__atomic_or_fetch'。 – Jester

+0

你的意思是把它放在哪里?例如,如果我有代码set_bit(nr,&events); ?你的意思是像__atomic_or_fetch * vec | = 1

+0

你可以放在那里,当然也可以放在'set_bit'中。不,你使用它像'__atomic_or_fetch(addr,1 Jester

我想你应该写每行只有一个指令串(在每个指令的末尾添加\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 
    :); 
    } 
+0

我试过这个,但得到了:我避免使用位操作,现在它工作正常。 ../../../../../rtems-4.10.99-src/c/src/libchip/sdmmc/ald-sd-card。c:159:1:错误:无效'asm':无效操作数输出代码 __asm__ __volatile__( ^ ../../../../../rtems-4.10.99-src/c/src /libchip/sdmmc/ald-sd-card.c:159:1:错误:无效'asm':无效操作数输出代码 ../../../../../rtems-4.10.99- src/c/src/libchip/sdmmc/ald-sd-card.c:159:1:错误:无效'asm':操作数超出范围 ../../../../../ rtems-4.10.99-src/c/src/libchip/sdmmc/ald-sd-card.c:159:1:错误:无效'asm':操作数输出代码无效 –

看来您使用的是GCC。

由于@MikeCAT表示说明需要在单独的行上。

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

nr is in %o0, addr in %o1 by sparc rule

有没有这样的规则,你可能会想对该函数的调用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"必须在clobber列表中。

我把你引用到GCC Manual

编辑:错过了指针解除引用。