BREW程序执行周期

很多人对BREW程序的机制不是很清楚,不明白为什么BREW无法使用静态变量,无法使用异常,为什么AEEApplet必须放在第一个位置,这一切,都是和BREW程序的结构造成的。
先从BREW的执行文件的格式来说,BREW的mod文件可以认为是可行镜像,仅仅只有代码段,没有其他的数据段,因此,静态变量,异常等等,就无处栖身,所以无法支持。但为什么Applet必须在第一个呢?这有BREW程序的执行顺序决定的。
BREW的mod文件只有代码段,因此,上来只有代码,刚开支执行的代码其实是AEEMod_Load的代码,在编译时选项 -first AEEMod_Load已经指明了,AEEMod_Load接下来调用的是AEEStaticMod_New函数了,AEEMod_Load需要的IShell, pf, ppMod都是由系统给的。

在AEEStaticMod_New函数中,主要初始化AEEMod结构,这个结构将会返回给系统,在AEEMod结构中,会初始化AEEMod结构中的AddRef,Release,CreateInstance,FreeResources函数指针,以及其他的函数指针。将m_nRef的值初始化为1。这样如果系统中存在多个相同的AEEMod的时候,释放时,当m_nRef得值减小到0的话,就会真正的从内存中清空。
在上述函数执行完成之后,应该返回系统了,系统将会执行其他的步骤,在这期间,应该调用了AEEMod_CreateInstance函数,这个函数的任务就是调用BREW给我们生成的模板的AEEClsCreateInstance。至于系统执行了哪些内容,我不是研究BREW系统执行的,所以也不知道,从顺序上来说,应该是这样。
现在到了我们自己可以随便修改的代码了,在AEEClsCreateInstance中,首先判断ClsID的值(从mif文件中获得的),然后通过AEEApplet_New函数来生成新的AEEApplet。
AEEApplet_New将会设置AEEApplet中的shell,mode等变量以及回调函数,在该函数中,对于AEEApplet的地址,AEEApplet_New并不知道,因此,它要求AEEApplet必须在结构体的第一个,这样AEEApplet的地址和申请的内存的地址是一样的,它将会修改AEEApplet大小的内存,之后的内存,并不做修改,在这些之后,它将生成一个默认的IDisplay。
在AEEApplet_New执行成功之后,将会调用Instance_InitAppData,让用户来初始化其他变量。
如果所有的都成功,将会返回到系统(AEEClsCreateInstance),系统将会调用AEEApplet中设置好的事件回调函数,进行各种事件的发送。
如果系统中存在多个实例,系统将会调用Add_Ref函数,如果减少了一个实例,将会调用_Release函数,如果m_nRefs减少到0,将表示该彻底从系统中删除了。
上面基本上就是BREW程序的整个是生命期,由于mod结构的影响,无法使用静态变量等需要使用其他数据段的方法,由于初始化的需要,AEEApplet被放置到了第一个位置。不过,使用GCC的编译器的话,将不会受到静态变量等影响,但AEEApplet还是得要第一个(这个不是编译器的限制)。从GCC的link控制脚本便可以看出来:

       /*
 * File: armelf.brew
 *
 * Simple Linker Script for 4.1.0 WinARM Tool Chain for BREW
 *
 * This linker script creates an ELF suitable for input to BREWelf2Mod.
 * Please read the comments and don't be afraid.
 *
 * Besides taking care of some BREW housekeeping, its big claim to fame
 * is KEEP()-ing the .data  and .bss segments around in the 4.x GCC world 
 * (even if empty) so BREWelf2mod (I'm using 53,248 byte version of 15 Mar 04)
 * doesn't go nuts and make multi-megabyte mod files.
 *
 * This script takes care of the -entry, and -T text 0 switches for you,
 * and, on a good day, arranges for AEEModGen.o to be linked first.
 * (You could add another line for AEEAppGen.o after too, then you would
 * not have to specify either when linking.)
 *
 * This is free and unrestricted for your use and modification. 
 * Standard disclaimers. Please return useful changes to the forum.
 *
 * Use:
 *    \winarm\bin\arm-elf-ld.exe --script armelf.brew  
 *                                --emit-relocs 
 *                                --verbose
 *                                --no-warn-mismatch
 *                                -Map "myapp.map" --cref 
 *                                -L \winARM\lib\gcc\arm-elf\4.1.0\ [...]
 *                                -o "myapp.elf" 
 *                                AEEAppGen.o myapp.o ...
 *
 * --emit-relocs and --script are _required_.
 *
 *
 * HISTORY
 *
 * 04May06      Ward Willats / VeriSign    First try
 * 08May06      Ward Willats / VeriSign    Force section with ARRModLoad to be first
 * 30Jul06      Ward Willats / VeriSign    force alignment of .bss -- fixes odd-ball
 *                                         crashes in relocation fixup code if sizes
 *                                         happen to come out odd
 * 18Apr07      Richard Willis / Openwave  Added ctors & dtors, modified the
 *                                         AEEModGen.o entry to allow the object to
 *                                         be specified on the command line.
 */  

OUTPUT_FORMAT("elf32-littlearm")   /* change or add elf32-bigarm if you need it */
OUTPUT_ARCH(arm)
ENTRY(AEEMod_Load)                 /* don't need -entry switch anymore, silence warnings */

