제
This presentation is the property of its rightful owner.
Sponsored Links
1 / 40

exec() PowerPoint PPT Presentation


  • 89 Views
  • Uploaded on
  • Presentation posted in: General

제 30 강 : exec(). exec(). EXECVE(2) Linux Programmer's Manual EXECVE(2) NAME execute program SYNOPSIS #include <unistd.h> int execve (const char *filename , char *const argv [], char *const envp []); DESCRIPTION

Download Presentation

exec()

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


Exec

제30강 : exec()

exec()


Exec

EXECVE(2) Linux Programmer's Manual EXECVE(2)

NAME execute program

SYNOPSIS

#include <unistd.h>

int execve (const char*filename, char *constargv [], char *constenvp[]);

DESCRIPTION

execve() executes the program pointed to by filename must be either abinary

executable, or a script starting with a line of the form "#! interpreter [arg]". ….

argv is an array of argument strings passed to the new program.

envp is an array of strings, conventionally of the form key=value, which are passed

as environment to the new program.

Both, argv and envp must be terminated by null pointer. The argument

vector and environment can be accessed by the called program's main function,

when it is defined as int main(int argc, char *argv[], char *envp[]).

execve() does not return on success, and the text, data, bss, and stack of the

calling process are overwritten by that of the program loaded. The program invoked

inherits the calling process's PID, and any open file descriptors that are not set to

close on exec.

Parent passes arguments to child

Child’s a.out

(env_var_name, env_var_value)

(child program will invoke exit() system call at termination -- compiler puts it)


Parent sh

main() {

loop:

printf (prompt)

scanf (eg cat ch1 ch2 > ch12)

pid=fork()

if (child)

exec(“/bin/cat”)

else /* parent */

wait()

go to top

}

(1)prompt %

(2) command % cat ch1 ch2> ch3

command line argument

parent sh


Parent sh1

main() {

loop:

printf (prompt)

scanf (eg cat ch1 ch2 > ch12)

pid=fork()

if (child)

exec(“/bin/cat”)

else /* parent */

wait()

go to top

}

(1)prompt %

(2) command % cat ch1 ch2> ch3

command line argument

parent sh

parent’s

variable


Parent sh2

main() {

loop:

printf (prompt)

scanf (eg cat ch1 ch2 > ch12)

pid=fork()

if (child)

exec(“/bin/cat”)

else /* parent */

wait()

go to top

}

child sh

parent sh

main() {

loop:

printf (prompt)

scanf (eg cat ch1 ch2 > ch12)

pid=fork()

if (child)

exec(“/bin/cat”)

else /* parent */

wait()

go to top

}


Parent sh3

main() {

loop:

printf (prompt)

scanf (eg cat ch1 ch2 > ch12)

pid=fork()

if (child)

exec(“/bin/cat”)

else /* parent */

wait()

go to top

}

child sh

parent sh

main() {

loop:

printf (prompt)

scanf (eg cat ch1 ch2 > ch12)

pid=fork()

if (child)

exec(“/bin/cat”)

else /* parent */

wait()

go to top

}


Exec

cat ch1 ch2

fork()

call newproc()

newproc()

copy proc

copy image

rerturn(0)

exec()

overlay

wait()

swtch()

parent retire

proc[0]

child arise

return(1)

