3 #include <minix/type.h>
4 #include <minix/const.h>
6 #include <minix/syslib.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 */
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
) {
35 if((hdr
->e_type
!= ET_EXEC
) && (hdr
->e_type
!= ET_DYN
)) {
39 if ((hdr
->e_phoff
> SECTOR_SIZE
) ||
40 (hdr
->e_phoff
+ hdr
->e_phentsize
* hdr
->e_phnum
) > SECTOR_SIZE
) {
42 printf("libexec: peculiar phoff\n");
50 static int elf_ph_sane(Elf_Phdr
*phdr
)
52 if (rounddown((uintptr_t)phdr
, sizeof(Elf_Addr
)) != (uintptr_t)phdr
) {
58 static int elf_unpack(char *exec_hdr
,
59 size_t hdr_len
, Elf_Ehdr
**hdr
, Elf_Phdr
**phdr
)
61 if(hdr_len
< sizeof(Elf_Ehdr
))
64 *hdr
= (Elf_Ehdr
*) exec_hdr
;
68 *phdr
= (Elf_Phdr
*)(exec_hdr
+ (*hdr
)->e_phoff
);
69 if(!elf_ph_sane(*phdr
)) {
73 if((int)((*phdr
) + (*hdr
)->e_phnum
) >= hdr_len
) return ENOEXEC
;
78 #define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
79 (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
80 (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
81 (ehdr).e_ident[EI_MAG3] == ELFMAG3)
83 static int check_header(Elf_Ehdr
*hdr
)
86 hdr
->e_ident
[EI_DATA
] != ELF_TARG_DATA
||
87 hdr
->e_ident
[EI_VERSION
] != EV_CURRENT
||
88 hdr
->e_phentsize
!= sizeof(Elf_Phdr
) ||
89 hdr
->e_version
!= ELF_TARG_VER
)
95 /* Return >0 if there is an ELF interpreter (i.e. it is a dynamically linked
96 * executable) and we could extract it successfully.
97 * Return 0 if there isn't one.
100 int elf_has_interpreter(char *exec_hdr
, /* executable header */
101 size_t hdr_len
, char *interp
, size_t maxsz
)
103 Elf_Ehdr
*hdr
= NULL
;
104 Elf_Phdr
*phdr
= NULL
;
107 if((e
=elf_unpack(exec_hdr
, hdr_len
, &hdr
, &phdr
)) != OK
) return 0;
109 for (i
= 0; i
< hdr
->e_phnum
; i
++) {
110 switch (phdr
[i
].p_type
) {
112 if(!interp
) return 1;
113 if(phdr
[i
].p_filesz
>= maxsz
)
115 if(phdr
[i
].p_offset
+ phdr
[i
].p_filesz
>= hdr_len
)
117 memcpy(interp
, exec_hdr
+ phdr
[i
].p_offset
, phdr
[i
].p_filesz
);
118 interp
[phdr
[i
].p_filesz
] = '\0';
127 int libexec_load_elf(struct exec_info
*execi
)
129 Elf_Ehdr
*hdr
= NULL
;
130 Elf_Phdr
*phdr
= NULL
;
133 vir_bytes startv
= 0, stacklow
;
135 assert(execi
!= NULL
);
136 assert(execi
->hdr
!= NULL
);
138 if((e
=elf_unpack(execi
->hdr
, execi
->hdr_len
, &hdr
, &phdr
)) != OK
) {
142 /* this function can load the dynamic linker, but that
143 * shouldn't require an interpreter itself.
145 i
= elf_has_interpreter(execi
->hdr
, execi
->hdr_len
, NULL
, 0);
150 execi
->stack_size
= roundup(execi
->stack_size
, PAGE_SIZE
);
151 execi
->stack_high
= rounddown(execi
->stack_high
, PAGE_SIZE
);
152 stacklow
= execi
->stack_high
- execi
->stack_size
;
154 assert(execi
->copymem
);
155 assert(execi
->clearmem
);
156 assert(execi
->allocmem_prealloc_cleared
);
157 assert(execi
->allocmem_prealloc_junk
);
158 assert(execi
->allocmem_ondemand
);
160 for (i
= 0; i
< hdr
->e_phnum
; i
++) {
161 Elf_Phdr
*ph
= &phdr
[i
];
162 off_t file_limit
= ph
->p_offset
+ ph
->p_filesz
;
163 /* sanity check binary before wiping out the target process */
164 if(execi
->filesize
< file_limit
) {
169 if(execi
->clearproc
) execi
->clearproc(execi
);
171 for (i
= 0; i
< hdr
->e_phnum
; i
++) {
172 vir_bytes seg_membytes
, page_offset
, p_vaddr
, vaddr
;
173 vir_bytes chunk
, vfileend
, vmemend
;
174 off_t foffset
, fbytes
;
175 Elf_Phdr
*ph
= &phdr
[i
];
179 int mmap_prot
= PROT_READ
;
182 printf("libexec: -------------------\n");
183 printf("libexec: phdr %x (%d)\n", (uint32_t)ph
, i
);
185 if(!(ph
->p_flags
& PF_R
)) {
186 printf("libexec: warning: unreadable segment\n");
189 if(ph
->p_flags
& PF_W
) {
190 mmap_prot
|= PROT_WRITE
;
192 printf("libexec: adding PROT_WRITE\n");
196 printf("libexec: not adding PROT_WRITE\n");
200 if (ph
->p_type
!= PT_LOAD
|| ph
->p_memsz
== 0) continue;
202 if((ph
->p_vaddr
% PAGE_SIZE
) != (ph
->p_offset
% PAGE_SIZE
)) {
203 printf("libexec: unaligned ELF program?\n");
211 foffset
= ph
->p_offset
;
212 fbytes
= ph
->p_filesz
;
213 vaddr
= p_vaddr
= ph
->p_vaddr
+ execi
->load_offset
;
214 seg_membytes
= ph
->p_memsz
;
216 page_offset
= vaddr
% PAGE_SIZE
;
217 vaddr
-= page_offset
;
218 foffset
-= page_offset
;
219 seg_membytes
+= page_offset
;
220 fbytes
+= page_offset
;
221 vfileend
= p_vaddr
+ ph
->p_filesz
;
223 /* if there's usable memory after the file end, we have
224 * to tell VM to clear the memory part of the page when it's
227 if((pagechunk
= (vfileend
% PAGE_SIZE
))
228 && ph
->p_filesz
< ph
->p_memsz
) {
229 clearend
= PAGE_SIZE
- pagechunk
;
232 seg_membytes
= roundup(seg_membytes
, PAGE_SIZE
);
233 fbytes
= roundup(fbytes
, PAGE_SIZE
);
235 if(first
|| startv
> vaddr
) startv
= vaddr
;
238 if ((ph
->p_flags
& PF_X
) != 0 && execi
->text_size
< seg_membytes
)
239 execi
->text_size
= seg_membytes
;
241 execi
->data_size
= seg_membytes
;
243 if(try_mmap
&& execi
->memmap(execi
, vaddr
, fbytes
, foffset
, clearend
, mmap_prot
) == OK
) {
245 printf("libexec: mmap 0x%lx-0x%llx done, clearend 0x%x\n",
246 vaddr
, vaddr
+fbytes
, clearend
);
249 if(seg_membytes
> fbytes
) {
250 int rem_mem
= seg_membytes
- fbytes
;;
251 vir_bytes remstart
= vaddr
+ fbytes
;
252 if(execi
->allocmem_ondemand(execi
,
253 remstart
, rem_mem
) != OK
) {
254 printf("libexec: mmap extra mem failed\n");
258 else printf("libexec: allocated 0x%lx-0x%lx\n",
260 remstart
, remstart
+rem_mem
);
264 /* make us some memory */
265 if(execi
->allocmem_prealloc_junk(execi
, vaddr
, seg_membytes
) != OK
) {
266 if(execi
->clearproc
) execi
->clearproc(execi
);
271 printf("libexec: mmapped 0x%lx-0x%lx\n", vaddr
, vaddr
+seg_membytes
);
274 /* Copy executable section into it */
275 if(execi
->copymem(execi
, ph
->p_offset
, p_vaddr
, ph
->p_filesz
) != OK
) {
276 if(execi
->clearproc
) execi
->clearproc(execi
);
281 printf("libexec: copied 0x%lx-0x%lx\n", p_vaddr
, p_vaddr
+ph
->p_filesz
);
284 /* Clear remaining bits */
285 vmemend
= vaddr
+ seg_membytes
;
286 if((chunk
= p_vaddr
- vaddr
) > 0) {
288 printf("libexec: start clearing 0x%lx-0x%lx\n", vaddr
, vaddr
+chunk
);
290 execi
->clearmem(execi
, vaddr
, chunk
);
293 if((chunk
= vmemend
- vfileend
) > 0) {
295 printf("libexec: end clearing 0x%lx-0x%lx\n", vfileend
, vfileend
+chunk
);
297 execi
->clearmem(execi
, vfileend
, chunk
);
302 /* Make it a stack */
303 if(execi
->allocmem_ondemand(execi
, stacklow
, execi
->stack_size
) != OK
) {
304 if(execi
->clearproc
) execi
->clearproc(execi
);
309 printf("libexec: stack mmapped 0x%lx-0x%lx\n", stacklow
, stacklow
+execi
->stack_size
);
312 /* record entry point and lowest load vaddr for caller */
313 execi
->pc
= hdr
->e_entry
+ execi
->load_offset
;
314 execi
->load_base
= startv
;