Call a foreign-language function: Difference between revisions

Content added Content deleted
m (omit from assembly)
(→‎NASM: rewrote it, the old one made me puke. -.-)
Line 3,050: Line 3,050:
===NASM===
===NASM===
{{trans|Wren}}
{{trans|Wren}}
So yeah. This inits Wrens WM in Assembly to call strdup in C.
So yeah. This inits Wrens VM in Assembly to call strdup in C. Now PIE(Position independent executable) compliant.
<lang asm>
<lang asm>
;; Libc stuff..
;; libc stuff..
extern printf
extern printf
extern exit
extern exit
extern malloc
extern free
extern fopen
extern fclose
extern fread
extern fseek
extern ftell
extern rewind


;; Wren imports
;; Wren stuff..
extern wrenNewVM
extern wrenNewVM
extern wrenInterpret
extern wrenInterpret
extern wrenFreeVM
extern wrenFreeVM
extern wrenGetSlotString
extern wrenGetSlotString
extern wrenSetSlowString
extern wrenSetSlotString
extern wrenInitConfiguration
extern wrenInitConfiguration


%define WREN_RESULT_SUCCESS 0
;; Our C function
%define WREN_RESULT_COMPILE_ERROR 1
%define WREN_RESULT_RUNTIME_ERROR 2

;; Stuff...
extern C_strdup
extern C_strdup


;; time saver 'macros' for PIC(mmm, PIE..)
;; Wren Interpret results
;; These Macros basically end up being exactly what they look
%assign WREN_RESULT_SUCCESS 0
;; like in code, there's very little preprocessing in NASM,
%assign WREN_RESULT_COMPILE_ERROR 1
;; unlike M/UASM's macro systems.(Still more than Gas doe..)
%assign WREN_RESULT_RUNTIME_ERROR 2
%macro xlea 2
lea %1, [rel %2]
%endmacro

%macro xcall 1
call [rel %1 wrt ..got]
%endmacro


section .bss
section .bss
wrenConfig resb 84
WrenConfig resb 84 ;; The config struct is 84 bytes(10qwords(8 bytes), 1dword(4 bytes))
WrenVM resq 1 ;; wren VM handle
wrenVM resq 1


section .rodata
section .rodata
;; Messages and shit..
szmsg db "--> Starting and configuring WrenVM",10,0
szmsg db "--> Starting and configuring WrenVM",10,0
vm_err_str db "--> Returned an error",10,"--> Error number: %d",10,0
sznoargs db "--> ! No args passed. Supply a filename.",10,0
sznofile db "--> ! Invaild file passed.",10,0
szothererr db "--> ! Wren Error, check script...",10,0
szmod db "main",0
pfmt db "%s",0
szread db "r",0 ;; Why does this have to be a string? Seriously.


;; Let this freakshow begin..
mod db "main",0
msg db "--> %s",0

;; Hard coded wren script..
;; If you care that much, write a filereader yaself T_T
c_strdup_wren db 'class C {',10
db ' foreign static strdup(s)',10
db '}',10
db 'var s = "Hello World!"',10
db 'System.print(C.strdup(s))',10

;; Let this freakshow begin...
section .text
section .text
global main
global main
Line 3,099: Line 3,111:
push rbp
push rbp
mov rbp, rsp
mov rbp, rsp
lea rdi, szmsg
sub rsp, 16
cmp edi, 1 ;; argc
call printf
jle _main_noargs ;; if(argc <= 1)
lea rdi, WrenConfig
mov rax, qword [rsi+1*8] ;; argv[1] - dun dun dunnnn
call wrenInitConfiguration
lea rax, WrenConfig
mov qword [rbp-8], rax
lea rbx, bindfunc
xlea rdi, szmsg
xcall printf
mov qword [rax+24], rbx ;; wrenconfig.WrenBindForeignMethodFn
lea rbx, writefn
xlea rdi, wrenConfig
xcall wrenInitConfiguration
mov qword [rax+40], rbx ;; wrenconfig.WrenWriteFn
lea rbx, errfn
xlea rax, wrenConfig
xlea rbx, bindfn
mov qword [rax+48], rbx ;; wrenconfig.WrenErrorFn
mov qword [rax+24], rbx ;; wrenconfig.WrenBindForeignFn
lea rdi, WrenConfig
call wrenNewVM
xlea rbx, writefn
mov qword [rax+40], rbx ;; wrenconfig.WrenWriteFn
mov [WrenVM], rax
xlea rbx, errfn
lea rdx, c_strdup_wren ;; script
lea rsi, mod ;; module
mov qword [rax+48], rbx ;; wrenconfig.WrenErrorFn
mov rdi, [WrenVM] ;; WrenVM
xlea rdi, wrenConfig
call wrenInterpret
xcall wrenNewVM
mov [rel wrenVM], rax
mov rdi, qword [rbp-8]
call srcread
mov qword [rbp-16], rax ;; char *wrenScript;
mov rdx, qword [rbp-16]
xlea rsi, szmod
mov esi, 0
mov rdi, [rel wrenVM]
xcall wrenInterpret
cmp rax, WREN_RESULT_SUCCESS
cmp rax, WREN_RESULT_SUCCESS
jg _main_noargs
jg _wrenvm_err ;; if > RESULT_SUCCESS = error.
jmp _exit ;; Time to gtfo.


