Tôi đã phát triển một thư viện xử lý tín hiệu SIGILL. Vì tôi muốn tránh sự phụ thuộc của libc, và sử dụng các syscalls Linux trực tiếp. Tôi nhận thấy rằng thư viện của tôi bị treo trên một số hệ thống Linux và sau rất nhiều lần gỡ lỗi, tôi thấy rằng việc sử dụng số sê-ri rt_sigaction
thay vì số sigaction
giải quyết được sự cố. Tuy nhiên, tôi không tìm thấy một mô tả về sự khác biệt giữa hai syscalls. Có ai trên SO biết các chi tiết cơ bản không?Sự khác biệt giữa tín hiệu và rt_signal syscalls trong Linux là gì?
Cập nhật: Tôi sử dụng trình xử lý tín hiệu để phát hiện hỗ trợ CPU cho một số tiện ích mở rộng hướng dẫn ARM, ví dụ: Hướng dẫn XScale MIATT
. Dưới đây là hướng dẫn chức năng thăm dò:
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;
}
Trong xử lý SIGILL tôi thúc đẩy PC
đăng ký bởi 4 byte (kích thước của hướng dẫn này), và thay đổi một trong những thanh ghi để cho biết rằng handler SIGILL được gọi. Đây là mã xử lý tín hiệ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;
}
Dưới đây là cách tôi làm thăm dò (hàm trả về 0 nếu lệnh không gây SIGILL, 1 nếu handler SIGILL được gọi, và 2 nếu sigaction syscall thất bại):
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;
}
}
đây là việc tôi triển khai chức năng sigaction syscall stub:
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;
}
Tôi đã thử nghiệm mã này trong trình giả lập từ Android SDK (qemu) và trên Pandaboard chạy Ubuntu. Trong giả lập mã chạy tốt (cả khi mô phỏng CPU ARM9 và Cortex-A8), nhưng trên Pandaboard nó treo trên hướng dẫn MIATT nếu tôi sử dụng __NR_sigaction: có vẻ như sau khi trình xử lý tín hiệu mã không bỏ qua 4 byte, nhưng chạy cùng một hướng dẫn.
Tôi đoán phiên bản 'rt_sigaction' là phiên bản" thời gian thực ". Có nghĩa là nó được thiết kế để có thời gian gọi xác định. –
Đây là gần như chính xác cùng một mã, cả hai đất tại do_sigaction() trong hạt nhân. Nếu bạn đang gặp vấn đề, nó có lẽ sẽ giúp chi tiết chúng. –
Tôi đã thêm chi tiết và phần có liên quan của mã của tôi vào câu hỏi. –