Created
May 3, 2013 19:50
-
-
Save jkominek/5513385 to your computer and use it in GitHub Desktop.
takes a string of assembly, feeds it to nasm, loads it into memory marked executable, and uses the ffi to turn pointers in it into procedures. obviously the assembly has to match your architecture, which has to be 32 or 64 bit x86, as well as your OS calling conventions. example assembly is for 64 bit unix.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(module nasm racket/base | |
(require racket/system | |
racket/file | |
racket/dict | |
ffi/unsafe | |
ffi/unsafe/alloc) | |
(define posix_memalign | |
; ((allocator free) ; can't auto free these pointers until we ensure that everything using | |
; the allocated block of memory holds a reference to it, lest it be | |
; freed prematurely | |
(get-ffi-obj 'posix_memalign #f | |
(_fun (p : (_ptr o _pointer)) _size _size | |
-> (ret : _int) | |
-> (if (= ret 0) | |
p | |
(error (format "returned ~a" ret))))));) | |
(define _protection (_bitmask '(PROT_NONE = 0 | |
PROT_READ = 1 | |
PROT_WRITE = 2 | |
PROT_EXEC = 4) _int)) | |
(define _flags (_bitmask '(MAP_ANON = 4096 | |
MAP_PRIVATE = 2) _int)) | |
(define mprotect (get-ffi-obj 'mprotect #f | |
(_fun _pointer _size _protection | |
-> (ret : _int) | |
-> (if (= ret 0) | |
(void) | |
(error (format "returned ~a" ret)))))) | |
(define (compile-asm code #:for-size [for-size #f]) | |
(let ([out-filename (make-temporary-file "~a.asm")] | |
[out-bin (make-temporary-file "~a.bin")]) | |
(with-output-to-file out-filename #:exists 'truncate | |
(lambda () | |
(write-string code))) | |
(system (format "/Users/kominek/bin/nasm -o ~a -f bin ~a" out-bin out-filename)) | |
(if for-size | |
(file-size out-bin) | |
(file->bytes out-bin)))) | |
(define (prepend-origin code ptr) | |
(string-append (format "[org 0x~a]\n" | |
(number->string (cast ptr _pointer _uintptr) 16)) | |
code)) | |
(define (load-asm/mem code) | |
(let* ([code-size (compile-asm code #:for-size #t)] | |
[alloc-size (* 8192 (ceiling (/ code-size 8192)))] | |
[ptr (posix_memalign 8192 alloc-size)]) | |
(bytes-copy! (make-sized-byte-string ptr alloc-size) | |
0 | |
(compile-asm (prepend-origin code ptr))) | |
(mprotect ptr alloc-size '(PROT_READ PROT_EXEC)) | |
ptr)) | |
(define (load-asm/pointers code) | |
(let* ([map-name (make-temporary-file "~a.map")] | |
[map-code (string-append (format "[map symbols ~a]\n" map-name) | |
code)] | |
[ptr (load-asm/mem map-code)] | |
[saw-start #f] | |
[symbols (make-hash)]) | |
(define pat #px"^\\s+([0-9a-fA-F]+)\\s+([0-9a-fA-F]+)\\s+(\\S+)") | |
(for ([l (in-list (file->lines map-name))]) | |
(when saw-start | |
(let ([result (regexp-match pat l)]) | |
(when result | |
(hash-set! symbols (string->symbol (cadddr result)) (cast (string->number (cadr result) 16) _uintptr _pointer))))) | |
(when (regexp-match? #px"Real\\s+Virtual\\s+Name" l) | |
(set! saw-start #t))) | |
symbols)) | |
(define (load-asm/procs code types) | |
(let ([symbol-map (load-asm/pointers code)]) | |
(for/hash ([(name type) (in-dict types)]) | |
(values name (cast (hash-ref symbol-map name) _pointer type))))) | |
; need a preprocessor for code which | |
; 1) finds extern statements | |
; 2) extracts all of the symbols named in them | |
; 3) uses get-ffi-obj to try and locate those symbols | |
; 4) replaces the extern statements with EQU lines defining the | |
; symbols to make them point at the appropriate location | |
(define some-asm " | |
[bits 64] | |
section .text | |
identity: | |
push rbp | |
mov rbp, rsp | |
mov rax, rdi | |
leave | |
ret | |
fortytwo: | |
push rbp | |
mov rbp, rsp | |
mov rax, 42 | |
leave | |
ret | |
") | |
(define procs (load-asm/procs some-asm `((identity . ,(_fun _uint64 -> _uint64)) (fortytwo . ,(_fun -> _uint64))))) | |
(define fortytwo (hash-ref procs 'fortytwo)) | |
(define identity (hash-ref procs 'identity)) | |
(identity (fortytwo)) | |
; do i want to do some syntax for define-asm, or do i just want to make a language? | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment