Rollup merge of #138783 - bjorn3:cache_current_dll_path, r=lqd
Cache current_dll_path output Computing the current dll path is somewhat expensive relative to other work when compiling `fn main() {}` as `dladdr` needs to iterate over the symbol table of librustc_driver.so until it finds a match.
This commit is contained in:
commit
ab138e6aa8
1 changed files with 64 additions and 54 deletions
|
@ -60,66 +60,76 @@ pub fn make_target_bin_path(sysroot: &Path, target_triple: &str) -> PathBuf {
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn current_dll_path() -> Result<PathBuf, String> {
|
fn current_dll_path() -> Result<PathBuf, String> {
|
||||||
use std::ffi::{CStr, OsStr};
|
use std::sync::OnceLock;
|
||||||
use std::os::unix::prelude::*;
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "aix"))]
|
// This is somewhat expensive relative to other work when compiling `fn main() {}` as `dladdr`
|
||||||
unsafe {
|
// needs to iterate over the symbol table of librustc_driver.so until it finds a match.
|
||||||
let addr = current_dll_path as usize as *mut _;
|
// As such cache this to avoid recomputing if we try to get the sysroot in multiple places.
|
||||||
let mut info = std::mem::zeroed();
|
static CURRENT_DLL_PATH: OnceLock<Result<PathBuf, String>> = OnceLock::new();
|
||||||
if libc::dladdr(addr, &mut info) == 0 {
|
CURRENT_DLL_PATH
|
||||||
return Err("dladdr failed".into());
|
.get_or_init(|| {
|
||||||
}
|
use std::ffi::{CStr, OsStr};
|
||||||
if info.dli_fname.is_null() {
|
use std::os::unix::prelude::*;
|
||||||
return Err("dladdr returned null pointer".into());
|
|
||||||
}
|
|
||||||
let bytes = CStr::from_ptr(info.dli_fname).to_bytes();
|
|
||||||
let os = OsStr::from_bytes(bytes);
|
|
||||||
Ok(PathBuf::from(os))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "aix")]
|
#[cfg(not(target_os = "aix"))]
|
||||||
unsafe {
|
unsafe {
|
||||||
// On AIX, the symbol `current_dll_path` references a function descriptor.
|
let addr = current_dll_path as usize as *mut _;
|
||||||
// A function descriptor is consisted of (See https://reviews.llvm.org/D62532)
|
let mut info = std::mem::zeroed();
|
||||||
// * The address of the entry point of the function.
|
if libc::dladdr(addr, &mut info) == 0 {
|
||||||
// * The TOC base address for the function.
|
return Err("dladdr failed".into());
|
||||||
// * The environment pointer.
|
|
||||||
// The function descriptor is in the data section.
|
|
||||||
let addr = current_dll_path as u64;
|
|
||||||
let mut buffer = vec![std::mem::zeroed::<libc::ld_info>(); 64];
|
|
||||||
loop {
|
|
||||||
if libc::loadquery(
|
|
||||||
libc::L_GETINFO,
|
|
||||||
buffer.as_mut_ptr() as *mut u8,
|
|
||||||
(size_of::<libc::ld_info>() * buffer.len()) as u32,
|
|
||||||
) >= 0
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
if std::io::Error::last_os_error().raw_os_error().unwrap() != libc::ENOMEM {
|
|
||||||
return Err("loadquery failed".into());
|
|
||||||
}
|
}
|
||||||
buffer.resize(buffer.len() * 2, std::mem::zeroed::<libc::ld_info>());
|
if info.dli_fname.is_null() {
|
||||||
}
|
return Err("dladdr returned null pointer".into());
|
||||||
}
|
}
|
||||||
let mut current = buffer.as_mut_ptr() as *mut libc::ld_info;
|
let bytes = CStr::from_ptr(info.dli_fname).to_bytes();
|
||||||
loop {
|
|
||||||
let data_base = (*current).ldinfo_dataorg as u64;
|
|
||||||
let data_end = data_base + (*current).ldinfo_datasize;
|
|
||||||
if (data_base..data_end).contains(&addr) {
|
|
||||||
let bytes = CStr::from_ptr(&(*current).ldinfo_filename[0]).to_bytes();
|
|
||||||
let os = OsStr::from_bytes(bytes);
|
let os = OsStr::from_bytes(bytes);
|
||||||
return Ok(PathBuf::from(os));
|
Ok(PathBuf::from(os))
|
||||||
}
|
}
|
||||||
if (*current).ldinfo_next == 0 {
|
|
||||||
break;
|
#[cfg(target_os = "aix")]
|
||||||
|
unsafe {
|
||||||
|
// On AIX, the symbol `current_dll_path` references a function descriptor.
|
||||||
|
// A function descriptor is consisted of (See https://reviews.llvm.org/D62532)
|
||||||
|
// * The address of the entry point of the function.
|
||||||
|
// * The TOC base address for the function.
|
||||||
|
// * The environment pointer.
|
||||||
|
// The function descriptor is in the data section.
|
||||||
|
let addr = current_dll_path as u64;
|
||||||
|
let mut buffer = vec![std::mem::zeroed::<libc::ld_info>(); 64];
|
||||||
|
loop {
|
||||||
|
if libc::loadquery(
|
||||||
|
libc::L_GETINFO,
|
||||||
|
buffer.as_mut_ptr() as *mut u8,
|
||||||
|
(size_of::<libc::ld_info>() * buffer.len()) as u32,
|
||||||
|
) >= 0
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if std::io::Error::last_os_error().raw_os_error().unwrap() != libc::ENOMEM {
|
||||||
|
return Err("loadquery failed".into());
|
||||||
|
}
|
||||||
|
buffer.resize(buffer.len() * 2, std::mem::zeroed::<libc::ld_info>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut current = buffer.as_mut_ptr() as *mut libc::ld_info;
|
||||||
|
loop {
|
||||||
|
let data_base = (*current).ldinfo_dataorg as u64;
|
||||||
|
let data_end = data_base + (*current).ldinfo_datasize;
|
||||||
|
if (data_base..data_end).contains(&addr) {
|
||||||
|
let bytes = CStr::from_ptr(&(*current).ldinfo_filename[0]).to_bytes();
|
||||||
|
let os = OsStr::from_bytes(bytes);
|
||||||
|
return Ok(PathBuf::from(os));
|
||||||
|
}
|
||||||
|
if (*current).ldinfo_next == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current = (current as *mut i8).offset((*current).ldinfo_next as isize)
|
||||||
|
as *mut libc::ld_info;
|
||||||
|
}
|
||||||
|
return Err(format!("current dll's address {} is not in the load map", addr));
|
||||||
}
|
}
|
||||||
current =
|
})
|
||||||
(current as *mut i8).offset((*current).ldinfo_next as isize) as *mut libc::ld_info;
|
.clone()
|
||||||
}
|
|
||||||
return Err(format!("current dll's address {} is not in the load map", addr));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue