多个线程访问相同的寄存器值 ARM 程序集

Multiple Threads Accessing Same Register Value ARM Assembly

我正在使用一些 ARM 代码对需要访问同一寄存器的多个线程进行试验。我在 asm 调用中使用 C。但是,我把运行存成总线错误。这是我的意思的一个例子:

#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 中的值无效,因为不能保证在子例程调用中保留寄存器。也许在第一个例子中,我只是运气好,放在 setup() 中的 R7 中的值恰好保留了下来,但线程代码导致 R7 中的值被破坏。

如果是这样的话,有什么方法可以保留R7吗?我可以保存并存储到堆栈,但多个线程将同时访问它。是否有某种编译标志我可以通过 gcc 传递以确保在 setup() 中加载的 R7 的值在 loadAction() 中被访问?

谢谢

每个线程都有自己的寄存器值。这实际上是使线程成为线程的原因。如果两个线程共享它们的寄存器值(尤其是 PC 和 SP),它们就是同一个线程。


是的,寄存器通常不会在子例程调用中保留。编译器使用它们来存储 您的代码使用的每个值 - 它们不是一些您只能通过内联汇编代码访问的特殊不寻常的东西。根据程序中使用的 calling convention,编译器可能有义务保存它决定使用的某些寄存器的旧值,并在子例程 returns.[=18= 之前将它们恢复回来]

根据链接的维基百科页面,在 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;
}

然后编译器将尽一切努力确保值从 setup 变为 loadAction