diff options
| author | Drahflow <drahflow@gmx.de> | 2013-10-15 10:43:45 +0200 |
|---|---|---|
| committer | Drahflow <drahflow@gmx.de> | 2013-10-15 10:43:45 +0200 |
| commit | 64419a3ffee442e831dc3d54a64fe382baf7c297 (patch) | |
| tree | eddfd7b0ba69be0c8ae86806c87c5c98f0468489 | |
| parent | 00feca5e1e9bd4e1625a76fc548b06f05a0e88f8 (diff) | |
Dynamically shared object support
| -rw-r--r-- | compiler/elymasAsm.ey | 67 | ||||
| -rw-r--r-- | compiler/elymasGlobal.ey | 27 | ||||
| -rw-r--r-- | compiler/elymasGlobalSysAsm.ey | 17 | ||||
| -rw-r--r-- | compiler/standardClient.ey | 3 | ||||
| -rw-r--r-- | elymas/Makefile | 7 | ||||
| -rw-r--r-- | elymas/lib/ffi.ey | 6 | ||||
| -rw-r--r-- | elymas/lib/ffi/sdl.ey | 15 | ||||
| -rw-r--r-- | elymas/lib/sys/linux.ey | 53 | ||||
| -rw-r--r-- | elymas/lib/sys/so.ey | 984 | ||||
| -rw-r--r-- | elymas/lib/txt.ey | 18 | ||||
| -rw-r--r-- | elymas/shared.ey | 5 | ||||
| -rw-r--r-- | examples/working-loaded/sharedObject.test | 4 | ||||
| -rw-r--r-- | examples/working-shared/sdl.ey | 15 | ||||
| -rw-r--r-- | notes | 2 |
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 + < + ".[1;31m-[33m=[32m#[34m=[35m-[0m" ==?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 @@ -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 == |
