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("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 int hdr_len
, Elf_Ehdr
**hdr
, Elf_Phdr
**phdr
)
61 *hdr
= (Elf_Ehdr
*) exec_hdr
;
65 *phdr
= (Elf_Phdr
*)(exec_hdr
+ (*hdr
)->e_phoff
);
66 if(!elf_ph_sane(*phdr
)) {
70 if((int)((*phdr
) + (*hdr
)->e_phnum
) >= hdr_len
) return ENOEXEC
;
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
)
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
)
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.
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
;
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
) {
109 if(!interp
) return 1;
110 if(phdr
[i
].p_filesz
>= maxsz
)
112 if(phdr
[i
].p_offset
+ phdr
[i
].p_filesz
>= hdr_len
)
114 memcpy(interp
, exec_hdr
+ phdr
[i
].p_offset
, phdr
[i
].p_filesz
);
115 interp
[phdr
[i
].p_filesz
] = '\0';
124 int libexec_load_elf(struct exec_info
*execi
)
126 Elf_Ehdr
*hdr
= NULL
;
127 Elf_Phdr
*phdr
= NULL
;
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
) {
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);
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_cleared
);
154 assert(execi
->allocmem_prealloc_junk
);
155 assert(execi
->allocmem_ondemand
);
157 for (i
= 0; i
< hdr
->e_phnum
; i
++) {
158 Elf_Phdr
*ph
= &phdr
[i
];
159 off_t file_limit
= ph
->p_offset
+ ph
->p_filesz
;
160 /* sanity check binary before wiping out the target process */
161 if(execi
->filesize
< file_limit
) {
166 if(execi
->clearproc
) execi
->clearproc(execi
);
168 for (i
= 0; i
< hdr
->e_phnum
; i
++) {
169 vir_bytes seg_membytes
, page_offset
, p_vaddr
, vaddr
;
170 vir_bytes chunk
, vfileend
, vmemend
;
171 off_t foffset
, fbytes
;
172 Elf_Phdr
*ph
= &phdr
[i
];
176 int mmap_prot
= PROT_READ
;
178 if(!(ph
->p_flags
& PF_R
)) {
179 printf("libexec: warning: unreadable segment\n");
182 if(ph
->p_flags
& PF_W
) {
183 mmap_prot
|= PROT_WRITE
;
185 printf("libexec: adding PROT_WRITE\n");
189 printf("libexec: not adding PROT_WRITE\n");
193 if (ph
->p_type
!= PT_LOAD
|| ph
->p_memsz
== 0) continue;
195 if((ph
->p_vaddr
% PAGE_SIZE
) != (ph
->p_offset
% PAGE_SIZE
)) {
196 printf("libexec: unaligned ELF program?\n");
204 foffset
= ph
->p_offset
;
205 fbytes
= ph
->p_filesz
;
206 vaddr
= p_vaddr
= ph
->p_vaddr
+ execi
->load_offset
;
207 seg_membytes
= ph
->p_memsz
;
209 page_offset
= vaddr
% PAGE_SIZE
;
210 vaddr
-= page_offset
;
211 foffset
-= page_offset
;
212 seg_membytes
+= page_offset
;
213 fbytes
+= page_offset
;
214 vfileend
= p_vaddr
+ ph
->p_filesz
;
216 /* if there's usable memory after the file end, we have
217 * to tell VM to clear the memory part of the page when it's
220 if((pagechunk
= (vfileend
% PAGE_SIZE
))
221 && ph
->p_filesz
< ph
->p_memsz
) {
222 clearend
= PAGE_SIZE
- pagechunk
;
225 seg_membytes
= roundup(seg_membytes
, PAGE_SIZE
);
226 fbytes
= roundup(fbytes
, PAGE_SIZE
);
228 if(first
|| startv
> vaddr
) startv
= vaddr
;
231 if ((ph
->p_flags
& PF_X
) != 0 && execi
->text_size
< seg_membytes
)
232 execi
->text_size
= seg_membytes
;
234 execi
->data_size
= seg_membytes
;
236 if(try_mmap
&& execi
->memmap(execi
, vaddr
, fbytes
, foffset
, clearend
, mmap_prot
) == OK
) {
238 printf("libexec: mmap 0x%lx-0x%lx done, clearend 0x%x\n",
239 vaddr
, vaddr
+fbytes
, clearend
);
242 if(seg_membytes
> fbytes
) {
243 int rem_mem
= seg_membytes
- fbytes
;;
244 vir_bytes remstart
= vaddr
+ fbytes
;
245 if(execi
->allocmem_ondemand(execi
,
246 remstart
, rem_mem
) != OK
) {
247 printf("libexec: mmap extra mem failed\n");
251 else printf("libexec: allocated 0x%lx-0x%lx\n",
253 remstart
, remstart
+rem_mem
);
257 /* make us some memory */
258 if(execi
->allocmem_prealloc_junk(execi
, vaddr
, seg_membytes
) != OK
) {
259 if(execi
->clearproc
) execi
->clearproc(execi
);
264 printf("mmapped 0x%lx-0x%lx\n", vaddr
, vaddr
+seg_membytes
);
267 /* Copy executable section into it */
268 if(execi
->copymem(execi
, ph
->p_offset
, p_vaddr
, ph
->p_filesz
) != OK
) {
269 if(execi
->clearproc
) execi
->clearproc(execi
);
274 printf("copied 0x%lx-0x%lx\n", p_vaddr
, p_vaddr
+ph
->p_filesz
);
277 /* Clear remaining bits */
278 vmemend
= vaddr
+ seg_membytes
;
279 if((chunk
= p_vaddr
- vaddr
) > 0) {
281 printf("start clearing 0x%lx-0x%lx\n", vaddr
, vaddr
+chunk
);
283 execi
->clearmem(execi
, vaddr
, chunk
);
286 if((chunk
= vmemend
- vfileend
) > 0) {
288 printf("end clearing 0x%lx-0x%lx\n", vfileend
, vfileend
+chunk
);
290 execi
->clearmem(execi
, vfileend
, chunk
);
295 /* Make it a stack */
296 if(execi
->allocmem_ondemand(execi
, stacklow
, execi
->stack_size
) != OK
) {
297 if(execi
->clearproc
) execi
->clearproc(execi
);
302 printf("stack mmapped 0x%lx-0x%lx\n", stacklow
, stacklow
+execi
->stack_size
);
305 /* record entry point and lowest load vaddr for caller */
306 execi
->pc
= hdr
->e_entry
+ execi
->load_offset
;
307 execi
->load_base
= startv
;