Fil-C on Nix

Filnix wiki

the formal campaign

rocq/backend/EmitObject.v

# Function objects

Every function has a getter, a generic entry and a function object, so that its address can be taken; an exported one also has the public alias of its implementation and a global getter. As filc_amd64.pl's function_object//5 and variadic_object//4. The generic entry adapts a packet of cells in the thread to the fast convention and the fast result back to a packet.

From Stdlib Require Import String ZArith List Bool
From Nanofil Require Import Term Syntax Maps
From Backend Require Import Text Asm Plan PlanTerm Layout
Import ListNotations
Open Scope string_scope
Open Scope Z_scope
Open Scope list_scope

Adapter operands

Where an adapter reads a word of the fast call from: memory, a register, or the aux word at an offset of a promoted packet, which has no aux if %r13 is null.

23Inductive adapter_operand: Type ≔
|AoMem
off : Z base : string
|AoReg
r : string
|AoSnapshotLower
off : Z

As channel_offset/2: the thread offset of a generic cell's data or aux word.

30Definition channel_offsets : source : optionZ ≔
match s with

As adapter_operand/3: for the area thread the cells are in the thread at %rbx; for snapshot they are in the promoted packet at %r12.

40Definition adapter_operand_ofsnapshot : bool s : source : optionadapter_operand ≔
snapshot
→
match s with
⇒
SomeAoMemeight × i "r12"
⇒
SomeAoReg"r12"
_
⇒
None
else
option_mapλoff ⇒ AoMemoff "rbx" channel_offsets

As snapshot_load//2: the operand into %rax.

51Definition snapshot_loado : adapter_operand g : string : listline ≔
match o with
⇒
ins"mov" "q" regr; reg"rax"
AoMemoff b
⇒
ins"mov" "q" memoff b; reg"rax"
⇒
let noaux ≔ g ++ ".lower." ++ decimaloff%string in
ins"xor" "l" reg"eax"; reg"eax"; ins"test" "q" reg"r13"; reg"r13"; ins0"jz" symnoaux; ins"mov" "q" memoff "r13"; reg"rax"; labelnoaux
64Definition is_singlek : class : bool ≔
match k with
⇒
true
_
⇒
false

As adapter_load//3: a single is the low half of its word.

67Definition adapter_loadk : class o : adapter_operand g : string : listline ≔
++
→
ins"mov" "l" reg"eax"; reg"eax"
else
[ ]

A word of the adapter's fast call and its operand.

71Definition adapter_wordsnapshot : bool w : word : class × optionadapter_operand ≔
match w with
Wfk s
⇒
k, adapter_operand_ofsnapshot s

As adapter_stack//3: the words that travel on the stack, through %rax, which is the only scratch register.

76Fixpoint adapter_stackts : listclass × optionadapter_operand ls : listlocation g : string : listline ≔
match ts, ls with
k, o :: ts′, l :: ls′
⇒
match l, o with
LocStacki, Someo′
⇒
adapter_loadk o′ g ++ ins"mov" "q" reg"rax"; memeight × i "rsp"
LocStack_, None
⇒
todo"adapter source"
_, _
⇒
[ ]
++
adapter_stackts′ ls′ g
_, _
⇒
[ ]

As adapter_registers//3: an integer register takes a word in memory directly.

92Fixpoint adapter_registersts : listclass × optionadapter_operand ls : listlocation g : string : listline ≔
match ts, ls with
k, o :: ts′, l :: ls′
⇒
match l, o with
⇒
[ ]
_, None
⇒
todo"adapter source"
LocRegr, SomeAoMemoff b
⇒
→
adapter_loadk AoMemoff b g ++ ins"mov" "q" reg"rax"; regreg64r
else
ins"mov" "q" memoff b; regreg64r
LocRegr, Someo′
⇒
adapter_loadk o′ g ++ ins"mov" "q" reg"rax"; regreg64r
LocXmmx, Someo′
⇒
adapter_loadk o′ g ++ to_xmmk "a" x
++
adapter_registersts′ ls′ g
_, _
⇒
[ ]

