Fil-C on Nix

Filnix wiki

the formal campaign

rocq/backend/Asm.v

x86-64 assembly as the backend builds it, and its printer as GNU as (AT&T) text: asm.pl's line terms as inductives, and asm.pl's grammar as functions. The text is asm.pl's byte for byte, which the backend's gate checks on every line the Prolog compiler emits for the corpus (asm.sh).

Mnemonics, suffixes and register names are strings, as they are atoms in asm.pl: the set is whatever instruction selection uses, and this file only prints.

From Stdlib Require Import String ZArith List Ascii Bool
From Backend Require Import Text
Import ListNotations
Open Scope string_scope

What asm.pl prints with literal//1: an integer or an atom.

17Inductive lit: Type ≔
|LInt
n : Z
an integer, in decimal
|LSym
s : string
an atom, as it is

An expression: a literal or a sum.

22Inductive expr: Type ≔
|ELit
a : lit
|EAdd
a b : expr
A + B; a left operand that is a sum is parenthesized

An operand. Registers are named concretely (eax, cl, r9d), so mixed widths need no bookkeeping.

28Inductive operand: Type ≔
|OImm
e : expr
$E
|OReg
r : string
%R
|OMem
d : lit b : string
D(%B), D omitted when it is 0
|OMemIndex
d : lit b i : string
D(%B,%I), D omitted when it is 0
|ORip
e : expr
E(%rip)
|OGotpcrel
s : lit
S@GOTPCREL(%rip)
|OPlt
s : lit
S@PLT
|OGottpoff
s : lit
S@GOTTPOFF(%rip)
|OFs
o : operand
%fs:O
|OSym
e : expr
E, a jump or call target
|OInd
o : operand
*O

A section.

42Inductive section: Type ≔
|SText
|SData
|SRodata
|SBss
|STbss
thread-local, zeroed
|SDataRelRo
|SNoteGnuStack
|SInit
ctor : bool prio : optionlit
.init_array or .fini_array, with .Prio if any

A directive.

53Inductive directive: Type ≔
|DSection
s : section
|DP2align
n : lit
|DBalign
n : lit
|DGlobl
s : lit
|DWeak
s : lit
|DHidden
s : lit
|DType
s t : lit
.type S, @T
|DSize
s : lit
.size S, .-S
|DSizeOf
s n : lit
.size S, N
|DSet
s : lit e : expr
|DQuad
e : expr
|DLong
n : lit
|DInt
n : lit
|DShort
n : lit
|DByte
n : lit ns : listlit
.byte and a non-empty list
|DZero
n : lit
|DAscii
cs : listascii
.ascii and the bytes, escaped
|DAsciz
a : lit
.asciz and the atom, as it is

A fixed-register instruction from the emitter's own table (docs/asm-fixed.md).

75Inductive fixed: Type ≔
|Cpuid
|Xgetbv
|Rdtsc
|Rdtscp
|Lfence
|Sfence
|Pause

A line.

85Inductive line: Type ≔
|Label
s : lit
S:
|Fixed
m : fixed
|Ins
op : string suffix : optionstring os : listoperand

Op, then the suffix if any, then the operands in AT&T order

|Dir
d : directive

The printer

The text of a literal.

95Definition lit_texta : lit : string ≔
match a with
⇒
s
101Fixpoint expr_partse : expr k : parts : parts ≔
match e with
⇒
lit_texta :: k
EAdda b
⇒
let rest ≔ "+" :: expr_partsb k in
match a with
EAdd_ _
⇒
"(" :: expr_partsa ")" :: rest
⇒

A displacement; 0 is omitted.

113Definition disp_partsd : lit k : parts : parts ≔
match d with
⇒
k
_
⇒
lit_textd :: k
119Fixpoint operand_partso : operand k : parts : parts ≔
match o with
⇒
"$" :: expr_partse k
⇒
"%" :: r :: k
OMemd b
⇒
disp_partsd "(%" :: b :: ")" :: k
⇒
disp_partsd "(%" :: b :: ",%" :: i :: ")" :: k
⇒
expr_partse "(%rip)" :: k
⇒
lit_texts :: "@GOTPCREL(%rip)" :: k
⇒
lit_texts :: "@PLT" :: k
⇒
lit_texts :: "@GOTTPOFF(%rip)" :: k
OFso′
⇒
"%fs:" :: operand_partso′ k
OIndo′
⇒
"*" :: operand_partso′ k
134Fixpoint more_operandsos : listoperand k : parts : parts ≔
match os with
[ ]
⇒
k
o :: os′
⇒
", " :: operand_partso more_operandsos′ k

