fn relocate(
        elf: &Elf,
        elf_bytes: &mut [u8],
        calls: &mut HashMap<u32, usize>,
    ) -> Result<(), ELFError> {
        let text_section = Self::get_section(elf, ".text")?;

        // Fixup all program counter relative call instructions
        Self::fixup_relative_calls(
            calls,
            &mut elf_bytes
                .get_mut(text_section.file_range())
                .ok_or(ELFError::OutOfBounds)?,
        )?;

        // Fixup all the relocations in the relocation section if exists
        for relocation in &elf.dynrels {
            let r_offset = relocation.r_offset as usize;

            // Offset of the immediate field
            let imm_offset = r_offset.saturating_add(BYTE_OFFSET_IMMEDIATE);
            match BPFRelocationType::from_x86_relocation_type(relocation.r_type) {
                Some(BPFRelocationType::R_BPF_64_RELATIVE) => {
                    // Raw relocation between sections.  The instruction being relocated contains
                    // the virtual address that it needs turned into a physical address.  Read it,
                    // locate it in the ELF, convert to physical address

                    // Read the instruction's immediate field which contains virtual
                    // address to convert to physical
                    let checked_slice = elf_bytes
                        .get(imm_offset..imm_offset.saturating_add(BYTE_LENGTH_IMMEIDATE))
                        .ok_or(ELFError::OutOfBounds)?;
                    let refd_va = LittleEndian::read_u32(&checked_slice) as u64;

                    if refd_va == 0 {
                        return Err(ELFError::InvalidVirtualAddress(refd_va));
                    }

                    // final "physical address" from the VM's perspetive is rooted at `MM_PROGRAM_START`
                    let refd_pa = ebpf::MM_PROGRAM_START.saturating_add(refd_va);

                    // trace!(
                    //     "Relocation section va {:#x} off {:#x} va {:#x} pa {:#x} va {:#x} pa {:#x}",
                    //     section_infos[target_section].va, target_offset, relocation.addr, section_infos[target_section].bytes.as_ptr() as usize + target_offset, refd_va, refd_pa
                    // );

                    // Write the physical address back into the target location
                    if text_section.file_range().contains(&r_offset) {
                        // Instruction lddw spans two instruction slots, split the
                        // physical address into a high and low and write into both slot's imm field

                        let mut checked_slice = elf_bytes
                            .get_mut(imm_offset..imm_offset.saturating_add(BYTE_LENGTH_IMMEIDATE))
                            .ok_or(ELFError::OutOfBounds)?;
                        LittleEndian::write_u32(&mut checked_slice, (refd_pa & 0xFFFFFFFF) as u32);
                        let mut checked_slice = elf_bytes
                            .get_mut(
                                imm_offset.saturating_add(ebpf::INSN_SIZE)
                                    ..imm_offset
                                        .saturating_add(ebpf::INSN_SIZE + BYTE_LENGTH_IMMEIDATE),
                            )
                            .ok_or(ELFError::OutOfBounds)?;
                        LittleEndian::write_u32(&mut checked_slice, (refd_pa >> 32) as u32);
                    } else {
                        // 64 bit memory location, write entire 64 bit physical address directly
                        let mut checked_slice = elf_bytes
                            .get_mut(r_offset..r_offset.saturating_add(mem::size_of::<u64>()))
                            .ok_or(ELFError::OutOfBounds)?;
                        LittleEndian::write_u64(&mut checked_slice, refd_pa);
                    }
                }
                Some(BPFRelocationType::R_BPF_64_32) => {
                    // The .text section has an unresolved call to symbol instruction
                    // Hash the symbol name and stick it into the call instruction's imm
                    // field.  Later that hash will be used to look up the function location.

                    let sym = elf
                        .dynsyms
                        .get(relocation.r_sym)
                        .ok_or(ELFError::UnknownSymbol(relocation.r_sym))?;
                    let name = elf
                        .dynstrtab
                        .get(sym.st_name)
                        .ok_or(ELFError::UnknownSymbol(sym.st_name))?
                        .map_err(|_| ELFError::UnknownSymbol(sym.st_name))?;
                    let hash = ebpf::hash_symbol_name(&name.as_bytes());
                    let mut checked_slice = elf_bytes
                        .get_mut(imm_offset..imm_offset.saturating_add(BYTE_LENGTH_IMMEIDATE))
                        .ok_or(ELFError::OutOfBounds)?;
                    LittleEndian::write_u32(&mut checked_slice, hash);
                    let text_section = Self::get_section(elf, ".text")?;
                    if sym.is_function() && sym.st_value != 0 {
                        if !text_section.vm_range().contains(&(sym.st_value as usize)) {
                            return Err(ELFError::OutOfBounds);
                        }
                        calls.insert(
                            hash,
                            (sym.st_value - text_section.sh_addr) as usize / ebpf::INSN_SIZE,
                        );
                    }
                }
                _ => return Err(ELFError::UnknownRelocation(relocation.r_type)),
            }
        }

        Ok(())
    }