The generic result

As generic_zeroings//1.

113Definition generic_zeroingsoffs : listZ : listline ≔
mapλoff ⇒ ins"mov" "q" imm0; memoff "rbx" offs

As generic_reg_stores//2: each result register at its thread offset.

118Fixpoint generic_reg_storesoffs : listZ rs : liststring : listline ≔
match offs, rs with
[ ], _
⇒
[ ]
off :: offs′, r :: rs′
⇒
ins"mov" "q" regr; memoff "rbx" :: generic_reg_storesoffs′ rs′
_ :: _, [ ]
⇒
todo"result registers"

As generic_buffer_copies//2: each word of the return buffer, from off(%rsp) on, to its thread offset.

128Fixpoint generic_buffer_copiesdests : listZ off : Z : listline ≔
match dests with
[ ]
⇒
[ ]
d :: dests′
⇒
ins"mov" "q" memoff "rsp"; reg"rax"; ins"mov" "q" reg"rax"; memd "rbx" ++ generic_buffer_copiesdests′ off + eight

As typed_ret_kind/3: a pointer of a returned tuple is two integer words.

138Definition typed_ret_kindsks : listclass : listclass ≔
flat_map
λ k  ⇒
match k with
⇒
L; L
_
⇒
k
ks

As generic_typed_gprs//2 and generic_typed_xmms//2, over the registers result_registers/2 gives the words.

143Fixpoint generic_typed_gprsrs : listresult_reg offs : listZ : listline ≔
match rs, offs with
[ ], [ ]
⇒
[ ]
r :: rs′, off :: offs′
⇒
match r with
⇒
ins"mov" "q" regg; memoff "rbx"
⇒
[ ]
++
generic_typed_gprsrs′ offs′
_, _
⇒
todo"result registers"
155Fixpoint generic_typed_xmmsrs : listresult_reg offs : listZ : listline ≔
match rs, offs with
[ ], [ ]
⇒
[ ]
r :: rs′, off :: offs′
⇒
match r with
⇒
from_xmmk x "a" ++ ins"mov" "q" reg"rax"; memoff "rbx"
⇒
[ ]
++
generic_typed_xmmsrs′ offs′
_, _
⇒
todo"result registers"

As generic_reg_results//2: the result words from their registers to their thread offsets; a void result is one zero word.

170Definition generic_reg_resultsc : adapter_channel dests zeros : listZ : listline ≔
match c with
⇒
match dests with
[ ]
⇒
_
⇒
todo"void result"
⇒
match dests, zeros with
off, lower
⇒
from_xmmk "xmm0" "d" ++ ins"mov" "q" reg"rdx"; memoff "rbx"; ins"mov" "q" imm0; memlower "rbx"
_, _
⇒
todo"float result"
⇒
match result_registerstyped_ret_kindsks "rdx"; "rcx" "xmm0"; "xmm1" with
Somers
⇒
generic_typed_gprsrs dests ++ generic_typed_xmmsrs dests ++ ins"xor" "l" reg"eax"; reg"eax" ++ generic_zeroingszeros
None
⇒
todo"result registers"
⇒
generic_reg_storesdests "rdx"; "rcx" ++ generic_zeroingszeros
191Definition stack_releasebytes : Z : listline ≔
bytes >? 0
→
ins"add" "q" immbytes; reg"rsp"
else
[ ]
193Definition reserve_stackbytes : Z : listline ≔
bytes >? 0
→
ins"sub" "q" immbytes; reg"rsp"
else
[ ]
195Definition ret_buffer_reservationr : protocol : listline ≔
match r with
⇒
[ ]
⇒
ins"sub" "q" immbuffer_bytesn; reg"rsp"
200Definition ret_buffer_releaser : protocol : listline ≔
match r with
⇒
[ ]
⇒
ins"add" "q" immbuffer_bytesn; reg"rsp"

The thread offsets of sources; None if one is not a cell.

207Fixpoint channel_offsetsss : listsource : optionlistZ ≔
match ss with
[ ]
⇒
Some[ ]
s :: ss′
⇒
Someo, Someos
⇒
Someo :: os
_, _
⇒
None

