恩,首先要感謝 Rickleaf, 介紹 QEMU 模擬 MINI2440 的方案給我,並且將MINI2440移植好的bsp分享給我。使我工作速度大大增加。
以下是他的一篇移植 rtems4.9.5 到 qemu 上的文章。
http://blog.csdn.net/rickleaf/archive/2011/03/16/6254361.aspx
當時雖然能運行,但是使用gdb載入的方式。而不是使用uboot的載入方式。uboot的載入方式一直有問題。
Rickleaf研究了一下,發現載入和啟動地址都是 0x30000100。詳見博文:
http://blog.csdn.net/rickleaf/archive/2011/03/18/6260292.aspx
但對於這篇文章所說的原因:
/------------------------------以下文字摘自rickleaf的部落格---------------------------------------/
2.探究原因
原來轉換成bin檔案以後,entry前面的偽指令是沒有的,
想想也對,不燒到那裡不就預留了嗎?:-)
/------------------------------以上文字摘自rickleaf的部落格---------------------------------------/
個人對這個原因持不同意見。我做了如下的工作:
首先,使用編譯好的mini2440的bsp編譯hello_world_c樣本。官方帶的。編譯成功後,在hello_world_c下的o-optimize下有一個hello.num檔案。這個是hello.exe(實際上是elf格式)中的符號位置。其中前22行是:
w _Jv_RegisterClasses
w __deregister_frame_info
w __register_frame_info
00000100 A _abt_stack_size
00000400 A _fiq_stack_size
00001000 A _irq_stack_size
00001000 A _svc_stack_size
04000000 A _sdram_size
30000000 A _sdram_base
30000000 B arm_exception_table
30000000 B arm_reset_vect
30000004 B arm_undef_vect
30000008 B arm_swi_vect
3000000c B arm_iabrt_vect
30000010 B arm_dabrt_vect
30000018 B arm_irq_vect
3000001c B arm_fiq_vect
30000020 B rtems_vector_table
30000040 B bsp_vector_table
30000100 T _axf_text_start
30000100 T _start
3000026c T Reset_Handler
從0x3000 0000 地址到 0x3000 0040 地址我們看到都是有東西的。並且符號是B。B是什麼,查閱官方文檔是:
該符號的值出現在非初始化資料區段(bss)中。例如,在一個檔案中定義全域static int test。則該符號test的類型為b,位於bss section中。其值表示該符號在bss段中的位移。一般而言,bss段分配於RAM中。
原來 arm_exception_table、arm_reset_vect 就是一個靜態全域變數,但沒有初始化。恩,那我使用arm_reset_vect搜尋整個bsp的代碼,並沒有發現代碼中對這個變數進行初始化或聲明。 《using ld》 文檔對這個問題的描述是,在串連指令碼裡可以使用指派陳述式申明一些全域變數。以下是我翻譯的關於運算式這段的原文:
既然是在串連指令碼中定義的,那我們就去看看mini2440的rtems串連指令碼。我把rickleaf寫的指令碼前90行貼出來了。
/*<br /> * MINI2440 Linker script<br /> *<br /> * Written by Ricky Wu <rickleaf.wu@gmail.com><br /> *<br /> * The license and distribution terms for this file may be<br /> * found in the file LICENSE in this distribution or at<br /> *<br /> * http://www.rtems.com/license/LICENSE.<br /> *<br /> * $Id: linkcmds,v 1.1 2008/05/06 21:01:27 joel Exp $<br /> */<br />OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm","elf32-littlearm")<br />OUTPUT_ARCH(arm)<br />ENTRY(_start)<br />/* SEARCH_DIR(/usr/local/rtems-arm-dev-tools/arm-rtems/lib); */<br />MEMORY {<br />sdram : ORIGIN = 0x30000000, LENGTH = 128M<br />}<br />/*<br /> * Declare some sizes.<br /> */<br />/* The base for SDRAM is set to umon's APPRAMBASE */<br />_sdram_base = DEFINED(_sdram_base) ? _sdram_base : 0x30000000;<br />_sdram_size = DEFINED(_sdram_size) ? _sdram_size : 128M;<br />_irq_stack_size = DEFINED(_irq_stack_size) ? _irq_stack_size : 0x1000;<br />_fiq_stack_size = DEFINED(_fiq_stack_size) ? _fiq_stack_size : 0x400;<br />_abt_stack_size = DEFINED(_abt_stack_size) ? _abt_stack_size : 0x100;<br />_svc_stack_size = DEFINED(_svc_stack_size) ? _svc_stack_size : 0x1000;<br />/* Do we need any of these for elf?<br /> __DYNAMIC = 0; */<br />SECTIONS<br />{<br /> .base :<br /> {<br /> arm_exception_table = .;<br /> arm_reset_vect = .; /* 0x00 */<br /> . += 4;<br /> arm_undef_vect = .; /* 0x04 */<br /> . += 4;<br /> arm_swi_vect = .; /* 0x08 */<br /> . += 4;<br /> arm_iabrt_vect = .; /* 0x0c */<br /> . += 4;<br /> arm_dabrt_vect = .; /* 0x10 */<br /> . += 4;<br /> /* no vector here */<br /> . += 4;<br /> arm_irq_vect = .; /* 0x18 */<br /> . += 4;<br /> arm_fiq_vect = .; /* 0x1c */<br /> . += 4;<br /> /* FIXME: */<br /> rtems_vector_table = .;<br /> . += (8 * 4); /* 8 ARM interrupts */</p><p> bsp_vector_table = .;<br /> . += (32 * 4); /* 32 S3C2400 interrupts */<br /> . = ALIGN (0x100);<br /> } > sdram<br /> .text :<br /> {<br /> _axf_text_start = . ;<br /> *(EXCLUDE_FILE (*text.iwram*) .text)<br /> *(.text.*)<br /> *(.stub)
從串連指令碼上看,sdram的地址從0x3000 0000 開始,首先放置的是.base段,.base段佔用 0x100 個位元組。實際上沒那麼多,因為. = ALIGN(0x100)這句話使得地址計數器按0x100對齊。使得.text地址從0x3000 0100開始。我們看到指令碼第15行ENTRY(_start) 實際上是第一條指令,也是.text的第一條指令。毫無疑問rtems的第一條指令在0x3000 0100的位置。
那麼就糊塗了,整個鏡像從linkcmd中看到的是從0x3000 0000開始,0x3000 0100是第一條指令。為什麼在uboot中輸入一下命令:
tftp 30000000 image.bin
go 30000100
沒有任何反應?
(((
注意,編譯好的hello.exe使用命令:
arm-rtems4.9-objcopy -O binary hello.exe /tftpboot/image.bin
(我的tftp伺服器檔案夾在/tftpboot下,因人而異)
)))
只有一句話:##Starting application at 0x30000100 ...
根據上面的hello.nm,猜想:全域未初始化資料區段如果在鏡像的末尾或在鏡像的開始,實際上是不會包含在鏡像裡的。
那麼,我要證明一下這個猜想。修改一下指令碼:
SECTIONS
{
.base :
{
arm_exception_table = .;
arm_reset_vect = .; /* 0x00 */
LONG(200) /*. += 4;*//*Modified by Bacon*/
arm_undef_vect = .; /* 0x04 */
LONG表示在地址計數器位置儲存一個4位元組的整數。這裡是儲存個200 ,純粹為了實驗。
恩,重新編譯mini2440的rtems bsp和hello world的樣本。
再次查看hello.nm,前22行是:
w _Jv_RegisterClasses
w __deregister_frame_info
w __register_frame_info
00000100 A _abt_stack_size
00000400 A _fiq_stack_size
00001000 A _irq_stack_size
00001000 A _svc_stack_size
04000000 A _sdram_size
30000000 A _sdram_base
30000000 D arm_exception_table
30000000 D arm_reset_vect
30000004 D arm_undef_vect
30000008 D arm_swi_vect
3000000c D arm_iabrt_vect
30000010 D arm_dabrt_vect
30000018 D arm_irq_vect
3000001c D arm_fiq_vect
30000020 D rtems_vector_table
30000040 D bsp_vector_table
30000100 T _axf_text_start
30000100 T _start
3000026c T Reset_Handler
注意:原來由符號B改成符號D了。
D表示符號位於初始化資料區段中。一般來說,分配到data section中。例如定義全域int baud_table[5] = {9600, 19200, 38400, 57600, 115200},則會分配於初始化資料區段中。
然後進入~/qemu檔案夾下,運行:
./mini2440/mini2440_start.sh
啟動qemu
(這部詳細請參考:http://blog.csdn.net/coolbacon/archive/2011/03/16/6252938.aspx)
輸入命令:
tftp 30000000 image.bin
go 30000100
哈哈,順利的看到了hello world!!
下面是有圖有真相時間:
這印證了我的猜測。說明,最終的鏡像不包含全域未初始化的資料區段。
對於這個問題,還有深究的空間,以下是全域未初始化資料區段空間位置的三種情況:
對於第一種和第三種,我覺得都是可以缺失的,即最終的記憶體鏡像裡可以不包含"全域未初始化資料區段"。對於第二種情況,就有些值得研究了。根據我的經驗,我認為如果“其他段”需要體現在最終鏡像裡,那麼”全域未初始化資料區段“也必須體現在鏡像裡,則需要包含。如果其他段不需要體現,那麼全域未初始化資料區段也不會體現在最終鏡像裡。(得空做個實驗驗證一下我的想法。)
關於這個問題,不想證明誰對誰錯,探求真理,是做技術人員的天性。感謝Rickleaf的貢獻,沒有他我也不會想到這一層。