Conceptually, MemToShadowImpl::Apply() could just use a hash table that maps any App memory address to a Shadow memory address. With this method, ASLR doesn't matter. Unfortunately, the hash table method is relatively slow.
Instead, TSan uses a simple mathematical formula (explained below) that maps App memory addresses to Shadow memory addresses.
However, aggressive ASLR means that there is a wide range of App memory addresses that the binaries/libraries could be loaded into; we would also need to have a wide range of corresponding Shadow memory areas, and that's very hard (and often infeasible, because shadow memory takes 2.5x as much memory compared to App memory). If ASLR is too aggressive, TSan will disable ASLR entirely.