|
| 1 | +//! AArch64 Memory tagging intrinsics |
| 2 | +//! |
| 3 | +//! [ACLE documentation](https://arm-software.github.io/acle/main/acle.html#markdown-toc-mte-intrinsics) |
| 4 | +
|
| 5 | +extern "unadjusted" { |
| 6 | + #[cfg_attr( |
| 7 | + any(target_arch = "aarch64", target_arch = "arm64ec"), |
| 8 | + link_name = "llvm.aarch64.irg" |
| 9 | + )] |
| 10 | + fn irg_(ptr: *const (), exclude: i64) -> *const (); |
| 11 | + #[cfg_attr( |
| 12 | + any(target_arch = "aarch64", target_arch = "arm64ec"), |
| 13 | + link_name = "llvm.aarch64.gmi" |
| 14 | + )] |
| 15 | + fn gmi_(ptr: *const (), exclude: i64) -> i64; |
| 16 | + #[cfg_attr( |
| 17 | + any(target_arch = "aarch64", target_arch = "arm64ec"), |
| 18 | + link_name = "llvm.aarch64.ldg" |
| 19 | + )] |
| 20 | + fn ldg_(ptr: *const (), tag_ptr: *const ()) -> *const (); |
| 21 | + #[cfg_attr( |
| 22 | + any(target_arch = "aarch64", target_arch = "arm64ec"), |
| 23 | + link_name = "llvm.aarch64.stg" |
| 24 | + )] |
| 25 | + fn stg_(tagged_ptr: *const (), addr_to_tag: *const ()); |
| 26 | + #[cfg_attr( |
| 27 | + any(target_arch = "aarch64", target_arch = "arm64ec"), |
| 28 | + link_name = "llvm.aarch64.addg" |
| 29 | + )] |
| 30 | + fn addg_(ptr: *const (), value: i64) -> *const (); |
| 31 | + #[cfg_attr( |
| 32 | + any(target_arch = "aarch64", target_arch = "arm64ec"), |
| 33 | + link_name = "llvm.aarch64.subp" |
| 34 | + )] |
| 35 | + fn subp_(ptr_a: *const (), ptr_b: *const ()) -> i64; |
| 36 | +} |
| 37 | + |
| 38 | +/// Return a pointer containing a randomly generated logical address tag. |
| 39 | +/// |
| 40 | +/// `src`: A pointer containing an address. |
| 41 | +/// `mask`: A mask where each of the lower 16 bits specifies logical |
| 42 | +/// tags which must be excluded from consideration. Zero excludes no |
| 43 | +/// tags. |
| 44 | +/// |
| 45 | +/// The returned pointer contains a copy of the `src` address, but with a |
| 46 | +/// randomly generated logical tag, excluding any specified by `mask`. |
| 47 | +/// |
| 48 | +/// SAFETY: The pointer provided by this intrinsic will be invalid until the memory |
| 49 | +/// has been appropriately tagged with `__arm_mte_set_tag`. If using that intrinsic |
| 50 | +/// on the provided pointer is itself invalid, then it will be permanently invalid |
| 51 | +/// and Undefined Behavior to dereference it. |
| 52 | +#[inline] |
| 53 | +#[target_feature(enable = "mte")] |
| 54 | +#[unstable(feature = "stdarch_aarch64_mte", issue = "129010")] |
| 55 | +pub unsafe fn __arm_mte_create_random_tag<T>(src: *const T, mask: u64) -> *const T { |
| 56 | + irg_(src as *const (), mask as i64) as *const T |
| 57 | +} |
| 58 | + |
| 59 | +/// Return a pointer with the logical address tag offset by a value. |
| 60 | +/// |
| 61 | +/// `src`: A pointer containing an address and a logical tag. |
| 62 | +/// `OFFSET`: A compile-time constant value in the range [0, 15]. |
| 63 | +/// |
| 64 | +/// Adds offset to the logical address tag in `src`, wrapping if the result is |
| 65 | +/// outside of the valid 16 tags. |
| 66 | +/// |
| 67 | +/// SAFETY: See `__arm_mte_create_random_tag`. |
| 68 | +#[inline] |
| 69 | +#[target_feature(enable = "mte")] |
| 70 | +#[unstable(feature = "stdarch_aarch64_mte", issue = "129010")] |
| 71 | +pub unsafe fn __arm_mte_increment_tag<const OFFSET: i64, T>(src: *const T) -> *const T { |
| 72 | + addg_(src as *const (), OFFSET) as *const T |
| 73 | +} |
| 74 | + |
| 75 | +/// Add a logical tag to the set of excluded logical tags. |
| 76 | +/// |
| 77 | +/// `src`: A pointer containing an address and a logical tag. |
| 78 | +/// `excluded`: A mask where the lower 16 bits each specify currently-excluded |
| 79 | +/// logical tags. |
| 80 | +/// |
| 81 | +/// Adds the logical tag stored in `src` to the set in `excluded`, and returns |
| 82 | +/// the result. |
| 83 | +#[inline] |
| 84 | +#[target_feature(enable = "mte")] |
| 85 | +#[unstable(feature = "stdarch_aarch64_mte", issue = "129010")] |
| 86 | +pub unsafe fn __arm_mte_exclude_tag<T>(src: *const T, excluded: u64) -> u64 { |
| 87 | + gmi_(src as *const (), excluded as i64) as u64 |
| 88 | +} |
| 89 | + |
| 90 | +/// Store an allocation tag for the 16-byte granule of memory. |
| 91 | +/// |
| 92 | +/// `tag_address`: A pointer containing an address and a logical tag, which |
| 93 | +/// must be 16-byte aligned. |
| 94 | +/// |
| 95 | +/// SAFETY: `tag_address` must be 16-byte aligned. The tag will apply to the |
| 96 | +/// entire 16-byte memory granule. |
| 97 | +#[inline] |
| 98 | +#[target_feature(enable = "mte")] |
| 99 | +#[unstable(feature = "stdarch_aarch64_mte", issue = "129010")] |
| 100 | +pub unsafe fn __arm_mte_set_tag<T>(tag_address: *const T) { |
| 101 | + stg_(tag_address as *const (), tag_address as *const ()); |
| 102 | +} |
| 103 | + |
| 104 | +/// Load an allocation tag from memory, returning a new pointer with the |
| 105 | +/// corresponding logical tag. |
| 106 | +/// |
| 107 | +/// `address`: A pointer containing an address from which allocation tag memory |
| 108 | +/// is read. This does not need to be 16-byte aligned. |
| 109 | +#[inline] |
| 110 | +#[target_feature(enable = "mte")] |
| 111 | +#[unstable(feature = "stdarch_aarch64_mte", issue = "129010")] |
| 112 | +pub unsafe fn __arm_mte_get_tag<T>(address: *const T) -> *const T { |
| 113 | + ldg_(address as *const (), address as *const ()) as *const T |
| 114 | +} |
| 115 | + |
| 116 | +/// Calculate the difference between the address parts of two pointers, ignoring |
| 117 | +/// the tags, and sign-extending the result. |
| 118 | +#[inline] |
| 119 | +#[target_feature(enable = "mte")] |
| 120 | +#[unstable(feature = "stdarch_aarch64_mte", issue = "129010")] |
| 121 | +pub unsafe fn __arm_mte_ptrdiff<T, U>(a: *const T, b: *const U) -> i64 { |
| 122 | + subp_(a as *const (), b as *const ()) |
| 123 | +} |
| 124 | + |
| 125 | +#[cfg(test)] |
| 126 | +mod test { |
| 127 | + use super::*; |
| 128 | + use stdarch_test::assert_instr; |
| 129 | + |
| 130 | + #[cfg_attr(test, assert_instr(irg))] |
| 131 | + #[allow(dead_code)] |
| 132 | + #[target_feature(enable = "mte")] |
| 133 | + pub unsafe fn __test_create_random_tag(src: *const (), mask: u64) -> *const () { |
| 134 | + __arm_mte_create_random_tag(src, mask) |
| 135 | + } |
| 136 | + |
| 137 | + #[cfg_attr(test, assert_instr(addg))] |
| 138 | + #[allow(dead_code)] |
| 139 | + #[target_feature(enable = "mte")] |
| 140 | + pub unsafe fn __test_increment_tag(src: *const ()) -> *const () { |
| 141 | + __arm_mte_increment_tag::<1, _>(src) |
| 142 | + } |
| 143 | + |
| 144 | + #[cfg_attr(test, assert_instr(gmi))] |
| 145 | + #[allow(dead_code)] |
| 146 | + #[target_feature(enable = "mte")] |
| 147 | + pub unsafe fn __test_exclude_tag(src: *const (), excluded: u64) -> u64 { |
| 148 | + __arm_mte_exclude_tag(src, excluded) |
| 149 | + } |
| 150 | + |
| 151 | + #[cfg_attr(test, assert_instr(stg))] |
| 152 | + #[allow(dead_code)] |
| 153 | + #[target_feature(enable = "mte")] |
| 154 | + pub unsafe fn __test_set_tag(src: *const ()) { |
| 155 | + __arm_mte_set_tag(src) |
| 156 | + } |
| 157 | + |
| 158 | + #[cfg_attr(test, assert_instr(ldg))] |
| 159 | + #[allow(dead_code)] |
| 160 | + #[target_feature(enable = "mte")] |
| 161 | + pub unsafe fn __test_get_tag(src: *const ()) -> *const () { |
| 162 | + __arm_mte_get_tag(src) |
| 163 | + } |
| 164 | + |
| 165 | + #[cfg_attr(test, assert_instr(subp))] |
| 166 | + #[allow(dead_code)] |
| 167 | + #[target_feature(enable = "mte")] |
| 168 | + pub unsafe fn __test_ptrdiff(a: *const (), b: *const ()) -> i64 { |
| 169 | + __arm_mte_ptrdiff(a, b) |
| 170 | + } |
| 171 | +} |
0 commit comments