Linux0.11 kernel--load executable binary file 3.exec

Source: Internet
Author: User
Tags goto

Finally, the core of the function Do_execve, because here for the sake of simplicity I do not analyze the case of the shell command,

/** ' do_execve () ' function executes a new program. The */////Execve () system interrupts the calling function. Load and execute child processes (other programs). The function is called by the system interrupt call (int 0x80) function number __NR_EXECVE. Parameters: EIP-pointer to program code pointers in the stack calling system interrupts in the EIP, see the description of the KERNEL/SYSTEM_CALL.S program//start section; TMP-The return address of the system interrupt when calling this function, useless;//filename-the name of the program file being executed; RGV-Array of command-line parameter pointers; envp-environment variable pointer array. Returns: does not return if the call succeeds, otherwise sets an error number and returns-1. Intdo_execve (unsigned long *eip, long tmp, Char *filename, Char **argv, char **envp) {struct M_inode *inode;//in-Memory I node  Pointer structure variables.  struct Buffer_head *bh;//cache header pointer.  struct EXEC ex;//executes the file header data structure variable.  Unsigned a long page[max_arg_pages];//parameter and an array of page pointers for the environment string space.  int I, argc, ENVC;  int E_uid, e_gid;//valid user ID and valid group ID.  int retval;//the return value. int Sh_bang = 0;//Controls whether script processing code is required.  The offset pointer in the parameter and environment string space, initialized to the last long word pointing to the space.  unsigned long p = page_size * max_arg_pages-4;//eip[1] is the original code segment register CS, where the selector can not be a kernel segment selector, that is, the kernel cannot call this function.  if (0xFFFF & eip[1)! = 0x000f) Panic ("Execve called from supervisor Mode");//initialization parameters and an array of page pointers (tables) for the environment string space. for (i = 0; i < max_arg_pages; i++)//Clear page-table */page[i] = 0;//Take executable fileCorresponds to the I node number. if (! (  Inode = Namei (filename))/* Get executables Inode */return-enoent;//calculates the number of parameters and the number of environment variables.  ARGC = count (argv); ENVC = count (ENVP);//The execution file must be a regular file. If it is not a regular file, the error return code, jump to Exec_error2 (line No. 347). Restart_interp:if (!      S_isreg (Inode->i_mode)) {/* Must be regular file */retval =-eacces;    Goto Exec_error2; }//checks the execution permissions of the executed file.  Depending on its properties (corresponding to the UID and GID of the I node), see if this process is authorized to execute it.  i = inode->i_mode;//Fetch the file attribute field value. If the file's setting User ID flag (SET-USER-ID) is set, then the valid user ID (EUID) of the subsequent execution process is//set to the user ID of the file, otherwise set to the euid of the current process.  This value is temporarily stored in the E_UID variable. If the setting Group ID flag (SET-GROUP-ID) of the file is set, then the valid group ID (egid) of the execution process is set to//the group ID of the file.  Otherwise set to the egid of the current process. E_uid = (I & s_isuid)?  inode->i_uid:current->euid; E_gid = (I & s_isgid)?  inode->i_gid:current->egid;  If the file belongs to the user running the process, the file attribute word is shifted to the right 6 bits, the minimum 3 bits is the access permission flag for the file host.  Otherwise, if the file is in the same group as the user running the process, the minimum 3 bits of the attribute word is the access flag for the filegroup user.  Otherwise, the minimum 3 bits of the attribute word are the permissions that other users have to access the file.  if (Current->euid = = inode->i_uid) I >>= 6;  else if (Current->egid = = inode->i_gid) I >>= 3;If the corresponding user above does not have execution and no other user has any permissions, and is not a superuser, then the file is not/can be executed.  So the non-executable error code, jump to Exec_error2 place to deal with. if (! ( I & 1) &&!    ((Inode->i_mode & 0111) && suser ()))      {retval =-enoexec;    Goto Exec_error2;  }//reads the first piece of data from the execution file to the high-speed buffer area, and if there is an error, the error code is redirected to Exec_error2. if (! (      BH = Bread (Inode->i_dev, inode->i_zone[0]))) {retval =-eacces;    Goto Exec_error2;  }//the header structure data of the executing file is processed below, first, the ex points to the data structure of the execution head section.  ex = * (struct exec *) bh->b_data);/* Read Exec-header *//* reads the execution head portion */...//shell...//releases the buffer. Brelse (BH);//The Execution header information is processed below. Programs are not executed if the execution file is not a requirement page executable (zmagic), or the Code relocation section//length a_trsize is not equal to 0, or the data relocation information length is not equal to 0, or the code snippet + data segment + heap segment length exceeds 50MB,//or I  The length of the execution file indicated by the node is less than the sum of the code snippet + data segment + symbol table length + execution head part length.      if (N_magic (ex)! = Zmagic | | ex.a_trsize | | ex.a_drsize | |      Ex.a_text + ex.a_data + EX.A_BSS > 0x3000000 | |      Inode->i_size < Ex.a_text + ex.a_data + ex.a_syms + n_txtoff (ex)) {retval =-enoexec;    Goto Exec_error2; }//if the execution of the file execution header part length is not equal to a memory block size (1024 bytes), nor can it be executed.  Turn Exec_error2. if (N_txtoff (ex)! = block_size) {PRINTK ("%s:n_txtoff! = block_size.      See a.out.h. ", filename);      retval =-enoexec;    Goto Exec_error2; }//If the Sh_bang flag is not set, the specified number of environment variable strings and parameters are copied into the parameter and environment space.  If the Sh_bang flag is already set, the script will be run, and the environment variable page is copied without any duplication.      if (!sh_bang) {p = copy_strings (ENVC, ENVP, page, p, 0); p = copy_strings (argc, argv, page, p, 0);//If p=0, the environment variable and parameter space pages are already full and cannot fit.      Go to the error handling point.  if (!p) {retval =-enomem;    Goto Exec_error2;}  }/* OK, this is the point of no return *//* OK, there is no place to return from the beginning *///if the original program is also an execution program, release its I node and let the process executable field point to the new program I node.  if (current->executable) iput (current->executable); current->executable = inode;//to reset all signal processing handles. However, for sig_ign handles cannot be reset, there is a need to add a//if statement between 322 and 323 rows: if (current->sa[i].sa_handler! = sig_ign).  This is a bug in the source code. for (i = 0; i <; i++) Current->sigaction[i].sa_handler = null;//According to the bitmap flag of the Close (close_on_exec) file handle on execution, closes the specified open file and resets the  Sign. for (i = 0; i < Nr_open; i++) if (currEnt->close_on_exec >> i) & 1) sys_close (i);  Current->close_on_exec = 0;//Releases the memory block and the page table itself specified by the memory page table of the original program code snippet and data segment, based on the specified base address and limit length. The executed program does not occupy any pages in the main memory area at this time.  When executed, it causes the memory management program to perform a page fault processing and request//memory pages, and read the program into memory.  Free_page_tables (Get_base (current->ldt[1]), Get_limit (0x0f));  Free_page_tables (Get_base (current->ldt[2]), Get_limit (0x17));//If "Last task used coprocessor" points to the current process, it is empty and resets the flag that uses the coprocessor.  if (Last_task_used_math = = current) Last_task_used_math = NULL; Current->used_math = 0;//modifies the descriptor base and segment limits in the local table according to A_text, and places the parameters and environment space pages at the end of the data segment.  After executing the following statement, p is at this point offset from the beginning of the data segment, still pointing at the beginning of the parameter and ambient spatial data, and/or the pointer being converted to the stack.  p + = Change_ldt (ex.a_text, page)-Max_arg_pages * page_size;//create_tables () creates the environment and parameter variable pointer table in the new user stack and returns the stack pointer. p = (unsigned long) create_tables ((char *) p, argc, ENVC);//Modify the information for the new execution of the fields of the current process.  Make process code segment tail Value field End_code = A_text; make process data//segment tail Field end_data = A_data + a_text; Make process heap end field BRK = A_text + A_data + A_BSS. CURRENT-&GT;BRK = Ex.a_bss + (Current->end_data = Ex.a_data + (Current->end_code = Ex.a_text));//Set the process Stack Start field to the page where the stack pointer resides, and reset the process's valid user ID and valid group ID.  Current->start_stack = P & 0xfffff000;  Current->euid = E_uid;  Current->egid = e_gid;//Initializes a page of BSS data, all zeros.  i = Ex.a_text + ex.a_data; while (I & 0XFFF) put_fs_byte (0, (char *) (i++)), replace the code pointer on the stack with the original calling system interrupt with the entry point pointing to the new executor, and replace the stack pointer//with the stack pointer of the new executor.  The return instruction pops up the stack data and causes the CPU to execute the new execution program, so it does not go back to the program that called the system interrupt. Eip[0] = ex.a_entry;/* Eip, magic happens:-) *//* Eip, Magic Works */eip[3] = p;/* stack pointer *//* ESP, stack pointer */return 0;E  Xec_error2:iput (inode); exec_error1:for (i = 0; i < max_arg_pages; i++) free_page (Page[i]); return (retval);}

