Creation of processes and loading of executable programs

Source: Internet
Author: User
Tags strtok terminates volatile cpu usage

http://blog.csdn.net/q_l_s/article/details/52597330

First, the process of testing
Programming to implement a simple shell program

Click (here) to collapse or open

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <sys/types.h>
  6. #define NUM 1024
  7. int Mystrtok (char *argv[], char* string)
  8. {//Traversal string, intercept each character string between spaces, save into parameter array argv
  9. int i=0;
  10. Char delim[]= "";
  11. Argv[0] = strtok (String,delim);//string strings are divided into fragments according to the spacer Delim
  12. while (Argv[i]!=null)
  13. {
  14. Argv[++i] = strtok (Null,delim);
  15. }
  16. return 0;
  17. }
  18. int main ()
  19. {
  20. Char Str[num];
  21. int status;
  22. pid_t pid;
  23. char * argv[num];
  24. while (1)
  25. {
  26. printf ("n$:");
  27. Fgets (Str,num,stdin);//read command characters from the keyboard until line breaks are encountered
  28. Str[strlen (str) -1]= ' 0 ';//Add string Terminator ' 0 ' to the string read
  29. Status = Mystrtok (ARGV,STR);//intercept commands and parameters in argv array
  30. if (status!=0)//Intercept failed
  31. {
  32. printf ("Fail to get command!\n");
  33. }
  34. PID = fork ();
  35. if (pid==-1)
  36. printf ("fork failure!\n");
  37. else if (pid==0)//child process
  38. {
  39. EXECVP (ARGV[0],ARGV);
  40. EXECVP () finds the file name that matches the parameter argv[0] from the directory that the PATH environment variable refers to, executes the file after it is found, and then passes the second argument argv to the file that you want to execute
  41. }
  42. else//Parent Process
  43. {
  44. Wait ();
  45. }
  46. }
  47. }

The results of the operation are as follows:

Second, C Code embedded assembly code

1, C code embedded in the General Assembly code

Click (here) to collapse or open

  1. #include <stdio.h>
  2. int main ()
  3. {
  4. unsigned int val1=1;
  5. unsigned int val2=2;
  6. unsigned int val3=0;
  7. printf ("vala:%d,val2:%d,val3:%d\n", VAL1,VAL2,VAL3);
  8. ASM volatile (
  9. "Movl $0,%%eax\n\t"
  10. "Addl%1,%%eax\n\t"
  11. "Addl%2,%%eax\n\t"
  12. "Movl%%eax,%0\n\t"
  13. : "=m" (VAL3)
  14. : "C" (Val1), "D" (Val2)
  15. );
  16. printf ("val1:%d+val2:%d=val3:%d\n", VAL1,VAL2,VAL3);
  17. }


2, C code embedded system call assembly code

Click (here) to collapse or open

  1. #include <stdio.h>
  2. #include <time.h>
  3. int main ()
  4. {
  5. time_t tt;
  6. struct TM *t;
  7. int ret;
  8. #if 0
  9. Time (&TT);
  10. printf ("tt:%ld\n", TT);
  11. #else
  12. Do not use regular register%EBX to pass the parameter
  13. ASM volatile (
  14. "mov $0,%%ebx\n\t"//not using the Parameters TT
  15. "Mov $0xd,%%eax\n\t"
  16. "Int $0x80\n\t"
  17. "Mov%%eax,%0\n\t"
  18. : "=m" (TT)
  19. );
  20. printf ("tt:%ld\n", TT);
  21. T=localtime (&TT);
  22. printf ("time:%d:%d:%d:%d:%d:%d\n", t->tm_year+1900,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t- >TM_SEC);
  23. Using the general register%EBX to pass the parameter
  24. ASM volatile (
  25. "mov%1,%%ebx\n\t"//using the Parameters TT
  26. "Mov $0xd,%%eax\n\t"
  27. "Int $0x80\n\t"
  28. "Mov%%eax,%0\n\t"
  29. : "=m" (ret)
  30. : "B" (&TT)
  31. );
  32. printf ("tt:%ld\n", TT);
  33. T=localtime (&TT);
  34. printf ("time:%d:%d:%d:%d:%d:%d\n", t->tm_year+1900,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t- >TM_SEC);
  35. #endif
  36. return 0;
  37. }

First look at the assembly code of time, execute the time function in the code above, and then disassemble the following:

