Skip to content

Commit 7ea8c94

Browse files
authored
Merge pull request #179 from h33p/master
Decouple instructions into a separate feature flag.
2 parents f156401 + 8a5b527 commit 7ea8c94

19 files changed

+223
-186
lines changed

.github/workflows/build.yml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,23 +62,26 @@ jobs:
6262
- name: "Run cargo build"
6363
run: cargo build
6464

65+
- name: "Run cargo build for stable without instructions"
66+
run: cargo build --no-default-features
67+
6568
- name: "Run cargo build for stable"
66-
run: cargo build --no-default-features --features stable
69+
run: cargo build --no-default-features --features external_asm,instructions
6770
if: runner.os != 'Windows'
6871

6972
- name: "Run cargo build for stable on musl"
70-
run: cargo build --target x86_64-unknown-linux-musl --no-default-features --features stable
73+
run: cargo build --target x86_64-unknown-linux-musl --no-default-features --features external_asm,instructions
7174
if: runner.os == 'Linux'
7275

7376
- name: "Run cargo test"
7477
run: cargo test
7578

7679
- name: "Run cargo test for stable"
77-
run: cargo test --no-default-features --features stable
80+
run: cargo test --no-default-features --features external_asm,instructions
7881
if: runner.os != 'Windows'
7982

8083
- name: "Run cargo test for stable on musl"
81-
run: cargo test --target x86_64-unknown-linux-musl --no-default-features --features stable
84+
run: cargo test --target x86_64-unknown-linux-musl --no-default-features --features external_asm,instructions
8285
if: runner.os == 'Linux'
8386

8487
- name: 'Deny Warnings'
@@ -90,8 +93,8 @@ jobs:
9093
rustup target add thumbv7em-none-eabihf
9194
- name: 'Build on non x86_64 platforms'
9295
run: |
93-
cargo build --target i686-unknown-linux-gnu
94-
cargo build --target thumbv7em-none-eabihf
96+
cargo build --target i686-unknown-linux-gnu --no-default-features --features nightly
97+
cargo build --target thumbv7em-none-eabihf --no-default-features --features nightly
9598
9699
- name: "Install Rustup Components"
97100
run: rustup component add rust-src llvm-tools-preview

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ edition = "2018"
2828
[dependencies]
2929
bit_field = "0.9.0"
3030
bitflags = "1.0.4"
31-
array-init = { version = "0.1.1", optional = true }
3231

3332
[build-dependencies]
3433
cc = { version = "1.0.37", optional = true }
3534

3635
[features]
37-
default = [ "nightly" ]
36+
default = [ "nightly", "instructions" ]
37+
instructions = []
3838
deny-warnings = []
39-
stable = [ "cc", "array-init" ]
39+
external_asm = [ "cc" ]
4040
nightly = [ "inline_asm", "const_fn", "abi_x86_interrupt" ]
4141
inline_asm = []
4242
abi_x86_interrupt = []

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ Support for x86_64 specific instructions (e.g. TLB flush), registers (e.g. contr
77

88
## Crate Feature Flags
99

10-
* `nightly`: This is the default.
11-
* `stable`: Use this to build with non-nightly rust. Needs `default-features = false`.
10+
* `nightly`: Enables features only available on nightly Rust; enabled by default.
11+
* `instructions`: Enabled by default, turns on x86\_64 specific instructions, and dependent features. Only available for x86\_64 targets.
12+
* `external_asm`: Use this to build with non-nightly rust. Needs `default-features = false, features = ["instructions"]`. Is unsupported on Windows.
1213

1314
## Building with stable rust
1415

build.rs

Lines changed: 47 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,54 @@
1-
#[cfg(feature = "inline_asm")]
2-
fn main() {}
3-
4-
#[cfg(all(not(feature = "inline_asm"), not(feature = "stable")))]
51
fn main() {
6-
compile_error!("Neither feature \"stable\" nor \"nightly\" was set!");
7-
}
2+
println!("cargo:rerun-if-changed=build.rs");
83

9-
#[cfg(all(not(feature = "inline_asm"), feature = "stable"))]
10-
fn main() {
11-
use std::ffi::OsString;
12-
use std::fs;
4+
#[cfg(all(feature = "external_asm", windows))]
5+
compile_error!("\"external_asm\" feature is not available on windows toolchain!");
136

14-
println!("cargo:rerun-if-changed=build.rs");
7+
#[cfg(feature = "instructions")]
8+
if std::env::var("CARGO_CFG_TARGET_ARCH").unwrap() != "x86_64" {
9+
panic!("\"instructions\" feature is only available for x86_64 targets!");
10+
}
1511

16-
let entries = fs::read_dir("src/asm")
17-
.unwrap()
18-
.filter_map(|f| {
19-
f.ok().and_then(|e| {
20-
let path = e.path();
21-
match path.extension() {
22-
Some(ext) if ext.eq(&OsString::from("s")) => Some(path),
23-
_ => None,
24-
}
12+
#[cfg(all(
13+
feature = "instructions",
14+
not(feature = "inline_asm"),
15+
not(feature = "external_asm")
16+
))]
17+
compile_error!("\"instructions\" feature is enabled, but neither feature \"external_asm\" nor \"inline_asm\" was set!");
18+
19+
#[cfg(all(feature = "inline_asm", feature = "external_asm"))]
20+
compile_error!(
21+
"\"inline_asm\" and \"external_asm\" features can not be enabled at the same time!"
22+
);
23+
24+
#[cfg(all(feature = "instructions", feature = "external_asm"))]
25+
{
26+
use std::ffi::OsString;
27+
use std::fs;
28+
29+
let entries = fs::read_dir("src/asm")
30+
.unwrap()
31+
.filter_map(|f| {
32+
f.ok().and_then(|e| {
33+
let path = e.path();
34+
match path.extension() {
35+
Some(ext) if ext.eq(&OsString::from("s")) => Some(path),
36+
_ => None,
37+
}
38+
})
2539
})
26-
})
27-
.collect::<Vec<_>>();
28-
29-
cc::Build::new()
30-
.no_default_flags(true)
31-
.files(&entries)
32-
.pic(true)
33-
.static_flag(true)
34-
.shared_flag(false)
35-
.compile("x86_64_asm");
36-
37-
for e in entries {
38-
println!("cargo:rerun-if-changed={}", e.to_str().unwrap());
40+
.collect::<Vec<_>>();
41+
42+
cc::Build::new()
43+
.no_default_flags(true)
44+
.files(&entries)
45+
.pic(true)
46+
.static_flag(true)
47+
.shared_flag(false)
48+
.compile("x86_64_asm");
49+
50+
for e in entries {
51+
println!("cargo:rerun-if-changed={}", e.to_str().unwrap());
52+
}
3953
}
4054
}

src/instructions/mod.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![cfg(target_arch = "x86_64")]
1+
#![cfg(feature = "instructions")]
22

33
//! Special x86_64 instructions.
44
@@ -51,3 +51,18 @@ pub fn bochs_breakpoint() {
5151
llvm_asm!("xchgw %bx, %bx" :::: "volatile");
5252
}
5353
}
54+
55+
/// Gets the current instruction pointer. Note that this is only approximate as it requires a few
56+
/// instructions to execute.
57+
#[cfg(feature = "inline_asm")]
58+
#[inline(always)]
59+
pub fn read_rip() -> u64 {
60+
let rip: u64;
61+
unsafe {
62+
llvm_asm!(
63+
"lea (%rip), $0"
64+
: "=r"(rip) ::: "volatile"
65+
);
66+
}
67+
rip
68+
}

src/instructions/random.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
/// Used to obtain random numbers using x86_64's RDRAND opcode
55
pub struct RdRand(());
66

7-
#[cfg(target_arch = "x86_64")]
87
impl RdRand {
98
/// Creates Some(RdRand) if RDRAND is supported, None otherwise
109
#[inline]
@@ -66,7 +65,7 @@ impl RdRand {
6665
}
6766
}
6867