Although a large portion is deleted, the code is still very long. But it doesn't matter, the core code is a small part, mostly a judgmental code. The judgment code does not do the analysis, looks closely also can understand.

Note BH = bread (Inode->i_dev, inode->i_zone[0]) first reads the first piece of data from the executable to the high-speed buffer area, followed by ex = * (struct exec *) bh->b_data); b_ Data is copied to ex, which indicates that the file's B_data type data is the exec structure.

The back is a bunch of judgments about ex.

The copy_strings is then called, at which point P points to the parameter and the used address of the environment space.

This is followed by a heap of operations that assign values to the current process.

Then two times the code snippet and data segment of the Free_page_tables release LDT.

It then calls Change_ldt to set the LDT for the current process, which is analyzed before the position p points to.

Next Analyze Create_tables:

The/** create_tables () function resolves environment variables and parameter strings in the new user memory by creating pointer tables, placing their addresses on the stack, and returning pointer values for the new stack. */////creates the environment and parameter variable pointer tables in the new user stack. Parameters: P-The offset pointer of the parameter and environment information starting from the data segment; argc-the number of arguments; ENVC-the number of environment variables. Returns: Stack pointer.  Static unsigned long *create_tables (char *p, int argc, int envc) {unsigned long *argv, *ENVP;  The unsigned long *sp;//stack pointer is addressed as a 4-byte (1-section) boundary, so the SP is an integer multiple of 4.  SP = (unsigned long *) (0XFFFFFFFC & (unsigned long) p);//The SP moves down, vacated the number of space occupied by the environment parameter, and points the environment parameter pointer envp to that place.  SP-= ENVC + 1; ENVP = sp;//sp moves down, empty the number of space that the command-line parameter pointer occupies, and let the argv pointer point to that place.  The following pointer plus 1,sp increments the pointer width byte value.  SP-= argc + 1;  argv = sp;//Presses the environment parameter pointer envp and the command-line argument pointer and the number of command-line arguments onto the stack.  Put_fs_long (unsigned long) envp,--SP);  Put_fs_long (unsigned long) argv,--SP);  Put_fs_long ((unsigned long) argc,--SP);//the command line parameter pointers are placed in the corresponding space in front of the empty, and the last place a null pointer.      while (argc--> 0) {put_fs_long ((unsigned long) p, argv++);    while (Get_fs_byte (p++))//Nothing */; p pointer moves forward 4 bytes.  } put_fs_long (0, argv);//Place the environment variable pointer in the space in front of it, and finally place a null pointer. while (envc--> 0) {put_fS_long ((unsigned long) p, envp++);    while (Get_fs_byte (p++))/* nothing */;  } put_fs_long (0, ENVP); Return sp;//returns the current new stack pointer constructed. }

