Jak o następujących, które wydaje się działać dla mnie w małym teście:
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;
}
Jeśli ta również zostanie miscompiled mógłbyś to niewielki fragment, który wyzwala to zachowanie?
Jeśli chodzi o pytanie o bonus, nie sądzę, że możliwe jest rozgałęzienie po bloku asemblera przy użyciu kodu warunku z instrukcji cmpxchg8b
(chyba że używasz asm goto
lub podobnej funkcjonalności).Od GNU C Language Extensions:
Naturalnym pomysłem jest znalezienie sposobu na udostępnienie kodu warunku pozostawionego przez instrukcję assemblera. Jednak, gdy próbowaliśmy to wdrożyć, nie znaleźliśmy sposobu, aby sprawić, by działał on niezawodnie. Problem polega na tym, że operandy wyjściowe mogą wymagać ponownego załadowania, co skutkowałoby dodatkowymi instrukcjami "składowania". Na większości komputerów instrukcje te zmieniłyby kod warunków, zanim zdążyliby go przetestować. Ten problem nie występuje w przypadku zwykłych instrukcji "test" i "porównaj", ponieważ nie mają żadnych argumentów wyjściowych.
EDIT: Nie mogę znaleźć żadnego źródła, które określa jedną lub drugą stronę, czy to jest OK, aby zmodyfikować stos jednocześnie stosując wartości wejściowych %N
(This starożytny Link mówi „Można nawet naciskać na swoich rejestrów stos, użyj ich i odłóż. "ale przykład nie ma wejścia).
Ale to powinno być możliwe do zrobienia bez ustalając wartości do innych rejestrów:
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;
}
Fakt, że wewnętrzna kompilator nie działa z flagą -fPIC jest tylko płaska-out kompilator bug: http: //gcc.gnu.org/bugzilla/show_bug.cgi?id=37651 To jest do bani, gdy musisz obejść uszkodzony kompilator, więc możesz chcieć umieścić się na liście CC dla tego błędu. – Crashworks
Używasz '-fPIC' na IA32? Jestem ciekawy dlaczego. – Gabe
@Gabe - Najważniejsze przy pisaniu obiektów z biblioteki współdzielonej. Ulrich Drepper ma dobry artykuł na ten temat: http://www.akkadia.org/drepper/dsohowto.pdf – Crashworks