SECTIONS
{
    /* This is the text section. I am setting both the RVA and  LMA
    ...to zero. This means you don't have to use -T text 0 on the 
    ...command line. Also, I am forcing AEEModGen.o to be first.
    */


    .text 0 : AT( 0 )
    {   
        /* This locates AEEMod_Load and makes sure it is first no matter
           what your optimization settings are. You _MUST_ compile 
           AEEModGen.c with -ffunction-sections for this to work.
           Note this was modified from Ward's original version, and now
           uses '*' wildcard prefix.  This prevents the linker from loading
           the file unless it's specified on the command line, thus making
           it easier to support different object directories.
        */
        *AEEModGen.o(.text.AEEMod_Load)

        /* and bring in all the other code */

        *(.text .text.* .gnu.linkonce.t.*)   /* .text and .text.func name -- if separate sections for each file */
        *(.glue_7t) *(.glue_7)

        /* global constructors (these directives taken from the RedHat "Using ld" guide) */
        . = ALIGN( 4 );                              /* ensure the constructors list starts on a 4byte boundary (may be unnecessary, but it's better to be safe) */
        __CTOR_LIST__ = .;                           /* define a label equal to the start of the global constructors */
        LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2) /* store the nof constructors in the list ( "/4" as each entry is 4 bytes long, "-2" to ignore this length & the NULL terminator ) */
        *(.ctors)                                    /* store the global constructors here */
        LONG(0)                                      /* NULL terminate the list */
        __CTOR_END__ = .;                            /* define a label equal to the end of the constructor list */

        /* global destructors (see constructor comments) */
        . = ALIGN( 4 );
        __DTOR_LIST__ = .;
        LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)
        *(.dtors)
        LONG(0)
        __DTOR_END__ = .;
    }

     /* Following provides symbolic .fini section with symbols to 
     ...mark the end of .text, but not used by BREWelf2mod, I think.
     ...Dunno about RTL. "KEEP()"  makes sure this emtpy sections gets
     ...by empty section garbage collection by ld . This is symbolic
     ...so "free" to keep here. */

    .fini : { KEEP( *(.fini) ) } = 0
    PROVIDE (__etext = .);
    PROVIDE (_etext = .);
    PROVIDE (etext = .);
    
    /* Read-Only Data */

    .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.* ) }

    /* You shouldn't have any initialized global data here, you bad 
    ...boy, but BREWelf2mod definitely needs a .data section in the
    ...output file NO MATTER WHAT, so it can figure out how long the
    ...text section is. */

    .data :
    {
        __data_start = . ;         /* this label probably isn't used, but       */ 
        KEEP( *(.data .data.* .gnu.linkonce.d.* ) ) 
    }

    /* Okay, uninitialized global variables go here. I found out
    ...by leaving this out BREWelf2mod uses this in its calculations
    ...too -- probably to determine image size (which it records in the
    ...header of the startup code it sticks on the mod file). So you must KEEP()
    ...it. I also added labels marking the beginning and end of bss.
    ...My thinking is that, although the mod startup code BREWelf2mod adds
    ...to the mod image _may_ zero BSS, you could guarantee it by having
    ...the first thing that happens in AEEMod_Load() be something like:
    ...      
    ...    byte * pby    = (byte*) &__bss_start;
    ...    byte * pbyEnd = (byte*) &__bss_end;
    ...    while( pby < pbyEnd ) *pby++ = 0;
    ...          
    ...or, you know, a fancy 32-bit loop for ARM.
    ...
    ...
    */

    __bss_start = NEXT(0x8);
    .bss ALIGN(0x8): { KEEP( *(.bss .bss.* .gnu.linkonce.b.* ) ) *(COMMON) }
    __bss_end = .;


    /* Don't think BREW needs this either but seems good to provide 
     ...end of everything" label */

    __end__ = . ;
    _end = .; PROVIDE (end = .);

    /* Following debugging stuff I just lifted wholesale from armelf.xc */

    .stab           0 : { *(.stab) }
    .stabstr        0 : { *(.stabstr) }
    .stab.excl      0 : { *(.stab.excl) }
    .stab.exclstr   0 : { *(.stab.exclstr) }
    .stab.index     0 : { *(.stab.index) }
    .stab.indexstr  0 : { *(.stab.indexstr) }
    .comment        0 : { *(.comment) }
    .debug          0 : { *(.debug) }
    .line           0 : { *(.line) }
    .debug_srcinfo  0 : { *(.debug_srcinfo) }
    .debug_sfnames  0 : { *(.debug_sfnames) }
    .debug_aranges  0 : { *(.debug_aranges) }
    .debug_pubnames 0 : { *(.debug_pubnames) }
    .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
    .debug_abbrev   0 : { *(.debug_abbrev) }
    .debug_line     0 : { *(.debug_line) }
    .debug_frame    0 : { *(.debug_frame) }
    .debug_str      0 : { *(.debug_str) }
    .debug_loc      0 : { *(.debug_loc) }
    .debug_macinfo  0 : { *(.debug_macinfo) }

    /* and we don't need a stack segment for BREW since AEE 
    ...takes care of everything */

}

/* end: armelf.brew  */

       

gcc非常的灵活,它通过link脚本将变量定义到了代码段,代码段和其他段本质上差的不多,也是可以读写的,所以不会引发问题.

发布者

rix

如果连自己都不爱自己,哪还有谁来爱你