I'll introduce a new way to provide “strong atomicity” in an implementation of atomic blocks using transactional memory. Strong atomicity lets us offer clear semantics to programs, even if they access the same locations inside and outside atomic blocks. It also avoids differences between hardware-implemented transactions and software-implemented ones. Our new idea is to use off-the-shelf page-level memory protection hardware to detect conflicts between normal memory accesses and transactional ones. The page-level system ensures correctness but gives poor performance because of the costs of manipulating memory protection hardware from user-mode and the costs of synchronizing protection settings between processors or cores. However, in practice, we show how a combination of careful object placement and dynamic code update allow us to eliminate almost all of the protection changes. Existing implementations of strong atomicity in software rely on detecting conflicts by conservatively treating some non-transacted accesses as short transactions. In contrast, our page-level technique provides a foundation that lets us be less conservative about how nontransacted accesses are treated; we avoid changes to non-transacted code until a possible conflict is detected dynamically, and we can respond to phase changes where a given instruction sometimes generates conflicts and sometimes does not. We evaluate our implementation with C# versions of many of the STAMP benchmarks. Our implementation requires no changes to the operating system.