Zhu Yuxiang + Original works reproduced please specify the source + "Linux kernel analysis" MOOC course http://mooc.study.163.com/course/USTC-1000029000
The main executable file in Linux is the elf file, we can load it into our own program, this time we will analyze the Linux loading executable program process.
First, make it clear that there are two ways to load executable programs: static and dynamic links. The so-called static link, is to complete all the link work before the program executes, compose an executable file, put into memory execution. The disadvantage of this is that when there are multiple files to link the same executable file, there will be more copies of the executable in memory, which is to some extent a waste of memory. As a result, the concept of dynamic linking is invented, which means that the program does not assemble all the modules before execution, but instead completes the link work when the module is needed, which makes it more flexible and saves memory than static links.
Dynamic links are divided into dynamic links at load time and dynamic links at runtime, and you can be interested in further understanding.
After the basics have been popularized, let's analyze how Linux is loading executable programs.
The Linux mount executable system call is Execve, which, like the fork function, changes the code snippet that is returned when execution completes.
Its job is to first read the incoming file name, parameters, and environment variables, and then call the parse list to find the structure that resolves the executable file:
List_for_each_entry (FMT, &formats, LH) { if (!try_module_get (fmt->module)) continue; Read_unlock (&binfmt_lock); bprm->recursion_depth++; retval = Fmt->load_binary (BPRM); Read_lock (&binfmt_lock);
For example, when we read the elf file, it is necessary to find the parser for the elf file in the list. Note that the Observer pattern is used here: Linux will pre-register the various parsers, and when a new parser is added, the parsed list will be changed. such as in the Elf file:
static struct Linux_binfmt Elf_format = { . module = This_module, . load_binary = load_elf_binary, . Load_shlib = Load_elf_library, . Core_dump = Elf_core_dump, . Min_coredump = elf_exec_ PAGESIZE,};
Here, it defines the concrete implementation of Load_lef_binary as the parser load_binary (in fact, is a polymorphic), after the structure is registered to the list of the parser, and then encounter the elf file, search the parser chain list, you can find a special parsing such a file parser.
static int __init init_elf_binfmt (void) { register_binfmt (&elf_format); return 0;}
In the elf's own analytic function load_elf_binary, the process is different for static and dynamic links.
if (elf_interpreter) {unsigned long interp_map_addr = 0;elf_entry = Load_elf_interp (&LOC->INTERP_ELF_EX, Interpreter, &interp_map_addr, load_bias), if (!is_err ((void *) elf_entry)) {/* * LOAD_ELF_INTERP () Returns relocation * Adjustment */interp_load_addr = elf_entry;elf_entry + = Loc->interp_elf_ex.e_entry;} if (BAD_ADDR (elf_entry)) {retval = Is_err ((void *) elf_entry)? ( int) Elf_entry:-einval;goto out_free_dentry;} Reloc_func_desc = interp_load_addr;allow_write_access (interpreter); Fput (interpreter); Kfree (Elf_interpreter);} else {elf_entry = Loc->elf_ex.e_entry;if (bad_addr (elf_entry)) {retval =-einval;goto out_free_dentry;}}
...
Start_thread (REGS,ELF_ENTRY,BPRM->P);
For dynamic linking, this code executes the part of the Elf_interpreter directly, and then loads a dynamic linker, which then performs the specific memory management, which is not discussed here for the time being.
For static linking, the part of else is executed directly, and the entry address of the ELF snippet is paid to the elf_entry variable.
The Start_thread function is then executed, which stacks the process context and assigns the elf_entry to the IP, and for a static link, the first code that executes after the code jumps out of the kernel state is the ELF's entry code.
In this way, the ability to load executable programs can be implemented.
Summarize:
This blog discusses the process of Linux loading executable programs, loaded executable program is divided into static and dynamic link two ways. When parsing an executable, Linux takes advantage of polymorphic mechanisms and observer patterns, and changes the EIP address of the kernel stack during parsing, enabling the next code to be executed to change to the executable program.
The experimental process is based on the experimental building system, here is a simple display of several:
A brief analysis of Linux loading executable program