The GCC compiler also does not use the EBX register for the disassembly of time.
Then perform the test with the else part of the code above, as shown in the following example:

Output without%ebx the result of passing parameters is exactly the same as the result of running parameters with%EBX.

As we can see, the TIEM system call function does not use%EBX for parameter passing, and obviously does not follow the general method of system invocation parameter passing.

Iii. analyzing the execution of the fork and exec system calls in the kernel

1. Task_struct Process Control block

To describe and control the running of a process, the operating system defines a data structure for each process, the Process Control block (BLOCK,PCB). The process entity we usually call consists of a program segment, a data segment, and a three-part PCB. The PCB occupies an important position in the process entity. The so-called creation process is essentially the process of creating a PCB, while the undo process is essentially the revocation of the PCB. In the Linux kernel, the PCB corresponds to a specific structural body-task_struct, the so-called process descriptor (processes descriptor). The data structure contains all the information related to a process, such as a number of fields that describe the properties of the process, and pointers to other process-related structures. Include/linux/sched.h contains the definition of a struct task_struct:

There is a pointer to the mm_struct struct in the process descriptor, which is a description of the user space of the process, and a pointer to the fs_struct struct, which is a description of the current directory of the process, and a pointer to the Files_ Pointer to a struct struct file, which describes all the files that the process has opened, and a small process descriptor (low-level information)-thread_info. In this struct, there is also a pointer to the process descriptor task. Therefore, the two structures are interrelated.

Linux allocates a 8KB-sized memory area for each process to hold two different data structures for the process: Thread_info and the kernel stack of the process, as follows:



2, fork system call in the kernel of the execution process

When a fork system call is executed, the operating system performs the following actions:

(1) The kernel ensures that sufficient system resources are required to create a new process. The completion process is as follows:

The ① kernel ensures that the system can handle multiple processes that will be scheduled, and that the load on the scheduler can be managed.

The ② kernel ensures that this particular user is not currently running too many processes that monopolize the use of existing resources.

The ③ kernel ensures that sufficient memory space is provided for the new process.
The operating system already knows: the new process and the parent process are the same in every respect at this point. This also includes memory requirements. In a switching system, the entire memory is available. In a pure paging system, a large amount of memory space is required to hold the entire address space and the page map table. In the request paging schedule, the START process, at least the page map table is necessary. In the request paging method, more pages in the address space can be accumulated through page faults.
If there is not enough memory space, the kernel checks for space on the disk and, if so, occupies the swap area of that space. As discussed earlier in process state transitions, the status of child processes is determined accordingly.

(2) The kernel now finds a location from the process table and begins to construct the context of the child process.

(3) The kernel maintains the global value of the "Next available ID number". At any time, when the fork system calls to create a new process, the kernel assigns the ID to the new child process and adds 1 to the number. The kernel also sets a maximum value, and when the setting exceeds this value, the system cannot process any processes. If the number is equal to or greater than this maximum, the kernel will reassign the number from 0, but on the other hand the process that expects the PID to be equal to 0 has terminated.

(4) The kernel initializes the fields in the process table slot of the child process, as follows:

The ① kernel copies the actual valid user ID from the process table slot of the parent process to the corresponding location of the child process.

The ② kernel also copies the exact values of the parent process to the child process.

The ③ kernel links the child processes in the process tree structure by copying the parent process ID to the child process slot.

The ④ kernel initializes different scheduling fields and statistics fields in the child process slots, such as initial priority, CPU usage, and so on.

The ⑤ kernel sets the status of the child process to "creating".

(5) Now, the kernel searches the file descriptor in the parent process U zone (Process information interchange) and opens the file descriptor from the user to the file table entry along the pointer, increasing the reference count of those entries in the File table by 1.

(6) The kernel allocates memory space for the U-Zone, the Region table, the page table, etc. of the child process.

(7) The kernel now copies the U zone of the parent process to the child process, in addition to the appropriate adjustment of the pointer to the process table slot in the sub-process U area. This is because the parent and child processes have two different entries in the process table. As a result, pointers to these two different entries are not the same. At this point, all other content is the same.

(8) The kernel copies the data and the stack area (non-shared parts) to another memory area of the child process and adjusts the region table entry. However, it only saves a copy of the text area because the text area is shared. As shown, the text now contains the same program code.

