use crate::{
Result, TlsError,
elf::{ElfLayout, ElfPhdr, ElfProgramType},
memory::VmAddr,
sync::{Arc, Weak},
};
pub(crate) const TLS_GET_ADDR_SYMBOL: &str = "__tls_get_addr";
#[derive(Clone, Copy, Default)]
pub struct TlsInfo {
pub vaddr: usize,
pub filesz: usize,
pub memsz: usize,
pub align: usize,
}
impl core::fmt::Debug for TlsInfo {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("TlsInfo")
.field("vaddr", &format_args!("0x{:x}", self.vaddr))
.field("filesz", &self.filesz)
.field("memsz", &self.memsz)
.field("align", &self.align)
.finish()
}
}
impl TlsInfo {
pub fn new<L: ElfLayout>(phdr: &ElfPhdr<L>) -> Self {
assert_eq!(phdr.program_type(), ElfProgramType::TLS);
Self {
vaddr: phdr.p_vaddr().get(),
filesz: phdr.p_filesz(),
memsz: phdr.p_memsz(),
align: phdr.p_align(),
}
}
#[inline]
pub fn template<'a>(self, image: &'a [u8]) -> TlsTemplate<'a> {
debug_assert_eq!(image.len(), self.filesz);
TlsTemplate { info: self, image }
}
}
#[derive(Clone, Copy)]
pub struct TlsTemplate<'a> {
pub info: TlsInfo,
pub image: &'a [u8],
}
impl core::fmt::Debug for TlsTemplate<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("TlsTemplate")
.field("info", &self.info)
.field("image_len", &self.image.len())
.finish()
}
}
#[derive(Clone)]
pub struct TlsImageSource {
info: TlsInfo,
provider: Weak<dyn TlsImageProvider>,
}
impl core::fmt::Debug for TlsImageSource {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("TlsImageSource")
.field("info", &self.info())
.finish()
}
}
impl TlsImageSource {
#[inline]
pub(crate) fn new(info: TlsInfo, provider: Weak<dyn TlsImageProvider>) -> Self {
Self { info, provider }
}
#[inline]
pub fn info(&self) -> TlsInfo {
self.info
}
#[inline]
pub fn with_template(&self, f: &mut dyn FnMut(TlsTemplate<'_>) -> Result<()>) -> Result<()> {
let Some(provider) = self.provider.upgrade() else {
return Err(TlsError::TemplateUnavailable.into());
};
provider.with_tls_template(f)
}
}
pub(crate) trait TlsImageProvider: Send + Sync {
fn with_tls_template(&self, f: &mut dyn FnMut(TlsTemplate<'_>) -> Result<()>) -> Result<()>;
}
pub(crate) fn tls_image_provider_handle<T>(provider: Arc<T>) -> Arc<dyn TlsImageProvider>
where
T: TlsImageProvider + 'static,
{
let ptr = Arc::into_raw(provider);
let ptr: *const dyn TlsImageProvider = ptr;
unsafe { Arc::from_raw(ptr) }
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TlsDescValue {
resolver: VmAddr,
arg: usize,
}
impl TlsDescValue {
#[inline]
pub const fn new(resolver: VmAddr, arg: usize) -> Self {
Self { resolver, arg }
}
#[inline]
pub const fn resolver(&self) -> VmAddr {
self.resolver
}
#[inline]
pub const fn arg(&self) -> usize {
self.arg
}
}
#[repr(transparent)]
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TlsModuleId(usize);
impl TlsModuleId {
pub const RESERVED: Self = Self(0);
#[inline]
pub const fn new(raw: usize) -> Self {
Self(raw)
}
#[inline]
pub const fn get(self) -> usize {
self.0
}
#[inline]
pub const fn is_reserved(self) -> bool {
self.0 == Self::RESERVED.0
}
}
impl core::fmt::Display for TlsModuleId {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
#[repr(transparent)]
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TlsTpOffset(isize);
impl TlsTpOffset {
#[inline]
pub const fn new(raw: isize) -> Self {
Self(raw)
}
#[inline]
pub const fn get(self) -> isize {
self.0
}
}
impl core::fmt::Display for TlsTpOffset {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct TlsIndex {
pub ti_module: TlsModuleId,
pub ti_offset: usize,
}