69-
#[cfg(all(test, target_arch = "x86_64"))]
68+
#[cfg(all(test))]
7069
mod tests {
7170
use super::*;
7271

src/instructions/segmentation.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,102 @@ pub fn cs() -> SegmentSelector {
140140
SegmentSelector(segment)
141141
}
142142
}
143+
144+
/// Writes the FS segment base address
145+
///
146+
/// ## Safety
147+
///
148+
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
149+
///
150+
/// The caller must ensure that this write operation has no unsafe side
151+
/// effects, as the FS segment base address is often used for thread
152+
/// local storage.
153+
#[inline]
154+
pub unsafe fn wrfsbase(val: u64) {
155+
#[cfg(feature = "inline_asm")]
156+
#[inline(always)]
157+
unsafe fn inner(val: u64) {
158+
llvm_asm!("wrfsbase $0" :: "r"(val) :: "volatile")
159+
}
160+
161+
#[cfg(not(feature = "inline_asm"))]
162+
#[inline(always)]
163+
unsafe fn inner(val: u64) {
164+
crate::asm::x86_64_asm_wrfsbase(val)
165+
}
166+
167+
inner(val)
168+
}
169+
170+
/// Reads the FS segment base address
171+
///
172+
/// ## Safety
173+
///
174+
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
175+
#[inline]
176+
pub unsafe fn rdfsbase() -> u64 {
177+
#[cfg(feature = "inline_asm")]
178+
#[inline(always)]
179+
unsafe fn inner() -> u64 {
180+
let val: u64;
181+
llvm_asm!("rdfsbase $0" : "=r" (val) ::: "volatile");
182+
val
183+
}
184+
185+
#[cfg(not(feature = "inline_asm"))]
186+
#[inline(always)]
187+
unsafe fn inner() -> u64 {
188+
crate::asm::x86_64_asm_rdfsbase()
189+
}
190+
191+
inner()
192+
}
193+
194+
/// Writes the GS segment base address
195+
///
196+
/// ## Safety
197+
///
198+
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
199+
///
200+
/// The caller must ensure that this write operation has no unsafe side
201+
/// effects, as the GS segment base address might be in use.
202+
#[inline]
203+
pub unsafe fn wrgsbase(val: u64) {
204+
#[cfg(feature = "inline_asm")]
205+
#[inline(always)]
206+
unsafe fn inner(val: u64) {
207+
llvm_asm!("wrgsbase $0" :: "r"(val) :: "volatile")
208+
}
209+
210+
#[cfg(not(feature = "inline_asm"))]
211+
#[inline(always)]
212+
unsafe fn inner(val: u64) {
213+
crate::asm::x86_64_asm_wrgsbase(val)
214+
}
215+
216+
inner(val)
217+
}
218+
219+
/// Reads the GS segment base address
220+
///
221+
/// ## Safety
222+
///
223+
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
224+
#[inline]
225+
pub unsafe fn rdgsbase() -> u64 {
226+
#[cfg(feature = "inline_asm")]
227+
#[inline(always)]
228+
unsafe fn inner() -> u64 {
229+
let val: u64;
230+
llvm_asm!("rdgsbase $0" : "=r" (val) ::: "volatile");
231+
val
232+
}
233+
234+
#[cfg(not(feature = "inline_asm"))]
235+
#[inline(always)]
236+
unsafe fn inner() -> u64 {
237+
crate::asm::x86_64_asm_rdgsbase()
238+
}
239+
240+
inner()
241+
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ macro_rules! const_fn {
3232
}
3333
}
3434

35-
#[cfg(not(feature = "inline_asm"))]
35+
#[cfg(all(feature = "instructions", feature = "external_asm"))]
3636
pub(crate) mod asm;
3737

3838
pub mod addr;

src/registers/control.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ bitflags! {
125125
}
126126
}
127127

128-
#[cfg(target_arch = "x86_64")]
128+
#[cfg(feature = "instructions")]
129129
mod x86_64 {
130130
use super::*;
131131
use crate::structures::paging::PhysFrame;

0 commit comments

Comments
 (0)