(9) The kernel creates dynamic content after the static part of the child process context. It copies the parent process context that contains the first layer of the register and kernel stack that holds the fork system call. At this point, the contents of the kernel stack of the parent and child processes are exactly the same.

(10) The kernel creates a pseudo-program context at layer 2nd of the child process, which includes the 1th-level saved register context. It sets the program counter (PC) and other registers in the register content save area so that the child process can be "restarted" at the appropriate location.

(11) The kernel now changes the child process state from ready to ready to run (either in memory or in exchange, depending on the situation). It returns the child process ID to the user.

(12) The scheduler finally dispatches the child process. In the program, the scheduler checks that it is not a child process. Because if it is a child process, it executes an "Exec" system call, which loads the new program into the child process's address space. The next section describes the system call "Exec". Gives the copied process address space (including the shared text area), the U-zone (including the same pointer to the file table), the kernel stack, and so on.

3, EXEC system call in the kernel of the execution process

The kernel implements this system call by following these steps:

(1) The Exec system call requires an executable file name in the form of a parameter and stores the parameter for future use. Along with the file name, additional parameters are provided and stored, for example, if the shell command is "ls-l", then LS is the file name, and the-l as an option is stored together for future use.

(2) Now, the kernel parses the file pathname to get the index node number of the file. Then, access and read the index node. The kernel knows that for any shell command, it first searches in the/bin directory.

(3) The kernel determines the user class (owner, group, or other). You then get the Execute (X) permission on the user class of the executable file from the index node. The kernel checks whether the process is authorized to execute the file. If not, the kernel prompts for an error message and exits.

(4) If everything is OK, it accesses the header of the executable file.

(5) The kernel now loads the executable file of the program that it expects to use (for example, LS in this example) into the zone of the child process. However, the size of the different areas required for "LS" differs from the areas where the child processes already exist because they are copied from the parent process. Therefore, the kernel frees all the areas associated with the child process. This is the zone in which the new program in the executable image is ready to be loaded into the child process. Frees space after calling a storage parameter for the system that is only stored in memory. They are stored to avoid the "LS" executable code overwriting them and causing them to be lost. Store it in the right place, depending on how it is implemented. For example, if "LS" is a command, "-L" is its parameter, then "-l" is stored in the kernel area. The binary code of the "LS" utility in the/bin directory is the content that the kernel will load into the child process memory space.

(6) Then, the kernel queries the executable file (for example, LS) after the head of the mirror to allocate a new area of the desired size. At this point, establish a link between the regional table and the page map table.

(7) The kernel Associates these zones with sub-processes, which is the creation of links between the regional table and the P-zone table.

(8) The kernel then loads the contents of the actual zone into the allocated memory.

(9) The kernel creates a save register context using the Register initial value in the header of the executable file.

(10) At this point, the child process ("LS" program) has been run. Therefore, the kernel plugs into the appropriate location in the Ready process list based on the child process priority. Finally, the child process is dispatched.

(11) After the child process is dispatched, the context of the process is generated by the Save register context described in the preceding (9). Then, the PC, SP and so on have the correct value.

(12) The kernel then jumps to the address indicated by the PC. This is the address of the first executable instruction in the program to be executed. Now start a new program such as "LS". The kernel gets the parameters from the predetermined area stored in step (5) and generates the desired output. If the child process executes in the foreground, the parent process waits until the child process terminates, otherwise it continues execution.

(13) The child process terminates, into the zombie state, the expected use of the program has been completed. Now the kernel sends a signal to the parent process indicating "child process death" so that the parent process can now be awakened.

If the child process opens a new file, the user File descriptor table, open file list, and INODE tables structure of the child process are different from the parent process. If the child process calls another subroutine, the Execute/branch process is repeated. This creates a process structure at a different depth level.


Iii. analysis of the relationship between the elf file format and the process address space in the new process of fork generation


1, the virtual address space of the process

Each program has its own virtual address space, the size of which is determined by the hardware platform (number of CPU bits). Each program has 4G virtual space under a 32-bit platform. However, 4G space is not the user space allocated to the program, but also the virtual space of the system. As the Linux system by default high 1G is the virtual address space of the system, low 3G is the user space. This means that each process can use up to 3G of virtual space in principle.

2. Process loading

Overlay loading (Overlay) and page mapping (Paging) are two typical dynamic load methods. Now the former is no longer necessary.

