Coins Java - Experiment03

インスタンスメソッドの直接呼出し

[Coins Java - Experiment]

目的

作業

まず、java.lang.Objectのメソッドを調べる

$ javap java.lang.Object
public class java.lang.Object{
    public native int hashCode();
    static {};
    public java.lang.Object();
    protected void finalize();
       throws java/lang/Throwable
    public final native void notify();
    public final native void notifyAll();
    public final void wait();
       throws java/lang/InterruptedException
    public final native void wait(long);
       throws java/lang/InterruptedException
    public final void wait(long,int);
       throws java/lang/InterruptedException
    public final native java.lang.Class getClass();
    protected native java.lang.Object clone();
       throws java/lang/CloneNotSupportedException
    public boolean equals(java.lang.Object);
    public java.lang.String toString();
}

このうち、オーバーライド可能なメソッドを取り出す

実際にオーバーライドしたクラスを作成する

$ emacs Overridden.java
--- Overridden.java
public class Overridden {
    public int hashCode() {
        System.out.println("hashCode");
        return 0;
    }

    public void finalize() {
        System.out.println("finalize");
    }

    public Object clone() {
        System.out.println("clone");
        return null;
    }

    public boolean equals(Object o) {
        System.out.println("equals");
        return false;
    }

    public String toString() {
        System.out.println("toString");
        return null;
    }
}
---
$ javac Overridden.java
$ gcj -c Overridden.class

mangleされたメソッド名を調べる

$ objdump -t Overridden.o

Overridden.o:     file format elf32-i386

SYMBOL TABLE:
00000000 l    df *ABS*  00000000 Overridden.class
00000000 l    d  .text  00000000
00000000 l    d  .data  00000000
00000000 l    d  .bss   00000000
00000000 l    d  .debug_abbrev  00000000
00000000 l    d  .debug_info    00000000
00000000 l    d  .debug_line    00000000
000000a4 l     O .data  00000018 _CD_Overridden
00000000 l    d  .rodata        00000000
00000000 l     O .rodata        00000004 _Utf1
0000000c l     O .rodata        00000004 _Utf2
00000014 l     O .rodata        00000004 _Utf3
00000022 l     O .rodata        00000004 _Utf4
0000002a l     O .rodata        00000004 _Utf5
00000038 l     O .rodata        00000004 _Utf6
00000042 l     O .rodata        00000004 _Utf7
0000005c l     O .rodata        00000004 _Utf8
00000068 l     O .rodata        00000004 _Utf9
00000082 l     O .rodata        00000004 _Utf10
00000090 l     O .rodata        00000004 _Utf11
00000000 l     O .data  00000078 _MT_Overridden
000000bc l     O .data  00000006 _CT_Overridden
000000aa l     O .rodata        00000004 _Utf12
00000000 l    d  .jcr   00000000
00000000 l     O .bss   00000018 otable_syms
00000000 l    d  .debug_frame   00000000
00000000 l    d  .eh_frame      00000000
00000000 l    d  .debug_pubnames        00000000
00000000 l    d  .debug_aranges 00000000
00000000 l    d  .debug_str     00000000
00000000 l    d  .note.GNU-stack        00000000
00000000 l    d  .comment       00000000
00000000 g     F .text  00000017 _ZN10OverriddenC1Ev
00000000         *UND*  00000000 _ZN4java4lang6ObjectC1Ev
00000018 g     F .text  00000038 _ZN10Overridden8hashCodeEv
00000000         *UND*  00000000 _ZN4java4lang6System6class$E
00000000         *UND*  00000000 _Jv_InitClass
00000000         *UND*  00000000 _ZN4java4lang6System3outE
00000050 g     F .text  00000033 _ZN10Overridden8finalizeEv
00000084 g     F .text  00000038 _ZN10Overridden5cloneEv
000000bc g     F .text  00000038 _ZN10Overridden6equalsEPN4java4lang6ObjectE
000000f4 g     F .text  00000038 _ZN10Overridden8toStringEv
00000080 g     O .data  00000024 _ZTVN10OverriddenE
000000e0 g     O .data  00000068 _ZN10Overridden6class$E
00000000         *UND*  00000000 _ZTVN4java4lang5ClassE
00000000         *UND*  00000000 _ZN4java4lang6Object6class$E
00000000         *UND*  00000000 __gcj_personality_v0

