1 use core::arch::asm; 2 3 // Do not remove inline: will result in relocation failure 4 #[inline(always)] 5 pub(crate) unsafe fn rel_ptr<T>(offset: u64) -> *const T { 6 (image_base() + offset) as *const T 7 } 8 9 // Do not remove inline: will result in relocation failure 10 #[inline(always)] 11 pub(crate) unsafe fn rel_ptr_mut<T>(offset: u64) -> *mut T { 12 (image_base() + offset) as *mut T 13 } 14 15 extern "C" { 16 static ENCLAVE_SIZE: usize; 17 static HEAP_BASE: u64; 18 static HEAP_SIZE: usize; 19 } 20 21 /// Returns the base memory address of the heap 22 pub(crate) fn heap_base() -> *const u8 { 23 unsafe { rel_ptr_mut(HEAP_BASE) } 24 } 25 26 /// Returns the size of the heap 27 pub(crate) fn heap_size() -> usize { 28 unsafe { HEAP_SIZE } 29 } 30 31 // Do not remove inline: will result in relocation failure 32 // For the same reason we use inline ASM here instead of an extern static to 33 // locate the base 34 /// Returns address at which current enclave is loaded. 35 #[inline(always)] 36 pub fn image_base() -> u64 { 37 let base: u64; 38 unsafe { 39 asm!( 40 "lea IMAGE_BASE(%rip), {}", 41 lateout(reg) base, 42 options(att_syntax, nostack, preserves_flags, nomem, pure), 43 ) 44 }; 45 base 46 } 47 48 /// Returns `true` if the specified memory range is in the enclave. 49 /// 50 /// For safety, this function also checks whether the range given overflows, 51 /// returning `false` if so. 52 pub fn is_enclave_range(p: *const u8, len: usize) -> bool { 53 let start = p as usize; 54 55 // Subtract one from `len` when calculating `end` in case `p + len` is 56 // exactly at the end of addressable memory (`p + len` would overflow, but 57 // the range is still valid). 58 let end = if len == 0 { 59 start 60 } else if let Some(end) = start.checked_add(len - 1) { 61 end 62 } else { 63 return false; 64 }; 65 66 let base = image_base() as usize; 67 start >= base && end <= base + (unsafe { ENCLAVE_SIZE } - 1) // unsafe ok: link-time constant 68 } 69 70 /// Returns `true` if the specified memory range is in userspace. 71 /// 72 /// For safety, this function also checks whether the range given overflows, 73 /// returning `false` if so. 74 pub fn is_user_range(p: *const u8, len: usize) -> bool { 75 let start = p as usize; 76 77 // Subtract one from `len` when calculating `end` in case `p + len` is 78 // exactly at the end of addressable memory (`p + len` would overflow, but 79 // the range is still valid). 80 let end = if len == 0 { 81 start 82 } else if let Some(end) = start.checked_add(len - 1) { 83 end 84 } else { 85 return false; 86 }; 87 88 let base = image_base() as usize; 89 end < base || start > base + (unsafe { ENCLAVE_SIZE } - 1) // unsafe ok: link-time constant 90 } 91