diff --git a/doc/learn.md b/doc/learn.md
index ff27907..7060d50 100644
--- a/doc/learn.md
+++ b/doc/learn.md
@@ -1685,3 +1685,23 @@ residual are all word-aligned `complete=false` strings `-O` cannot resolve
either), bare indirect calls 1178 -> 1, ~150 misaligned `+0x..7` bogus comments
-> 0, and 64439 slots now carry a kind/name plus xrefs. Verified on iOS (Dart
3.13/3.2.5, cws=8) and Android (w0rdle, Dart 2.18, cws=4): 0 misaligned on both.
+
+## Expose the ObjectPool as r2's global pointer (anal.gp) in r2flutter-A
+
+x27 (PP) is the only Dart reserved register with a *static* address: the
+ObjectPool lives in the snapshot, so we know its base. `r2flutter -p -r`
+already emitted `e anal.gp=` / `dr x27=` / `e anal.roregs=...`, but
+the analysis command never set them, and the `-R` script had a dead
+`dr x27=\`e anal.gp\`` that depended on an unset value. `r2flutter -A` (every
+depth) now calls `r2flutter_setup_pp_gp`, which seeds `anal.gp` with the pool
+base, `anal.gpseed=x27`, `anal.roregs=x27,gp,zero` and an `f PP` flag, so plain
+r2 analysis/ESIL resolves `[x27, off]` pool loads consistently.
+
+Gotcha worth remembering: `dart_resolve_pp_info` populates the context read
+cache (`ctx->rmem`) and can leave a stale layout pointer. `dart_app_new_from_core`
+copies the `DartCtx` by value (`memcpy`), so resolving on the live session
+context and then running the analysis double-freed that cache (SIGABRT after
+"Loaded N functions"). The setup resolves on a shallow copy with its own
+`rmem`/`layout` and frees only what it allocated, leaving the session context
+pristine. x22 (NULL_REG) and x26 (THR) are runtime pointers with no static
+address, so they are documented/annotated, never seeded as anal.gp.
diff --git a/src/r2/core_flutter.c b/src/r2/core_flutter.c
index c44f63d..976e2c2 100644
--- a/src/r2/core_flutter.c
+++ b/src/r2/core_flutter.c
@@ -394,6 +394,9 @@ static bool r2flutter_run_cmd(RCore *core, DartCtx *dctx, const R2FlutterCmd *cm
if (cmd->analysis_depth >= 2) {
dctx->dump_fields = 1;
}
+ // Seed anal.gp/gpseed/roregs with the ObjectPool base for every -A depth
+ // so plain-r2 analysis can resolve [x27, off] pool loads.
+ r2flutter_setup_pp_gp (core, dctx);
if (cmd->analysis_depth >= 3) {
r2flutter_analysis_run (core, dctx, dctx->quiet);
} else {
diff --git a/src/r2/flutter_analysis.c b/src/r2/flutter_analysis.c
index 184e805..707efbb 100644
--- a/src/r2/flutter_analysis.c
+++ b/src/r2/flutter_analysis.c
@@ -1317,6 +1317,34 @@ static void flutter_scan_functions(RCore *core, FlutterAnalModel *model, Flutter
ht_up_free (seen_fcns);
}
+// Expose the reconstructed ObjectPool as r2's global pointer so that plain-r2
+// analysis and ESIL resolve `[x27, off]` loads to pool addresses, matching how
+// `r2flutter -p -r` already wires it up. x27 (PP) is the only Dart reserved
+// register with a static address; x22 (NULL_REG) and x26 (THR) are runtime
+// pointers and cannot be seeded this way.
+void r2flutter_setup_pp_gp(RCore *core, DartCtx *dctx) {
+ if (!core || !dctx) {
+ return;
+ }
+ // Resolve on a shallow copy: dart_resolve_pp_info populates the read cache
+ // (ctx->rmem) and can leave a stale layout pointer in the context. The real
+ // dctx is copied by value into the analysis DartApp, so polluting it here
+ // would double-free that cache. The copy shares heap-owned pointers with
+ // dctx, so we only release what we allocated into it (its own rmem).
+ DartCtx probe = *dctx;
+ probe.rmem = NULL;
+ probe.layout = NULL;
+ DartPpInfo pp = { 0 };
+ if (dart_resolve_pp_info (&probe, &pp) && pp.base) {
+ r_config_set_i (core->config, "anal.gp", pp.base);
+ r_config_set (core->config, "anal.gpseed", "x27");
+ r_config_set (core->config, "anal.roregs", "x27,gp,zero");
+ r_flag_set (core->flags, "PP", pp.base, 1);
+ }
+ dart_pp_info_fini (&pp);
+ dart_read_cache_free (probe.rmem);
+}
+
bool r2flutter_analysis_run(RCore *core, DartCtx *dctx, bool quiet) {
R_RETURN_VAL_IF_FAIL (core && dctx, false);
DartApp *app = dart_app_new_from_core (core, dctx);
diff --git a/src/r2/flutter_analysis.h b/src/r2/flutter_analysis.h
index 59f210d..bc7e07b 100644
--- a/src/r2/flutter_analysis.h
+++ b/src/r2/flutter_analysis.h
@@ -5,5 +5,6 @@
#include "../../include/r2flutter/dart_r2.h"
bool r2flutter_analysis_run(RCore *core, DartCtx *dctx, bool quiet);
+void r2flutter_setup_pp_gp(RCore *core, DartCtx *dctx);
#endif
diff --git a/test/db/cmd/pp-gp-register-ios b/test/db/cmd/pp-gp-register-ios
new file mode 100644
index 0000000..63f4902
--- /dev/null
+++ b/test/db/cmd/pp-gp-register-ios
@@ -0,0 +1,17 @@
+NAME=r2-pp-gp-register-ios
+FILE=bins/ios/Runner.app/Frameworks/App.framework/App
+ARGS=-NN -e scr.color=0 -e bin.relocs.apply=true
+CMDS=<