jmp _main_exit ;; Let's gtfo of dodge.
_wrenvm_err:
mov rsi, rax
_main_noargs:
lea rdi, vm_err_str
call printf
xlea rdi, sznoargs
xcall printf


;; At this point we should free the mem but
_exit:
;; the program ends so who gives a ....
mov rdi, [WrenVM]
_main_exit:
call wrenFreeVM
mov rax, 0
add rsp, 16
pop rbp
pop rbp
xor rdi, rdi
xor rdi, rdi
call exit
xcall exit
ret
ret


;; We only care about the file name once, So.. No keepy keepy.
;;Callback functions for the WrenVM
srcread:
;; writefn(rdi, rsi) - WrenVM isn't used so just overwrite it.
push rbp
mov rbp, rsp
sub rsp, 32
xlea rsi,szread
xcall fopen
cmp rax, 0
jle _srcread_nofile
mov qword [rbp-8], rax ;; file handle.
mov edx, 2 ;; SEEK_END
mov esi, 0
mov rdi, qword [rbp-8]
xcall fseek
mov rdi, qword [rbp-8]
xcall ftell
mov qword [rbp-16], rax
mov rdi, qword [rbp-8]
xcall rewind
mov rax, qword [rbp-16]
add rax, 1
mov rdi, rax
xcall malloc
mov qword [rbp-24], rax
mov rcx, qword [rbp-8] ;; file handle
mov rdx, qword [rbp-16] ;; size
mov esi, 1
mov rdi, qword [rbp-24] ;; buffer
xcall fread
mov rdi, qword [rbp-8]
xcall fclose
mov rcx, qword [rbp-16]
mov rax, qword [rbp-24]
add rax, rcx
mov byte [rax], 0
jmp _srcread_exit

_srcread_nofile:
xlea rdi, sznofile
xcall printf

_srcread_exit:
mov rax, qword [rbp-24]
add rsp, 32
pop rbp
ret

;; Just prints whatever's given to it's one argument.
writefn:
writefn:
push rbp
push rbp
mov rbp, rsp
mov rbp, rsp
lea rdi, msg
xlea rdi, pfmt
call printf
xcall printf
pop rbp
pop rbp
ret
ret


;; Just print generic message and return the error number
errfn:
errfn:
push rbp
push rbp
mov rbp, rsp
mov rbp, rsp
mov rdi, vm_err_str
xlea rdi, szothererr
call printf
xcall printf
mov rax, 0
pop rbp
pop rbp
ret
ret


;; Still to lazy to do those if checks... -.-
bindfunc:
;; I'll do it properly one day, I promise. :]
push rbp
bindfn:
mov rbp, rsp
push rbp
lea rax, C_strdup
pop rbp
mov rbp, rsp
ret
xlea rax, C_strdup
pop rbp
ret

</lang>
strdup.wren
<lang wren>
class C {
foreign static strdup(s)
}
var s = "Goodbye, World!"
System.print(C.strdup(s))
</lang>
</lang>
strdup.c
<lang c>
<lang c>
void free( void* ptr );
void free( void* ptr );
Line 3,180: Line 3,257:
<pre>
<pre>
--> Starting and configuring WrenVM
--> Starting and configuring WrenVM
--> Hello World!
Goodbye, World!
</pre>
</pre>