Skip to content

Commit b188a58

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 07a80aa commit b188a58

File tree

8 files changed

+240
-230
lines changed

8 files changed

+240
-230
lines changed

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")]

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]

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;

src/backend/linux_raw/param/auxv.rs

+85-25
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ use core::sync::atomic::AtomicU8;
2121
use core::sync::atomic::Ordering::Relaxed;
2222
use core::sync::atomic::{AtomicPtr, AtomicUsize};
2323
use linux_raw_sys::elf::*;
24+
#[cfg(target_arch = "x86")]
25+
use linux_raw_sys::general::AT_SYSINFO;
2426
use linux_raw_sys::general::{
2527
AT_BASE, AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_MINSIGSTKSZ, AT_NULL, AT_PAGESZ,
2628
AT_SYSINFO_EHDR,
@@ -38,8 +40,12 @@ pub(crate) fn page_size() -> usize {
3840
let mut page_size = PAGE_SIZE.load(Relaxed);
3941

4042
if page_size == 0 {
41-
init_auxv();
42-
page_size = PAGE_SIZE.load(Relaxed);
43+
#[cold]
44+
fn compute_page_size() -> usize {
45+
init_auxv();
46+
PAGE_SIZE.load(Relaxed)
47+
}
48+
page_size = compute_page_size();
4349
}
4450

4551
page_size
@@ -51,8 +57,12 @@ pub(crate) fn clock_ticks_per_second() -> u64 {
5157
let mut ticks = CLOCK_TICKS_PER_SECOND.load(Relaxed);
5258

5359
if ticks == 0 {
54-
init_auxv();
55-
ticks = CLOCK_TICKS_PER_SECOND.load(Relaxed);
60+
#[cold]
61+
fn compute_clock_ticks_per_second() -> usize {
62+
init_auxv();
63+
CLOCK_TICKS_PER_SECOND.load(Relaxed)
64+
}
65+
ticks = compute_clock_ticks_per_second();
5666
}
5767

5868
ticks as u64
@@ -65,9 +75,12 @@ pub(crate) fn linux_hwcap() -> (usize, usize) {
6575
let mut hwcap2 = HWCAP2.load(Relaxed);
6676

6777
if hwcap == 0 || hwcap2 == 0 {
68-
init_auxv();
69-
hwcap = HWCAP.load(Relaxed);
70-
hwcap2 = HWCAP2.load(Relaxed);
78+
#[cold]
79+
fn compute_linux_hwcap() -> (usize, usize) {
80+
init_auxv();
81+
(HWCAP.load(Relaxed), HWCAP2.load(Relaxed))
82+
}
83+
(hwcap, hwcap2) = compute_linux_hwcap();
7184
}
7285

7386
(hwcap, hwcap2)
@@ -92,8 +105,12 @@ pub(crate) fn linux_execfn() -> &'static CStr {
92105
let mut execfn = EXECFN.load(Relaxed);
93106

94107
if execfn.is_null() {
95-
init_auxv();
96-
execfn = EXECFN.load(Relaxed);
108+
#[cold]
109+
fn compute_linux_execfn() -> *mut c::c_char {
110+
init_auxv();
111+
EXECFN.load(Relaxed)
112+
}
113+
execfn = compute_linux_execfn();
97114
}
98115

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

109126
// 0 means not initialized yet.
110127
if secure == 0 {
111-
init_auxv();
112-
secure = SECURE.load(Relaxed);
128+
#[cold]
129+
fn compute_linux_secure() -> u8 {
130+
init_auxv();
131+
SECURE.load(Relaxed)
132+
}
133+
secure = compute_linux_secure();
113134
}
114135

115136
// 0 means not present. Libc `getauxval(AT_SECURE)` would return 0.
@@ -125,11 +146,13 @@ pub(crate) fn exe_phdrs() -> (*const c::c_void, usize, usize) {
125146
let mut phent = PHENT.load(Relaxed);
126147
let mut phnum = PHNUM.load(Relaxed);
127148

128-
if phdr.is_null() || phnum == 0 {
129-
init_auxv();
130-
phdr = PHDR.load(Relaxed);
131-
phent = PHENT.load(Relaxed);
132-
phnum = PHNUM.load(Relaxed);
149+
if phdr.is_null() || phent == 0 || phnum == 0 {
150+
#[cold]
151+
fn compute_exe_phdrs() -> (*mut Elf_Phdr, usize, usize) {
152+
init_auxv();
153+
(PHDR.load(Relaxed), PHENT.load(Relaxed), PHNUM.load(Relaxed))
154+
}
155+
(phdr, phent, phnum) = compute_exe_phdrs();
133156
}
134157

135158
(phdr.cast(), phent, phnum)
@@ -145,12 +168,16 @@ pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr {
145168
let mut ehdr = SYSINFO_EHDR.load(Relaxed);
146169

147170
if ehdr.is_null() {
148-
// Use `maybe_init_auxv` to to read the aux vectors if it can, but do
149-
// nothing if it can't. If it can't, then we'll get a null pointer
150-
// here, which our callers are prepared to deal with.
151-
maybe_init_auxv();
171+
#[cold]
172+
fn compute_sysinfo_ehdr() -> *mut Elf_Ehdr {
173+
// Use `maybe_init_auxv` to to read the aux vectors if it can, but do
174+
// nothing if it can't. If it can't, then we'll get a null pointer
175+
// here, which our callers are prepared to deal with.
176+
maybe_init_auxv();
177+
SYSINFO_EHDR.load(Relaxed)
178+
}
152179

153-
ehdr = SYSINFO_EHDR.load(Relaxed);
180+
ehdr = compute_sysinfo_ehdr();
154181
}
155182

156183
ehdr
@@ -162,8 +189,12 @@ pub(crate) fn entry() -> usize {
162189
let mut entry = ENTRY.load(Relaxed);
163190

164191
if entry == 0 {
165-
init_auxv();
166-
entry = ENTRY.load(Relaxed);
192+
#[cold]
193+
fn compute_entry() -> usize {
194+
init_auxv();
195+
ENTRY.load(Relaxed)
196+
}
197+
entry = compute_entry();
167198
}
168199

169200
entry
@@ -175,13 +206,34 @@ pub(crate) fn random() -> *const [u8; 16] {
175206
let mut random = RANDOM.load(Relaxed);
176207

177208
if random.is_null() {
178-
init_auxv();
179-
random = RANDOM.load(Relaxed);
209+
#[cold]
210+
fn compute_random() -> *mut [u8; 16] {
211+
init_auxv();
212+
RANDOM.load(Relaxed)
213+
}
214+
random = compute_random();
180215
}
181216

182217
random
183218
}
184219

220+
#[cfg(target_arch = "x86")]
221+
#[inline]
222+
pub(crate) fn vsyscall() -> *const c::c_void {
223+
let mut vsyscall = VSYSCALL.load(Relaxed);
224+
225+
if vsyscall.is_null() {
226+
#[cold]
227+
fn compute_vsyscall() -> *const c::c_void {
228+
init_auxv();
229+
VSYSCALL.load(Relaxed)
230+
}
231+
vsyscall = compute_vsyscall();
232+
}
233+
234+
vsyscall
235+
}
236+
185237
static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
186238
static CLOCK_TICKS_PER_SECOND: AtomicUsize = AtomicUsize::new(0);
187239
static HWCAP: AtomicUsize = AtomicUsize::new(0);
@@ -201,6 +253,8 @@ static PHNUM: AtomicUsize = AtomicUsize::new(0);
201253
static ENTRY: AtomicUsize = AtomicUsize::new(0);
202254
#[cfg(feature = "runtime")]
203255
static RANDOM: AtomicPtr<[u8; 16]> = AtomicPtr::new(null_mut());
256+
#[cfg(feature = "x86")]
257+
static VSYSCALL: AtomicPtr<c::c_void> = AtomicPtr::new(null_mut());
204258

205259
const PR_GET_AUXV: c::c_int = 0x4155_5856;
206260

@@ -389,6 +443,8 @@ unsafe fn init_from_aux_iter(aux_iter: impl Iterator<Item = Elf_auxv_t>) -> Opti
389443
let mut egid = None;
390444
#[cfg(feature = "runtime")]
391445
let mut random = null_mut();
446+
#[cfg(target_arch = "x86")]
447+
let mut vsyscall = null_mut();
392448

393449
for Elf_auxv_t { a_type, a_val } in aux_iter {
394450
match a_type as _ {
@@ -428,6 +484,8 @@ unsafe fn init_from_aux_iter(aux_iter: impl Iterator<Item = Elf_auxv_t>) -> Opti
428484
AT_ENTRY => entry = a_val as usize,
429485
#[cfg(feature = "runtime")]
430486
AT_RANDOM => random = check_raw_pointer::<[u8; 16]>(a_val as *mut _)?.as_ptr(),
487+
#[cfg(target_arch = "x86")]
488+
AT_SYSINFO => vsyscall = a_val.cast(),
431489

432490
AT_NULL => break,
433491
_ => (),
@@ -464,6 +522,8 @@ unsafe fn init_from_aux_iter(aux_iter: impl Iterator<Item = Elf_auxv_t>) -> Opti
464522
ENTRY.store(entry, Relaxed);
465523
#[cfg(feature = "runtime")]
466524
RANDOM.store(random, Relaxed);
525+
#[cfg(target_arch = "x86")]
526+
VSYSCALL.store(vsyscall, Relaxed);
467527

468528
Some(())
469529
}

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_MINSIGSTKSZ, AT_NULL, AT_PAGESZ, AT_SYSINFO_EHDR,
1921
};
@@ -96,6 +98,12 @@ pub(crate) fn random() -> *const [u8; 16] {
9698
unsafe { RANDOM.load(Ordering::Relaxed) }
9799
}
98100

101+
#[cfg(target_arch = "x86")]
102+
#[inline]
103+
pub(crate) fn vsyscall() -> *const c_void {
104+
unsafe { VSYSCALL.load(Ordering::Relaxed) }
105+
}
106+
99107
static mut PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
100108
static mut CLOCK_TICKS_PER_SECOND: AtomicUsize = AtomicUsize::new(0);
101109
static mut HWCAP: AtomicUsize = AtomicUsize::new(0);
@@ -118,6 +126,8 @@ static mut PHNUM: AtomicUsize = AtomicUsize::new(0);
118126
static mut ENTRY: AtomicUsize = AtomicUsize::new(0);
119127
#[cfg(feature = "runtime")]
120128
static mut RANDOM: AtomicPtr<[u8; 16]> = AtomicPtr::new(NonNull::dangling().as_ptr());
129+
#[cfg(target_arch = "x86")]
130+
static mut VSYSCALL: AtomicPtr<c_void> = AtomicPtr::new(NonNull::dangling().as_ptr());
121131

122132
/// When "use-explicitly-provided-auxv" is enabled, we export a function to be
123133
/// called during initialization, and passed a pointer to the original
@@ -170,6 +180,8 @@ unsafe fn init_from_auxp(mut auxp: *const Elf_auxv_t) {
170180
AT_ENTRY => ENTRY.store(a_val as usize, Ordering::Relaxed),
171181
#[cfg(feature = "runtime")]
172182
AT_RANDOM => RANDOM.store(a_val.cast::<[u8; 16]>(), Ordering::Relaxed),
183+
#[cfg(feature = "x86")]
184+
AT_SYSINFO => VSYSCALL.store(a_val.cast::<c_void>(), Ordering::Relaxed),
173185

174186
AT_NULL => break,
175187
_ => (),

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")]
@@ -192,3 +202,25 @@ pub(crate) fn entry() -> usize {
192202
pub(crate) fn random() -> *const [u8; 16] {
193203
unsafe { getauxval(AT_RANDOM) as *const [u8; 16] }
194204
}
205+
206+
#[cfg(target_arch = "x86")]
207+
#[inline]
208+
pub(crate) fn vsyscall() -> *const c_void {
209+
// We call this for every system call, so memoize the value.
210+
static VSYSCALL: AtomicPtr<c_void> = AtomicPtr::new(null_mut());
211+
212+
let mut vsyscall = VSYSCALL.load(Relaxed);
213+
214+
if vsyscall.is_null() {
215+
#[cold]
216+
fn compute_vsyscall() -> *mut c_void {
217+
let vsyscall = unsafe { getauxval(AT_SYSINFO) } as *mut c_void;
218+
VSYSCALL.store(vsyscall, Relaxed);
219+
vsyscall
220+
}
221+
222+
vsyscall = compute_vsyscall();
223+
}
224+
225+
vsyscall
226+
}

0 commit comments

Comments
 (0)