Rust · 13573 bytes Raw Blame History
1 #[allow(dead_code)]
2 #[path = "common/corpus.rs"]
3 mod common;
4
5 use std::fmt::Write as _;
6 use std::fs;
7 use std::path::PathBuf;
8 use std::sync::atomic::{AtomicU64, Ordering};
9
10 static COUNTER: AtomicU64 = AtomicU64::new(0);
11
12 struct StressPaths {
13 root: PathBuf,
14 asm: PathBuf,
15 ours_obj: PathBuf,
16 ref_obj: PathBuf,
17 support_obj: PathBuf,
18 ours_linked: PathBuf,
19 ref_linked: PathBuf,
20 }
21
22 impl StressPaths {
23 fn new(prefix: &str) -> Self {
24 let id = COUNTER.fetch_add(1, Ordering::Relaxed);
25 let root = std::env::temp_dir().join(format!("{}_{}_{}", prefix, std::process::id(), id));
26 fs::create_dir_all(&root).expect("create temp root");
27 Self {
28 asm: root.join("input.s"),
29 ours_obj: root.join("ours.o"),
30 ref_obj: root.join("ref.o"),
31 support_obj: root.join("support.o"),
32 ours_linked: root.join("ours-linked.o"),
33 ref_linked: root.join("ref-linked.o"),
34 root,
35 }
36 }
37 }
38
39 struct Rng(u64);
40
41 impl Rng {
42 fn new(seed: u64) -> Self {
43 Self(seed ^ 0xD1B5_4A32_D192_ED03)
44 }
45
46 fn next_u32(&mut self) -> u32 {
47 self.0 ^= self.0 << 13;
48 self.0 ^= self.0 >> 7;
49 self.0 ^= self.0 << 17;
50 self.0 as u32
51 }
52
53 fn bounded(&mut self, upper: u32) -> u32 {
54 self.next_u32() % upper
55 }
56 }
57
58 fn normalize_tool_output(text: &str) -> String {
59 text.lines()
60 .filter(|line| !line.trim_end().ends_with(".o:") && !line.trim_end().ends_with(":"))
61 .map(str::trim_end)
62 .filter(|line| !line.is_empty())
63 .collect::<Vec<_>>()
64 .join("\n")
65 }
66
67 fn generate_metadata_heavy_case(seed: u64) -> String {
68 let mut rng = Rng::new(seed);
69 let mut src = String::new();
70 let common_value = 9 + rng.bounded(11) as u64;
71 let hidden_value = 2 + rng.bounded(5) as u64;
72 let local_value = 6 + rng.bounded(7) as u64;
73 let tls_init = 3 + rng.bounded(9) as u64;
74 let addend = 4 * (1 + rng.bounded(3) as i64);
75
76 let _ = writeln!(src, ".build_version macos, 11, 0 sdk_version 15, 5");
77 let _ = writeln!(src, ".subsections_via_symbols");
78 let _ = writeln!(src, ".globl _meta_{}", seed);
79 let _ = writeln!(src, ".private_extern _hidden_{}", seed);
80 let _ = writeln!(src, ".weak_definition _local_{}", seed);
81 let _ = writeln!(src, ".weak_reference _weak_ext");
82 let _ = writeln!(src, ".comm _common_{}, 8, 3", seed);
83 let _ = writeln!(src, ".section __TEXT,__text,regular,pure_instructions");
84 let _ = writeln!(src, ".p2align 2");
85 let _ = writeln!(src, "_meta_{}:", seed);
86 let _ = writeln!(src, "LlohP0_{}:", seed);
87 let _ = writeln!(src, " adrp x0, msg_{}@PAGE", seed);
88 let _ = writeln!(src, "LlohP1_{}:", seed);
89 let _ = writeln!(src, " add x0, x0, msg_{}@PAGEOFF", seed);
90 let _ = writeln!(src, "LlohG0_{}:", seed);
91 let _ = writeln!(src, " adrp x8, _ext@GOTPAGE");
92 let _ = writeln!(src, "LlohG1_{}:", seed);
93 let _ = writeln!(src, " ldr x8, [x8, _ext@GOTPAGEOFF]");
94 let _ = writeln!(src, " bl _puts");
95 let _ = writeln!(src, " bl _hidden_{}", seed);
96 let _ = writeln!(src, " mov x19, x0");
97 let _ = writeln!(src, " bl _local_{}", seed);
98 let _ = writeln!(src, " add x19, x19, x0");
99 let _ = writeln!(src, " bl _weak_ext");
100 let _ = writeln!(src, " adrp x9, _common_{}@PAGE", seed);
101 let _ = writeln!(src, " add x9, x9, _common_{}@PAGEOFF", seed);
102 let _ = writeln!(src, " mov x10, #{}", common_value);
103 let _ = writeln!(src, " str x10, [x9]");
104 let _ = writeln!(src, " ldr x10, [x9]");
105 let _ = writeln!(src, " add x19, x19, x10");
106 let _ = writeln!(src, " adrp x11, _tls_value_{}@TLVPPAGE", seed);
107 let _ = writeln!(src, " ldr x11, [x11, _tls_value_{}@TLVPPAGEOFF]", seed);
108 let _ = writeln!(src, " ldr x12, [x11]");
109 let _ = writeln!(src, " blr x12");
110 let _ = writeln!(src, " ldr x13, [x11]");
111 let _ = writeln!(src, " add x0, x19, x13");
112 let _ = writeln!(src, " ret");
113 let _ = writeln!(src, ".loh AdrpAdd LlohP0_{}, LlohP1_{}", seed, seed);
114 let _ = writeln!(src, ".loh AdrpLdrGot LlohG0_{}, LlohG1_{}", seed, seed);
115 let _ = writeln!(src);
116 let _ = writeln!(src, ".p2align 2");
117 let _ = writeln!(src, "_hidden_{}:", seed);
118 let _ = writeln!(src, " mov x0, #{}", hidden_value);
119 let _ = writeln!(src, " ret");
120 let _ = writeln!(src);
121 let _ = writeln!(src, ".p2align 2");
122 let _ = writeln!(src, "_local_{}:", seed);
123 let _ = writeln!(src, " mov x0, #{}", local_value);
124 let _ = writeln!(src, " ret");
125 let _ = writeln!(src);
126 let _ = writeln!(src, ".section __TEXT,__cstring,cstring_literals");
127 let _ = writeln!(src, "msg_{}:", seed);
128 let _ = writeln!(
129 src,
130 " .asciz \"meta-stress-{}-{:08x}\"",
131 seed,
132 rng.next_u32()
133 );
134 let _ = writeln!(src);
135 let _ = writeln!(src, ".section __TEXT,__const");
136 let _ = writeln!(src, ".p2align 3");
137 let _ = writeln!(src, "meta_const0_{}:", seed);
138 let _ = writeln!(src, " .quad msg_{}", seed);
139 let _ = writeln!(src, "meta_const1_{}:", seed);
140 let _ = writeln!(src, " .quad _other - _ext + {}", addend);
141 let _ = writeln!(src, "meta_const2_{}:", seed);
142 let _ = writeln!(src, " .quad _puts@GOT");
143 let _ = writeln!(src);
144 let _ = writeln!(src, ".data");
145 let _ = writeln!(src, ".p2align 3");
146 let _ = writeln!(src, "meta_data0_{}:", seed);
147 let _ = writeln!(src, " .quad meta_const0_{}", seed);
148 let _ = writeln!(src, "meta_data1_{}:", seed);
149 let _ = writeln!(src, " .quad _common_{}", seed);
150 let _ = writeln!(src, "meta_data2_{}:", seed);
151 let _ = writeln!(src, " .quad _weak_ext");
152 let _ = writeln!(src);
153 let _ = writeln!(src, ".zerofill __DATA,__bss,_scratch_{},16,4", seed);
154 let _ = writeln!(src);
155 let _ = writeln!(src, ".section __DATA,__thread_data,thread_local_regular");
156 let _ = writeln!(src, "_tls_value_{}$tlv$init:", seed);
157 let _ = writeln!(src, " .quad {}", tls_init);
158 let _ = writeln!(src);
159 let _ = writeln!(
160 src,
161 ".zerofill __DATA,__thread_bss,_tls_bss_{}$tlv$init,8,3",
162 seed
163 );
164 let _ = writeln!(src);
165 let _ = writeln!(src, ".section __DATA,__thread_vars,thread_local_variables");
166 let _ = writeln!(src, ".globl _tls_value_{}", seed);
167 let _ = writeln!(src, "_tls_value_{}:", seed);
168 let _ = writeln!(src, " .quad __tlv_bootstrap");
169 let _ = writeln!(src, " .quad 0");
170 let _ = writeln!(src, " .quad _tls_value_{}$tlv$init", seed);
171 let _ = writeln!(src, ".globl _tls_bss_{}", seed);
172 let _ = writeln!(src, "_tls_bss_{}:", seed);
173 let _ = writeln!(src, " .quad __tlv_bootstrap");
174 let _ = writeln!(src, " .quad 0");
175 let _ = writeln!(src, " .quad _tls_bss_{}$tlv$init", seed);
176
177 src
178 }
179
180 fn generate_section_switch_case(seed: u64) -> String {
181 let mut rng = Rng::new(seed ^ 0xF00D_BAAD);
182 let mut src = String::new();
183 let addend = 4 * (1 + rng.bounded(4) as i64);
184 let cstring_count = 2 + rng.bounded(2) as usize;
185
186 let _ = writeln!(src, ".build_version macos, 11, 0 sdk_version 15, 5");
187 let _ = writeln!(src, ".subsections_via_symbols");
188 let _ = writeln!(src, ".section __TEXT,__text,regular,pure_instructions");
189 let _ = writeln!(src, ".globl _switch_{}", seed);
190 let _ = writeln!(src, ".p2align 2");
191 let _ = writeln!(src, "_switch_{}:", seed);
192 let _ = writeln!(src, " adrp x0, cstr0_{}@PAGE", seed);
193 let _ = writeln!(src, " add x0, x0, cstr0_{}@PAGEOFF", seed);
194 let _ = writeln!(src, " adrp x1, switch_data0_{}@PAGE", seed);
195 let _ = writeln!(src, " add x1, x1, switch_data0_{}@PAGEOFF", seed);
196 let _ = writeln!(src, " adrp x2, switch_lit0_{}@PAGE", seed);
197 let _ = writeln!(src, " add x2, x2, switch_lit0_{}@PAGEOFF", seed);
198 let _ = writeln!(src, " ldr x3, [x1]");
199 let _ = writeln!(src, " ldr x4, [x2]");
200 let _ = writeln!(src, " add x0, x3, x4");
201 let _ = writeln!(src, " ret");
202 let _ = writeln!(src);
203
204 let _ = writeln!(src, ".section __TEXT,__cstring,cstring_literals");
205 for index in 0..cstring_count {
206 let _ = writeln!(src, "cstr{}_{}:", index, seed);
207 let _ = writeln!(
208 src,
209 " .asciz \"switch-{}-{}-{:08x}\"",
210 seed,
211 index,
212 rng.next_u32()
213 );
214 }
215 let _ = writeln!(src);
216
217 let _ = writeln!(src, ".data");
218 let _ = writeln!(src, ".p2align 3");
219 let _ = writeln!(src, "switch_data0_{}:", seed);
220 let _ = writeln!(src, " .quad cstr0_{}", seed);
221 let _ = writeln!(src, "switch_data1_{}:", seed);
222 let _ = writeln!(src, " .quad switch_const0_{}", seed);
223 let _ = writeln!(src);
224
225 let _ = writeln!(src, ".section __TEXT,__const");
226 let _ = writeln!(src, ".p2align 3");
227 let _ = writeln!(src, "switch_const0_{}:", seed);
228 let _ = writeln!(src, " .quad switch_data0_{}", seed);
229 let _ = writeln!(src, "switch_const1_{}:", seed);
230 let _ = writeln!(src, " .quad _other - _ext + {}", addend);
231 let _ = writeln!(src, "switch_const2_{}:", seed);
232 let _ = writeln!(src, " .quad _puts@GOT");
233 let _ = writeln!(src);
234
235 let _ = writeln!(src, ".section __TEXT,__literal16,16byte_literals");
236 let _ = writeln!(src, ".p2align 4");
237 let _ = writeln!(src, "switch_lit0_{}:", seed);
238 let _ = writeln!(src, " .quad switch_const0_{}", seed);
239 let _ = writeln!(src, " .quad switch_data1_{}", seed);
240 let _ = writeln!(src);
241
242 let _ = writeln!(src, ".zerofill __DATA,__bss,_switch_bss_{},24,4", seed);
243 let _ = writeln!(src);
244
245 let _ = writeln!(src, ".section __DATA,__thread_data,thread_local_regular");
246 let _ = writeln!(src, "_switch_tls_{}$tlv$init:", seed);
247 let _ = writeln!(src, " .quad {}", 1 + rng.bounded(9));
248 let _ = writeln!(src);
249
250 let _ = writeln!(src, ".section __DATA,__thread_vars,thread_local_variables");
251 let _ = writeln!(src, ".globl _switch_tls_{}", seed);
252 let _ = writeln!(src, "_switch_tls_{}:", seed);
253 let _ = writeln!(src, " .quad __tlv_bootstrap");
254 let _ = writeln!(src, " .quad 0");
255 let _ = writeln!(src, " .quad _switch_tls_{}$tlv$init", seed);
256
257 src
258 }
259
260 fn assert_raw_parity(prefix: &str, src: &str) -> StressPaths {
261 let paths = StressPaths::new(prefix);
262 fs::write(&paths.asm, src).expect("write stress source");
263 let obj = afs_as::assemble::assemble_source(src)
264 .unwrap_or_else(|err| panic!("afs-as failed for {}\n{}\n{}", prefix, src, err));
265 let mut file = fs::File::create(&paths.ours_obj).expect("create afs-as object");
266 afs_as::macho::write_macho(&obj, &mut file).expect("write Mach-O object");
267 common::assemble_with_system(&paths.asm, &paths.ref_obj);
268
269 let ours = fs::read(&paths.ours_obj).expect("read ours");
270 let reference = fs::read(&paths.ref_obj).expect("read reference");
271 if ours != reference {
272 panic!(
273 "raw object mismatch for {}\nroot: {}\n---source---\n{}\n---ours load---\n{}\n---ref load---\n{}\n---ours relocs---\n{}\n---ref relocs---\n{}\n---ours symbols---\n{}\n---ref symbols---\n{}",
274 prefix,
275 paths.root.display(),
276 src,
277 common::object_load_commands(&paths.ours_obj),
278 common::object_load_commands(&paths.ref_obj),
279 common::object_relocations(&paths.ours_obj),
280 common::object_relocations(&paths.ref_obj),
281 common::object_symbols_verbose(&paths.ours_obj),
282 common::object_symbols_verbose(&paths.ref_obj),
283 );
284 }
285
286 paths
287 }
288
289 fn assert_relocatable_parity(paths: &StressPaths, src: &str) {
290 common::assemble_link_support(&paths.support_obj);
291 common::link_relocatable_with_system(
292 &[&paths.ours_obj, &paths.support_obj],
293 &paths.ours_linked,
294 );
295 common::link_relocatable_with_system(&[&paths.ref_obj, &paths.support_obj], &paths.ref_linked);
296
297 let ours = fs::read(&paths.ours_linked).expect("read ours linked");
298 let reference = fs::read(&paths.ref_linked).expect("read ref linked");
299 if ours != reference {
300 panic!(
301 "relocatable mismatch for {}\n---source---\n{}\n---ours undef---\n{}\n---ref undef---\n{}\n---ours load---\n{}\n---ref load---\n{}\n---ours symbols---\n{}\n---ref symbols---\n{}",
302 paths.root.display(),
303 src,
304 normalize_tool_output(&common::object_undefined_symbols(&paths.ours_linked)),
305 normalize_tool_output(&common::object_undefined_symbols(&paths.ref_linked)),
306 normalize_tool_output(&common::object_load_commands(&paths.ours_linked)),
307 normalize_tool_output(&common::object_load_commands(&paths.ref_linked)),
308 normalize_tool_output(&common::object_symbols_verbose(&paths.ours_linked)),
309 normalize_tool_output(&common::object_symbols_verbose(&paths.ref_linked)),
310 );
311 }
312 }
313
314 #[test]
315 fn grouped_metadata_heavy_cases_match_system_as_and_link_relocatable() {
316 for seed in 1..=4u64 {
317 let src = generate_metadata_heavy_case(seed);
318 let paths = assert_raw_parity(&format!("afs_grouped_meta_{}", seed), &src);
319 assert_relocatable_parity(&paths, &src);
320 }
321 }
322
323 #[test]
324 fn grouped_section_switch_cases_match_system_as() {
325 for seed in 1..=6u64 {
326 let src = generate_section_switch_case(seed);
327 let _paths = assert_raw_parity(&format!("afs_grouped_switch_{}", seed), &src);
328 }
329 }
330