Linux下,没有在Andorid下面搞,安卓开发效率太低了。。只是单纯手搓一下。。
HelloJNI.java
public class HelloJNI {
static {
System.loadLibrary("hello"); // 加载本地库
}
// 声明一个本地方法
private native void sayHello();
public static void main(String[] args) {
new HelloJNI().sayHello(); // 调用本地方法
}
}
hello.cpp
#include <jni.h>
#include <iostream>
// 定义本地方法
extern "C" JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *, jobject) {
std::cout << "Hello from C++!" << std::endl;
}
生成JNI头文件
javac HelloJNI.java
javah -jni HelloJNI
这里会生成HelloJNI.class。
之后会生成头文件,HelloJNI.h。
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloJNI */
#ifndef _Included_HelloJNI
#define _Included_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloJNI
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloJNI_sayHello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
中间可能会提示Java没有装,装下面几个就可以了。也不用全装,headless装一个就行了。
sudo apt install openjdk-11-jdk-headless # version 11.0.23+9-1ubuntu1~20.04.2, or
sudo apt install default-jdk # version 2:1.11-72
sudo apt install openjdk-13-jdk-headless # version 13.0.7+5-0ubuntu1~20.04
sudo apt install openjdk-16-jdk-headless # version 16.0.1+9-1~20.04
sudo apt install openjdk-17-jdk-headless # version 17.0.11+9-1~20.04.2
sudo apt install openjdk-21-jdk-headless # version 21.0.3+9-1ubuntu1~20.04.1
sudo apt install openjdk-8-jdk-headless # version 8u412-ga-1~20.04.1
sudo apt install ecj # version 3.16.0-1
编译和运行
export JAVA_HOME="/usr/lib/jvm/java-1.8.0-openjdk-amd64"
g++ -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -shared -o libhello.so hello.cpp
java -Djava.library.path=. HelloJNI
之后就会生成libhello.so
然后直接运行即可。
其实可以看到,JNI整个也并没有做太多东西,本质就是一个动态运行库。整个也没有对操作系统,语言做一些很深层次的定制,大部分还是基于语言的特性来弄的。有空可以看看JNI那几个宏,就一切都明白了。
#define JNIEXPORT __attribute__ ((visibility ("default")))
。。。
对了,这个so本身也是ELF格式的,可以用相关命令查看。
ubuntu@VM-8-10-ubuntu:~/test/jni$ readelf -h libhello.so
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x10c0
Start of program headers: 64 (bytes into file)
Start of section headers: 14944 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 11
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 29
详细看可以看到里面有两个符号表,常规的.symtab, 另一种是精简的.dynsym。要链接的是在动态中,也就是12: 0000000000001179 66 FUNC GLOBAL DEFAULT 14 Java_HelloJNI_sayHello
只要代码里面稍微改变一点,就可以看到这个函数大小发生变化。
ubuntu@VM-8-10-ubuntu:~/test/jni$ readelf -s libhello.so
Symbol table '.dynsym' contains 13 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitC1Ev@GLIBCXX_3.4 (2)
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __cxa_atexit@GLIBC_2.2.5 (3)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev@GLIBCXX_3.4 (2)
5: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZStlsISt11char_traitsIcE@GLIBCXX_3.4 (2)
7: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
8: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (3)
9: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND _ZSt4cout@GLIBCXX_3.4 (2)
10: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSolsEPFRSoS_E@GLIBCXX_3.4 (2)
11: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZSt4endlIcSt11char_trait@GLIBCXX_3.4 (2)
12: 0000000000001179 66 FUNC GLOBAL DEFAULT 14 Java_HelloJNI_sayHello
Symbol table '.symtab' contains 62 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000000002a8 0 SECTION LOCAL DEFAULT 1
2: 00000000000002c8 0 SECTION LOCAL DEFAULT 2
3: 00000000000002f0 0 SECTION LOCAL DEFAULT 3
4: 0000000000000318 0 SECTION LOCAL DEFAULT 4
5: 0000000000000450 0 SECTION LOCAL DEFAULT 5
6: 00000000000005b8 0 SECTION LOCAL DEFAULT 6
7: 00000000000005d8 0 SECTION LOCAL DEFAULT 7
8: 0000000000000618 0 SECTION LOCAL DEFAULT 8
9: 0000000000000720 0 SECTION LOCAL DEFAULT 9
10: 0000000000001000 0 SECTION LOCAL DEFAULT 10
11: 0000000000001020 0 SECTION LOCAL DEFAULT 11
12: 0000000000001070 0 SECTION LOCAL DEFAULT 12
13: 0000000000001080 0 SECTION LOCAL DEFAULT 13
14: 00000000000010c0 0 SECTION LOCAL DEFAULT 14
15: 0000000000001224 0 SECTION LOCAL DEFAULT 15
16: 0000000000002000 0 SECTION LOCAL DEFAULT 16
17: 0000000000002014 0 SECTION LOCAL DEFAULT 17
18: 0000000000002050 0 SECTION LOCAL DEFAULT 18
19: 0000000000003de0 0 SECTION LOCAL DEFAULT 19
20: 0000000000003df0 0 SECTION LOCAL DEFAULT 20
21: 0000000000003df8 0 SECTION LOCAL DEFAULT 21
22: 0000000000003fc8 0 SECTION LOCAL DEFAULT 22
23: 0000000000004000 0 SECTION LOCAL DEFAULT 23
24: 0000000000004038 0 SECTION LOCAL DEFAULT 24
25: 0000000000004040 0 SECTION LOCAL DEFAULT 25
26: 0000000000000000 0 SECTION LOCAL DEFAULT 26
27: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
28: 00000000000010c0 0 FUNC LOCAL DEFAULT 14 deregister_tm_clones
29: 00000000000010f0 0 FUNC LOCAL DEFAULT 14 register_tm_clones
30: 0000000000001130 0 FUNC LOCAL DEFAULT 14 __do_global_dtors_aux
31: 0000000000004040 1 OBJECT LOCAL DEFAULT 25 completed.8061
32: 0000000000003df0 0 OBJECT LOCAL DEFAULT 20 __do_global_dtors_aux_fin
33: 0000000000001170 0 FUNC LOCAL DEFAULT 14 frame_dummy
34: 0000000000003de0 0 OBJECT LOCAL DEFAULT 19 __frame_dummy_init_array_
35: 0000000000000000 0 FILE LOCAL DEFAULT ABS hello.cpp
36: 0000000000002000 1 OBJECT LOCAL DEFAULT 16 _ZStL19piecewise_construc
37: 0000000000004041 1 OBJECT LOCAL DEFAULT 25 _ZStL8__ioinit
38: 00000000000011bb 77 FUNC LOCAL DEFAULT 14 _Z41__static_initializati
39: 0000000000001208 25 FUNC LOCAL DEFAULT 14 _GLOBAL__sub_I_hello.cpp
40: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
41: 0000000000002120 0 OBJECT LOCAL DEFAULT 18 __FRAME_END__
42: 0000000000000000 0 FILE LOCAL DEFAULT ABS
43: 0000000000002014 0 NOTYPE LOCAL DEFAULT 17 __GNU_EH_FRAME_HDR
44: 0000000000001224 0 FUNC LOCAL DEFAULT 15 _fini
45: 0000000000004000 0 OBJECT LOCAL DEFAULT 23 _GLOBAL_OFFSET_TABLE_
46: 0000000000004040 0 OBJECT LOCAL DEFAULT 24 __TMC_END__
47: 0000000000004038 0 OBJECT LOCAL DEFAULT 24 __dso_handle
48: 0000000000003df8 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC
49: 0000000000001000 0 FUNC LOCAL DEFAULT 10 _init
50: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
51: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitC1Ev@@
52: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __cxa_atexit@@GLIBC_2.2.5
53: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev@@
54: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
55: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZStlsISt11char_traitsIcE
56: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
57: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.2
58: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND _ZSt4cout@@GLIBCXX_3.4
59: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSolsEPFRSoS_E@@GLIBCXX
60: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZSt4endlIcSt11char_trait
61: 0000000000001179 66 FUNC GLOBAL DEFAULT 14 Java_HelloJNI_sayHello
当然,用nm也可以查看:
ubuntu@VM-8-10-ubuntu:~/test/jni$ nm libhello.so
0000000000004040 b completed.8061
U __cxa_atexit@@GLIBC_2.2.5
w __cxa_finalize@@GLIBC_2.2.5
00000000000010c0 t deregister_tm_clones
0000000000001130 t __do_global_dtors_aux
0000000000003df0 d __do_global_dtors_aux_fini_array_entry
0000000000004038 d __dso_handle
0000000000003df8 d _DYNAMIC
00000000000012d0 t _fini
0000000000001170 t frame_dummy
0000000000003de0 d __frame_dummy_init_array_entry
0000000000002120 r __FRAME_END__
0000000000004000 d _GLOBAL_OFFSET_TABLE_
00000000000012b4 t _GLOBAL__sub_I_hello.cpp
w __gmon_start__
0000000000002014 r __GNU_EH_FRAME_HDR
0000000000001000 t _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000001179 T Java_HelloJNI_sayHello
00000000000010f0 t register_tm_clones
0000000000004040 d __TMC_END__
0000000000001267 t _Z41__static_initialization_and_destruction_0ii
U _ZNSolsEPFRSoS_E@@GLIBCXX_3.4
U _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4
U _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4
U _ZSt4cout@@GLIBCXX_3.4
U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@@GLIBCXX_3.4
0000000000002000 r _ZStL19piecewise_construct
0000000000004041 b _ZStL8__ioinit
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@@GLIBCXX_3.4
还是一个分析工具就是objdump,空了再单独写一个ELF吧。
参考: