2015-09-05 155 views
0

我必須實現應該是原子操作的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 << bit; ? –

+0

你可以放在那裏,當然也可以放在'set_bit'中。不,你使用它像'__atomic_or_fetch(addr,1 << nr,__ATOMIC_SEQ_CST)'。 – Jester

回答

0

我想你應該寫每行只有一個指令串(在每個指令的末尾添加\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':操作數輸出代碼無效 –

0

看來您使用的是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

編輯:錯過了指針解除引用。