pkgin_all: script to auto-install all packages
[minix.git] / lib / libexec / exec_elf.c
blob625b3f0873acc364f099ed27ad929fabdeda279a
1 #define _SYSTEM 1
3 #include <minix/type.h>
4 #include <minix/const.h>
5 #include <minix/com.h>
6 #include <minix/syslib.h>
7 #include <sys/param.h>
8 #include <sys/mman.h>
9 #include <assert.h>
10 #include <unistd.h>
11 #include <errno.h>
12 #include <libexec.h>
13 #include <string.h>
14 #include <machine/elf.h>
15 #include <machine/vmparam.h>
16 #include <machine/memory.h>
17 #include <minix/syslib.h>
19 /* For verbose logging */
20 #define ELF_DEBUG 0
22 /* Support only 32-bit ELF objects */
23 #define __ELF_WORD_SIZE 32
25 #define SECTOR_SIZE 512
27 static int check_header(Elf_Ehdr *hdr);
29 static int elf_sane(Elf_Ehdr *hdr)
31 if (check_header(hdr) != OK) {
32 return 0;
35 if((hdr->e_type != ET_EXEC) && (hdr->e_type != ET_DYN)) {
36 return 0;
39 if ((hdr->e_phoff > SECTOR_SIZE) ||
40 (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > SECTOR_SIZE) {
41 #if ELF_DEBUG
42 printf("peculiar phoff\n");
43 #endif
44 return 0;
47 return 1;
50 static int elf_ph_sane(Elf_Phdr *phdr)
52 if (rounddown((uintptr_t)phdr, sizeof(Elf_Addr)) != (uintptr_t)phdr) {
53 return 0;
55 return 1;
58 static int elf_unpack(char *exec_hdr,
59 int hdr_len, Elf_Ehdr **hdr, Elf_Phdr **phdr)
61 *hdr = (Elf_Ehdr *) exec_hdr;
62 if(!elf_sane(*hdr)) {
63 return ENOEXEC;
65 *phdr = (Elf_Phdr *)(exec_hdr + (*hdr)->e_phoff);
66 if(!elf_ph_sane(*phdr)) {
67 return ENOEXEC;
69 #if 0
70 if((int)((*phdr) + (*hdr)->e_phnum) >= hdr_len) return ENOEXEC;
71 #endif
72 return OK;
75 #define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
76 (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
77 (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
78 (ehdr).e_ident[EI_MAG3] == ELFMAG3)
80 static int check_header(Elf_Ehdr *hdr)
82 if (!IS_ELF(*hdr) ||
83 hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
84 hdr->e_ident[EI_VERSION] != EV_CURRENT ||
85 hdr->e_phentsize != sizeof(Elf_Phdr) ||
86 hdr->e_version != ELF_TARG_VER)
87 return ENOEXEC;
89 return OK;
92 /* Return >0 if there is an ELF interpreter (i.e. it is a dynamically linked
93 * executable) and we could extract it successfully.
94 * Return 0 if there isn't one.
95 * Return <0 on error.
97 int elf_has_interpreter(char *exec_hdr, /* executable header */
98 int hdr_len, char *interp, int maxsz)
100 Elf_Ehdr *hdr = NULL;
101 Elf_Phdr *phdr = NULL;
102 int e, i;
104 if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) return 0;
106 for (i = 0; i < hdr->e_phnum; i++) {
107 switch (phdr[i].p_type) {
108 case PT_INTERP:
109 if(!interp) return 1;
110 if(phdr[i].p_filesz >= maxsz)
111 return -1;
112 if(phdr[i].p_offset + phdr[i].p_filesz >= hdr_len)
113 return -1;
114 memcpy(interp, exec_hdr + phdr[i].p_offset, phdr[i].p_filesz);
115 interp[phdr[i].p_filesz] = '\0';
116 return 1;
117 default:
118 continue;
121 return 0;
124 int libexec_load_elf(struct exec_info *execi)
126 Elf_Ehdr *hdr = NULL;
127 Elf_Phdr *phdr = NULL;
128 int e, i = 0;
129 int first = 1;
130 vir_bytes startv = 0, stacklow;
132 assert(execi != NULL);
133 assert(execi->hdr != NULL);
135 if((e=elf_unpack(execi->hdr, execi->hdr_len, &hdr, &phdr)) != OK) {
136 return e;
139 /* this function can load the dynamic linker, but that
140 * shouldn't require an interpreter itself.
142 i = elf_has_interpreter(execi->hdr, execi->hdr_len, NULL, 0);
143 if(i > 0) {
144 return ENOEXEC;
147 execi->stack_size = roundup(execi->stack_size, PAGE_SIZE);
148 execi->stack_high = rounddown(execi->stack_high, PAGE_SIZE);
149 stacklow = execi->stack_high - execi->stack_size;
151 assert(execi->copymem);
152 assert(execi->clearmem);
153 assert(execi->allocmem_prealloc);
154 assert(execi->allocmem_ondemand);
156 for (i = 0; i < hdr->e_phnum; i++) {
157 Elf_Phdr *ph = &phdr[i];
158 off_t file_limit = ph->p_offset + ph->p_filesz;
159 /* sanity check binary before wiping out the target process */
160 if(execi->filesize < file_limit) {
161 return ENOEXEC;
165 if(execi->clearproc) execi->clearproc(execi);
167 for (i = 0; i < hdr->e_phnum; i++) {
168 vir_bytes seg_membytes, page_offset, p_vaddr, vaddr;
169 vir_bytes chunk, vfileend, vmemend;
170 Elf_Phdr *ph = &phdr[i];
171 if (ph->p_type != PT_LOAD || ph->p_memsz == 0) continue;
172 vaddr = p_vaddr = ph->p_vaddr + execi->load_offset;
173 seg_membytes = ph->p_memsz;
174 page_offset = vaddr % PAGE_SIZE;
175 vaddr -= page_offset;
176 seg_membytes += page_offset;
177 seg_membytes = roundup(seg_membytes, PAGE_SIZE);
178 if(first || startv > vaddr) startv = vaddr;
179 first = 0;
181 /* make us some memory */
182 if(execi->allocmem_prealloc(execi, vaddr, seg_membytes) != OK) {
183 if(execi->clearproc) execi->clearproc(execi);
184 return ENOMEM;
187 #if ELF_DEBUG
188 printf("mmapped 0x%lx-0x%lx\n", vaddr, vaddr+seg_membytes);
189 #endif
191 /* Copy executable section into it */
192 if(execi->copymem(execi, ph->p_offset, p_vaddr, ph->p_filesz) != OK) {
193 if(execi->clearproc) execi->clearproc(execi);
194 return ENOMEM;
197 #if ELF_DEBUG
198 printf("copied 0x%lx-0x%lx\n", p_vaddr, p_vaddr+ph->p_filesz);
199 #endif
201 /* Clear remaining bits */
202 vfileend = p_vaddr + ph->p_filesz;
203 vmemend = vaddr + seg_membytes;
204 if((chunk = p_vaddr - vaddr) > 0) {
205 #if ELF_DEBUG
206 printf("start clearing 0x%lx-0x%lx\n", vaddr, vaddr+chunk);
207 #endif
208 execi->clearmem(execi, vaddr, chunk);
210 if((chunk = vmemend - vfileend) > 0) {
211 #if ELF_DEBUG
212 printf("end clearing 0x%lx-0x%lx\n", vfileend, vaddr+chunk);
213 #endif
214 execi->clearmem(execi, vfileend, chunk);
218 /* Make it a stack */
219 if(execi->allocmem_ondemand(execi, stacklow, execi->stack_size) != OK) {
220 if(execi->clearproc) execi->clearproc(execi);
221 return ENOMEM;
224 #if ELF_DEBUG
225 printf("stack mmapped 0x%lx-0x%lx\n", stacklow, stacklow+execi->stack_size);
226 #endif
228 /* record entry point and lowest load vaddr for caller */
229 execi->pc = hdr->e_entry + execi->load_offset;
230 execi->load_base = startv;
232 return OK;