{

sh (parent)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

2

sh

{

to create

a child

1

{

{


Exec

copy parent’s image

fork()

call newproc()

newproc()

copy proc

copy image

rerturn(0)

exec()

overlay

wait()

swtch()

parent retire

proc[0]

child arise

return(1)

sh (parent)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

Stack:

sub-shell (child)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

Stack:

2

sh

1

3*

Also copy parent’s ppda

entered newproc()

entered fork()

entered newproc()

entered fork()

3*child created (ready)


Exec

fork()

call newproc()

newproc()

copy proc

copy image

rerturn(0)

exec()

overlay

wait()

swtch()

parent retire

proc[0]

child arise

return(1)

sub-shell (child)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

Stack:

sh (parent)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

sh

5

1

child (sub-shell)

created

4

entered newproc()

entered fork()

3*child created (ready)


Exec

fork()

call newproc()

newproc()

copy proc

copy image

rerturn(0)

exec()

overlay

wait()

swtch()

parent retire

proc[0]

child arise

return(1)

sh (parent)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

sh (child)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

Stack:

sh

5

1

6

entered newproc()

entered fork()

parent wants

to rest

6*

3*child created (ready)

7*pop return address

12* exec() at 10 is done

back to user mode


Exec

fork()

call newproc()

newproc()

copy proc

copy image

rerturn(0)

exec()

overlay

wait()

swtch()

parent retire

proc[0]

child arise

return(1)

sh (parent)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

sh (child)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

Stack:

sh

1

entered newproc()

entered fork()

3*child created (ready)

7*pop return address

12* exec() at 10 is done

back to user mode

Child runs

on CPU


Exec

fork()

call newproc()

newproc()

copy proc

copy image

rerturn(0)

exec()

overlay

wait()

swtch()

parent retire

proc[0]

child arise

return(1)

sh (parent)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

sh (child)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

Stack:

sh

8

pop & returns

to fork()

entered newproc()

entered fork()

3*child created (ready)

7*pop return address

12* exec() at 10 is done

back to user mode

7*


Exec

fork()

call newproc()

return

newproc()

copy proc

copy image

rerturn(0)

exec()

overlay

wait()

swtch()

parent retire

proc[0]

child arise

return(1)

sh (parent)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

sh (child)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

Stack:

sh

9-1

finish kernel mode

9-2

return to where?

same place as parent

entered fork()

On return from fork()

kernel stack

becomes empty

9-3

3*child created (ready)

7*pop return address

12* exec() at 10 is done

back to user mode


Exec

fork()

call newproc()

newproc()

copy proc

copy image

rerturn(0)

exec()

overlay

wait()

swtch()

parent retire

proc[0]

child arise

return(1)

sh (parent)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

sh (child)

main()

{

If (PID=fork())

PID=0 exec() /*child*/

PID<>0 wait() /*parent*/

Stack

sh

Return from fork()

PID = = 0 for child

3*child created (ready)

7*pop return address

12* exec() at 10 is done

back to user mode


Exec

fork()

call newproc()

newproc()

copy proc

copy image

rerturn(0)

exec()

overlay

wait()

swtch()

parent retire

proc[0]

child arise

return(1)

sh (parent)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

sh (child)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

Stack

sh

10

entered exec()

kernel stack changes

3*child created (ready)

7*pop return address

12* exec() at 10 is done

back to user mode


Exec

cat ch1 ch2

fork()

call newproc()

newproc()

copy proc

copy image

rerturn(0)

exec()

overlay

wait()

swtch()

parent retire

proc[0]

child arise

return(1)

sh (parent)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

sh (child)

main()

{

If (PID=fork())

PID=0exec( ) /*child*/

PID<>0 wait() /*parent*/

sh

cat ch1

10

parameters of exec( )

exec (pathname, argv, envp)

3*child created (ready)

7*pop return address

12* exec() at 10 is done

back to user mode


Exec

cat ch1 ch2

fork()

call newproc()

newproc()

copy proc

copy image

rerturn(0)

exec()

overlay

wait()

swtch()

parent retire

proc[0]

child arise

return(1)

sh (parent)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

sh (child)

main()

{

If (PID=fork())

PID=0exec( ) /*child*/

PID<>0 wait() /*parent*/

Stack:

sh

cat ch1

10

entered exec()

11

cat

3*child created (ready)

7*pop return address

12* exec() at 10 is done

back to user mode


Exec

cat ch1 ch2

fork()

call newproc()

newproc()

copy proc

copy image

rerturn(0)

exec()

overlay

wait()

swtch()

parent retire

proc[0]

child arise

return(1)

sh (parent)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

cat (child)

main()

{

Stack:

sh

new code cat

empty

user stack

11

cat

3*child created (ready)

7*pop return address

12* exec() at 10 is done

back to user mode


Exec

P A

P A

fork

P A

exec

P’A

P B

(New a.out )

  • To create a new process:

    • Allocate & init proc[], ready queue --- fork()

    • Allocate & init swappable image

    • load a.out from disk (overlay) --- exec()

    • init user stack for main(argv, envp)

    • Start from main()


Algorithm of exec

Algorithm of exec()

  • load a.out from disk (overlay)

  • init user stack for main(argv, envp)

  • Start from main()

Get pathname “/bin/cat”

Get inode

Is this file executable?

….

Copy argv, envp from caller to kernel

(first, allocate kernel buffer, then copy)

Copy argv, envp from buf to child’s stack

(as passing para to main())

... Yes .. it is like an IPC .. kernel in between


Exec

  • 3034 get pathname, map it to inode pointer

    • uchar() (7686)function name alone=pointer to function, “goto u & get char”

    • returns string (defining pathname)

    • pointed to by u -> u.u_dirp: value of 1st argument (pathname)

    • namei() (7518)maps:[pathname -> *inode]

  • 3041 Is it executable?

    • access() (6732)

    • check mode permission (r_w_x) -- return(1) on error (6779)


Prepare to read by readi readi parameters 6221

prepare to read by readi()readi( ) parameters6221

  • from (file, offset)  to (address, count)

    ip u_offset u_base u_count

[3] Memory

Address?

u_base

[1] Which file?

Inode

(ip)

[4] How many?

u_count

[2] file offset

u_offset


Exec

  • 3086 prepare to read executable file (6221 readi() needs them)

    • Read first (u_offset = 0) 8 bytes (u_count=8)

    • u_base is destination address (6216) set to &u.u_arg[0]

    • i.e. “read into u_arg[0]”

    • read 1st 8 bytes into u.u_arg[0] (u_base=u_uarg[0])

    • readi()  w0: file type, w1/w2/w3: sizes of each segments

  • 3095 check file type (pure code - separate text & data?)


A out format

a.out format

w0

w1

8 bytes

magic number

text size

data size

bss size

symbol table size

entry point

relo. info.

w2

w3

“Magic number”first few bytes of executable file

Binary Standard“COFF & ELF” (trend – ELF supports dynamic libraries)

ScriptIf first 2 bytes is # ! – pathname of interpreter

(from BSD --- to Linux)


8 words

8 words

  • We just read 8 bytes from a.out

  • and we checked file type

  • We need to read body of a.out

  • First, need to allocate memory space

  • So find out the size of text, data segment

  • 3129adjust memory space according to the finding

  • expand()

  • xalloc() is at 4433 and is for shared code

  • address of user space is now determined

  • 3138 estabur() again (save addresses in struct u)

  • prepare to read a.out file – read the rest of a.out

  • parameters for readi()

  • 3142 read data segment (i.e. main body of a.out)

u.u_arg[]


Exec

Passing arguments

to child process


Exec

EXECVE(2) Linux Programmer's Manual EXECVE(2)

NAME execute program

SYNOPSIS

#include <unistd.h>

int execve (const char*filename, char *constargv [], char *constenvp[]);

DESCRIPTION

execve() executes the program pointed to by filename must be either abinary

executable, or a script starting with a line of the form "#! interpreter [arg]". ….

argv is an array of argument strings passed to the new program.

envp is an array of strings, conventionally of the form key=value, which are passed

as environment to the new program.

Both, argv and envp must be terminated by null pointer. The argument

vector and environment can be accessed by the called program's main function,

when it is defined as int main(int argc, char *argv[], char *envp[]).

execve() does not return on success, and the text, data, bss, and stack of the

calling process are overwritten by that of the program loaded. The program invoked

inherits the calling process's PID, and any open file descriptors that are not set to

close on exec.

Parent passes arguments to child

Child’s a.out

(env_var_name, env_var_value)

(child program will invoke exit() system call at termination -- compiler puts it)


Exec

cat ch1 ch2

fork()

call newproc()

newproc()

copy proc

copy image

rerturn(0)

exec()

overlay

wait()

swtch()

parent retire

proc[0]

child arise

return(1)

sh (parent)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

sh (child)

main()

{

If (PID=fork())

PID=0exec( ) /*child*/

PID<>0 wait() /*parent*/

sh

sh

cat ch1 ch2

cat ch1 ch2

10

3*child created (ready)

7*pop return address

12* exec() at 10 is done

back to user mode


Exec

cat ch1 ch2

fork()

call newproc()

newproc()

copy proc

copy image

rerturn(0)

exec()

overlay

wait()

swtch()

parent retire

proc[0]

child arise

return(1)

sh (parent)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

cat (child)

main()

{

Stack:

sh

cat

Overlay

11

cat

3*child created (ready)

7*pop return address

12* exec() at 10 is done

back to user mode


Exec

We just read a.out file from disk, Next, copy argv & envp

(1)

Parent sh forks child sh

(2)

Child sh calls exec()

(3) exec()

Kernel:

struct user

k-stack

Kernel

a.out

copy

to

kernel

buffer

copy

from

kernel

buffer

struct user

k-stack

(0)

cat

argv

a.out

Parent

sh

copy argv, envp

from child-sh’s user var

to kernel buffer

load cat a.out

overwriting shell

copy argv, envp

from kernel buffer

to child’s user stack

<3-1>

u--stack

(1)

argv

envp

<3-2>

(2)

(4)

struct user

k-stack

struct user

k-stack

load

overlay

a.out

cat

a.out

<3-3>

Child

sub-sh

(3)

u--stack

u--stack

cat


Exec

  • bp=getblk()

  • (4921) allocate a kernel buffer (from buffer cache)

  • 3049 Copy from caller to buffer (3049 3052 3059 ..)

    • Remaining sys call arguments, following pathname

    • (filename,argv, envp, ….)

    • 3049 cp points to actual kernel buffer (not buffer header)

    • 3052 ap = fuword();  3058 c =fubyte(ap++);

    • 3059 for ( ) {c= fubyte(ap++); /* byte from parent’s image*/

      • (*cp++ = c) /* exec() sys call arg  into kernel buffer */

      • until ( c = = 0) at 3067

  • We must copy (argv, envp) into kernel buffer.

  • BEFORE loading new a.out image from disk.

  • because current user image is being overwritten during loading


Exec

  • Now new image has been read from disk (at 3142)

  • 3153 Copy from buffer to new user process stack

    • 3153cp points to actual kernel buffer (not header)

    • 3161while {

    • 3161 subyte(c++, *cp); /* store byte into user space */

  • Eventually, the system call arguments are moved

    • from previous user image

    •  kernel buffer

    • new image’s user stack


Algorithm of exec1

Algorithm of exec()

  • load a.out from disk (overlay)

  • init user stack for main (path, argv, envp)

  • Start from main()

Copy argv, envp from sub-shell to kernel

(first, allocate kernel buffer, then copy)

Copy them from kernel to new a.out’s user stack

(as arguments to main())

... Yes .. it is like an IPC .. kernel in between

Read new a.out

(Overlay old a.out)


Exec

1. Makes proc[0] then

call newproc() to make proc #1

2. Alloc & copy proc[1]

alloc & copy image for proc #1

10. swtch() becomes

proc #0 which

selects next job

retu (sh)

4. Return(0) from newproc()

Call sched() .. swtch()

saveu()

main()

proc 0

8. init creates sh

for terminals

9. swtch()

proc 1

7. exec init, i.e.

load & run init

3. Proc #1 is

created & is in

Ready state

6. Copy array to

user space & jump

11. sh runs

sh is created

ready queue

(Continued)

sh

5. retu(), return(1)

from newproc() to main


Exec

User types “cat” at shell prompt …

Parent invokes

wait() sys call

Creates child

fork()

7. Returns from swtch()

1. Calls swtch()

5 End of cat code

exit () sys call

 swtch()

sh

(parent)

2. scheduler

proc #0

3. within swtch()

calls retu (child)

child is dispatched

6. scheduler chooses

parent sh

retu (sh)

child-sh is

created & is in

Ready state

cat

(child)

4. child returns from swtch()

returns from fork()

child-sh exec(“bin/cat)

User mode

Kernel mode


Exec

Creates child

fork()

6 Returns from swtch()

1. Calls swtch()

sh

(parent)

4 calls swtch()

2. scheduler

proc #0

3. cat dispatched

5. scheduler

cat

(child)

Coroutine Calls:

sh

cat

swtch()

swtch()

User mode

Kernel mode

cat

sh


Exec

Creates child cat

6 Returns from swtch()

1. Calls swtch()

sh

(parent)

4 calls swtch()

2. scheduler

proc #0

3. cat dispatched

5. scheduler

cat

(child)

Retiring

sh

cat

OS sched

swtch()

swtch()

User mode

Kernel mode

Arising

cat

sh


Exec

Fork() creates child

Later exit() syscall

calls swtch()

wait() sys call

which calls swtch()

sh

(parent)

2. scheduler

proc #0

3. Child is dispatched

cat

(child)

sh

exec

cat

child: main(argv )

{ finds out argv= cat any

fork()

exec(cat)

pass “any” as argv to Pcat

}

User mode

Kernel mode


Exec

fork()

call newproc()

newproc()

copy proc

copy image

rerturn(0)

exec()

overlay

wait()

swtch()

parent retire

proc[0]

child arise

return(1)

sh (parent)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

sh (child)

main()

{

If (PID=fork())

PID=0exec () /*child*/

PID<>0 wait() /*parent*/

Stack:

overlay

new a.out (child)

main()

exit()

2

9

sh

5

1

3*

4

10

6

8

entered newproc()

entered fork()

11

12*

6*

3*child created (ready)

7*pop return address

12* exec() at 10 is done

back to user mode

cat

13

7*


  • Login