实现我自己的互斥锁时如何从内联汇编引用 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()
内的 *mutex
。 gcc -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 我会把你写的东西称为自旋锁(一个非常糟糕的主意),而不是互斥体。
作为练习,我正在尝试实现我自己的互斥锁库,以便在我即将推出的 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()
内的 *mutex
。 gcc -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 我会把你写的东西称为自旋锁(一个非常糟糕的主意),而不是互斥体。