我正在使用一些 ARM 代碼來試驗需要訪問同一暫存器的多個執行緒。我將 C 與asm呼叫一起使用。但是,我一直遇到總線錯誤。這是我的意思的一個例子:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
int someVar = 0;
void setup(){
__asm__("LDR R7, =someVar\n\t"); // load someVar into R7
}
void loadAction(){
__asm__("LDREX R1, [R7]\n\t");
}
int main(){
setup();
loadAction();
}
這作業得很好。
但是,當我引入執行緒時,會出現這樣的總線錯誤:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
int someVar = 0;
void setup(){
__asm__("LDR R7, =someVar\n\t"); // load someVar into R7
}
void *loadAction(void *threadArg){
__asm__("LDREX R1, [R7]\n\t");
}
int main(){
pthread_t tid;
setup();
int i;
for (i = 0; i < 1; i ){
pthread_create(&tid, NULL, loadAction, (void *)&tid);
}
pthread_exit(NULL);
return 0;
}
我對這個問題的最佳猜測是 R7 中的值無效,因為不能保證在子程式呼叫中保留暫存器。也許在第一個示例中,我只是走運了,R7 中的值恰好保留在 setup() 中,但是執行緒代碼導致 R7 中的值被破壞。
如果是這種情況,有什么辦法可以保留 R7 嗎?我可以保存并存盤到堆疊中,但多個執行緒將同時訪問它。是否有某種編譯標志我可以通過 gcc 傳遞以確保在 setup() 中加載的 R7 的值可以在 loadAction() 中訪問?
謝謝
uj5u.com熱心網友回復:
每個執行緒都有自己的暫存器值。這實際上是使執行緒成為執行緒的原因。如果兩個執行緒共享它們的暫存器值(尤其是 PC 和 SP),它們將是同一個執行緒。
是的,暫存器通常不會在子程式呼叫中保留。編譯器使用它們來存盤您的代碼使用的每個值- 它們不是您只能通過行內匯編代碼訪問的特殊不尋常的東西。根據程式中使用的呼叫約定,編譯器可能有義務保存它決定使用的某些暫存器的舊值,并在子例程回傳之前將它們恢復回來。
根據鏈接的 Wikipedia 頁面,在 32 位 ARM 上,r7是編譯器必須保存和恢復的暫存器之一。
在這種情況下,編譯器尚未決定在setup函式中使用 r7(因為其中沒有實際編譯的代碼);如果setup確實有一堆 C 代碼并且編譯器決定使用 r7,那么它會在開始時保存舊值,在最后加載舊值,在中間使用暫存器,然后加載到 r7 將覆寫任何內容編譯器認為存盤在那里的值,從而破壞了 C 代碼。當loadAction在同一個執行緒上運行時,舊值將被放回 r7。
有一種方法可以在 C 語言中保存一個暫存器,它被稱為變數。
而不是這個:
// wrong code
void setup(){
__asm__("LDR R7, =someVar\n\t"); // load someVar into R7
}
void *loadAction(void *threadArg){
__asm__("LDREX R1, [R7]\n\t");
}
如果你這樣寫:
int *pSomeVar;
void setup(){
pSomeVar = &someVar; // load someVar into pSomeVar
}
void *loadAction(void *threadArg){
int value = *pSomeVar;
}
然后編譯器將盡一切努力確保該值從setupto獲取loadAction。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/464752.html
