簡體   English   中英

如何理解PowerPC stwbrx的這個GNU C內聯匯編宏

[英]How to understand this GNU C inline assembly macro for PowerPC stwbrx

這基本上是在傳輸消息緩沖區時執行緩沖區的交換。 這句話讓我感到困惑(因為我不熟悉c中的嵌入式匯編代碼)。 這是一個power pc指令

#define ASMSWAP32(dest_addr,data) __asm__ volatile ("stwbrx %0, 0, %1" : : "r" (data), "r" (dest_addr))

除了因為一個bug而不安全之外,這個宏的效率也低於編譯器為你生成的效率。


stwbrx = 存儲字字節反轉 x代表索引。

在GNU C中你不需要內聯asm,你可以使用__builtin_bswap32讓編譯器為你發出這個指令。

void swapstore_asm(int a, int *p) {
    ASMSWAP32(p, a);
}

void swapstore_c(int a, int *p) {
    *p = __builtin_bswap32(a);
}

使用gcc4.8.5 -O3 -mregnames編譯,我們從兩個函數(Godbolt編譯器資源管理器)獲得相同的代碼:

swapstore:
    stwbrx %r3, 0, %r4
    blr
swapstore_c:
    stwbrx %r3,0,%r4
    blr

但是對於更復雜的地址(存儲到p[off] ,其中off是整數函數arg),編譯器知道如何使用兩個寄存器輸入,而宏強制編譯器將地址放在一個寄存器中:

void swapstore_offset(int a, int *p, int off) {
     = __builtin_bswap32(a);
}

swapstore_offset:
    slwi %r5,%r5,2              # *4 = sizeof(int)
    stwbrx %r3,%r4,%r5          # use an indexed addressing mode, with both registers non-zero
    blr

swapstore_offset_asm:
    slwi %r5,%r5,2
    add %r4,%r4,%r5            # extra instruction forced by using the macro
    stwbrx %r3, 0, %r4
    blr

順便說一句,如果您在理解GNU C內聯asm模板時遇到問題,查看編譯器的asm輸出可能是查看替換內容的有用方法。請參閱如何從GCC / clang程序集輸出中刪除“noise”? 有關讀取編譯器asm輸出的更多信息。


還要注意這個宏是錯誤的:它缺少商店的"memory"破壞 是的,你仍然需要asm volatile 編譯器不會假設*dest_addr被修改,除非你告訴它,所以它可以在此insn之前提升*dest_addr的非易失性加載,或者更可能是真正的問題,在它之后接收存儲。 (例如,如果在使用此存儲器將存儲器歸零之前,編譯器可能此指令之后實際為零。)

您可以告訴編譯器您使用=m" (*dest_addr)操作數修改哪個內存位置,或者作為偽操作數或者在尋址模式上使用約束,而不是"memory" clobber(並且也省略volatile )您可以將它用作reg+reg 。(IDK PPC足以知道"=m"通常會擴展到什么。)

在大多數情況下,這個bug不會咬你,但它仍然是一個bug。 升級您的編譯器版本或使用鏈接時優化可能會使您的程序錯誤,沒有源級別的更改。

這種事情是為什么https://gcc.gnu.org/wiki/DontUseInlineAsm

另請參見https://stackoverflow.com/tags/inline-assembly/info

#define ASMSWAP32(dest_addr,data) ......

這部分應該清楚

__asm__ volatile ( ... : : "r" (data), "r" (dest_addr))

這是實際的內聯匯編:

兩個值傳遞給匯編代碼; 匯編代碼中沒有返回任何值(這是實際匯編代碼之后的冒號)。

兩個參數都在寄存器( "r" )中傳遞。 表達式%0將被包含data值的寄存器替換,而表達式%1將被包含dest_addr值的寄存器替換(在這種情況下將是指針)。

這里的volatile意味着匯編代碼必須在此時執行,不能移動到其他地方。

因此,如果您在C源代碼中使用以下代碼:

ASMSWAP(&a, b);

...將生成以下匯編代碼:

# write the address of a to register 5 (for example)
...
# write the value of b to register 6
...
stwbrx 6, 0, 5

所以,第一個參數stwbrx指令的值b和最后一個參數是地址a

stwbrx x, 0, y

該指令將寄存器x的值寫入寄存器y存儲的地址; 但是它將值寫入“反向端”(在大端CPU上它寫入值“little endian”)。

以下代碼:

uint32 a;
ASMSWAP32(&a, 0x12345678);

...因此應該導致a = 0x78563412

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM