1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
| | #include <stdlib.h>
#include <stdint.h>
#include <sys/mman.h>
#include "libc.h"
#include "lock.h"
#include "fork_impl.h"
#define malloc __libc_malloc
#define calloc __libc_calloc
#define realloc undef
#define free undef
static struct fl
{
struct fl *next;
struct fl_pair {
void (*f)(void *);
void *a;
} pairs[];
} *head;
static int slot;
static size_t slot_max;
static volatile int lock[1];
volatile int *const __atexit_lockptr = lock;
void __funcs_on_exit()
{
void (*func)(void *), *arg;
LOCK(lock);
for (; head; head=head->next, slot=slot_max) {
struct fl *next = head->next;
while(slot-->0) {
func = head->pairs[slot].f;
arg = head->pairs[slot].a;
UNLOCK(lock);
func(arg);
LOCK(lock);
}
munmap(head, PAGE_SIZE);
head = next;
}
}
void __cxa_finalize(void *dso)
{
}
int __cxa_atexit(void (*func)(void *), void *arg, void *dso)
{
struct fl *cursor;
LOCK(lock);
/* Figure out how many slots we can have per page: page size minus one pointer then divided by two for function-argument pairs. */
slot_max = (PAGE_SIZE - sizeof(void *)) / sizeof(struct fl_pair);
/* Determine if a new allocation is necessary. */
if (!head || slot == slot_max)
cursor = 0;
else
cursor = head;
/* If a new allocation is necessary, allocate it read-write, otherwise make the current atexit list read-write. */
if (!cursor) {
cursor = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
if (cursor == MAP_FAILED) {
UNLOCK(lock);
return -1;
}
cursor->next = head;
head = cursor;
slot = 0;
} else if (mprotect(cursor, PAGE_SIZE, PROT_READ | PROT_WRITE)) {
UNLOCK(lock);
return -1;
}
/* Append function to the list. */
cursor->pairs[slot].f = func;
cursor->pairs[slot].a = arg;
slot++;
/* Mark the atexit list read-only to avoid its abuse. */
if (mprotect(cursor, PAGE_SIZE, PROT_READ)) {
UNLOCK(lock);
return -1;
}
UNLOCK(lock);
return 0;
}
static void call(void *p)
{
((void (*)(void))(uintptr_t)p)();
}
int atexit(void (*func)(void))
{
return __cxa_atexit(call, (void *)(uintptr_t)func, 0);
}
|