As generic_entry_call//6: the call of the fast entry of the function object in %rsi, then the result into the packet and its size in %edx. An exception skips the result.

220Definition generic_entry_callres : adapter_result pop : Z done : string : listline ≔
Somedests, Somezeros
⇒
match ar_returnres with
⇒
ins"call" "q" indmemfunction_object_fast_entry "rsi" ++ stack_releasepop ++ ins"test" "b" imm1; reg"al"; ins0"jnz" symdone ++ generic_reg_resultsar_channelres dests zeros ++ ins"mov" "l" immar_sizeres; reg"edx"; labeldone
⇒
ins"mov" "q" reg"rsi"; reg"rdx"; ins"mov" "q" reg"rbx"; reg"rsi"; ins"lea" "q" mempop "rsp"; reg"rdi"; ins"call" "q" indmemfunction_object_fast_entry "rdx" ++ stack_releasepop ++ ins"mov" "b" mem0 "rsp"; reg"al"; ins"test" "b" reg"al"; reg"al"; ins0"jnz" symdone ++ generic_buffer_copiesdests eight ++ generic_zeroingszeros ++ ins"mov" "l" immar_sizeres; reg"edx"; ins"xor" "l" reg"eax"; reg"eax"; labeldone ++ ret_buffer_releaseBuffern
_, _
⇒
todo"adapter packet"

The failure of an entry given fewer than need bytes of arguments.

251Definition short_argsshort : string need : Z : listline ≔
labelshort; ins"mov" "q" reg"rdx"; reg"rdi"; ins"mov" "l" immneed; reg"esi"; ins"xor" "l" reg"edx"; reg"edx"; ins0"call" plt"filc_cc_args_check_failure"; ins0"ud2" [ ]

As generic_entry//2: {i1, i64 ret_size} (thread, callee_lower, args_size).

261Definition generic_entrygeneric : string need : Z ws : listword res : adapter_result : listline ≔
let ts ≔ mapadapter_wordfalse ws in
let 'ls, ns, _ ≔ typed_locationsws ar_returnres in
let pop ≔ stack_bytesns in
DirDSectionSText; labelgeneric; ins"push" "q" reg"rbx"; ins"cmp" "q" immneed; reg"rdx"; ins0"jb" symgeneric ++ ".short"; ins"mov" "q" reg"rdi"; reg"rbx" ++ ret_buffer_reservationar_returnres ++ reserve_stackpop ++ adapter_stackts ls generic ++ adapter_registersts ls generic ++ generic_entry_callres pop generic ++ ".done" ++ ins"pop" "q" reg"rbx"; ins0"ret" [ ] ++ short_argsgeneric ++ ".short" need

As variadic_adapter//3: the generic entry of a variadic function, which promotes its packet to the heap and passes the snapshot to the private fast body, whose object is body. The promotion is the only exiting call before the body roots the snapshot.

284Definition variadic_adaptergeneric body : string need : Z ws : listword res : adapter_result : listline ≔
let ts ≔ mapadapter_wordtrue ws in
let 'ls, ns, _ ≔ typed_locationsws ar_returnres in
let pop ≔ stack_bytesns in
let aux ≔ generic ++ ".aux"%string in
DirDSectionSText; DirDTypeLSymgeneric LSym"function"; labelgeneric; ins"push" "q" reg"rbx"; ins"push" "q" reg"r12"; ins"push" "q" reg"r13"; ins"cmp" "q" immneed; reg"rdx"; ins0"jb" symgeneric ++ ".short"; ins"mov" "q" reg"rdi"; reg"rbx"; ins"mov" "q" reg"rdx"; reg"rsi"; ins0"call" plt"filc_promote_args_to_heap"; ins"mov" "q" reg"rax"; reg"r12"; ins"xor" "l" reg"r13d"; reg"r13d"; ins"test" "q" reg"rdx"; reg"rdx"; ins0"jz" symaux; ins"mov" "q" mem−8 "rdx"; reg"r13"; ins"movabs" "q" imm281474976710655; reg"rax"; ins"and" "q" reg"rax"; reg"r13"; labelaux ++ ret_buffer_reservationar_returnres ++ reserve_stackpop ++ adapter_stackts ls generic ++ adapter_registersts ls generic ++ ins"mov" "q" reg"rbx"; reg"rdi"; ins"lea" "q" ripbody; reg"rsi" ++ generic_entry_callres pop generic ++ ".done" ++ ins"pop" "q" reg"r13"; ins"pop" "q" reg"r12"; ins"pop" "q" reg"rbx"; ins0"ret" [ ] ++ short_argsgeneric ++ ".short" need

