1use elf::{endian::NativeEndian, string_table::StringTable, symbol::SymbolTable};
2use petgraph::graph::NodeIndex;
3use tracing::error;
4
5use crate::{
6 context::{relocate::EitherRel, Context},
7 library::Library,
8 symbol::LookupFlags,
9 tls::{TlsRegion, TlsVariant},
10 DynlinkError, DynlinkErrorKind,
11};
12
13pub(crate) const MINIMUM_TLS_ALIGNMENT: usize = 32;
14
15pub use elf::abi::{
16 R_X86_64_64 as REL_SYMBOLIC, R_X86_64_DTPMOD64 as REL_DTPMOD, R_X86_64_DTPOFF64 as REL_DTPOFF,
17 R_X86_64_GLOB_DAT as REL_GOT, R_X86_64_JUMP_SLOT as REL_PLT, R_X86_64_RELATIVE as REL_RELATIVE,
18 R_X86_64_TPOFF64 as REL_TPOFF, STB_WEAK,
19};
20
21#[repr(C)]
22pub struct Tcb<T> {
23 pub self_ptr: *const Tcb<T>,
24 pub dtv_len: usize,
25 pub dtv: *const usize,
26 pub runtime_data: T,
27}
28
29pub fn get_tls_variant() -> TlsVariant {
31 TlsVariant::Variant2
32}
33
34pub unsafe fn get_current_thread_control_block<T>() -> *mut Tcb<T> {
39 let mut val: usize;
40 core::arch::asm!("mov {}, fs:0", out(reg) val);
41 val as *mut _
42}
43
44impl TlsRegion {
45 pub unsafe fn get_thread_control_block<T>(&self) -> *mut Tcb<T> {
50 self.get_thread_pointer_value() as *mut _
51 }
52}
53
54impl Context {
55 pub(crate) fn do_reloc(
56 &self,
57 lib: &Library,
58 rel: EitherRel,
59 strings: &StringTable,
60 syms: &SymbolTable<NativeEndian>,
61 deps_list: &[NodeIndex],
62 ) -> Result<(), DynlinkError> {
63 let addend = rel.addend();
64 let base = lib.base_addr() as u64;
65 let target: *mut u64 = lib.laddr_mut(rel.offset());
66 let mut is_weak = false;
67 let symbol = if rel.sym() != 0 {
69 let sym = syms.get(rel.sym() as usize)?;
70 let flags = if sym.st_bind() == STB_WEAK {
71 is_weak = true;
72 LookupFlags::ALLOW_WEAK
73 } else {
74 LookupFlags::ALLOW_WEAK
75 };
76 strings
77 .get(sym.st_name as usize)
78 .map(|name| (name, self.lookup_symbol(lib.id(), name, flags, deps_list)))
79 .ok()
80 } else {
81 None
82 };
83 let sn = symbol.as_ref().map(|s| s.0).unwrap_or_default();
84
85 let open_sym = || {
87 if let Some((name, sym)) = symbol {
88 if let Ok(sym) = sym {
89 Result::<_, DynlinkError>::Ok(sym)
90 } else if is_weak {
91 Result::<_, DynlinkError>::Ok(crate::symbol::RelocatedSymbol::new_zero(lib))
92 } else {
93 error!("{}: needed symbol {} not found", lib, name);
94 Err(DynlinkErrorKind::SymbolLookupFail {
95 symname: name.into(),
96 sourcelib: lib.name.as_str().into(),
97 }
98 .into())
99 }
100 } else {
101 error!("{}: invalid relocation, no symbol data", lib);
102 Err(DynlinkErrorKind::MissingSection {
103 name: "symbol data".into(),
104 }
105 .into())
106 }
107 };
108
109 match rel.r_type() {
111 REL_RELATIVE => unsafe { *target = base.wrapping_add_signed(addend) },
112 REL_SYMBOLIC => unsafe {
113 *target = open_sym()?.reloc_value().wrapping_add_signed(addend)
114 },
115 REL_PLT | REL_GOT => unsafe { *target = open_sym()?.reloc_value() },
116 REL_DTPMOD => {
117 let id = if rel.sym() == 0 {
119 lib.tls_id
120 .as_ref()
121 .ok_or_else(|| DynlinkErrorKind::NoTLSInfo {
122 library: lib.name.as_str().into(),
123 })?
124 .tls_id()
125 } else {
126 let other_lib = open_sym()?.lib;
127 other_lib
128 .tls_id
129 .as_ref()
130 .ok_or_else(|| DynlinkErrorKind::NoTLSInfo {
131 library: other_lib.name.as_str().into(),
132 })?
133 .tls_id()
134 };
135 unsafe { *target = id }
136 }
137 REL_DTPOFF => {
138 let val = open_sym().map(|sym| sym.raw_value()).unwrap_or(0);
139 unsafe { *target = val.wrapping_add_signed(addend) }
140 }
141 REL_TPOFF => {
142 let sym = open_sym()?;
143 if let Some(tls) = sym.lib.tls_id {
144 unsafe {
145 *target = sym
146 .raw_value()
147 .wrapping_sub(tls.offset() as u64)
148 .wrapping_add_signed(addend)
149 }
150 } else {
151 error!(
152 "{}: TPOFF relocations require a PT_TLS segment (sym {})",
153 lib, sn
154 );
155 Err(DynlinkErrorKind::NoTLSInfo {
156 library: lib.name.as_str().into(),
157 })?
158 }
159 }
160 _ => {
161 error!("{}: unsupported relocation: {}", lib, rel.r_type());
162 Result::<_, DynlinkError>::Err(
163 DynlinkErrorKind::UnsupportedReloc {
164 library: lib.name.as_str().into(),
165 reloc: rel.r_type().to_string().into(),
166 }
167 .into(),
168 )?
169 }
170 }
171
172 Ok(())
173 }
174}