Opracowałem bibliotekę, która obsługuje sygnały SIGILL. Ponieważ chcę uniknąć zależności od libc i bezpośrednio korzystać z Linuksa. Zauważyłem, że moja biblioteka zawiesza się na niektórych systemach Linux, a po wielu debugowaniach odkryłem, że używanie rt_sigaction
syscall zamiast sigaction
rozwiązuje problem. Jednak nie znalazłem opisu różnicy między tymi dwoma systemami. Czy ktokolwiek na SO zna podstawowe szczegóły?Jaka jest różnica między syscalls sygnału i rt_signal w systemie Linux?
Aktualizacja: Używam programów obsługi sygnału do wykrywania obsługi procesorów dla niektórych rozszerzeń instrukcji ARM, np. XScale instrukcja MIATT
. Oto funkcja sondowania instrukcja:
static uint32_t probe_xscale() {
register uint32_t retValue asm("r0") = 0;
asm volatile (
// Equivalent of the following code:
// ".arch xscale\n"
// "MIATT acc0, r0, r0;"
// If the next line raises SIGILL, the signal handle will change r0 to 1 and skip the instruction (4 bytes)
"MCR P0, 0x1, r0, c15, c0, 0;"
: "+r" (retValue)
:
:
);
return retValue;
}
W obsługi SIGILL I awansować rejestr PC
przez 4 bajty (rozmiar instrukcji) i zmienić jedną z rejestrów wskazują, że SIGILL obsługi została wywołana. Oto kod obsługi sygnału.
static void probe_signal_handler(int, siginfo_t *, void* ptr) {
ucontext_t* ctx = (ucontext_t*)ptr;
ctx->uc_mcontext.arm_pc += 4;
ctx->uc_mcontext.arm_r0 = 1;
}
Oto jak zrobić to sondowanie (funkcja zwraca 0, jeśli instrukcja nie powoduje SIGILL 1 jeśli SIGILL obsługi nazwano i 2, jeżeli sigaction syscall nie powiodło się):
static uint32_t probeInstruction(uint32_t (*ProbeFunction)()) {
struct sigaction oldSigillAction;
struct sigaction probeSigillAction;
memset(&probeSigillAction, 0, sizeof(probeSigillAction));
probeSigillAction.sa_sigaction = &probe_signal_handler;
// Needs Linux >= 2.2
probeSigillAction.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
int sigactionResult = _syscall_sigaction(SIGILL, &probeSigillAction, &oldSigillAction);
if (sigactionResult == 0) {
const uint32_t probeResult = ProbeFunction();
_syscall_sigaction(SIGILL, &oldSigillAction, NULL);
return probeResult;
} else {
return 2;
}
}
Tutaj moja realizacja sigaction funkcji syscall skrótowej:
static int _syscall_sigaction(int signum, const struct sigaction *new_action, struct sigaction *old_action) __attribute__((noinline));
static int _syscall_sigaction(int signalNumberParameter, const struct sigaction *newActionParameter, struct sigaction *oldActionParameter) {
register int result asm ("r0");
register int signalNumber asm ("r0") = signalNumberParameter;
register const struct sigaction *newAction asm ("r1") = newActionParameter;
register struct sigaction *oldAction asm ("r2") = oldActionParameter;
register int syscallNumber asm ("r7") = __NR_rt_sigaction;
asm volatile (
"swi $0;"
: "=r" (result)
: "r" (signalNumber), "r" (newAction), "r" (oldAction), "r" (syscallNumber)
:
);
return result;
}
testowałem ten kod w emulatorze z Android SDK (qemu), a na Pandaboard Ubuntu. W emulatorze kod działa dobrze (zarówno podczas emulacji ARM9, jak i Cortex-A8), ale na Pandaboard zawiesza się na instrukcji MIATT, jeśli używam __NR_sigaction: wydaje się, że po obsłudze sygnału kod nie pomija 4 bajtów, ale działa ta sama instrukcja.
Zgaduję, że wersja 'rt_sigaction' jest wersją" w czasie rzeczywistym ". Oznacza to, że projekt ma deterministyczny czas połączenia. –
Są to prawie dokładnie ten sam kod, oba grunty w do_sigaction() w jądrze. Jeśli masz problemy, prawdopodobnie pomoże to je wyszczególnić. –
Dodałem więcej szczegółów i odpowiednią część mojego kodu do pytania. –