Machine code: Difference between revisions
Content added Content deleted
Thundergnat (talk | contribs) m (Reverted edits by LVrOk6FqRY (talk) to last revision by Thundergnat) |
|||
Line 991: | Line 991: | ||
Considered to be more harmful than useful. |
Considered to be more harmful than useful. |
||
=={{header|Smalltalk}}== |
|||
I agree that this is more harmful than useful. The only target audience are compiler writers and Smalltalk-core developers (of which I guess are not too many around). |
|||
Also, this is highly cpu specific, the task is for an x86 and also assuming a particular calling convention; both is probably (definitely) not the case (most, incl. myself are on 64bit machines these days). |
|||
Anyway, as a sketch, here is how to do it (I won't waste time in making an x86_64 version for the particular calling convention used on my machine; and yes: it is even different between Unix and Windows systems!): |
|||
First we need a way to allocate executable memory (btw. we should probably also care to flush any instruction caches, which I won't go into here); |
|||
This is very Smalltalk dialect specific, and probably not supported on other Smalltalks; in ST/X, we can define it as: |
|||
{{works with|Smalltalk/X}} |
|||
<lang smalltalk>!ExternalBytes class methods! |
|||
mapExecutableBytes:size |
|||
%{ |
|||
# include <sys/mman.h> |
|||
void *mem; |
|||
OBJ retVal; |
|||
int nBytes = __intVal(size); |
|||
mem = mmap(nil, nBytes, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON, -1, 0); |
|||
if (mem != MAP_FAILED) { |
|||
RETURN( __MKEXTERNALBYTES_N(mem, nBytes)); |
|||
} |
|||
%}. |
|||
self primitiveFailed |
|||
! !</lang> |
|||
next, we need the correct code; the following presents the x86 version (but do not expect this code to NOT crash the Smalltalk VM, as the calling convention is certainly wrong..) |
|||
<lang smalltalk>OperatingSystem getCPUType = #'x86' ifTrue:[ |
|||
code := #[0x8B 0x44 0x24 0x04 0x03 0x44 0x24 0x08 0xC3]. |
|||
] ifFalse:[ |
|||
self error:'unsupported cpu' |
|||
]. |
|||
handle := ExternalBytes mapExecutableBytes:100. |
|||
handle replaceFrom:1 with:code. |
|||
" dump it (debugging only)... " |
|||
e'code at {handle address hexPrintString} is:' printCR. |
|||
(handle copyFrom:1 to:50) asByteArray hexPrintString printCR. |
|||
" create an ExternalFunction for it " |
|||
func := ExternalLibraryFunction new code:handle address. |
|||
func name:'unnamed' module:nil returnType:#int argumentTypes:#(int int). |
|||
func beCallTypeC. |
|||
func printCR. |
|||
" now call it " |
|||
result := func invokeWithArguments:{10 . 20} |
|||
</lang> |
|||
With a few more tricks, it is even possible to install that function as a method in a class; but additional code needs to be generated, to assert that the passed data is correctly boxed/unboxed. |
|||
=={{header|Swift}}== |
=={{header|Swift}}== |