Machine code: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|C}}: Do the whole task)
(→‎Tcl: Added implementation)
Line 69: Line 69:
;; Free the pointer
;; Free the pointer
(ccl::free ptr)</lang>
(ccl::free ptr)</lang>

=={{header|Tcl}}==
{{trans|C}}
{{libheader|Critcl}}
<lang tcl>package require critcl

critcl::ccode {
#include <sys/mman.h>
}

# Define a command using C. The C is embedded in Tcl, and will be
# built into a shared library at runtime. Note that Tcl does not
# provide a native way of doing this sort of thing; this thunk is
# mandatory.
critcl::cproc runMachineCode {Tcl_Obj* codeObj int a int b} int {
int size, result;
unsigned char *code = Tcl_GetByteArrayFromObj(codeObj, &size);
void *buf;

/* copy code to executable buffer */
buf = mmap(0, (size_t) size, PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANON, -1, 0);
memcpy(buf, code, (size_t) size);
/* run code */
result = ((int (*) (int, int)) buf)(a, b);
/* dispose buffer */
munmap(buf, (size_t) size);

return result;
}

# But now we have our thunk, we can execute arbitrary binary blobs
set code {0x8B 0x44 0x24 0x4 0x3 0x44 0x24 0x8 0xC3}
puts [runMachineCode [binary format c* $code] 7 12]</lang>

Revision as of 22:39, 15 January 2014

Machine code is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

The task requires poking machine code directly into memory and executing it. This is strictly for x86 (32 bit) architectures. The machine code is the opcodes of the following simple program:

<lang asm>mov EAX, [ESP+4] add EAX, [ESP+8] ret</lang>

which translates into the following opcodes: (139 68 36 4 3 68 36 8 195) and in Hex this would correspond to the following: ("8B" "44" "24" "4" "3" "44" "24" "8" "C3")

Implement the following in your favorite programming language (take the common lisp code as an example if you wish):

  1. Poke the above opcodes into a memory pointer
  2. Excute it with the following arguments: [ESP+4] => unsigned-byte argument of value 7; [ESP+8] => unsigned-byte argument of value 12; The result would be 19.
  3. Free the Pointer

C

<lang C>#include <stdio.h>

  1. include <sys/mman.h>
  2. include <string.h>

int test (int a, int b) {

 /*
      mov EAX, [ESP+4]
      add EAX, [ESP+8]
      ret
 */
 char code[] = {0x8B, 0x44, 0x24, 0x4, 0x3, 0x44, 0x24, 0x8, 0xC3};
 void *buf;
 int c;
 /* copy code to executable buffer */
 buf = mmap (0,sizeof(code),PROT_READ|PROT_WRITE|PROT_EXEC,
            MAP_PRIVATE|MAP_ANON,-1,0);
 memcpy (buf, code, sizeof(code));
 /* run code */
 c = ((int (*) (int, int))buf)(a, b);
 /* free buffer */
 munmap (buf, sizeof(code));
 return c;

}

int main () {

 printf("%d\n", test(7,12));
 return 0;

}</lang>

Common Lisp

<lang lisp>;; This uses the Clozure common lisp foreign function interface implementation.

(note that by using the 'CFFI' library, one can apply this procedure portably in any lisp implementation;
in this code however I chose to demonstrate only the implementation-dependent program)
Allocate a memory pointer and poke the opcode into it

(defparameter ptr (ccl::malloc 9))

(loop for i in '(139 68 36 4 3 68 36 8 195)

  for j from 0 do
  (setf (ccl::%get-unsigned-byte ptr j) i))
Execute with the required arguments and return the result as an unsigned-byte

(ccl::ff-call ptr :UNSIGNED-BYTE 7 :UNSIGNED-BYTE 12 :UNSIGNED-BYTE)

Output = 19
Free the pointer

(ccl::free ptr)</lang>

Tcl

Translation of: C
Library: Critcl

<lang tcl>package require critcl

critcl::ccode {

   #include <sys/mman.h>

}

  1. Define a command using C. The C is embedded in Tcl, and will be
  2. built into a shared library at runtime. Note that Tcl does not
  3. provide a native way of doing this sort of thing; this thunk is
  4. mandatory.

critcl::cproc runMachineCode {Tcl_Obj* codeObj int a int b} int {

   int size, result;
   unsigned char *code = Tcl_GetByteArrayFromObj(codeObj, &size);
   void *buf;
   /* copy code to executable buffer */
   buf = mmap(0, (size_t) size, PROT_READ|PROT_WRITE|PROT_EXEC,
           MAP_PRIVATE|MAP_ANON, -1, 0); 
   memcpy(buf, code, (size_t) size);
   /* run code */
   result = ((int (*) (int, int)) buf)(a, b);
   /* dispose buffer */
   munmap(buf, (size_t) size);
   return result;

}

  1. But now we have our thunk, we can execute arbitrary binary blobs

set code {0x8B 0x44 0x24 0x4 0x3 0x44 0x24 0x8 0xC3} puts [runMachineCode [binary format c* $code] 7 12]</lang>