Source code analysis of relocatable files loaded by RT-Thread

Source: Internet
Author: User
1 Preface

The previous chapter summarizes the source code analysis for loading shared files. Previously, RT-thread currently supports shared files and relocated files, which is also the purpose of this chapter.

A relocated file is simply a. o file that contains code and data suitable for creating executable files or sharing target files through links to other target files.

In rt-thread, this loading process is implemented by the function _ load_relocated_object. In general, there are three simple steps to load relocated files:

  • Calculate the memory image size and allocate memory.
  • Copy data to the memory image.
  • Relocate data in the memory image.
2. Calculate the memory image size and allocate memory

Generally, the image in the program's memory mainly contains text (CODE), rodata (read-only data, which refers to constants), and data (data can be read and written, which is generally the initialized global variable, does not include values initialized to 0 and BSS (uninitialized global variables ). Therefore, the program calculates the size of the four segments in the memory image:

// Traverse all the section header tables in the ELF File for (Index = 0; index <elf_module-> e_shnum; index ++) {/* text */If (is_prog (shdr [Index]) & is_ax (shdr [Index]) // If the table is the header of the text section, that is, code {module_size + = shdr [Index]. sh_size; // increase the memory image size. module_addr = shdr [Index]. sh_addr; // record the address of the code segment}/* rodata */If (is_prog (shdr [Index]) & is_alloc (shdr [Index]) // if it is read-only data {module_size + = shdr [Index]. sh_size; // increase the memory image size}/* Data */If (is_prog (shdr [Index]) & is_aw (shdr [Index]) // if the data can be read and written, that is, the initialized global variable area {module_size + = shdr [Index]. sh_size; // increase the memory image size}/* BSS */If (is_noprog (shdr [Index]) & is_aw (shdr [Index]) // if it is an uninitialized global variable {module_size + = shdr [Index]. sh_size; // increase the memory image size}/* No text, data and BSS on image */If (module_size = 0) return rt_null;

Next, allocate space for the memory image and initialize it:

Module = (struct rt_module *) rt_object_allocate (rt_object_class_module, (const char *) Name); // dynamically allocates a module kernel pair like if (module = rt_null) return rt_null; /* allocate module space */Module-> module_space = rt_malloc (module_size); // allocate space based on the previously calculated memory image 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 allocated memory image space rt_memset (PTR, 0, module_size );

From the source code above, we can see that so far, the program has only allocated a memory image and initialized it.
 

3. Copy data to the memory image

Copying data is mainly to copy the data corresponding to the four types of segments mentioned earlier to the memory image. The process of the four segments is slightly different:

For (Index = 0; index <elf_module-> e_shnum; index ++) // traverse all the section header tables {/* load text section */If (is_prog (shdr [Index]) & is_ax (shdr [Index]) // if the current text segment is {rt_memcpy (PTR, (rt_uint8_t *) elf_module + shdr [Index]. sh_offset, // copy all data corresponding to the text segment to the memory image shdr [Index]. sh_size); rt_debug_log (rt_debug_module, ("load text 0x % x, size % d \ n", PTR, shdr [Index]. sh_size); PTR + = shdr [Index]. sh_size;}/* load rodata Section */If (is_prog (shdr [Index]) & is_alloc (shdr [Index]) // if the current rodata segment is {rt_memcpy (PTR, (rt_uint8_t *) elf_module + shdr [Index]. sh_offset, // copy the data in the rodata segment to the memory image shdr [Index]. sh_size); rodata_addr = (rt_uint32_t) PTR; // record the read-only data address rt_debug_log (rt_debug_module, ("load rodata 0x % x, size % d, rodata 0x % x \ n ", PTR, shdr [Index]. sh_size, * (rt_uint32_t *) data_addr); PTR + = shdr [Index]. sh_size;}/* load data section */If (is_prog (shdr [Index]) & is_aw (shdr [Index]) // if the current read/write data segment is {rt_memcpy (PTR, (rt_uint8_t *) elf_module + shdr [Index]. sh_offset, // copy the data corresponding to the data segment to the memory image shdr [Index]. sh_size); data_addr = (rt_uint32_t) PTR; // record the address of the data segment in the memory image rt_debug_log (rt_debug_module, ("load data 0x % x, size % d, data 0x % x \ n ", PTR, shdr [Index]. sh_size, * (rt_uint32_t *) data_addr); PTR + = shdr [Index]. sh_size;}/* load BSS section */If (is_noprog (shdr [Index]) & is_aw (shdr [Index]) // if the current BSS segment is {rt_memset (PTR, 0, shdr [Index]. sh_size); // clear all BSS segment space in the memory image bss_addr = (rt_uint32_t) PTR; rt_debug_log (rt_debug_module, ("load BSS 0x % x, size % d, \ n ", PTR, shdr [Index]. sh_size) ;}}/* set Module entry */Module-> module_entry = // set the module entry address (rt_uint8_t *) module-> module_space + elf_module-> e_entry-module_addr;

