x86.rs 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. #![allow(unused_imports)]
  2. use core::intrinsics;
  3. // NOTE These functions are implemented using assembly because they using a custom
  4. // calling convention which can't be implemented using a normal Rust function
  5. // NOTE These functions are never mangled as they are not tested against compiler-rt
  6. // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca
  7. #[cfg(all(
  8. windows,
  9. target_env = "gnu",
  10. not(feature = "no-asm"),
  11. not(feature = "mangled-names")
  12. ))]
  13. #[naked]
  14. #[no_mangle]
  15. pub unsafe extern "C" fn ___chkstk_ms() {
  16. core::arch::asm!(
  17. "push %ecx",
  18. "push %eax",
  19. "cmp $0x1000,%eax",
  20. "lea 12(%esp),%ecx",
  21. "jb 1f",
  22. "2:",
  23. "sub $0x1000,%ecx",
  24. "test %ecx,(%ecx)",
  25. "sub $0x1000,%eax",
  26. "cmp $0x1000,%eax",
  27. "ja 2b",
  28. "1:",
  29. "sub %eax,%ecx",
  30. "test %ecx,(%ecx)",
  31. "pop %eax",
  32. "pop %ecx",
  33. "ret",
  34. options(noreturn, att_syntax)
  35. );
  36. }
  37. // FIXME: __alloca should be an alias to __chkstk
  38. #[cfg(all(
  39. windows,
  40. target_env = "gnu",
  41. not(feature = "no-asm"),
  42. not(feature = "mangled-names")
  43. ))]
  44. #[naked]
  45. #[no_mangle]
  46. pub unsafe extern "C" fn __alloca() {
  47. core::arch::asm!(
  48. "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable"
  49. options(noreturn, att_syntax)
  50. );
  51. }
  52. #[cfg(all(
  53. windows,
  54. target_env = "gnu",
  55. not(feature = "no-asm"),
  56. not(feature = "mangled-names")
  57. ))]
  58. #[naked]
  59. #[no_mangle]
  60. pub unsafe extern "C" fn ___chkstk() {
  61. core::arch::asm!(
  62. "push %ecx",
  63. "cmp $0x1000,%eax",
  64. "lea 8(%esp),%ecx", // esp before calling this routine -> ecx
  65. "jb 1f",
  66. "2:",
  67. "sub $0x1000,%ecx",
  68. "test %ecx,(%ecx)",
  69. "sub $0x1000,%eax",
  70. "cmp $0x1000,%eax",
  71. "ja 2b",
  72. "1:",
  73. "sub %eax,%ecx",
  74. "test %ecx,(%ecx)",
  75. "lea 4(%esp),%eax", // load pointer to the return address into eax
  76. "mov %ecx,%esp", // install the new top of stack pointer into esp
  77. "mov -4(%eax),%ecx", // restore ecx
  78. "push (%eax)", // push return address onto the stack
  79. "sub %esp,%eax", // restore the original value in eax
  80. "ret",
  81. options(noreturn, att_syntax)
  82. );
  83. }