程序的装载

  用户程序从main开始,而调用用户程序的就是navyapps里crt0的start.S,这个汇编代码会调用crt0.c里面的call_main()函数,然后调用用户程序的main(),用户程序执行完了以后,返回crt0.c,继续执行exit()。然后结束。

  如何解决“不知道程序要被放到哪里”这个问题?在navy apps里,我们提前约定用户程序被链接到0x8300 0000 附近。这个变量约定在isa.mk里的LDFALGS,之后如果在loader函数里查看程序段的打印信息,我们可以看到么个段的v addr也都在0x8300 0000 附近开始。

  按照讲义走的话,可执行文件dummy就位于ramdisk的0处,直接访问就能获得第一个字节。

windows使用PE格式可执行文件(后缀一般exe),linux则使用elf文件(默认后缀elf)。除了实际程序,elf文件提供了每个段的类型、虚拟地址、对齐方式、偏移量和大小等内容,这样一来我们就知道了应该加载可执行文件的哪些字节了(加载一个程序不需要全部放入内存,只要放入与运行相关的部分就行,比如符号表和调试信息)。

  elf的filesize是它在磁盘里的大小,而memsize是加载到内存里的大小。虽然有的段不用放入内存,但未初始化的静态变量、内存对齐等原因会占用更多内存。

  将elf的某一段读入内存,就是按照offset和filesize,读取出这一段,然后放入到virtual addr,vaddr+filesize这个区间,同时把vaddr+filesize,vaddr+memsize这个内存空间清零,给程序用。

  elf文件的程序头表这一部分里,有的段不需要被加载到内存,我们可以根据段的PT_load标志来判断是否需要加载到内存。不需要的话直接跳过,就这样逐个装入。注意是malloc(前面自己实现的malloc)直接加载入内存,而不是又放入ramdisk。

  在nanos里,主程序首先调用naive_load,然后通过loader函数加载程序。在加载完成后,loader函数应该返回dummy程序的入口地址。这个入口地址就是elf文件头的e_entry。在收到入口地址后,naive load通过 ((void *)())entry() 启动程序。从这个角度来说,其实就是输入了程序的第一条指令,然后机器就会顺着向下执行。  void *表示程序指针需要void *,后面的括号表示不需要参数,((void *)())就表示将变量entry强制转换为不需要参数的函数指针,后面的()就是调用函数需要的括号。合起来就是调用函数,就和printf()意思一样。

posted @ 2024-11-03 16:21  namezhyp  阅读(5)  评论(0编辑  收藏  举报