/// Relocates the ELF in-place
Relocates the ELF in-place
Relocates the ELF in - place
fn relocate(
        elf: &Elf,
        elf_bytes: &mut [u8],
        calls: &mut HashMap<u32, usize>,
    ) -> Result<(), ELFError> {
        let text_section = Self::get_section(elf, ".text")?;
        // Fixup all program counter relative call instructions
        Self::fixup_relative_calls(
            calls,
            &mut elf_bytes
                .get_mut(text_section.file_range())
                .ok_or(ELFError::OutOfBounds)?,
        )?;
        // Fixup all the relocations in the relocation section if exists
        for relocation in &elf.dynrels {
            let r_offset = relocation.r_offset as usize;
            // Offset of the immediate field
            let imm_offset = r_offset.saturating_add(BYTE_OFFSET_IMMEDIATE);
            match BPFRelocationType::from_x86_relocation_type(relocation.r_type) {
                Some(BPFRelocationType::R_BPF_64_RELATIVE) => {
                    // Raw relocation between sections.  The instruction being relocated contains
                    // the virtual address that it needs turned into a physical address.  Read it,
                    // locate it in the ELF, convert to physical address
                    // Read the instruction's immediate field which contains virtual
                    // address to convert to physical
                    let checked_slice = elf_bytes
                        .get(imm_offset..imm_offset.saturating_add(BYTE_LENGTH_IMMEIDATE))
                        .ok_or(ELFError::OutOfBounds)?;
                    let refd_va = LittleEndian::read_u32(&checked_slice) as u64;
                    if refd_va == 0 {
                        return Err(ELFError::InvalidVirtualAddress(refd_va));
                    }
                    // final "physical address" from the VM's perspetive is rooted at `MM_PROGRAM_START`
                    let refd_pa = ebpf::MM_PROGRAM_START.saturating_add(refd_va);
                    // trace!(
                    //     "Relocation section va {:#x} off {:#x} va {:#x} pa {:#x} va {:#x} pa {:#x}",
                    //     section_infos[target_section].va, target_offset, relocation.addr, section_infos[target_section].bytes.as_ptr() as usize + target_offset, refd_va, refd_pa
                    // );
                    // Write the physical address back into the target location
                    if text_section.file_range().contains(&r_offset) {
                        // Instruction lddw spans two instruction slots, split the
                        // physical address into a high and low and write into both slot's imm field
                        let mut checked_slice = elf_bytes
                            .get_mut(imm_offset..imm_offset.saturating_add(BYTE_LENGTH_IMMEIDATE))
                            .ok_or(ELFError::OutOfBounds)?;
                        LittleEndian::write_u32(&mut checked_slice, (refd_pa & 0xFFFFFFFF) as u32);
                        let mut checked_slice = elf_bytes
                            .get_mut(
                                imm_offset.saturating_add(ebpf::INSN_SIZE)
                                    ..imm_offset
                                        .saturating_add(ebpf::INSN_SIZE + BYTE_LENGTH_IMMEIDATE),
                            )
                            .ok_or(ELFError::OutOfBounds)?;
                        LittleEndian::write_u32(&mut checked_slice, (refd_pa >> 32) as u32);
                    } else {
                        // 64 bit memory location, write entire 64 bit physical address directly
                        let mut checked_slice = elf_bytes
                            .get_mut(r_offset..r_offset.saturating_add(mem::size_of::<u64>()))
                            .ok_or(ELFError::OutOfBounds)?;
                        LittleEndian::write_u64(&mut checked_slice, refd_pa);
                    }
                }
                Some(BPFRelocationType::R_BPF_64_32) => {
                    // The .text section has an unresolved call to symbol instruction
                    // Hash the symbol name and stick it into the call instruction's imm
                    // field.  Later that hash will be used to look up the function location.
                    let sym = elf
                        .dynsyms
                        .get(relocation.r_sym)
                        .ok_or(ELFError::UnknownSymbol(relocation.r_sym))?;
                    let name = elf
                        .dynstrtab
                        .get(sym.st_name)
                        .ok_or(ELFError::UnknownSymbol(sym.st_name))?
                        .map_err(|_| ELFError::UnknownSymbol(sym.st_name))?;
                    let hash = ebpf::hash_symbol_name(&name.as_bytes());
                    let mut checked_slice = elf_bytes
                        .get_mut(imm_offset..imm_offset.saturating_add(BYTE_LENGTH_IMMEIDATE))
                        .ok_or(ELFError::OutOfBounds)?;
                    LittleEndian::write_u32(&mut checked_slice, hash);
                    let text_section = Self::get_section(elf, ".text")?;
                    if sym.is_function() && sym.st_value != 0 {
                        if !text_section.vm_range().contains(&(sym.st_value as usize)) {
                            return Err(ELFError::OutOfBounds);
                        }
                        calls.insert(
                            hash,
                            (sym.st_value - text_section.sh_addr) as usize / ebpf::INSN_SIZE,
                        );
                    }
                }
                _ => return Err(ELFError::UnknownRelocation(relocation.r_type)),
            }
        }
        Ok(())
    }
