-
Notifications
You must be signed in to change notification settings - Fork 0
/
loader.c
144 lines (111 loc) · 3.04 KB
/
loader.c
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
* Loader Implementation
*
* 2022, Operating Systems
*/
#include <signal.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/stat.h>
#include "exec_parser.h"
#define page_size getpagesize()
static so_exec_t *exec;
static int fd;
static struct sigaction old_action; /* Default handler */
static void segv_handler(int signum, siginfo_t *info, void *context)
{
int i, page_index, seg_index, page_to_read = 0, offset = 0;
int *data, paging;
so_seg_t segment;
/* Checking if the signal is SIGSEGV */
if (signum != SIGSEGV) {
old_action.sa_sigaction(signum, info, context);
return;
}
/* Calculating the segment which caused SIGSEGV */
for (i = 0; i < exec->segments_no; i++) {
if (exec->segments[i].mem_size + exec->segments[i].vaddr > (uintptr_t)info->si_addr)
break;
}
seg_index = i;
segment = exec->segments[seg_index];
/* If the address of the segment which caused SIGSEGV is not found -> default handler */
if (seg_index == exec->segments_no) {
old_action.sa_sigaction(signum, info, context);
return;
}
/* Calculating the page fault index */
page_index = ((uintptr_t)info->si_addr - segment.vaddr) / page_size;
data = (int *) segment.data;
/* If the page is already mapped in memory -> default handler */
if(data[page_index] == 1) {
old_action.sa_sigaction(signum, info, context);
return;
}
/* If it is not mapped, we map it in memory using *data */
data[page_index] = 1;
paging = page_index * page_size;
offset = segment.offset + paging;
page_to_read = segment.file_size - paging;
/* Mapping the page */
void *addr = mmap ((void *)(segment.vaddr + paging), page_size, PROT_WRITE,
MAP_ANONYMOUS | MAP_FIXED | MAP_SHARED, -1, 0);
/* Checking if the the mapping has worked */
if (!addr)
return;
/* Finding the amount of data to read from page in memory */
if (page_to_read > 0)
page_to_read = ((page_size < page_to_read) ? page_size : page_to_read);
else
page_to_read = 0;
if (page_to_read != 0) {
lseek(fd, offset, SEEK_SET);
read(fd, addr, page_to_read);
}
/* Setting permissions */
if (mprotect(addr, page_size, segment.perm) == -1)
return;
}
int so_init_loader(void)
{
int rc;
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = segv_handler;
sa.sa_flags = SA_SIGINFO;
rc = sigaction(SIGSEGV, &sa, NULL);
if (rc < 0) {
perror("sigaction");
return -1;
}
return 0;
}
int so_execute(char *path, char *argv[])
{
int pages;
fd = open(path, O_RDONLY);
if (fd < 0)
return -1;
exec = so_parse_exec(path);
if (!exec)
return -1;
/* Calculating no of pages for every segment and allocating data */
for (int i = 0; i < exec->segments_no; i++) {
pages = exec->segments[i].mem_size / page_size;
if(!exec->segments[i].data)
exec->segments[i].data = malloc(pages * sizeof(int));
}
so_start_exec(exec, argv);
for (int i = 0; i < exec->segments_no; i++)
free(exec->segments[i].data);
free(exec->segments);
free(exec);
free(path);
close(fd);
return -1;
}