@@ -30,10 +30,19 @@ use crate::arch::{
3030 dynamic_table_addr, ehdr_addr, relocation_load, relocation_mprotect_readonly, relocation_store,
3131} ;
3232use core:: ffi:: c_void;
33+ use core:: mem;
3334use core:: ptr:: { null, null_mut, with_exposed_provenance} ;
3435use linux_raw_sys:: elf:: * ;
3536use linux_raw_sys:: general:: { AT_BASE , AT_ENTRY , AT_NULL , AT_PAGESZ } ;
3637
38+ // The Linux UAPI headers don't define the .relr types and consts yet.
39+ #[ allow( non_camel_case_types) ]
40+ type Elf_Relr = usize ;
41+
42+ const DT_RELRSZ : usize = 35 ;
43+ const DT_RELR : usize = 36 ;
44+ const DT_RELRENT : usize = 37 ;
45+
3746/// Locate the dynamic (startup-time) relocations and perform them.
3847///
3948/// This is unsafer than unsafe. It's meant to be called at a time when Rust
@@ -140,6 +149,12 @@ pub(super) unsafe fn relocate(envp: *mut *mut u8) {
140149 let mut rel_total_size = 0 ;
141150 let mut rel_entry_size = 0 ;
142151
152+ // Relr tables contain `Elf_Relr` elements which are a compact
153+ // way of representing relative relocations.
154+ let mut relr_ptr: * const Elf_Relr = null ( ) ;
155+ let mut relr_total_size = 0 ;
156+ let mut relr_entry_size = 0 ;
157+
143158 // Look through the `Elf_Dyn` entries to find the location and
144159 // size of the relocation table(s).
145160 let mut current_dyn: * const Elf_Dyn = dynv;
@@ -160,6 +175,12 @@ pub(super) unsafe fn relocate(envp: *mut *mut u8) {
160175 DT_RELSZ => rel_total_size = d_un. d_val as usize ,
161176 DT_RELENT => rel_entry_size = d_un. d_val as usize ,
162177
178+ // We found a relr table. As above, model this as
179+ // `with_exposed_provenance`.
180+ DT_RELR => relr_ptr = with_exposed_provenance ( d_un. d_ptr . wrapping_add ( offset) ) ,
181+ DT_RELRSZ => relr_total_size = d_un. d_val as usize ,
182+ DT_RELRENT => relr_entry_size = d_un. d_val as usize ,
183+
163184 // End of the Dynamic section
164185 DT_NULL => break ,
165186
@@ -209,6 +230,53 @@ pub(super) unsafe fn relocate(envp: *mut *mut u8) {
209230 }
210231 }
211232
233+ // Perform the relr relocations.
234+ let mut current_relr = relr_ptr;
235+ let relr_end = current_relr. byte_add ( relr_total_size) ;
236+ let mut reloc_addr = 0 ;
237+ while current_relr != relr_end {
238+ let mut entry = * current_relr;
239+ current_relr = current_relr. byte_add ( relr_entry_size) ;
240+
241+ if entry & 1 == 0 {
242+ // Entry encodes offset to relocate; calculate the location
243+ // the relocation will apply at.
244+ reloc_addr = offset + entry;
245+
246+ // Perform the relr relocation.
247+ let addend = relocation_load ( reloc_addr) ;
248+ let reloc_value = addend. wrapping_add ( offset) ;
249+ relocation_store ( reloc_addr, reloc_value) ;
250+
251+ // Advance relocation location.
252+ reloc_addr += mem:: size_of :: < usize > ( ) ;
253+ } else {
254+ // Entry encodes bitmask with locations to relocate; apply each entry.
255+
256+ let mut i = 0 ;
257+ loop {
258+ // Shift to next item in the bitmask.
259+ entry >>= 1 ;
260+ if entry == 0 {
261+ // No more entries left in the bitmask; early exit.
262+ break ;
263+ }
264+
265+ if entry & 1 != 0 {
266+ // Perform the relr relocation.
267+ let addend = relocation_load ( reloc_addr + i * mem:: size_of :: < usize > ( ) ) ;
268+ let reloc_value = addend. wrapping_add ( offset) ;
269+ relocation_store ( reloc_addr + i * mem:: size_of :: < usize > ( ) , reloc_value) ;
270+ }
271+
272+ i += 1 ;
273+ }
274+
275+ // Advance relocation location.
276+ reloc_addr += ( mem:: size_of :: < usize > ( ) * 8 - 1 ) * mem:: size_of :: < usize > ( ) ;
277+ }
278+ }
279+
212280 // FIXME split function into two here with a hint::black_box around the
213281 // function pointer to prevent the compiler from moving code between the
214282 // functions.
0 commit comments