1

Some change in the IBM J9 JVM 1.6 (over 1.5) causes a linkage error we were experiencing to cause a runtime exception. Specifically, we’re using the JNI to load a shared library that contains object files with the code:

extern _edata;
extern _etext;
extern _end;

These are addresses used in the memory subsystem, and are supposed to be supplied by the linker. However, the AIX linker isn’t linking them when we compile a shared library (it does, however, link properly if you make an executable).

JNI error message:

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)

Bare Bones Test file:

// 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);
 }

Compile object file without linking

$ gcc -c test.c

Create a shared library from test.o

$ gcc -shared -Wl,-G -o libtest.a test.c

Note that -G includes the -berok option for the linker, ignores errors. Otherwise we would see some undefined symbol errors for _etext, _edata, and _end here.

Dump symbol table from the shared library

$ 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 output:

$ nm libtest.a|grep _e
  _edata               U           -
  _edata               d   536872908           4
  _end                 U           -
  _end                 d   536872916           4
  _etext               U           -
  _etext               d   536872900           4

Not entirely clear to me what’s occurring here. On linux this works fine. Output of nm command on the same test but on GNU/Linux

0000000000201040 D _edata
0000000000201048 B _end
000000000000082d T _etext
Arthur
  • 21
  • 2

1 Answers1

2

The main program (eg /usr/java*/jre/bin/java) should export these symbols (linking option -Wl,-bE:esyms.sym), and the shared lib should import them (linking option -Wl,-bI:esyms.sym) The content of this esyms.sym file:

#! .
_etext
_edata
_end

You can check if your java exports these symbols:

dump -Tv -X32_64 /usr/java*/jre/bin/java | grep _etext
Lorinczy Zsigmond
  • 1,749
  • 1
  • 14
  • 21
  • What if your JRE doesn't export those symbols? `$ dump -Tv -X32_64 /usr/java6_64/jre/bin/java | grep _etext` returns nothing. – ktbiz Nov 02 '15 at 20:56
  • 1
    Well, you should decide if you really want to play with java/libc's memory management (I don't think you should). Nonetheless, you can try and relink java executable. – Lorinczy Zsigmond Nov 03 '15 at 09:09
  • 1
    Something like this: `ld -b64 -bE:esyms.sym -o java_haxored /usr/lib/crt0_64.o /usr/java6_64/jre/bin/java /usr/lib/libiconv.a /usr/lib/libpthread.a /usr/lib/libc.a` – Lorinczy Zsigmond Nov 03 '15 at 09:29