338-literal-addr-deref.c (1544B)
1 /* Store/load through a pointer whose address is a plain integer 2 * constant (no symbol). On aarch64, stock arm64-gen.c (0.9.26) handles 3 * only the VT_CONST | VT_LVAL | VT_SYM case in store/load and asserts 4 * out on bare VT_CONST | VT_LVAL — i.e. `*(volatile T*)0x1234`. The 5 * matching x86_64 path goes through gen_modrm and the riscv64 path has 6 * an explicit fr==VT_CONST branch, so neither tripped before. The 7 * vendor/tcc/patches/arm64-{store,load}-const-lvalue 8 * pair adds the missing case. 9 * 10 * The volatile global keeps tcc from constant-propagating the 11 * branch to false, so the body must emit code; the runtime value 12 * stays 0 so we never actually dereference 0x1234 / 0x5678. The test 13 * passes if the program both compiles and exits 0. 14 * 15 * Surfaced when building musl on aarch64 (boot4): __libc_start_main, 16 * the mallocng family, abort, asctime_r and friends emit this pattern 17 * through folded weak-hidden references and trip the assert. 18 */ 19 20 static volatile int never = 0; 21 22 int main(void) 23 { 24 if (never) { 25 *(volatile unsigned char *)0x1234 = 5; /* store */ 26 unsigned char b = *(volatile unsigned char *)0x1234; 27 28 *(volatile unsigned short *)0x2000 = 0xbeef; /* sized variants */ 29 unsigned short s = *(volatile unsigned short *)0x2000; 30 31 *(volatile unsigned int *)0x3000 = 0xdeadbeef; 32 unsigned int i = *(volatile unsigned int *)0x3000; 33 34 *(volatile unsigned long *)0x4000 = 0x1122334455667788UL; 35 unsigned long l = *(volatile unsigned long *)0x4000; 36 37 return (int)(b + s + i + l); 38 } 39 return 0; 40 }