Create a process, and then load the appropriate executable file and execute it. There are only three things to do at the beginning of the process:

① creates a separate virtual address space. The main assignment is a page directory.

② reads the header of the executable and establishes a mapping between the virtual space and the executable file. The main thing is to map the executable file to the virtual address space, that is, the mapping of the virtual page and the physical page so that it is loaded when "page faults".

The ③ sets the instruction register of the CPU to the entry address of the executable file and starts the operation. Start executing the program from the entry address in the Elf file.


3. Process Analysis

When executing a program under Bash, how does Linux load the elf file and execute it?
First bash calls the fork () system call to create a new process, and then the new process calls the EXECVE () system call to execute the specified elf file. The bash process continues to return waiting for the new process to finish executing, and then waits for the user to enter the command again. The EXECVE () system call is defined in Unistd.h, and its prototype is as follows:
int Execve (const char *filenarne, char *const argv[], char *const envp[]);
Its three parameters are executed by the program file name, execution parameters and environment change most. GLIBC EXECVP () system calls are packaged, providing 5 different forms of exec series APIs such as Execl (), EXECLP (), Execle (), Execv (), and EXECVP (), which differ only in the parameters of the call, But it will eventually be called to the Execve () system.

Call the EXECVE () system call, and then call the kernel's ingress Sys_execve (). Sys_execve () calls Do_execve () after some parameters are checked for replication. Because executables are more than just elf, there are Java programs and "#!" Start of the script and so on, so Do_execve () will first check the executed file, read the first 128 bytes, especially the beginning of 4 bytes of magic number, to determine the format of the executable file. If the script is an interpreted language, the first two bytes "#!" It makes up the magic number, and once the system determines the two bytes, the subsequent string is parsed to determine the path of the program interpreter.

When Do_execve () reads the 128-byte file header, then calls Search_binary_handle () to search for and match the appropriate executable file loading process. All supported executable formats in Linux have a corresponding loading process, and Search_binary_handle () determines the file's format by determining the number of magic in the head of the file, and invokes the appropriate loading process. such as Elf with Load_elf_binary (), a.out with Load_aout_binary (), script with Load_script (). The main steps of the elf loading process are:
① checks the validity of the elf executable format, such as the number of magic numbers and the middle of the program header (Segment).
② find the dynamically linked ". Interp" segment, which saves the path to the dynamic linker required by the executable, and sets the dynamic linker path.
③ maps elf files, such as code, data, and read-only data, according to the description of the Program Header table of the Elf executable.
④ initializes the ELF process environment, such as the address of the EDX register at the start of the process, which should be the address of the Dt_fini (end code address).
⑤ changes the return address of the system call to the entry point of the Elf executable, which depends on how the program is linked, and for statically linked elf executables, the entry is the address e_enery the file header of the Elf file, and for the dynamically linked elf executable file, The program entry point is a dynamic linker.
When the Elf is load_elf_binary () loaded, the function returns to Do_execve () in return to Sys_execve (). The return address of the system call in Load_elf_binary () (5th) has been changed to the entry address of the ELF program. So when the SYS_EXECVE () system call returns from the kernel state to the user state, the EIP register jumps directly to the ELF program's entry address, and the new program begins execution, and the elf executable is loaded.


Iv. experience of the experiment


In Unix, fork is the only way for a process to create another process. Only the first process that is called "Init" needs to be "created manually". All other processes are created with the fork, the system call. The fork system call simply replicates the data and stack of the parent process and shares the text area between the two processes. The fork system calls in a smarter way-"write-time copy (Copy-on-write)" technology, so that the fork after the end does not immediately copy the contents of the parent process, but to the real practical when the copy, so that the efficiency greatly improved. After the fork function creates a child process, the child process calls the Exec family function to execute another program.
With the advent of the hardware MMU, multi-process, multi-user, virtual storage of the operating system after the emergence of executable file loading process becomes very complex. The virtual address space of the process is introduced, and then based on how the operating system allocates code, data, heaps, stacks, and the process address space of the program, how they are distributed, and finally maps the program to the process virtual address space in the form of a page map.
Dynamic linking is a different concept from static linker, that is, a single executable module is split into several modules, a way to link when the program runs. Then, according to the practical example, Do_exece () analyzes the approximate process of elf loading, and realizes dynamic link in the middle.

Creation of processes and loading of executable programs

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.