简介: 前一段时间,曾先后移植了uClinux-2.0.x和uClinux-2.4.x的内核, 我的移植基本上是从零做起,linux并没有支持该目标机的代码,所以这 个移植工作基本上是新增加对一种目标机的支持。
工作过程中,我学到了不少知识,除了操作系统,还了解了一些编 译,调试,汇编,链接的的技术,在此我会一并介绍,可能介绍比较多 的是连接器,因为这个相对和操作系统联系更加紧密一些。 我希望能够与大家分享自己经验,同时,有错误和不当的地方欢迎 网友指出,共同进步,这是我写这些原创帖的动力。
“编程并非零和的游戏。将己所知教给程序员同胞,他们并不会夺你 所知。能将我所知与人分享,我感到高兴,因为我身在其中、热爱编程。” ——John Carmack
uClinux下用户程序的执行
之所以从用户程序谈起,是因为我们平常接触最多的还是应用程序。 从应用程序引出到操作系统我觉得比较自然。下面就从一个简单例子介 绍一个程序如何在操作系统中运行。
假如有个c程序: int main(int argc, char **argv[]) { printf("hello world!"); return 0; }
这是一个最简单不过的程序了,一般一个C语言程序,都从main开始 执行。那么,main函数是不是与其他函数有所区别,地位有些特殊呢? 不是的。main函数和其他函数地位一样。其实,我们完全可以做到让一个 c程序从任何地方开始执行。比如linux,它就没有main函数,大家都知道, 系统执行过启动的一段汇编后,就会跳转到位于init/main.c中的 start_kernel中开始执行。
那么为什么用户程序都要从main函数执行呢?这就是用户C库的原因。 一般用户用c语言开发时会调用一些库函数,编译成obj文件后,在链接过 程中把库函数的二进制代码链接进入程序,最后形成二进制可执行文件。 链接过程中,链接器会在用户程序前插入一些初始化的代码。uClinux下 是在crt0.s中(我移植的是uClibc库)。不管什么平台下什么形式的crt0.s, 这个文件最后几行代码中肯定有一个jmp(或者call或br等转移指令) main (或__uClibc_main)。这就是为什么你的程序都从main开始执行。如果你把 这个跳转标号改成任意一个标号,比如foo。而你的程序里面既有main,又 有foo,则这种情况下,程序就先从foo开始执行。所以,main函数和其他 函数一样,并没有特殊地位。
下面谈谈在uClinux中,main函数的argc,argv是参数怎样传递的。我们 以flat格式可执行文件为例。uClinux下支持一种叫flat的可执行文件格式。 这种文件格式比较简单,基本上是平铺的,所以叫flat很形象。现在好像 uClinux-2.4.x内核的版本已经能够支持elf格式的文件执行了。不过为了 举例简单,我还是用flat格式举例。这里暂不分析flat文件格式,我们把注 意力放到参数传递上。uClinux开发用户程序,首先当然是编码,然后编译, 编译生成的文件是elf格式的,所以要用工具elf2flt将elf文件转换成flat, 假设这个工作已经完成。
我们在uclinux的shell下执行一个文件foo x y,foo是程序名,x, y是 参数。学过C语言的都知道,x,y作为参数会传递给main,其中argc=3, argv[0]="foo", argv[1]="x", argv[2]="y"。这些参数是如何传递进来的呢。 在你执行一个程序的时候,操作系统会调用 程中把库函数的二进制代码链接进入程序,最后形成二进制可执行文件。 链接过程中,链接器会在用户程序前插入一些初始化的代码。uClinux下 是在crt0.s中(我移植的是uClibc库)。不管什么平台下什么形式的crt0.s, 这个文件最后几行代码中肯定有一个jmp(或者call或br等转移指令) main (或__uClibc_main)。这就是为什么你的程序都从main开始执行。如果你把 这个跳转标号改成任意一个标号,比如foo。而你的程序里面既有main,又 有foo,则这种情况下,程序就先从foo开始执行。所以,main函数和其他 函数一样,并没有特殊地位。
下面谈谈在uClinux中,main函数的argc,argv是参数怎样传递的。我们 以flat格式可执行文件为例。uClinux下支持一种叫flat的可执行文件格式。 这种文件格式比较简单,基本上是平铺的,所以叫flat很形象。现在好像 uClinux-2.4.x内核的版本已经能够支持elf格式的文件执行了。不过为了 举例简单,我还是用flat格式举例。这里暂不分析flat文件格式,我们把注 意力放到参数传递上。uClinux开发用户程序,首先当然是编码,然后编译, 编译生成的文件是elf格式的,所以要用工具elf2flt将elf文件转换成flat, 假设这个工作已经完成。 |