Fil-C on Nix

Filnix wiki

mbrock/filnix/nanofil

asm.pl

x86-64 assembly as terms, and their printer as GNU as (AT&T) text. The backends build a list of lines; this module is the only place that knows AT&T syntax.

Lines

LinePrints as
labelSS:
insOp, Suffix, OperandsOp, then Suffix unless it is none, then the operands in AT&T order (sources first)
a directivethe directive, below
DirectivePrints as
sectionSthe section S: text, data, rodata, bss, tbss (thread-local, zeroed), data_rel_ro, note_gnu_stack, or initctor | dtor, Priority for .init_array or .fini_array, with .Priority unless it is none
p2alignN balignN.p2align N, .balign N
globlS weakS hiddenS.globl S, .weak S, .hidden S
typeS, T.type S, @T, T function or object
sizeS.size S, .-S
sizeS, N.size S, N
setS, E.set S, E
quadE.quad E
longN intN shortN.long N, .int N, .short N
byteNs.byte and the non-empty list Ns
zeroN.zero N
asciiChars.ascii and the characters, escaped
ascizAtom.asciz and the atom, as it is

Operands

Operands name concrete registers, so mixed widths such as movzbl %al, %eax need no width bookkeeping.

OperandPrints as
immE$E
regR%R, for example regeax, regcl, regr9d
memD, BD(%B), D omitted when 0
memD, B, ID(%B,%I), D omitted when 0
ripEE(%rip)
gotpcrelSS@GOTPCREL(%rip)
pltSS@PLT
gottpoffSS@GOTTPOFF(%rip), the GOT slot of thread-local S's offset from %fs
fsO%fs:O, memory operand O in the thread segment
symEE, a jump or call target
indO*O

An expression E is an integer, a symbol atom or E1+E2; a left operand that is itself a sum is parenthesized.

moduleasm
useslists
usesdcgs
usesformat
78lines_text[], Cs, Cs
79lines_textLine|Lines, Cs0, Cs ←
lineLine, Cs0, Cs1
lines_textLines, Cs1, Cs

The text of one line, committed to its first parse.

84lineLine, Cs0, Cs ←
line_textLine, Cs0, Cs
→
true
else
thrownanofil_errorbad_asm_lineLine
89line_charsLine, Cs ←
phraseline_textLine, Parts
atomic_list_concatParts, Text
atom_charsText, Cs
line_text+Line//

the text of Line. directive//1 has no clause for label/1 or ins/3, so the cases are disjoint; line//1 commits to the first parse.

97line_textlabelS ⟶
":\n"

A fixed-register asm (docs/asm-fixed.md) from the emitter's own table. cpuid writes rbx, which may hold a register home: it is kept in rsi, and cpuid's b result is brought out in edi.

103line_textasm_fixedcpuid ⟶
!
"\tmovq %rbx, %rsi\n\tcpuid\n\tmovl %ebx, %edi\n\tmovq %rsi, %rbx\n"
105line_textasm_fixedM ⟶
memberchkM, xgetbv, rdtsc, rdtscp, lfence, sfence, pause
!
"\t"
"\n"
108line_textinsOp, Suffix, Operands ⟶
"\t"
suffixSuffix
operandsOperands
"\n"
114line_textDirective ⟶
"\t"
directiveDirective
"\n"

The cut is for the default case: a suffix is none or any other atom (a defaulty term shared with the backends).

121suffixnone ⟶
!
122suffixS ⟶
124operands[] ⟶
[]
125operandsO|Os ⟶
130more_operands[] ⟶
[]
131more_operandsO|Os ⟶
136operandimmE ⟶
"$"
137operandregR ⟶
138operandmemD, B ⟶
"(%"
")"
139operandmemD, B, I ⟶
"(%"
",%"
")"
140operandripE ⟶
"(%rip)"
141operandgotpcrelS ⟶
"@GOTPCREL(%rip)"
142operandpltS ⟶
"@PLT"
143operandgottpoffS ⟶
"@GOTTPOFF(%rip)"
144operandfsO ⟶
"%fs:"
145operandsymE ⟶
146operandindO ⟶

A displacement of 0 is omitted; the cut is for the default case.

149disp0 ⟶
!
150dispD ⟶

A sum whose left operand is itself a sum parenthesizes it. The cut is for the default case, an integer or symbol (a defaulty term shared with the backends; literal//1 would throw on a sum).

155exprA + B ⟶
!
A = _ + _
→
"("
")"
else
"+"
162exprE ⟶
164directivesectionS ⟶
165directivep2alignN ⟶
".p2align "
166directivebalignN ⟶
".balign "
167directivegloblS ⟶
".globl "
168directiveweakS ⟶
".weak "
169directivehiddenS ⟶
".hidden "
170directivetypeS, T ⟶
".type "
", @"
171directivesizeS ⟶
".size "
", .-"
172directivesizeS, N ⟶
".size "
", "
173directivesetS, E ⟶
".set "
", "
174directivequadE ⟶
".quad "
175directivelongN ⟶
".long "
176directiveintN ⟶
".int "
177directiveshortN ⟶
".short "
178directivebyteN|Ns ⟶
179directivezeroN ⟶
".zero "
180directiveasciiCs ⟶
".ascii \""
"\""
181directiveascizA ⟶
".asciz \""
"\""
ascii_chars+Cs//

the bytes Cs, one per character, 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 three octal digits.

187ascii_chars[] ⟶
[]
188ascii_charsC|Cs ⟶
190ascii_char'"' ⟶
!
"\\\""
191ascii_char\ ⟶
!
"\\\\"
192ascii_char'\n' ⟶
!
"\\n"
193ascii_char'\t' ⟶
!
"\\t"
194ascii_charC ⟶
char_codeC, N
N ≥ 32
N ≤ 126
!
C
195ascii_charC ⟶
char_codeC, N
maplistoctal_charN, 6, 3, 0, Os
"\\"
octal_char+N, +Shift, -O

O is the octal digit of N at bit Shift.

201octal_charN, Shift, O ←
D is N >> Shift /\ 7 + 0'0
char_codeO, D
203more_bytes[] ⟶
[]
204more_bytesN|Ns ⟶
section_name?Section, ?Name

Name is the directive text of Section.

210section_nametext, ".text"
211section_namedata, ".data"
212section_namerodata, ".section .rodata"
213section_namebss, ".bss"
214section_nametbss, ".section .tbss,\"awT\",@nobits"
215section_namedata_rel_ro, ".section .data.rel.ro,\"aw\",@progbits"
216section_namenote_gnu_stack, ".section .note.GNU-stack,\"\",@progbits"
217section_nameinitKind, Prio, Name ←
.init_array[.Prio], .fini_array[.Prio]
nonvarKind
Kind ≡ ctor
→
Array = init_array
else
Array = fini_array
Prio ≡ none
→
formatatomA, '.section .~w,"aw",@~w', Array, Array
else
formatatomA, '.section .~w.~w,"aw",@~w', Array, Prio, Array
atom_charsA, Name

The text of an atom or number, as one part.

227literalX ⟶
atomicX
X
chars+Cs//

the characters Cs, as parts.

230charsCs, S0, S ←
appendCs, S, S0