assembler.rs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. // SPDX-License-Identifier: (Apache-2.0 OR MIT)
  2. // Copyright 2017 Rich Lane <[email protected]>
  3. //! This module translates eBPF assembly language to binary.
  4. use alloc::{
  5. collections::BTreeMap,
  6. format,
  7. string::{String, ToString},
  8. vec,
  9. vec::Vec,
  10. };
  11. use self::InstructionType::{
  12. AluBinary, AluUnary, Call, Endian, JumpConditional, JumpUnconditional, LoadAbs, LoadImm,
  13. LoadInd, LoadReg, NoOperand, StoreImm, StoreReg,
  14. };
  15. use crate::{
  16. asm_parser::{
  17. parse, Instruction, Operand,
  18. Operand::{Integer, Memory, Nil, Register},
  19. },
  20. ebpf::{self, Insn},
  21. };
  22. #[derive(Clone, Copy, Debug, PartialEq)]
  23. enum InstructionType {
  24. AluBinary,
  25. AluUnary,
  26. LoadImm,
  27. LoadAbs,
  28. LoadInd,
  29. LoadReg,
  30. StoreImm,
  31. StoreReg,
  32. JumpUnconditional,
  33. JumpConditional,
  34. Call,
  35. Endian(i64),
  36. NoOperand,
  37. }
  38. fn make_instruction_map() -> BTreeMap<String, (InstructionType, u8)> {
  39. let mut result = BTreeMap::new();
  40. let alu_binary_ops = [
  41. ("add", ebpf::BPF_ADD),
  42. ("sub", ebpf::BPF_SUB),
  43. ("mul", ebpf::BPF_MUL),
  44. ("div", ebpf::BPF_DIV),
  45. ("or", ebpf::BPF_OR),
  46. ("and", ebpf::BPF_AND),
  47. ("lsh", ebpf::BPF_LSH),
  48. ("rsh", ebpf::BPF_RSH),
  49. ("mod", ebpf::BPF_MOD),
  50. ("xor", ebpf::BPF_XOR),
  51. ("mov", ebpf::BPF_MOV),
  52. ("arsh", ebpf::BPF_ARSH),
  53. ];
  54. let mem_sizes = [
  55. ("w", ebpf::BPF_W),
  56. ("h", ebpf::BPF_H),
  57. ("b", ebpf::BPF_B),
  58. ("dw", ebpf::BPF_DW),
  59. ];
  60. let jump_conditions = [
  61. ("jeq", ebpf::BPF_JEQ),
  62. ("jgt", ebpf::BPF_JGT),
  63. ("jge", ebpf::BPF_JGE),
  64. ("jlt", ebpf::BPF_JLT),
  65. ("jle", ebpf::BPF_JLE),
  66. ("jset", ebpf::BPF_JSET),
  67. ("jne", ebpf::BPF_JNE),
  68. ("jsgt", ebpf::BPF_JSGT),
  69. ("jsge", ebpf::BPF_JSGE),
  70. ("jslt", ebpf::BPF_JSLT),
  71. ("jsle", ebpf::BPF_JSLE),
  72. ];
  73. {
  74. let mut entry = |name: &str, inst_type: InstructionType, opc: u8| {
  75. result.insert(name.to_string(), (inst_type, opc))
  76. };
  77. // Miscellaneous.
  78. entry("exit", NoOperand, ebpf::EXIT);
  79. entry("ja", JumpUnconditional, ebpf::JA);
  80. entry("call", Call, ebpf::CALL);
  81. entry("lddw", LoadImm, ebpf::LD_DW_IMM);
  82. // AluUnary.
  83. entry("neg", AluUnary, ebpf::NEG64);
  84. entry("neg32", AluUnary, ebpf::NEG32);
  85. entry("neg64", AluUnary, ebpf::NEG64);
  86. // AluBinary.
  87. for &(name, opc) in &alu_binary_ops {
  88. entry(name, AluBinary, ebpf::BPF_ALU64 | opc);
  89. entry(&format!("{name}32"), AluBinary, ebpf::BPF_ALU | opc);
  90. entry(&format!("{name}64"), AluBinary, ebpf::BPF_ALU64 | opc);
  91. }
  92. // LoadAbs, LoadInd, LoadReg, StoreImm, and StoreReg.
  93. for &(suffix, size) in &mem_sizes {
  94. entry(
  95. &format!("ldabs{suffix}"),
  96. LoadAbs,
  97. ebpf::BPF_ABS | ebpf::BPF_LD | size,
  98. );
  99. entry(
  100. &format!("ldind{suffix}"),
  101. LoadInd,
  102. ebpf::BPF_IND | ebpf::BPF_LD | size,
  103. );
  104. entry(
  105. &format!("ldx{suffix}"),
  106. LoadReg,
  107. ebpf::BPF_MEM | ebpf::BPF_LDX | size,
  108. );
  109. entry(
  110. &format!("st{suffix}"),
  111. StoreImm,
  112. ebpf::BPF_MEM | ebpf::BPF_ST | size,
  113. );
  114. entry(
  115. &format!("stx{suffix}"),
  116. StoreReg,
  117. ebpf::BPF_MEM | ebpf::BPF_STX | size,
  118. );
  119. }
  120. // JumpConditional.
  121. for &(name, condition) in &jump_conditions {
  122. entry(name, JumpConditional, ebpf::BPF_JMP | condition);
  123. entry(
  124. &format!("{name}32"),
  125. JumpConditional,
  126. ebpf::BPF_JMP32 | condition,
  127. );
  128. }
  129. // Endian.
  130. for &size in &[16, 32, 64] {
  131. entry(&format!("be{size}"), Endian(size), ebpf::BE);
  132. entry(&format!("le{size}"), Endian(size), ebpf::LE);
  133. }
  134. }
  135. result
  136. }
  137. fn insn(opc: u8, dst: i64, src: i64, off: i64, imm: i64) -> Result<Insn, String> {
  138. if !(0..16).contains(&dst) {
  139. return Err(format!("Invalid destination register {dst}"));
  140. }
  141. if dst < 0 || src >= 16 {
  142. return Err(format!("Invalid source register {src}"));
  143. }
  144. if !(-32768..32768).contains(&off) {
  145. return Err(format!("Invalid offset {off}"));
  146. }
  147. if !(-2147483648..2147483648).contains(&imm) {
  148. return Err(format!("Invalid immediate {imm}"));
  149. }
  150. Ok(Insn {
  151. opc,
  152. dst: dst as u8,
  153. src: src as u8,
  154. off: off as i16,
  155. imm: imm as i32,
  156. })
  157. }
  158. // TODO Use slice patterns when available and remove this function.
  159. fn operands_tuple(operands: &[Operand]) -> Result<(Operand, Operand, Operand), String> {
  160. match operands.len() {
  161. 0 => Ok((Nil, Nil, Nil)),
  162. 1 => Ok((operands[0], Nil, Nil)),
  163. 2 => Ok((operands[0], operands[1], Nil)),
  164. 3 => Ok((operands[0], operands[1], operands[2])),
  165. _ => Err("Too many operands".to_string()),
  166. }
  167. }
  168. fn encode(inst_type: InstructionType, opc: u8, operands: &[Operand]) -> Result<Insn, String> {
  169. let (a, b, c) = (operands_tuple(operands))?;
  170. match (inst_type, a, b, c) {
  171. (AluBinary, Register(dst), Register(src), Nil) => insn(opc | ebpf::BPF_X, dst, src, 0, 0),
  172. (AluBinary, Register(dst), Integer(imm), Nil) => insn(opc | ebpf::BPF_K, dst, 0, 0, imm),
  173. (AluUnary, Register(dst), Nil, Nil) => insn(opc, dst, 0, 0, 0),
  174. (LoadAbs, Integer(imm), Nil, Nil) => insn(opc, 0, 0, 0, imm),
  175. (LoadInd, Register(src), Integer(imm), Nil) => insn(opc, 0, src, 0, imm),
  176. (LoadReg, Register(dst), Memory(src, off), Nil)
  177. | (StoreReg, Memory(dst, off), Register(src), Nil) => insn(opc, dst, src, off, 0),
  178. (StoreImm, Memory(dst, off), Integer(imm), Nil) => insn(opc, dst, 0, off, imm),
  179. (NoOperand, Nil, Nil, Nil) => insn(opc, 0, 0, 0, 0),
  180. (JumpUnconditional, Integer(off), Nil, Nil) => insn(opc, 0, 0, off, 0),
  181. (JumpConditional, Register(dst), Register(src), Integer(off)) => {
  182. insn(opc | ebpf::BPF_X, dst, src, off, 0)
  183. }
  184. (JumpConditional, Register(dst), Integer(imm), Integer(off)) => {
  185. insn(opc | ebpf::BPF_K, dst, 0, off, imm)
  186. }
  187. (Call, Integer(imm), Nil, Nil) => insn(opc, 0, 0, 0, imm),
  188. (Endian(size), Register(dst), Nil, Nil) => insn(opc, dst, 0, 0, size),
  189. (LoadImm, Register(dst), Integer(imm), Nil) => insn(opc, dst, 0, 0, (imm << 32) >> 32),
  190. _ => Err(format!("Unexpected operands: {operands:?}")),
  191. }
  192. }
  193. fn assemble_internal(parsed: &[Instruction]) -> Result<Vec<Insn>, String> {
  194. let instruction_map = make_instruction_map();
  195. let mut result: Vec<Insn> = vec![];
  196. for instruction in parsed {
  197. let name = instruction.name.as_str();
  198. match instruction_map.get(name) {
  199. Some(&(inst_type, opc)) => {
  200. match encode(inst_type, opc, &instruction.operands) {
  201. Ok(insn) => result.push(insn),
  202. Err(msg) => return Err(format!("Failed to encode {name}: {msg}")),
  203. }
  204. // Special case for lddw.
  205. if let LoadImm = inst_type {
  206. if let Integer(imm) = instruction.operands[1] {
  207. result.push(insn(0, 0, 0, 0, imm >> 32).unwrap());
  208. }
  209. }
  210. }
  211. None => return Err(format!("Invalid instruction {name:?}")),
  212. }
  213. }
  214. Ok(result)
  215. }
  216. /// Parse assembly source and translate to binary.
  217. ///
  218. /// # Examples
  219. ///
  220. /// ```
  221. /// use rbpf::assembler::assemble;
  222. /// let prog = assemble("add64 r1, 0x605
  223. /// mov64 r2, 0x32
  224. /// mov64 r1, r0
  225. /// be16 r0
  226. /// neg64 r2
  227. /// exit");
  228. /// println!("{:?}", prog);
  229. /// # assert_eq!(prog,
  230. /// # Ok(vec![0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00,
  231. /// # 0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
  232. /// # 0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  233. /// # 0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
  234. /// # 0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  235. /// # 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]));
  236. /// ```
  237. ///
  238. /// This will produce the following output:
  239. ///
  240. /// ```test
  241. /// Ok([0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00,
  242. /// 0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
  243. /// 0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  244. /// 0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
  245. /// 0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  246. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
  247. /// ```
  248. pub fn assemble(src: &str) -> Result<Vec<u8>, String> {
  249. let parsed = (parse(src))?;
  250. let insns = (assemble_internal(&parsed))?;
  251. let mut result: Vec<u8> = vec![];
  252. for insn in insns {
  253. result.extend_from_slice(&insn.to_array());
  254. }
  255. Ok(result)
  256. }