完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
这里以s3c2440为主,我们都知道2440内存有效的应用范围是地址SRAM的0-1000(16进制),还有就是sdram的30000000-34000000。
那么我们要运行一个程序的话就要选用一个内存来运行我们的程序,要想办法把程序放进去,我们一般放到sdram里面运行,一般sram是用作一些初始化的。 在sdram中33000000以上的空间已被uboot所占用,我们只能用33000000以下的空间。 我们用C语言来写,最简单的莫过于hello world!我们就用这个例子来讲解,命令为test.c。 #include int main(int argc,char **argv) { printf("hello world!n") return 0; } 该程序在x86平台上编译时很简单的,gcc test.c -o test 运行./test 在X86上面是装着linux操作系统的,但是在我们一开始开发板没有装操作系统的话那怎么办呢? 要是我们在arm开发板上运行怎么办? 我们知道编译的过程是先把C语言编程汇编,再把汇编编程机器代码,但是ARM和X86不是同一个体系。汇编指令也不一样,就是说运算的指令是不一样的! 那么我们就不能用上面的来编译了!那么怎么办呢? 我们只能用arm编译器,那么我们要安装交叉工具链,如何安装呢? 下面就讲解交叉编译器的安装 我们先下载arm-linux-gcc-3.4.1.tar.bz2(这个有不同版本,各取所爱) 下载地址:http://www.arm8.net/thread-36-1-1.html 首先我们用tar jxf arm-linux-gcc-3.4.1.tar.bz2解压出来 解压出来了就是我们的编译器,支持的汇编或者机器指令是arm的,为什么要叫arm-linux-gcc呢? 意思是在arm平台上装一个Linux,写出来的程序就能再我们arm开发板上运行。 解压后运行./3.4.1/bin/arm-linux-gcc -v 可以查看该版本的信息。 我们可以看到gcc version 3.4.1就是我们编译器的版本信息了! 再看看prefix=/usr/local/arm/3.4.1这里的信息就是我们要安装的路径。 那么我们先来看看我们系统的路径。 ls /usr/local有没有我们的arm。 没有的话我们建一个目录mkdir /usr/local/arm 然后我们就可以把刚刚解压的目录移动在我们新建的文件夹里面了! mv 3.4.1 /usr/local/arm/ 那么我们现在就试一下编译我们的test.c文件, 输入命令 /usr/local/arm/3.4.1/bin/arm-linux-gcc test.c -o test 这里就有人问,那么我每次编译时都需要输入/usr/local/arm/3.4.1/bin/这个路径吗? 我们来设置一下环境变量 vi /etc/bashrc 增加PATH=/usr/lpcal/arm3.4.1/binPATH 保存 那么我们下次编译就可以直接写arm-linux-gcc test.c -o test了。 现在编译的文件是在x86上运行不了的!那么我们能不能把该程序放到我们的arm开发板上运行呢? 我们就用tftp把程序拷到开发板上 我们先用tftp 30000000 test 把文件拷到30000000这个地址 如何不会用不清楚tftp服务的话可到论坛咨询。 那么我拷过去了之后,如何去执行它? 我们知道在30000000-34000000已经有uboot移植在那里执行了! 那么我们如何跳到30000000这个位置执行呢? go 30000000这个命令就可以跳到该地址上执行。 那么它又如何返回去的呢? 这个就是按照C语言函数的规范,叫做APCS规范,如果是一个函数的话自然会有一个返回的值自然能返回去。 但是我们运行了之后却发现“垮”掉了,整个平台都死掉了!这是为什么呢?如图0. 因为有两点: 一:任何一个编译出来的程序将在哪里执行是谁决定的呢?也就是说我们在内存里面执行,但在内存哪个地址上执行是谁决定的呢? 答:是编译器决定的,一个应用想在内存的哪个地址执行要一开始由编译器来决定的! 那么我们可以看看test程序的信息。 命令:arm-linux-objdump -d test 我们可以看到里面有很多很多的函数,并且他要求我们的main函数在000083d0这个地址上执行,如图1。 实际上我们板子上是没有这个地址的!那怎么办呢?那就需要我们自己来指定了! 二:printf我们并没有实现,printf这个是由库文件来实现的,我们执行时是调动态库来实现该函数的,要想用库的函数,前提是要我们平台上有操作系统。 操作系统才会帮我们装载库,但在我们arm开发板上的bootloader是很简单的,不能和操作系统相比,库在它上面是用不了的!bootloader是连文件也不支持的! printf是不是也要我们自己来写呢?其实不用,在uboot上我们是不是可以看到它打印很多信息给我们看,其实它自身已实现了printf函数。 我们通过uboot编译的文件最后输出的system.map可以看到printf的地址,其实在33000000-34000000的33f94aa8这个地址。 那么我们不能用库里面的函数了! 我们改一下我们写的代码: 我们不能再用库的函数了!把库去掉。 我们定义一个函数 void (*show)(char *,...); int main(int argc,char **argv) { show=0x33f94aa8;//0x33f94aa8是ubbot printf函数的地址,那么我们就可以把show当成printf来使用。 show("hello-uboot.n"); return 0; } 现在库的问题已经解决,那么第一点中在哪个地址运行的地址还没解决。 我们只能手动链接,arm-linux-gcc -c test.c -o test.o 我们先编译不链接, -o就是不链接。 然后我们链接arm-linux-ld -Ttext=0x3000000 test.o -o test 现在我们再看看arm-linux-objdump -d test该信息 那么我们现在来看已经没有其他函数只有main函数,且在30000000这个地址上运行了! 因为我们现在没有链接库了!因为链接库会产生很多的中间信息(函数),现在都没有了!只有我们写的代码,如图2. -Ttext就是代码段的起始地址是30000000,也可以加上arm-linux-ld -Ttext=0x3000000 -nostdlib test.o -o test -nostdlib 是指不需要和库进行连接。 现在的程序是否就能在arm开发板上运行呢? 我们tftp 30000000 test拷到开发板上, g0 30000000跳到该地址运行。 我们发现还是不行,报错。如图2-1 其实我们g0 30000000跳到该区域执行时,它想要执行的是一条指令,但我们的test的第一句话时是否是一条指令呢? 我们用vi test命令查看该程序,图3. 我们发现它第一条竟然不是指令,实际上是一个可执行文件的头信息,任何一个可执行文件都有一件(外衣)。 头里面装有一些描述性的信息。这个头是我们可执行文件的格式。通常格式有AOUT,ELF,当然window的格式问PE。 我们g0 30000000 跳到30000000运行时因为uboot过于简单,不能解释这个头信息,所以就报错了! 那么我们可以把头去掉。 输入命令arm-linux-objcopy test test.bin 其实这个软件可以去头和加头,那么我们可以明确告诉它 arm-linux-objcopy test -I elf32-littlearm -o binary test.bin 告诉编译器我们文件格式是32位elf格式,并且为小端格式,输出binary,这个就是一个纯粹没有头的文件,意思要去掉这个头。 我们可以看看有头和无头文件的大小,如图4. 有头文件为33k,实际上无头文件为100个字节。 那么现在我们把该bin文件拷进去开发板执行,终于能打印出hello-uboot了!如图5. |
|
相关推荐
|
|
犀利!!!!!
|
|
|
|
|
|
787 浏览 0 评论
飞凌嵌入式ElfBoard ELF 1板卡-mfgtools烧录流程介绍之烧写所需镜像
888 浏览 0 评论
飞凌嵌入式ElfBoard ELF 1板卡-mfgtools烧录流程之烧写方法
608 浏览 0 评论
飞凌嵌入式ElfBoard ELF 1板卡-内核编译之初次编译
905 浏览 0 评论
飞凌嵌入式ElfBoard ELF 1板卡-内核源代码的目录结构和文件说明
821 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 19:00 , Processed in 0.705299 second(s), Total 77, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号