9 typedef struct Elfhdr Elfhdr
;
10 typedef struct Proghdr Proghdr
;
11 typedef struct ElfEx ElfEx
;
59 if(n
= (pagealign(addr
) - addr
))
60 memset((void*)addr
, 0, n
);
72 /* machine architectures */
83 /* program segment types */
93 /* program segment flags */
100 loadelf(char *file
, ElfEx
*ex
, int depth
)
117 if((fd
= sys_open(file
, O_RDONLY
, 0)) < 0){
118 werrstr("cant open %s", file
);
122 if(sys_read(fd
, &hdr
, sizeof(hdr
)) != sizeof(hdr
)){
123 werrstr("cant read elf header");
127 if(memcmp(hdr
.ident
, "\x7fELF", 4)!=0){
128 werrstr("no elf magic");
132 l
= hdr
.phnum
* hdr
.phentsize
;
134 sys_lseek(fd
, hdr
.phoff
, 0);
135 if(sys_read(fd
, phdr
, l
) != l
){
136 werrstr("cant read program headers");
142 mapflags
= MAP_PRIVATE
;
143 if(hdr
.type
!= ElfTShared
)
144 mapflags
|= MAP_FIXED
;
146 trace("loadelf(): phnum=%d", hdr
.phnum
);
149 for(i
=0; i
<hdr
.phnum
; i
++){
153 if(p
->type
== ElfPInterp
){
155 werrstr("multiple interpeter sections");
160 interpreter
= kmalloc(l
+1);
161 sys_lseek(fd
, p
->offset
, 0);
162 if(sys_read(fd
, interpreter
, l
)!=l
){
163 werrstr("cant read interpreter section");
166 interpreter
[l
] = '\0';
169 if(p
->type
== ElfPLoad
){
173 trace("loadelf(): phdr %d: vaddr=%lux memsz=%lux filesz=%lux offset=%lux flags=%lux",
182 if(p
->flags
& ElfPFR
)
183 mapprot
|= PROT_READ
;
184 if(p
->flags
& ElfPFW
)
185 mapprot
|= PROT_WRITE
;
186 if(p
->flags
& ElfPFX
)
187 mapprot
|= PROT_EXEC
;
189 if(hdr
.entry
>= p
->vaddr
&& hdr
.entry
< p
->vaddr
+ p
->memsz
)
190 mapprot
|= PROT_EXEC
;
192 diff
= p
->vaddr
- (p
->vaddr
& ~(PAGESIZE
-1));
194 /* have to call mapdata() before we do the first mmap */
195 if(loadaddr
== 0 && depth
== 0){
196 if(hdr
.type
== ElfTShared
){
197 mapbase
= pagealign((ulong
)end
+ 0x4000000);
198 mapflags
|= MAP_FIXED
;
200 mapdata((mapbase
+ p
->vaddr
) - diff
);
204 (mapbase
+ p
->vaddr
) - diff
,
209 (p
->offset
- diff
)/PAGESIZE
);
211 if(((int)a
< 0) && ((int)a
> -EMAX
)){
212 werrstr("mmap failed: %E", (int)a
);
217 if(hdr
.type
== ElfTShared
&& mapbase
== 0){
219 mapflags
|= MAP_FIXED
;
221 if(mapprot
& PROT_WRITE
)
222 padzero(mapbase
+ p
->vaddr
+ p
->filesz
);
224 if(mapbase
+ p
->vaddr
+ p
->memsz
> bss
)
225 bss
= mapbase
+ p
->vaddr
+ p
->memsz
;
227 trace("loadelf(): phdr %d: type=%lux", i
, p
->type
);
232 ex
->entry
= hdr
.entry
+ ((hdr
.type
== ElfTShared
) ? loadaddr
: 0);
234 ex
->phdr
= loadaddr
+ hdr
.phoff
;
235 ex
->phent
= hdr
.phentsize
;
236 ex
->phnum
= hdr
.phnum
;
239 sys_brk(pagealign(bss
));
241 current
->codestart
= loadaddr
;
242 current
->codeend
= bss
;
248 if(loadelf(interpreter
, &interpex
, depth
+1) < 0){
249 werrstr("cant load interpreter: %r");
254 ex
->ientry
= interpex
.entry
;
255 ex
->ibase
= interpex
.base
;
257 ex
->ientry
= ex
->entry
;
258 ex
->ibase
= 0; /* no interpreter */
296 AT_SYSINFO_EHDR
= 33,
300 setupstack(ElfEx
*ex
, char *argv
[], char *envp
[])
314 * calculate the size we need on stack
317 while(argv
&& argv
[argc
]) argc
++;
320 while(envp
&& envp
[envc
]) envc
++;
323 n
+= sizeof(ulong
); // argc
324 n
+= (argc
+1)*sizeof(char*); // argv + nil
325 n
+= (envc
+1)*sizeof(char*); // envp + nil
326 n
+= 16*(2*sizeof(ulong
)); // aux
328 for(i
=0; i
<argc
; i
++)
329 n
+= (strlen(argv
[i
])+1);
330 for(i
=0; i
<envc
; i
++)
331 n
+= (strlen(envp
[i
])+1);
333 if(USTACK
- n
< PAGESIZE
){
334 werrstr("too many arguments passed on stack");
338 stack
= mapstack(USTACK
);
340 if(((int)stack
< 0) && ((int)stack
> -EMAX
)){
341 werrstr("mapstack failed: %E", (int)stack
);
344 stack
= (ulong
*)(((ulong
)stack
- n
) & ~7);
346 current
->stackstart
= (ulong
)stack
;
358 #define AUXENT(k, v) {p[0]=k; p[1]=v; p+=2;}
359 AUXENT(AT_PAGESZ
, PAGESIZE
);
360 AUXENT(AT_CLKTCK
, HZ
);
361 AUXENT(AT_PHDR
, ex
->phdr
);
362 AUXENT(AT_PHENT
, ex
->phent
);
363 AUXENT(AT_PHNUM
, ex
->phnum
);
364 AUXENT(AT_BASE
, ex
->ibase
);
366 AUXENT(AT_ENTRY
, ex
->entry
);
367 AUXENT(AT_UID
, current
->uid
);
368 AUXENT(AT_EUID
, current
->uid
);
369 AUXENT(AT_GID
, current
->gid
);
370 AUXENT(AT_EGID
, current
->gid
);
379 for(i
=0; i
<argc
; i
++)
380 x
+= (strlen(dargv
[i
] = strcpy(x
, argv
[i
])) + 1);
382 for(i
=0; i
<envc
; i
++)
383 x
+= (strlen(denv
[i
] = strcpy(x
, envp
[i
])) + 1);
390 copystrings(char *a
[])
401 n
+= sizeof(a
[0]) + (strlen(a
[i
]) + 1);
408 p
+= strlen(r
[i
] = strcpy(p
, a
[i
]))+1;
414 setcomm(char *exe
, char *name
, char *argv
[])
419 n
= strlen(exe
) + strlen(name
) +2;
420 for(i
=0; argv
[i
]; i
++)
421 n
+= strlen(argv
[i
])+1;
426 p
+= strlen(strcpy(p
, name
));
427 for(i
=0; argv
[i
]; i
++){
428 p
+= strlen(strcpy(p
, " "));
429 p
+= strlen(strcpy(p
, argv
[i
]));
433 /* comm contains the full exe name + argv */
435 p
+= strlen(strcpy(p
, exe
));
437 for(i
=0; argv
[i
]; i
++){
438 p
+= strlen(strcpy(p
, argv
[i
]));
445 current
->ncomm
= p
- buf
;
449 clinote(struct Ureg
*ureg
)
461 notejmp(ureg
, jmp
, 1);
480 struct kexecveargs
*args
;
485 char *b
, *p
, *e
, *x
, **a
;
503 if(r
= sys_access(name
, 05)){
508 if((r
= sys_open(name
, O_RDONLY
, 0)) < 0)
511 if(f
= fdgetfile(r
)){
513 strncpy(p
, f
->path
, e
-p
);
514 p
+= strlen(exe
= p
)+1;
518 n
= sys_read(r
, p
, (e
-p
)-1);
525 if(memcmp(p
, "#!", 2) == 0){
529 if((x
= strchr(p
, '\n')) == nil
)
534 n
= (e
- (char*)a
) / sizeof(a
[0]);
537 n
= getfields(&p
[2], a
, n
, 1, "\t\r\n ");
541 if(&a
[n
+1] >= (char**)e
)
547 if(&a
[n
+1] >= (char**)e
)
562 if(memcmp(p
, "\x7fELF", 4)!=0)
566 * the contents on envp[] or argv[] maybe stored in b[], stack or bss of the calling linux
567 * process that is destroyed on free(b) and exitmem()... so we need to temporary
571 name
= kstrdup(name
);
574 argv
= copystrings(argv
);
577 envp
= copystrings(envp
);
580 /* get out of the note before we destroy user stack */
582 clinote(current
->ureg
);
586 /* this is the point of no return! */
599 setcomm(exe
, name
, argv
);
601 if(loadelf(name
, &ex
, 0) < 0){
602 trace("kexecve(): loadelf failed: %r");
606 if((stack
= setupstack(&ex
, argv
, envp
)) == nil
){
607 trace("kexecve(): setupstack failed: %r");
611 memset(&u
, 0, sizeof(u
));
613 u
.pc
= (ulong
)ex
.ientry
;
615 current
->syscall
= nil
;
618 trace("kexecve(): startup pc=%lux sp=%lux", current
->ureg
->pc
, current
->ureg
->sp
);
629 case 3: exitproc(current
, SIGKILL
, 1);
634 int sys_execve(char *name
, char *argv
[], char *envp
[])
636 struct kexecveargs args
;
638 trace("sys_execve(%s, %p, %p)", name
, argv
, envp
);
644 return onstack(kstack
, kexecve
, &args
);