relocation.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. //! Program relocation handling.
  2. use alloc::{borrow::ToOwned, collections::BTreeMap, string::String};
  3. use core::mem;
  4. use log::debug;
  5. use object::{SectionIndex, SymbolKind};
  6. #[cfg(not(feature = "std"))]
  7. use crate::std;
  8. use crate::{
  9. generated::{
  10. bpf_insn, BPF_CALL, BPF_JMP, BPF_K, BPF_PSEUDO_CALL, BPF_PSEUDO_FUNC, BPF_PSEUDO_MAP_FD,
  11. BPF_PSEUDO_MAP_VALUE,
  12. },
  13. maps::Map,
  14. obj::{Function, Object},
  15. util::{HashMap, HashSet},
  16. BpfSectionKind,
  17. };
  18. pub(crate) const INS_SIZE: usize = mem::size_of::<bpf_insn>();
  19. /// The error type returned by [`Object::relocate_maps`] and [`Object::relocate_calls`]
  20. #[derive(thiserror::Error, Debug)]
  21. #[error("error relocating `{function}`")]
  22. pub struct BpfRelocationError {
  23. /// The function name
  24. function: String,
  25. #[source]
  26. /// The original error
  27. error: RelocationError,
  28. }
  29. /// Relocation failures
  30. #[derive(Debug, thiserror::Error)]
  31. pub enum RelocationError {
  32. /// Unknown symbol
  33. #[error("unknown symbol, index `{index}`")]
  34. UnknownSymbol {
  35. /// The symbol index
  36. index: usize,
  37. },
  38. /// Section not found
  39. #[error("section `{section_index}` not found, referenced by symbol `{}` #{symbol_index}",
  40. .symbol_name.clone().unwrap_or_default())]
  41. SectionNotFound {
  42. /// The section index
  43. section_index: usize,
  44. /// The symbol index
  45. symbol_index: usize,
  46. /// The symbol name
  47. symbol_name: Option<String>,
  48. },
  49. /// Unknown function
  50. #[error("function {address:#x} not found while relocating `{caller_name}`")]
  51. UnknownFunction {
  52. /// The function address
  53. address: u64,
  54. /// The caller name
  55. caller_name: String,
  56. },
  57. /// Unknown function
  58. #[error("program at section {section_index} and address {address:#x} was not found while relocating")]
  59. UnknownProgram {
  60. /// The function section index
  61. section_index: usize,
  62. /// The function address
  63. address: u64,
  64. },
  65. /// Invalid relocation offset
  66. #[error("invalid offset `{offset}` applying relocation #{relocation_number}")]
  67. InvalidRelocationOffset {
  68. /// The relocation offset
  69. offset: u64,
  70. /// The relocation number
  71. relocation_number: usize,
  72. },
  73. }
  74. #[derive(Debug, Copy, Clone)]
  75. pub(crate) struct Relocation {
  76. // byte offset of the instruction to be relocated
  77. pub(crate) offset: u64,
  78. pub(crate) size: u8,
  79. // index of the symbol to relocate to
  80. pub(crate) symbol_index: usize,
  81. }
  82. #[derive(Debug, Clone)]
  83. pub(crate) struct Symbol {
  84. pub(crate) index: usize,
  85. pub(crate) section_index: Option<usize>,
  86. pub(crate) name: Option<String>,
  87. pub(crate) address: u64,
  88. pub(crate) size: u64,
  89. pub(crate) is_definition: bool,
  90. pub(crate) kind: SymbolKind,
  91. }
  92. impl Object {
  93. /// Relocates the map references
  94. pub fn relocate_maps<'a, I: Iterator<Item = (&'a str, std::os::fd::RawFd, &'a Map)>>(
  95. &mut self,
  96. maps: I,
  97. text_sections: &HashSet<usize>,
  98. ) -> Result<(), BpfRelocationError> {
  99. let mut maps_by_section = HashMap::new();
  100. let mut maps_by_symbol = HashMap::new();
  101. for (name, fd, map) in maps {
  102. maps_by_section.insert(map.section_index(), (name, fd, map));
  103. if let Some(index) = map.symbol_index() {
  104. maps_by_symbol.insert(index, (name, fd, map));
  105. }
  106. }
  107. for function in self.functions.values_mut() {
  108. if let Some(relocations) = self.relocations.get(&function.section_index) {
  109. relocate_maps(
  110. function,
  111. relocations.values(),
  112. &maps_by_section,
  113. &maps_by_symbol,
  114. &self.symbol_table,
  115. text_sections,
  116. )
  117. .map_err(|error| BpfRelocationError {
  118. function: function.name.clone(),
  119. error,
  120. })?;
  121. }
  122. }
  123. Ok(())
  124. }
  125. /// Relocates function calls
  126. pub fn relocate_calls(
  127. &mut self,
  128. text_sections: &HashSet<usize>,
  129. ) -> Result<(), BpfRelocationError> {
  130. for (name, program) in self.programs.iter() {
  131. let linker = FunctionLinker::new(
  132. &self.functions,
  133. &self.relocations,
  134. &self.symbol_table,
  135. text_sections,
  136. );
  137. let func_orig =
  138. self.functions
  139. .get(&program.function_key())
  140. .ok_or_else(|| BpfRelocationError {
  141. function: name.clone(),
  142. error: RelocationError::UnknownProgram {
  143. section_index: program.section_index,
  144. address: program.address,
  145. },
  146. })?;
  147. let func = linker.link(func_orig).map_err(|error| BpfRelocationError {
  148. function: name.to_owned(),
  149. error,
  150. })?;
  151. self.functions.insert(program.function_key(), func);
  152. }
  153. Ok(())
  154. }
  155. }
  156. fn relocate_maps<'a, I: Iterator<Item = &'a Relocation>>(
  157. fun: &mut Function,
  158. relocations: I,
  159. maps_by_section: &HashMap<usize, (&str, std::os::fd::RawFd, &Map)>,
  160. maps_by_symbol: &HashMap<usize, (&str, std::os::fd::RawFd, &Map)>,
  161. symbol_table: &HashMap<usize, Symbol>,
  162. text_sections: &HashSet<usize>,
  163. ) -> Result<(), RelocationError> {
  164. let section_offset = fun.section_offset;
  165. let instructions = &mut fun.instructions;
  166. let function_size = instructions.len() * INS_SIZE;
  167. for (rel_n, rel) in relocations.enumerate() {
  168. let rel_offset = rel.offset as usize;
  169. if rel_offset < section_offset || rel_offset >= section_offset + function_size {
  170. // the relocation doesn't apply to this function
  171. continue;
  172. }
  173. // make sure that the relocation offset is properly aligned
  174. let ins_offset = rel_offset - section_offset;
  175. if ins_offset % INS_SIZE != 0 {
  176. return Err(RelocationError::InvalidRelocationOffset {
  177. offset: rel.offset,
  178. relocation_number: rel_n,
  179. });
  180. }
  181. let ins_index = ins_offset / INS_SIZE;
  182. // a map relocation points to the ELF section that contains the map
  183. let sym = symbol_table
  184. .get(&rel.symbol_index)
  185. .ok_or(RelocationError::UnknownSymbol {
  186. index: rel.symbol_index,
  187. })?;
  188. let Some(section_index) = sym.section_index else {
  189. // this is not a map relocation
  190. continue;
  191. };
  192. // calls and relocation to .text symbols are handled in a separate step
  193. if insn_is_call(&instructions[ins_index]) || text_sections.contains(&section_index) {
  194. continue;
  195. }
  196. let (_name, fd, map) = if let Some(m) = maps_by_symbol.get(&rel.symbol_index) {
  197. let map = &m.2;
  198. debug!(
  199. "relocating map by symbol index {:?}, kind {:?} at insn {ins_index} in section {}",
  200. map.symbol_index(),
  201. map.section_kind(),
  202. fun.section_index.0
  203. );
  204. debug_assert_eq!(map.symbol_index().unwrap(), rel.symbol_index);
  205. m
  206. } else {
  207. let Some(m) = maps_by_section.get(&section_index) else {
  208. debug!("failed relocating map by section index {}", section_index);
  209. return Err(RelocationError::SectionNotFound {
  210. symbol_index: rel.symbol_index,
  211. symbol_name: sym.name.clone(),
  212. section_index,
  213. });
  214. };
  215. let map = &m.2;
  216. debug!(
  217. "relocating map by section index {}, kind {:?} at insn {ins_index} in section {}",
  218. map.section_index(),
  219. map.section_kind(),
  220. fun.section_index.0,
  221. );
  222. debug_assert_eq!(map.symbol_index(), None);
  223. debug_assert!(matches!(
  224. map.section_kind(),
  225. BpfSectionKind::Bss | BpfSectionKind::Data | BpfSectionKind::Rodata
  226. ));
  227. m
  228. };
  229. debug_assert_eq!(map.section_index(), section_index);
  230. if !map.data().is_empty() {
  231. instructions[ins_index].set_src_reg(BPF_PSEUDO_MAP_VALUE as u8);
  232. instructions[ins_index + 1].imm = instructions[ins_index].imm + sym.address as i32;
  233. } else {
  234. instructions[ins_index].set_src_reg(BPF_PSEUDO_MAP_FD as u8);
  235. }
  236. instructions[ins_index].imm = *fd;
  237. }
  238. Ok(())
  239. }
  240. struct FunctionLinker<'a> {
  241. functions: &'a BTreeMap<(usize, u64), Function>,
  242. linked_functions: HashMap<u64, usize>,
  243. relocations: &'a HashMap<SectionIndex, HashMap<u64, Relocation>>,
  244. symbol_table: &'a HashMap<usize, Symbol>,
  245. text_sections: &'a HashSet<usize>,
  246. }
  247. impl<'a> FunctionLinker<'a> {
  248. fn new(
  249. functions: &'a BTreeMap<(usize, u64), Function>,
  250. relocations: &'a HashMap<SectionIndex, HashMap<u64, Relocation>>,
  251. symbol_table: &'a HashMap<usize, Symbol>,
  252. text_sections: &'a HashSet<usize>,
  253. ) -> FunctionLinker<'a> {
  254. FunctionLinker {
  255. functions,
  256. linked_functions: HashMap::new(),
  257. relocations,
  258. symbol_table,
  259. text_sections,
  260. }
  261. }
  262. fn link(mut self, program_function: &Function) -> Result<Function, RelocationError> {
  263. let mut fun = program_function.clone();
  264. // relocate calls in the program's main function. As relocation happens,
  265. // it will trigger linking in all the callees.
  266. self.relocate(&mut fun, program_function)?;
  267. // this now includes the program function plus all the other functions called during
  268. // execution
  269. Ok(fun)
  270. }
  271. fn link_function(
  272. &mut self,
  273. program: &mut Function,
  274. fun: &Function,
  275. ) -> Result<usize, RelocationError> {
  276. if let Some(fun_ins_index) = self.linked_functions.get(&fun.address) {
  277. return Ok(*fun_ins_index);
  278. };
  279. // append fun.instructions to the program and record that `fun.address` has been inserted
  280. // at `start_ins`. We'll use `start_ins` to do pc-relative calls.
  281. let start_ins = program.instructions.len();
  282. program.instructions.extend(&fun.instructions);
  283. debug!(
  284. "linked function `{}` at instruction {}",
  285. fun.name, start_ins
  286. );
  287. // link func and line info into the main program
  288. // the offset needs to be adjusted
  289. self.link_func_and_line_info(program, fun, start_ins)?;
  290. self.linked_functions.insert(fun.address, start_ins);
  291. // relocate `fun`, recursively linking in all the callees
  292. self.relocate(program, fun)?;
  293. Ok(start_ins)
  294. }
  295. fn relocate(&mut self, program: &mut Function, fun: &Function) -> Result<(), RelocationError> {
  296. let relocations = self.relocations.get(&fun.section_index);
  297. let n_instructions = fun.instructions.len();
  298. let start_ins = program.instructions.len() - n_instructions;
  299. debug!(
  300. "relocating program `{}` function `{}` size {}",
  301. program.name, fun.name, n_instructions
  302. );
  303. // process all the instructions. We can't only loop over relocations since we need to
  304. // patch pc-relative calls too.
  305. for ins_index in start_ins..start_ins + n_instructions {
  306. let ins = program.instructions[ins_index];
  307. let is_call = insn_is_call(&ins);
  308. let rel = relocations
  309. .and_then(|relocations| {
  310. relocations
  311. .get(&((fun.section_offset + (ins_index - start_ins) * INS_SIZE) as u64))
  312. })
  313. .and_then(|rel| {
  314. // get the symbol for the relocation
  315. self.symbol_table
  316. .get(&rel.symbol_index)
  317. .map(|sym| (rel, sym))
  318. })
  319. .filter(|(_rel, sym)| {
  320. // only consider text relocations, data relocations are
  321. // relocated in relocate_maps()
  322. sym.kind == SymbolKind::Text
  323. || sym
  324. .section_index
  325. .map(|section_index| self.text_sections.contains(&section_index))
  326. .unwrap_or(false)
  327. });
  328. // not a call and not a text relocation, we don't need to do anything
  329. if !is_call && rel.is_none() {
  330. continue;
  331. }
  332. let (callee_section_index, callee_address) = if let Some((rel, sym)) = rel {
  333. let address = match sym.kind {
  334. SymbolKind::Text => sym.address,
  335. // R_BPF_64_32 this is a call
  336. SymbolKind::Section if rel.size == 32 => {
  337. sym.address + (ins.imm + 1) as u64 * INS_SIZE as u64
  338. }
  339. // R_BPF_64_64 this is a ld_imm64 text relocation
  340. SymbolKind::Section if rel.size == 64 => sym.address + ins.imm as u64,
  341. _ => todo!(), // FIXME: return an error here,
  342. };
  343. (sym.section_index.unwrap(), address)
  344. } else {
  345. // The caller and the callee are in the same ELF section and this is a pc-relative
  346. // call. Resolve the pc-relative imm to an absolute address.
  347. let ins_size = INS_SIZE as i64;
  348. (
  349. fun.section_index.0,
  350. (fun.section_offset as i64
  351. + ((ins_index - start_ins) as i64) * ins_size
  352. + (ins.imm + 1) as i64 * ins_size) as u64,
  353. )
  354. };
  355. debug!(
  356. "relocating {} to callee address {:#x} in section {} ({}) at instruction {ins_index}",
  357. if is_call { "call" } else { "reference" },
  358. callee_address,
  359. callee_section_index,
  360. if rel.is_some() {
  361. "relocation"
  362. } else {
  363. "pc-relative"
  364. },
  365. );
  366. // lookup and link the callee if it hasn't been linked already. `callee_ins_index` will
  367. // contain the instruction index of the callee inside the program.
  368. let callee = self
  369. .functions
  370. .get(&(callee_section_index, callee_address))
  371. .ok_or(RelocationError::UnknownFunction {
  372. address: callee_address,
  373. caller_name: fun.name.clone(),
  374. })?;
  375. debug!("callee is `{}`", callee.name);
  376. let callee_ins_index = self.link_function(program, callee)? as i32;
  377. let ins = &mut program.instructions[ins_index];
  378. let ins_index = ins_index as i32;
  379. ins.imm = callee_ins_index - ins_index - 1;
  380. debug!(
  381. "callee `{}` is at ins {callee_ins_index}, {} from current instruction {ins_index}",
  382. callee.name, ins.imm
  383. );
  384. if !is_call {
  385. ins.set_src_reg(BPF_PSEUDO_FUNC as u8);
  386. }
  387. }
  388. debug!(
  389. "finished relocating program `{}` function `{}`",
  390. program.name, fun.name
  391. );
  392. Ok(())
  393. }
  394. fn link_func_and_line_info(
  395. &mut self,
  396. program: &mut Function,
  397. fun: &Function,
  398. start: usize,
  399. ) -> Result<(), RelocationError> {
  400. let func_info = &fun.func_info.func_info;
  401. let func_info = func_info.iter().cloned().map(|mut info| {
  402. // `start` is the new instruction offset of `fun` within `program`
  403. info.insn_off = start as u32;
  404. info
  405. });
  406. program.func_info.func_info.extend(func_info);
  407. program.func_info.num_info = program.func_info.func_info.len() as u32;
  408. let line_info = &fun.line_info.line_info;
  409. if !line_info.is_empty() {
  410. // this is the original offset
  411. let original_start_off = line_info[0].insn_off;
  412. let line_info = line_info.iter().cloned().map(|mut info| {
  413. // rebase offsets on top of start, which is the offset of the
  414. // function in the program being linked
  415. info.insn_off = start as u32 + (info.insn_off - original_start_off);
  416. info
  417. });
  418. program.line_info.line_info.extend(line_info);
  419. program.line_info.num_info = program.func_info.func_info.len() as u32;
  420. }
  421. Ok(())
  422. }
  423. }
  424. fn insn_is_call(ins: &bpf_insn) -> bool {
  425. let klass = (ins.code & 0x07) as u32;
  426. let op = (ins.code & 0xF0) as u32;
  427. let src = (ins.code & 0x08) as u32;
  428. klass == BPF_JMP
  429. && op == BPF_CALL
  430. && src == BPF_K
  431. && ins.src_reg() as u32 == BPF_PSEUDO_CALL
  432. && ins.dst_reg() == 0
  433. && ins.off == 0
  434. }
  435. #[cfg(test)]
  436. mod test {
  437. use alloc::{string::ToString, vec, vec::Vec};
  438. use super::*;
  439. use crate::{
  440. maps::{BtfMap, LegacyMap, Map},
  441. BpfSectionKind,
  442. };
  443. fn fake_sym(index: usize, section_index: usize, address: u64, name: &str, size: u64) -> Symbol {
  444. Symbol {
  445. index,
  446. section_index: Some(section_index),
  447. name: Some(name.to_string()),
  448. address,
  449. size,
  450. is_definition: false,
  451. kind: SymbolKind::Data,
  452. }
  453. }
  454. fn ins(bytes: &[u8]) -> bpf_insn {
  455. unsafe { core::ptr::read_unaligned(bytes.as_ptr() as *const _) }
  456. }
  457. fn fake_legacy_map(symbol_index: usize) -> Map {
  458. Map::Legacy(LegacyMap {
  459. def: Default::default(),
  460. section_index: 0,
  461. section_kind: BpfSectionKind::Undefined,
  462. symbol_index: Some(symbol_index),
  463. data: Vec::new(),
  464. })
  465. }
  466. fn fake_btf_map(symbol_index: usize) -> Map {
  467. Map::Btf(BtfMap {
  468. def: Default::default(),
  469. section_index: 0,
  470. symbol_index,
  471. data: Vec::new(),
  472. })
  473. }
  474. fn fake_func(name: &str, instructions: Vec<bpf_insn>) -> Function {
  475. Function {
  476. address: Default::default(),
  477. name: name.to_string(),
  478. section_index: SectionIndex(0),
  479. section_offset: Default::default(),
  480. instructions,
  481. func_info: Default::default(),
  482. line_info: Default::default(),
  483. func_info_rec_size: Default::default(),
  484. line_info_rec_size: Default::default(),
  485. }
  486. }
  487. #[test]
  488. fn test_single_legacy_map_relocation() {
  489. let mut fun = fake_func(
  490. "test",
  491. vec![ins(&[
  492. 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  493. 0x00, 0x00,
  494. ])],
  495. );
  496. let symbol_table = HashMap::from([(1, fake_sym(1, 0, 0, "test_map", 0))]);
  497. let relocations = [Relocation {
  498. offset: 0x0,
  499. symbol_index: 1,
  500. size: 64,
  501. }];
  502. let maps_by_section = HashMap::new();
  503. let map = fake_legacy_map(1);
  504. let maps_by_symbol = HashMap::from([(1, ("test_map", 1, &map))]);
  505. relocate_maps(
  506. &mut fun,
  507. relocations.iter(),
  508. &maps_by_section,
  509. &maps_by_symbol,
  510. &symbol_table,
  511. &HashSet::new(),
  512. )
  513. .unwrap();
  514. assert_eq!(fun.instructions[0].src_reg(), BPF_PSEUDO_MAP_FD as u8);
  515. assert_eq!(fun.instructions[0].imm, 1);
  516. }
  517. #[test]
  518. fn test_multiple_legacy_map_relocation() {
  519. let mut fun = fake_func(
  520. "test",
  521. vec![
  522. ins(&[
  523. 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  524. 0x00, 0x00, 0x00,
  525. ]),
  526. ins(&[
  527. 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  528. 0x00, 0x00, 0x00,
  529. ]),
  530. ],
  531. );
  532. let symbol_table = HashMap::from([
  533. (1, fake_sym(1, 0, 0, "test_map_1", 0)),
  534. (2, fake_sym(2, 0, 0, "test_map_2", 0)),
  535. ]);
  536. let relocations = [
  537. Relocation {
  538. offset: 0x0,
  539. symbol_index: 1,
  540. size: 64,
  541. },
  542. Relocation {
  543. offset: mem::size_of::<bpf_insn>() as u64,
  544. symbol_index: 2,
  545. size: 64,
  546. },
  547. ];
  548. let maps_by_section = HashMap::new();
  549. let map_1 = fake_legacy_map(1);
  550. let map_2 = fake_legacy_map(2);
  551. let maps_by_symbol = HashMap::from([
  552. (1, ("test_map_1", 1, &map_1)),
  553. (2, ("test_map_2", 2, &map_2)),
  554. ]);
  555. relocate_maps(
  556. &mut fun,
  557. relocations.iter(),
  558. &maps_by_section,
  559. &maps_by_symbol,
  560. &symbol_table,
  561. &HashSet::new(),
  562. )
  563. .unwrap();
  564. assert_eq!(fun.instructions[0].src_reg(), BPF_PSEUDO_MAP_FD as u8);
  565. assert_eq!(fun.instructions[0].imm, 1);
  566. assert_eq!(fun.instructions[1].src_reg(), BPF_PSEUDO_MAP_FD as u8);
  567. assert_eq!(fun.instructions[1].imm, 2);
  568. }
  569. #[test]
  570. fn test_single_btf_map_relocation() {
  571. let mut fun = fake_func(
  572. "test",
  573. vec![ins(&[
  574. 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  575. 0x00, 0x00,
  576. ])],
  577. );
  578. let symbol_table = HashMap::from([(1, fake_sym(1, 0, 0, "test_map", 0))]);
  579. let relocations = [Relocation {
  580. offset: 0x0,
  581. symbol_index: 1,
  582. size: 64,
  583. }];
  584. let maps_by_section = HashMap::new();
  585. let map = fake_btf_map(1);
  586. let maps_by_symbol = HashMap::from([(1, ("test_map", 1, &map))]);
  587. relocate_maps(
  588. &mut fun,
  589. relocations.iter(),
  590. &maps_by_section,
  591. &maps_by_symbol,
  592. &symbol_table,
  593. &HashSet::new(),
  594. )
  595. .unwrap();
  596. assert_eq!(fun.instructions[0].src_reg(), BPF_PSEUDO_MAP_FD as u8);
  597. assert_eq!(fun.instructions[0].imm, 1);
  598. }
  599. #[test]
  600. fn test_multiple_btf_map_relocation() {
  601. let mut fun = fake_func(
  602. "test",
  603. vec![
  604. ins(&[
  605. 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  606. 0x00, 0x00, 0x00,
  607. ]),
  608. ins(&[
  609. 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  610. 0x00, 0x00, 0x00,
  611. ]),
  612. ],
  613. );
  614. let symbol_table = HashMap::from([
  615. (1, fake_sym(1, 0, 0, "test_map_1", 0)),
  616. (2, fake_sym(2, 0, 0, "test_map_2", 0)),
  617. ]);
  618. let relocations = [
  619. Relocation {
  620. offset: 0x0,
  621. symbol_index: 1,
  622. size: 64,
  623. },
  624. Relocation {
  625. offset: mem::size_of::<bpf_insn>() as u64,
  626. symbol_index: 2,
  627. size: 64,
  628. },
  629. ];
  630. let maps_by_section = HashMap::new();
  631. let map_1 = fake_btf_map(1);
  632. let map_2 = fake_btf_map(2);
  633. let maps_by_symbol = HashMap::from([
  634. (1, ("test_map_1", 1, &map_1)),
  635. (2, ("test_map_2", 2, &map_2)),
  636. ]);
  637. relocate_maps(
  638. &mut fun,
  639. relocations.iter(),
  640. &maps_by_section,
  641. &maps_by_symbol,
  642. &symbol_table,
  643. &HashSet::new(),
  644. )
  645. .unwrap();
  646. assert_eq!(fun.instructions[0].src_reg(), BPF_PSEUDO_MAP_FD as u8);
  647. assert_eq!(fun.instructions[0].imm, 1);
  648. assert_eq!(fun.instructions[1].src_reg(), BPF_PSEUDO_MAP_FD as u8);
  649. assert_eq!(fun.instructions[1].imm, 2);
  650. }
  651. }