diff --git a/arch/x64/loader.ld b/arch/x64/loader.ld
index 78b25279aee89d26ed50e0fb4c71019fc0a6ec13..121edec27da6926e419bcfaaa67a94747a800203 100644
--- a/arch/x64/loader.ld
+++ b/arch/x64/loader.ld
@@ -11,11 +11,13 @@ SECTIONS
     . = 0x201000;
     .dynamic : { *(.dynamic) } :dynamic :text
     .text : {
+        text_start = .;
         *(.text.hot .text.hot.*)
         *(.text.unlikely .text.*_unlikely)
         *(.text.fixup)
         *(.text.startup .text.startup.*)
         *(.text .text.*)
+        text_end = .;
     } :text
     . = ALIGN(8);
     .fixup : {
diff --git a/core/mmu.cc b/core/mmu.cc
index 465caca25733fc4c5b5e72131e6564bcce5330cb..97378b03c9916f8f748c3e9f44d9213842ceba79 100644
--- a/core/mmu.cc
+++ b/core/mmu.cc
@@ -868,10 +868,18 @@ void switch_to_runtime_page_table()
 
 void page_fault(exception_frame *ef)
 {
+    extern const char text_start[], text_end[];
     sched::exception_guard g;
     auto addr = processor::read_cr2();
     if (fixup_fault(ef)) {
         return;
     }
+    auto pc = reinterpret_cast<void*>(ef->rip);
+    if (!pc) {
+        abort("trying to execute null pointer");
+    }
+    if (pc >= text_start && pc < text_end) {
+        abort("page fault outside application");
+    }
     osv::handle_segmentation_fault(addr, ef);
 }