I am writing a linux dynamic linker in rust, and I am having issues preforming initial relocations without segfaulting. I've seen how origin does it and can do the same, but I would like to make my code more readable.
The issue is that calls to the PLT (I am pretty sure it's the PLT...) will segfault because nothing has been relocated yet. I would really like to find a way to get this code working reliably:
// main.rs (called by a custom _start)
let miros = if base.is_null() {
// We are the executable:
StaticPie::from_program_headers(&program_header_table, pseudorandom_bytes)
} else {
// We are the dynmaic linker:
StaticPie::from_base(base, pseudorandom_bytes)
};
miros.relocate().allocate_tls(); // <- PLT call here
// static_pie.rs
use std::{
arch::asm,
marker::PhantomData,
ptr::{null, null_mut},
slice,
};
use crate::{
arch::{
exit, io,
mmap::{mmap, MAP_ANONYMOUS, MAP_PRIVATE, PROT_READ, PROT_WRITE},
thread_pointer::set_thread_pointer,
},
elf::{
dynamic_array::{DynamicArrayItem, DynamicArrayIter, DT_RELA, DT_RELAENT, DT_RELASZ},
header::{ElfHeader, ET_DYN},
program_header::{ProgramHeader, PT_DYNAMIC, PT_PHDR, PT_TLS},
relocate::{Rela, RelocationSlices},
thread_local_storage::ThreadControlBlock,
},
linux::page_size,
syscall_debug_assert,
utils::round_up_to_boundary,
};
pub struct Ingredients;
pub struct Baked;
/// A struct representing a statically relocatable Position Independent Executable (PIE). 🥧
pub struct StaticPie<T> {
base_address: *const (),
relocation_slices: RelocationSlices,
tls_program_header: *const ProgramHeader,
pseudorandom_bytes: *const [u8; 16],
phantom_data: PhantomData<T>,
}
impl StaticPie<Ingredients> {
pub unsafe fn from_base(
base: *const (),
pseudorandom_bytes: *const [u8; 16],
) -> StaticPie<Ingredients> {
// ELf Header:
let header = &*(base as *const ElfHeader);
syscall_debug_assert!(header.e_type == ET_DYN);
syscall_debug_assert!(header.e_phentsize == size_of::<ProgramHeader>() as u16);
// Program Headers:
let program_header_table = slice::from_raw_parts(
base.byte_add(header.e_phoff) as *const ProgramHeader,
header.e_phnum as usize,
);
let (mut dynamic_program_header, mut tls_program_header) = (null(), null());
for header in program_header_table {
match header.p_type {
PT_DYNAMIC => dynamic_program_header = header,
PT_TLS => tls_program_header = header,
_ => (),
}
}
syscall_debug_assert!(dynamic_program_header != null());
Self::build(
base,
dynamic_program_header,
tls_program_header,
pseudorandom_bytes,
)
}
pub unsafe fn from_program_headers(
program_header_table: &'static [ProgramHeader],
pseudorandom_bytes: *const [u8; 16],
) -> StaticPie<Ingredients> {
let (mut base, mut dynamic_program_header, mut tls_program_header) =
(null(), null(), null());
for header in program_header_table {
match header.p_type {
PT_PHDR => {
base = program_header_table.as_ptr().byte_sub(header.p_vaddr) as *const ();
}
PT_DYNAMIC => dynamic_program_header = header,
PT_TLS => tls_program_header = header,
_ => (),
}
}
syscall_debug_assert!(dynamic_program_header != null());
Self::build(
base,
dynamic_program_header,
tls_program_header,
pseudorandom_bytes,
)
}
#[must_use]
unsafe fn build(
base: *const (),
dynamic_program_header: *const ProgramHeader,
tls_program_header: *const ProgramHeader,
pseudorandom_bytes: *const [u8; 16],
) -> StaticPie<Ingredients> {
// Dynamic Arrary:
let dynamic_array = DynamicArrayIter::new(
base.byte_add((*dynamic_program_header).p_vaddr) as *const DynamicArrayItem
);
syscall_debug_assert!(dynamic_array.clone().count() != 0);
let mut rela_pointer: *const Rela = null();
let mut rela_count = 0;
for item in dynamic_array {
match item.d_tag {
DT_RELA => {
rela_pointer = base.byte_add(item.d_un.d_ptr.addr()) as *const Rela;
}
DT_RELASZ => {
rela_count = item.d_un.d_val / core::mem::size_of::<Rela>();
}
#[cfg(debug_assertions)]
DT_RELAENT => {
syscall_debug_assert!(item.d_un.d_val as usize == size_of::<Rela>())
}
_ => (),
}
}
syscall_debug_assert!(rela_pointer != null());
let rela_slice = slice::from_raw_parts(rela_pointer, rela_count);
StaticPie::<Ingredients> {
base_address: base,
relocation_slices: RelocationSlices { rela_slice },
tls_program_header,
pseudorandom_bytes,
phantom_data: PhantomData,
}
}
}
impl StaticPie<Ingredients> {
#[must_use]
pub unsafe fn relocate(self) -> StaticPie<Baked> {
#[cfg(target_arch = "x86_64")]
for rela in self.relocation_slices.rela_slice {
let relocate_address = rela.r_offset.wrapping_add(self.base_address.addr());
// x86_64 assembly pointer widths:
// byte | 8 bits (1 byte)
// word | 16 bits (2 bytes)
// dword | 32 bits (4 bytes) | "double word"
// qword | 64 bits (8 bytes) | "quad word"
use crate::elf::relocate::{R_X86_64_IRELATIVE, R_X86_64_RELATIVE};
match rela.r_type() {
R_X86_64_RELATIVE => {
let relocate_value =
self.base_address.addr().wrapping_add_signed(rela.r_addend);
asm!(
"mov qword ptr [{}], {}",
in(reg) relocate_address,
in(reg) relocate_value,
options(nostack, preserves_flags),
);
}
R_X86_64_IRELATIVE => {
let function_pointer =
self.base_address.addr().wrapping_add_signed(rela.r_addend);
let function: extern "C" fn() -> usize = core::mem::transmute(function_pointer);
let relocate_value = function();
asm!(
"mov qword ptr [{}], {}",
in(reg) relocate_address,
in(reg) relocate_value,
options(nostack, preserves_flags),
);
}
_ => {
io::write(io::STD_ERR, "Unsupported Relocation");
exit::exit(3233);
}
}
}
StaticPie::<Baked> {
phantom_data: PhantomData::<Baked>,
..self
}
}
}
impl StaticPie<Baked> {
pub unsafe fn allocate_tls(self) {
// Static Thread Local Storage [before Thread Pointer]:
// ┌---------------------┐
// ┌----------------------------┐ <- | tls-offset[1] |
// | Static TLS Block | |---------------------|
// |----------------------------| <- | Thread Pointer (TP) |
// ┌--- | Thread Control Block (TCB) | └---------------------┘
// | └----------------------------┘
// |
// | ┌------------------┐
// └-> | Null Dtv Pointer |
// └------------------┘
// NOTE: I am not bothering with alignment at the first address because it's already page aligned...
if self.tls_program_header.is_null() {
return;
}
let tls_program_header = *self.tls_program_header;
let tls_blocks_size_and_align =
round_up_to_boundary(tls_program_header.p_memsz, tls_program_header.p_align);
let tcb_size = size_of::<ThreadControlBlock>();
let required_size = tls_blocks_size_and_align + tcb_size;
let tls_block_pointer = mmap(
null_mut(),
required_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, // file descriptor (-1 for anonymous mapping)
0, // offset
);
syscall_debug_assert!(tls_block_pointer.addr() % page_size::get_page_size() == 0);
// Initialize the TLS data from template image:
slice::from_raw_parts_mut(tls_block_pointer as *mut u8, tls_program_header.p_filesz)
.copy_from_slice(slice::from_raw_parts(
self.base_address.byte_add(tls_program_header.p_offset) as *mut u8,
tls_program_header.p_filesz,
));
// Zero out TLS data beyond `p_filesz`:
slice::from_raw_parts_mut(
tls_block_pointer.byte_add(tls_program_header.p_filesz) as *mut u8,
tls_program_header.p_memsz - tls_program_header.p_filesz,
)
.fill(0);
// Initialize the Thread Control Block (TCB):
let thread_control_block =
tls_block_pointer.byte_add(tls_blocks_size_and_align) as *mut ThreadControlBlock;
let thread_pointer_register: *mut () =
(*thread_control_block).thread_pointee.as_mut_ptr().cast();
*thread_control_block = ThreadControlBlock {
thread_pointee: [],
thread_pointer_register,
dynamic_thread_vector: null_mut(),
_padding: [0; 3],
canary: usize::from_ne_bytes(
(*self.pseudorandom_bytes)[..size_of::<usize>()]
.try_into()
.unwrap(),
),
};
// Make the thread pointer (which is fs on x86_64) point to the TCB:
set_thread_pointer(thread_pointer_register);
}
}
When debuging The segfault occurse like so:
Breakpoint 1, miros::rust_main (stack_pointer=0x7fffffffe7c0) at src/main.rs:87
87 miros.relocate().allocate_tls();
(gdb) x/15i $pc
=> 0x23800b <_ZN5miros9rust_main17hbf1c54ea22468c36E+1547>:
lea 0x1c8(%rsp),%rdi
0x238013 <_ZN5miros9rust_main17hbf1c54ea22468c36E+1555>:
lea 0x178(%rsp),%rsi
0x23801b <_ZN5miros9rust_main17hbf1c54ea22468c36E+1563>:
mov $0x28,%edx
0x238020 <_ZN5miros9rust_main17hbf1c54ea22468c36E+1568>:
call 0x2ec640
0x238025 <_ZN5miros9rust_main17hbf1c54ea22468c36E+1573>:
lea 0x1a0(%rsp),%rdi
0x23802d <_ZN5miros9rust_main17hbf1c54ea22468c36E+1581>:
lea 0x1c8(%rsp),%rsi
0x238035 <_ZN5miros9rust_main17hbf1c54ea22468c36E+1589>:
call 0x237000 <_ZN5miros10static_pie47StaticPie$LT$miros..static_pie..Ingredients$GT$8relocate17h8991c1b754563d5fE>
0x23803a <_ZN5miros9rust_main17hbf1c54ea22468c36E+1594>:
lea 0x1a0(%rsp),%rdi
0x238042 <_ZN5miros9rust_main17hbf1c54ea22468c36E+1602>:
call 0x237020 <_ZN5miros10static_pie41StaticPie$LT$miros..static_pie..Baked$GT$12allocate_tls17h6659d728bf640a30E>
0x238047 <_ZN5miros9rust_main17hbf1c54ea22468c36E+1607>:
--Type <RET> for more, q to quit, c to continue without paging--
lea 0x1f0(%rsp),%rdi
0x23804f <_ZN5miros9rust_main17hbf1c54ea22468c36E+1615>:
call 0x23a790 <_ZN5alloc3vec12Vec$LT$T$GT$3new17h4563aef74b1e7031E>
0x238054 <_ZN5miros9rust_main17hbf1c54ea22468c36E+1620>:
lea 0x1f0(%rsp),%rdi
0x23805c <_ZN5miros9rust_main17hbf1c54ea22468c36E+1628>:
lea -0x37713(%rip),%rsi # 0x200950
0x238063 <_ZN5miros9rust_main17hbf1c54ea22468c36E+1635>:
mov $0x5,%edx
0x238068 <_ZN5miros9rust_main17hbf1c54ea22468c36E+1640>:
lea 0xb58e9(%rip),%rcx # 0x2ed958
(gdb) si
0x0000000000238013 87 miros.relocate().allocate_tls();
(gdb) si
0x000000000023801b 87 miros.relocate().allocate_tls();
(gdb) si
0x0000000000238020 87 miros.relocate().allocate_tls();
(gdb) si
0x00000000002ec640 in ?? ()
from ./target/debug/miros
(gdb) x/15i $pc
=> 0x2ec640:
jmp *0x7f52(%rip) # 0x2f4598
0x2ec646: push $0x0
0x2ec64b: jmp 0x0
0x2ec650:
jmp *0x7f4a(%rip) # 0x2f45a0
0x2ec656: push $0x1
0x2ec65b: jmp 0x0
0x2ec660:
jmp *0x7f42(%rip) # 0x2f45a8
0x2ec666: push $0x2
0x2ec66b: jmp 0x0
0x2ec670:
jmp *0x7f3a(%rip) # 0x2f45b0
0x2ec676: push $0x3
0x2ec67b: jmp 0x0
0x2ec680:
jmp *0x7f32(%rip) # 0x2f45b8
0x2ec686: push $0x4
0x2ec68b: jmp 0x0
(gdb) si
0x0000000000000000 in ?? ()
(gdb) si
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
The table(?)/section which it jumps to and proceds to derefrence a null pointer seems to be this one:
Disassembly of section .iplt:
00000000002ec640 <.iplt>:
2ec640: ff 25 52 7f 00 00 jmp *0x7f52(%rip) # 2f4598 <_GLOBAL_OFFSET_TABLE_+0x18>
2ec646: 68 00 00 00 00 push $0x0
2ec64b: e9 b0 39 d1 ff jmp 0 <__evoke_link_warning_gethostbyname2_r>
2ec650: ff 25 4a 7f 00 00 jmp *0x7f4a(%rip) # 2f45a0 <_GLOBAL_OFFSET_TABLE_+0x20>
2ec656: 68 01 00 00 00 push $0x1
2ec65b: e9 a0 39 d1 ff jmp 0 <__evoke_link_warning_gethostbyname2_r>
2ec660: ff 25 42 7f 00 00 jmp *0x7f42(%rip) # 2f45a8 <_GLOBAL_OFFSET_TABLE_+0x28>
2ec666: 68 02 00 00 00 push $0x2
2ec66b: e9 90 39 d1 ff jmp 0 <__evoke_link_warning_gethostbyname2_r>
2ec670: ff 25 3a 7f 00 00 jmp *0x7f3a(%rip) # 2f45b0 <_GLOBAL_OFFSET_TABLE_+0x30>
2ec676: 68 03 00 00 00 push $0x3
2ec67b: e9 80 39 d1 ff jmp 0 <__evoke_link_warning_gethostbyname2_r>
2ec680: ff 25 32 7f 00 00 jmp *0x7f32(%rip) # 2f45b8 <_GLOBAL_OFFSET_TABLE_+0x38>
2ec686: 68 04 00 00 00 push $0x4
2ec68b: e9 70 39 d1 ff jmp 0 <__evoke_link_warning_gethostbyname2_r>
2ec690: ff 25 2a 7f 00 00 jmp *0x7f2a(%rip) # 2f45c0 <_GLOBAL_OFFSET_TABLE_+0x40>
2ec696: 68 05 00 00 00 push $0x5
2ec69b: e9 60 39 d1 ff jmp 0 <__evoke_link_warning_gethostbyname2_r>
2ec6a0: ff 25 22 7f 00 00 jmp *0x7f22(%rip) # 2f45c8 <_GLOBAL_OFFSET_TABLE_+0x48>
2ec6a6: 68 06 00 00 00 push $0x6
2ec6ab: e9 50 39 d1 ff jmp 0 <__evoke_link_warning_gethostbyname2_r>
2ec6b0: ff 25 1a 7f 00 00 jmp *0x7f1a(%rip) # 2f45d0 <_GLOBAL_OFFSET_TABLE_+0x50>
2ec6b6: 68 07 00 00 00 push $0x7
2ec6bb: e9 40 39 d1 ff jmp 0 <__evoke_link_warning_gethostbyname2_r>
2ec6c0: ff 25 12 7f 00 00 jmp *0x7f12(%rip) # 2f45d8 <_GLOBAL_OFFSET_TABLE_+0x58>
2ec6c6: 68 08 00 00 00 push $0x8
2ec6cb: e9 30 39 d1 ff jmp 0 <__evoke_link_warning_gethostbyname2_r>
2ec6d0: ff 25 0a 7f 00 00 jmp *0x7f0a(%rip) # 2f45e0 <_GLOBAL_OFFSET_TABLE_+0x60>
2ec6d6: 68 09 00 00 00 push $0x9
2ec6db: e9 20 39 d1 ff jmp 0 <__evoke_link_warning_gethostbyname2_r>
2ec6e0: ff 25 02 7f 00 00 jmp *0x7f02(%rip) # 2f45e8 <_GLOBAL_OFFSET_TABLE_+0x68>
2ec6e6: 68 0a 00 00 00 push $0xa
2ec6eb: e9 10 39 d1 ff jmp 0 <__evoke_link_warning_gethostbyname2_r>
I am compiling with this .cargo/config.toml
[build]
rustflags = ["-C", "target-feature=+crt-static", "-C", "link-arg=-nostartfiles"
]
and file shows this:
❯ file ./target/debug/miros 01/01/25
./target/debug/miros: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=7232f6a293119031a16474c11812750c8a1a6d9b, with debug_info, not stripped, too many notes (256)
and readelf shows this:
❯ readelf -d ./target/debug/miros 01/01/25
There is no dynamic section in this file.
❯ readelf -r ./target/debug/miros 02/01/25
Relocation section '.rela.dyn' at offset 0x298 contains 23 entries:
Offset Info Type Sym. Value Sym. Name + Addend
0000002f4598 000000000025 R_X86_64_IRELATIV 2a8a60
0000002f45a0 000000000025 R_X86_64_IRELATIV 2a9480
0000002f45a8 000000000025 R_X86_64_IRELATIV 2a9280
0000002f45b0 000000000025 R_X86_64_IRELATIV 2a89f0
0000002f45b8 000000000025 R_X86_64_IRELATIV 2a89f0
0000002f45c0 000000000025 R_X86_64_IRELATIV 2a98a0
0000002f45c8 000000000025 R_X86_64_IRELATIV 2a9380
0000002f45d0 000000000025 R_X86_64_IRELATIV 2a97d0
0000002f45d8 000000000025 R_X86_64_IRELATIV 2a9910
0000002f45e0 000000000025 R_X86_64_IRELATIV 2a9740
0000002f45e8 000000000025 R_X86_64_IRELATIV 2a9660
0000002f45f0 000000000025 R_X86_64_IRELATIV 2a96d0
0000002f45f8 000000000025 R_X86_64_IRELATIV 2aa3f0
0000002f4600 000000000025 R_X86_64_IRELATIV 2a9840
0000002f4608 000000000025 R_X86_64_IRELATIV 2a9570
0000002f4610 000000000025 R_X86_64_IRELATIV 2a99f0
0000002f4618 000000000025 R_X86_64_IRELATIV 2a8970
0000002f4620 000000000025 R_X86_64_IRELATIV 2a95e0
0000002f4628 000000000025 R_X86_64_IRELATIV 2a9a60
0000002f4630 000000000025 R_X86_64_IRELATIV 2aa4d0
0000002f4638 000000000025 R_X86_64_IRELATIV 2c3630
0000002f4640 000000000025 R_X86_64_IRELATIV 2c35c0
0000002f4648 000000000025 R_X86_64_IRELATIV 2c4c10
❯ readelf -e ./target/debug/miros 01/01/25
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x23a170
Start of program headers: 64 (bytes into file)
Start of section headers: 4847824 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 10
Size of section headers: 64 (bytes)
Number of section headers: 40
Section header string table index: 38
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .note.gnu.bu[...] NOTE 0000000000200270 00000270
0000000000000024 0000000000000000 A 0 0 4
[ 2] .rela.dyn RELA 0000000000200298 00000298
0000000000000228 0000000000000018 A 0 0 8
[ 3] .rodata PROGBITS 00000000002004c0 000004c0
0000000000020823 0000000000000000 AMS 0 0 32
[ 4] .gcc_except_table PROGBITS 0000000000220ce4 00020ce4
0000000000002e00 0000000000000000 A 0 0 4
[ 5] rodata.cst32 PROGBITS 0000000000223b00 00023b00
0000000000000060 0000000000000020 AM 0 0 32
[ 6] .eh_frame_hdr PROGBITS 0000000000223b60 00023b60
0000000000002f8c 0000000000000000 A 0 0 4
[ 7] .eh_frame PROGBITS 0000000000226af0 00026af0
000000000000e708 0000000000000000 A 0 0 8
[ 8] .text PROGBITS 0000000000236200 00035200
00000000000b6431 0000000000000000 AX 0 0 64
[ 9] .iplt PROGBITS 00000000002ec640 000eb640
0000000000000170 0000000000000000 AX 0 0 16
[10] .tdata PROGBITS 00000000002ed7b0 000eb7b0
0000000000000038 0000000000000000 WAT 0 0 8
[11] .tbss NOBITS 00000000002ed7e8 000eb7e8
0000000000000068 0000000000000000 WAT 0 0 8
[12] .data.rel.ro PROGBITS 00000000002ed800 000eb800
0000000000006558 0000000000000000 WA 0 0 32
[13] .init_array INIT_ARRAY 00000000002f3d58 000f1d58
0000000000000008 0000000000000000 WA 0 0 8
[14] .fini_array FINI_ARRAY 00000000002f3d60 000f1d60
0000000000000008 0000000000000008 WA 0 0 8
[15] .got PROGBITS 00000000002f3d68 000f1d68
0000000000000818 0000000000000000 WA 0 0 8
[16] .got.plt PROGBITS 00000000002f4580 000f2580
00000000000000d0 0000000000000000 WA 0 0 8
[17] .relro_padding NOBITS 00000000002f4650 000f2650
00000000000009b0 0000000000000000 WA 0 0 1
[18] .data PROGBITS 00000000002f5660 000f2660
0000000000001a5c 0000000000000000 WA 0 0 32
[19] .bss NOBITS 00000000002f70c0 000f40bc
00000000000052e8 0000000000000000 WA 0 0 32
[20] .debug_abbrev PROGBITS 0000000000000000 000f40bc
0000000000003e1d 0000000000000000 0 0 1
[21] .debug_info PROGBITS 0000000000000000 000f7ed9
0000000000109e41 0000000000000000 0 0 1
[22] .debug_aranges PROGBITS 0000000000000000 00201d1a
0000000000007aa0 0000000000000000 0 0 1
[23] .debug_ranges PROGBITS 0000000000000000 002097ba
00000000000aae60 0000000000000000 0 0 1
[24] .debug_str PROGBITS 0000000000000000 002b461a
0000000000155335 0000000000000001 MS 0 0 1
[25] .comment PROGBITS 0000000000000000 0040994f
00000000000000ef 0000000000000001 MS 0 0 1
[26] .debug_frame PROGBITS 0000000000000000 00409a40
0000000000000ab8 0000000000000000 0 0 8
[27] .debug_line PROGBITS 0000000000000000 0040a4f8
000000000006983f 0000000000000000 0 0 1
[28] .debug_loc PROGBITS 0000000000000000 00473d37
0000000000000280 0000000000000000 0 0 1
[29] .gnu.build.a[...] NOTE 0000000000000000 00473fb8
0000000000002274 0000000000000000 0 0 4
[30] .note.stapsdt NOTE 0000000000000000 0047622c
0000000000001994 0000000000000000 0 0 4
[31] .gnu.warning[...] PROGBITS 0000000000000000 00477bc0
0000000000000087 0000000000000000 0 0 32
[32] .gnu.warning[...] PROGBITS 0000000000000000 00477c60
000000000000008c 0000000000000000 0 0 32
[33] .gnu.warning[...] PROGBITS 0000000000000000 00477d00
0000000000000086 0000000000000000 0 0 32
[34] .gnu.warning[...] PROGBITS 0000000000000000 00477da0
000000000000008b 0000000000000000 0 0 32
[35] .gnu.warning[...] PROGBITS 0000000000000000 00477e40
0000000000000082 0000000000000000 0 0 32
[36] .gnu.warning[...] PROGBITS 0000000000000000 00477ee0
0000000000000083 0000000000000000 0 0 32
[37] .symtab SYMTAB 0000000000000000 00477f68
0000000000010d58 0000000000000018 39 2175 8
[38] .shstrtab STRTAB 0000000000000000 00488cc0
0000000000000205 0000000000000000 0 0 1
[39] .strtab STRTAB 0000000000000000 00488ec5
0000000000016a04 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), l (large), p (processor specific)
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000200040 0x0000000000200040
0x0000000000000230 0x0000000000000230 R 0x8
LOAD 0x0000000000000000 0x0000000000200000 0x0000000000200000
0x00000000000351f8 0x00000000000351f8 R 0x1000
LOAD 0x0000000000035200 0x0000000000236200 0x0000000000236200
0x00000000000b65b0 0x00000000000b65b0 R E 0x1000
LOAD 0x00000000000eb7b0 0x00000000002ed7b0 0x00000000002ed7b0
0x0000000000006ea0 0x0000000000007850 RW 0x1000
LOAD 0x00000000000f2660 0x00000000002f5660 0x00000000002f5660
0x0000000000001a5c 0x0000000000006d48 RW 0x1000
TLS 0x00000000000eb7b0 0x00000000002ed7b0 0x00000000002ed7b0
0x0000000000000038 0x00000000000000a0 R 0x8
GNU_RELRO 0x00000000000eb7b0 0x00000000002ed7b0 0x00000000002ed7b0
0x0000000000006ea0 0x0000000000007850 R 0x1
GNU_EH_FRAME 0x0000000000023b60 0x0000000000223b60 0x0000000000223b60
0x0000000000002f8c 0x0000000000002f8c R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x0
NOTE 0x0000000000000270 0x0000000000200270 0x0000000000200270
0x0000000000000024 0x0000000000000024 R 0x4
Section to Segment mapping:
Segment Sections...
00
01 .note.gnu.build-id .rela.dyn .rodata .gcc_except_table rodata.cst32 .eh_frame_hdr .eh_frame
02 .text .iplt
03 .tdata .data.rel.ro .init_array .fini_array .got .got.plt .relro_padding
04 .data .bss
05 .tdata .tbss
06 .tdata .data.rel.ro .init_array .fini_array .got .got.plt .relro_padding
07 .eh_frame_hdr
08
09 .note.gnu.build-id
I know what the problem is, this instruction in the .iplt section:
jmp *0x7f52(%rip) # 2f4598 <_GLOBAL_OFFSET_TABLE_+0x18>
It is dereferencing a yet to be preformed relocation. This one to be exact:
0000002f4598 000000000025 R_X86_64_IRELATIV 2a8a60
I tried using #[inline(always)]
but LLVM ignores that in debug mode... apparently it's just a suggestion.
Is there another way to avoid calls to the PLT while still using pretty functions, or do I just have to write C code in rust?
Thanks in advance for any help!