@@ -7051,6 +7051,104 @@ fn linker_run_icf_safe_keeps_address_taken_functions_distinct() { |
| 7051 | 7051 | let _ = fs::remove_file(our_out); |
| 7052 | 7052 | } |
| 7053 | 7053 | |
| 7054 | +#[test] |
| 7055 | +fn linker_run_icf_safe_keeps_adrp_add_address_taken_functions_distinct() { |
| 7056 | + if !have_xcrun() { |
| 7057 | + eprintln!("skipping: xcrun unavailable"); |
| 7058 | + return; |
| 7059 | + }; |
| 7060 | + |
| 7061 | + let obj = scratch("icf-adrp-address-taken.o"); |
| 7062 | + let baseline_out = scratch("icf-adrp-address-taken-baseline.out"); |
| 7063 | + let our_out = scratch("icf-adrp-address-taken-ours.out"); |
| 7064 | + let src = r#" |
| 7065 | + .section __TEXT,__text,regular,pure_instructions |
| 7066 | + .globl _main |
| 7067 | + _main: |
| 7068 | + stp x29, x30, [sp, #-16]! |
| 7069 | + mov x29, sp |
| 7070 | + adrp x10, _helper1@PAGE |
| 7071 | + add x10, x10, _helper1@PAGEOFF |
| 7072 | + adrp x11, _helper2@PAGE |
| 7073 | + add x11, x11, _helper2@PAGEOFF |
| 7074 | + cmp x10, x11 |
| 7075 | + b.ne 1f |
| 7076 | + mov w0, #1 |
| 7077 | + ldp x29, x30, [sp], #16 |
| 7078 | + ret |
| 7079 | + 1: |
| 7080 | + mov w0, #0 |
| 7081 | + ldp x29, x30, [sp], #16 |
| 7082 | + ret |
| 7083 | + |
| 7084 | + .private_extern _helper1 |
| 7085 | + _helper1: |
| 7086 | + mov w0, #7 |
| 7087 | + ret |
| 7088 | + |
| 7089 | + .private_extern _helper2 |
| 7090 | + _helper2: |
| 7091 | + mov w0, #7 |
| 7092 | + ret |
| 7093 | + .subsections_via_symbols |
| 7094 | + "#; |
| 7095 | + if let Err(e) = assemble(src, &obj) { |
| 7096 | + eprintln!("skipping: assemble failed: {e}"); |
| 7097 | + return; |
| 7098 | + } |
| 7099 | + |
| 7100 | + let baseline_opts = LinkOptions { |
| 7101 | + inputs: vec![obj.clone()], |
| 7102 | + output: Some(baseline_out.clone()), |
| 7103 | + kind: OutputKind::Executable, |
| 7104 | + ..LinkOptions::default() |
| 7105 | + }; |
| 7106 | + Linker::run(&baseline_opts).unwrap(); |
| 7107 | + |
| 7108 | + let opts = LinkOptions { |
| 7109 | + inputs: vec![obj.clone()], |
| 7110 | + output: Some(our_out.clone()), |
| 7111 | + kind: OutputKind::Executable, |
| 7112 | + icf_mode: afs_ld::IcfMode::Safe, |
| 7113 | + ..LinkOptions::default() |
| 7114 | + }; |
| 7115 | + Linker::run(&opts).unwrap(); |
| 7116 | + |
| 7117 | + let baseline_bytes = fs::read(&baseline_out).unwrap(); |
| 7118 | + let our_bytes = fs::read(&our_out).unwrap(); |
| 7119 | + let baseline_symbols = symbol_values(&baseline_bytes); |
| 7120 | + let our_symbols = symbol_values(&our_bytes); |
| 7121 | + let baseline_text = output_section(&baseline_bytes, "__TEXT", "__text") |
| 7122 | + .unwrap() |
| 7123 | + .1; |
| 7124 | + let our_text = output_section(&our_bytes, "__TEXT", "__text").unwrap().1; |
| 7125 | + |
| 7126 | + assert_ne!( |
| 7127 | + our_symbols.get("_helper1"), |
| 7128 | + our_symbols.get("_helper2"), |
| 7129 | + "adrp/add address-taken helpers should not be folded by afs-ld -icf=safe" |
| 7130 | + ); |
| 7131 | + assert_ne!( |
| 7132 | + baseline_symbols.get("_helper1"), |
| 7133 | + baseline_symbols.get("_helper2"), |
| 7134 | + "baseline link should keep adrp/add address-taken helpers separate" |
| 7135 | + ); |
| 7136 | + assert_eq!( |
| 7137 | + Command::new(&our_out).status().unwrap().code(), |
| 7138 | + Some(0), |
| 7139 | + "adrp/add address-taken executable should preserve pointer inequality" |
| 7140 | + ); |
| 7141 | + assert_eq!( |
| 7142 | + our_text.len(), |
| 7143 | + baseline_text.len(), |
| 7144 | + "adrp/add address-taken helpers should not shrink under -icf=safe" |
| 7145 | + ); |
| 7146 | + |
| 7147 | + let _ = fs::remove_file(obj); |
| 7148 | + let _ = fs::remove_file(baseline_out); |
| 7149 | + let _ = fs::remove_file(our_out); |
| 7150 | +} |
| 7151 | + |
| 7054 | 7152 | #[test] |
| 7055 | 7153 | fn linker_run_icf_safe_folds_matching_branch_relocs() { |
| 7056 | 7154 | if !have_xcrun() { |