The code above shows that the program copies the corresponding data of the Text Segment, rodata segment, and data segment to the memory image, but not in the BSS segment, because BSS segments represent uninitialized global variables (including global variables initialized to 0), the program only clears all the space corresponding to BSS segments in the memory image. During data copying, the program also records both the rodata and data segments. The BSS segment's address in the memory image is used for subsequent relocation operations.

In addition, the program also sets the module entry address.

4. Relocate data in memory Images

In fact, the relocation operation is to modify part of the data that has been copied to the memory image. This process is based on the relocated section.

For (Index = 0; index <elf_module-> e_shnum; index ++) // scan all the section header tables {rt_uint32_t I, nr_reloc; elf32_sym * symtab; elf32_rel * rel; if (! Is_rel (shdr [Index]) // only operations can be performed to relocate the table item continue in the header of the Section;/* Get relocate item */rel = (elf32_rel *) (rt_uint8_t *) module_ptr + shdr [Index]. sh_offset); // point to the relocated Section/* locate. dynsym and. dynstr */symtab = (elf32_sym *) (rt_uint8_t *) module_ptr + // obtain its symbol table shdr [shdr [Index]. sh_link]. sh_offset); // obtain its string table strtab = (rt_uint8_t *) module_ptr + shdr [shdr [shdr [Index]. sh_link]. sh_link]. sh_offset; shstrab = (rt_uint8_t *) Module_ptr + // obtain the global string table shdr [elf_module-> e_shstrndx]. sh_offset; nr_reloc = (rt_uint32_t) (shdr [Index]. sh_size/sizeof (elf32_rel); // obtain the number of relocate table items/* Relocate every items */for (I = 0; I <nr_reloc; I ++) // traverse all the relocable table items {elf32_sym * sym = & symtab [elf32_r_sym (rel-> r_info)]; // obtain its symbol rt_debug_log (rt_debug_module, ("relocate symbol: % s \ n ", strtab + sym-> st_name); If (sym-> st_shndx! = Stn_undef) {If (elf_st_type (sym-> st_info) = stt_section) | // if the current symbol type represents data (elf_st_type (sym-> st_info) = stt_object) {If (rt_strncmp (const char *) (shstrab + // The symbol is rodata? Shdr [sym-> st_shndx]. sh_name), elf_rodata, 8) = 0) {/* relocate rodata Section */rt_debug_log (rt_debug_module, ("rodata \ n ")); // relocate rodata in the memory image rt_module_arm_relocate (module, Rel, (elf32_addr) (rodata_addr + sym-> st_value);} else if (rt_strncmp (const char *) (shstrab + shdr [sym-> st_shndx]. sh_name), elf_bss, 5) = 0) // The symbol is BSS? {/* Relocate BSS section */rt_debug_log (rt_debug_module, ("BSS \ n"); Modules (module, Rel, (elf32_addr) bss_addr + sym-> st_value ); // relocate BSS} else if (rt_strncmp (const char *) (shstrab + shdr [sym-> st_shndx] in the memory image. sh_name), // The symbol is data? Elf_data, 6) = 0) {/* relocate data section */rt_debug_log (rt_debug_module, ("data \ n"); rt_module_arm_relocate (module, Rel, (elf32_addr) data_addr + sym-> st_value); // relocate data in the memory image }}else if (elf_st_type (sym-> st_info) = stt_func) // if it is a function symbol {/* relocate function */rt_module_arm_relocate (module, Rel, (elf32_addr) (rt_uint8_t *) // relocate the corresponding address module in the memory image-> module_space-module_addr + sym-> st_val UE);} else // other types of symbols {elf32_addr ADDR; If (elf32_r_type (rel-> r_info )! = R_arm_v4bx) // The type is not r_arm_v4bx? {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 )); // find the corresponding module if (ADDR! = (Elf32_addr) rt_null) {rt_module_arm_relocate (module, Rel, ADDR); // relocate the rt_debug_log (rt_debug_module, ("symbol ADDR 0x % x \ n ", ADDR);} else rt_kprintf ("module: Can't find % s in kernel symbol table \ n", strtab + sym-> st_name);} else {rt_module_arm_relocate (module, rel, (elf32_addr) (rt_uint8_t *) // relocate this module-> module_space-module_addr + sym-> st_value);} rel ++; // next relocated table item }}

In general, the relocatable operation is to relocate the rodata, Data, BSS, functions, r_arm_v4bx Symbols Based on the relocable table items. The rest will find the modules in the kernel based on the symbol names and then relocate them.

 

Complete!

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.