x86_alignment_check/
lib.rs1#![no_std]
57
58#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
60pub fn x86_alignment_check(b: bool) -> bool {
61 let old_eflags = unsafe { __read_eflags() };
62 let new_eflags = if b {
63 old_eflags | EFLAGS_AC_BIT
64 } else {
65 old_eflags & !EFLAGS_AC_BIT
66 };
67 unsafe { __write_eflags(new_eflags) };
68 (old_eflags & EFLAGS_AC_BIT) != 0
70}
71
72#[cfg(target_arch = "x86")]
73const EFLAGS_AC_BIT: u32 = 1 << 18; #[cfg(target_arch = "x86_64")]
76const EFLAGS_AC_BIT: u64 = 1 << 18; #[cfg(target_arch = "x86")]
79#[inline(always)]
80unsafe fn __read_eflags() -> u32 {
81 let mut eflags: u32;
82 core::arch::asm!("pushfd; pop {eflags:e}", eflags = out(reg) eflags);
83 eflags
84}
85
86#[cfg(target_arch = "x86")]
87#[inline(always)]
88unsafe fn __write_eflags(eflags: u32) {
89 core::arch::asm!("push {eflags:e}; popfd", eflags = in(reg) eflags);
90}
91
92#[cfg(target_arch = "x86_64")]
93#[inline(always)]
94unsafe fn __read_eflags() -> u64 {
95 let mut rflags: u64;
96 core::arch::asm!("pushfq; pop {rflags}", rflags = out(reg) rflags);
97 rflags
98}
99
100#[cfg(target_arch = "x86_64")]
101#[inline(always)]
102unsafe fn __write_eflags(rflags: u64) {
103 core::arch::asm!("push {rflags}; popfq", rflags = in(reg) rflags);
104}
105
106pub fn ac_call_once<F, T>(f: F) -> T
108where
109 F: FnOnce() -> T,
110{
111 let old = x86_alignment_check(true);
112 let r = f();
113 let _ = x86_alignment_check(old);
114 r
115}
116
117pub fn no_ac_call_once<F, T>(f: F) -> T
119where
120 F: FnOnce() -> T,
121{
122 let old = x86_alignment_check(false);
123 let r = f();
124 let _ = x86_alignment_check(old);
125 r
126}
127
128#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn it_works_0() {
137 let old_0 = x86_alignment_check(true);
138 let old_1 = x86_alignment_check(true);
139 let old_2 = x86_alignment_check(false);
140 let old_3 = x86_alignment_check(true);
141 let old_4 = x86_alignment_check(false);
142 let _old_5 = x86_alignment_check(old_0);
143 assert!(old_1);
145 assert!(old_2);
146 assert!(!old_3);
147 assert!(old_4);
148 }
149 #[test]
150 fn it_works_1() {
151 let val = ac_call_once(|| 1);
152 assert_eq!(val, 1);
153 }
154 #[test]
155 fn it_works_2() {
156 let val = no_ac_call_once(|| 1);
157 assert_eq!(val, 1);
158 }
159 #[test]
160 fn it_works_3() {
161 let buf = [0_u8; 100];
162 let val = ac_call_once(|| {
164 let val = no_ac_call_once(|| {
165 let ptr = buf.as_ptr();
166 let ptr = unsafe { ptr.add(3) };
167 let _v: u32 = unsafe { (ptr as *const u32).read() };
170 1
171 });
172 val + 1
173 });
174 assert_eq!(val, 2);
175 }
176 #[test]
177 #[ignore]
178 fn it_works_ignore_0() {
179 let buf = [0_u8; 100];
180 let _old_0 = x86_alignment_check(true);
182 {
183 let ptr = buf.as_ptr();
184 let ptr = unsafe { ptr.add(3) };
185 let _v: u32 = unsafe { (ptr as *const u32).read() };
187 }
188 }
189}