Instructions to use asm2c/wyvern-1-7b with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use asm2c/wyvern-1-7b with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="asm2c/wyvern-1-7b") messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("asm2c/wyvern-1-7b") model = AutoModelForCausalLM.from_pretrained("asm2c/wyvern-1-7b", device_map="auto") messages = [ {"role": "user", "content": "Who are you?"}, ] inputs = tokenizer.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=256) print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use asm2c/wyvern-1-7b with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "asm2c/wyvern-1-7b" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "asm2c/wyvern-1-7b", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/asm2c/wyvern-1-7b
- SGLang
How to use asm2c/wyvern-1-7b with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "asm2c/wyvern-1-7b" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "asm2c/wyvern-1-7b", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "asm2c/wyvern-1-7b" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "asm2c/wyvern-1-7b", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use asm2c/wyvern-1-7b with Docker Model Runner:
docker model run hf.co/asm2c/wyvern-1-7b
wyvern-1-7b
asm in, C out. Give wyvern-1 one function's x86 disassembly and its toolchain, and it writes C that gcc compiles back to the same bytes (relocations masked). The target is byte-identical C, which is stricter than equivalent C.
By asm2c. Model page: asm2c.xyz/model. Training pairs: asm2c.xyz/pairs.
- base:
Qwen/Qwen2.5-Coder-7B-Instruct, LoRA SFT, merged to bf16 (weights at the repo root) - LoRA alone:
adapter/ - toolchain:
gcc-i686-o2(gcc 15.2 -O2, i686-linux-gnu, flags below), C - prompt format:
asm2c-chat-v2, implemented inprompt.py
Results
Every answer is compiled with the target's toolchain and diffed by the asm2c scorer. A function counts only if the bytes are identical. If a function's prompt doesn't fit the context, or the model gives no output, it counts as a miss.
test: 234 held-out functions of doom, duke3d, quake, quake2 and zlib, whole translation units held out too. Every model gets the same functions, the same prompt and the same scorer.
| model | params | first-shot exact | pass@1 | best-of-9 | mean score |
|---|---|---|---|---|---|
| wyvern-1 | 7B | 25.2% | 24.1% | 31.2% | 48.7 |
| Qwen2.5-Coder-32B-Instruct | 32B | 9.0% | 9.2% | 16.2% | 27.0 |
| Qwen3-Coder-30B-A3B-Instruct | 30B MoE, 3B active | 7.7% | 8.5% | 9.4% | 14.3 |
| DeepSeek-Coder-V2-Lite-Instruct | 16B MoE, 2.4B active | 6.0% | 5.3% | 7.7% | 15.0 |
| Qwen2.5-Coder-7B-Instruct (base) | 7B | 5.1% | 4.6% | 6.4% | 14.5 |
fresh: 158 functions of heretic, sqlite and wolf3d, held out by stable hash before training. Same prompt, settings and scorer for every model.
| model | params | first-shot exact | pass@1 | best-of-9 | mean score |
|---|---|---|---|---|---|
| wyvern-1 | 7B | 9.5% | 8.6% | 13.3% | 27.8 |
| Qwen2.5-Coder-32B-Instruct | 32B | 2.5% | 2.8% | 5.7% | 21.1 |
| Qwen3-Coder-30B-A3B-Instruct | 30B MoE, 3B active | 1.3% | 1.1% | 1.3% | 2.0 |
| Qwen2.5-Coder-7B-Instruct (base) | 7B | 0.0% | 0.2% | 1.9% | 8.7 |
| DeepSeek-Coder-V2-Lite-Instruct | 16B MoE, 2.4B active | 0.0% | 0.2% | 1.3% | 10.2 |
- first-shot: the greedy output is byte-exact. No retries, no compiler feedback.
- pass@1: unbiased estimate from 8 samples (T 0.8, top-p 0.95). best-of-9: greedy or any of the 8 samples is exact.
- mean score: scorer similarity of the greedy output, 0–100. A compile error scores 0.
- Same input for every model: the system line and user turn of
prompt.py, greedy plus 8 samples, up to 1,536 new tokens, a 16,384-token context, vLLM in bf16. The open models weren't tuned or given extra instructions. - fresh includes 22 functions that no agent has matched yet. 136 of the 158 have a known match.
- The test prompts used an earlier wording of the system line's first sentence (only the name differs).
Raw numbers: bench/.
Data
Every training pair is one function that an agent matched byte-for-byte during asm2c runs. The scorer recompiled the agent's C with the pinned toolchain and got identical bytes (relocations masked). An agent's own claim never admits a pair; only the scorer's re-check does. No synthetic pairs.
5,316 pairs (1,577,853 bytes of matched code), giving 7,760 training rows and about 23.5M tokens. The 2026-10-19 run and brogue pairs are weighted ×2, the earlier pairs ×1.
| target | program | licence | pairs | rows |
|---|---|---|---|---|
| doom | linuxdoom 1.10 | GPL-2.0 | 642 | 642 |
| duke3d | Duke Nukem 3D 1.5 (jfduke3d) | GPL-2.0 | 306 | 306 |
| quake | WinQuake 1.09 | GPL-2.0 | 897 | 897 |
| quake2 | Quake II game 3.21 | GPL-2.0 | 909 | 909 |
| zlib | zlib 1.2.13 | Zlib | 118 | 118 |
| brogue | Brogue CE | AGPL-3.0 | 383 | 766 |
| heretic | Heretic 1.3 | GPL-2.0 | 471 | 942 |
| sqlite | SQLite 3.54.1 | public domain | 1,198 | 2,396 |
| wolf3d | Wolf4SDL | GPL-2.0 or id Wolf3D licence | 392 | 784 |
| total | 5,316 | 7,760 |
- One pair per (target, symbol). Identical asm under one toolchain is collapsed. Any training row whose asm equals a held-out function's asm is dropped.
- Splits are by function, using a stable hash. The test split also holds out whole translation units.
- Per-target counts and drops:
dataset_stats.json.
Training
- LoRA r 64, alpha 128, dropout 0.05 on q/k/v/o/gate/up/down (161.5M trainable)
- initialised from an earlier asm2c LoRA trained on the 2,872 earlier pairs, then 1 epoch over the 7,760 rows
- seq_len 8192 (207 longer rows dropped, 7,553 trained), batch 1 × grad-accum 16, lr 1e-4, bf16, gradient checkpointing, seed 2026
- loss on the assistant (C) turn only
- 473 steps, 22.4M tokens, 2.6 h on one A100-SXM4-80GB
- train loss 0.191, val loss 0.264 (55 held-out pairs)
Log and config: logs/train.log, run_summary.json.
Usage
There are two turns: the system line names the toolchain, and the user turn carries one function. prompt.py builds
both exactly as in training. The chat template's default system line is the gcc-i686-o2 one, so a bare user turn
also works.
System:
You are asm2c, a matching decompiler. Write C source for ONE function so that it recompiles to byte-identical machine code (relocations masked) with the exact toolchain below. Reproduce the original control flow, types, operand order and statement order the compiler needs; do not optimize or restructure. Output only C: any needed declarations, then the function definition.
toolchain: gcc-i686-o2
compiler: gcc 15.2 -O2 (i686-linux-gnu)
flags: -std=gnu89 -O2 -march=i686 -fno-pic -fno-pie -fno-asynchronous-unwind-tables -fno-stack-protector -fcf-protection=none -fcommon -fno-reorder-blocks-and-partition -fno-ipa-sra -fno-ipa-cp -fno-ipa-vrp -fno-ipa-bit-cp -fno-partial-inlining -fno-ipa-icf -fno-ipa-pure-const -fno-ipa-reference -fno-ipa-modref -fno-ipa-ra -w
arch: i386
User (a fresh wolf3d function; the types: block is trimmed here):
function: FixedMul (25 bytes) · tu wl_utils.c
context:
proto: fixed FixedMul (fixed a, fixed b); /* wl_utils.h */
includes: "wl_utils.h"
sameTu: safe_malloc FixedDiv ReadShort ReadLong Error Help
types:
```c
typedef signed int __int32_t;
typedef __int32_t int32_t;
typedef int32_t fixed;
```
target assembly:
```asm
# FixedMul (TU wl_utils.c, section .text, 25 bytes, binding global)
# AT&T syntax. .Lxx = fn-relative branch targets; relocations shown symbolized:
# "text" = string literal (.rodata.str), =0x.. = float/double constant (.rodata.cstN)
FixedMul:
/* 000 */ mov 0x4(%esp),%eax
/* 004 */ imull 0x8(%esp)
/* 008 */ add $0x8000,%eax
/* 00d */ adc $0x0,%edx
/* 010 */ mov %eax,%ecx
/* 012 */ shrd $0x10,%edx,%ecx
/* 016 */ mov %ecx,%eax
/* 018 */ ret
```
wyvern-1, greedy (byte-exact):
#include "wl_utils.h"
fixed FixedMul (fixed a, fixed b)
{
return (fixed)(((long long)a * (long long)b + 0x8000) >> 16);
}
The context lines are optional: proto, includes, callees, refs, data and sameTu. The types: block holds
the declarations the function needs. The asm is the function's listing in the format above. The model was trained
with this context present, so leaving it out is untested.
# hf download asm2c/wyvern-1-7b prompt.py --local-dir .
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
from prompt import build_messages, extract_c
tok = AutoTokenizer.from_pretrained("asm2c/wyvern-1-7b")
model = AutoModelForCausalLM.from_pretrained("asm2c/wyvern-1-7b", dtype=torch.bfloat16, device_map="auto")
pair = {
"symbol": "FixedMul", "size": 25, "file": "wl_utils.c",
"context": {"proto": "fixed FixedMul (fixed a, fixed b); /* wl_utils.h */",
"includes": ['"wl_utils.h"'],
"sameTu": ["safe_malloc", "FixedDiv", "ReadShort", "ReadLong", "Error", "Help"]},
"types": "typedef signed int __int32_t;\ntypedef __int32_t int32_t;\ntypedef int32_t fixed;",
"asm": open("FixedMul.s").read(), # the listing, as above
}
ids = tok.apply_chat_template(build_messages(pair), add_generation_prompt=True,
return_tensors="pt", return_dict=True).to(model.device)
out = model.generate(**ids, max_new_tokens=2048) # greedy by default (generation_config.json)
print(extract_c(tok.decode(out[0][ids["input_ids"].shape[1]:], skip_special_tokens=True)))
Treat the output as a candidate. Compile it with the toolchain above and compare the function's bytes. Output that doesn't match can still compile. For a better hit rate, sample several answers (T 0.8, top-p 0.95) and keep the one that matches. On fresh, that takes 9.5% first-shot to 13.3% best-of-9.
Limitations
- One toolchain: gcc 15.2 -O2 for i686, C. Other compilers, flags, optimisation levels and architectures are out of distribution, and the same asm under another toolchain needs different C.
- The training code is game, database and compression code from the programs above. Unseen programs score lower.
- Prompts over 8,192 tokens were not trained on.
Licence
The weights are Apache-2.0, the same as the base model. The training C reconstructs functions of the programs listed above, and each of those programs keeps its own licence.
- Downloads last month
- 20
