<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/the-nx-bit-is-not-just-about-security-jhrbfxkss" -->

---
title: The NX bit is not just about security | daily.dev
description: A developer building a bare-metal ARM64 hypervisor for postmarketOS on a MediaTek MT6735 phone tracked down a months-long boot lockup bug caused by speculative...
canonical: https://daily.dev/posts/the-nx-bit-is-not-just-about-security-jhrbfxkss
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: The NX bit is not just about security | daily.dev
og:description: A developer building a bare-metal ARM64 hypervisor for postmarketOS on a MediaTek MT6735 phone tracked down a months-long boot lockup bug caused by speculative...
og:url: https://daily.dev/posts/the-nx-bit-is-not-just-about-security-jhrbfxkss
og:image: https://api.daily.dev/og/posts/JhRBFxKsS.png
og:image:alt: The NX bit is not just about security
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# The NX bit is not just about security

**[Lobsters](https://daily.dev/sources/lobsters)** · 12 min read · 0 upvotes · 0 comments

## Summary

A developer building a bare-metal ARM64 hypervisor for postmarketOS on a MediaTek MT6735 phone tracked down a months-long boot lockup bug caused by speculative instruction fetches to an unmapped bootrom address at 0x0. After ruling out register corruption, icache/dcache coherency, kernel panics, and CPU errata, the fix turned out to be that marking memory as Device only blocks speculative data accesses on ARM - speculative instruction fetches require the memory to be separately marked non-executable (NX). Once the hypervisor's memory mappings were marked non-executable, the phone booted reliably to Android.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://purplesyringa.moe/blog/guest/the-nx-bit-is-not-just-about-security>

## Questions this post answers

### Does marking a memory region as Device on ARM prevent speculative instruction fetches to it?

No. Marking a region as Device memory on ARM only prevents speculative data accesses, not speculative instruction fetches. Instruction fetches treat any executable memory as Normal memory regardless of its Device attribute, so a region must also be marked non-executable to fully block speculative instruction accesses, per ARM's own documentation on device memory.

_Developers hardening low-level ARM memory mappings can find debugging deep dives like this on daily.dev._

### Why would an ARM64 CPU randomly hang or reset when executing a dynamic branch instruction like blr near unmapped memory?

A dynamic branch such as blr uses branch prediction and can speculatively mispredict to address 0x0, causing a speculative instruction fetch from that address. If the memory at 0x0 (such as a locked bootrom on a MediaTek MT6735 SoC) is mapped but not marked non-executable, the speculative fetch can trigger a system lockup, even though the mispredicted path is never architecturally taken.

_Anyone chasing intermittent ARM boot hangs can follow similar low-level debugging writeups on daily.dev._

### Why does using a static branch instruction instead of an indirect call fix a mysterious ARM64 boot crash?

A static branch like bl always jumps to a known target and cannot mispredict, so it never triggers a speculative instruction fetch to an invalid address like 0x0. An indirect call like blr uses branch prediction and can speculatively fetch instructions from a mispredicted target address, which caused a system lockup on a Cortex-A53-based MediaTek MT6735 phone until the memory was marked non-executable.

_Track down subtle hardware-level bugs like this one by following low-level ARM debugging content on daily.dev._

## Community take

How the wider developer community reacted, aggregated from 2 discussions and 8 comments across lobsters, hackernews (as of 2026-09-04).

**TL;DR:** Technical commenters found the deep dive compelling, focusing on the nuances of instruction/data cache coherency across architectures and sharing similar real-world bugs encountered in bootloaders and hypervisors like seL4.

**Sentiment:** 25% positive · 70% mixed · 5% skeptical

**The case for**

- The write-up surfaced a genuinely obscure and useful bit of ARM/x86 architecture knowledge that experienced engineers hadn't fully internalized.
- Others confirmed hitting nearly identical speculative-fetch bugs in unrelated projects (seL4 bootloaders on Cortex-A35, ZynqMP boards), validating the root cause analysis.

**The pushback**

- Some noted the post's claim that CPUs never signal faults for speculative accesses is only partially true, since speculative accesses reaching the system bus can trigger SErrors on ARM.

**By community**

- lobsters (positive): Commenters engaged deeply with the cache-coherency details, added architecture-specific nuance (x86 vs ARM, Apple vs Qualcomm Oryon designs), and shared analogous bugs from their own bootloader/hypervisor work.

**Open questions**

- Would x86 performance improve if self-modifying code required manual icache invalidation instead of automatic coherency?

**Highlights**

> We ran into this in the seL4 boot loaders as well(unverified code). More specifically, someone from [STM32 contributing platform support for the STM32MP2](https://lists.sel4.systems/hyperkitty/list/devel@sel4.systems/thread/DJNDO5CUQBKGIA4SQHXCNQ3T6SKZEY4A/) did, on a Cortex-A35. Slightly different, it was `ret` vs `br x30`, but same idea - `ret` got predicted whilst `br x30` did not. This time it was memory protected by STM's RIF (resource isolation framework). We solved it a slightly different way, by only mapping the necessary memory, but then we're a bootloader not a hypervisor. Funnily enough, the ZynqMP (ZCU102) board had been having periodic failures booting in 32-bit mode every so often (not consistent even with the same binary), and this solved it  > CPUs don’t signal page faults for speculative accesses This is not strictly true - the CPU *core* won't (which is what produces page faults, so technically correct), but on ARM, such as in the case with the RIF, speculative accesses that make it out to the system bus and to various peripherals can produce SErrors.
> — [juliaaa on lobsters · 10 points](https://lobste.rs/s/eokmrg/nx_bit_is_not_just_about_security#c_o81yad)

> Arm server-grade cores have coherent icaches because explicit flushes are pretty expensive especially when with the system-wide broadcast needed combined with huge core counts. However, on Arm's server cores, opting into the coherent icache comes at the price of having the L1i be strictly included within the L2. Arm does not offer that option on client-oriented cores. Apple's design has a non-coherent L1i but Qualcomm's Oryon cores even on phones ship with a coherent L1i.
> — [never\_released on lobsters · 3 points, 1 comments](https://lobste.rs/s/eokmrg/nx_bit_is_not_just_about_security#c_tpsfo0)

> x86 is somewhat weird here not requiring it: they have special code in the frontend that handles even self-modifying-code and will flush the pipeline (that doesn't work when modified through a different address - that requires a pipeline flush); and then i-cache and d-cache are coherent as you mentioned. I'm more of an ARM person, I've barely touched x86, but it seems weird to me that they'd be coherent: after all, that's extra work the processor needs to do to maintain coherency for a relatively rare operation. (This is true also for loading programs into memory - not just modifying existing operations; which is arguably the same thing).
> — [juliaaa on lobsters · 7 points, 2 comments](https://lobste.rs/s/eokmrg/nx_bit_is_not_just_about_security#c_kqohda)

> Oh wow. The first issue found on the way is a lot more "nightmare fuel" than the main event: > modifications to the data do not automatically propagate to the instruction fetches I guess I never really even realized that that was the case because… well, modifying instructions is generally not something I would do just for fun, but that's quite the footgun for those rare cases when that happens.
> — [valpackett on lobsters · 4 points, 1 comments](https://lobste.rs/s/eokmrg/nx_bit_is_not_just_about_security#c_slbtm7)

**Source threads**

- [lobsters](https://lobste.rs/s/eokmrg/nx_bit_is_not_just_about_security) · 37 points · 8 comments
- [hackernews](https://news.ycombinator.com/item?id=49564609) · 3 points · 0 comments

## Similar posts on daily.dev

- [Project Zero: Defeating KASLR by Doing Nothing at All](https://daily.dev/posts/project-zero-defeating-kaslr-by-doing-nothing-at-all-y7lgmwolo) · Project Zero · 0 upvotes · 0 comments
- [Analyzing the Security Implications of Unlocked Bootloaders](https://daily.dev/posts/analyzing-the-security-implications-of-unlocked-bootloaders-hn4zqpgtq) · droidcon · 0 upvotes · 0 comments
- [NDSS 2025 – Retrofitting XoM For Stripped Binaries Without Embedded Data Relocation](https://daily.dev/posts/ndss-2025-retrofitting-xom-for-stripped-binaries-without-embedded-data-relocation-y9kymcsqp) · Security Boulevard · 0 upvotes · 0 comments
- [A new unpatchable flaw in Apple chips opens the door to an iPhone jailbreak](https://daily.dev/posts/a-new-unpatchable-flaw-in-apple-chips-opens-the-door-to-an-iphone-jailbreak-qqrtgimnp) · TechCrunch · 0 upvotes · 0 comments

---

Tags: [#hardware](https://daily.dev/tags/hardware), [#assembly](https://daily.dev/tags/assembly)

[View this post on daily.dev](https://daily.dev/posts/the-nx-bit-is-not-just-about-security-jhrbfxkss)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"The NX bit is not just about security","url":"https://daily.dev/posts/the-nx-bit-is-not-just-about-security-jhrbfxkss","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/the-nx-bit-is-not-just-about-security-jhrbfxkss"},"datePublished":"2026-09-04T13:59:00.207Z","dateModified":"2026-09-04T23:11:37.611Z","description":"A developer building a bare-metal ARM64 hypervisor for postmarketOS on a MediaTek MT6735 phone tracked down a months-long boot lockup bug caused by speculative...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/f7fc1ba03caad1b3f11dbe0c717da24d?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/f7fc1ba03caad1b3f11dbe0c717da24d?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Lobsters","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Lobsters","logo":"https://media.daily.dev/image/upload/s--tl8v_Fku--/f_auto,t_logo/v1698841318/logos/lobste.jpg","url":"https://daily.dev/sources/lobsters"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/the-nx-bit-is-not-just-about-security-jhrbfxkss","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"hardware,assembly","timeRequired":"PT12M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Lobsters","item":"https://daily.dev/sources/lobsters"},{"@type":"ListItem","position":3,"name":"The NX bit is not just about security"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/the-nx-bit-is-not-just-about-security-jhrbfxkss#faq","mainEntity":[{"@type":"Question","name":"Does marking a memory region as Device on ARM prevent speculative instruction fetches to it?","acceptedAnswer":{"@type":"Answer","text":"No. Marking a region as Device memory on ARM only prevents speculative data accesses, not speculative instruction fetches. Instruction fetches treat any executable memory as Normal memory regardless of its Device attribute, so a region must also be marked non-executable to fully block speculative instruction accesses, per ARM's own documentation on device memory. Developers hardening low-level ARM memory mappings can find debugging deep dives like this on daily.dev."}},{"@type":"Question","name":"Why would an ARM64 CPU randomly hang or reset when executing a dynamic branch instruction like blr near unmapped memory?","acceptedAnswer":{"@type":"Answer","text":"A dynamic branch such as blr uses branch prediction and can speculatively mispredict to address 0x0, causing a speculative instruction fetch from that address. If the memory at 0x0 (such as a locked bootrom on a MediaTek MT6735 SoC) is mapped but not marked non-executable, the speculative fetch can trigger a system lockup, even though the mispredicted path is never architecturally taken. Anyone chasing intermittent ARM boot hangs can follow similar low-level debugging writeups on daily.dev."}},{"@type":"Question","name":"Why does using a static branch instruction instead of an indirect call fix a mysterious ARM64 boot crash?","acceptedAnswer":{"@type":"Answer","text":"A static branch like bl always jumps to a known target and cannot mispredict, so it never triggers a speculative instruction fetch to an invalid address like 0x0. An indirect call like blr uses branch prediction and can speculatively fetch instructions from a mispredicted target address, which caused a system lockup on a Cortex-A53-based MediaTek MT6735 phone until the memory was marked non-executable. Track down subtle hardware-level bugs like this one by following low-level ARM debugging content on daily.dev."}}]}
```