fn relocate ( elf : & Elf , elf_bytes : & mut [ u8 ] , calls : & mut HashMap < u32 , usize > , ) -> Result < ( ) , ELFError > { let text_section = Self :: get_section ( elf , " " ) ? ; // Fixup all program counter relative call instructions Self :: fixup_relative_calls ( calls , & mut elf_bytes . get_mut ( text_section . file_range ( ) ) . ok_or ( ELFError :: OutOfBounds ) ? , ) ? ; // Fixup all the relocations in the relocation section if exists for relocation in & elf . dynrels { let r_offset = relocation . r_offset as usize ; // Offset of the immediate field let imm_offset = r_offset . saturating_add ( BYTE_OFFSET_IMMEDIATE ) ; match BPFRelocationType :: from_x86_relocation_type ( relocation . r_type ) { Some ( BPFRelocationType :: R_BPF_64_RELATIVE ) => { // Raw relocation between sections.  The instruction being relocated contains // the virtual address that it needs turned into a physical address.  Read it, // locate it in the ELF, convert to physical address // Read the instruction's immediate field which contains virtual // address to convert to physical let checked_slice = elf_bytes . get ( imm_offset .. imm_offset . saturating_add ( BYTE_LENGTH_IMMEIDATE ) ) . ok_or ( ELFError :: OutOfBounds ) ? ; let refd_va = LittleEndian :: read_u32 ( & checked_slice ) as u64 ; if refd_va == 0 { return Err ( ELFError :: InvalidVirtualAddress ( refd_va ) ) ; } // final "physical address" from the VM's perspetive is rooted at `MM_PROGRAM_START` let refd_pa = ebpf :: MM_PROGRAM_START . saturating_add ( refd_va ) ; // trace!( //     "Relocation section va {:#x} off {:#x} va {:#x} pa {:#x} va {:#x} pa {:#x}", //     section_infos[target_section].va, target_offset, relocation.addr, section_infos[target_section].bytes.as_ptr() as usize + target_offset, refd_va, refd_pa // ); // Write the physical address back into the target location if text_section . file_range ( ) . contains ( & r_offset ) { // Instruction lddw spans two instruction slots, split the // physical address into a high and low and write into both slot's imm field let mut checked_slice = elf_bytes . get_mut ( imm_offset .. imm_offset . saturating_add ( BYTE_LENGTH_IMMEIDATE ) ) . ok_or ( ELFError :: OutOfBounds ) ? ; LittleEndian :: write_u32 ( & mut checked_slice , ( refd_pa & 0xFFFFFFFF ) as u32 ) ; let mut checked_slice = elf_bytes . get_mut ( imm_offset . saturating_add ( ebpf :: INSN_SIZE ) .. imm_offset . saturating_add ( ebpf :: INSN_SIZE + BYTE_LENGTH_IMMEIDATE ) , ) . ok_or ( ELFError :: OutOfBounds ) ? ; LittleEndian :: write_u32 ( & mut checked_slice , ( refd_pa >> 32 ) as u32 ) ; } else { // 64 bit memory location, write entire 64 bit physical address directly let mut checked_slice = elf_bytes . get_mut ( r_offset .. r_offset . saturating_add ( mem :: size_of :: < u64 > ( ) ) ) . ok_or ( ELFError :: OutOfBounds ) ? ; LittleEndian :: write_u64 ( & mut checked_slice , refd_pa ) ; } } Some ( BPFRelocationType :: R_BPF_64_32 ) => { // The .text section has an unresolved call to symbol instruction // Hash the symbol name and stick it into the call instruction's imm // field.  Later that hash will be used to look up the function location. let sym = elf . dynsyms . get ( relocation . r_sym ) . ok_or ( ELFError :: UnknownSymbol ( relocation . r_sym ) ) ? ; let name = elf . dynstrtab . get ( sym . st_name ) . ok_or ( ELFError :: UnknownSymbol ( sym . st_name ) ) ? . map_err ( | _ | ELFError :: UnknownSymbol ( sym . st_name ) ) ? ; let hash = ebpf :: hash_symbol_name ( & name . as_bytes ( ) ) ; let mut checked_slice = elf_bytes . get_mut ( imm_offset .. imm_offset . saturating_add ( BYTE_LENGTH_IMMEIDATE ) ) . ok_or ( ELFError :: OutOfBounds ) ? ; LittleEndian :: write_u32 ( & mut checked_slice , hash ) ; let text_section = Self :: get_section ( elf , " " ) ? ; if sym . is_function ( ) && sym . st_value != 0 { if ! text_section . vm_range ( ) . contains ( & ( sym . st_value as usize ) ) { return Err ( ELFError :: OutOfBounds ) ; } calls . insert ( hash , ( sym . st_value - text_section . sh_addr ) as usize / ebpf :: INSN_SIZE , ) ; } } _ => return Err ( ELFError :: UnknownRelocation ( relocation . r_type ) ) , } } Ok ( ( ) ) }
Relocates the ELF in-place
Relocates the ELF in - place
elf
&Elf
elf_bytes
&mut [u8]
calls
&mut HashMap<u32, usize>