assembly-x86
Use when reading GCC or Clang x86-64 assembly, writing inline asm, decoding AT&T syntax, or applying System V AMD64 register rules. Not for SIMD intrinsic selection: use simd-intrinsics.
Install
npx skills add https://github.com/OutlineDriven/outline-driven-development/tree/main/.devin/skills/assembly-x86
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install outlinedriven-outline-driven-development@llmmart
git clone https://github.com/OutlineDriven/outline-driven-development.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole outlinedriven/outline-driven-development collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
x86-64 assembly
GCC and Clang emit AT&T syntax by default. This skill reads that output, writes inline asm, and keeps register use inside the System V AMD64 ABI.
Contract
| Field | Bound contract |
|---|---|
| Trigger | The task reads compiler assembly output, writes inline asm in C or C++, decides AT&T versus Intel syntax, or explains calling conventions and stack layout in a disassembly. |
| Authority | Read-only. The skill explains and drafts; edits land through the normal coding path. No remote mutation. |
| Side effect | None. |
| Done | The drafted assembly assembles with gcc -c or clang -c, or the compiler output under discussion is explained register by register. |
Inputs
- The C or C++ source, compiler output, or assembly fragment: required.
- The compiler: required. AT&T versus Intel output and inline asm details follow it.
- The ABI: required. System V for Linux and macOS; the Microsoft x64 ABI changes the register map entirely.
Procedure
- Generate the baseline. Read the compiler's own output before writing any. Done when: the disassembly of the function under discussion is on screen.
gcc -O2 -S -fverbose-asm foo.c -o foo.s
gcc -O2 -c foo.c -o foo.o && objdump -d -M intel foo.o
- Map registers by role. Done when: every register in the fragment is classified.
| Register | 32-bit view | Role |
|---|---|---|
rax |
eax |
Accumulator, 1st return value, caller saved |
rbx |
ebx |
Base, callee saved |
rcx |
ecx |
4th argument, caller saved |
rdx |
edx |
3rd argument, 2nd return value, caller saved |
rsi |
esi |
2nd argument, caller saved |
rdi |
edi |
1st argument, caller saved |
rbp |
ebp |
Frame pointer, callee saved |
rsp |
esp |
Stack pointer |
r8 to r11 |
5th through 8th arguments, caller saved | |
r12 to r15 |
Callee saved | |
rflags |
flags |
Condition codes |
xmm0 to xmm7 |
FP and SIMD arguments and returns | |
xmm8 to xmm15 |
FP and SIMD scratch, caller saved |
System V argument order: integer and pointer args in rdi, rsi, rdx, rcx, r8, r9, then the stack; float and vector args in xmm0 to xmm7.
- Respect the stack rules.
rspstays 16-byte aligned before acall, because the call pushes 8 bytes and the callee expects alignment. The red zone is the 128 bytes belowrspthat leaf functions may use without adjustingrsp. Kernel code compiles with-mno-red-zonebecause interrupts do not honor it. Done when: the drafted prologue keeps the alignment and names the red-zone choice.
push rbp
mov rbp, rsp
sub rsp, 16 # keep rsp a multiple of 16 before call sites
- Read the recurring instruction shapes. Done when: each line in the fragment parses.
| Pattern | Meaning |
|---|---|
mov %rdi, -8(%rbp) |
Store the first argument to a local slot |
mov (%rdi), %rax |
Load 8 bytes from the address in rdi |
lea 8(%rdi), %rax |
Compute an address without memory access |
addq $8, %rdi |
Advance a pointer by one element |
push %rbp then pop %rbp |
Frame save and restore |
call func then ret |
Call pushes the return address, ret pops it |
leave |
mov %rbp, %rsp then pop %rbp |
test %rax, %rax |
Set flags from rax == 0 cheaply |
cmp $0, %rax |
Same flag result, one byte longer |
sete %al |
Copy ZF into a byte register |
cmovne %rdx, %rax |
Conditional move, branchless select |
- Choose a syntax and stay in it. AT&T puts the source operand first and prefixes registers and immediates; Intel puts the destination first. Done when: the listing and the written code use one syntax.
| AT&T | Intel |
|---|---|
mov %rax, %rbx |
mov rbx, rax |
mov $8, %rax |
mov rax, 8 |
movb %al, (%rdi) |
mov byte ptr [rdi], al |
| Default in GCC | -masm=intel or objdump -M intel |
- Write inline asm with the extended syntax. The template lists outputs, inputs, and clobbers. Constraint codes:
rgeneral register,a/b/c/dspecific ones,mmemory,iimmediate. Tell the compiler about memory effects with"memory". Done when: the fragment compiles and survives optimization with correct results.
static inline long cpuid_leaf(long leaf) {
long a, b, c, d;
__asm__ volatile("cpuid"
: "=a"(a), "=b"(b), "=c"(c), "=d"(d)
: "a"(leaf));
return a;
}
static inline int atomic_incr(int *p) {
int ret;
__asm__ volatile("lock xaddl %0, %1"
: "=r"(ret), "+m"(*p) // +m: read and written
: "0"(1));
return ret; // returns the previous value
}
- Recognize the SSE and AVX headers when reading vector code.
<xmmintrin.h>provides SSE,<emmintrin.h>SSE2, and<immintrin.h>everything through AVX-512. For choosing and writing intrinsics usesimd-intrinsics. Done when: vector code under discussion is attributed to its instruction set level.
Failure and recovery
| Failure class | Behavior |
|---|---|
Crash after a call in hand-written asm |
Stack misalignment. Re-align rsp to 16 before every call site. |
Inline asm result wrong at -O2 |
Missing volatile, a wrong constraint, or a missing "memory" clobber. Fix the declaration, not the build flags. |
lock prefix rejected |
The destination is a register or the assembler is 16-bit mode. lock needs a memory destination. |
| Intel-syntax source fails to build | The file mixes syntaxes. Convert with objdump -M intel as reference, and compile with one syntax. |
| Value lost across a call | It sat in a caller-saved register. Move it to rbx, r12 to r15, or spill it. |
Output
Annotated assembly or inline asm with register roles, stack alignment stated, and clobbers justified. The full instruction tables, flags register map, conditional jump list, and prologue patterns are in references/reference.md.
Files (outline-driven-development)
-
agents
-
openai.yaml 197 B
interface: display_name: "Assembly X86" short_description: "Use when reading GCC or Clang x86-64 assembly, writing inline asm, decoding AT&T syntax, or applying System V AMD64 register rules."
-
-
references
-
reference.md 4 KB
# x86-64 assembly reference Sources: Intel SDM, the System V AMD64 ABI, and GCC inline asm documentation. ## Data movement | Instruction | Effect | |-------------|--------| | `mov src, dst` | Copy | | `movzx src, dst` | Copy with zero extend | | `movsx src, dst` | Copy with sign extend | | `lea mem, reg` | Compute the address into a register, no memory access | | `push reg` | Push onto the stack | | `pop reg` | Pop from the stack | | `xchg a, b` | Exchange operands, implicit `LOCK` for memory | | `cmpxchg a, b` | Compare and exchange, sets `ZF` | ## Arithmetic | Instruction | Effect | |-------------|--------| | `add src, dst` | `dst += src` | | `sub src, dst` | `dst -= src` | | `imul r/m` | Signed multiply, `rdx:rax = rax * operand` in one-operand form | | `mul r/m` | Unsigned multiply, same two-operand split | | `idiv r/m` | Signed divide, quotient in `rax`, remainder in `rdx` | | `div r/m` | Unsigned divide, same split | | `inc`, `dec` | Increment, decrement without touching `CF` | | `neg dst` | Two's complement negate | ## Bit operations | Instruction | Effect | |-------------|--------| | `and`, `or`, `xor`, `not` | Bitwise logic | | `shl`/`sal` | Shift left | | `shr` | Shift right, logical | | `sar` | Shift right, arithmetic | | `rol`, `ror`, `rcl`, `rcr` | Rotates through carry or not | | `bsf src, dst` | Index of lowest set bit | | `bsr src, dst` | Index of highest set bit | | `tzcnt`, `lzcnt` | Trailing and leading zero counts, BMI or ABM | | `popcnt` | Count set bits | | `bt`, `bts`, `btr`, `btc` | Bit test and set, reset, complement | ## Comparison and branching | Instruction | Effect | |-------------|--------| | `cmp a, b` | Set flags from `a - b` without storing | | `test a, b` | Set flags from `a & b` without storing | | `jmp target` | Unconditional jump | | `jcc target` | Conditional jump, see the table below | | `cmovcc src, dst` | Conditional move | | `setcc reg8` | Store the condition as 0 or 1 | | `loop label` | Decrement `rcx`, jump when nonzero | ## rflags bits | Bit | Flag | Set when | |-----|------|----------| | CF | Carry | Unsigned overflow | | PF | Parity | Low byte has an even count of set bits | | AF | Adjust | Carry from bit 3 to bit 4 | | ZF | Zero | Result is zero | | SF | Sign | Result is negative | | TF | Trap | Single step enabled | | IF | Interrupt | Interrupts enabled | | DF | Direction | String ops go downward | | OF | Overflow | Signed overflow | ## Conditional jumps | Instruction | Condition | Flags | |-------------|-----------|-------| | `je`/`jz` | Equal | `ZF=1` | | `jne`/`jnz` | Not equal | `ZF=0` | | `js` | Sign set | `SF=1` | | `jns` | Sign clear | `SF=0` | | `jc` | Carry | `CF=1` | | `jnc` | No carry | `CF=0` | | `jo` | Overflow | `OF=1` | | `jno` | No overflow | `OF=0` | | `jl`/`jnge` | Signed less | `SF!=OF` | | `jle`/`jng` | Signed less or equal | `ZF=1` or `SF!=OF` | | `jg`/`jnle` | Signed greater | `ZF=0` and `SF=OF` | | `jge`/`jnl` | Signed greater or equal | `SF=OF` | | `jb`/`jnae` | Unsigned below | `CF=1` | | `jbe`/`jna` | Unsigned below or equal | `CF=1` or `ZF=1` | | `ja`/`jnbe` | Unsigned above | `CF=0` and `ZF=0` | | `jae`/`jnb` | Unsigned above or equal | `CF=0` | ## SIMD header map | Header | Provides | |--------|----------| | `<xmmintrin.h>` | SSE, `__m128` | | `<emmintrin.h>` | SSE2, `__m128d` and `__m128i` | | `<pmmintrin.h>` | SSE3 | | `<tmmintrin.h>` | SSSE3 | | `<smmintrin.h>` | SSE4.1 | | `<nmmintrin.h>` | SSE4.2 | | `<immintrin.h>` | Everything through AVX-512, use this one | ## Prologue patterns Frame pointer kept: ```asm push %rbp mov %rsp, %rbp sub $N, %rsp # allocate locals, keep rsp 16-byte aligned # body leave # mov %rbp, %rsp; pop %rbp ret ``` Frame pointer omitted, the default at `-O2`: ```asm sub $N, %rsp # body, locals addressed through rsp add $N, %rsp ret ``` Callee-saved registers used by the body: ```asm push %rbx push %r12 push %r13 # body that uses rbx, r12, r13 pop %r13 pop %r12 pop %rbx ret ``` Restore in reverse push order. On Linux the kernel is built with `-mno-red-zone`, so kernel-mode code never relies on the 128-byte red zone.
-
-
SKILL.md 6 KB
--- name: assembly-x86 description: 'Use when reading GCC or Clang x86-64 assembly, writing inline asm, decoding AT&T syntax, or applying System V AMD64 register rules. Not for SIMD intrinsic selection: use simd-intrinsics.' --- # x86-64 assembly GCC and Clang emit AT&T syntax by default. This skill reads that output, writes inline asm, and keeps register use inside the System V AMD64 ABI. ## Contract | Field | Bound contract | |---|---| | Trigger | The task reads compiler assembly output, writes inline asm in C or C++, decides AT&T versus Intel syntax, or explains calling conventions and stack layout in a disassembly. | | Authority | Read-only. The skill explains and drafts; edits land through the normal coding path. No remote mutation. | | Side effect | None. | | Done | The drafted assembly assembles with `gcc -c` or `clang -c`, or the compiler output under discussion is explained register by register. | ## Inputs - The C or C++ source, compiler output, or assembly fragment: required. - The compiler: required. AT&T versus Intel output and inline asm details follow it. - The ABI: required. System V for Linux and macOS; the Microsoft x64 ABI changes the register map entirely. ## Procedure 1. Generate the baseline. Read the compiler's own output before writing any. Done when: the disassembly of the function under discussion is on screen. ```bash gcc -O2 -S -fverbose-asm foo.c -o foo.s gcc -O2 -c foo.c -o foo.o && objdump -d -M intel foo.o ``` 2. Map registers by role. Done when: every register in the fragment is classified. | Register | 32-bit view | Role | |----------|-------------|------| | `rax` | `eax` | Accumulator, 1st return value, caller saved | | `rbx` | `ebx` | Base, callee saved | | `rcx` | `ecx` | 4th argument, caller saved | | `rdx` | `edx` | 3rd argument, 2nd return value, caller saved | | `rsi` | `esi` | 2nd argument, caller saved | | `rdi` | `edi` | 1st argument, caller saved | | `rbp` | `ebp` | Frame pointer, callee saved | | `rsp` | `esp` | Stack pointer | | `r8` to `r11` | | 5th through 8th arguments, caller saved | | `r12` to `r15` | | Callee saved | | `rflags` | `flags` | Condition codes | | `xmm0` to `xmm7` | | FP and SIMD arguments and returns | | `xmm8` to `xmm15` | | FP and SIMD scratch, caller saved | System V argument order: integer and pointer args in `rdi, rsi, rdx, rcx, r8, r9`, then the stack; float and vector args in `xmm0` to `xmm7`. 3. Respect the stack rules. `rsp` stays 16-byte aligned before a `call`, because the call pushes 8 bytes and the callee expects alignment. The red zone is the 128 bytes below `rsp` that leaf functions may use without adjusting `rsp`. Kernel code compiles with `-mno-red-zone` because interrupts do not honor it. Done when: the drafted prologue keeps the alignment and names the red-zone choice. ```asm push rbp mov rbp, rsp sub rsp, 16 # keep rsp a multiple of 16 before call sites ``` 4. Read the recurring instruction shapes. Done when: each line in the fragment parses. | Pattern | Meaning | |---------|---------| | `mov %rdi, -8(%rbp)` | Store the first argument to a local slot | | `mov (%rdi), %rax` | Load 8 bytes from the address in `rdi` | | `lea 8(%rdi), %rax` | Compute an address without memory access | | `addq $8, %rdi` | Advance a pointer by one element | | `push %rbp` then `pop %rbp` | Frame save and restore | | `call func` then `ret` | Call pushes the return address, `ret` pops it | | `leave` | `mov %rbp, %rsp` then `pop %rbp` | | `test %rax, %rax` | Set flags from `rax == 0` cheaply | | `cmp $0, %rax` | Same flag result, one byte longer | | `sete %al` | Copy `ZF` into a byte register | | `cmovne %rdx, %rax` | Conditional move, branchless select | 5. Choose a syntax and stay in it. AT&T puts the source operand first and prefixes registers and immediates; Intel puts the destination first. Done when: the listing and the written code use one syntax. | AT&T | Intel | |------|-------| | `mov %rax, %rbx` | `mov rbx, rax` | | `mov $8, %rax` | `mov rax, 8` | | `movb %al, (%rdi)` | `mov byte ptr [rdi], al` | | Default in GCC | `-masm=intel` or `objdump -M intel` | 6. Write inline asm with the extended syntax. The template lists outputs, inputs, and clobbers. Constraint codes: `r` general register, `a`/`b`/`c`/`d` specific ones, `m` memory, `i` immediate. Tell the compiler about memory effects with `"memory"`. Done when: the fragment compiles and survives optimization with correct results. ```c static inline long cpuid_leaf(long leaf) { long a, b, c, d; __asm__ volatile("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(leaf)); return a; } ``` ```c static inline int atomic_incr(int *p) { int ret; __asm__ volatile("lock xaddl %0, %1" : "=r"(ret), "+m"(*p) // +m: read and written : "0"(1)); return ret; // returns the previous value } ``` 7. Recognize the SSE and AVX headers when reading vector code. `<xmmintrin.h>` provides SSE, `<emmintrin.h>` SSE2, and `<immintrin.h>` everything through AVX-512. For choosing and writing intrinsics use `simd-intrinsics`. Done when: vector code under discussion is attributed to its instruction set level. ## Failure and recovery | Failure class | Behavior | |---|---| | Crash after a `call` in hand-written asm | Stack misalignment. Re-align `rsp` to 16 before every call site. | | Inline asm result wrong at `-O2` | Missing `volatile`, a wrong constraint, or a missing `"memory"` clobber. Fix the declaration, not the build flags. | | `lock` prefix rejected | The destination is a register or the assembler is 16-bit mode. `lock` needs a memory destination. | | Intel-syntax source fails to build | The file mixes syntaxes. Convert with `objdump -M intel` as reference, and compile with one syntax. | | Value lost across a call | It sat in a caller-saved register. Move it to `rbx`, `r12` to `r15`, or spill it. | ## Output Annotated assembly or inline asm with register roles, stack alignment stated, and clobbers justified. The full instruction tables, flags register map, conditional jump list, and prologue patterns are in `references/reference.md`.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.