Skip to content

Commit 0892b09

Browse files
committed
On 32-bit x86, get the vsyscall address from the AUX vector
On 32-bit x86, get the vsyscall address from the AT_SYSINFO AUX vector entry, rather than looking it up in the vDSO. This avoids the need to link in all the vDSO code if it isn't otherwise needed. And, it's simpler, avoiding the need for the `rustix_int_0x80` function.
1 parent c2e1182 commit 0892b09

File tree

8 files changed

+237
-227
lines changed

8 files changed

+237
-227
lines changed

Diff for: src/backend/linux_raw/arch/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ pub(in crate::backend) mod asm;
5151
))]
5252
pub(in crate::backend) use self::asm as choose;
5353

54-
// On 32-bit x86, use vDSO wrappers for all syscalls. We could use the
55-
// architecture syscall instruction (`int 0x80`), but the vDSO kernel_vsyscall
54+
// On 32-bit x86, use the kernel_vsyscall mechanism for syscalls. We could use
55+
// the architecture syscall instruction (`int 0x80`), but the kernel_vsyscall
5656
// mechanism is much faster.
5757
#[cfg(target_arch = "x86")]
58-
pub(in crate::backend) use super::vdso_wrappers::x86_via_vdso as choose;
58+
pub(in crate::backend) use super::x86_vsyscall as choose;
5959

6060
// This would be the code for always using `int 0x80` on 32-bit x86.
6161
//#[cfg(target_arch = "x86")]

Diff for: src/backend/linux_raw/arch/x86.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use crate::backend::reg::{
1616
ArgReg, FromAsm, RetReg, SyscallNumber, ToAsm, A0, A1, A2, A3, A4, A5, R0,
1717
};
18-
use crate::backend::vdso_wrappers::SyscallType;
18+
use crate::backend::x86_vsyscall::SyscallType;
1919
use core::arch::asm;
2020

2121
#[inline]

Diff for: src/backend/linux_raw/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
mod arch;
1919
mod conv;
2020
mod reg;
21-
#[cfg(any(feature = "time", feature = "process", target_arch = "x86"))]
21+
#[cfg(any(feature = "time", feature = "process"))]
2222
mod vdso;
23-
#[cfg(any(feature = "time", feature = "process", target_arch = "x86"))]
23+
#[cfg(any(feature = "time", feature = "process"))]
2424
mod vdso_wrappers;
25+
#[cfg(target_arch = "x86")]
26+
mod x86_vsyscall;
2527

2628
#[cfg(feature = "event")]
2729
pub(crate) mod event;

Diff for: src/backend/linux_raw/param/auxv.rs

