Source code analysis of RT-thread loading shared target files

Source: Internet
Author: User

In the upper (refer to: http://blog.csdn.net/flydream0/article/details/8719036 ). Here, we assume that you have a good understanding of the ELF File Format and have a thorough understanding of the source code of the _ load_shared_object function. This gives you a thorough understanding of how RT-thread inputs a shared target file.

The _ load_relocated_object function is divided into four steps:

  1. Allocate and initialize memory.
  2. Based on the order of input target files, assemble them in segments and map them to module-> module_space memory space.
  3. Modify the content of module-> module_space according to the relocation information.
  4. Generate the final symbol table.
1. Analyze memory and initialize

Static struct rt_module * _ load_shared_object (const char * Name, void * module_ptr) {optional * PTR = rt_null; rt_module_t module = rt_null; required linked = rt_false; required index, module_size = 0; rt_assert (module_ptr! = Rt_null); // check whether the ELF File ID is "\ 177rtm", indicating that the ELF file has not been linked, the linked ID will be used during the relocation process, if (rt_memcmp (elf_module-> e_ident, rtmmag, selfmag) = 0) {/* rtmlinker finished */linked = rt_true ;} /* Get the elf image size * // calculate the elf memory image size for (Index = 0; index <elf_module-> e_phnum; index ++) {If (phdr [Index]. p_type = pt_load) module_size + = phdr [Index]. p_memsz;} If (module_size = 0) {rt_kprintf ("module: siz E error \ n "); Return rt_null;}/* allocate module * // dynamically allocates an rt_moudule object module = (struct rt_module *) rt_object_allocate (rt_object_class_module, name ); if (! Module) return rt_null; // The number of times the module is referenced is initialized to 0 module-> nref = 0; /* allocate module space * // dynamically allocates a piece of memory based on the size of the previously calculated memory image, which is directed by module-> module_space. Module-> module_space = rt_malloc (module_size); If (module-> module_space = rt_null) {rt_kprintf ("module: Allocate space failed. \ n "); rt_object_delete (& (module-> parent); Return rt_null;}/* zero all space */PTR = module-> module_space; // clear all the memory. rt_memset (PTR, 0, module_size );

2 assemble segments to memory image

Next we will assemble all the segments of the pt_load type into the memory image:

For (Index = 0; index <elf_module-> e_phnum; index ++) // scan all segments {If (phdr [Index]. p_type = pt_load) // If the segment type is pt_load {rt_memcpy (PTR + phdr [Index]. p_paddr, // copy the content of the segment to the memory error image (rt_uint8_t *) elf_module + phdr [Index]. p_offset, phdr [Index]. p_filesz) ;}}/* set Module entry * // set the module's thread entry address module-> module_entry = module-> module_space + elf_module-> e_entry;

The preceding code scans all program header table items. If the corresponding segment type is pt_load, the original content of the segment is copied to the memory image. The segment address is given by p_offset, the memory image address is offset by p_paddr, And the size is determined by p_filesz.

Note that p_filesz may be smaller than p_memsz, for example. BSS segment, but all previously cleared, so if the image corresponding to the memory is not copied in, all is cleared, which is equivalent to initial initialization, for example, all uninitialized variables.

3. Modify the memory image based on the relocation Information

For (Index = 0; index <elf_module-> e_shnum; index ++) // scan the table items {rt_uint32_t I, nr_reloc; elf32_sym * symtab; elf32_rel * rel; rt_uint8_t * strtab; static rt_bool_t unsolved = rt_false; If (! Is_rel (shdr [Index]) // filter out non-Relocated section continue; /* Get relocate item * // get the data structure of the relocation item rel = (elf32_rel *) (rt_uint8_t *) module_ptr + shdr [Index]. sh_offset);/* locate. rel. PLT and. rel. dyn Section */symtab = (elf32_sym *) (rt_uint8_t *) module_ptr + // when the section type is "reoriented", the value refers to the table item shdr [shdr [Index] in the section header of the symbol table type. sh_link]. sh_offset); strtab = (rt_uint8_t *) module_ptr + // at this time, sh_link of the number one table item in the section area of the symbol table Type points to the table item SH in the section header of the string type. Dr [shdr [shdr [Index]. sh_link]. sh_link]. sh_offset; nr_reloc = (rt_uint32_t) (shdr [Index]. sh_size/sizeof (elf32_rel); // gets the number of relocation item data structures/* Relocate every items */for (I = 0; I <nr_reloc; I ++) // Scan each relocated data structure contained in this section {elf32_sym * sym = & symtab [elf32_r_sym (rel-> r_info)]; // rel-> r_info indicates the index value of the symbol table. This line of code returns a symbol table item rt_debug_log (rt_debug_module, ("relocate symbol % s shndx % d \ n", // debug and print strtab + sym-> st_name, sym-> St_shndx); If (sym-> st_shndx! = Sht_null) | // If the table item associated with the symbol table item is not empty or the symbol table item type is a local symbol (elf_st_bind (sym-> st_info) = stb_local) {rt_module_arm_relocate (module, Rel, // modify the content in the memory image based on the relocation information (elf32_addr) (module-> module_space + sym-> st_value ));} else if (! Linked) // if you have not linked the list {elf32_addr ADDR; rt_debug_log (rt_debug_module, ("relocate Symbol: % s \ n", strtab + sym-> st_name )); /* need to resolve symbol in kernel symbol table */ADDR = rt_module_symbol_find (const char *) (strtab + sym-> st_name )); // search for the module if (ADDR = 0) {rt_kprintf ("module: can't find % s in kernel symbol table \ n ", strtab + sym-> st_name); unsolved = rt_true; // unresolved flag} else rt_module_arm_relocate (module, Rel, ADDR); // find the corresponding module in the kernel for relocation} rel ++;} If (unsolved) // Delete this module if it is not resolved, then {rt_object_delete (& (module-> parent); Return rt_null ;}} is returned ;}}

In the above Code, the program will operate on the number one table item of the section area of the positioning section for each type, according to. This information is obtained.

Then, locate the specific symbol to be relocated based on the data in the relocation item. The data structure of the relocation item is defined as follows:

Typedef struct elf32_sym {elf32_word st_name; // symbol name elf32_addr st_value; // symbol value elf32_word st_size; // symbol size unsigned char st_info; // symbol type and binding attributes (see Section 2.5.2 of the previous blog) unsigned char st_other; // meaningless elf32_half st_shndx; // index of table items in the section header associated with this symbol} elf32_sym;

The four-digit high of st_info in the symbol table indicates the symbol binding attribute. The four-digit low indicates the symbol type. For details, see section 2.5.1of http://blog.csdn.net/flydream0/article/details/87109361_t10.

Next, judge whether the section associated with this symbol is not empty or the symbol is a local symbol. In this way, you can relocate it based on this section, the relocation operation is completed through the rt_module_arm_relocate function, which is a function related to the ARM architecture machine. It needs to input three parameters, module address, and relocate the data structure, the specific section location of the module memory image (given by the st_value value of the symbol table item, see Section 2.5.3 of the previous Article). With these three parameters, you can modify the specific location of the memory image. Because the rt_module_arm_relocate function is too closely related to the specific arm machine, it is meaningless to introduce it in detail here, So skip this step, if you are interested in finding relevant information, study it yourself.

If the preceding conditions are not met, if the ELF file is not linked, this symbol can be linked through other modules to locate the corresponding memory image location, so the program will find the corresponding module in the kernel according to the name, and then perform the relocation operation.

4. Generate the final symbol table

RT-thread first searches for the table named ". dynsym "section, which is a special section. See section 2.3.2 of the previous article. It contains a Dynamic Linked List symbol table.

Find the. dynsym section:

For (Index = 0; index <elf_module-> e_shnum; index ++) // scan table items in the header of all nodes {/* Find. dynsym Section */rt_uint8_t * shstrab; shstrab = (rt_uint8_t *) module_ptr + shdr [elf_module-> e_shstrndx]. sh_offset; // locate the string table if (rt_strcmp (const char *) (shstrab + shdr [Index]. sh_name), elf_dynsym) = 0) // determines whether the partition name is ". dynsym "break ;}

Next, determine how many global symbols are contained in this section and apply for memory space for it:

If (index! = Elf_module-> e_shnum) {int I, Count = 0; elf32_sym * symtab = rt_null; rt_uint8_t * strtab = rt_null; symtab = (elf32_sym *) module_ptr + shdr [Index]. sh_offset); // obtain the symbol table strtab = (rt_uint8_t *) module_ptr + shdr [shdr [Index]. sh_link]. sh_offset; // string table for (I = 0; I <shdr [Index]. sh_size/sizeof (elf32_sym); I ++) // scan all symbol table items to obtain the number of global function symbols, that is, the exported function name symbol {If (elf_st_bind (symtab [I]. st_info) = stb_global) & (elf_st_type (symtab [I]. st_info) = stt_func) Count ++;} module-> symtab = (struct rt_module_symtab *) rt_malloc // allocate the memory space of the symbol table for the module (count * sizeof (struct rt_module_symtab); Module-> nsym = count; // set the number of symbols

Finally, copy the symbols one by one:

For (I = 0, Count = 0; I <shdr [Index]. sh_size/sizeof (elf32_sym); I ++) scan all export symbols {rt_size_t length; If (elf_st_bind (symtab [I]. st_info )! = Stb_global) | (elf_st_type (symtab [I]. st_info )! = Stt_func) continue; length = rt_strlen (const char *) (strtab + symtab [I]. st_name) + 1; // symbol Name Length module-> symtab [count]. ADDR = (void *) (module-> module_space + symtab [I]. st_value); // set the symbolic address module-> symtab [count]. name = rt_malloc (length); // set the symbol name rt_memset (void *) module-> symtab [count]. name, 0, length); rt_memcpy (void *) module-> symtab [count]. name, strtab + symtab [I]. st_name, length); count ++ ;}

We can see from the above that the process of exporting the symbol table is actually to find out. dynsym section, because this section contains all linked list symbols, but not all symbols need to be exported, only when the logo is a global symbol, this symbol type is a function symbol that needs to be exported. Finally, all global functions of this type are exported to the symbol table corresponding to the module.

RT-thread: the process of loading shared files has been analyzed!

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.