Call a foreign-language function: Difference between revisions

→‎{{header|X86-64 Assembly}}: (N)asm calls Wren calls C. o.O
(→‎{{header|X86-64 Assembly}}: (N)asm calls Wren calls C. o.O)
Line 3,047:
---> Lua calc: 1342 + 1551 = 2893
-> Return from lua func: 2893
</pre>
===NASM===
{{trans|Wren}}
So yeah. This inits Wrens WM in Assembly to call strdup in C.
<lang asm>
;; Libc stuff..
extern printf
extern exit
 
;; Wren imports
extern wrenNewVM
extern wrenInterpret
extern wrenFreeVM
extern wrenGetSlotString
extern wrenSetSlowString
extern wrenInitConfiguration
 
;; Our C function
extern C_strdup
 
;; Wren Interpret results
%assign WREN_RESULT_SUCCESS 0
%assign WREN_RESULT_COMPILE_ERROR 1
%assign WREN_RESULT_RUNTIME_ERROR 2
 
section .bss
WrenConfig resb 84 ;; The config struct is 84 bytes(10qwords(8 bytes), 1dword(4 bytes))
WrenVM resq 1 ;; wren VM handle
 
section .rodata
;; Messages and shit..
szmsg db "--> Starting and configuring WrenVM",10,0
vm_err_str db "--> Returned an error",10,"--> Error number: %d",10,0
 
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
global main
 
main:
push rbp
mov rbp, rsp
lea rdi, szmsg
call printf
lea rdi, WrenConfig
call wrenInitConfiguration
lea rax, WrenConfig
lea rbx, bindfunc
mov qword [rax+24], rbx ;; wrenconfig.WrenBindForeignMethodFn
lea rbx, writefn
mov qword [rax+40], rbx ;; wrenconfig.WrenWriteFn
lea rbx, errfn
mov qword [rax+48], rbx ;; wrenconfig.WrenErrorFn
lea rdi, WrenConfig
call wrenNewVM
mov [WrenVM], rax
lea rdx, c_strdup_wren ;; script
lea rsi, mod ;; module
mov rdi, [WrenVM] ;; WrenVM
call wrenInterpret
cmp rax, WREN_RESULT_SUCCESS
jg _wrenvm_err ;; if > RESULT_SUCCESS = error.
jmp _exit ;; Time to gtfo.
 
_wrenvm_err:
mov rsi, rax
lea rdi, vm_err_str
call printf
 
_exit:
mov rdi, [WrenVM]
call wrenFreeVM
mov rax, 0
pop rbp
xor rdi, rdi
call exit
ret
 
;;Callback functions for the WrenVM
;; writefn(rdi, rsi) - WrenVM isn't used so just overwrite it.
writefn:
push rbp
mov rbp, rsp
lea rdi, msg
call printf
pop rbp
ret
 
;; Just print generic message and return the error number
errfn:
push rbp
mov rbp, rsp
mov rdi, vm_err_str
call printf
mov rax, 0
pop rbp
ret
 
;; Just stored all the arguments on the stack just in case...
;; Honestly, if we ignore the module comparison this could be done like
;; bindfunc:
;; push rbp
;; mov rbp, rsp
;; lea rax, C_strdup
;; pop rsp
;; ret
bindfunc:
push rbp
mov rbp, rsp
sub rsp, (8*6) ;; make some space on the stack to store our arguments.
mov [rsp+32], rdi ;; WrenVM *vm - not used, Saved for consistancy.
mov [rsp+24], rsi ;; const char *module
mov [rsp+16], rdx ;; const char *className - not used, to lazy.
mov [rsp+8], rcx ;; bool isStatic - not used, to lazy.
mov [rsp+0], r8 ;; const char *signature - not used, still to lazy.
mov rdi, [rsp+24]
call strlen
cmp rax, 0
jle _bf_fail
mov ecx, eax
lea rsi, mod
mov rdi, [rsp+24]
call strcmp
cmp eax, 0
jne _bf_fail
lea rax, C_strdup
jmp _bf_exit
 
_bf_fail:
mov rax, 1
_bf_exit:
add rsp, (8*6)
pop rbp
ret
 
;; strlen(rdi) - str1 - returns in eax
strlen:
push rbp
mov rbp, rsp
mov rax,-1
_1:
inc eax
cmp byte [rdi+rax], 0
jne _1
pop rbp
ret
;;strcmp(rdi, rsi, ecx) str1, str2, maxlen
strcmp:
push rbp
mov rbp, rsp
repe cmpsb
jne _false
mov rax, 0
jmp _true
_false:
mov rax, 1
_true:
pop rbp
ret
</lang>
<lang c>
void free( void* ptr );
char * strdup( const char *str1 );
 
typedef struct WrenVM WrenVM;
const char* wrenGetSlotString(WrenVM* vm, int slot);
void wrenSetSlotString(WrenVM* vm, int slot, const char* text);
 
void C_strdup(WrenVM* vm) {
const char *s = wrenGetSlotString(vm, 1);
char *t = strdup(s);
wrenSetSlotString(vm, 0, t);
free(t);
}
</lang>
{{out}}
<pre>
--> Starting and configuring WrenVM
--> Hello World!
</pre>