The interaction of Java and ... Assembler?

In Java, it is possible to use program code implemented in other programming languages, the so-called JNI . You can write a dynamically linked library, then load it in Java code and use the functions from there, declaring them as the native methods of the class that loaded it. JNI was created primarily in order to perform machine-dependent actions (and also, possibly, improve the performance of speed-critical parts of the application) in C / C ++, but no one bothers us from writing a library in assembler too.

Tools


To create this distortion, we used Windows, Oracle JDK, Yasm (without macros) and the linker from Microsoft Visual Studio 2010. If you wanted, it would not be difficult to replace any of these components with your favorite, I tried not to use any non-standard features.

Using JNI


To begin, let's create a class in Java in which a function from a future .dll will be called:

public class TestJNI {    
    native static int sum(int x, int y);    // импортируемая функция sum
    public static void main(String[] args) {
        System.loadLibrary("mydll");        // загружаем библиотеку mydll.dll
        System.out.println(sum(2, 3));      // вызываем функцию
    }
}


Name Mangling in Java


Now we need to find out what function name the Java machine expects to find in our library. We will use the javah program from the JDK for this: In this case, a C ++ header will be generated:

javac TestJNI.java
javah TestJNI



/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
/* Header for class TestJNI */
#ifndef _Included_TestJNI
#define _Included_TestJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     TestJNI
 * Method:    sum
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_TestJNI_sum
  (JNIEnv *, jclass, jint, jint);
#ifdef __cplusplus
}
#endif
#endif


The information contained here is needed mainly for further writing the library in C ++, but we are only interested in the signature of the function:

JNIEXPORT jint JNICALL Java_TestJNI_sum
  (JNIEnv *, jclass, jint, jint);


We see that in the dll the function should have the name JNICALL Java_TestJNI_sum and take 4 parameters. For the simplest functions, we will not need the first two of them. All sorts of strange data types like JNIEXPORT, as you might guess, are declared in the jni.h file, which is part of the JDK.

Assembler


Let's write the library:

;mydll.asm
section .text
global Java_TestJNI_sum
Java_TestJNI_sum:
    mov eax, [esp + 12] ; игнорируем первые 2 параметра
    add eax, [esp + 16]
    ret 16
end


;mydll.def
LIBRARY mydll
EXPORTS Java_TestJNI_sum


Compile and link: At the output, we get a .dll file, which we need to transfer to Java code.
yasm -f win32 mydll.asm
link /SUBSYSTEM:windows /DLL /NOENTRY /DEF:mydll.def mydll.obj




Result


We put the files mydll.dll and TestJNI.class in one folder and see what happened: This is a victory, we learned how to add two numbers! If suddenly someone became interested, then the following links will come in handy:

>java TestJNI
5







Also popular now: