string.rs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. // string operations
  2. //
  3. // cmp si di
  4. // movs 0 1 1/w A4
  5. // cmps 1 1 1/r A6
  6. // stos 0 0 1/w AA
  7. // lods 0 1 0 AC
  8. // scas 1 0 1/r AE
  9. // ins 0 0 1/w
  10. // outs 0 1 0
  11. use cpu::arith::{cmp8, cmp16, cmp32};
  12. use cpu::cpu::{
  13. get_seg, io_port_read8, io_port_read16, io_port_read32, io_port_write8, io_port_write16,
  14. io_port_write32, read_reg16, read_reg32, safe_read8, safe_read16, safe_read32s, safe_write8,
  15. safe_write16, safe_write32, set_reg_asize, test_privileges_for_io, translate_address_read,
  16. translate_address_write_and_can_skip_dirty, writable_or_pagefault, write_reg8, write_reg16,
  17. write_reg32, AL, AX, DX, EAX, ECX, EDI, ES, ESI, FLAG_DIRECTION,
  18. };
  19. use cpu::global_pointers::{flags, instruction_pointer, previous_ip};
  20. use cpu::memory::{
  21. in_mapped_range, memcpy_no_mmap_or_dirty_check, memset_no_mmap_or_dirty_check,
  22. read8_no_mmap_check, read16_no_mmap_check, read32_no_mmap_check, write8_no_mmap_or_dirty_check,
  23. write16_no_mmap_or_dirty_check, write32_no_mmap_or_dirty_check,
  24. };
  25. use page::Page;
  26. fn count_until_end_of_page(direction: i32, size: i32, addr: u32) -> u32 {
  27. (if direction == 1 {
  28. (0x1000 - (addr & 0xFFF)) / size as u32
  29. }
  30. else {
  31. (addr & 0xFFF) / size as u32 + 1
  32. }) as u32
  33. }
  34. #[derive(Copy, Clone)]
  35. enum Instruction {
  36. Movs,
  37. Lods,
  38. Stos,
  39. Scas,
  40. Cmps,
  41. Ins,
  42. Outs,
  43. }
  44. #[derive(PartialEq)]
  45. enum Size {
  46. B,
  47. W,
  48. D,
  49. }
  50. #[derive(Copy, Clone)]
  51. enum Rep {
  52. None,
  53. Z,
  54. NZ,
  55. }
  56. // We implement all string instructions here and rely on the inliner on doing its job of optimising
  57. // away anything known at compile time (check with `wasm-dis build/v86.wasm`)
  58. #[inline(always)]
  59. unsafe fn string_instruction(
  60. is_asize_32: bool,
  61. ds: i32,
  62. instruction: Instruction,
  63. size: Size,
  64. rep: Rep,
  65. ) {
  66. let asize_mask = if is_asize_32 { -1 } else { 0xFFFF };
  67. let direction = if 0 != *flags & FLAG_DIRECTION { -1 } else { 1 };
  68. let es = match instruction {
  69. Instruction::Movs
  70. | Instruction::Cmps
  71. | Instruction::Stos
  72. | Instruction::Scas
  73. | Instruction::Ins => return_on_pagefault!(get_seg(ES)),
  74. _ => 0,
  75. };
  76. let size_bytes = match size {
  77. Size::B => 1,
  78. Size::W => 2,
  79. Size::D => 4,
  80. };
  81. let size_mask = match size {
  82. Size::B => 0xFF,
  83. Size::W => 0xFFFF,
  84. Size::D => -1,
  85. };
  86. let increment = direction * size_bytes;
  87. let data = match instruction {
  88. Instruction::Stos | Instruction::Scas => read_reg32(EAX),
  89. _ => 0,
  90. };
  91. let mut src = match instruction {
  92. Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
  93. read_reg32(ESI) & asize_mask
  94. },
  95. _ => 0,
  96. };
  97. let mut dst = match instruction {
  98. Instruction::Movs
  99. | Instruction::Cmps
  100. | Instruction::Stos
  101. | Instruction::Scas
  102. | Instruction::Ins => read_reg32(EDI) & asize_mask,
  103. _ => 0,
  104. };
  105. let mut count = match rep {
  106. Rep::Z | Rep::NZ => {
  107. let c = (read_reg32(ECX) & asize_mask) as u32;
  108. if c == 0 {
  109. return;
  110. };
  111. c
  112. },
  113. Rep::None => 0,
  114. };
  115. let port = match instruction {
  116. Instruction::Ins | Instruction::Outs => {
  117. let port = read_reg16(DX);
  118. if !test_privileges_for_io(port, size_bytes) {
  119. return;
  120. }
  121. port
  122. },
  123. _ => 0,
  124. };
  125. let is_aligned = (ds + src) & (size_bytes - 1) == 0 && (es + dst) & (size_bytes - 1) == 0;
  126. let mut rep_fast = is_aligned
  127. && is_asize_32 // 16-bit address wraparound
  128. && match rep {
  129. Rep::NZ | Rep::Z => true,
  130. Rep::None => false,
  131. };
  132. let mut phys_dst = 0;
  133. let mut phys_src = 0;
  134. let mut skip_dirty_page = false;
  135. if rep_fast {
  136. match instruction {
  137. Instruction::Movs | Instruction::Stos | Instruction::Ins => {
  138. let (addr, skip) =
  139. return_on_pagefault!(translate_address_write_and_can_skip_dirty(es + dst));
  140. rep_fast = rep_fast && !in_mapped_range(addr);
  141. phys_dst = addr;
  142. skip_dirty_page = skip;
  143. },
  144. Instruction::Cmps | Instruction::Scas => {
  145. let addr = return_on_pagefault!(translate_address_read(es + dst));
  146. rep_fast = rep_fast && !in_mapped_range(addr);
  147. phys_dst = addr;
  148. skip_dirty_page = true;
  149. },
  150. _ => {},
  151. };
  152. match instruction {
  153. Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
  154. let addr = return_on_pagefault!(translate_address_read(ds + src));
  155. rep_fast = rep_fast && !in_mapped_range(addr);
  156. phys_src = addr;
  157. },
  158. _ => {},
  159. };
  160. match instruction {
  161. Instruction::Movs => {
  162. // note: This check is also valid for both direction == 1 and direction == -1
  163. let overlap = u32::max(phys_src, phys_dst) - u32::min(phys_src, phys_dst)
  164. < count * size_bytes as u32;
  165. rep_fast = rep_fast && !overlap;
  166. },
  167. _ => {},
  168. }
  169. }
  170. if rep_fast {
  171. let count_until_end_of_page = u32::min(
  172. count,
  173. match instruction {
  174. Instruction::Movs | Instruction::Cmps => u32::min(
  175. count_until_end_of_page(direction, size_bytes, phys_src),
  176. count_until_end_of_page(direction, size_bytes, phys_dst),
  177. ),
  178. Instruction::Stos | Instruction::Ins | Instruction::Scas => {
  179. count_until_end_of_page(direction, size_bytes, phys_dst)
  180. },
  181. Instruction::Lods | Instruction::Outs => {
  182. count_until_end_of_page(direction, size_bytes, phys_src)
  183. },
  184. },
  185. );
  186. dbg_assert!(count_until_end_of_page > 0);
  187. if !skip_dirty_page {
  188. ::jit::jit_dirty_page(::jit::get_jit_state(), Page::page_of(phys_dst));
  189. }
  190. let mut rep_cmp_finished = false;
  191. let mut i = 0;
  192. while i < count_until_end_of_page {
  193. i += 1;
  194. let src_val = match instruction {
  195. Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
  196. match size {
  197. Size::B => read8_no_mmap_check(phys_src),
  198. Size::W => read16_no_mmap_check(phys_src),
  199. Size::D => read32_no_mmap_check(phys_src),
  200. }
  201. },
  202. Instruction::Scas | Instruction::Stos => data & size_mask,
  203. Instruction::Ins => match size {
  204. Size::B => io_port_read8(port),
  205. Size::W => io_port_read16(port),
  206. Size::D => io_port_read32(port),
  207. },
  208. };
  209. let mut dst_val = 0;
  210. match instruction {
  211. Instruction::Cmps | Instruction::Scas => match size {
  212. Size::B => dst_val = read8_no_mmap_check(phys_dst),
  213. Size::W => dst_val = read16_no_mmap_check(phys_dst),
  214. Size::D => dst_val = read32_no_mmap_check(phys_dst),
  215. },
  216. Instruction::Outs => match size {
  217. Size::B => io_port_write8(port, src_val),
  218. Size::W => io_port_write16(port, src_val),
  219. Size::D => io_port_write32(port, src_val),
  220. },
  221. Instruction::Lods => match size {
  222. Size::B => write_reg8(AL, src_val),
  223. Size::W => write_reg16(AX, src_val),
  224. Size::D => write_reg32(EAX, src_val),
  225. },
  226. Instruction::Ins => match size {
  227. Size::B => write8_no_mmap_or_dirty_check(phys_dst, src_val),
  228. Size::W => write16_no_mmap_or_dirty_check(phys_dst, src_val),
  229. Size::D => write32_no_mmap_or_dirty_check(phys_dst, src_val),
  230. },
  231. Instruction::Movs => {
  232. if direction == -1 {
  233. phys_src -= (count_until_end_of_page - 1) * size_bytes as u32;
  234. phys_dst -= (count_until_end_of_page - 1) * size_bytes as u32;
  235. }
  236. memcpy_no_mmap_or_dirty_check(
  237. phys_src,
  238. phys_dst,
  239. count_until_end_of_page * size_bytes as u32,
  240. );
  241. i = count_until_end_of_page;
  242. break;
  243. },
  244. Instruction::Stos => match size {
  245. Size::B => {
  246. if direction == -1 {
  247. phys_dst -= count_until_end_of_page - 1
  248. }
  249. memset_no_mmap_or_dirty_check(
  250. phys_dst,
  251. src_val as u8,
  252. count_until_end_of_page,
  253. );
  254. i = count_until_end_of_page;
  255. break;
  256. },
  257. Size::W => write16_no_mmap_or_dirty_check(phys_dst, src_val),
  258. Size::D => write32_no_mmap_or_dirty_check(phys_dst, src_val),
  259. },
  260. };
  261. match instruction {
  262. Instruction::Movs
  263. | Instruction::Cmps
  264. | Instruction::Stos
  265. | Instruction::Scas
  266. | Instruction::Ins => {
  267. phys_dst += increment as u32;
  268. },
  269. _ => {},
  270. }
  271. match instruction {
  272. Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
  273. phys_src += increment as u32;
  274. },
  275. _ => {},
  276. };
  277. match instruction {
  278. Instruction::Scas | Instruction::Cmps => {
  279. let rep_cmp = match rep {
  280. Rep::Z => src_val == dst_val,
  281. Rep::NZ => src_val != dst_val,
  282. Rep::None => {
  283. dbg_assert!(false);
  284. true
  285. },
  286. };
  287. if !rep_cmp || count == i {
  288. match size {
  289. Size::B => cmp8(src_val, dst_val),
  290. Size::W => cmp16(src_val, dst_val),
  291. Size::D => cmp32(src_val, dst_val),
  292. };
  293. rep_cmp_finished = true;
  294. break;
  295. }
  296. },
  297. _ => {},
  298. }
  299. }
  300. dbg_assert!(i <= count);
  301. count -= i;
  302. if !rep_cmp_finished && count != 0 {
  303. // go back to the current instruction, since this loop just handles a single page
  304. *instruction_pointer = *previous_ip;
  305. }
  306. src += i as i32 * increment;
  307. dst += i as i32 * increment;
  308. }
  309. else {
  310. loop {
  311. match instruction {
  312. Instruction::Ins => {
  313. // check fault *before* reading from port
  314. // (technically not necessary according to Intel manuals)
  315. break_on_pagefault!(writable_or_pagefault(es + dst, size_bytes));
  316. },
  317. _ => {},
  318. };
  319. let src_val = match instruction {
  320. Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
  321. break_on_pagefault!(match size {
  322. Size::B => safe_read8(ds + src),
  323. Size::W => safe_read16(ds + src),
  324. Size::D => safe_read32s(ds + src),
  325. })
  326. },
  327. Instruction::Scas | Instruction::Stos => data & size_mask,
  328. Instruction::Ins => match size {
  329. Size::B => io_port_read8(port),
  330. Size::W => io_port_read16(port),
  331. Size::D => io_port_read32(port),
  332. },
  333. };
  334. let mut dst_val = 0;
  335. match instruction {
  336. Instruction::Cmps | Instruction::Scas => match size {
  337. Size::B => dst_val = break_on_pagefault!(safe_read8(es + dst)),
  338. Size::W => dst_val = break_on_pagefault!(safe_read16(es + dst)),
  339. Size::D => dst_val = break_on_pagefault!(safe_read32s(es + dst)),
  340. },
  341. Instruction::Outs => match size {
  342. Size::B => io_port_write8(port, src_val),
  343. Size::W => io_port_write16(port, src_val),
  344. Size::D => io_port_write32(port, src_val),
  345. },
  346. Instruction::Lods => match size {
  347. Size::B => write_reg8(AL, src_val),
  348. Size::W => write_reg16(AX, src_val),
  349. Size::D => write_reg32(EAX, src_val),
  350. },
  351. Instruction::Movs | Instruction::Stos | Instruction::Ins => match size {
  352. Size::B => break_on_pagefault!(safe_write8(es + dst, src_val)),
  353. Size::W => break_on_pagefault!(safe_write16(es + dst, src_val)),
  354. Size::D => break_on_pagefault!(safe_write32(es + dst, src_val)),
  355. },
  356. };
  357. match instruction {
  358. Instruction::Movs
  359. | Instruction::Cmps
  360. | Instruction::Stos
  361. | Instruction::Scas
  362. | Instruction::Ins => dst = dst + increment & asize_mask,
  363. _ => {},
  364. }
  365. match instruction {
  366. Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
  367. src = src + increment & asize_mask
  368. },
  369. _ => {},
  370. };
  371. let finished = match rep {
  372. Rep::Z | Rep::NZ => {
  373. let rep_cmp = match (rep, instruction) {
  374. (Rep::Z, Instruction::Scas | Instruction::Cmps) => src_val == dst_val,
  375. (Rep::NZ, Instruction::Scas | Instruction::Cmps) => src_val != dst_val,
  376. _ => true,
  377. };
  378. count -= 1;
  379. if count != 0 && rep_cmp {
  380. //*instruction_pointer = *previous_ip
  381. false
  382. }
  383. else {
  384. true
  385. }
  386. },
  387. Rep::None => true,
  388. };
  389. if finished {
  390. match instruction {
  391. Instruction::Scas | Instruction::Cmps => match size {
  392. Size::B => cmp8(src_val, dst_val),
  393. Size::W => cmp16(src_val, dst_val),
  394. Size::D => cmp32(src_val, dst_val),
  395. },
  396. _ => {},
  397. }
  398. break;
  399. }
  400. }
  401. }
  402. match instruction {
  403. Instruction::Movs
  404. | Instruction::Cmps
  405. | Instruction::Stos
  406. | Instruction::Scas
  407. | Instruction::Ins => set_reg_asize(is_asize_32, EDI, dst),
  408. _ => {},
  409. }
  410. match instruction {
  411. Instruction::Movs | Instruction::Cmps | Instruction::Lods | Instruction::Outs => {
  412. set_reg_asize(is_asize_32, ESI, src)
  413. },
  414. _ => {},
  415. };
  416. match rep {
  417. Rep::Z | Rep::NZ => {
  418. set_reg_asize(is_asize_32, ECX, count as i32);
  419. },
  420. Rep::None => {},
  421. }
  422. }
  423. #[no_mangle]
  424. pub unsafe fn movsb_rep(is_asize_32: bool, ds: i32) {
  425. string_instruction(is_asize_32, ds, Instruction::Movs, Size::B, Rep::Z)
  426. }
  427. #[no_mangle]
  428. pub unsafe fn movsw_rep(is_asize_32: bool, ds: i32) {
  429. string_instruction(is_asize_32, ds, Instruction::Movs, Size::W, Rep::Z)
  430. }
  431. #[no_mangle]
  432. pub unsafe fn movsd_rep(is_asize_32: bool, ds: i32) {
  433. string_instruction(is_asize_32, ds, Instruction::Movs, Size::D, Rep::Z)
  434. }
  435. #[no_mangle]
  436. pub unsafe fn movsb_no_rep(is_asize_32: bool, ds: i32) {
  437. string_instruction(is_asize_32, ds, Instruction::Movs, Size::B, Rep::None)
  438. }
  439. #[no_mangle]
  440. pub unsafe fn movsw_no_rep(is_asize_32: bool, ds: i32) {
  441. string_instruction(is_asize_32, ds, Instruction::Movs, Size::W, Rep::None)
  442. }
  443. #[no_mangle]
  444. pub unsafe fn movsd_no_rep(is_asize_32: bool, ds: i32) {
  445. string_instruction(is_asize_32, ds, Instruction::Movs, Size::D, Rep::None)
  446. }
  447. #[no_mangle]
  448. pub unsafe fn lodsb_rep(is_asize_32: bool, ds: i32) {
  449. string_instruction(is_asize_32, ds, Instruction::Lods, Size::B, Rep::Z)
  450. }
  451. #[no_mangle]
  452. pub unsafe fn lodsw_rep(is_asize_32: bool, ds: i32) {
  453. string_instruction(is_asize_32, ds, Instruction::Lods, Size::W, Rep::Z)
  454. }
  455. #[no_mangle]
  456. pub unsafe fn lodsd_rep(is_asize_32: bool, ds: i32) {
  457. string_instruction(is_asize_32, ds, Instruction::Lods, Size::D, Rep::Z)
  458. }
  459. #[no_mangle]
  460. pub unsafe fn lodsb_no_rep(is_asize_32: bool, ds: i32) {
  461. string_instruction(is_asize_32, ds, Instruction::Lods, Size::B, Rep::None)
  462. }
  463. #[no_mangle]
  464. pub unsafe fn lodsw_no_rep(is_asize_32: bool, ds: i32) {
  465. string_instruction(is_asize_32, ds, Instruction::Lods, Size::W, Rep::None)
  466. }
  467. #[no_mangle]
  468. pub unsafe fn lodsd_no_rep(is_asize_32: bool, ds: i32) {
  469. string_instruction(is_asize_32, ds, Instruction::Lods, Size::D, Rep::None)
  470. }
  471. #[no_mangle]
  472. pub unsafe fn stosb_rep(is_asize_32: bool) {
  473. string_instruction(is_asize_32, 0, Instruction::Stos, Size::B, Rep::Z)
  474. }
  475. #[no_mangle]
  476. pub unsafe fn stosw_rep(is_asize_32: bool) {
  477. string_instruction(is_asize_32, 0, Instruction::Stos, Size::W, Rep::Z)
  478. }
  479. #[no_mangle]
  480. pub unsafe fn stosd_rep(is_asize_32: bool) {
  481. string_instruction(is_asize_32, 0, Instruction::Stos, Size::D, Rep::Z)
  482. }
  483. #[no_mangle]
  484. pub unsafe fn stosb_no_rep(is_asize_32: bool) {
  485. string_instruction(is_asize_32, 0, Instruction::Stos, Size::B, Rep::None)
  486. }
  487. #[no_mangle]
  488. pub unsafe fn stosw_no_rep(is_asize_32: bool) {
  489. string_instruction(is_asize_32, 0, Instruction::Stos, Size::W, Rep::None)
  490. }
  491. #[no_mangle]
  492. pub unsafe fn stosd_no_rep(is_asize_32: bool) {
  493. string_instruction(is_asize_32, 0, Instruction::Stos, Size::D, Rep::None)
  494. }
  495. #[no_mangle]
  496. pub unsafe fn cmpsb_repz(is_asize_32: bool, ds: i32) {
  497. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::B, Rep::Z)
  498. }
  499. #[no_mangle]
  500. pub unsafe fn cmpsw_repz(is_asize_32: bool, ds: i32) {
  501. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::W, Rep::Z)
  502. }
  503. #[no_mangle]
  504. pub unsafe fn cmpsd_repz(is_asize_32: bool, ds: i32) {
  505. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::D, Rep::Z)
  506. }
  507. #[no_mangle]
  508. pub unsafe fn cmpsb_repnz(is_asize_32: bool, ds: i32) {
  509. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::B, Rep::NZ)
  510. }
  511. #[no_mangle]
  512. pub unsafe fn cmpsw_repnz(is_asize_32: bool, ds: i32) {
  513. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::W, Rep::NZ)
  514. }
  515. #[no_mangle]
  516. pub unsafe fn cmpsd_repnz(is_asize_32: bool, ds: i32) {
  517. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::D, Rep::NZ)
  518. }
  519. #[no_mangle]
  520. pub unsafe fn cmpsb_no_rep(is_asize_32: bool, ds: i32) {
  521. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::B, Rep::None)
  522. }
  523. #[no_mangle]
  524. pub unsafe fn cmpsw_no_rep(is_asize_32: bool, ds: i32) {
  525. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::W, Rep::None)
  526. }
  527. #[no_mangle]
  528. pub unsafe fn cmpsd_no_rep(is_asize_32: bool, ds: i32) {
  529. string_instruction(is_asize_32, ds, Instruction::Cmps, Size::D, Rep::None)
  530. }
  531. #[no_mangle]
  532. pub unsafe fn scasb_repz(is_asize_32: bool) {
  533. string_instruction(is_asize_32, 0, Instruction::Scas, Size::B, Rep::Z)
  534. }
  535. #[no_mangle]
  536. pub unsafe fn scasw_repz(is_asize_32: bool) {
  537. string_instruction(is_asize_32, 0, Instruction::Scas, Size::W, Rep::Z)
  538. }
  539. #[no_mangle]
  540. pub unsafe fn scasd_repz(is_asize_32: bool) {
  541. string_instruction(is_asize_32, 0, Instruction::Scas, Size::D, Rep::Z)
  542. }
  543. #[no_mangle]
  544. pub unsafe fn scasb_repnz(is_asize_32: bool) {
  545. string_instruction(is_asize_32, 0, Instruction::Scas, Size::B, Rep::NZ)
  546. }
  547. #[no_mangle]
  548. pub unsafe fn scasw_repnz(is_asize_32: bool) {
  549. string_instruction(is_asize_32, 0, Instruction::Scas, Size::W, Rep::NZ)
  550. }
  551. #[no_mangle]
  552. pub unsafe fn scasd_repnz(is_asize_32: bool) {
  553. string_instruction(is_asize_32, 0, Instruction::Scas, Size::D, Rep::NZ)
  554. }
  555. #[no_mangle]
  556. pub unsafe fn scasb_no_rep(is_asize_32: bool) {
  557. string_instruction(is_asize_32, 0, Instruction::Scas, Size::B, Rep::None)
  558. }
  559. #[no_mangle]
  560. pub unsafe fn scasw_no_rep(is_asize_32: bool) {
  561. string_instruction(is_asize_32, 0, Instruction::Scas, Size::W, Rep::None)
  562. }
  563. #[no_mangle]
  564. pub unsafe fn scasd_no_rep(is_asize_32: bool) {
  565. string_instruction(is_asize_32, 0, Instruction::Scas, Size::D, Rep::None)
  566. }
  567. #[no_mangle]
  568. pub unsafe fn outsb_rep(is_asize_32: bool, ds: i32) {
  569. string_instruction(is_asize_32, ds, Instruction::Outs, Size::B, Rep::Z)
  570. }
  571. #[no_mangle]
  572. pub unsafe fn outsw_rep(is_asize_32: bool, ds: i32) {
  573. string_instruction(is_asize_32, ds, Instruction::Outs, Size::W, Rep::Z)
  574. }
  575. #[no_mangle]
  576. pub unsafe fn outsd_rep(is_asize_32: bool, ds: i32) {
  577. string_instruction(is_asize_32, ds, Instruction::Outs, Size::D, Rep::Z)
  578. }
  579. #[no_mangle]
  580. pub unsafe fn outsb_no_rep(is_asize_32: bool, ds: i32) {
  581. string_instruction(is_asize_32, ds, Instruction::Outs, Size::B, Rep::None)
  582. }
  583. #[no_mangle]
  584. pub unsafe fn outsw_no_rep(is_asize_32: bool, ds: i32) {
  585. string_instruction(is_asize_32, ds, Instruction::Outs, Size::W, Rep::None)
  586. }
  587. #[no_mangle]
  588. pub unsafe fn outsd_no_rep(is_asize_32: bool, ds: i32) {
  589. string_instruction(is_asize_32, ds, Instruction::Outs, Size::D, Rep::None)
  590. }
  591. #[no_mangle]
  592. pub unsafe fn insb_rep(is_asize_32: bool) {
  593. string_instruction(is_asize_32, 0, Instruction::Ins, Size::B, Rep::Z)
  594. }
  595. #[no_mangle]
  596. pub unsafe fn insw_rep(is_asize_32: bool) {
  597. string_instruction(is_asize_32, 0, Instruction::Ins, Size::W, Rep::Z)
  598. }
  599. #[no_mangle]
  600. pub unsafe fn insd_rep(is_asize_32: bool) {
  601. string_instruction(is_asize_32, 0, Instruction::Ins, Size::D, Rep::Z)
  602. }
  603. #[no_mangle]
  604. pub unsafe fn insb_no_rep(is_asize_32: bool) {
  605. string_instruction(is_asize_32, 0, Instruction::Ins, Size::B, Rep::None)
  606. }
  607. #[no_mangle]
  608. pub unsafe fn insw_no_rep(is_asize_32: bool) {
  609. string_instruction(is_asize_32, 0, Instruction::Ins, Size::W, Rep::None)
  610. }
  611. #[no_mangle]
  612. pub unsafe fn insd_no_rep(is_asize_32: bool) {
  613. string_instruction(is_asize_32, 0, Instruction::Ins, Size::D, Rep::None)
  614. }