fix(ld_so/dso): TPOFF with undefined symbol index
Fixes random `rustc` errors/page fault:
```
Dump of assembler code for function _RNvYNCNkNvNtNtCskfd1poFMNVt_21rustc_data_structures4sync12worker_local8REGISTRY00INtNtNtCs713rKgAoQ4g_4core3ops8function6FnOnceTINtNtB1o_6option6OptionQIB23_INtNtNtB1o_4cell4once8OnceCellNtB8_8RegistryEEEEE9call_onceBc_:
0x0000000007651e50 <+0>: 41 56 push r14
0x0000000007651e52 <+2>: 53 push rbx
0x0000000007651e53 <+3>: 50 push rax
0x0000000007651e54 <+4>: 48 8b 1d 6d 9c 46 02 mov rbx,QWORD PTR [rip+0x2469c6d] # 0x9abbac8
0x0000000007651e5b <+11>: 64 48 8b 04 25 00 00 00 00 mov rax,QWORD PTR fs:0x0
0x0000000007651e64 <+20>: 0f b6 4c 18 08 movzx ecx,BYTE PTR [rax+rbx*1+0x8]
0x0000000007651e69 <+25>: 48 01 d8 add rax,rbx
0x0000000007651e6c <+28>: 83 f9 01 cmp ecx,0x1
0x0000000007651e6f <+31>: 74 07 je 0x7651e78 <_RNvYNCNkNvNtNtCskfd1poFMNVt_21rustc_data_structures4sync12worker_local8REGISTRY00INtNtNtCs713rKgAoQ4g_4core3ops8function6FnOnceTINtNtB1o_6option6OptionQIB23_INtNtNtB1o_4cell4once8OnceCellNtB8_8RegistryEEEEE9call_onceBc_+40>
0x0000000007651e71 <+33>: 83 f9 02 cmp ecx,0x2
0x0000000007651e74 <+36>: 75 0a jne 0x7651e80 <_RNvYNCNkNvNtNtCskfd1poFMNVt_21rustc_data_structures4sync12worker_local8REGISTRY00INtNtNtCs713rKgAoQ4g_4core3ops8function6FnOnceTINtNtB1o_6option6OptionQIB23_INtNtNtB1o_4cell4once8OnceCellNtB8_8RegistryEEEEE9call_onceBc_+48>
0x0000000007651e76 <+38>: 31 c0 xor eax,eax
0x0000000007651e78 <+40>: 48 83 c4 08 add rsp,0x8
0x0000000007651e7c <+44>: 5b pop rbx
0x0000000007651e7d <+45>: 41 5e pop r14
0x0000000007651e7f <+47>: c3 ret
0x0000000007651e80 <+48>: 48 8d 35 69 11 00 00 lea rsi,[rip+0x1169] # 0x7652ff0 <_RINvNtNtNtNtCs7Gz96wxcBnT_3std3sys12thread_local6native5eager7destroyINtNtNtCs713rKgAoQ4g_4core4cell4once8OnceCellNtNtNtCskfd1poFMNVt_21rustc_data_structures4sync12worker_local8RegistryEEB1U_.llvm.5183627946997663933>
0x0000000007651e87 <+55>: 48 89 c7 mov rdi,rax
0x0000000007651e8a <+58>: 49 89 c6 mov r14,rax
0x0000000007651e8d <+61>: ff 15 c5 6b 47 02 call QWORD PTR [rip+0x2476bc5] # 0x9ac8a58
0x0000000007651e93 <+67>: 4c 89 f0 mov rax,r14
0x0000000007651e96 <+70>: 64 48 8b 0c 25 00 00 00 00 mov rcx,QWORD PTR fs:0x0
# rcx = 0x20aeb000 [FSBASE]
# rbx = 0x2b40
0x0000000007651e9f <+79>: c6 44 19 08 01 mov BYTE PTR [rcx+rbx*1+0x8],0x1 # <--- PAGE FAULT
0x0000000007651ea4 <+84>: 48 83 c4 08 add rsp,0x8
0x0000000007651ea8 <+88>: 5b pop rbx
0x0000000007651ea9 <+89>: 41 5e pop r14
0x0000000007651eab <+91>: c3 ret
```
Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
+23
-8
@@ -62,6 +62,9 @@ mod shim {
|
||||
|
||||
pub use shim::*;
|
||||
|
||||
/// Undefined Symbol Index
|
||||
pub const STN_UNDEF: SymbolIndex = SymbolIndex(0);
|
||||
|
||||
enum HashTable<'a> {
|
||||
Gnu(GnuHashTable<'a, FileHeader>),
|
||||
Sysv(SysVHashTable<'a, FileHeader>),
|
||||
@@ -878,7 +881,7 @@ impl DSO {
|
||||
fn static_relocate(&self, global_scope: &Scope, reloc: Relocation) -> object::Result<()> {
|
||||
let b = self.mmap.as_ptr() as usize;
|
||||
|
||||
let (sym, my_sym) = if reloc.sym.0 > 0 {
|
||||
let (sym, my_sym) = if reloc.sym != STN_UNDEF {
|
||||
let name = self.dynamic.symbol_name(reloc.sym).unwrap();
|
||||
|
||||
let lookup_scopes = [global_scope, self.scope()];
|
||||
@@ -896,11 +899,18 @@ impl DSO {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
let (s, t, tls_id) = sym
|
||||
let (s, tls_obj) = sym
|
||||
.as_ref()
|
||||
.map(|(sym, obj)| (sym.as_ptr() as usize, obj.tls_offset, obj.tls_module_id))
|
||||
// TODO: is self.tls_module_id the right fallback?
|
||||
.unwrap_or((0, 0, self.tls_module_id));
|
||||
.map(|(sym, obj)| (sym.as_ptr() as usize, obj.as_ref()))
|
||||
// (1) According to the System V gABI (Chapter 4, "Relocation"): if
|
||||
// the symbol index (`reloc.sym`) is undefined, the symbol value
|
||||
// (`s`) is defined as 0.
|
||||
//
|
||||
// (2) According to Drepper's ELF Handling For Thread-Local Storage
|
||||
// (Section 4.2, "Local Dynamic TLS Model"): a relocation with
|
||||
// undefined symbol index implies a reference to the current module
|
||||
// itself. Hence we resolve the object to `self`.
|
||||
.unwrap_or((0, self));
|
||||
|
||||
let ptr = if self.pie {
|
||||
(b + reloc.offset) as *mut u8
|
||||
@@ -922,7 +932,7 @@ impl DSO {
|
||||
};
|
||||
|
||||
match reloc.kind {
|
||||
RelocationKind::DTPMOD => set_usize(tls_id),
|
||||
RelocationKind::DTPMOD => set_usize(tls_obj.tls_module_id),
|
||||
// TODO: Subtract DTP_OFFSET, which is 0x800 on riscv64, 0 on x86?
|
||||
RelocationKind::DTPOFF => {
|
||||
if reloc.sym.0 > 0 {
|
||||
@@ -939,13 +949,18 @@ impl DSO {
|
||||
RelocationKind::RELATIVE => set_usize(b + a),
|
||||
RelocationKind::SYMBOLIC => set_usize(s + a),
|
||||
RelocationKind::TPOFF => {
|
||||
assert!(
|
||||
!tls_obj.dlopened,
|
||||
"The {{local/initial}}-exec access model is used for symbol '{}' in '{}', which requires a static TLS block. However, the definition in '{}' resides in the dynamic TLS block because the object was loaded via dlopen(2).",
|
||||
reloc.sym, self.name, tls_obj.name
|
||||
);
|
||||
if reloc.sym.0 > 0 {
|
||||
let (sym, _) = sym
|
||||
.as_ref()
|
||||
.expect("RelocationKind::TPOFF called without valid symbol");
|
||||
set_usize((sym.value + a).wrapping_sub(t));
|
||||
set_usize((sym.value + a).wrapping_sub(tls_obj.tls_offset));
|
||||
} else {
|
||||
set_usize(a.wrapping_sub(t));
|
||||
set_usize(a.wrapping_sub(tls_obj.tls_offset));
|
||||
}
|
||||
}
|
||||
RelocationKind::IRELATIVE => unsafe {
|
||||
|
||||
Reference in New Issue
Block a user