The Create_tables () function is used for the given current stack pointer value p and the number of parameter variables argc and the number of environment variables
ENVC, creates the environment and parameter variable pointer table in the new program stack, and returns the stack pointer value at this time sp. After creation, the stack refers to
The form of the needle table is shown in Figure 9-24.

Note that there are three consecutive Put_fs_long function calls, where the compaction stack is not really a stack, but the data is stored in a stacked way.

Then there are two loops to place p corresponding byte values, note that this is p++, because the previous copy of the time is--p.

Returns the SP when the data population is complete.

Next, assign the start_stack of the current process to the page where P is located.

Finally, it is worth noting that:

Replace the code pointer on the stack with the program that originally called the system break with the entry point pointing to the new executor, and replace the stack pointer//with the stack pointer of the new executor. The return instruction pops up the stack data and causes the CPU to execute the new execution program, so it does not go back to the program that called the system interrupt.  eip[0] = ex.a_entry;/* Eip, magic happens:-) *//* Eip, Magic Works */  eip[3] = p;/* stack pointer *//* ESP, stack pointer */

Do_execve is called in the SYSTEM_CALL.S:

# # # # This is a SYS_EXECVE () system call. Take the code pointer of the interrupt invoker as a parameter to call the C function Do_execve (). # Do_execve () in (fs/exec.c,182): Align 2_sys_execve:lea EIP (%ESP),%EAXPUSHL%eaxcall _do_execveaddl $4,%esp # The EIP value that is pressed into the stack when the call is discarded. Ret

It can be observed that this EIP is pressed in before calling _system_call, so Do_execve's EIP is this EIP:

/** 0 (%ESP)-%eax* 4 (%ESP)-%ebx* 8 (%ESP)-%ecx* C (%ESP)-%edx* (%ESP)-%fs* (%ESP)-%es* (%ESP)-%ds* 1C (%es P)-%eip* (%ESP)-%cs* (%ESP)-%eflags* (%ESP)-%oldesp* 2C (%ESP)-%oldss*/

So eip[0] is%EIP, assigned to the program's entry address, eip[3] is%OLDESP, assigned the value of P.

This EXEC.C analysis is over!

Linux0.11 kernel--load executable binary file 3.exec

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.