The object

S + 16, the address of the payload of the object s.

318Definition payload_ofs : string : expr ≔

As aux_bits/2 of [global, readonly, function].

321Definition function_object_flags: Z ≔
36873221949095936

As object_getter//2: the getter of the function object fo gives its flight pointer, whose lower is its address, in %rax and %rdx.

326Definition object_gettergetter fo : string : listline ≔
DirDTypeLSymgetter LSym"function"; labelgetter; ins"lea" "q" ORippayload_offo; reg"rax"; ins"mov" "q" reg"rax"; reg"rdx"; ins0"ret" [ ]

As function_object_data//4: the object with its entries (a symbol, or 0 for none) and its signature. Its header has upper = lower, so it cannot be read or written, and an aux word that points at itself.

336Definition function_object_datafo : string fast : optionstring generic : string sig : Z : listline ≔

A function's linkage.

347Inductive linkage: Type ≔
|LkExport
|LkLocal
|LkWeak
|LkOther
349Definition linkage_oft : term : linkage ≔
match t with
⇒
String.eqba "export"
→
String.eqba "local"
→
String.eqba "weak"
→

As linkage_alias//4: an exported function has the public alias fi of its implementation and a global getter; a weak one has a weak getter and no alias, since callers elsewhere go through their thunks to whichever definition the linker keeps.

363Definition linkage_aliasl : linkage fi impl getter : string : listline ≔
match l with
373Definition p2align4: line ≔

As function_object//5. The object of a function that is not local names its fast entry by a local alias, since a global implementation symbol is preemptible and the dynamic linker would bind the word to the first definition of the name.

379Definition function_objectname : string l : linkage sig need : Z ws : listword res : adapter_result impl : string : listline ≔
let fi ≔ entry_symbolSigNumbersig name in
let fo ≔ function_object_symbolname in
let getter ≔ getter_symbolname in
let generic ≔ ".L" ++ name ++ "..generic"%string in
let local ≔ ".L" ++ impl ++ ".local"%string in
linkage_aliasl fi impl getter
++
object_gettergetter fo
++
generic_entrygeneric need ws res
++
match l with
⇒
[ ]
_
⇒
DirDTypeLSymlocal LSym"function"; DirDSetLSymlocal ELitLSymimpl
++
++
Some
match l with
⇒
impl
_
⇒
local
generic
sig

As variadic_object//4: a variadic function has a generic entry only, which is public, and a private fast body.

398Definition variadic_objectname : string l : linkage need : Z ws : listword res : adapter_result impl : string : listline ≔
let fo ≔ function_object_symbolname in
let getter ≔ getter_symbolname in
let generic ≔ impl_symbol0 name in
let fi ≔ entry_symbolSigNumber0 name in
let body ≔ generic ++ ".body"%string in
linkage_aliasl fi generic getter ++ object_gettergetter fo ++ variadic_adaptergeneric body need ws res ++ DirDSectionSDataRelRo; p2align4; labelbody; quad_symimpl ++ function_object_datafo None generic 0

As body_function_object//4.

412Definition function_object_linescx : ctx p : plan impl : string : listline ≔
let l ≔ linkage_ofpl_linkagep in
match pl_objectp with
FastAndGenericsig need ws res
⇒
function_objectcx_namecx l sig need ws res impl
GenericOnlyneed ws res
⇒
variadic_objectcx_namecx l need ws res impl