1#![warn(warnings, unused_variables)]
6
7use core::{mem, ptr};
8use object::{
9 Endianness,
10 elf::{self, ProgramHeader32, ProgramHeader64},
11 read::elf::ProgramHeader,
12};
13
14use self::tcb::{Master, Tcb};
15use crate::{
16 header::sys_auxv::{AT_NULL, AT_PHDR, AT_PHENT, AT_PHNUM},
17 platform::{Pal, Sys},
18 start::Stack,
19};
20
21pub const PATH_SEP: char = ':';
22
23mod access;
24pub mod callbacks;
25pub mod debug;
26mod dso;
27pub mod linker;
28pub mod start;
29pub mod tcb;
30
31pub use generic_rt::{ExpectTlsFree, panic_notls};
32
33static mut STATIC_TCB_MASTER: Master = Master {
34 ptr: ptr::null_mut(),
35 image_size: 0,
36 segment_size: 0,
37 offset: 0,
38};
39
40#[inline(never)]
41fn static_init(
42 sp: &'static Stack,
43 #[cfg(target_os = "redox")] thr_fd: redox_rt::proc::FdGuardUpper,
44) {
45 const SIZEOF_PHDR64: usize = mem::size_of::<ProgramHeader64<Endianness>>();
46 const SIZEOF_PHDR32: usize = mem::size_of::<ProgramHeader32<Endianness>>();
47
48 let mut phdr_opt = None;
49 let mut phent_opt = None;
50 let mut phnum_opt = None;
51
52 let mut auxv = sp.auxv();
53 loop {
54 let (kind, value) = unsafe { *auxv };
55 if kind == AT_NULL {
56 break;
57 }
58
59 match kind {
60 AT_PHDR => phdr_opt = Some(value),
61 AT_PHENT => phent_opt = Some(value),
62 AT_PHNUM => phnum_opt = Some(value),
63 _ => (),
64 }
65
66 auxv = unsafe { auxv.add(1) };
67 }
68
69 let phdr = phdr_opt.expect_notls("failed to find AT_PHDR");
70 let phent = phent_opt.expect_notls("failed to find AT_PHENT");
71 let phnum = phnum_opt.expect_notls("failed to find AT_PHNUM");
72
73 for i in 0..phnum {
74 let ph_addr = phdr + phent * i;
75 let endian = Endianness::default();
76 let (p_align, p_filesz, p_memsz, p_type, p_vaddr) = match phent {
77 SIZEOF_PHDR64 => unsafe {
78 let ph = &*(ph_addr as *const ProgramHeader64<Endianness>);
79 (
80 ph.p_align(endian) as usize,
81 ph.p_filesz(endian) as usize,
82 ph.p_memsz(endian) as usize,
83 ph.p_type(endian),
84 ph.p_vaddr(endian) as usize,
85 )
86 },
87
88 SIZEOF_PHDR32 => unsafe {
89 let ph = &*(ph_addr as *const ProgramHeader32<Endianness>);
90 (
91 ph.p_align(endian) as usize,
92 ph.p_filesz(endian) as usize,
93 ph.p_memsz(endian) as usize,
94 ph.p_type(endian),
95 ph.p_vaddr(endian) as usize,
96 )
97 },
98 _ => panic_notls(format_args!("unknown AT_PHENT size {}", phent)),
99 };
100
101 let page_size = Sys::getpagesize();
102 let voff = p_vaddr % page_size;
103 let vsize = (p_memsz + voff).div_ceil(page_size) * page_size;
105
106 if p_type == elf::PT_TLS {
107 let valign = if p_align > 0 {
108 p_memsz.div_ceil(p_align) * p_align
109 } else {
110 p_memsz
111 };
112
113 unsafe {
114 STATIC_TCB_MASTER.ptr = p_vaddr as *const u8;
115 STATIC_TCB_MASTER.image_size = p_filesz;
116 STATIC_TCB_MASTER.offset = valign;
117
118 let tcb = Tcb::new(vsize).expect_notls("failed to allocate TCB");
119 tcb.masters_ptr = ptr::addr_of_mut!(STATIC_TCB_MASTER);
120 tcb.masters_len = mem::size_of::<Master>();
121 tcb.copy_masters()
122 .expect_notls("failed to copy TLS master data");
123 tcb.activate(
124 #[cfg(target_os = "redox")]
125 Some(thr_fd),
126 );
127 }
128
129 return;
131 }
132 }
133}
134
135#[cfg(any(target_os = "linux", target_os = "redox"))]
136pub unsafe fn init(
137 sp: &'static Stack,
138 #[cfg(target_os = "redox")] thr_fd: redox_rt::proc::FdGuardUpper,
139) {
140 let tp: usize;
141
142 #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
143 {
144 const ARCH_GET_FS: usize = 0x1003;
145 let mut val = 0usize;
146 syscall!(ARCH_PRCTL, ARCH_GET_FS, &raw mut val);
147 tp = val;
148 }
149 #[cfg(target_arch = "aarch64")]
150 unsafe {
151 core::arch::asm!(
152 "mrs {}, tpidr_el0",
153 out(reg) tp,
154 );
155 }
156 #[cfg(all(target_os = "redox", target_arch = "x86"))]
157 {
158 let mut env = syscall::EnvRegisters::default();
159
160 {
161 let file = thr_fd
162 .dup_into_upper(b"regs/env")
163 .expect_notls("failed to open handle for process registers");
164
165 file.read(&mut env).expect_notls("failed to read gsbase");
166 }
167
168 tp = env.gsbase as usize;
169 }
170 #[cfg(all(target_os = "redox", target_arch = "x86_64"))]
171 {
172 let mut env = syscall::EnvRegisters::default();
173
174 {
175 let file = thr_fd
176 .dup_into_upper(b"regs/env")
177 .expect_notls("failed to open handle for process registers");
178
179 file.read(&mut env).expect_notls("failed to read fsbase");
180 }
181
182 tp = env.fsbase as usize;
183 }
184 #[cfg(all(target_os = "redox", target_arch = "riscv64"))]
185 unsafe {
186 core::arch::asm!(
187 "mv {}, tp",
188 out(reg) tp,
189 );
190 }
191
192 if tp == 0 {
193 static_init(
194 sp,
195 #[cfg(target_os = "redox")]
196 thr_fd,
197 );
198 } else {
199 #[cfg(target_os = "redox")]
201 core::mem::forget(thr_fd);
202 }
203}
204
205pub unsafe fn fini() {
206 if let Some(tcb) = unsafe { Tcb::current() }
207 && !tcb.linker_ptr.is_null()
208 {
209 let linker = unsafe { (*tcb.linker_ptr).lock() };
210 linker.fini();
211 }
212}