解析 dylib 文件并且找到 java native 方法的源代码

参见博客

1
2
nm libjava.dylib
gobjdump -tT libjava.dylib // 使用 brew install binutils 安装

Native 方法在 Oracle Java 是不让看的。我们只能从 Openjdk 中看。我在编译好的 openjdk 源码的 build.log 中找到了一大堆 native 方法的编译 log,但是却没有发现它们到底最后被编译到哪了。而且挨个翻 Makefile 也是不太可能的(看不懂哈哈)。于是只能暴力一些了。找到 Openjdk 目录下的各种 libs,首先我的 jdk 在前一个博客也说过是 openjdk8。在 <yourjdk>/build/macosx-x86_64-normal-server-****/jdk/lib 下,有一大堆的 libs。我估计就是他们(逃)。但是怎么确认呢?请参加上方的 blog。执行那两个命令之中的任意一个。然后你就会得到一大堆的输出。然后随便找一个函数,直接在源码目录 yourjdk/jdk/src/share/native 目录下使用 grep -rn <method_name> . 就好了!然后发现确实能查到的!虽然不能一一对应就是了。不过这样也是大有进展,这样就可以直接调用人家写好的 Native 方法了~

外赠一个 shell 脚本来检查到底某个 native 方法被放到哪个 dylib 中去了:

1
2
3
4
5
6
7
8
9
cd <yourjdk>/build/macosx-x86_64-normal-server-****/jdk/lib # 此句是伪码
for file in ./*
do
if [[ "$file" =~ "dylib$" ]] # 以 dylib 结尾的文件
then
nm $file | grep registerNative | xargs -0 echo $file {} # registerNative 可以换成你要查找的方法名~
fi
done

1
2
3
4
5
6
7
8
9
10
11
# 输出:
./libawt.dylib {} 00000000000403e0 T _Java_sun_java2d_loops_GraphicsPrimitiveMgr_registerNativeLoops
./libhprof.dylib {} 000000000001ab63 T _registerNatives # 很清晰地知道,我们要找的 registerNatives 函数在 libhprof.dylib 中~
./libjava.dylib {} 00000000000028d0 T _Java_java_lang_ClassLoader_registerNatives
0000000000002460 T _Java_java_lang_Class_registerNatives
0000000000003f10 T _Java_java_lang_Compiler_registerNatives
0000000000006ea0 T _Java_java_lang_Object_registerNatives
00000000000096d0 T _Java_java_lang_System_registerNatives
000000000000f110 T _Java_java_lang_Thread_registerNatives

随后我还是查看了 Makefile……
比如 libjava 的 output 指定的 Makefile 脚本在:

/jdk/make/lib/CoreLibraries.gmk 下。(gmk 即 Gnu Makefile)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 116 - 129 行
LIBJAVA_SRC_DIRS := $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/java/lang \
$(JDK_TOPDIR)/src/share/native/java/lang \
$(JDK_TOPDIR)/src/share/native/java/lang/reflect \
$(JDK_TOPDIR)/src/share/native/java/io \
$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/java/io \
$(JDK_TOPDIR)/src/share/native/java/nio \
$(JDK_TOPDIR)/src/share/native/java/security \
$(JDK_TOPDIR)/src/share/native/common \
$(JDK_TOPDIR)/src/share/native/sun/misc \
$(JDK_TOPDIR)/src/share/native/sun/reflect \
$(JDK_TOPDIR)/src/share/native/java/util \
$(JDK_TOPDIR)/src/share/native/java/util/concurrent/atomic \
$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/common \
$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/java/util
# 这一部分指出了 libjava 的 src。所有的这些 Native 文件最后都被打包成为 libjava.dylib 的一部分。
// 220 - 224 行
$(BUILD_LIBJAVA): $(LIBJLI_BINARY) # 这个命令开始 build libjli.dylib,在 <yourjdk>/build/macosx-x86_64-normal-server-****/jdk/lib/ 下
$(BUILD_LIBJAVA): $(BUILD_LIBVERIFY) # 这个命令开始 build libverify.dylib,位置同上
$(BUILD_LIBJAVA): $(BUILD_LIBFDLIBM) # 这个命令开始 build libfdlibm.a,在 <yourjdk>/build/macosx-x86_64-normal-server-****/jdk/obj/ 下。
# libjava.dylib 依赖这三个 lib。

嗯嗯。还想要继续找的话,请各种使用 grep 命令会方便很多~