Во-первых, почему вы используете усеченные 32-битные адреса в коде сборки, тогда как остальная часть программы скомпилирована для выполнения в 64-битном режиме и работы с 64-битными адресами / указателями? Я имею в виду ebx
. Почему это не rbx
?
Во-вторых, почему вы пытаетесь вернуть значение из кода сборки с помощью "=r"(resource)
? Ваши функции изменяют значение в памяти с помощью xchg eax, [ebx]
и mov DWORD PTR [ebx], 0x00
и возвращают void
. Удалить "=r"(resource)
.
Наконец, если вы внимательно посмотрите на разборку SpinLock::lock()
, разве вы не можете увидеть что-то странное в ebx
?:
mov %rdi,-0x10(%rbp)
mov -0x10(%rbp),%rax
mov (%rax),%edx
mov %edx,%ebx
<InUseLoop>:
mov $0x1,%eax
addr32 xchg %eax,(%ebx)
В этом коде значение ebx
, являющееся адресом / указателем, не берется непосредственно из параметра функции (rdi
), сначала в параметре разыменовывается значение mov (%rax),%edx
, но почему? Если вы отбросите все запутанные ссылки на C ++, технически функция получит указатель на u32
, а не указатель на указатель на u32
, и, следовательно, не нуждается в дополнительной разыменовке.
Проблема здесь: "r"(resource)
. Это должно быть "r"(&resource)
.
Небольшое 32-разрядное тестовое приложение демонстрирует эту проблему:
#include <iostream>
using namespace std;
void unlock1(unsigned& resource)
{
__asm__ __volatile__
(
/* "mov DWORD PTR ds:[%0],0x00\n\t" */
"movl %0, %%ebx\n\t"
"movl $0, (%%ebx)\n\t"
:
:"r"(resource)
:"ebx"
);
}
void unlock2(unsigned& resource)
{
__asm__ __volatile__
(
/* "mov DWORD PTR ds:[%0],0x00\n\t" */
"movl %0, %%ebx\n\t"
"movl $0, (%%ebx)\n\t"
:
:"r"(&resource)
:"ebx"
);
}
unsigned blah;
int main(void)
{
blah = 3456789012u;
cout << "before unlock2() blah=" << blah << endl;
unlock2(blah);
cout << "after unlock2() blah=" << blah << endl;
blah = 3456789012u;
cout << "before unlock1() blah=" << blah << endl;
unlock1(blah); // may crash here, but if it doesn't, it won't change blah
cout << "after unlock1() blah=" << blah << endl;
return 0;
}
Выход:
before unlock2() blah=3456789012
after unlock2() blah=0
before unlock1() blah=3456789012
Exiting due to signal SIGSEGV
General Protection Fault at eip=000015eb
eax=ce0a6a14 ...