instruction.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. use crate::dynsym::RelocationType;
  2. use crate::lexer::{ImmediateValue, Token};
  3. use crate::syscall::SYSCALLS;
  4. use crate::errors::CompileError;
  5. use sbpf_common::opcode::Opcode;
  6. use std::ops::Range;
  7. #[derive(Debug, Clone)]
  8. pub struct Instruction {
  9. pub opcode: Opcode,
  10. pub operands: Vec<Token>,
  11. pub span: Range<usize>,
  12. }
  13. impl Instruction {
  14. //
  15. pub fn get_size(&self) -> u64 {
  16. match self.opcode {
  17. Opcode::Lddw => 16,
  18. _ => 8,
  19. }
  20. }
  21. //
  22. pub fn needs_relocation(&self) -> bool {
  23. match self.opcode {
  24. Opcode::Call | Opcode::Lddw => {
  25. matches!(&self.operands.last(), Some(Token::Identifier(_, _)))
  26. }
  27. _ => false,
  28. }
  29. }
  30. //
  31. pub fn is_jump(&self) -> bool {
  32. matches!(
  33. self.opcode,
  34. Opcode::Ja
  35. | Opcode::JeqImm
  36. | Opcode::JgtImm
  37. | Opcode::JgeImm
  38. | Opcode::JltImm
  39. | Opcode::JleImm
  40. | Opcode::JsetImm
  41. | Opcode::JneImm
  42. | Opcode::JsgtImm
  43. | Opcode::JsgeImm
  44. | Opcode::JsltImm
  45. | Opcode::JsleImm
  46. | Opcode::JeqReg
  47. | Opcode::JgtReg
  48. | Opcode::JgeReg
  49. | Opcode::JltReg
  50. | Opcode::JleReg
  51. | Opcode::JsetReg
  52. | Opcode::JneReg
  53. | Opcode::JsgtReg
  54. | Opcode::JsgeReg
  55. | Opcode::JsltReg
  56. | Opcode::JsleReg
  57. )
  58. }
  59. //
  60. pub fn get_relocation_info(&self) -> (RelocationType, String) {
  61. match self.opcode {
  62. Opcode::Lddw => match &self.operands[1] {
  63. Token::Identifier(name, _) => (RelocationType::RSbf64Relative, name.clone()),
  64. _ => panic!("Expected label operand"),
  65. },
  66. _ => {
  67. if let Token::Identifier(name, _) = &self.operands[0] {
  68. (RelocationType::RSbfSyscall, name.clone())
  69. } else {
  70. panic!("Expected label operand")
  71. }
  72. }
  73. }
  74. }
  75. //
  76. pub fn from_bytes(bytes: &[u8]) -> Result<Self, CompileError> {
  77. let mut operands = Vec::new();
  78. let span = 0..bytes.len();
  79. let opcode = Opcode::from_u8(bytes[0]).unwrap();
  80. let reg = bytes[1];
  81. let src = reg >> 4;
  82. let dst = reg & 0x0f;
  83. let off = i16::from_le_bytes([bytes[2], bytes[3]]);
  84. let imm = match opcode {
  85. Opcode::Lddw => {
  86. let imm_low = i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
  87. let imm_high = i32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]);
  88. ((imm_high as i64) << 32) | (imm_low as u32 as i64)
  89. }
  90. _ => i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) as i64,
  91. };
  92. match opcode {
  93. Opcode::Lddw => {
  94. if src != 0 || off != 0 {
  95. return Err(CompileError::BytecodeError {
  96. error: format!("Lddw instruction expects src and off to be 0, but got src: {}, off: {}", src, off),
  97. span: span.clone(),
  98. custom_label: None,
  99. });
  100. }
  101. operands.push(Token::Register(dst, 1..2));
  102. operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..12));
  103. }
  104. Opcode::Call => {
  105. if let Some(name) = SYSCALLS.get(&(imm as u32)) {
  106. if reg != 0 || off != 0 {
  107. return Err(CompileError::BytecodeError {
  108. error: format!("Call instruction with syscall expects reg and off to be 0, but got reg: {}, off: {}", reg, off),
  109. span: span.clone(),
  110. custom_label: None,
  111. });
  112. }
  113. operands.push(Token::Identifier(name.to_string(), 4..8));
  114. } else {
  115. if reg != 16 || off != 0 {
  116. return Err(CompileError::BytecodeError {
  117. error: format!("Call instruction with immediate expects reg to be 16 and off to be 0, but got reg: {}, off: {}", reg, off),
  118. span: span.clone(),
  119. custom_label: None,
  120. });
  121. }
  122. operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..8));
  123. }
  124. }
  125. Opcode::Callx => {
  126. if src != 0 || off != 0 || imm != 0 {
  127. return Err(CompileError::BytecodeError {
  128. error: format!("Callx instruction expects src, off, and imm to be 0, but got src: {}, off: {}, imm: {}", src, off, imm),
  129. span: span.clone(),
  130. custom_label: None,
  131. });
  132. }
  133. // callx destination register is encoded in the dst field
  134. operands.push(Token::Register(dst, 1..2));
  135. }
  136. Opcode::Ja => {
  137. if reg != 0 || imm != 0 {
  138. return Err(CompileError::BytecodeError {
  139. error: format!("Ja instruction expects reg and imm to be 0, but got reg: {}, imm: {}", reg, imm),
  140. span: span.clone(),
  141. custom_label: None,
  142. });
  143. }
  144. operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
  145. }
  146. Opcode::JeqImm
  147. | Opcode::JgtImm
  148. | Opcode::JgeImm
  149. | Opcode::JltImm
  150. | Opcode::JleImm
  151. | Opcode::JsetImm
  152. | Opcode::JneImm
  153. | Opcode::JsgtImm
  154. | Opcode::JsgeImm
  155. | Opcode::JsltImm
  156. | Opcode::JsleImm => {
  157. if src != 0 {
  158. return Err(CompileError::BytecodeError {
  159. error: format!("Jump instruction with immediate expects src to be 0, but got src: {}", src),
  160. span: span.clone(),
  161. custom_label: None,
  162. });
  163. }
  164. operands.push(Token::Register(dst, 1..2));
  165. operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..8));
  166. operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
  167. }
  168. Opcode::JeqReg
  169. | Opcode::JgtReg
  170. | Opcode::JgeReg
  171. | Opcode::JltReg
  172. | Opcode::JleReg
  173. | Opcode::JsetReg
  174. | Opcode::JneReg
  175. | Opcode::JsgtReg
  176. | Opcode::JsgeReg
  177. | Opcode::JsltReg
  178. | Opcode::JsleReg => {
  179. if imm != 0 {
  180. return Err(CompileError::BytecodeError {
  181. error: format!("Jump instruction with register expects imm to be 0, but got imm: {}", imm),
  182. span: span.clone(),
  183. custom_label: None,
  184. });
  185. }
  186. operands.push(Token::Register(dst, 1..2));
  187. operands.push(Token::Register(src, 1..2));
  188. operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
  189. }
  190. // Arithmetic instructions with immediate values
  191. Opcode::Add32Imm
  192. | Opcode::Sub32Imm
  193. | Opcode::Mul32Imm
  194. | Opcode::Div32Imm
  195. | Opcode::Or32Imm
  196. | Opcode::And32Imm
  197. | Opcode::Lsh32Imm
  198. | Opcode::Rsh32Imm
  199. | Opcode::Mod32Imm
  200. | Opcode::Xor32Imm
  201. | Opcode::Mov32Imm
  202. | Opcode::Arsh32Imm
  203. | Opcode::Lmul32Imm
  204. | Opcode::Udiv32Imm
  205. | Opcode::Urem32Imm
  206. | Opcode::Sdiv32Imm
  207. | Opcode::Srem32Imm
  208. | Opcode::Add64Imm
  209. | Opcode::Sub64Imm
  210. | Opcode::Mul64Imm
  211. | Opcode::Div64Imm
  212. | Opcode::Or64Imm
  213. | Opcode::And64Imm
  214. | Opcode::Lsh64Imm
  215. | Opcode::Rsh64Imm
  216. | Opcode::Mod64Imm
  217. | Opcode::Xor64Imm
  218. | Opcode::Mov64Imm
  219. | Opcode::Arsh64Imm
  220. | Opcode::Hor64Imm
  221. | Opcode::Lmul64Imm
  222. | Opcode::Uhmul64Imm
  223. | Opcode::Udiv64Imm
  224. | Opcode::Urem64Imm
  225. | Opcode::Shmul64Imm
  226. | Opcode::Sdiv64Imm
  227. | Opcode::Srem64Imm
  228. | Opcode::Be
  229. | Opcode::Le => {
  230. if src != 0 || off != 0 {
  231. return Err(CompileError::BytecodeError {
  232. error: format!("Arithmetic instruction with immediate expects src and off to be 0, but got src: {}, off: {}", src, off),
  233. span: span.clone(),
  234. custom_label: None,
  235. });
  236. }
  237. operands.push(Token::Register(dst, 1..2));
  238. operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..8));
  239. }
  240. // Arithmetic instructions with register operands
  241. Opcode::Add32Reg
  242. | Opcode::Sub32Reg
  243. | Opcode::Mul32Reg
  244. | Opcode::Div32Reg
  245. | Opcode::Or32Reg
  246. | Opcode::And32Reg
  247. | Opcode::Lsh32Reg
  248. | Opcode::Rsh32Reg
  249. | Opcode::Mod32Reg
  250. | Opcode::Xor32Reg
  251. | Opcode::Mov32Reg
  252. | Opcode::Arsh32Reg
  253. | Opcode::Lmul32Reg
  254. | Opcode::Udiv32Reg
  255. | Opcode::Urem32Reg
  256. | Opcode::Sdiv32Reg
  257. | Opcode::Srem32Reg
  258. | Opcode::Add64Reg
  259. | Opcode::Sub64Reg
  260. | Opcode::Mul64Reg
  261. | Opcode::Div64Reg
  262. | Opcode::Or64Reg
  263. | Opcode::And64Reg
  264. | Opcode::Lsh64Reg
  265. | Opcode::Rsh64Reg
  266. | Opcode::Mod64Reg
  267. | Opcode::Xor64Reg
  268. | Opcode::Mov64Reg
  269. | Opcode::Arsh64Reg
  270. | Opcode::Lmul64Reg
  271. | Opcode::Uhmul64Reg
  272. | Opcode::Udiv64Reg
  273. | Opcode::Urem64Reg
  274. | Opcode::Shmul64Reg
  275. | Opcode::Sdiv64Reg
  276. | Opcode::Srem64Reg => {
  277. if off != 0 || imm != 0 {
  278. return Err(CompileError::BytecodeError {
  279. error: format!("Arithmetic instruction with register expects off and imm to be 0, but got off: {}, imm: {}", off, imm),
  280. span: span.clone(),
  281. custom_label: None,
  282. });
  283. }
  284. operands.push(Token::Register(dst, 1..2));
  285. operands.push(Token::Register(src, 1..2));
  286. }
  287. Opcode::Ldxw | Opcode::Ldxh | Opcode::Ldxb | Opcode::Ldxdw => {
  288. if imm != 0 {
  289. return Err(CompileError::BytecodeError {
  290. error: format!("Load instruction expects imm to be 0, but got imm: {}", imm),
  291. span: span.clone(),
  292. custom_label: None,
  293. });
  294. }
  295. operands.push(Token::Register(dst, 1..2));
  296. operands.push(Token::Register(src, 1..2));
  297. operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
  298. }
  299. Opcode::Stw | Opcode::Sth | Opcode::Stb | Opcode::Stdw => {
  300. if src != 0 {
  301. return Err(CompileError::BytecodeError {
  302. error: format!("Store instruction expects src to be 0, but got src: {}", src),
  303. span: span.clone(),
  304. custom_label: None,
  305. });
  306. }
  307. operands.push(Token::Register(dst, 1..2));
  308. operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
  309. operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..8));
  310. }
  311. Opcode::Stxb | Opcode::Stxh | Opcode::Stxw | Opcode::Stxdw => {
  312. if imm != 0 {
  313. return Err(CompileError::BytecodeError {
  314. error: format!("Store instruction with register expects imm to be 0, but got imm: {}", imm),
  315. span: span.clone(),
  316. custom_label: None,
  317. });
  318. }
  319. operands.push(Token::Register(dst, 1..2));
  320. operands.push(Token::Register(src, 1..2));
  321. operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
  322. }
  323. // Unary operations
  324. Opcode::Neg32 | Opcode::Neg64 | Opcode::Exit => {
  325. if src != 0 || off != 0 || imm != 0 {
  326. return Err(CompileError::BytecodeError {
  327. error: format!("Unary operation expects src, off, and imm to be 0, but got src: {}, off: {}, imm: {}", src, off, imm),
  328. span: span.clone(),
  329. custom_label: None,
  330. });
  331. }
  332. operands.push(Token::Register(dst, 1..2));
  333. }
  334. _ => {
  335. return Err(CompileError::BytecodeError {
  336. error: format!("Unsupported opcode: {:?}", opcode),
  337. span: span.clone(),
  338. custom_label: None,
  339. });
  340. }
  341. }
  342. Ok(Instruction {
  343. opcode,
  344. operands,
  345. span,
  346. })
  347. }
  348. }