实现我自己的互斥锁时如何从内联汇编引用 C 中的指针

How to refer to pointer in C from inline assembly when implementing my own mutex

作为练习,我正在尝试实现我自己的互斥锁库,以便在我即将推出的 C 程序中使用。我被建议为此使用内联汇编,因此为 x86 (AT&T) 生成了以下代码:

#include "mymutex.h"

void init_my_mutex(my_mutex_t *mutex){
        *mutex = 1;
}

void lock_my_mutex(my_mutex_t *mutex){
        asm(    "movq [=10=], %%rax\n\t"    // temp = 0
                "movq [=10=], %%rbx\n\t"
                "1: xchgq (mutex), %%rax\n\t"
                "cmpq %%rax, %%rbx\n\t"
                "jz 1b\n\t":::"rax","rbx");
}

void unlock_my_mutex(my_mutex_t *mutex){
        *mutex = 1;
}

问题是我不知道如何正确处理 lock_my_mutex 内的 asm() 内的 *mutexgcc -c mymutex.c -o mymutex.o 编译正常,但是当尝试使用 gcc -pthread count-primes.c mymutex.o -o count-primes 编译我的测试程序 count-primes.c 时,出现以下错误:relocation R_X86_64_32S against undefined symbol 'mutex' can not be used when making a PIE object; recompile with -fPIC。我尝试用 -fPIC 重新编译(我不知道这应该有什么帮助),但我仍然遇到同样的错误。

我的头文件如下所示:

#ifndef __mymutex_h
#define __mymutex_h

// Our mutex is very simple so it is either locked
// or unlocked and we don't keep any other information 
typedef long long my_mutex_t;

// Initializes a mutex to be unlocked
void init_my_mutex(my_mutex_t *mutex);

// Tries to grab a lock. The function only
// returns when the current thread holds the lock
void lock_my_mutex(my_mutex_t *mutex);

// Unlock the mutex. You don't need to check to see
// if the current thread holds the lock
void unlock_my_mutex(my_mutex_t *mutex);

#endif

count-primes.c 中,我尝试这样使用互斥体:

my_mutex_t lock;
...

lock_my_mutex(&lock);
                        // Synchronized operation
unlock_my_mutex(&lock);

...

我怀疑问题与我在使用 asm() 时对互斥体的寻址有关,并且认为理解如何(以及为什么)这样做将使我能够解决这个问题。但在任何其他方面的帮助也非常感谢。

最佳,

史蒂芬

要么使用内存约束,要么使用包含地址和内存破坏器的输入寄存器:

有内存限制:

void lock_my_mutex(my_mutex_t *mutex){
        uint64_t tmp;
        asm(    "mov [=10=], %1\n\t"
                "1: xchg %1,%0\n\t"
                "test %1, %1\n\t"
                "jz 1b\n\t": "+m(*mutex), "=&r"(tmp));
}

内存破坏:

void lock_my_mutex(my_mutex_t *mutex){
        uint64_t tmp;
        asm volatile(
                "mov [=11=], %0\n\t"
                "1: xchg %0,(%1)\n\t"
                "test %0, %0\n\t"
                "jz 1b\n\t": "=&r"(tmp) : "r"(mutex) : "memory");
}

真的,内存破坏应该以任何一种方式来模拟这样的想法,即由于与其他线程同步,其他对象的值可能会在编译器的背后发生变化(受互斥锁保护的对象)。我更喜欢后一种方法,因为它并不意味着如果永远不会再次访问互斥对象,则可以删除 asm。

请注意,您可以通过以下方式进一步删除 mov:

void lock_my_mutex(my_mutex_t *mutex){
        uint64_t tmp;
        asm volatile(
                "1: xchg %0,(%1)\n\t"
                "test %0, %0\n\t"
                "jz 1b\n\t": "=&r"(tmp) : "r"(mutex), "0"(0) : "memory");
}

FWIW 我会把你写的东西称为自旋锁(一个非常糟糕的主意),而不是互斥体。