ADS的默认连接分析及编译器产生符号解惑

时间:2022-09-08 04:45:20

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的默认连接分析及编译器产生符号解惑
ADS的默认连接分析及编译器产生符号解惑
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.o

Execution 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.o

Execution 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      Debug

29120        407     505876     267608     114304   Object Totals
     15804        747          0         96       5096   Library Totals

================================================================================
      Code    RO Data    RW Data    ZI Data      Debug

44924       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()函数之前内容中的字符串。