+82-22
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ use core::sync::atomic::AtomicU8;
2020
use core::sync::atomic::Ordering::Relaxed;
2121
use core::sync::atomic::{AtomicPtr, AtomicUsize};
2222
use linux_raw_sys::elf::*;
23+
#[cfg(target_arch = "x86")]
24+
use linux_raw_sys::general::AT_SYSINFO;
2325
use linux_raw_sys::general::{
2426
AT_BASE, AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_NULL, AT_PAGESZ, AT_SYSINFO_EHDR,
2527
};
@@ -34,8 +36,12 @@ pub(crate) fn page_size() -> usize {
3436
let mut page_size = PAGE_SIZE.load(Relaxed);
3537

3638
if page_size == 0 {
37-
init_auxv();
38-
page_size = PAGE_SIZE.load(Relaxed);
39+
#[cold]
40+
fn compute_page_size() -> usize {
41+
init_auxv();
42+
PAGE_SIZE.load(Relaxed)
43+
}
44+
page_size = compute_page_size();
3945
}
4046

4147
page_size
@@ -47,8 +53,12 @@ pub(crate) fn clock_ticks_per_second() -> u64 {
4753
let mut ticks = CLOCK_TICKS_PER_SECOND.load(Relaxed);
4854

4955
if ticks == 0 {
50-
init_auxv();
51-
ticks = CLOCK_TICKS_PER_SECOND.load(Relaxed);
56+
#[cold]
57+
fn compute_clock_ticks_per_second() -> usize {
58+
init_auxv();
59+
CLOCK_TICKS_PER_SECOND.load(Relaxed)
60+
}
61+
ticks = compute_clock_ticks_per_second();
5262
}
5363

5464
ticks as u64
@@ -61,9 +71,12 @@ pub(crate) fn linux_hwcap() -> (usize, usize) {
6171
let mut hwcap2 = HWCAP2.load(Relaxed);
6272

6373
if hwcap == 0 || hwcap2 == 0 {
64-
init_auxv();
65-
hwcap = HWCAP.load(Relaxed);
66-
hwcap2 = HWCAP2.load(Relaxed);
74+
#[cold]
75+
fn compute_linux_hwcap() -> (usize, usize) {
76+
init_auxv();
77+
(HWCAP.load(Relaxed), HWCAP2.load(Relaxed))
78+
}
79+
(hwcap, hwcap2) = compute_linux_hwcap();
6780
}
6881

6982
(hwcap, hwcap2)
@@ -75,8 +88,12 @@ pub(crate) fn linux_execfn() -> &'static CStr {
7588
let mut execfn = EXECFN.load(Relaxed);
7689

7790
if execfn.is_null() {
78-
init_auxv();
79-
execfn = EXECFN.load(Relaxed);
91+
#[cold]
92+
fn compute_linux_execfn() -> *mut c::c_char {
93+
init_auxv();
94+
EXECFN.load(Relaxed)
95+
}
96+
execfn = compute_linux_execfn();
8097
}
8198

8299
// SAFETY: We assume the `AT_EXECFN` value provided by the kernel is a
@@ -91,8 +108,12 @@ pub(crate) fn linux_secure() -> bool {
91108

92109
// 0 means not initialized yet.
93110
if secure == 0 {
94-
init_auxv();
95-
secure = SECURE.load(Relaxed);
111+
#[cold]
112+
fn compute_linux_secure() -> u8 {
113+
init_auxv();
114+
SECURE.load(Relaxed)
115+
}
116+
secure = compute_linux_secure();
96117
}
97118

98119
// 0 means not present. Libc `getauxval(AT_SECURE)` would return 0.
@@ -108,11 +129,13 @@ pub(crate) fn exe_phdrs() -> (*const c::c_void, usize, usize) {
108129
let mut phent = PHENT.load(Relaxed);
109130
let mut phnum = PHNUM.load(Relaxed);
110131

111-
if phdr.is_null() || phnum == 0 {
112-
init_auxv();
113-
phdr = PHDR.load(Relaxed);
114-
phent = PHENT.load(Relaxed);
115-
phnum = PHNUM.load(Relaxed);
132+
if phdr.is_null() || phent == 0 || phnum == 0 {
133+
#[cold]
134+
fn compute_exe_phdrs() -> (*mut Elf_Phdr, usize, usize) {
135+
init_auxv();
136+
(PHDR.load(Relaxed), PHENT.load(Relaxed), PHNUM.load(Relaxed))
137+
}
138+
(phdr, phent, phnum) = compute_exe_phdrs();
116139
}
117140

118141
(phdr.cast(), phent, phnum)
@@ -125,8 +148,12 @@ pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr {
125148
let mut ehdr = SYSINFO_EHDR.load(Relaxed);
126149

127150
if ehdr.is_null() {
128-
init_auxv();
129-
ehdr = SYSINFO_EHDR.load(Relaxed);
151+
#[cold]
152+
fn compute_sysinfo_ehdr() -> *mut Elf_Ehdr {
153+
init_auxv();
154+
SYSINFO_EHDR.load(Relaxed)
155+
}
156+
ehdr = compute_sysinfo_ehdr();
130157
}
131158

132159
ehdr
@@ -138,8 +165,12 @@ pub(crate) fn entry() -> usize {
138165
let mut entry = ENTRY.load(Relaxed);
139166

140167
if entry == 0 {
141-
init_auxv();
142-
entry = ENTRY.load(Relaxed);
168+
#[cold]
169+
fn compute_entry() -> usize {
170+
init_auxv();
171+
ENTRY.load(Relaxed)
172+
}
173+
entry = compute_entry();
143174
}
144175

145176
entry
@@ -151,13 +182,34 @@ pub(crate) fn random() -> *const [u8; 16] {
151182
let mut random = RANDOM.load(Relaxed);
152183

153184
if random.is_null() {
154-
init_auxv();
155-
random = RANDOM.load(Relaxed);
185+
#[cold]
186+
fn compute_random() -> *mut [u8; 16] {
187+
init_auxv();
188+
RANDOM.load(Relaxed)
189+
}
190+
random = compute_random();
156191
}
157192

158193
random
159194
}
160195

196+
#[cfg(target_arch = "x86")]
197+
#[inline]
198+
pub(crate) fn vsyscall() -> *const c::c_void {
199+
let mut vsyscall = VSYSCALL.load(Relaxed);
200+
201+
if vsyscall.is_null() {
202+
#[cold]
203+
fn compute_vsyscall() -> *const c::c_void {
204+
init_auxv();
205+
VSYSCALL.load(Relaxed)
206+
}
207+
vsyscall = compute_vsyscall();
208+
}
209+
210+
vsyscall
211+
}
212+
161213
static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
162214
static CLOCK_TICKS_PER_SECOND: AtomicUsize = AtomicUsize::new(0);
163215
static HWCAP: AtomicUsize = AtomicUsize::new(0);
@@ -176,6 +228,8 @@ static PHNUM: AtomicUsize = AtomicUsize::new(0);
176228
static ENTRY: AtomicUsize = AtomicUsize::new(0);
177229
#[cfg(feature = "runtime")]
178230
static RANDOM: AtomicPtr<[u8; 16]> = AtomicPtr::new(null_mut());
231+
#[cfg(feature = "x86")]
232+
static VSYSCALL: AtomicPtr<c::c_void> = AtomicPtr::new(null_mut());
179233

180234
#[cfg(feature = "alloc")]
181235
fn pr_get_auxv() -> crate::io::Result<Vec<u8>> {
@@ -315,6 +369,8 @@ unsafe fn init_from_aux_iter(aux_iter: impl Iterator<Item = Elf_auxv_t>) -> Opti
315369
let mut egid = None;
316370
#[cfg(feature = "runtime")]
317371
let mut random = null_mut();
372+
#[cfg(target_arch = "x86")]
373+
let mut vsyscall = null_mut();
318374

319375
for Elf_auxv_t { a_type, a_val } in aux_iter {
320376
match a_type as _ {
@@ -353,6 +409,8 @@ unsafe fn init_from_aux_iter(aux_iter: impl Iterator<Item = Elf_auxv_t>) -> Opti
353409
AT_ENTRY => entry = a_val as usize,
354410
#[cfg(feature = "runtime")]
355411
AT_RANDOM => random = check_raw_pointer::<[u8; 16]>(a_val as *mut _)?.as_ptr(),
412+
#[cfg(target_arch = "x86")]
413+
AT_SYSINFO => vsyscall = a_val.cast(),
356414

357415
AT_NULL => break,
358416
_ => (),
@@ -388,6 +446,8 @@ unsafe fn init_from_aux_iter(aux_iter: impl Iterator<Item = Elf_auxv_t>) -> Opti
388446
ENTRY.store(entry, Relaxed);
389447
#[cfg(feature = "runtime")]
390448
RANDOM.store(random, Relaxed);
449+
#[cfg(target_arch = "x86")]
450+
VSYSCALL.store(vsyscall, Relaxed);
391451

392452
Some(())
393453
}

Diff for: src/backend/linux_raw/param/init.rs

+12
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use core::ptr::{null_mut, read, NonNull};
1414
use core::sync::atomic::AtomicBool;
1515
use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
1616
use linux_raw_sys::elf::*;
17+
#[cfg(target_arch = "x86")]
18+
use linux_raw_sys::general::AT_SYSINFO;
1719
use linux_raw_sys::general::{
1820
AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_NULL, AT_PAGESZ, AT_SYSINFO_EHDR,
1921
};
@@ -90,6 +92,12 @@ pub(crate) fn random() -> *const [u8; 16] {
9092
unsafe { RANDOM.load(Ordering::Relaxed) }
9193
}
9294

95+
#[cfg(target_arch = "x86")]
96+
#[inline]
97+
pub(crate) fn vsyscall() -> *const c_void {
98+
unsafe { VSYSCALL.load(Ordering::Relaxed) }
99+
}
100+
93101
static mut PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
94102
static mut CLOCK_TICKS_PER_SECOND: AtomicUsize = AtomicUsize::new(0);
95103
static mut HWCAP: AtomicUsize = AtomicUsize::new(0);
@@ -111,6 +119,8 @@ static mut PHNUM: AtomicUsize = AtomicUsize::new(0);
111119
static mut ENTRY: AtomicUsize = AtomicUsize::new(0);
112120
#[cfg(feature = "runtime")]
113121
static mut RANDOM: AtomicPtr<[u8; 16]> = AtomicPtr::new(NonNull::dangling().as_ptr());
122+
#[cfg(target_arch = "x86")]
123+
static mut VSYSCALL: AtomicPtr<c_void> = AtomicPtr::new(NonNull::dangling().as_ptr());
114124

115125
/// When "use-explicitly-provided-auxv" is enabled, we export a function to be
116126
/// called during initialization, and passed a pointer to the original
@@ -162,6 +172,8 @@ unsafe fn init_from_auxp(mut auxp: *const Elf_auxv_t) {
162172
AT_ENTRY => ENTRY.store(a_val as usize, Ordering::Relaxed),
163173
#[cfg(feature = "runtime")]
164174
AT_RANDOM => RANDOM.store(a_val.cast::<[u8; 16]>(), Ordering::Relaxed),
175+
#[cfg(feature = "x86")]
176+
AT_SYSINFO => VSYSCALL.store(a_val.cast::<c_void>(), Ordering::Relaxed),
165177

166178
AT_NULL => break,
167179
_ => (),

Diff for: src/backend/linux_raw/param/libc_auxv.rs

+32
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ use crate::ffi::CStr;
1111
#[cfg(not(feature = "runtime"))]
1212
use core::ptr::null;
1313
use linux_raw_sys::elf::*;
14+
#[cfg(target_arch = "x86")]
15+
use {
16+
core::ffi::c_void, core::ptr::null_mut, core::sync::atomic::AtomicPtr,
17+
core::sync::atomic::Ordering::Relaxed,
18+
};
1419

1520
// `getauxval` wasn't supported in glibc until 2.16. Also this lets us use
1621
// `*mut` as the return type to preserve strict provenance.
@@ -38,6 +43,8 @@ const AT_RANDOM: c::c_ulong = 25;
3843
const AT_HWCAP2: c::c_ulong = 26;
3944
const AT_SECURE: c::c_ulong = 23;
4045
const AT_EXECFN: c::c_ulong = 31;
46+
#[cfg(target_arch = "x86")]
47+
const AT_SYSINFO: c::c_ulong = 32;
4148
const AT_SYSINFO_EHDR: c::c_ulong = 33;
4249

4350
// Declare `sysconf` ourselves so that we don't depend on all of libc just for
@@ -72,6 +79,9 @@ fn test_abi() {
7279
const_assert_eq!(self::AT_ENTRY, ::libc::AT_ENTRY);
7380
#[cfg(feature = "runtime")]
7481
const_assert_eq!(self::AT_RANDOM, ::libc::AT_RANDOM);
82+
// TODO: Upstream x86's `AT_SYSINFO` to libc.
83+
#[cfg(target_arch = "x86")]
84+
const_assert_eq!(self::AT_SYSINFO, ::linux_raw_sys::general::AT_SYSINFO);
7585
}
7686

7787
#[cfg(feature = "param")]
@@ -173,3 +183,25 @@ pub(crate) fn entry() -> usize {
173183
pub(crate) fn random() -> *const [u8; 16] {
174184
unsafe { getauxval(AT_RANDOM) as *const [u8; 16] }
175185
}
186+
187+
#[cfg(target_arch = "x86")]
188+
#[inline]
189+
pub(crate) fn vsyscall() -> *const c_void {
190+
// We call this for every system call, so memoize the value.
191+
static VSYSCALL: AtomicPtr<c_void> = AtomicPtr::new(null_mut());
192+
193+
let mut vsyscall = VSYSCALL.load(Relaxed);
194+
195+
if vsyscall.is_null() {
196+
#[cold]
197+
fn compute_vsyscall() -> *mut c_void {
198+
let vsyscall = unsafe { getauxval(AT_SYSINFO) } as *mut c_void;
199+
VSYSCALL.store(vsyscall, Relaxed);
200+
vsyscall
201+
}
202+
203+
vsyscall = compute_vsyscall();
204+
}
205+
206+
vsyscall
207+
}

0 commit comments

Comments
 (0)