Связывание проблем с JNI при переходе с Java 1.5 на 1.6 под IBM J9
Некоторое изменение в IBM J9 JVM 1.6 (более 1.5) приводит к ошибке связывания, которая вызывает возникновение исключения во время выполнения. В частности, мы используем JNI для загрузки общей библиотеки, которая содержит объектные файлы с кодом:
extern _edata;
extern _etext;
extern _end;
Эти адреса используются в подсистеме памяти и должны предоставляться компоновщиком. Однако компоновщик AIX не связывает их, когда мы компилируем разделяемую библиотеку (однако он связывает правильно, если вы создаете исполняемый файл).
Сообщение об ошибке JNI:
java.lang.UnsatisfiedLinkError: oas-jni (rtld: 0712-001 Symbol _edata was referenced
from module /usr/IBM/blackbird/lib/liboas-jni.so(), but a runtime definition of the symbol was not found.
rtld: 0712-001 Symbol _etext was referenced from module /usr/IBM/blackbird/lib/liboas-jni.so(), but a runtime definition of the symbol was not found.
rtld: 0712-001 Symbol _end was referenced from module /usr/IBM/blackbird/lib/liboas-jni.so(), but a runtime definition of the symbol was not found.
rtld: 0712-002 fatal error: ex)
at java.lang.ClassLoader.loadLibraryWithPath(ClassLoader.java:1035)
at java.lang.ClassLoader.loadLibraryWithClassLoader(ClassLoader.java:999)
at java.lang.System.loadLibrary(System.java:507)
at com.integrasolv.owl.oas.OAS_Init.<clinit>(OAS_Init.java:16)
at java.lang.J9VMInternals.initializeImpl(Native Method)
at java.lang.J9VMInternals.initialize(J9VMInternals.java:201)
at com.integrasolv.owl.oas.OAS_Agent.<clinit>(OAS_Agent.java:87)
at java.lang.J9VMInternals.initializeImpl(Native Method)
at java.lang.J9VMInternals.initialize(J9VMInternals.java:201)
at blackbird.testclient.TestClient.initOwlProcesses(TestClient.java:120)
at blackbird.testclient.TestClient.main(TestClient.java:75)
Exception in thread "main" java.lang.UnsatisfiedLinkError: com/integrasolv/owl/oas/OAS_Agent.setEnv(Ljava/lang/String;Ljava/lang/String;)V
at blackbird.testclient.TestClient.initOwlProcesses(TestClient.java:120)
at blackbird.testclient.TestClient.main(TestClient.java:75)
Тестовый файл "Голые кости":
// test.c
#include <stdio.h>
#include <stdlib.h>
extern char _etext, _edata, _end;
int runtest() {
printf("First address past:\n");
printf(" program text (etext) %10p\n", &_etext);
printf(" initialized data (edata) %10p\n", &_edata);
printf(" uninitialized data (end) %10p\n", &_end);
exit(EXIT_SUCCESS);
}
Скомпилировать объектный файл без ссылки
$ gcc -c test.c
Создайте общую библиотеку из test.o
$ gcc -shared -Wl,-G -o libtest.a test.c
Обратите внимание, что -G включает параметр -berok для компоновщика, игнорирует ошибки. В противном случае мы увидим некоторые неопределенные ошибки символов для _etext, _edata и _end здесь.
Дамп таблицы символов из общей библиотеки
$ dump -Tv libtest.a
libtest.a:
***Loader Section***
***Loader Symbol Table Information***
[Index] Value Scn IMEX Sclass Type IMPid Name
[0] 0x200006e4 .data RW SECdef [noIMid] __rtinit
[1] 0x00000000 undef IMP DS EXTref libgcc_s.a(shr.o) __cxa_finalize
[2] 0x00000000 undef IMP DS EXTref libc.a(shr.o) exit
[3] 0x00000000 undef IMP DS EXTref libc.a(shr.o) printf
[4] 0x00000000 undef IMP DS EXTref libc.a(shr.o) strtod
[5] 0x00000000 undef IMP DS EXTref libc.a(shr.o) __fd_select
[6] 0x00000000 undef IMP DS EXTref libc.a(shr.o) puts
[7] 0x00000000 undef IMP DS EXTref libc.a(shr.o) __strtollmax
[8] 0x200006d0 .data EXP RW Ldef [noIMid] __dso_handle
[9] 0x20000750 .data EXP DS Ldef [noIMid] __init_aix_libgcc_cxa_atexit
[10] 0x20000780 .data EXP DS Ldef [noIMid] runtest
[11] 0x00000000 undef IMP PR EXTref .. _etext
[12] 0x00000000 undef IMP PR EXTref .. _edata
[13] 0x00000000 undef IMP PR EXTref .. _end
нм выход:
$ nm libtest.a|grep _e
_edata U -
_edata d 536872908 4
_end U -
_end d 536872916 4
_etext U -
_etext d 536872900 4
Мне не совсем понятно, что здесь происходит. На Linux это работает нормально. Вывод команды nm в том же тесте, но в GNU/Linux
0000000000201040 D _edata
0000000000201048 B _end
000000000000082d T _etext
1 ответ
Основная программа (например, /usr/java*/jre/bin/java) должна экспортировать эти символы (опция связывания -Wl, -bE: esyms.sym), а разделяемая библиотека должна их импортировать (опция связывания -Wl, -bI: esyms.sym) Содержимое этого файла esyms.sym:
#! .
_etext
_edata
_end
Вы можете проверить, экспортирует ли ваша Java эти символы:
dump -Tv -X32_64 /usr/java*/jre/bin/java | grep _etext