c没有main函数/java没有main方法--语言运行的实质之实例

前面我们看到,没有main的代码也能执行,之所以拥有main是为了遵循一种规定,遵循这个规定得到的益处是一切更加紧凑,数据冗余更小,程序更好维护,系统更好维护...如果抛开这些不谈,代码的编写其实是很灵活的,完全不需要遵循任何的附加规定,所需要遵循的只是冯氏机器的执行流程。本文就来整一套没有main的c代码和java代码的混合,旨在揭示代码运行的深层含义以及c语言和java语言的启动和层次关系。我们按一个操作步骤一步一步来:
1.准备没有main方法但是期望成为java主类的类文件-Test.java
class Test {
        public native void Wrapper();
        static {
                System.loadLibrary("from-java");
        }
        public static void sub(String[] args) {
                new TestStunnel().Wrapper();
        }
}
编译之:javac Test.java
并且用c实现一个so,实现Wrapper方法,它可以是stunnel,可以是openvpn,只需要将其main函数改为Wrapper并且编译成so而不是可执行文件即可!
2.准备一个汇编文件-loader.asm,它负责直接接管sys_execve内核系统调用返回用户态的第一时间的执行流:
global _start
extern not_main
section .text
_start:
        call not_main
        ret
用nasm编译之:nasm -f elf loader.asm
3.准备一个c文件-startjvm.c,它启动java虚拟机,并且执行java方法:
#include <jni.h>
#include <stdio.h>
int not_main() {
        JavaVM *vm;
        JNIEnv *env;
    ... //见上篇的代码或者直接参考java.c
}
用gcc编译之:gcc -c startjvm.c -I<jdk的include和include/linux目录>
4.将上述的链接在一起:gcc -nostartfiles  startjvm.o loader.o <jre的jvm动态库路径>/libjvm.so -o no_main_main
必须使用-nostartfiles,因为只有这样,编译器才不会自动加入启动函数以及别的库级别的初始化,才不会调用标准链接器的_start,关于这个你可以通过ld --verbose来观看!
5.执行吧:./no_main_main
6.结果Wrapper被调用,整个过程完全自给掌控,没有main函数,也没有main方法!
7.有一种更方便的不调用main的方式,那就是gcc指定-e参数,后面跟你希望执行的函数名称,这样虽然能达到一定的效果,但是估计你除了多学习了一个gcc参数之外,什么也学不到。
8.整个过程中我们把所有的逻辑往下压了一层,c语言中不再从语言机制的main开始,而是从链接器机制的_start开始,java语言中不再以语言机制的main开始,而是从jvm的GetStaticMethodID和随后的CallStaticVoidMethod开始。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值