星期六, 3月 29, 2008

移植KVM到arm-linux


引用自: http://tech.jayya.com/2007/11/28/porting-kvm-to-armlinux.html

上午kvm能正常在板子上运行了,并且还解决了preverify的问题(感谢一下陶老师的帮助和提醒),今天一并完整的写出来整个过程吧

  1. 建立交叉编译环境:
    • 下载xscale-arm-linux-toolchain.tgz,tar zxfv xscale-arm-linux-toolchain.tgz,将解压后的文件在/usr/local/arm-linux下,将他击入当前的路径下, 比如修改你的.bash_profile,PATH=$PATH:/usr/local/arm-linux/bin,退出,在登陆使之生效,输入arm -linux-gcc -v可以查看gcc的版本;
    • 很抱歉,写得时候漏写了一个重要的设置步骤,多谢雨里来的提醒,现补充如下:我们还需要安装交叉编译环境的标准C函数库,进入系统的/usr/目录并解压库函数软件包
      [user@host]# cd /usr
      [user@host]# tar zvxf /root/gnupro-bin-glibc2.2.4.tgz
      上述命令会在系统目录/usr/cygnus/xscale-020726/H-i686-pc-linux-gnulibc2.4/目录下建立一系列的子目录和文件,它们是交叉编译时需要的标准C函数库和各种工具。
  2. 下载sun的cldc的src
  3. 解压,里面包含有相关的源码。我这里使用了j2me_cldc-1_0_4-src-winunix.zip,j2me_cldc-1_1-fcs -src-winunix.zip这两个都可以在sun的网站下载,不过推荐大家抓紧时间下载,因为今天去下载midp2.0就已经不能下载了(sun 阿,令人失望!)。

  4. 安装jdk并设置后相关路径
  5. 这里不推荐使用jdk1.5,因为他对中文的支持有问题,使用1.4或者更低的都可以(希望可以在sun的官方找到)
    我使用的是1.4.2_01。修改.bash_profile或者/etc/profile添加PATH或者CLASSPATH。这里说一些为什么要用到 jdk,主要是要编译api里面的java文件,当然我们只一致kvm就不需要这个了,详细地大家可以看看解开的文件cldc文件夹里面的make文件

  6. 修改make文件
  7. 进入j2me_cldc/kvm/VmUnix/build/,vi修改Makefile,主要修改将原来使用的x86的编译器GCC改为我们的 arm-linux-gcc,这样才能得到我们的所需,我主要是修改下面的句子:ifeq ($(GCC), true) CC =arm-linux-gcc,另外我又在文件的开始指定export PLATFORM=linux,当然你也可以在make的时候加参数PLATFORM=linux。

  8. 编译
  9. 先编译preverify,进入tools/preverfiyer/build/linux下,make,这里没有必要对这个makefile进 行修改,况且你的编译平台是x86,应该不能进行修改,否则编译出来的preverify是不运行的,那么kvm的编译也将会不能通过。
    编译kvm,进入kvm/VmUnix/build,make,就可以得到kvm,注意这个是在kvm的build目录下生成的,file kvm会的到以下信息:kvm: ELF 32-bit LSB executable, ARM, version 1 (ARM), for GNU/Linux 2.4.18, dynamically linked (uses shared libs), not stripped

  10. 在板子上运行并进行相应的测试
  11. 将得到的kvm,烧到板子上,x86下kvm运行所需文件: libm.so.6 => /lib/tls/libm.so.6 (0xb75c0000)
    libnsl.so.1 => /lib/libnsl.so.1 (0xb75ab000)
    libc.so.6 => /lib/tls/libc.so.6 (0xb7473000)
    /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0xb75eb000)
    大家可以参考以下,以便能使板子环境符合要求.更改属性为a+x,运行kvm,没有任何参数的情况下将会出现以下信息:ALERT: Must provide class name
    Usage: kvm < -options>
    Options:
    -version
    -classpath
    -heapsize (e.g. 65536 or 128k or 1M)

  12. 运行helloworld并正确使用preverify
  13. 这一步准确来说不是移植要做的事情,因为这是j2me开发者要注意的事情.我们先来看看kvm的执行.class 文件的机制:
    portingVerifiera.gif
    如图示:我们javac编译完的生成的.class文件必须经过preverify预验证后才能被kvm正确的执行,否则会出现 java/class/Verifyerror,为什么要采用预验证机制,是因为sun考虑到嵌入式设备资源有限,所以将jvm的庞大字节码验证机制进行 严重的”缩水”,也就用了一个轻量级机制
    来保证安全.说了这么多,讲讲具体怎么使用(这个流程开发j2me程序的人应该都知道点,虽然大家都不常用这个来开发).
    1编译javac -classpath kvm/classes hello.java 这里kvm/classes指你编译生成的classes文件夹
    2预验证preverify -classpath kvm/classes -d . mydir
    preverify有几个参数: -classpath 同上 -d 输出验证后的class文件,默认的是当前目录下的output文件夹下,还有检测是否使用了 finalizers ,float,native methods等
    将检验后的classs文件放到板子上,就可以执行了!