The operands after a mnemonic: a space, then the operands with commas between them, or nothing.

142Definition operands_partsos : listoperand k : parts : parts ≔
match os with
[ ]
⇒
k
o :: os′
⇒
148Fixpoint more_bytesns : listlit k : parts : parts ≔
match ns with
[ ]
⇒
k
n :: ns′
⇒
", " :: lit_textn :: more_bytesns′ k

A byte in three octal digits.

155Definition octaln : nat : string ≔
digitn / 64 ++ digitn / 8 mod 8 ++ digitn mod 8

One byte inside an .ascii string: printable ASCII as itself except quote and backslash, which are escaped, newline and tab as \n and \t, any other byte as a backslash and three octal digits.

161Definition ascii_char_textc : ascii : string ≔
let n ≔ nat_of_asciic in
n =? 34%nat
→
"\"""
n =? 92%nat
→
"\\"
n =? 10%nat
→
"\n"
n =? 9%nat
→
"\t"
32 ≤? n && n ≤? 126%nat
→
Stringc EmptyString
else
"\" ++ octaln
170Fixpoint ascii_partscs : listascii k : parts : parts ≔
match cs with
[ ]
⇒
k
c :: cs′
⇒
176Definition section_partss : section k : parts : parts ≔
match s with
⇒
".text" :: k
⇒
".data" :: k
⇒
".section .rodata" :: k
⇒
".bss" :: k
⇒
".section .tbss,""awT"",@nobits" :: k
⇒
".section .data.rel.ro,""aw"",@progbits" :: k
⇒
".section .note.GNU-stack,"""",@progbits" :: k
SInitctor prio
⇒
let array ≔
ctor
→
"init_array"
else
"fini_array"
in
let rest ≔ ",""aw"",@" :: array :: k in
".section ."
::
array
::
match prio with
None
⇒
rest
Somep
⇒
"." :: lit_textp :: rest
195Definition directive_partsd : directive k : parts : parts ≔
match d with
⇒
".p2align " :: lit_textn :: k
⇒
".balign " :: lit_textn :: k
⇒
".globl " :: lit_texts :: k
⇒
".weak " :: lit_texts :: k
⇒
".hidden " :: lit_texts :: k
⇒
".type " :: lit_texts :: ", @" :: lit_textt :: k
⇒
".size " :: lit_texts :: ", .-" :: lit_texts :: k
⇒
".size " :: lit_texts :: ", " :: lit_textn :: k
DSets e
⇒
".set " :: lit_texts :: ", " :: expr_partse k
⇒
".quad " :: expr_partse k
⇒
".long " :: lit_textn :: k
⇒
".int " :: lit_textn :: k
⇒
".short " :: lit_textn :: k
DByten ns
⇒
".byte " :: lit_textn :: more_bytesns k
⇒
".zero " :: lit_textn :: k
⇒
".ascii """ :: ascii_partscs """" :: k
⇒
".asciz """ :: lit_texta :: """" :: k
217Definition fixed_namem : fixed : string ≔
match m with
⇒
"cpuid"
⇒
"xgetbv"
⇒
"rdtsc"
⇒
"rdtscp"
⇒
"lfence"
⇒
"sfence"
⇒
"pause"

cpuid writes rbx, which may hold a register home: it is kept in rsi, and cpuid's b result is brought out in edi.

230Definition cpuid_text: string ≔
tab ++ "movq %rbx, %rsi" ++ nl ++ tab ++ "cpuid" ++ nl ++ tab ++ "movl %ebx, %edi" ++ nl ++ tab ++ "movq %rsi, %rbx" ++ nl
234Definition line_partsl : line k : parts : parts ≔
match l with
⇒
lit_texts :: ":" :: nl :: k
⇒
tab :: fixed_namem :: nl :: k
Insop suffix os
⇒
let rest ≔ operands_partsos nl :: k in
::
op
::
match suffix with
None
⇒
rest
Somes
⇒
s :: rest
⇒

The parts of the lines in rev, which is the lines in reverse, in front of k. A loop, so a module of any length prints in constant stack.

252Fixpoint rev_lines_partsrev : listline k : parts : parts ≔
match rev with
[ ]
⇒
k
l :: rev′
⇒

The text of ls.

259Definition lines_partsls : listline : parts ≔
rev_lines_partsrev'ls [ ]
Proof 1 step Qed
reflexivity