打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
java和c的性质
java很神奇吗?说什么跨平台,虚构机之类的。c#很神奇吗?c很神奇吗?垄断系统呢?cpu呢?其实这些都不神奇,过去不懂垄断系统的时候,目睹个多线程就跟目睹个传神的,目前呢?linux内核容易看,容易改,不即便历程管教那一堆事嘛,也未曾多少代码。学习任何东西的时候,凡是静态的框架以及动态的流程搞打听了,都不难的,这就和学英语一样,静态的东西其实即便字母表和单词,动态的东西即便听说读写,动静联合,必有长进。
下面以c和java为例解释其原理,尤其解释c和java是如何启用的,想必搞这个之前,每个人的c可能java的功底定然很高了。下面就一步一步地来:
写c过程的时候,等闲要写个main:
int main(int argc, char **argv);
写java的时候,等闲也要写个main:
public static void main(String argv[]);
在c语言的下面,有加载器,相仿的,在java的下面,也有加载器,c的加载器定然脱离c语言编程的机制,然而依旧能够利用c的语法写成,那么启用java的机制也定然脱离java编程的机制(加载器以下可能称为链接器)。
每一个编译好的c过程都会在其elf文件中被加入动态链接器的消息,垄断系统启用新的elf文件的时候(和历程未曾联系,历程是fork创立的,这里仅仅是加载elf,也即便exec),率先调用链接器的入口,然后连接器中再调用c的main函数(如上),其实仅仅告诉垄断系统一个入口点就能够了,容易一个都能够,垄断系统会积极调转到那里的,然而等闲而言每个垄断系统的动态链接过程是安宁的,例如在linux上即便ld-linux,这是为了收缩数据冗余,和重用组件的信念是统一的,因而等闲而言,安宁的链接器调用安宁的c入口,这个入口就被法定成了main函数,万一你自定义链接器的入口,那么你全面能够调起来入口不是main的c过程。切实上,我们曾经在利用这个措施了,那即便加载动态库并且调用动态库的函数,这个含义上,动态库即便一个能够未曾main的c过程,ld-linux.so这一类so性质上它们才是恳挚的过程入口,而我们编写的带有main的c过程能够会意成是ld-linux.so的一个动态库。
java的链接器可能加
载器可能称为启用器其实也是一样的理由,只是它比c更上层了,它的启用器不是垄断系统直接调用的,而是c语言调用的,能够感受一个带有main函数的c语言写成的过程作为了java的启用器,这个c启用器能够调用别的动态库,在这些本地环境中为java的厉行发生了一个虚构的“厉行”环境,这即便java虚构机,当心,这里“厉行”环境很重要,它导致java是跨平台的,垄断系统和c库其实也做到了屏障基层的作用,然而它们都未曾能模仿一个厉行环境,仅仅做到了接口接受而不是二进制接受,对于垄断系统而言,例如linux全面向用户空间泄露了机器号召,因而安装在sparc上的linux和安装在x86上的linux其上的利用过程是不接受的,c库也是一样的理由。另外即便垄断系统本身的系统调用接口的不统一也会导致过程无法即便在雷同硬件然而不同垄断系统上二进制跨平台。这种场面可能在垄断系统和库设计扶持,对于跨平台厉行未曾太大的需求,再者彼时的硬件功能普遍很低,添置许多的虚构层定然会进一步减退功能,第三,彼时的人们并未曾面对混杂利用的挑动,因而和机器比拟亲昵,软件工程几乎全?**丛幌低匙聊ァ?br/>ld-linux.so究竟有什么用以及怎么用?它是到ld-2.x.so的软链接,由于几乎每一个正常且正规的过程都利用它,能够说,你把它剔除非你的系统就起不来了,除非把磁盘mount到另一个体系上,然后拷贝一个过去,可能自己在别的系统上写一个自定义链接器的过程...(还有一种措施即便安装sash-standaloneshell,它不依靠任何别的库,静态编译的它因而也不依靠ld-linux,因而能够穿越内核启用参数init=/sbin/sash来启用到它),然而万一你挪动了它导致系统找不到它引起的任何过程无法运行,凡是你懂得把它搞到了哪里,那就有救,做以下实验:
#mv /lib/ld-2.7.so ./aaa
然后你会觉察任何过程都未曾措施运行了,此刻幸亏还有一个shell,凡是不关闭它,ld-2.7.so就始终在它的空间里被照射着,这是因为linux是基于引用计数剔除被挪动的文件的。凡是有shell就能够,厉行:
#./aaa /bin/cp ./aaa /lib/ld-2.7.so
一切还原正常。
那么ld-2.7.so究竟是什么呢?万一它作为链接器的话,它的链接器在哪里呢?切实上它是一个静态链接的so,并且它是可厉行的,从它的man手册上能够看出,它即便用来加载过程以及过程必需的动态库的,然后施征途序,它本身是不依靠其它的so的,它凡是OS就能运行,因而任何过程都能够看起来这么运行:
#/lib/ld-2.7.so XX [可厉行文件全路径XX的参数]
例如:
#/lib/ld-2.7.so /bin/ls的收获和ls是一样的。
只不过为了得体,linux内置了对elf可厉行文件的直接扶持,当厉行exec的时候,OS积极地直接调用了ld-2.7.so(ld-2.7.so被动态链接进了elf可厉行文件,作为其一个so,能够穿越ldd看出来),而切实上,更加等闲的措施即便穿越号召行ld-2.7.soXXX来厉行elf可施征途序的(这么ld-2.7.so就无须要链接进elf可厉行文件了)。既然c/c++写出的代码能够直接编译成elf可厉行文件来直接厉行,其它任何的语言写出的代码都该当能够直接厉行,在linux中这是穿越binfmt_misc来扶持的,翔实的能够参看内核源码Documents目录中的binfmt_misc.txt文档。目前看一下java的厉行:
#java XX(XX为类文件去掉.class)
这里的java就相当于一个链接器,和/lib/ld-2.7.so是相仿的,只是它做了更多,包括发生一个虚构厉行环境(发生java虚构机)等,它启用了java类XX。
目前elf可厉行文件的厉行措施以及java类的厉行措施更加统一了,都是连接器来调用的:ld-2.7.so XX和javaXX,它们的背∶驿实是一样的。那么它们的互垄断就不成问题了,由于java过程本身即便一个elf可厉行文件,并且它是c写成的,因而java.c就表白了如何在c语言中调用java措施,只不过java.c调用了安宁的java措施,那即便main,这和ld-2.7.so最后调用c语言的main函数是一样的,全面是为了法定,未曾机制上的起因。既然java类本身是c语言写的过程启用的,因而对于本地代码,它确定能回调,这即便jni接口,能够在java类中调用本地c语言写成的函数。有会意了机制尔后,我们全面能够参看java.c文件写一个不调用main措施的新的java链接器:
代码参看自:om率先定义一个类,未曾main函数:
class Test {
public native void func(); //定义本地措施
static {
System.loadLibrary('func1');
}
public static void sub(String[] args) {
new Test().func();
}
}
编写一个c文件-startjava.c:
#include
#include
int main() {
JavaVM *vm;
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options[1];
options[0].optionString = '-Djava.class.path=.';
vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = 1;
vm_args.ignoreUnrecognized = 1;
jstring jstr;
jobjectArray args;
jint res = JNI_CreateJavaVM(&vm,压力变送器(void **)&env, &vm_args);
jclass cls = (*env)->FindClass(env, 'Test');//找到Test类,这个也能够穿越号召行递交
jmethodID mid = (*env)->GetStaticMethodID(env, cls, 'sub','([Ljava/lang/String;)V'); //调用sub措施,而不是main
jstring argString = (*env)->NewStringUTF(env, ''); //empty arglist
args = (*env)->NewObjectArray(env, 1, (*env)->FindClass(env,'java/lang/String'), jstr);
(*env)->CallStaticVoidMethod(env, cls, mid, args);
return 0;
}
然后定一个本地措施的告终-func1.c:
#include
JNIEXPORT void JNICALL Java_TestStunnel_func(JNIEnv *env, jobjectobj)
{
....//容易
}
最后startjava这个elf可厉行文件启用了一个未曾main的java类,然后java类中又调用一个本地措施,startjava.c同样也能够未曾main函数--将main改成abc,而是自己写一个链接器来厉行,这个链接器负责从OS内核接手用户空间的厉行(载入所需动态库-libc/libjvm等的过程早在内核分析elf的时候就做过了,因而无须要这个链接器来做),然后调用其abc函数即可。这么从当时从OS接手到来,每一个不管是elf可厉行的本地文件还是java类,未曾用到ld-2.7.so和java可施征途序,也未曾一个具有main函数(可能措施),然而“....//容易”真的就厉行了。
java是这么,其它的例如perl,python也是这么,包括c#等,都能如此折磨!
static的用法
UML组件图详解.
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
[保留] gcc与obj文件,动态链接文件和ELF文件
Linux下动态链接的步骤与实现详解
浅谈关于unix系统下的病毒特点 -
ELF文件格式与程序的编译链接
linux简单之美
How statically linked programs run on Linux
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服