summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2022-02-16 12:25:14 -0500
committerpommicket <pommicket@gmail.com>2022-02-16 12:25:14 -0500
commit408e9b0e81342b1e65870f35fc5e4e8b566c9c69 (patch)
tree0860f281a2efca0f553c820b80737dfc5ffca4d1
parent42911ccf67dd13293d332e75d6d7772c8ebb9fb8 (diff)
start signal.h
-rw-r--r--05/constants.b2
-rw-r--r--05/main.c9
-rw-r--r--05/setjmp.h2
-rw-r--r--05/signal.h85
4 files changed, 96 insertions, 2 deletions
diff --git a/05/constants.b b/05/constants.b
index 5027198..dc0d21e 100644
--- a/05/constants.b
+++ b/05/constants.b
@@ -5,7 +5,7 @@
; read-only data 4MB addresses 0x800000-0xbfffff
; read-write data 4MB addresses 0xc00000-0xffffff
; note that file offsets and runtime addresses are the same.
-; you should be able to change these constants (in a way that's consistent) without breaking anything:
+; if you want to change these constants, make sure you update signal.h's _SIGNAL_HANDLERS!
#define ENTRY_ADDR 0x200000
#define FUNCTIONS_ADDR 0x400000
#define FUNCTIONS_END 0x800000
diff --git a/05/main.c b/05/main.c
index 5f57418..1420330 100644
--- a/05/main.c
+++ b/05/main.c
@@ -1,9 +1,16 @@
#define _STDLIB_DEBUG
#include <math.h>
#include <stdio.h>
+#include <signal.h>
+
+void test_signal_handler(int x) {
+ printf("interompu\n");
+ _Exit(0);
+}
int main(int argc, char **argv) {
- printf("%.16g\n", cosh(10));
+ signal(SIGINT, test_signal_handler);
+ while (1){}
return 0;
}
diff --git a/05/setjmp.h b/05/setjmp.h
new file mode 100644
index 0000000..ad74d75
--- /dev/null
+++ b/05/setjmp.h
@@ -0,0 +1,2 @@
+// @NONSTANDARD
+#error "longjmp is not supported."
diff --git a/05/signal.h b/05/signal.h
new file mode 100644
index 0000000..dc10e41
--- /dev/null
+++ b/05/signal.h
@@ -0,0 +1,85 @@
+#ifndef _SIGNAL_H
+#define _SIGNAL_H
+
+
+#include <stdc_common.h>
+
+typedef long sig_atomic_t; // there are no "asynchronous interrupts"
+
+#define SIG_DFL 0
+#define SIG_IGN _sig_ign
+#define SIG_ERR (-1)
+
+typedef void (*_Sighandler)(int);
+
+struct sigaction {
+ void (*handler)(int);
+ unsigned long flags;
+ void (*restorer)(void);
+ unsigned long mask;
+};
+
+unsigned char _signal_restorer[] = {
+ 0x48,0xb8,15,0,0,0,0,0,0,0, // mov rax, 15 (sigreturn)
+ 0x0f,0x05 // syscall
+};
+
+#define _SIGNAL_HANDLERS 0xfff000
+#define _LE64(x) (x)&0xff, ((x)>> 8)&0xff, ((x)>>16)&0xff, ((x)>>24)&0xff, \
+ ((x)>>32)&0xff, ((x)>>40)&0xff, ((x)>>48)&0xff, (x)>>56
+
+// we need to do this weird indirection because linux has a different
+// calling convention from us.
+unsigned char _signal_handler[] = {
+ // signal # passed in rdi
+ 0x48,0x89,0xf8, // mov rax, rdi (signal #)
+ 0x50, // push rax
+ 0x50, // push rax (allocate space for return value)
+ 0x48,0xb8,_LE64(_SIGNAL_HANDLERS), // mov rax, _SIGNAL_HANDLERS
+ 0x48,0x89,0xc3, // mov rbx, rax
+ 0x48,0x89,0xf8, // mov rax, rdi (signal #)
+ 0x48,0xc1,0xe0,0x03, // shl rax, 3
+ 0x48,0x01,0xd8, // add rax, rbx
+ 0x48,0x89,0xc3, // mov rbx, rax
+ 0x48,0x8b,0x03, // mov rax, [rbx]
+ 0xff,0xd0, // call rax
+ 0x48,0x81,0xc4,16,0,0,0, // add rsp, 16
+ 0xc3 // ret
+};
+
+#define _SA_RESTORER 0x04000000
+
+int __sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) {
+ return __syscall(13, signum, act, oldact, 8, 0, 0);
+}
+
+
+void _sig_ign(int signal) {
+ return;
+}
+
+static unsigned long _sig_mask = 0;
+
+_Sighandler signal(int sig, _Sighandler func) {
+ if (func == SIG_DFL) {
+ // @TODO
+ return 0;
+ }
+ if (func == SIG_IGN) {
+ func = _sig_ign;
+ }
+
+ void **handlers = _SIGNAL_HANDLERS;
+ handlers[sig] = func;
+
+ _sig_mask |= 1ul << (sig-1);
+ struct sigaction act = {0};
+ act.handler = _signal_handler;
+ act.mask = _sig_mask;
+ act.flags = _SA_RESTORER;
+ act.restorer = _signal_restorer;
+ __sigaction(sig, &act, NULL);
+ return 0;//@TODO
+}
+
+#endif // _SIGNAL_H