很多人对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脚本将变量定义到了代码段,代码段和其他段本质上差的不多,也是可以读写的,所以不会引发问题.
this post is very usefull thx!