aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrahflow <drahflow@gmx.de>2013-10-15 10:43:45 +0200
committerDrahflow <drahflow@gmx.de>2013-10-15 10:43:45 +0200
commit64419a3ffee442e831dc3d54a64fe382baf7c297 (patch)
treeeddfd7b0ba69be0c8ae86806c87c5c98f0468489
parent00feca5e1e9bd4e1625a76fc548b06f05a0e88f8 (diff)
Dynamically shared object support
-rw-r--r--compiler/elymasAsm.ey67
-rw-r--r--compiler/elymasGlobal.ey27
-rw-r--r--compiler/elymasGlobalSysAsm.ey17
-rw-r--r--compiler/standardClient.ey3
-rw-r--r--elymas/Makefile7
-rw-r--r--elymas/lib/ffi.ey6
-rw-r--r--elymas/lib/ffi/sdl.ey15
-rw-r--r--elymas/lib/sys/linux.ey53
-rw-r--r--elymas/lib/sys/so.ey984
-rw-r--r--elymas/lib/txt.ey18
-rw-r--r--elymas/shared.ey5
-rw-r--r--examples/working-loaded/sharedObject.test4
-rw-r--r--examples/working-shared/sdl.ey15
-rw-r--r--notes2
14 files changed, 901 insertions, 322 deletions
diff --git a/compiler/elymasAsm.ey b/compiler/elymasAsm.ey
index 1d4d906..b3a61cd 100644
--- a/compiler/elymasAsm.ey
+++ b/compiler/elymasAsm.ey
@@ -770,12 +770,14 @@
/je _ %74 defJmpRel8 %84 defJmpRel32
/jg _ %7F defJmpRel8 %8F defJmpRel32
/jge _ %7D defJmpRel8 %8D defJmpRel32
+ /jl _ %7C defJmpRel8 %8C defJmpRel32
/jle _ %7E defJmpRel8 %8E defJmpRel32
/jnb _ %73 defJmpRel8 %83 defJmpRel32
/jnc _ %73 defJmpRel8 %83 defJmpRel32
/jne _ %75 defJmpRel8 %85 defJmpRel32
/jng _ %7E defJmpRel8 %8E defJmpRel32
/jnl _ %7D defJmpRel8 %8D defJmpRel32
+ /jnge _ %7C defJmpRel8 %8C defJmpRel32
/jnle _ %7F defJmpRel8 %8F defJmpRel32
/jns _ %79 defJmpRel8 %89 defJmpRel32
/jno _ %71 defJmpRel8 %81 defJmpRel32
@@ -928,6 +930,55 @@
%A5
} /movsq deff
+ { ==dst ==src
+ dst bit64assert
+ src bit8assert
+
+ 1 dst /none src rex
+ %0F
+ %BE
+ dst src modrm11
+ } /movsxbqRegReg deff
+
+ { ==dst ==src
+ dst bit64assert
+ src bit16assert
+
+ 1 dst /none src rex
+ %0F
+ %BF
+ dst src modrm11
+ } /movsxwqRegReg deff
+
+ { ==dst ==src
+ dst bit64assert
+ src bit32assert
+
+ 1 dst /none src rex
+ %63
+ dst src modrm11
+ } /movsxlqRegReg deff
+
+ { ==dst ==src
+ dst bit64assert
+ src bit8assert
+
+ 1 dst /none src rex
+ %0F
+ %B6
+ dst src modrm11
+ } /movzxbqRegReg deff
+
+ { ==dst ==src
+ dst bit64assert
+ src bit16assert
+
+ 1 dst /none src rex
+ %0F
+ %B7
+ dst src modrm11
+ } /movzxwqRegReg deff
+
{ ==reg ==mem
reg bit64assert
mem bit64assert
@@ -936,7 +987,7 @@
%0F
%B6
reg mem modrm00
- } /movzxMem8Reg64 deff
+ } /movzxMem8Reg64 deff # TODO: this is a weird name, should be movzxbqMemReg
{ ==reg ==mem ==disp
reg bit64assert
@@ -948,7 +999,7 @@
%B6
reg mem modrm01
disp imm8
- } /movzxMem8Disp8Reg64 deff
+ } /movzxMem8Disp8Reg64 deff # TODO: this is a weird name, should be movzxbqMemDisp8Reg
{ ==reg ==mem ==idx ==scale ==disp
reg bit64assert
@@ -962,7 +1013,7 @@
reg /sib modrm01
scale idx mem sib
disp imm8
- } /movzxMem8IndexScaleDisp8Reg64 deff
+ } /movzxMem8IndexScaleDisp8Reg64 deff # TODO: this is a weird name, should be movzxbqMemIndexScaleDisp8Reg
{ ==reg
reg bit64assert
@@ -1030,6 +1081,10 @@
} /reprcx deff
{
+ %F2
+ } /repnz deff
+
+ {
%F3
} /repz deff
@@ -1053,6 +1108,10 @@
/zero reg modrm11
} /rolqClReg deff
+ {
+ %AE
+ } /scasb deff
+
{ ==reg
reg regno %07 gt reg rexreqbyte or { 0 reg /none /none rex } rep
%0F
@@ -1140,7 +1199,7 @@
scale idx mem sib
} /testbRegMemIndexScale deff
- { ==reg =i
+ { ==reg ==i
reg bit8assert
i 256 lt not { "Imm8 too large" die } rep
diff --git a/compiler/elymasGlobal.ey b/compiler/elymasGlobal.ey
index 27527ee..8ac388e 100644
--- a/compiler/elymasGlobal.ey
+++ b/compiler/elymasGlobal.ey
@@ -1894,6 +1894,8 @@
@eachString
16 /rax /rcx :movqMemDisp8Reg
+ /rcx /rcx :testqRegReg
+ /end :jzLbl8
/rcx 8 /r15 :movqRegMemDisp8
24 /rax /rcx :leaqMemDisp8Reg
/rcx /r15 :movqRegMem
@@ -2002,6 +2004,31 @@
:ud2
]] /ey.| defv
+ # test whether a scope member exists
+ # 0 -> member name
+ # 1 -> scope
+ # 0 <- 1 if scope member exists, 0 otherwise
+ [[
+ 8 /r15 :subqImm8Reg
+ /r15 :popqMem
+
+ /rsi :popqReg # fetch identifier
+ /rdi :popqReg # fetch scope
+ ::internalResolve /rax :movqImmReg
+ /rax :callqReg
+
+ /rax /rax :testqRegReg
+ /unresolved :jzLbl8
+ 1 /rax :movqImmReg
+ @unresolved
+ 63 /rax :btsqImm8Reg
+ /rax :pushqReg
+
+ /r15 :pushqMem
+ 8 /r15 :addqImm8Reg
+ :retn
+ ]] /ey.? defv
+
# enumerate scope keys
# 0 -> scope
# 0 <- array of keys
diff --git a/compiler/elymasGlobalSysAsm.ey b/compiler/elymasGlobalSysAsm.ey
index f233a7b..3a7e2c1 100644
--- a/compiler/elymasGlobalSysAsm.ey
+++ b/compiler/elymasGlobalSysAsm.ey
@@ -407,6 +407,22 @@
:retn
]] /eyinternalAllocateInteger defv
+ # returns internalAllocateString into userspace
+ # 0 <- ::internalAllocateString as integer
+ [[
+ /rbx :popqReg
+
+ ::internalAllocateInteger /rax :movqImmReg
+ /rax :callqReg
+ /rax :pushqReg
+
+ ::internalAllocateString /rdx :movqImmReg
+ /rdx 8 /rax :movqRegMemDisp8
+
+ /rbx :pushqReg
+ :retn
+ ]] /eyinternalAllocateString defv
+
# returns internalAllocateScope into userspace
# 0 <- ::internalAllocateScope as integer
[[
@@ -422,6 +438,7 @@
/rbx :pushqReg
:retn
]] /eyinternalAllocateScope defv
+
# (template) program boot sequence after freeze
[[
/rsp :movqImmOOBReg %EE %EE %EE %EE %EE %EE %EE %EE # 10
diff --git a/compiler/standardClient.ey b/compiler/standardClient.ey
index bdc637c..f75af2c 100644
--- a/compiler/standardClient.ey
+++ b/compiler/standardClient.ey
@@ -131,6 +131,9 @@
} { ^n } {
{ 0 "\n" * eq }" terminal =a
tail
+ } { ^[ } {
+ { 0 "[" * eq }" terminal =a
+ tail
} { 1 } {
"invalid character '" "' after \\ in regex" -120 cat cat die
} ] conds
diff --git a/elymas/Makefile b/elymas/Makefile
index 6ee1265..754f997 100644
--- a/elymas/Makefile
+++ b/elymas/Makefile
@@ -1,5 +1,8 @@
+shared: loaded shared.ey lib/sys/so.ey
+ ./loaded < shared.ey
+
loaded: optimized loaded.ey $(shell find lib -name '*.ey')
- ./optimized < loaded.ey || true
+ ./optimized < loaded.ey
optimized: interpreter optimized.ey lib/math.ey lib/sys/opt.ey
- ./interpreter < optimized.ey || true
+ ./interpreter < optimized.ey
diff --git a/elymas/lib/ffi.ey b/elymas/lib/ffi.ey
new file mode 100644
index 0000000..7899632
--- /dev/null
+++ b/elymas/lib/ffi.ey
@@ -0,0 +1,6 @@
+<
+ { =*? }' /deff deffd
+ { ==? }' /defv deffd
+> /ffi defv
+
+# vim: syn=elymas
diff --git a/elymas/lib/ffi/sdl.ey b/elymas/lib/ffi/sdl.ey
new file mode 100644
index 0000000..605e6e3
--- /dev/null
+++ b/elymas/lib/ffi/sdl.ey
@@ -0,0 +1,15 @@
+<
+ sys .so ":" via
+
+ "/usr/lib/x86_64-linux-gnu/libSDL2.so" :dlopen --
+
+ 32 ==:SDL_INIT_VIDEO
+
+ { -0021 :resolveFunction -01 deffd }' "->" deffd
+
+ "i" "i32" ->SDL_Init
+ "" "s" ->SDL_GetError
+ "siiiii" "p" ->SDL_CreateWindow
+> /sdl ffi .defv
+
+# vim: syn=elymas
diff --git a/elymas/lib/sys/linux.ey b/elymas/lib/sys/linux.ey
index d4c97ec..127f76f 100644
--- a/elymas/lib/sys/linux.ey
+++ b/elymas/lib/sys/linux.ey
@@ -5,7 +5,7 @@
<
43 ==:ACCEPT
# 288 ==:ACCEPT64
- # 21 ==:ACCESS
+ 21 ==:ACCESS # TODO: not implemented here
# 163 ==:ACCT
# 248 ==:ADDKEY
# 159 ==:ADJTIMEX
@@ -21,7 +21,7 @@
# 92 ==:CHOWN
# 161 ==:CHROOT
# 229 ==:CLOCKGETRES
- # 228 ==:CLOCKGETTIME
+ 228 ==:CLOCKGETTIME # TODO: not implemented here
# 230 ==:CLOCKNANOSLEEP
# 227 ==:CLOCKSETTIME
# 56 ==:CLONE
@@ -31,7 +31,7 @@
# 174 ==:CREATEMODULE
# 176 ==:DELETEMODULE
# 32 ==:DUP
- # 33 ==:DUP2
+ 33 ==:DUP2
# 292 ==:DUP3
213 ==:EPOLLCREATE
# 291 ==:EPOLLCREATE1
@@ -42,7 +42,7 @@
# 215 ==:EPOLLWAITOLD
# 284 ==:EVENTFD
# 290 ==:EVENTFD2
- # 59 ==:EXECVE
+ 59 ==:EXECVE
# 60 ==:EXIT
# 231 ==:EXITGROUP
# 269 ==:FACCESSAT
@@ -55,12 +55,12 @@
# 268 ==:FCHMODAT
# 93 ==:FCHOWN
# 260 ==:FCHOWNAT
- # 72 ==:FCNTL
+ 72 ==:FCNTL # TODO: not implemented here
# 75 ==:FDATASYNC
# 193 ==:FGETXATTR
# 196 ==:FLISTXATTR
# 73 ==:FLOCK
- # 57 ==:FORK
+ 57 ==:FORK
# 199 ==:FREMOVEXATTR
# 190 ==:FSETXATTR
5 ==:FSTAT
@@ -81,10 +81,10 @@
# 104 ==:GETGID
# 115 ==:GETGROUPS
# 36 ==:GETITIMER
- # 52 ==:GETPEERNAME
+ 52 ==:GETPEERNAME # TODO: not implemented here
# 121 ==:GETPGID
# 111 ==:GETPGRP
- # 39 ==:GETPID
+ 39 ==:GETPID
# 181 ==:GETPMSG
# 110 ==:GETPPID
# 140 ==:GETPRIORITY
@@ -93,7 +93,7 @@
# 97 ==:GETRLIMIT
# 98 ==:GETRUSAGE
# 124 ==:GETSID
- # 51 ==:GETSOCKNAME
+ 51 ==:GETSOCKNAME # TODO: not implemented here
# 55 ==:GETSOCKOPT
# 186 ==:GETTID
96 ==:GETTIMEOFDAY
@@ -116,7 +116,7 @@
# 251 ==:IOPRIOSET
# 246 ==:KEXECLOAD
# 250 ==:KEYCTL
- # 62 ==:KILL
+ 62 ==:KILL
# 94 ==:LCHOWN
# 192 ==:LGETXATTR
# 86 ==:LINK
@@ -168,9 +168,9 @@
# 298 ==:PERFEVENTOPEN
# 135 ==:PERSONALITY
# 22 ==:PIPE
- # 293 ==:PIPE2
+ 293 ==:PIPE2
# 155 ==:PIVOTROOT
- # 7 ==:POLL
+ 7 ==:POLL # TODO: not implemented here
# 271 ==:PPOLL
# 157 ==:PRCTL
# 17 ==:PREAD64
@@ -189,7 +189,7 @@
# 267 ==:READLINKAT
# 19 ==:READV
# 169 ==:REBOOT
- # 45 ==:RECVFROM
+ 45 ==:RECVFROM # TODO: not implemented here
# 299 ==:RECVMMSG
# 47 ==:RECVMSG
# 216 ==:REMAPFILEPAGES
@@ -199,7 +199,7 @@
# 249 ==:REQUESTKEY
# 219 ==:RESTARTSYSCALL
# 84 ==:RMDIR
- # 13 ==:RTSIGACTION
+ 13 ==:RTSIGACTION # TODO: not implemented here
# 127 ==:RTSIGPENDING
# 14 ==:RTSIGPROCMASK
# 129 ==:RTSIGQUEUEINFO
@@ -253,7 +253,7 @@
# 31 ==:SHMCTL
# 67 ==:SHMDT
# 29 ==:SHMGET
- # 48 ==:SHUTDOWN
+ 48 ==:SHUTDOWN # TODO: not implemented here
# 131 ==:SIGALTSTACK
# 282 ==:SIGNALFD
# 289 ==:SIGNALFD4
@@ -289,7 +289,7 @@
# 184 ==:TUXCALL
# 95 ==:UMASK
# 166 ==:UMOUNT2
- # 63 ==:UNAME
+ 63 ==:UNAME # TODO: not implemented here
# 87 ==:UNLINK
# 263 ==:UNLINKAT
# 272 ==:UNSHARE
@@ -305,7 +305,7 @@
61 ==:WAIT4
# 247 ==:WAITID
1 ==:WRITE
- # 20 ==:WRITEV
+ 20 ==:WRITEV # TODO: not implemented here
0 ==errno
@@ -331,6 +331,14 @@
{ _ len 0 0 0 CONNECT } /connect defStdSyscall
+ { 0 0 0 0 DUP2 } /dup2 defStdSyscall
+
+ { 0 0 0 0 0 EXECVE } /exec defStdSyscall
+
+ { 0 0 0 0 0 0 FORK } /fork defStdSyscall
+
+ { 0 0 0 0 0 0 GETPID } /getpid defStdSyscall
+
# 0 <- raw return value
# 1 <- seconds since 1970
# 2 <- microseconds since 1970
@@ -428,6 +436,8 @@
buf parseStatStruct -02
} /fstat deffd
+ { 0 0 0 0 KILL } /kill defStdSyscall
+
{ 0 0 0 0 LISTEN } /listen defStdSyscall
1 ==:PROTREAD
@@ -511,6 +521,15 @@
{ 0 0 0 OPEN } /open defStdSyscall
+ # 0 <- raw return value
+ # 1 <- read end (possibly invalid)
+ # 2 <- write end (possibly invalid)
+ {
+ 16 str .alloc ==buf
+ buf 0 0 0 0 0 PIPE2 sys .asm .syscall =errno
+ buf ->u32 -01 ->u32 -023
+ } /pipe deffd
+
<
2 ==:PTRACEPEEKDATA
3 ==:PTRACEPEEKUSER
diff --git a/elymas/lib/sys/so.ey b/elymas/lib/sys/so.ey
index d40e5ef..4a0632f 100644
--- a/elymas/lib/sys/so.ey
+++ b/elymas/lib/sys/so.ey
@@ -1,4 +1,4 @@
-# Access shared libraries (and link dynamically)
+# Freeze into ELF binary which requires libc (for dlsym and dlopen).
<
sys .linux "+" via
@@ -7,10 +7,12 @@
sys .asm .|peek =*:peek
sys .asm .|poke =*:poke
+ { -1010 gt -021 ? } /max deffd
+ { -1010 lt -021 ? } /min deffd
+
# hex decoding
- { ==strNumber
- strNumber len 2 neq { "not a valid hex-string" die } rep
- 1 0 { strNumber * 48 sub [ 0 1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 0 10 11 12 13 14 15 ] * } -20*10* 16 mul add
+ { # ==strNumber
+ 0 -01 { 48 sub [ 0 1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 0 10 11 12 13 14 15 ] * -01 16 mul -01 add } each
} "%" defq
<
@@ -38,7 +40,7 @@
# 2 -> int to convert to bytes
{ ==w ==a ==i
a _ w add range { 0 -01 poke }" each
- i 256 math .base _ dom { -101*0 poke }" each --
+ i 256 math .base _ dom { -101*0 a add poke }" each --
} /uw deffst
defBitVariants
@@ -47,305 +49,123 @@
.consume "=>" via
.produce "<=" via
- 17592186044416 ==threadLocalStorageAddress # 0x100000000000
- 17592186044416 ==threadLocalStorageEnd
- 17592186044416 ==threadLocalStorageAllocEnd
-
- threadLocalStorageAddress +archSetFs
-
- { ==reservedSize ==dataSize ==dataBase
- threadLocalStorageEnd reservedSize add threadLocalStorageAllocEnd sub ==necessaryAllocation
- necessaryAllocation 0 gt {
- necessaryAllocation 1 sub 4096 div 1 add 4096 mul =necessaryAllocation
- threadLocalStorageAllocEnd necessaryAllocation
- +PROTREAD +PROTWRITE +PROTEXEC bor bor +MAPPRIVATE +MAPFIXED +MAPANONYMOUS bor bor 1 neg 0 +mmap -- # TODO: error handling
- threadLocalStorageAllocEnd necessaryAllocation add =threadLocalStorageAllocEnd
- } rep
-
- 0 dataSize range { ==i
- dataBase i add peek threadLocalStorageEnd i add poke
- } each
- dataSize reservedSize range { ==i
- 0 threadLocalStorageEnd i add poke
- } each
- 0 8 range { ==i
- %EE threadLocalStorageEnd i add poke # %fs:0x0 shall hold the TLS-pointer. FIXME: what to put here?
- } each
-
- threadLocalStorageEnd reservedSize add =threadLocalStorageEnd # return old start and add reserved size
- } /addToTLSTemplate deffd
-
- 35184372088832 ==freeAddress # 0x200000000000
-
- < { ==? }' > /symbols defvst /saveSymbol deffst
-
- # load a concrete shared library
- # 0 -> filename of a shared library
- {
- "\0" cat +ORDONLY 0 +open ==fd # TODO: error handling
- fd +fstat -- # TODO: error handling
- .size 1 sub 4096 div 1 add 4096 mul ==size
- freeAddress size +PROTREAD +PROTWRITE +PROTEXEC bor bor +MAPPRIVATE +MAPFIXED bor fd 0 +mmap -- # TODO: error handling
- freeAddress ==loadedAt
- freeAddress size add =freeAddress
-
- { ==err 1 -021 { -011 ==a peek eq and a 1 add } each -- not { err die } rep } /expectAt deffd
- { loadedAt add } /at deffst
-
- 0 at [ %7F %45 %4C %46 ] "Not a valid ELF library (magic bytes missing)" expectAt
- 4 at [ %02 ] "Not a valid ELF library (not ELFCLASS64)" expectAt
- 5 at [ %01 ] "Not a valid ELF library (not little endian)" expectAt
- 6 at [ %01 ] "Not a valid ELF library (wrong version)" expectAt
- 7 at [ %00 %00 ] "Not a valid ELF library (non SYS-V ABI)" expectAt
- 16 at =>u16 3 neq { "Not a dynamic library" die } rep
- 18 at =>u16 62 neq { "Not valid for this architecture (AMD64 ABI expects EM_X86_64)" die } rep
- 20 at =>u32 1 neq { "Not a valid ELF library (wrong version, 2nd field)" die } rep
- 24 at =>u64 ==entryPoint # not that it would be useful
- 32 at =>u64 ==programHeaderOffset
- 40 at =>u64 ==sectionHeaderOffset
- 48 at =>u32 0 neq { "Unexpected processor specific flags" die } rep
- 52 at =>u16 %40 neq { "ELF header size wrong" die } rep
- 54 at =>u16 %38 neq { "ProgramHeader size wrong" die } rep
- 56 at =>u16 ==programHeaderCount
- 58 at =>u16 %40 neq { "SectionHeader size wrong" die } rep
- 60 at =>u16 ==sectionHeaderCount
- 62 at =>u16 ==sectionNameTableIndex
-
- 0 ==stringTable
- 0 ==stringTableSize
- 0 ==symbolTable
- 0 ==symbolTableEntrySize
- 0 ==initFunction
- 0 ==initFunctionArray
- 0 ==initFunctionArraySize
- 0 ==symbolHashTable
- 0 ==libraryName
- 0 ==plt
- 0 ==pltSize
- 0 ==pltRelocationType
- 0 ==pltRelocationAddress
- [ ] ==neededLibraries
- [ ] ==relaTables
- [ ] ==relaTableSizes
- 0 ==relaEntrySize
- 0 ==flags
- 0 ==tlsTemplateStart
- 0 ==tlsTemplateFileSize
- 0 ==tlsTemplateMemorySize
- 0 ==tlsLoadedAddress
-
- { -1010 gt -021 ? } /max deffd
-
- [
- loadedAt programHeaderOffset add
- 0 programHeaderCount range %38 mul add
- { 48 add =>u64 } each
- ] |max fold ==loadingAlignment
-
- freeAddress loadingAlignment div 1 add loadingAlignment mul ==loadingAddress
-
- loadedAt programHeaderOffset add
- 0 programHeaderCount range %38 mul add
- { { add }_ /at deffst
-
- 0 at =>u32 ==type
- 4 at =>u32 ==flags
- 8 at =>u64 ==fileOffset
- 16 at =>u64 ==memoryAddress
- # 24 is unused
- 32 at =>u64 ==fileSize
- 40 at =>u64 ==memorySize
- 48 at =>u64 ==alignment
-
- type 1 eq {
- # "Mapping..." dump
-
- fileOffset 4096 div 4096 mul ==alignedFileOffset
- fileOffset memorySize add alignedFileOffset sub 1 sub 4096 div 1 add 4096 mul ==alignedSize
- loadingAddress memoryAddress add 4096 div 4096 mul ==alignedMemoryAddress
-
- # "Mapping start: " dump alignedMemoryAddress dump
- # "Mapping end: " dump alignedMemoryAddress alignedSize add dump
- # "File mapping start: " dump alignedFileOffset dump
-
- flags 2 band { # writable segment, allocate full memory size and clone contents
- alignedMemoryAddress alignedSize
- +PROTREAD +PROTWRITE bor
- +MAPPRIVATE +MAPFIXED +MAPANONYMOUS bor bor 1 neg 0 +mmap -- # TODO: error handling
-
- { ==count ==dst ==src
- 0 count range { ==i src i add peek dst i add poke } each
- } /rawMemcopy deffd
-
- loadedAt alignedFileOffset add alignedMemoryAddress fileSize rawMemcopy
- } { # readonly segment, just mamp file
- alignedMemoryAddress alignedSize
- +PROTREAD +PROTEXEC bor
- +MAPPRIVATE +MAPFIXED bor fd alignedFileOffset +mmap -- # TODO: error handling
- } ? *
-
- alignedMemoryAddress alignedSize add =freeAddress
- } rep
-
- type 2 eq {
- # "Parsing relocations..." dump
-
- loadedAt fileOffset add
- 0 fileSize 16 div range 16 mul add
- { { add }_ /at deffst
- 0 at =>u64 ==tag
- 8 at =>u64 ==value
-
- [
- { tag 0 eq }' { } # end of table (redundantly limited by size)
- { tag 1 eq }' { neededLibraries [ value ] cat =neededLibraries }
- { tag 2 eq }' { value =pltSize }
- { tag 3 eq }' { value =plt }
- { tag 4 eq }' { value =symbolHashTable }
- { tag 5 eq }' { value =stringTable }
- { tag 6 eq }' { value =symbolTable }
- { tag 7 eq }' { relaTables [ value ] cat =relaTables }
- { tag 8 eq }' { relaTableSizes [ value ] cat =relaTableSizes }
- { tag 9 eq }' { value =relaEntrySize }
- { tag 10 eq }' { value =stringTableSize }
- { tag 11 eq }' { value =symbolTableEntrySize }
- { tag 12 eq }' { value =initFunction }
- { tag 14 eq }' { value =libraryName }
- { tag 20 eq }' { value =pltRelocationType }
- { tag 23 eq }' { value =pltRelocationAddress }
- { tag 25 eq }' { value =initFunctionArray }
- { tag 27 eq }' { value =initFunctionArraySize }
- { tag 30 eq }' { value =flags }
- { tag 65536 gt }' { } # environment specific use
-
- { 1 }' { "unknown tag" die }
- ] conds
- } each
- } rep
-
- type 7 eq {
- # "Parsing thread local storage initalization template..." dump
- loadingAddress memoryAddress add =tlsTemplateStart
- fileSize =tlsTemplateFileSize
- memorySize =tlsTemplateMemorySize
- } rep
- } each
-
- { ==a
- 4096 str .alloc ==buf
-
- 0 ==i
- { i a add peek _ i buf len lt and } {
- i buf =[]
- i 1 add =i
- } loop --
-
- i buf str .prefix
- } /peekString deffst
-
- # "Following dependencies..." dump
+ { ==a
+ 4096 str .alloc ==buf
- neededLibraries {
- stringTable add loadedAt add peekString
- # "Library: " dump _ dump
- -- # TOOD actually follow something here
- } each
+ 0 ==i
+ { i a add peek _ i buf len lt and } {
+ i buf =[]
+ i 1 add =i
+ } loop --
- # "Loading symbols..." dump
+ i buf str .prefix
+ } /peekString deffd
- <
- 1 ==i
-
- { i 24 mul symbolTable add loadedAt add ==symbolTableEntry
- 0 symbolTableEntry add =>u32 ==name
- 4 symbolTableEntry add =>u8 ==info
- 5 symbolTableEntry add =>u8 ==other
- 6 symbolTableEntry add =>u16 ==section
- 8 symbolTableEntry add =>u64 ==value
- 16 symbolTableEntry add =>u64 ==size
-
- name stringTableSize lt
- }' {
- info value < loadingAddress add ==value ==info >
- name stringTable add loadedAt add peekString saveSymbol
- i 1 add =i
- }' loop
- > --
+ { ::rawAddress 24 add } /rawContentAddress deffd
- # "Executing RELA tables..." dump
+ 8 str .alloc _ str .zero ==:dlopenAddress
+ 8 str .alloc _ str .zero ==:dlsymAddress
- 0 ==lastOffset
+ 8 str .alloc ==:r15backup
+ 8 str .alloc ==:rspbackup
- 0 relaTables len range { ==i
- loadedAt i relaTables * add
- 0 i relaTableSizes * 24 div range 24 mul add
- { { add }_ /at deffst
- 0 at =>u64 ==offset
- 8 at =>u32 ==type
- 12 at =>u32 ==symbolIndex
- 16 at =>u64 ==addend
+ [ ] ==saveFromGC
- # [ /offset /type /symbolIndex /addend ] { _ | -01 dump dump } each
+ { ==f ==sym
+ [
+ rspbackup rawContentAddress /rax :movqImmReg
+ /rsp /rax :movqRegMem
+ /r15 /rax :movqRegReg
+ r15backup rawContentAddress /r15 :movqImmReg
+ /r15 /r15 :movqMemReg
+
+ 8 /r15 :subqImm8Reg
+ /r15 :popqMem
+ 8 /r15 :subqImm8Reg
+ /rax /r15 :movqRegMem
+
+ /r14 :pushqReg
+ /r13 :pushqReg
+ /r12 :pushqReg
+ /rbx :pushqReg
+ /rbp :pushqReg
- loadingAddress offset add ==finalAddress
- # "loadingAddress: " dump loadingAddress dump
- # "offset: " dump offset dump
- # "final address: " dump finalAddress dump
+ [ /rdi /rsi /rdx /rcx /r8 /r9 ] { :pushqReg } each
- loadedAt _ symbolTable add symbolIndex 24 mul add =>u32
- add stringTable add peekString _ ==symbolName
- symbols -01 . .value ==symbolValue
+ [ /rdi /rsi /rdx /rcx /r8 /r9 ] { --
+ ::internalAllocateInteger /rax :movqImmReg
+ /rax :callqReg
+ /rax :pushqReg
+ } each
- offset lastOffset eq { "Consecutive RELA not implemented" die } rep
- offset =lastOffset
+ [ /rdi /rsi /rdx /rcx /r8 /r9 ] { --
+ /rdi :popqReg # integer on stack
+ 5 8 mul /rsp /rax :movqMemDisp8Reg
+ /rax 8 /rdi :movqRegMemDisp8 # load value
+ /rdi 5 8 mul /rsp :movqRegMemDisp8 # replace register value by integer object
+ } each
- addend ==A loadingAddress ==B finalAddress ==P symbolValue ==S threadLocalStorageEnd threadLocalStorageAddress sub ==T
+ f ::rawAddress /rax :movqImmReg
+ /rax :pushqReg
+ "*" | ::rawCodeAddress /rax :movqImmReg
+ /rax :callqReg
- { 0 ==i
- 256 math .base { finalAddress i add -10 poke i 1 add =i } each
- i 8 range { finalAddress add 0 -01 poke } each
- } /writeRela64 deffst
+ /rdx :popqReg
- [
- { type 1 eq }' { S A add writeRela64 }
- { type 6 eq }' { S writeRela64 }
- { type 8 eq }' { B A add writeRela64 }
- { type 16 eq }' { } # FIXME: DTPMOD64 thread local storage ignored, let's hope stuff still works
- { type 17 eq }' { } # FIXME: DTPOFF64 thread local storage ignored, let's hope stuff still works
- { type 18 eq }' { T A add writeRela64 }
- { 1 }' { type dump "unknown RELA type" die }
- ] conds
+ 63 /rdx :btrqImm8Reg
+ [
+ 8 /rdx /rdx :movqMemDisp8Reg
+ ] len :jcRel8
- # finalAddress 35184378017584 eq { "HERE ADDR" die } rep
- # symbolName "stdout" streq { "HERE SYM" die } rep
- } each
- } each
+ 8 /rdx /rdx :movqMemDisp8Reg
- # "Populating TLS area..." dump
+ /rbp :popqReg
+ /rbx :popqReg
+ /r12 :popqReg
+ /r13 :popqReg
+ /r14 :popqReg
- threadLocalStorageEnd ==tlsAddress
- # tlsTemplateStart dump
- # tlsTemplateFileSize dump
- # tlsTemplateMemorySize dump
- tlsTemplateStart tlsTemplateFileSize tlsTemplateMemorySize addToTLSTemplate
- # tlsAddress dump
- # "--------------------------------" dump
- } /loadFile deffd
+ /r15 /rax :movqMemReg
+ 8 /r15 :addqImm8Reg
+ /r15 :pushqMem
+ 8 /r15 :addqImm8Reg
+ /rax /r15 :movqRegReg
- # resolves a C function
- # 0 -> argument specification string
+ /rdx /rax :movqRegReg
+ :retn
+ ] [ f ] ::createFunction _ ::rawCodeAddress < ==value 0 ==info > sym saveSymbol
+ [ -01 ] saveFromGC -01 cat =saveFromGC
+ } /defineFunction deffst
+
+ # wrap a C function
+ # 0 -> return value specification string
+ # v: no return value
+ # p: pointer return value
+ # u8: uint8_t return value
+ # u16: uint16_t return value
+ # u32: uint32_t return value
+ # u64: uint64_t return value
+ # i8: int8_t return value
+ # i16: int16_t return value
+ # i32: int32_t return value
+ # i64: int64_t return value
+ # s: string return value (will be copied)
+ # 1 -> argument specification string
# "iis" == foo(int, int, char *)
- # i: integer argument (of any width), also used for general pointers
- # s: string argument (pointer to string content passed)
- # 1 -> name of symbol
+ # p: pointer argument
+ # i: integer argument (of any width)
+ # s: string argument (pointer to string content passed, string is zero-terminated)
+ # b: buffer argument (pointer to string content passed, no zero-termination, but no copy)
+ # 2 -> address of function
# the resulting function will take as many arguments as specified and return a single integer
- { ==args ==name
+ { ==rets ==args ==func
[ /rdi /rsi /rdx /rcx /r8 /r9 ] =*:availableIntegerRegisters
0 ==nextIntegerRegister
[
args { ==t [
- { t 0 "i" * eq }' {
+ { t 0 "i" * eq
+ t 0 "p" * eq or }' {
nextIntegerRegister availableIntegerRegisters ==reg
nextIntegerRegister 1 add =nextIntegerRegister
@@ -356,7 +176,7 @@
8 reg reg :movqMemDisp8Reg
]
}
- { t 0 "s" * eq }' {
+ { t 0 "b" * eq }' {
nextIntegerRegister availableIntegerRegisters ==reg
nextIntegerRegister 1 add =nextIntegerRegister
@@ -365,6 +185,50 @@
24 reg :addqImm8Reg
]
}
+ { t 0 "s" * eq }' {
+ nextIntegerRegister availableIntegerRegisters ==reg
+ nextIntegerRegister 1 add =nextIntegerRegister
+
+ {
+ 0 24 1 /rax reg :andbImmMemIndexScaleDisp8
+ 24 reg :addqImm8Reg
+ } =*finalZeroSpaceAvailable
+
+ {
+ 0 nextIntegerRegister 1 sub range { availableIntegerRegisters * :pushqReg } each
+
+ reg :pushqReg
+ 1 /rax /rdi :leaqMemDisp8Reg
+ ::internalAllocateString /rax :movqImmReg
+ /rax :callqReg
+
+ 24 /rax /rdi :leaqMemDisp8Reg
+
+ /rax :popqReg
+ 24 /rax /rsi :leaqMemDisp8Reg
+ 16 /rax /rcx :movqMemDisp8Reg
+ :reprcx :movsb
+ 0 /rsi :andbImmMem
+ 24 /rax reg :leaqMemDisp8Reg
+
+ 0 nextIntegerRegister 1 sub range reverse { availableIntegerRegisters * :popqReg } each
+ } =*finalZeroSpaceNotAvailable
+
+ [
+ reg :popqReg
+ 16 reg /rax :movqMemDisp8Reg
+ 7 /al :testbImmReg
+ [
+ finalZeroSpaceNotAvailable
+ 0 :jmpRel8
+ ] len :jnzRel8
+ finalZeroSpaceNotAvailable
+ [
+ finalZeroSpaceAvailable
+ ] len :jmpRel8
+ finalZeroSpaceAvailable
+ ]
+ }
{ 1 }' {
t dump
"unknown argument semantics argument" die
@@ -372,43 +236,579 @@
] conds } each
] ==argumentLoaders
- [
- /rbx :popqReg
-
- argumentLoaders reverse { _ len dearray } each
- symbols name . .value /rax :movqImmReg
- /rax :callqReg
-
+ {
/rax /rdx :movqRegReg
32 /rdx :shrqImm8Reg
[
63 /rax :btsqImm8Reg
- /rax :pushqReg
0 :jmpRel8
] len :jnzRel8
63 /rax :btsqImm8Reg
- /rax :pushqReg
[
/rax :pushqReg
::internalAllocateInteger /rax :movqImmReg
/rax :callqReg
8 /rax :popqMemDisp8
- /rax :pushqReg
] len :jmpRel8
/rax :pushqReg
::internalAllocateInteger /rax :movqImmReg
/rax :callqReg
8 /rax :popqMemDisp8
- /rax :pushqReg
+ } /wrapInteger deffd
+
+ {
+ [
+ { rets "v" streq }' { }
+ { rets "s" streq }' {
+ /rax :pushqReg
+ /rcx /rcx :xorqRegReg
+ /rax /rdi :movqRegReg
+ /rax /rax :xorqRegReg
+ /rcx :decqReg
+ :repnz :scasb
+ /rcx :negqReg
+ 2 /rcx :subqImm8Reg
+ /rcx /rdi :movqRegReg
+ ::internalAllocateString /rax :movqImmReg
+ /rax :callqReg
+ /rsi :popqReg
+ /rax :pushqReg
+ 24 /rax /rdi :leaqMemDisp8Reg
+ :repnz :movsb
+ }
+ { rets "i64" streq }' {
+ wrapInteger
+ /rax :pushqReg
+ }
+ { rets "i32" streq }' {
+ /eax /rax :movsxlqRegReg # sign extend result
+ wrapInteger
+ /rax :pushqReg
+ }
+ { rets "i16" streq }' {
+ /ax /rax :movsxwqRegReg # sign extend result
+ wrapInteger
+ /rax :pushqReg
+ }
+ { rets "i8" streq }' {
+ /al /rax :movsxbqRegReg # sign extend result
+ wrapInteger
+ /rax :pushqReg
+ }
+ { rets "u64" streq }' {
+ wrapInteger
+ /rax :pushqReg
+ }
+ { rets "u32" streq }' {
+ /eax /eax :movlRegReg # zero extend result
+ 63 /rax :btsqImm8Reg
+ /rax :pushqReg
+ }
+ { rets "u16" streq }' {
+ /ax /rax :movzxwqRegReg # zero extend result
+ 63 /rax :btsqImm8Reg
+ /rax :pushqReg
+ }
+ { rets "u8" streq }' {
+ /al /rax :movzxbqRegReg # zero extend result
+ 63 /rax :btsqImm8Reg
+ /rax :pushqReg
+ }
+ { rets "p" streq }' {
+ wrapInteger
+ /rax :pushqReg
+ }
+ { 1 }' {
+ rets dump
+ "unknown return type specification" die
+ }
+ ] conds
+ } =*returnWrapper
+
+ [
+ /rbx :popqReg
+
+ r15backup rawContentAddress /rax :movqImmReg
+ /r15 /rax :movqRegMem
+
+ argumentLoaders reverse { _ len dearray } each
+ func /rax :movqImmReg
+ /rax :callqReg
+
+ returnWrapper
/rbx :pushqReg
:retn
] [ ] ::createFunction
+ } /wrapFunction deffd
+
+ { "\0" cat } [
+ /rbx :popqReg
+
+ r15backup rawContentAddress /rax :movqImmReg
+ /r15 /rax :movqRegMem
+
+ /rdi :popqReg
+ 24 /rdi :addqImm8Reg # load filename
+ 257 /rsi :movqImmReg # RTLD_LAZY | RTLD_GLOBAL
+ dlopenAddress rawContentAddress /rax :movqImmReg
+ /rax /rax :movqMemReg
+ /rax :callqReg
+
+ /rax :pushqReg
+ ::internalAllocateInteger /rax :movqImmReg
+ /rax :callqReg
+ 8 /rax :popqMemDisp8
+ /rax :pushqReg
+
+ /rbx :pushqReg
+ :retn
+ ] [ ] ::createFunction ; /dlopen deffd
+
+ { -01 "\0" cat -01 } [
+ /rbx :popqReg
+
+ r15backup rawContentAddress /rax :movqImmReg
+ /r15 /rax :movqRegMem
+
+ /rdi :popqReg
+ 63 /rdi :btrqImm8Reg
+ [ 8 /rdi /rdi :movqMemDisp8Reg ] len :jcRel8
+ 8 /rdi /rdi :movqMemDisp8Reg # load library handle
+
+ /rsi :popqReg
+ 24 /rsi :addqImm8Reg # load symbol name
+
+ dlsymAddress rawContentAddress /rax :movqImmReg
+ /rax /rax :movqMemReg
+ /rax :callqReg
+
+ /rax :pushqReg
+ ::internalAllocateInteger /rax :movqImmReg
+ /rax :callqReg
+ 8 /rax :popqMemDisp8
+ /rax :pushqReg
+
+ /rbx :pushqReg
+ :retn
+ ] [ ] ::createFunction ; /dlsym deffd
+
+ # [
+ # /rbx :popqReg
+
+ # r15backup rawContentAddress /rax :movqImmReg
+ # /r15 /rax :movqRegMem
+
+ # /rdi :popqReg
+ # 63 /rdi :btrqImm8Reg
+ # # %100 /rsi :movqImmReg # RTLD_GLOBAL
+ # dlopenAddress rawContentAddress /rax :movqImmReg
+ # /rax /rax :movqMemReg
+ # /rax :callqReg
+ #
+ # /rax :pushqReg
+ # ::internalAllocateInteger /rax :movqImmReg
+ # /rax :callqReg
+ # 8 /rax :popqMemDisp8
+ # /rax :pushqReg
+
+ # /rbx :pushqReg
+ # :retn
+ # ] [ ] ::createFunction /malloc deffd
+
+ # 0 -> return specification string (see wrapFunction for details)
+ # 1 -> argument specification string (see wrapFunction for details)
+ # 2 -> name of function
+ # the resulting function will take as many arguments as specified and return a single integer
+ { ==rets ==args # ==name
+ 0 dlsym args rets wrapFunction
} /resolveFunction deffd
+
+ { ==filename # ==f (left on the stack a while and executed from sys .asm .programStart)
+ sys .asm .patchProgramStart ==frozenAllocationCount
+
+ { 8 { _ 256 mod -01 256 div } rep -- } /uint64 deffd
+ { _ 0 lt { 4294967296 add } rep 4294967295 band 4 { _ 256 mod -01 256 div } rep -- } /uint32 deffd
+ { _ 0 lt { 65536 add } rep 65535 band 2 { _ 256 mod -01 256 div } rep -- } /uint16 deffd
+ { _ 0 lt { 256 add } rep 255 band } /uint8 deffd
+
+ { ==align ==value
+ align value align mod sub align mod
+ } /alignUpto deff
+
+ sys .file ==out
+ filename out _ .creating _ .writeonly .open
+
+ [
+ <
+ ".null" ==?name
+ 0 ==?nameOffset { =nameOffset } /setNameOffset deff
+ 0 ==?dataOffset { =dataOffset } /setDataOffset deff
+ 0 ==?type # reserved first section
+ 0 ==?flags # none
+ 0 ==?addr # not loaded
+ 0 ==?link # no associated section
+ 0 ==?entsize # no entries
+ [ ] ==?data
+ 0 ==?dataSize
+ > <
+ ".strtab" ==?name
+ 0 ==?nameOffset { =nameOffset } /setNameOffset deff
+ 0 ==?dataOffset { =dataOffset } /setDataOffset deff
+ 3 ==?type # string table
+ 0 ==?flags # none
+ 0 ==?addr # not loaded
+ 0 ==?link # no associated section
+ 0 ==?entsize # no entries
+ [ ] ==?data # to be filled later
+ 0 ==?dataSize # to be filled later
+ { _ =data len =dataSize } /setData deff
+ > _ ==?stringTable <
+ ".dynamic" ==?name
+ 0 ==?nameOffset { =nameOffset } /setNameOffset deff
+ 0 ==?dataOffset { =dataOffset } /setDataOffset deff
+ 6 ==?type # dynamic linking table
+ 0 ==?flags # none
+ 0 ==?addr # not loaded
+ 0 ==?link # no associated section # TODO: that's a lie, the string table is associated
+ 0 ==?entsize # no entries # TODO: also a lie
+ [ ] ==?data # to be filled later
+ 0 ==?dataSize # to be filled later
+ { _ =data len =dataSize } /setData deff
+ > _ ==?dynamicTable <
+ ".dynsym" ==?name
+ 0 ==?nameOffset { =nameOffset } /setNameOffset deff
+ 0 ==?dataOffset { =dataOffset } /setDataOffset deff
+ 11 ==?type # dynamic linking table
+ 0 ==?flags # none
+ 0 ==?addr # not loaded
+ 1 ==?link # string table is associated
+ %18 ==?entsize
+ [ ] ==?data # to be filled later
+ 0 ==?dataSize # to be filled later
+ { _ =data len =dataSize } /setData deff
+ > _ ==?symbolTable <
+ ".rela" ==?name
+ 0 ==?nameOffset { =nameOffset } /setNameOffset deff
+ 0 ==?dataOffset { =dataOffset } /setDataOffset deff
+ 4 ==?type # relocation table
+ 0 ==?flags # none
+ 0 ==?addr # not loaded
+ 3 ==?link # symbol table is associated (section index 3)
+ %18 ==?entsize
+ [ ] ==?data # to be filled later
+ 0 ==?dataSize # to be filled later
+ { _ =data len =dataSize } /setData deff
+ > _ ==?relocationTable
+ ] ==metaSections
+
+ [
+ 0 frozenAllocationCount range { ==i
+ <
+ ".-=#=-" ==?name
+ 0 ==?nameOffset { =nameOffset } /setNameOffset deff
+ 0 ==?dataOffset { =dataOffset } /setDataOffset deff
+ 1 ==?type # program data
+ 7 ==?flags # writable, allocated, executable
+ 0 ==?addr # FIXME
+ 0 ==?link # no associated section
+ 0 ==?entsize # no entries
+ i sys .asm .globalAllocBase ==?dataBase
+ i sys .asm .globalAllocSize ==?dataSize
+ >
+ } each
+ ] ==allocSections
+
+ 4096 ==:PAGESIZE
+
+ allocSections len 4 add ==programHeaderCount
+ metaSections len allocSections len add ==sectionHeaderCount
+
+ "/lib64/ld-linux-x86-64.so.2" ==:INTERPRETERNAME 0 ==interpreterStringOffset
+ "libc.so.6" ==:LIBCNAME 0 ==libcStringOffset
+ "libdl.so.2" ==:LIBDLNAME 0 ==libdlStringOffset
+ "dlopen" ==:DLOPENNAME 0 ==dlopenStringOffset
+ "dlsym" ==:DLSYMNAME 0 ==dlsymStringOffset
+
+ < 1 ==stringOffset
+ { =*saveOffset ==string
+ string { } each %00
+ stringOffset _ saveOffset
+ string len add 1 add =stringOffset
+ } /stringTableEntry deffst
+
+ [
+ %00 # initial zero byte of string table
+ ### section names
+
+ [ metaSections allocSections ] { { ==s
+ s .name s .|setNameOffset stringTableEntry
+ } each } each
+
+ INTERPRETERNAME { =interpreterStringOffset } stringTableEntry
+ LIBCNAME { =libcStringOffset } stringTableEntry
+ LIBDLNAME { =libdlStringOffset } stringTableEntry
+ DLOPENNAME { =dlopenStringOffset } stringTableEntry
+ DLSYMNAME { =dlsymStringOffset } stringTableEntry
+ ] stringTable .setData
+ > --
+
+ <
+ [
+ 0 uint64 0 uint64 0 uint64 # symbol table index 0 is reserved
+
+ dlopenStringOffset uint32
+ %12 # globally visible function entry point
+ %00
+ 0 uint16
+ 0 uint64
+ 0 uint64
+
+ dlsymStringOffset uint32
+ %12 # globally visible function entry point
+ %00
+ 0 uint16
+ 0 uint64
+ 0 uint64
+ ] symbolTable .setData
+ > --
+
+ <
+ [
+ dlopenAddress rawContentAddress uint64
+ 7 uint32 # R_X86_64_JUMP_SLOT
+ 1 uint32
+ 0 uint64
+ dlsymAddress rawContentAddress uint64
+ 7 uint32 # R_X86_64_JUMP_SLOT
+ 2 uint32
+ 0 uint64
+ ] relocationTable .setData
+ > --
+
+ {
+ [
+ # TAG VALUE
+ 1 uint64 libcStringOffset uint64 # require libc (DT_NEEDED)
+ 1 uint64 libdlStringOffset uint64 # require libdl (DT_NEEDED)
+ 5 uint64 %700000000000 stringTable .dataOffset add uint64 # string table address (DT_STRTAB)
+ 6 uint64 %700000000000 symbolTable .dataOffset add uint64 # symbol table address (DT_SYMTAB)
+ 7 uint64 %700000000000 relocationTable .dataOffset add uint64 # relocation table address (DT_RELA)
+ 8 uint64 relocationTable .dataSize uint64 # relocation table size (DT_RELASZ)
+ 9 uint64 24 uint64 # relocation entry size (DT_RELAENT)
+ 10 uint64 stringTable .dataSize uint64 # string table size (DT_STRSZ)
+ 11 uint64 24 uint64 # symbol entry size (DT_SYMENT)
+ # 0x0000000000000015 (DEBUG) 0x0
+ # 0x0000000000000003 (PLTGOT) 0x604c48
+ # 0x0000000000000002 (PLTRELSZ) 888 (bytes)
+ # 0x0000000000000014 (PLTREL) RELA
+ # 0x0000000000000017 (JMPREL) 0x400af8
+
+ 24 uint64 0 uint64 # immediately apply all relocations (DT_BIND_NOW)
+ 0 uint64 0 uint64 # end of table (DT_NULL)
+ ] dynamicTable .setData
+ } /fillDynamicTable deffst
+
+ fillDynamicTable # some data not available yet, but size already needed
+
+ <
+ # %40 ==? section header size, %38 == program header size
+ sectionHeaderCount %40 mul
+ programHeaderCount %38 mul add
+ %40 add ==dataOffset
+ metaSections { ==s
+ dataOffset s .setDataOffset
+ dataOffset s .dataSize add =dataOffset
+ } each
+
+ dataOffset _ 4096 alignUpto add =dataOffset
+
+ allocSections { ==s
+ dataOffset s .setDataOffset
+ dataOffset s .dataSize add _ PAGESIZE alignUpto add =dataOffset
+ } each
+ > --
+
+ fillDynamicTable
+
+ [
+ ### elf header
+ # unsigned char e_ident[16]; /* ELF identification */
+ %7F 0 1 2 "ELF" -30*20*10* # elf identifier
+ %02 # elfclass64
+ %01 # elf version
+ %01 # little endian encoding
+ %00 %00 # Sys-V ABI
+ %00 %00 %00 %00 %00 %00 %00 # padding
+ # Elf64_Half e_type; /* Object file type */
+ %02 %00 # executable file
+ # Elf64_Half e_machine; /* Machine type */
+ %3E %00 # whatever, /bin/ls has this
+ # Elf64_Word e_version; /* Object file version */
+ %01 %00 %00 %00 # always 1
+ # Elf64_Addr e_entry; /* Entry point address */
+ sys .asm .|programStart sys .asm .rawCodeAddress uint64
+ # Elf64_Off e_phoff; /* Program header offset */
+ %40 uint64
+ # Elf64_Off e_shoff; /* Section header offset */
+ programHeaderCount %38 mul
+ %40 add uint64
+ # Elf64_Word e_flags; /* Processor-specific flags */
+ %00 %00 %00 %00 # taken from from /bin/ls
+ # Elf64_Half e_ehsize; /* ELF header size */
+ %40 %00
+ # Elf64_Half e_phentsize; /* Size of program header entry */
+ %38 %00
+ # Elf64_Half e_phnum; /* Number of program header entries */
+ programHeaderCount uint16
+ # Elf64_Half e_shentsize; /* Size of section header entry */
+ %40 %00
+ # Elf64_Half e_shnum; /* Number of section header entries */
+ sectionHeaderCount uint16
+ # Elf64_Half e_shstrndx; /* Section name string table index */
+ %01 %00 # section header name table index in section headers table
+
+ ### program header describing program header table *sigh*
+ 6 uint32 # program header table (PT_PHDR)
+ 7 uint32 # read | write | execute
+ # Elf64_Off p_offset; /* Offset in file */
+ %40 uint64
+ # Elf64_Addr p_vaddr; /* Virtual address in memory */
+ %700000000000 %40 add uint64
+ # Elf64_Addr p_paddr; /* Reserved */
+ %00 %00 %00 %00 %00 %00 %00 %00
+ # Elf64_Xword p_filesz; /* Size of segment in file */
+ programHeaderCount %38 mul uint64
+ # Elf64_Xword p_memsz; /* Size of segment in memory */
+ programHeaderCount %38 mul uint64
+ # Elf64_Xword p_align; /* Alignment of segment */
+ %08 %00 %00 %00 %00 %00 %00 %00 # alignment
+
+ ### program header requesting interpreter
+ 3 uint32 # interpreter requested (PT_INTERP)
+ 7 uint32 # read | write | execute
+ # Elf64_Off p_offset; /* Offset in file */
+ stringTable .dataOffset interpreterStringOffset add uint64
+ # Elf64_Addr p_vaddr; /* Virtual address in memory */
+ %700000000000 stringTable .dataOffset add interpreterStringOffset add uint64
+ # Elf64_Addr p_paddr; /* Reserved */
+ %00 %00 %00 %00 %00 %00 %00 %00
+ # Elf64_Xword p_filesz; /* Size of segment in file */
+ INTERPRETERNAME len 1 add uint64
+ # Elf64_Xword p_memsz; /* Size of segment in memory */
+ INTERPRETERNAME len 1 add uint64
+ # Elf64_Xword p_align; /* Alignment of segment */
+ %01 %00 %00 %00 %00 %00 %00 %00 # alignment
+
+ ### program header loading all meta sections
+ # Elf64_Word p_type; /* Type of segment */
+ 1 uint32 # loadable segment
+ # Elf64_Word p_flags; /* Segment attributes */
+ 7 uint32 # read | write | execute
+ # Elf64_Off p_offset; /* Offset in file */
+ 0 uint64
+ # Elf64_Addr p_vaddr; /* Virtual address in memory */
+ %700000000000 uint64
+ # Elf64_Addr p_paddr; /* Reserved */
+ %00 %00 %00 %00 %00 %00 %00 %00
+ # Elf64_Xword p_filesz; /* Size of segment in file */
+ [ metaSections { _ .dataOffset -01 .dataSize add } each ] |max fold uint64
+ # Elf64_Xword p_memsz; /* Size of segment in memory */
+ [ metaSections { _ .dataOffset -01 .dataSize add } each ] |max fold uint64
+ # Elf64_Xword p_align; /* Alignment of segment */
+ %00 %10 %00 %00 %00 %00 %00 %00 # alignment
+
+ allocSections { ==s
+ ### program header
+ # Elf64_Word p_type; /* Type of segment */
+ %01 %00 %00 %00 # loadable segment
+ # Elf64_Word p_flags; /* Segment attributes */
+ %07 %00 %00 %00 # read | write | execute
+ # Elf64_Off p_offset; /* Offset in file */
+ s .dataOffset uint64
+ # Elf64_Addr p_vaddr; /* Virtual address in memory */
+ s .dataBase uint64
+ # Elf64_Addr p_paddr; /* Reserved */
+ %00 %00 %00 %00 %00 %00 %00 %00
+ # Elf64_Xword p_filesz; /* Size of segment in file */
+ s .dataSize uint64
+ # Elf64_Xword p_memsz; /* Size of segment in memory */
+ s .dataSize uint64
+ # Elf64_Xword p_align; /* Alignment of segment */
+ %00 %10 %00 %00 %00 %00 %00 %00 # alignment
+ } each
+
+ ### program header describing dynamic table
+ 2 uint32 # dynamic table
+ 7 uint32 # read | write | execute
+ # Elf64_Off p_offset; /* Offset in file */
+ dynamicTable .dataOffset uint64
+ # Elf64_Addr p_vaddr; /* Virtual address in memory */
+ %700000000000 dynamicTable .dataOffset add uint64
+ # Elf64_Addr p_paddr; /* Reserved */
+ %00 %00 %00 %00 %00 %00 %00 %00
+ # Elf64_Xword p_filesz; /* Size of segment in file */
+ dynamicTable .dataSize uint64
+ # Elf64_Xword p_memsz; /* Size of segment in memory */
+ dynamicTable .dataSize uint64
+ # Elf64_Xword p_align; /* Alignment of segment */
+ %00 %10 %00 %00 %00 %00 %00 %00 # alignment
+
+ [ metaSections allocSections ] { { ==s
+ ### section header
+ # Elf64_Word sh_name; /* Section name */
+ s .nameOffset uint32
+ # Elf64_Word sh_type; /* Section type */
+ s .type uint32
+ # Elf64_Xword sh_flags; /* Section attributes */
+ s .flags uint64
+ # Elf64_Addr sh_addr; /* Virtual address in memory */
+ s .addr uint64
+ # Elf64_Off sh_offset; /* Offset in file */
+ s .dataOffset uint64
+ # Elf64_Xword sh_size; /* Size of section */
+ s .dataSize uint64
+ # Elf64_Word sh_link; /* Link to other section */
+ s .link uint32
+ # Elf64_Word sh_info; /* Miscellaneous information */
+ 0 uint32
+ # Elf64_Xword sh_addralign; /* Address alignment boundary */
+ 1 uint64
+ # Elf64_Xword sh_entsize; /* Size of entries, if section has table */
+ s .entsize uint64
+ } each } each
+ ] metaSections { .data cat } each ==fileData
+
+ fileData len str .alloc ==buffer
+ 0 fileData len range { ==i i fileData * i buffer =[] } each
+
+ buffer out .writeall
+
+ 1 ==:WRITE
+
+ buffer len ==fileOffset
+
+ allocSections { ==section
+ section .dataOffset fileOffset sub str .alloc out .writeall
+ section .dataOffset section .dataSize add =fileOffset
+
+ out .fd section .dataBase section .dataSize 0 0 0 WRITE sys .asm .syscall --
+ section .dataSize neq { "write failed" die } rep
+ } each
+
+ out .close
+
+ ==f
+
+ sys .asm .patchProgramStart frozenAllocationCount neq {
+ "freezing allocated new memory chunks, retrying..." dump
+ f filename sys .so .freeze
+ } rep
+ } /freeze deffd
> /so sys .defv
# vim: syn=elymas
diff --git a/elymas/lib/txt.ey b/elymas/lib/txt.ey
index 847b045..833ddc8 100644
--- a/elymas/lib/txt.ey
+++ b/elymas/lib/txt.ey
@@ -5,13 +5,27 @@
{ "^(\\d*)" regex -- ==n
[ n { 48 sub } each ] reverse 10 math .unbase
} /u deffd
+
+ # 0 -> string
+ # 0 <- leading hexadecimal digits converted to int (0, if none)
+ [
+ 0 1 2 3 4 5 6 7 8 9
+ 7 { 0 } rep
+ 10 11 12 13 14 15
+ 26 { 0 } rep
+ 10 11 12 13 14 15
+ ] =*:hexDigitsReverse
+
+ { "^([0-9A-Fa-f]*)" regex -- ==n
+ [ n { 48 sub hexDigitsReverse } each ] reverse 16 math .unbase
+ } /hu deffd
> /consume defvd
<
- # 0 -> positive integer
+ # 0 -> positive integer (or zero)
# 0 <- decimal representation as string
{
- [ -01 10 math .base reverse "0123456789" each ] str .fromArray
+ _ { [ -01 10 math .base reverse "0123456789" each ] str .fromArray } { -- "0" } ? *
} /u deffd
> /produce defvd
> /txt defvd
diff --git a/elymas/shared.ey b/elymas/shared.ey
new file mode 100644
index 0000000..869cea0
--- /dev/null
+++ b/elymas/shared.ey
@@ -0,0 +1,5 @@
+#!/usr/bin/env elymas
+
+"lib/sys/so.ey" include
+
+{ "/proc/self/fd/0" include 0 sys .exit }' "shared" sys .so .freeze
diff --git a/examples/working-loaded/sharedObject.test b/examples/working-loaded/sharedObject.test
deleted file mode 100644
index c28b7f1..0000000
--- a/examples/working-loaded/sharedObject.test
+++ /dev/null
@@ -1,4 +0,0 @@
-"lib/sys/so.ey" include
-"/lib/x86_64-linux-gnu/libc.so.6" sys .so .loadFile
- 1 "Hello World\n" 12
-"write" "isi" sys .so .resolveFunction * dump
diff --git a/examples/working-shared/sdl.ey b/examples/working-shared/sdl.ey
new file mode 100644
index 0000000..23d2e79
--- /dev/null
+++ b/examples/working-shared/sdl.ey
@@ -0,0 +1,15 @@
+"lib/ffi.ey" include
+"lib/ffi/sdl.ey" include
+
+ffi .sdl ":" via
+
+:SDL_INIT_VIDEO :SDL_Init {
+ :SDL_GetError dump
+ "SDL_Init failed" die
+} rep
+
+"Ohai!" 0 0 800 600 0 :SDL_CreateWindow
+
+"done" die
+
+# vim: syn=elymas
diff --git a/notes b/notes
index 43014f6..b5153e4 100644
--- a/notes
+++ b/notes
@@ -140,7 +140,7 @@ Inspiration: http://wiki.luajit.org/new-garbage-collector
0x6???????????: Heap memory ("16 TB should be enough for everyone.")
0x5???????????: GC block bitmap
0x4???????????: GC mark bitmap
-0x3???????????: miscellaneous allocations
+0x3???????????: miscellaneous allocations (initial assembly in particular)
== Musings about possibly better schemes ==