Как насчет следующего, который, кажется, работает для меня в небольшом тесте:
int sbcas(uint64_t* ptr, uint64_t oldval, uint64_t newval)
{
int changed = 0;
__asm__ (
"push %%ebx\n\t" // -fPIC uses ebx, so save it
"mov %5, %%ebx\n\t" // load ebx with needed value
"lock\n\t"
"cmpxchg8b %0\n\t" // perform CAS operation
"setz %%al\n\t" // eax potentially modified anyway
"movzx %%al, %1\n\t" // store result of comparison in 'changed'
"pop %%ebx\n\t" // restore ebx
: "+m" (*ptr), "=r" (changed)
: "d" ((uint32_t)(oldval >> 32)), "a" ((uint32_t)(oldval & 0xffffffff)), "c" ((uint32_t)(newval >> 32)), "r" ((uint32_t)(newval & 0xffffffff))
: "flags", "memory"
);
return changed;
}
Если это также будет неправильно скомпилировано, не могли бы вы добавить небольшой фрагмент, который вызывает такое поведение?* Что касается вопроса о бонусе, я не думаю, что возможно выполнить ветвление после блока ассемблера, используя код условия из инструкции cmpxchg8b
(если вы не используете asm goto
или подобную функциональность).Из GNU C Language Extensions :
Естественно искать способ предоставить доступ к коду условия, оставленному инструкцией ассемблера.Однако, когда мы попытались реализовать это, мы не нашли способа заставить его работать надежно.Проблема в том, что выходные операнды могут нуждаться в перезагрузке, что приведет к дополнительным следующим инструкциям «сохранения».На большинстве машин эти инструкции изменяют код условия до того, как появится время для его проверки.Эта проблема не возникает для обычных команд «тест» и «сравнение», потому что у них нет выходных операндов.
РЕДАКТИРОВАТЬ: Я не могу найти источник, который так или иначе указывает, можно ли изменять стек, также используя входные значения %N
( This Древняя ссылка гласит: «Вы даже можете поместить свои регистры в стек, использовать их и поместить обратно», но в примере нет входных данных).
Но можно обойтись без фиксации значений в других регистрах:
int sbcas(uint64_t* ptr, uint64_t oldval, uint64_t newval)
{
int changed = 0;
__asm__ (
"push %%ebx\n\t" // -fPIC uses ebx
"mov %%edi, %%ebx\n\t" // load ebx with needed value
"lock\n\t"
"cmpxchg8b (%%esi)\n\t"
"setz %%al\n\t" // eax potentially modified anyway
"movzx %%al, %1\n\t"
"pop %%ebx\n\t"
: "+S" (ptr), "=a" (changed)
: "0" (ptr), "d" ((uint32_t)(oldval >> 32)), "a" ((uint32_t)(oldval & 0xffffffff)), "c" ((uint32_t)(newval >> 32)), "D" ((uint32_t)(newval & 0xffffffff))
: "flags", "memory"
);
return changed;
}