assembler.rs 8.6 KB

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