Skip to content

Commit 92920d5

Browse files
committed
Use correct asm! options
This adds some previously omitted options to our inline asm! Note that instuctions that just push/pop the stack (but otherwise don't touch memory) can be marked `nomem`. We also don't mark instuctions as `nomem` if they could modify memory translation: This includes - writing segment registers - invlpg/invpcid - writing cr2/cr3/cr4 - writing any MSR (we still mark these as `nostack` though. The following are still marked `nomem`: - Reading any MSR (as this cannot have a side-effect) - Writing XCR0 Signed-off-by: Joe Richey <[email protected]>
1 parent cc7f286 commit 92920d5

File tree

9 files changed

+63
-58
lines changed

9 files changed

+63
-58
lines changed

src/instructions/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub mod tlb;
1414
pub fn hlt() {
1515
unsafe {
1616
#[cfg(feature = "inline_asm")]
17-
asm!("hlt", options(nomem, nostack));
17+
asm!("hlt", options(nomem, nostack, preserves_flags));
1818

1919
#[cfg(not(feature = "inline_asm"))]
2020
crate::asm::x86_64_asm_hlt();
@@ -44,7 +44,7 @@ pub fn nop() {
4444
#[inline]
4545
pub fn bochs_breakpoint() {
4646
unsafe {
47-
asm!("xchg bx, bx", options(nomem, nostack));
47+
asm!("xchg bx, bx", options(nomem, nostack, preserves_flags));
4848
}
4949
}
5050

@@ -56,7 +56,7 @@ pub fn read_rip() -> crate::VirtAddr {
5656
let rip: u64;
5757
unsafe {
5858
asm!(
59-
"lea {}, [rip]", out(reg) rip, options(nostack, nomem)
59+
"lea {}, [rip]", out(reg) rip, options(nostack, nomem, preserves_flags)
6060
);
6161
}
6262
crate::VirtAddr::new(rip)

src/instructions/port.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ impl PortRead for u8 {
1111
#[cfg(feature = "inline_asm")]
1212
{
1313
let value: u8;
14-
asm!("in al, dx", out("al") value, in("dx") port, options(nomem, nostack));
14+
asm!("in al, dx", out("al") value, in("dx") port, options(nomem, nostack, preserves_flags));
1515
value
1616
}
1717
#[cfg(not(feature = "inline_asm"))]
@@ -25,7 +25,7 @@ impl PortRead for u16 {
2525
#[cfg(feature = "inline_asm")]
2626
{
2727
let value: u16;
28-
asm!("in ax, dx", out("ax") value, in("dx") port, options(nomem, nostack));
28+
asm!("in ax, dx", out("ax") value, in("dx") port, options(nomem, nostack, preserves_flags));
2929
value
3030
}
3131
#[cfg(not(feature = "inline_asm"))]
@@ -39,7 +39,7 @@ impl PortRead for u32 {
3939
#[cfg(feature = "inline_asm")]
4040
{
4141
let value: u32;
42-
asm!("in eax, dx", out("eax") value, in("dx") port, options(nomem, nostack));
42+
asm!("in eax, dx", out("eax") value, in("dx") port, options(nomem, nostack, preserves_flags));
4343
value
4444
}
4545
#[cfg(not(feature = "inline_asm"))]
@@ -51,7 +51,7 @@ impl PortWrite for u8 {
5151
#[inline]
5252
unsafe fn write_to_port(port: u16, value: u8) {
5353
#[cfg(feature = "inline_asm")]
54-
asm!("out dx, al", in("dx") port, in("al") value, options(nomem, nostack));
54+
asm!("out dx, al", in("dx") port, in("al") value, options(nomem, nostack, preserves_flags));
5555

5656
#[cfg(not(feature = "inline_asm"))]
5757
crate::asm::x86_64_asm_write_to_port_u8(port, value);
@@ -62,7 +62,7 @@ impl PortWrite for u16 {
6262
#[inline]
6363
unsafe fn write_to_port(port: u16, value: u16) {
6464
#[cfg(feature = "inline_asm")]
65-
asm!("out dx, ax", in("dx") port, in("ax") value, options(nomem, nostack));
65+
asm!("out dx, ax", in("dx") port, in("ax") value, options(nomem, nostack, preserves_flags));
6666

6767
#[cfg(not(feature = "inline_asm"))]
6868
crate::asm::x86_64_asm_write_to_port_u16(port, value);
@@ -73,7 +73,7 @@ impl PortWrite for u32 {
7373
#[inline]
7474
unsafe fn write_to_port(port: u16, value: u32) {
7575
#[cfg(feature = "inline_asm")]
76-
asm!("out dx, eax", in("dx") port, in("eax") value, options(nomem, nostack));
76+
asm!("out dx, eax", in("dx") port, in("eax") value, options(nomem, nostack, preserves_flags));
7777

7878
#[cfg(not(feature = "inline_asm"))]
7979
crate::asm::x86_64_asm_write_to_port_u32(port, value);

src/instructions/segmentation.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub unsafe fn set_cs(sel: SegmentSelector) {
2424
"1:",
2525
sel = in(reg) u64::from(sel.0),
2626
tmp = lateout(reg) _,
27+
options(preserves_flags),
2728
);
2829

2930
#[cfg(not(feature = "inline_asm"))]
@@ -39,7 +40,7 @@ pub unsafe fn set_cs(sel: SegmentSelector) {
3940
#[inline]
4041
pub unsafe fn load_ss(sel: SegmentSelector) {
4142
#[cfg(feature = "inline_asm")]
42-
asm!("mov ss, {0:x}", in(reg) sel.0, options(nostack));
43+
asm!("mov ss, {0:x}", in(reg) sel.0, options(nostack, preserves_flags));
4344

4445
#[cfg(not(feature = "inline_asm"))]
4546
crate::asm::x86_64_asm_load_ss(sel.0);
@@ -54,7 +55,7 @@ pub unsafe fn load_ss(sel: SegmentSelector) {
5455
#[inline]
5556
pub unsafe fn load_ds(sel: SegmentSelector) {
5657
#[cfg(feature = "inline_asm")]
57-
asm!("mov ds, {0:x}", in(reg) sel.0, options(nostack));
58+
asm!("mov ds, {0:x}", in(reg) sel.0, options(nostack, preserves_flags));
5859

5960
#[cfg(not(feature = "inline_asm"))]
6061
crate::asm::x86_64_asm_load_ds(sel.0);
@@ -69,7 +70,7 @@ pub unsafe fn load_ds(sel: SegmentSelector) {
6970
#[inline]
7071
pub unsafe fn load_es(sel: SegmentSelector) {
7172
#[cfg(feature = "inline_asm")]
72-
asm!("mov es, {0:x}", in(reg) sel.0, options(nostack));
73+
asm!("mov es, {0:x}", in(reg) sel.0, options(nostack, preserves_flags));
7374

7475
#[cfg(not(feature = "inline_asm"))]
7576
crate::asm::x86_64_asm_load_es(sel.0);
@@ -84,7 +85,7 @@ pub unsafe fn load_es(sel: SegmentSelector) {
8485
#[inline]
8586
pub unsafe fn load_fs(sel: SegmentSelector) {
8687
#[cfg(feature = "inline_asm")]
87-
asm!("mov fs, {0:x}", in(reg) sel.0, options(nostack));
88+
asm!("mov fs, {0:x}", in(reg) sel.0, options(nostack, preserves_flags));
8889

8990
#[cfg(not(feature = "inline_asm"))]
9091
crate::asm::x86_64_asm_load_fs(sel.0);
@@ -99,7 +100,7 @@ pub unsafe fn load_fs(sel: SegmentSelector) {
99100
#[inline]
100101
pub unsafe fn load_gs(sel: SegmentSelector) {
101102
#[cfg(feature = "inline_asm")]
102-
asm!("mov gs, {0:x}", in(reg) sel.0, options(nostack));
103+
asm!("mov gs, {0:x}", in(reg) sel.0, options(nostack, preserves_flags));
103104

104105
#[cfg(not(feature = "inline_asm"))]
105106
crate::asm::x86_64_asm_load_gs(sel.0);
@@ -114,7 +115,7 @@ pub unsafe fn load_gs(sel: SegmentSelector) {
114115
#[inline]
115116
pub unsafe fn swap_gs() {
116117
#[cfg(feature = "inline_asm")]
117-
asm!("swapgs", options(nostack));
118+
asm!("swapgs", options(nostack, preserves_flags));
118119

119120
#[cfg(not(feature = "inline_asm"))]
120121
crate::asm::x86_64_asm_swapgs();
@@ -127,7 +128,7 @@ pub fn cs() -> SegmentSelector {
127128

128129
#[cfg(feature = "inline_asm")]
129130
unsafe {
130-
asm!("mov {0:x}, cs", out(reg) segment, options(nostack, nomem));
131+
asm!("mov {0:x}, cs", out(reg) segment, options(nomem, nostack, preserves_flags));
131132
}
132133
#[cfg(not(feature = "inline_asm"))]
133134
unsafe {
@@ -149,7 +150,7 @@ pub fn cs() -> SegmentSelector {
149150
#[inline]
150151
pub unsafe fn wrfsbase(val: u64) {
151152
#[cfg(feature = "inline_asm")]
152-
asm!("wrfsbase {}", in(reg) val, options(nomem, nostack));
153+
asm!("wrfsbase {}", in(reg) val, options(nostack, preserves_flags));
153154

154155
#[cfg(not(feature = "inline_asm"))]
155156
crate::asm::x86_64_asm_wrfsbase(val);
@@ -165,7 +166,7 @@ pub unsafe fn rdfsbase() -> u64 {
165166
#[cfg(feature = "inline_asm")]
166167
{
167168
let val: u64;
168-
asm!("rdfsbase {}", out(reg) val, options(nomem, nostack));
169+
asm!("rdfsbase {}", out(reg) val, options(nomem, nostack, preserves_flags));
169170
val
170171
}
171172

@@ -184,7 +185,7 @@ pub unsafe fn rdfsbase() -> u64 {
184185
#[inline]
185186
pub unsafe fn wrgsbase(val: u64) {
186187
#[cfg(feature = "inline_asm")]
187-
asm!("wrgsbase {}", in(reg) val, options(nomem, nostack));
188+
asm!("wrgsbase {}", in(reg) val, options(nostack, preserves_flags));
188189

189190
#[cfg(not(feature = "inline_asm"))]
190191
crate::asm::x86_64_asm_wrgsbase(val);
@@ -200,7 +201,7 @@ pub unsafe fn rdgsbase() -> u64 {
200201
#[cfg(feature = "inline_asm")]
201202
{
202203
let val: u64;
203-
asm!("rdgsbase {}", out(reg) val, options(nomem, nostack));
204+
asm!("rdgsbase {}", out(reg) val, options(nomem, nostack, preserves_flags));
204205
val
205206
}
206207

src/instructions/tables.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub use crate::structures::DescriptorTablePointer;
1919
#[inline]
2020
pub unsafe fn lgdt(gdt: &DescriptorTablePointer) {
2121
#[cfg(feature = "inline_asm")]
22-
asm!("lgdt [{}]", in(reg) gdt, options(nostack));
22+
asm!("lgdt [{}]", in(reg) gdt, options(readonly, nostack, preserves_flags));
2323

2424
#[cfg(not(feature = "inline_asm"))]
2525
crate::asm::x86_64_asm_lgdt(gdt as *const _);
@@ -39,7 +39,7 @@ pub unsafe fn lgdt(gdt: &DescriptorTablePointer) {
3939
#[inline]
4040
pub unsafe fn lidt(idt: &DescriptorTablePointer) {
4141
#[cfg(feature = "inline_asm")]
42-
asm!("lidt [{}]", in(reg) idt, options(nostack));
42+
asm!("lidt [{}]", in(reg) idt, options(readonly, nostack, preserves_flags));
4343

4444
#[cfg(not(feature = "inline_asm"))]
4545
crate::asm::x86_64_asm_lidt(idt as *const _);
@@ -54,7 +54,7 @@ pub fn sidt() -> DescriptorTablePointer {
5454
};
5555
unsafe {
5656
#[cfg(feature = "inline_asm")]
57-
asm!("sidt [{}]", in(reg) &mut idt, options(nostack));
57+
asm!("sidt [{}]", in(reg) &mut idt, options(nostack, preserves_flags));
5858

5959
#[cfg(not(feature = "inline_asm"))]
6060
crate::asm::x86_64_asm_sidt(&mut idt as *mut _);
@@ -72,7 +72,7 @@ pub fn sidt() -> DescriptorTablePointer {
7272
#[inline]
7373
pub unsafe fn load_tss(sel: SegmentSelector) {
7474
#[cfg(feature = "inline_asm")]
75-
asm!("ltr {0:x}", in(reg) sel.0, options(nostack, nomem));
75+
asm!("ltr {0:x}", in(reg) sel.0, options(nomem, nostack, preserves_flags));
7676

7777
#[cfg(not(feature = "inline_asm"))]
7878
crate::asm::x86_64_asm_ltr(sel.0);

src/instructions/tlb.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::VirtAddr;
77
pub fn flush(addr: VirtAddr) {
88
unsafe {
99
#[cfg(feature = "inline_asm")]
10-
asm!("invlpg [{}]", in(reg) addr.as_u64(), options(nostack));
10+
asm!("invlpg [{}]", in(reg) addr.as_u64(), options(nostack, preserves_flags));
1111

1212
#[cfg(not(feature = "inline_asm"))]
1313
crate::asm::x86_64_asm_invlpg(addr.as_u64());
@@ -96,7 +96,7 @@ pub unsafe fn flush_pcid(command: InvPicdCommand) {
9696
}
9797

9898
#[cfg(feature = "inline_asm")]
99-
asm!("invpcid {1}, [{0}]", in(reg) &desc, in(reg) kind);
99+
asm!("invpcid {0}, [{1}]", in(reg) kind, in(reg) &desc, options(nostack, preserves_flags));
100100

101101
#[cfg(not(feature = "inline_asm"))]
102102
crate::asm::x86_64_asm_invpcid(kind, &desc as *const _ as u64);

src/registers/control.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ mod x86_64 {
144144

145145
#[cfg(feature = "inline_asm")]
146146
unsafe {
147-
asm!("mov {}, cr0", out(reg) value, options(nomem));
147+
asm!("mov {}, cr0", out(reg) value, options(nomem, nostack, preserves_flags));
148148
}
149149
#[cfg(not(feature = "inline_asm"))]
150150
unsafe {
@@ -182,7 +182,7 @@ mod x86_64 {
182182
#[inline]
183183
pub unsafe fn write_raw(value: u64) {
184184
#[cfg(feature = "inline_asm")]
185-
asm!("mov cr0, {}", in(reg) value, options(nostack));
185+
asm!("mov cr0, {}", in(reg) value, options(nostack, preserves_flags));
186186

187187
#[cfg(not(feature = "inline_asm"))]
188188
crate::asm::x86_64_asm_write_cr0(value);
@@ -215,7 +215,7 @@ mod x86_64 {
215215

216216
#[cfg(feature = "inline_asm")]
217217
unsafe {
218-
asm!("mov {}, cr2", out(reg) value, options(nomem));
218+
asm!("mov {}, cr2", out(reg) value, options(nomem, nostack, preserves_flags));
219219
}
220220
#[cfg(not(feature = "inline_asm"))]
221221
unsafe {
@@ -242,7 +242,7 @@ mod x86_64 {
242242

243243
#[cfg(feature = "inline_asm")]
244244
unsafe {
245-
asm!("mov {}, cr3", out(reg) value, options(nomem));
245+
asm!("mov {}, cr3", out(reg) value, options(nomem, nostack, preserves_flags));
246246
}
247247
#[cfg(not(feature = "inline_asm"))]
248248
unsafe {
@@ -295,7 +295,7 @@ mod x86_64 {
295295
let value = addr.as_u64() | val as u64;
296296

297297
#[cfg(feature = "inline_asm")]
298-
asm!("mov cr3, {}", in(reg) value, options(nostack));
298+
asm!("mov cr3, {}", in(reg) value, options(nostack, preserves_flags));
299299

300300
#[cfg(not(feature = "inline_asm"))]
301301
crate::asm::x86_64_asm_write_cr3(value)
@@ -316,7 +316,7 @@ mod x86_64 {
316316

317317
#[cfg(feature = "inline_asm")]
318318
unsafe {
319-
asm!("mov {}, cr4", out(reg) value, options(nostack));
319+
asm!("mov {}, cr4", out(reg) value, options(nomem, nostack, preserves_flags));
320320
}
321321
#[cfg(not(feature = "inline_asm"))]
322322
unsafe {
@@ -356,7 +356,7 @@ mod x86_64 {
356356
#[inline]
357357
pub unsafe fn write_raw(value: u64) {
358358
#[cfg(feature = "inline_asm")]
359-
asm!("mov cr4, {}", in(reg) value, options(nostack));
359+
asm!("mov cr4, {}", in(reg) value, options(nostack, preserves_flags));
360360

361361
#[cfg(not(feature = "inline_asm"))]
362362
crate::asm::x86_64_asm_write_cr4(value);

src/registers/model_specific.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,12 @@ mod x86_64 {
121121
#[cfg(feature = "inline_asm")]
122122
{
123123
let (high, low): (u32, u32);
124-
asm!("rdmsr", out("eax") low, out("edx") high, in("ecx") self.0, options(nostack));
124+
asm!(
125+
"rdmsr",
126+
in("ecx") self.0,
127+
out("eax") low, out("edx") high,
128+
options(nomem, nostack, preserves_flags),
129+
);
125130
((high as u64) << 32) | (low as u64)
126131
}
127132

@@ -141,7 +146,12 @@ mod x86_64 {
141146
{
142147
let low = value as u32;
143148
let high = (value >> 32) as u32;
144-
asm!("wrmsr", in("ecx") self.0, in("eax") low, in("edx") high, options(nostack))
149+
asm!(
150+
"wrmsr",
151+
in("ecx") self.0,
152+
in("eax") low, in("edx") high,
153+
options(nostack, preserves_flags),
154+
);
145155
}
146156

147157
#[cfg(not(feature = "inline_asm"))]

src/registers/rflags.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ mod x86_64 {
8181

8282
#[cfg(feature = "inline_asm")]
8383
unsafe {
84-
asm!("pushf; pop {}", out(reg) r);
84+
asm!("pushf; pop {}", out(reg) r, options(nomem, preserves_flags));
8585
}
8686
#[cfg(not(feature = "inline_asm"))]
8787
unsafe {
@@ -119,9 +119,10 @@ mod x86_64 {
119119
/// flags also used by Rust/LLVM can result in undefined behavior too.
120120
#[inline]
121121
pub unsafe fn write_raw(val: u64) {
122-
// FIXME - There's probably a better way than saying we preserve the flags even though we actually don't
122+
// HACK: we mark this function as preserves_flags to prevent Rust from restoring
123+
// saved flags after the "popf" below. See above note on safety.
123124
#[cfg(feature = "inline_asm")]
124-
asm!("push {}; popf", in(reg) val, options(preserves_flags));
125+
asm!("push {}; popf", in(reg) val, options(nomem, preserves_flags));
125126

126127
#[cfg(not(feature = "inline_asm"))]
127128
crate::asm::x86_64_asm_write_rflags(val);

0 commit comments

Comments
 (0)