asmsense

A local model for machine code without source. What we measured.

What today's tools miss in a raw firmware image, and where our small model stands next to large cloud models. Every number comes from the same data, including the places where we lose.

On AI use. The write-ups on this site, and the site itself, were made with Claude (Anthropic). The measurements come from our own pipeline and data. Our posts elsewhere are written by hand; we use AI as an assistant when interpreting the analysis.

01 · FreeRTOS · Cortex-M7 · 11 KB · no source code

One firmware image, analysed two ways. Today's tools miss 52 of its 93 functions.

The missed ones are not minor: startup (Reset, main), the task scheduler and the interrupt handlers. The information that finds them sits in the vector table at the start of the image.

First 64 bytes · vector table
000000 00 02 20c5 24 00 60
0008c1 24 00 60c1 24 00 60
0010c1 24 00 60c1 24 00 60
0018c1 24 00 6000 00 00 00
002000 00 00 0000 00 00 00
002800 00 00 0055 3e 00 60
0030c1 24 00 6000 00 00 00
00389d 3e 00 60f1 3f 00 60
  • 0x20020000 stack top · RAM
  • 0x600024C4 Reset
  • 0x60003E54 SVC
  • 0x60003E9C PendSV
  • 0x60003FF0 SysTick

The table tells the CPU where to start after reset and where to jump on each interrupt. The pointers are odd because of the Thumb bit: …c5 → Reset at …c4.

Each square is one function, in address order · scroll →
Truth · labels from source93 / 93Today · rbasefind + Ghidra41 / 93asmsense target · correct base + vector table85 / 93mainResetxTaskCreateSchedulerSVCPendSVSysTick
foundmissedpresentfalse positives: 0 / 0

Correct base address, still not enough

rbasefind answered 0x60002000, backed by 2 pointers against 1 for the runner-up. Ghidra still missed 52 functions.

The misses are the core of the device

Reset, main, xTaskCreate, the scheduler, and the SVC, PendSV and SysTick handlers. Today an analyst finds these by hand.

85 / 93 with the vector table

Most of the remaining 8 are tasks and callbacks that the code only references by pointer.

02 · 239 images · 12 applications · 5 Cortex-M cores · 28,743 functions

Not a single example. The missing pieces are the base address and the vector table.

We built these images from open RTOS and library code with real MCU memory maps, so the true address of every function is known. We ran Ghidra under four conditions.

Function detection, F1 · line = 95% confidence interval · scroll →
Ghidra alone · base unknown55%Ghidra + rbasefind · today's automatic chain61%Ghidra + correct base72%Ghidra + base + vector table · asmsense target92%
Which functions are found · ○ today → ● with base and vector table · scroll →
0%50%100%Reset + interrupt handlers2%100%Bootloader6%100%C runtime24%87%Application code27%67%RTOS + libraries69%89%libc / libm74%87%

On a raw Cortex-M image today, 2% of startup and interrupt code is found automatically, and for 41 of the 239 images no base address is found at all. Given the correct base and vector table, that becomes 100%. The vector table alone adds 20 points [10–34]. We are building the module that recovers this information automatically with a confidence score; its own accuracy has not been measured yet.

03 · x86-64 · the same 2,000 functions from 26 little-known projects

Naming a stripped function: our 8B model next to large cloud models.

The model never sees the function's name. It gets the machine code, the call context and Ghidra pseudocode, and writes a name and a description in two languages. The score is token F1 on the name; "exact" counts functions where the name matched in full.

Name prediction, token F1 · scroll →
0.000.050.100.150.20Qwen3-8B, untrained8B · localnot yet measured on these 2,000asmsense v1 · Qwen3-8B + LoRA8B · local0.106 25 exactasmsense v5 · + description target8B · local0.124 26 exactasmsense v6 · + Ghidra pseudocode8B · local0.135 31 exactDeepSeek v4.1 flash · asm + contextcloud0.154 40 exactMiMo v2.6 pro · asm + contextcloud0.167 40 exactMiMo v2.6 pro · same input as v6cloud0.192 52 exact
70%

of the large cloud model's score with the same input. Ours is 8B and runs on your own machine.

+27%

from v1 to v6. Same base model and test set; only the data and the input changed.

21%

of descriptions judged correct (automatic judge, 294 decisions). 20% for v5.

04 · Real test functions

The same machine code, four guesses. Where we win and where we lose.

Excerpt of the input · append_int · -O2
moveax, 0xcccccccd← ÷10 magic number
imulrsi, rax
shrrsi, 0x23
orr9b, 0x30← digit → '0'..'9'
movbyte ptr [rbp + r15 - 0x29], r9b
cmpecx, 0x9
jaloc_2← digit loop
…
learax, [rsi + rsi]← capacity × 2
callrealloc← grow the buffer
…
callmemcpy← append

The model sees sub_0004 instead of the name. The evidence is in the lines: division by 10, ASCII digits, a growing buffer, a copy to the end.

Real name → predictions
append_intjson_getsrgb_to_linear
asmsense v1itoalxlsx_reader_worksheet_find_cellsigmoid
asmsense v6append_intjson_object_getsRGB
DeepSeekappend_uint_to_stringlookup_symbol_by_namesaturate
MiMoappend_uint_to_bufferlookup_key_by_namesrgb_to_linear
exactclose (F1 ≥ 0.5)miss

We lose the third one: v6 recognised the sRGB curve but read the direction of the conversion backwards; MiMo got the name exactly.

Limits

What we do not claim.