抜き出すと以下のようになった

CNIを呼び出せるようなクラスを作成

$ emacs Start.java
--- Start.java
public class Start {

    public static void main(String[] args) {
        nativeMethod();
    }

    public static native void nativeMethod();
}
---
$ javac Start.java
$ gcc -c Start.class

CNIヘッダを作成

$ gcjh Start

CNIからCの関数を呼び出すためのヘッダを作成

$ emacs CoinsJavaP4.h
--- CoinsJavaP4.h
#ifndef __COINS_JAVA_P4_H
#define __COINS_JAVA_P4_H

extern "C" {
  void langc(void);
}

#endif /* __COINS_JAVA_P4_H */
---

CNIを実装

$ emacs natStart.cc
--- natStart.cc
#include "Start.h"
#include "CoinsJavaP4.h"

void Start::nativeMethod (){
  langc();
}
---
$ gcc -c natStart.cc

メソッド名をmangleしたヘッダを作る

$ emacs cCallNonvirtual.h
--- cCallNonvirtual.h
#ifndef __C_CALL_NONVIRTUAL_H
#define __C_CALL_NONVIRTUAL_H

long _ZN10Overridden8hashCodeEv(void *);
void _ZN10Overridden8finalizeEv(void *);
void *_ZN10Overridden5cloneEv(void *);
long _ZN10Overridden6equalsEPN4java4lang6ObjectE(void *, void *);
void *_ZN10Overridden8toStringEv(void *);

#endif /* __C_CALL_NONVIRTUAL_H */
---

順に呼び出してみるC++と同じ形式だと判断して、最初の引数はオブジェクトの参照を渡すここではnullリテラルを渡すことにする

$ emacs CoinsJavaP4.c
--- CoinsJavaP4.c
#include <stdio.h>
#include "cCallNonvirtual.h"

void langc(void) {
  _ZN10Overridden8hashCodeEv((void *)0);
  _ZN10Overridden5cloneEv((void *)0);
  _ZN10Overridden6equalsEPN4java4lang6ObjectE((void *)0, (void *)0);
  _ZN10Overridden8toStringEv((void *)0);
  _ZN10Overridden8finalizeEv((void *)0);
}
---
$ gcc -c CoinsJavaP4.c

コンパイル

$ gcj --main=Start Start.class natStart.o Overridden.o CoinsJavaP4.o

結果

以下のようになった

$ ./a.out

Aborted

<clinit>が存在しないのに、Abortされてしまったおそらく以下の理由だと推測できる

作業2

前回同様に、クラスの初期化を行う

まずは、Overriddenのjava.lang.Classインスタンスと_Jv_InitClassにアクセスできるようにする

$ emacs cCallNonvirtual.h
--- cCallNonvirtual.h
#ifndef __C_CALL_NONVIRTUAL_H
#define __C_CALL_NONVIRTUAL_H

extern void _ZN10Overridden6class$E;
void _Jv_InitClass(void *);

long _ZN10Overridden8hashCodeEv(void *);
void _ZN10Overridden8finalizeEv(void *);
void *_ZN10Overridden5cloneEv(void *);
long _ZN10Overridden6equalsEPN4java4lang6ObjectE(void *, void *);
void *_ZN10Overridden8toStringEv(void *);

#endif /* __C_CALL_NONVIRTUAL_H */
---

クラスの初期化を最初に行う

$ emacs CoinsJavaP4.c
--- CoinsJavaP4.c
#include <stdio.h>
#include "cCallNonvirtual.h"

void langc(void) {

  _Jv_InitClass(&_ZN10Overridden6class$E);

  _ZN10Overridden8hashCodeEv((void *)0);
  _ZN10Overridden5cloneEv((void *)0);
  _ZN10Overridden6equalsEPN4java4lang6ObjectE((void *)0, (void *)0);
  _ZN10Overridden8toStringEv((void *)0);
  _ZN10Overridden8finalizeEv((void *)0);
}
---
$ gcc -c CoinsJavaP4.c

コンパイル

$ gcj --main=Start Start.class natStart.o Overridden.o CoinsJavaP4.o

結果2

以下のようになった

$ ./a.out
hashCode
clone
equals
toString
finalize

正しく呼び出されていることが判る

Copyright (C) 2002-2006 s.arakawa