CLDC 1.0.4 Fix for Red_Hat

引用自: http://forum.java.sun.com/thread.jspa?threadID=468349


The following works for J2ME CLDC 1.1 (it may be the same for 1.0.4, I didn't try that).

If you don't care to verify that you are having the same problem, skip ahead a bit to what I did to fix the problem I was having.

Rebuild the kvm with debugging on. Goto the j2me_cldc/build/linux directory
edit Makefile around the 4th line add a line that says "export DEBUG=true"
If you have previously run make then do "make clean" then "make"

Im assuming your PATH and CLASSPATH are set appropriately so you can simply prevreify a class by typing "preverify HelloWorld" and you see "Segmentation fault"

At this point run "preverify -verbose HelloWorld" and you will see that it is indeed running and loading classes but it craps out after a few classes.

To run the debugger on this type "gdb --args preverify HelloWorld"
at the (gdb) prompt type "run". You will see
"Program received signal SIGSEGV, Segmentation fault."
Type bt (or backtrace) in the debuger. If you see something like this

#0 0x4207c1ac in memcpy () from /lib/tls/libc.so.6
#1 0x080520ef in utf2native ()
#2 0x0805b9ab in Locked_InitializeClass ()
...

then you either didn't get the "export DEBUG=true" part right or your didn't "make clean" or something else happened. You should see something more like this (more detail):

#0 0x4207c1ac in memcpy () from /lib/tls/libc.so.6
#1 0x080520ef in utf2native (from=0x8069740 "?_006b", to=0xbfff6ba0 "",
buflen=-1073779800) at ../../src/convert_md.c:100
#2 0x0805b9ab in Locked_InitializeClass (cb=0x8069740, detail=0xbfff6ba0)
at ../../src/classresolver.c:685
#3 0x0805b57a in InitializeClass (cb=0x8069740, detail=0xbfff6ba0)
at ../../src/classresolver.c:506
#4 0x0805c2af in InitializeAndResolveClass (cb=0x8069740, resolve=FALSE)
at ../../src/classresolver.c:991
...

what this is telling you is that the glibc memcpy function is where the segfault happened. memcpy is trying to copy memory but it looks like the buffer length (buflen) is bogus. memcpy is called from utf2native which is called by Locked_InitializerClass in classresolver.c

Quit the debugger (“quit”). Goto j2me_cldc/tools/preverifier/src/

Look at the file classresolver.c, at the Locked_InitializerClass function, around line 572. See the lines

char buff[BUFSIZ];
char *nativeName = &buff[0];

remember them. Look down to line 685, see the lines

utf2native(cbSuperName(cb), nativeName, BUFSIZ);
super = FindClassFromClass(ee, nativeName, FALSE, cb);

Nowehere else in classresolver.c is this buff or *nativeName used (so Im assuming we are free to mess with without significantly impacting anything else). What this is doing is creating a buffer on the stack that is BUFSIZ big (8192 bytes). utf2native gets the buffer and size and calls memcpy. Im guessing that because the preverifier seems to be loading classes recursively that there are lots of buffers like this on the stack hanging around and Im running out of stack space which results in a segmentation fault. I don’t know why EVERYONE running linux doesn’t have this problem.

How to fix this? We are now going to change the program to put the buffer in dynamic memory not on the stack.

In classresolver.c, around line 572, change the buff and nativeName declarations to this (comment out the old ones, put in new ones):

//char buff[BUFSIZ];
//char *nativeName = &buff[0];
char *buff;
char *nativeName;

The skip down to around line 685. Add a few lines around the call to utf2native to look like this:

buff = (char*)malloc(BUFSIZ);
if (buff == NULL)
fprintf( stderr, "Bogus, malloc failed." );
nativeName = buff;

utf2native(cbSuperName(cb), nativeName, BUFSIZ);
super = FindClassFromClass(ee, nativeName, FALSE, cb);

free(buff);

We added 4 lines before the utf2native call and the free(buff) after it. What we are doing is allocating dynamic memory for the buffer (not on the stack this time) and freeing it right after we are done with it.

Save your work. Now "make clean" and "make". When you try to run the preverifier, turn on -verbose. You will get the preverifier to run a little further but it may still die with a segmentation fault, this time in a different place, same problem. I found four c files that declare and use buff[BUFSIZ] (classloader.c, classresolver.c, file.c and jar_support.c). I also found that if you have your CLASSPATH is set to point to the j2me_cldc/api/classes directory or j2me_cldc/api/classes.zip file you will get the same error but different calling functions. My CLASSPATH originally pointed to the classes directory and the classloader.c and classresolver.c were crapping out. I switched to having the CLASSPATH point to the classes.zip file and then the jar_support.c functions were the problem. I fixed all 4 just to be sure. Im not guaranteeing this will solve your problem. But it solved mine.

Dan

0 意見: