From 244c51c2e1b1f613b894fa96e4d406667a67af33 Mon Sep 17 00:00:00 2001 From: QIU SHENGMING Date: Fri, 2 Oct 2026 13:39:39 +0800 Subject: [PATCH] Round 61: the overlay memset runs from a chain 0x080175fe -> 0x08016ff0 -> memset, a hundred times a second Reading the stack at the watchpoint hits gives the same chain every time: PC=0x0801ae7a (inside memset, entry 0x0801ae70), SP=0x20003c50, with return addresses 0x080047ca and 0x080175fe. So 0x080175fe calls the routine at 0x08016ff0, which calls memset(0x20000280, 0, 0x1000) from 0x0801701a, about a hundred times a second. Caveat worth stating: the sources quoted in recent rounds -- app_overlay.c, py25q16.c, radio.c -- came from armel/uv-k1-k5v3-firmware-custom's main branch while the running image is f4hwn's build. They need not be the same lineage, so claims like 'this routine is APP_LaunchOverlay' are inferences from those files rather than facts about this image. What is measured and source-independent: a routine at 0x08016ff0 is entered about a hundred times a second and each time zeroes the whole 4 KiB overlay, while the code is read into it exactly once -- so nothing the loader writes can survive, which is why a 24-byte app passes its CRC check and a 2568-byte one does not. --- AGENTS.md | 24 ++++++++++++++++++++++++ AGENTS.zh-CN.md | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 3145a8b..925cd74 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2405,3 +2405,27 @@ a second while the code is loaded once, so nothing the loader writes can survive The next measurement needs no disassembler: at the 1200 hits the stack pointer is 0x20003c50, so reading the words above it gives the whole return-address chain and therefore who calls the routine that calls memset. One run of that names the retry loop. + +**Round 61: the call chain is 0x080175fe -> 0x08016ff0 -> 0x0801701a -> memset, and it runs about a hundred times a second.** + +Reading the stack words at the watchpoint hits -- stack pointer 0x20003c50 -- gives the same chain every time: + + PC=0x0801ae7a (inside memset, entry 0x0801ae70) SP=0x20003c50 + return addresses on the stack: 0x080047ca 0x080175fe + +So 0x080175fe calls the routine whose prologue is at 0x08016ff0, which calls memset(0x20000280, 0, 0x1000) from +0x0801701a. That is the whole path, and it is taken about a hundred times a second. + +A caveat that matters, and that I should have stated earlier: the sources I have been quoting -- app_overlay.c, +py25q16.c, radio.c -- were fetched from armel/uv-k1-k5v3-firmware-custom's main branch, while the image running +here is f4hwn's build. They need not be the same lineage, so "this routine is APP_LaunchOverlay" and "that +memset is the launcher's own" are inferences from those files, not facts about this image. Nothing in the last +few rounds that rests on a fetched source should be treated as proven. + +What is measured, and independent of any source: a routine at 0x08016ff0 is entered about a hundred times a +second and each time zeroes the whole 4 KiB overlay through memset, while the code itself is read into that +overlay exactly once. Whatever the routine is called, nothing the loader writes can survive it, which is why a +24-byte app passes its CRC check and a 2568-byte one does not. + +Next: identify 0x080175fe and 0x080047ca against the image itself rather than against a fetched file -- for +instance by looking at what each calls and returns -- or fetch the sources for the exact build being run. diff --git a/AGENTS.zh-CN.md b/AGENTS.zh-CN.md index 49a9e9b..2e58c0a 100644 --- a/AGENTS.zh-CN.md +++ b/AGENTS.zh-CN.md @@ -2099,3 +2099,27 @@ DMA tx=4 rx=3 count=2568 tx_addr=0x20001338 rx_addr=0x20000280 tx_inc=0 rx_inc=1 **下一个测量不需要反汇编器** ✓:那 1200 次命中时 `SP = 0x20003c50` ✓,所以**把它上面的字读出来,就得到整条返回地址链** ✓ —— **也就得到「谁在调用那个调用 `memset` 的例程」** ✓。**跑一次就能给那个重试循环定名** ✓。 + +**第 61 轮:调用链是 `0x080175fe` → `0x08016ff0` → `0x0801701a` → `memset`,而它每秒执行约一百次。** + +在监视点命中处读栈(`SP = 0x20003c50` ✓),每一次得到的都是同一条链: + +``` +PC=0x0801ae7a(`memset` 内部,入口 0x0801ae70) SP=0x20003c50 +栈上的返回地址: 0x080047ca 0x080175fe +``` + +**所以是 `0x080175fe` 调用序言在 `0x08016ff0` 的例程,而它在 `0x0801701a` 处调用 `memset(0x20000280, 0, 0x1000)`** ✓。 +**这就是整条路径,而它每秒被走约一百次。** + +**有一条要紧的前提,我本该更早说明** ✗:**我一直在引用的那些源码 —— `app_overlay.c`、`py25q16.c`、`radio.c` —— 是从 +`armel/uv-k1-k5v3-firmware-custom` 的 main 分支取的 ✓,而这里跑的镜像是 f4hwn 的构建 ✓。两者未必同源** ✗✓。 +所以「这个例程就是 `APP_LaunchOverlay`」「那次 `memset` 就是启动器自己的」都只是**从那些文件推出的** ✓, +**而不是关于这份镜像的事实** ✓。**近几轮里任何依赖「取来的源码」的结论,都不该被当作已证。** + +**而有一条测量是独立于任何源码的** ✓:**`0x08016ff0` 那个例程每秒被进入约一百次 ✓,每次都通过 `memset` 把那整片 4 KiB 覆盖区清零 ✓**, +**而代码本身只被读进那片覆盖区一次** ✓。**无论那个例程叫什么,加载器写进去的东西都活不过它** ✓ —— +**这正是「24 字节的应用能过 CRC、2568 字节的过不了」的原因** ✓。 + +**下一步**:**对着镜像本身、而不是对着取来的文件,去认 `0x080175fe` 与 `0x080047ca`** ✓ —— +比如看它们各自调用与返回了什么 ✓ —— **或者去取「正在跑的那个构建」的源码** ✓。