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开始。

原文链接: https://blog.csdn.net/dog250/article/details/6007293

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

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

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/409574

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月26日 上午11:29
下一篇 2023年4月26日 上午11:29

相关推荐