Call a foreign-language function: Difference between revisions
Content added Content deleted
Puppydrum64 (talk | contribs) 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 |
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.. |
||
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 |
;; Wren stuff.. |
||
extern wrenNewVM |
extern wrenNewVM |
||
extern wrenInterpret |
extern wrenInterpret |
||
extern wrenFreeVM |
extern wrenFreeVM |
||
extern wrenGetSlotString |
extern wrenGetSlotString |
||
extern |
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 |
|||
section .rodata |
section .rodata |
||
;; Messages and shit.. |
|||
szmsg db "--> Starting and configuring WrenVM",10,0 |
szmsg db "--> Starting and configuring WrenVM",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 |
||
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 |
|||
mov qword [rbp-8], rax |
|||
xlea rdi, szmsg |
|||
xcall printf |
|||
mov qword [rax+24], rbx ;; wrenconfig.WrenBindForeignMethodFn |
|||
xlea rdi, wrenConfig |
|||
xcall wrenInitConfiguration |
|||
mov qword [rax+40], rbx ;; wrenconfig.WrenWriteFn |
|||
xlea rax, wrenConfig |
|||
xlea rbx, bindfn |
|||
mov qword [rax+48], rbx ;; wrenconfig.WrenErrorFn |
|||
mov qword [rax+24], rbx ;; wrenconfig.WrenBindForeignFn |
|||
lea rdi, WrenConfig |
|||
xlea rbx, writefn |
|||
mov qword [rax+40], rbx ;; wrenconfig.WrenWriteFn |
|||
mov [WrenVM], rax |
|||
xlea rbx, errfn |
|||
lea rdx, c_strdup_wren ;; script |
|||
mov qword [rax+48], rbx ;; wrenconfig.WrenErrorFn |
|||
xlea rdi, wrenConfig |
|||
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: |
|||
_main_noargs: |
|||
lea rdi, vm_err_str |
|||
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 |
|||
add rsp, 16 |
|||
pop rbp |
pop rbp |
||
xor rdi, rdi |
xor rdi, rdi |
||
xcall exit |
|||
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 |
||
xlea rdi, pfmt |
|||
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 |
||
xlea rdi, szothererr |
|||
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 |
|||
mov rbp, rsp |
|||
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 |
||
Goodbye, World! |
|||
</pre> |
</pre> |
||