ADS的默认连接顺序是怎样的呢?例如下边从2440init.s中摘出的编译器符号又该怎样理解呢?
BaseOfROM DCD |Image##RO##Base|
TopOfROM DCD |Image##RO##Limit|
BaseOfBSS DCD |Image##RW##Base|
BaseOfZero DCD |Image##ZI##Base|
EndOfBSS DCD |Image##ZI##Limit|
说明:由于“$ $”(实际上中间没有空格,但是不知为什么只要这两个字符并排着放在一起,提交后显示的时候总是出现问题)排版的问题,所以本文中所有用到的“$ $”都用##代替。
我根据TQ2440_Test.mcp做了一个测试。我知道下边的图片对于使用ADS的朋友很熟悉,但是我觉得还是有必要先把这个工程的编译配置选项贴出来。
为了说明这些问题,我不得不把ADS生成的List.txt内容列出来,尽管它很长,不过只去注意那些对问题有意义的地方。
================================================================================
Memory Map of the image
Image Entry point : 0x30000000
Load Region LR_1 (Base: 0x30000000, Size: 0x00086c14, Max: 0xffffffff, ABSOLUTE)
Execution Region ER_RO (Base: 0x30000000,Size: 0x0000b400, Max: 0xffffffff, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x30000000 0x00000544 Code RO 1 * Init 2440init.o
0x30000544 0x0000026c Code RO 10 .text nand.o
0x300007b0 0x00000aa0 Code RO 59 .text 2440lib.o
0x30001250 0x00000550 Code RO 145 .text Main.o
0x300017a0 0x00000288 Code RO 210 .text mmu.o
0x30001a28 0x0000046c Code RO 226 .text dma.o
0x30001e94 0x0000019c Code RO 264 .text Adc.o
0x30002030 0x00000e7c Code RO 279 .text camif.o
0x30002eac 0x000007f0 Code RO 411 .text IIC.o
0x3000369c 0x0000026c Code RO 445 .text keyscan.o
0x30003908 0x00000120 Code RO 501 .text RTC.o
0x30003a28 0x000003e8 Code RO 513 .text Test_OV9650.o
0x30003e10 0x0000026c Code RO 606 .text Touchpanel.o
0x3000407c 0x000005b4 Code RO 620 .text UDA1341.o
0x30004630 0x00000cdc Code RO 643 .text AudioDrv.o
0x3000530c 0x00000af0 Code RO 731 .text LCD_TFT.o
0x30005dfc 0x00001018 Code RO 766 .text SD_MMC.o
0x30006e14 0x00000034 Code RO 831 .text atoi.o(c_a__un.l)
0x30006e48 0x00000014 Code RO 833 .text rt_ctype_table.o(c_a__un.l)
0x30006e5c 0x000000d4 Code RO 835 .text rt_sdiv.o(c_a__un.l)
0x30006f30 0x000000c0 Code RO 837 .text rt_udiv.o(c_a__un.l)
0x30006ff0 0x00000068 Code RO 839 .text strlen.o(c_a__un.l)
0x30007058 0x00000058 Code RO 841 .text vsprintf.o(c_a__un.l)
0x300070b0 0x00000d38 Code RO 860 .text __vfpntf.o(c_a__un.l)
0x30007de8 0x0000001c Code RO 862 .text _sputc.o(c_a__un.l)
0x30007e04 0x0000003c Code RO 864 .text lc_ctype_c.o(c_a__un.l)
0x30007e40 0x0000000c Code RO 867 .text libspace.o(c_a__un.l)
0x30007e4c 0x0000000c Code RO 870 .text rt_div0.o(c_a__un.l)
0x30007e58 0x0000000c Code RO 872 .text rt_errno_addr.o(c_a__un.l)
0x30007e64 0x00000010 Code RO 874 .text rt_fp_status_addr.o(c_a__un.l)
0x30007e74 0x000000c0 Code RO 876 .text strtol.o(c_a__un.l)
0x30007f34 0x00000924 Code RO 894 .text _fp_disp.o(c_a__un.l)
0x30008858 0x00000060 Code RO 896 .text _fptrap.o(c_a__un.l)
0x300088b8 0x00000108 Code RO 898 .text _strtoul.o(c_a__un.l)
0x300089c0 0x00000098 Code RO 900 .text lludiv10.o(c_a__un.l)
0x30008a58 0x00000018 Code RO 902 .text rt_raise.o(c_a__un.l)
0x30008a70 0x0000002c Code RO 904 .text rtudiv10.o(c_a__un.l)
0x30008a9c 0x000000a0 Code RO 906 .text strcmp.o(c_a__un.l)
0x30008b3c 0x00000064 Code RO 910 .text __raise.o(c_a__un.l)
0x30008ba0 0x00000020 Code RO 912 .text _chval.o(c_a__un.l)
0x30008bc0 0x0000015c Code RO 914 .text bigflt0.o(c_a__un.l)
0x30008d1c 0x0000003c Code RO 919 .text lc_numeric_c.o(c_a__un.l)
0x30008d58 0x00000040 Code RO 922 .text rtsdiv10.o(c_a__un.l)
0x30008d98 0x00000018 Code RO 924 .text sys_exit.o(c_a__un.l)
0x30008db0 0x00000048 Code RO 928 .text classify.o(m_a_pu.l)
0x30008df8 0x00000054 Code RO 930 .text dtoi.o(m_a_pu.l)
0x30008e4c 0x00000160 Code RO 932 .text defsig.o(c_a__un.l)
0x30008fac 0x00000004 Code RO 936 .text use_semi.o(c_a__un.l)
0x30008fb0 0x00000018 Code RO 938 .text sys_wrch.o(c_a__un.l)
0x30008fc8 0x000001b4 Code RO 6 C$$code 2440slib.o
0x3000917c 0x00000898 Code RO 917 CL$$btodstuff btod.o(c_a__un.l)
0x30009a14 0x00000014 Code RO 446 i.ClearPending keyscan.o
0x30009a28 0x00000048 Code RO 516 i.OV9650_sccb_end Test_OV9650.o
0x30009a70 0x00000054 Code RO 515 i.OV9650_sccb_start Test_OV9650.o
0x30009ac4 0x00000050 Code RO 517 i.OV9650_sccb_write_bit Test_OV9650.o
0x30009b14 0x00000034 Code RO 518 i.OV9650_sccb_writechar Test_OV9650.o
0x30009b48 0x00000038 Code RO 644 i.SetPlayDma AudioDrv.o
0x30009b80 0x00000038 Code RO 645 i.SetRecDma AudioDrv.o
0x30009bb8 0x00000054 Code RO 514 i.set_gpio_ctrl Test_OV9650.o
0x30009c0c 0x0000049c Code RO 845 x$fpl$dadd daddsub.o(f_a_p.l)
0x3000a0a8 0x00000040 Code RO 880 x$fpl$dcheck dcheck.o(f_a_p.l)
0x3000a0e8 0x00000018 Code RO 882 x$fpl$dcheck1 dcheck1.o(f_a_p.l)
0x3000a100 0x000005b0 Code RO 847 x$fpl$ddiv ddiv.o(f_a_p.l)
0x3000a6b0 0x000000a4 Code RO 849 x$fpl$dfix dfix.o(f_a_p.l)
0x3000a754 0x00000064 Code RO 852 x$fpl$dflt dflt.o(f_a_p.l)
0x3000a7b8 0x000002b4 Code RO 854 x$fpl$dmul dmul_mull.o(f_a_p.l)
0x3000aa6c 0x00000230 Code RO 884 x$fpl$dunder dunder.o(f_a_p.l)
0x3000ac9c 0x00000164 Code RO 886 x$fpl$exception except.o(f_a_p.l)
0x3000ae00 0x0000003c Code RO 926 x$fpl$ieeestatus istatus.o(f_a_p.l)
0x3000ae3c 0x00000004 Code RO 878 x$fpl$printf1 printf1.o(f_a_p.l)
0x3000ae40 0x00000098 Code RO 908 x$fpl$retnan retnan.o(f_a_p.l)
0x3000aed8 0x000000a4 Code RO 892 x$fpl$trapveneer trapv.o(f_a_p.l)
0x3000af7c 0x000000d3 Data RO 147 .constdata Main.o
0x3000b04f 0x00000001 PAD (说明:为了使代码4字节对齐,起到占位作用,占了一个字节)
0x3000b050 0x00000058 Data RO 622 .constdata UDA1341.o
0x3000b0a8 0x00000110 Data RO 865 .constdata lc_ctype_c.o(c_a__un.l)
0x3000b1b8 0x00000094 Data RO 915 .constdata bigflt0.o(c_a__un.l)
0x3000b24c 0x0000001c Data RO 920 .constdata lc_numeric_c.o(c_a__un.l)
0x3000b268 0x0000012b Data RO 933 .constdata defsig.o(c_a__un.l)
0x3000b393 0x00000001 PAD (说明:为了使代码4字节对齐,起到占位作用,占了一个字节)
0x3000b394 0x00000040 Data RO 521 .constdata_check_OV9650 Test_OV9650.o
0x3000b3d4 0x0000002c Data RO 522 .constdata_s3c2440_camif_init Test_OV9650.oExecution Region ER_RW (Base: 0x3000b400, Size: 0x0007b814, Max: 0xffffffff, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x3000b400 0x00000004 Data RW 60 .data 2440lib.o
0x3000b404 0x00000068 Data RW 146 .data Main.o
0x3000b46c 0x00000004 Data RW 265 .data Adc.o
0x3000b470 0x000003ec Data RW 519 .data Test_OV9650.o
0x3000b85c 0x0003b760 Data RW 621 .data UDA1341.o
0x30046fbc 0x00000058 Data RW 646 .data AudioDrv.o
0x30047014 0x0003fc00 Data RW 760 .data TQ_LOGO.oExecution Region ER_ZI (Base: 0x30086c14, Size: 0x000415b8, Max: 0xffffffff, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x30086c14 0x00000004 Zero RW 61 .bss 2440lib.o
0x30086c18 0x00000020 Zero RW 148 .bss Main.o
0x30086c38 0x00000004 Zero RW 153 .bss Main.o
0x30086c3c 0x00000004 Zero RW 155 .bss Main.o
0x30086c40 0x00000020 Zero RW 227 .bss dma.o
0x30086c60 0x00000004 Zero RW 266 .bss Adc.o
0x30086c64 0x00000024 Zero RW 280 .bss camif.o
0x30086c88 0x00000230 Zero RW 412 .bss IIC.o
0x30086eb8 0x00001400 Zero RW 520 .bss Test_OV9650.o
0x300882b8 0x0000000c Zero RW 607 .bss Touchpanel.o
0x300882c4 0x00000004 Zero RW 623 .bss UDA1341.o
0x300882c8 0x00000064 Zero RW 647 .bss AudioDrv.o
0x3008832c 0x0003fc00 Zero RW 732 .bss LCD_TFT.o
0x300c7f2c 0x00000240 Zero RW 767 .bss SD_MMC.o
0x300c816c 0x00000060 Zero RW 868 .bss libspace.o(c_a__un.l)
================================================================================Image component sizes
Code RO Data RW Data ZI Data Debug29120 407 505876 267608 114304 Object Totals
15804 747 0 96 5096 Library Totals================================================================================
Code RO Data RW Data ZI Data Debug44924 1154 505876 267704 119400 Grand Totals
================================================================================
Total RO Size(Code + RO Data) 46078 ( 45.00kB) (0x0000B3FE)
Total RW Size(RW Data + ZI Data) 773580 ( 755.45kB) (0x000BCDCC)
Total ROM Size(Code + RO Data + RW Data) 551954 ( 539.02kB) (0x00086C12)================================================================================
分析:
(1)从Image Entry point : 0x30000000这句话中,我们可以看出程序的入口地址是0x30000000。
(2)上边橙色的部分是"RO Data"段,List.txt并没有把这一部分单列出来,而是与Code段放在一起。
(3)从Load Region LR_1 (Base: 0x30000000, Size: 0x00086c14, Max: 0xffffffff, ABSOLUTE)这句话中,我们可以知道最终下载程序(TQ2440_Test.bin)的大小是0x00086C14。如果想知道为什么是这个数,可以通过Jlink软件把TQ2440_Test.bin打开,然后看代码量就可以知道。
从Total ROM Size(Code + RO Data + RW Data) 551954 ( 539.02kB) (0x00086C12)这句,我们可以看出下载程序的代码量应该是0x00086C12,这与0x00086C14是矛盾的。其实不然,这是因为在"RO Data"段为了4字节对齐,用了两个单字节占位引起的多余空间。
(4)如果最终下载程序(TQ2440_Test.bin)的大小是0x00086C14,而并没有把bss段或者叫ZI段(0x000415b8)这部分算进去。也就是说最终的下载程序是不包括bss段的,bss段不会被下载到Flash或者RAM中,这也是为什么启动代码(比如说boot.s)要进行bss段初始化的原因。
(5)ADS默认的链接顺序就是代码段(.text)、只读数据段(.rodata)、(已初始化)数据段(.data)、未初始化数据段(.bss)。假设projiect里有三个文件,head.s、nand.c、maic.c,那么默认为的就先依次放这三个文件的代码段(head.s(.text)、nand.c(.text)、maic.c(.text)),再依次放只读数据段(head.s(.rodata)、nand.c(.rodata)、maic.c(.rodata)),依次再放这三个文件的数据段(head.s(.data)、nand.c(.data)、maic.c(.data)),最后再放(head.s(.bss)、nand.c(.bss)、maic.c(.bss))。
(6)为了理解编译器符号,我从TQ2440_Test.dis摘出的对应的反汇编代码如下。
300003b4 <BaseOfROM>:
300003b4: andcc r0, r0, r0 300003b8 <TopOfROM>:
300003b8: 3000b400 andcc fp, r0, r0, lsl # 300003bc <BaseOfBSS>:
300003bc: 3000b400 andcc fp, r0, r0, lsl # 300003c0 <BaseOfZero>:
300003c0: 30086c14 andcc r6, r8, r4, lsl ip 300003c4 <EndOfBSS>:
300003c4: 300c81cc andcc r8, ip, ip, asr #
注意把这些值与List.txt中深蓝色字体对比,你就会发现其中的奥秘。30000000、3000b400、30086c14都可以在深蓝色字体中找到,需要指出的是300c81cc这个数字。这个数字是这样理解的, 从“Execution Region ER_ZI (Base: 0x30086c14, Size: 0x000415b8, Max: 0xffffffff, ABSOLUTE)”这句话中我们可以看出,bss段(ZI段)的基址是0x30086c14,大小是 0x000415b8,把这两个数字加起来就可以得到bss段的终址是300c81cc。
由此,我们得出对ADS编译器生成的各段的认识如下所示。
BaseOfROM DCD |Image##RO##Base| 代码段的首地址
TopOfROM DCD |Image##RO##Limit| 代码段的结束地址
BaseOfBSS DCD |Image##RW##Base| 数据段的起始地址
BaseOfZero DCD |Image##ZI##Base| 未初始化数据段的首地址
EndOfBSS DCD |Image##ZI##Limit| 未初始化数据段的结束地址
附注:|Image##RW##Limit| = |Image##ZI##Limit|
怎样调用ADS编译器产生的参数?
从汇编代码“BaseOfROM DCD |Image##RO##Base|”中,我们就可以看出汇编程序是如何调用编译器产生的参数。但是,C语言又该怎样调用这些参数呢?我摘出了一段程序可以看出。
extern char Image##RW##Limit[];()
void *mallocPt=Image##RW##Limit;()
怎样理解呢?我是这样认为的。第(1)句在地址Image##RW##Limit处定义了一个数组,显然数组的首地址就是“Image##RW##Limit”。而第二句,就去调用这个首地址。
什么可以作为只读数据段(.rodata)?
下边的代码是从main.c中摘出来的。
void Temp_function() { Uart_Printf("\nPlease input 1-11 to select test!!!\n");
struct {
void (*fun)(void);
char *tip;
}CmdTip[] = {
{ Temp_function, "Please input 1-11 to select test" } ,
{ BUZZER_PWM_Test, "Test PWM" } ,
{ RTC_Display, "RTC time display" } ,
{ Test_Adc, "Test ADC" } ,
{ KeyScan_Test, "Test interrupt and key scan" } ,
{ Test_Touchpanel, "Test Touchpanel" } ,
{ Lcd_TFT_Test, "Test TFT LCD" } ,
{ Test_Iic, "Test IIC EEPROM" } ,
{ PlayMusicTest, "UDA1341 play music" } ,
{ RecordTest, "UDA1341 record voice" } ,
{ Test_SDI, "Test SD Card" } ,
{ Camera_Test, "Test CMOS Camera"},
{ , }
};
void Main(void)
{
Beep(, );
Uart_SendByte('\n');
Uart_Printf("<***************************************>\n");
Uart_Printf(" TQ2440 Test Program\n");
Uart_Printf(" www.embedsky.net\n");
// Uart_Printf(" Build time is: %s %s\n", __DATE__ , __TIME__ );
Uart_Printf("<***************************************>\n");
while()
{
U8 idx;
Uart_Printf("\nPlease select function : \n");
for(i=; CmdTip[i].fun!=; i++)
{ Uart_Printf("%d : %s\n", i, CmdTip[i].tip);
idx = Uart_GetIntNum_GJ() ;
if(idx<i)
{
(*CmdTip[idx].fun)();
Delay();
Uart_Init( , );
}
}
}
}
通过反汇编我们可以看出,main()函数中的字符串不会被当做只读数据段处理,而被视作程序代码(.text)的一部分。只有以变量形式定义的字符串才会被视作只读数据段,例如Main()函数之前内容中的字符串。