< < # read absolute address # 0 -> address to read # 0 <- byte read [[ /rbx :popqReg ::internalAllocateInteger /rax :movqImmReg /rax :callqReg /rcx :popqReg /rax :pushqReg 8 /rcx /rcx :movqMemDisp8Reg /rcx /rcx :movzxMem8Reg64 /rcx 8 /rax :movqRegMemDisp8 /rbx :pushqReg :retn ]] /eypeek defv # write absolute address # 0 -> address to write # 1 -> value to write [[ /rbx :popqReg /rax :popqReg 8 /rax /rax :movqMemDisp8Reg /rcx :popqReg 8 /rcx /rcx :movqMemDisp8Reg /cl /rax :movbRegMem /rbx :pushqReg :retn ]] /eypoke defv # call absolute address # 0 -> address to call [[ /rbx :popqReg /rax :popqReg 8 /rax /rax :movqMemDisp8Reg /rax :callqReg /rbx :pushqReg :retn ]] /eyexecute defv # conduct a syscall # 0 -> syscall number, rax before entry # 1 -> r9 before entry # 2 -> r8 before entry # 3 -> r10 before entry # 4 -> rdx before entry # 5 -> rsi before entry # 6 -> rdi before entry # 0 <- rdx after syscall # 1 <- rax after syscall [[ 8 /r15 :subqImm8Reg /r15 :popqMem 2 { ::internalAllocateInteger /rax :movqImmReg /rax :callqReg 8 /r15 :subqImm8Reg /rax /r15 :movqRegMem } rep # allocate return integers [ /rax /r9 /r8 /r10 /rdx /rsi /rdi ] { ==reg reg :popqReg 7 reg /bl :movbMemDisp8Reg %F0 /bl :andbImmReg /intLoad reg cat :jzLbl8 %10 /bl :cmpbImmReg /stringLoad reg cat :jeLbl8 "neither int nor string argument in sys .asm .syscall" ::outputError :ud2 /stringLoad reg cat :label 24 reg reg :leaqMemDisp8Reg /doneLoad reg cat :jmpLbl8 /intLoad reg cat :label 8 reg reg :movqMemDisp8Reg /doneLoad reg cat :label } each :syscall /r15 /rcx :movqMemReg /rax 8 /rcx :movqRegMemDisp8 /rcx :pushqReg 8 /r15 :addqImm8Reg /r15 /rcx :movqMemReg /rdx 8 /rcx :movqRegMemDisp8 /rcx :pushqReg 8 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /eysyscall defv # returns the number of allocations in the global allocation list # 0 <- number of allocations registered [[ /rbx :popqReg # allocate return integer ::internalAllocateInteger /rax :movqImmReg /rax :callqReg /rax :pushqReg ::globalAllocationList /rdx :movqImmReg /rdx /rdx :movqMemReg /rdx /rdx :movqMemReg 4 /rdx :shrqImm8Reg /rdx :decqReg /rdx 8 /rax :movqRegMemDisp8 /rbx :pushqReg :retn ]] /eyglobalAllocCount defv # returns the base address of a global allocation # 0 -> number of allocation # 0 <- allocation base address [[ /rbx :popqReg # allocate return integer ::internalAllocateInteger /rax :movqImmReg /rax :callqReg /rcx :popqReg /rax :pushqReg 8 /rcx /rcx :movqMemDisp8Reg ::globalAllocationList /rdx :movqImmReg /rdx /rdx :movqMemReg /rcx :incqReg 4 /rcx :shlqImm8Reg /rcx /rdx /rdx :movqMemIndexReg /rdx 8 /rax :movqRegMemDisp8 /rbx :pushqReg :retn ]] /eyglobalAllocBase defv # returns the size of a global allocation # 0 -> number of allocation # 0 <- allocation size [[ /rbx :popqReg # allocate return integer ::internalAllocateInteger /rax :movqImmReg /rax :callqReg /rcx :popqReg /rax :pushqReg 8 /rcx /rcx :movqMemDisp8Reg ::globalAllocationList /rdx :movqImmReg /rdx /rdx :movqMemReg /rcx :incqReg 4 /rcx :shlqImm8Reg 8 1 /rcx /rdx /rdx :movqMemIndexScaleDisp8Reg /rdx 8 /rax :movqRegMemDisp8 /rbx :pushqReg :retn ]] /eyglobalAllocSize defv # get raw object address from object # 0 -> object # 0 <- address of the object [[ /rbx :popqReg # allocate return integer ::internalAllocateInteger /rax :movqImmReg /rax :callqReg 8 /rax :popqMemDisp8 /rax :pushqReg /rbx :pushqReg :retn ]] /eyrawAddress defv # generate object from raw object # 0 -> address of the object # 0 <- object [[ /rbx :popqReg /rax :popqReg 8 /rax :pushqMemDisp8 # push integer value /rbx :pushqReg :retn ]] /eyrawObject defv # get raw code execution address from function object # 0 -> function object # 0 <- address of first instruction [[ /rbx :popqReg # allocate return integer ::internalAllocateInteger /rax :movqImmReg /rax :callqReg /rdx :popqReg 24 /rdx /rdx :movqMemDisp8Reg 8 /rdx :addqImm8Reg /rdx 8 /rax :movqRegMemDisp8 /rax :pushqReg /rbx :pushqReg :retn ]] /eyrawCodeAddress defv # (template) program boot sequence after freeze [[ /rsp :movqImmOOBReg %EE %EE %EE %EE %EE %EE %EE %EE # 10 /r15 :movqImmOOBReg %EE %EE %EE %EE %EE %EE %EE %EE # 20 ::heapEnd /rax :movqImmReg # 30 /rbx :movqImmOOBReg %EE %EE %EE %EE %EE %EE %EE %EE # 40 /rbx /rax :movqRegMem # 43 ::unusedHeapStart /rax :movqImmReg # 53 /rbx :movqImmOOBReg %EE %EE %EE %EE %EE %EE %EE %EE # 63 /rbx /rax :movqRegMem # 66 ::currentScope /rax :movqImmReg # 76 /rbx :movqImmOOBReg %EE %EE %EE %EE %EE %EE %EE %EE # 86 /rbx /rax :movqRegMem # 89 :globalAllocations .base /rax :movqImmReg # 99 /rbx :movqImmOOBReg %EE %EE %EE %EE %EE %EE %EE %EE # 109 /rbx /rax :movqRegMem # 112 # empty encoding buffer to ensure the GC does not follow residue from freeze into unallocated memory :quoteEncodingBuffer /rdi :movqImmReg :STACKSIZE 8 sub /rcx :movqImmReg 3 /rcx :shrqImm8Reg /rax /rax :xorqRegReg :reprcx :stosq |ey* /rax :movqImmReg /rax :callqReg :ud2 ]] /eyprogramStart defv > _ ==globalFunctions { defv }' ::allocateOffsetStruct < # patch programStart to current program state # this function must be called first in sys .freeze because it has to unwind the exactly # correct number of things from the stack to make the sys .freeze execution transparent # TODO: actually do this (e.g. by recoding the freeze startup in assembly) # TODO: ... for now just flush the call stack on freeze # returns the number of allocations according to frozen alloc list fill state [[ /rbx :popqReg eyprogramStart /rax :movqImmReg /rsp 2 /rax :movqRegMemDisp8 # /r15 12 /rax :movqRegMemDisp8 # TODO: something like this (but correctly adjusted) would be right :mainCallStack .base :STACKSIZE add /rdx :movqImmReg # TODO whereas this just flushes the stack /rdx 12 /rax :movqRegMemDisp8 ::heapEnd /rdx :movqImmReg /rdx /rdx :movqMemReg /rdx 32 /rax :movqRegMemDisp8 ::unusedHeapStart /rdx :movqImmReg /rdx /rdx :movqMemReg /rdx 55 /rax :movqRegMemDisp8 ::currentScope /rdx :movqImmReg /rdx /rdx :movqMemReg 16 /rdx /rdx :movqMemDisp8Reg # unwind one scope /rdx 78 /rax :movqRegMemDisp8 :globalAllocations .base /rdx :movqImmReg /rdx /rdx :movqMemReg /rdx :pushqReg # store allocation count for later return value /rdx 101 /rax :movqRegMemDisp8 ::internalAllocateInteger /rax :movqImmReg /rax :callqReg # type zero does not need to be changed /rdx :popqReg 4 /rdx :shrqImm8Reg /rdx :decqReg /rdx 8 /rax :movqRegMemDisp8 # store value /rax :pushqReg /rbx :pushqReg :retn ]] /eypatchProgramStart defv > _ ==globalFunctions2 { defv }' ::allocateOffsetStruct "asm" enterSubScope [ globalFunctions keys eydeff { | }' createScopeEntries globalFunctions2 keys eydeff { | }' createScopeEntries createScopeExtensionEntries ] :execute leaveSubScope > -- # vim: syn=elymas