Posted: May 17, 2009 at 3:10 pm | Tags: brew, mod, 动态加载
近日读到这样一段程序。可以在程序运行时调用另一个mod文件并执行。这样可以做到应用自升级,压缩程序文件等实用的功能。
要想理解这点,先看一下正常的BREW程序加载过程。
BREW程序的入口,即相当于c程序的main,是位于AEEModGen.c中的AEEMod_Load函数。这可以从mak文件的连接选项中看出来。
LINK_ORDER = -first AEEMod_Load
这个选项使得链接程序将该函数放在程序文件的0地址处。函数的定义如下:
int AEEMod_Load(IShell *pIShell, void *ph, IModule **ppMod)
{
// Invoke helper function to do the actual loading.
return AEEStaticMod_New(sizeof(AEEMod),pIShell,ph,ppMod,NULL,NULL);
}
BREW底层调用这个函数,需要提供三个参数。pIShell是ISHELL接口的指针,有了它就可以创建和访问其它接口。ph是helper function类函数的函数列表指针,有了它就可以调用MALLOC等函数。ppMod是用于返回给BREW底层的地址,存储生成的module的信息。
AEEMod_Load函数调用了AEEStaticMod_New函数。在这个函数中初始化了module数据结构,ppMod就是指向它的。函数结束后返回BREW底层。
BREW底层稍后通过存储在module数据结构中的函数指针,调用同样位于AEEModGen.c中的AEEMod_CreateInstance函数,生成该Module的某一个Applet实例。在这个函数中会调用到我们所编写的AEEClsCreateInstance函数。在我们这个函数中注册了HandleEvent函数和FreeAppDate函数。这些信息同样通过一个applet数据结构指针返回给BREW底层。这之后,BREW会通过给HandleEvent发各种Event,来驱动程序运行。
通过这整个过程,可以总结出BREW程序运行的必要条件。
程序必须得到IShell指针,Helper Function指针,这样程序中对BREW底层各种函数的调用才能进行。BREW底层必须知道两个地址,通过它们,可以将Event传递给程序,调用FreeAppDate函数。
因此,想在程序中调用另外一个mod,只需要想办法把程序里的IShell指针,Helper Function指针传递给mod,同时得到mod中的HandleEvent函数,FreeAppDate函数的地址就可以了。
剩下的问题就是,程序怎样和mod文件交互呢,mod文件的格式是怎样的?
生成mod的mak文件最后一般有这样两句话,
ld *.o a.elf
fromelf –bin a.elf a.mod
arm链接器ld生成ELF格式,之后用格式转换工具fromelf将ELF文件转换成mod文件。
ELF文件是带格式的可执行文件,对它的执行要靠操作系统的解析来进行。而通过–bin选项生成的mod文件,格式却是plain binary,即赤裸裸的二进制机器指令,其实是无格式的。只要将mod文件载入内存,跳转到它的0地址处,就可以一条条指令的执行下来。和mod文件交互,也就是要安排好mod文件0地址处的内容,知道mod文件的调用者会传入什么东西,mod文件会返回什么东西。
下面来看一种实际的调用方法吧。代码如下:
typedef int (*RunLoadMod)(IShell *pIShell, void *ph, IModule **ppMod);
pData = MyLoadZip(pIShell);
if( !pData )
return EFAILED;
DBGPRINTF(“to RunLoadMod”);
if( SUCCESS != ((RunLoadMod)pData)(pIShell,ph,&pOrgMod) )
{
DBGPRINTF(“RunLoadMod_Err”);
goto Crt_Err;
}
这段程序将mod文件读入内存,放在pData缓冲区内,用((RunLoadMod)pData)(pIShell,ph,&pOrgMod)一句执行之。RunLoadMod只不过是用typedef定义的一种函数指针类型。这句话的意思相当于是为待调用的mod文件准备好pIShell,ph,pOrgMod三个数据后,直接跳到内存中的mod文件的第一个字节处,将它当做普通机器指令一样执行。这种方法调用的mod文件,应是一个用完整的BREW框架编译后生成的。0地址处放下的是AEEMod_Load函数。Mod文件直接将Applet信息传递给BREW底层,注册HandleEvent函数。实际上是Mod文件取代了调用者的位置。
但是这段程序很可能会运行失败。因为BREW底层除了传参外,还做了其它事情。这在AEEStdlib.h中可以看出。
#define GET_HELPER() (*(((AEEHelperFuncs **)AEEMod_Load) – 1))
#define GET_HELPER_VER() (*((uint32 *)(((byte *)AEEMod_Load) – sizeof(AEEHelperFuncs *) – sizeof(uint32))))
这两个宏定义可以看成是两个全局常量。第一个是BREW Helper Function的函数指针表,第二个是函数指针表的版本号。上面提到的通过参数传递Helper Function函数指针,是只在模拟器上成立的。手机上其实是通过全局常量形式传递的。为保证mod可以正常运行,也应在缓冲区前保存这两个常量。
这种“冒名顶替”的方式,对于只想压缩一下mod的应用来说是完全可以的。但有时,我们希望新调用的mod只是整个应用的一小部分,调用者继续存在。这就需要调用者充当BREW底层的一部分角色,记住mod返回的各种信息,在适当的时候调用mod中的相应函数。新调用的mod如果想要取得主mod的信息,类似于上面提到的HelperFuncs全局常量指针的方法是个可行的选择。
其实知道了BREW程序的加载过程,就可以比较灵活的达到调用mod的目的,甚至BREW程序架构都是可以改动的。但是改动之后,如何在模拟器上进行调试就又成了一个问题。
程序中调用mod的技巧,在国外几年前就已得到了应用。甚至有家公司专门开发了利用这个技巧压缩mod的工具。
http://www.s-cradle.com/english/products/sophiacompress_brew/index.html
参考文章:
1.How to build A mod to load B mod?
http://brewforums.qualcomm.com/showthread.php?t=11637
2.How to run mod file that is loaded in the HEAP…
http://brewforums.qualcomm.com/showthread.php?t=18413&highlight=modloader
3.深入BREW模块加载机制
http://nicefuture.ycool.com/post.722858.html
4.深度剖析BREW实现原理收藏
http://blog.csdn.net/Gemsea/archive/2006/09/07/1190206.aspx
Posted: April 24, 2009 at 4:32 pm | Tags: ELF, OS, Symbian, 可执行文件
原译者:陈啸天(cxt_programmer)
请关注www.cpplite.com及bbs.cpplite.com
声明:原文出自大牛——ScreenShot作者A ntony P ranata 。本人英语很烂,之所以瞎译出来一是为了以后参考方便一些,二是在翻译的过程中自己能更仔细的看~。强烈建议大家对照英文原版来看哈。另外有些地方没有翻译,大家意会哈。
原文地址:
http://www.antonypranata.com/articles/new-symbian-os-9-executable-file-format-e32image
前言:
Symbian OS 9已经发布,与之前的版本相比,OS 9增加了许多新特性并有了一些改变,其中之一就是新的可执行文件格式(E32Image)。本文主要讨论了这个新的文件格式,如果你想了解OS 9之前的可执行文件格式,可以阅读一下我之前关于此话题的文章。
在开始之前,请注意我们仅仅讨论的是真机环境下的可执行文件格式(ARM)。为什么不讨论模拟器环境呢?因为运行在模拟器的可执行文件使用了一种不同的文件格式(Cxt注:模拟器下的可执行文件应该是windows的PE格式),如果你之前不了解任何一个平台的可执行文件格式,下面的介绍会更好的帮助你理解E32文件格式。
这篇文章是在Symbian网站或者其他拥有Symbian OS licensees的厂商(例如Nokia)提供的公开信息(文档)之上完成的。虽然我目前在一家手机厂商工作,但这篇文章涉及内容的正确性并未经过公司的核对。尽管我已经紧握最大的努力确保这篇文章内容的正确,但我仍然无法100%保证(Cxt音:看看,大牛总是很谦虚的,我们要做一个谦虚的人哈)。
EABI介绍( Introduction to EABI ):
ABI(应用程序二进制接口,Application Binary Interface)是由ARM及其合作伙伴们制定的一个标准,它定义了如何编译、链接,以及其他工具怎样生成obj文件和可执行文件。这个标准可以让不同编译器生成的obj文件互通,例如可以把不同编译器生成的obj文件组合在一起。EABI(嵌入式应用程序二进制接口, Embedded Application Binary Interface )也是这样的标准,它就是嵌入式平台的ABI。
写这篇文章的时候,有两种编译器可以用于Symbian OS 9——RVCT( RealView Compilation Tools )和GCCE。RVCT是ARM公司开发的编译器,license费用可达数千美元;与此不同,GCCE是一个由 CodeSourcery 开发的免费编译器;顾名思义,GCCE基于GNU编译器。
EABI编译器生成的格式为ELF( Executable and Linking Format ),它不同于Symbian OS 9之前的PE格式。然而Symbian OS并不使用ELF格式,因为Symbian OS通常在大小受限的ROM上,而标准ELF文件的尺寸通常又很大。所以Symbian把标准的ELF转换为Symbian特有的E32Image格式。如果你有安装Symbian SDK,可以在epoc32\tools目录下找到用于把ELF转换为E32Image的工具,它叫elf2e32.exe。
下图展示了Symbian OS 9的新工具链。如你所见,最后生成的是由elf2e32.exe转换完的Symbian特有格式——E32Image。Symbian网站和SDK中有更多关于这方面的介绍。(Cxt注:SDK help: » Symbian OS v9.1 » Symbian OS Tools And Utilities » Build tools guide » The native build targets 目录下有全面详细的文档介绍)。通常你不会看到下图所示的流程,因为Symbian OS使用一些脚本工具(例如bldmake、abld等)自动完成。

如果你不熟悉.dso文件也没关系,它其实与Symbian OS 9以及其他平台的.lib文件是一样的。(Cxt注:.dos提供导出的函数的名称和位置,DLL包含实际的函数和数据。)
我在前面说过,ELF文件通常都很大,不适合用于手机。减少ELF尺寸的方法之一是把函数名字替换为序号。例如可以把MyFunction()替换为1,正如你期望的,这种方法可以极大的减小ELF的尺寸,特别是当函数名称很长时(例如 ThisIsVeryLongFunction ())这种效果更加明显。额等等!如此一来,如何找到序号和函数名称之间的对应关系呢?别急,我们有一个.def文件,它提供了序号与函数名之间的对应关系。(Cxt:呼 …… )
E32Image概述( Overview of E32Image ):
现在让我们来看看E32Image吧。与其他标准的可执行文件类似,它也包含头(Header)、代码段(Code Section)、数据段(Data Section)、导入段(Import Section)等等。

上图展示了E32文件格式,与其他可执行文件格式一样,最开始的部分是header。下面我会着重介绍E32 header里面都有些什么东东。在Header之下还有一些其它section(Cxt:这部分大家意会哈^_^):
· Code section, contains all the object files (.o) of your source code as well as export address table that lists all the exported functions.
· BSS section, contains un-initialized data.
· Data section, contains initialized data.
· Import section, contains the information about all imported functions used by your program.
· Relocation section, contains relocation table needed by Symbian OS loader to load your program.
E32Image头( Header of E32Image ):
头信息也许是最有趣的部分,因为它包含了可执行文件的很多信息。E32ImageHeader的声明可以在SDK的\epoc32\include\f32image.h中找到。看看class E32ImageHeaderV 的声明,这可是E32Image文件格式完整的头信息。如果你仔细看了class E32ImageHeaderV ,你会发现它继承了E32HeaderComp(E32HeaderComp继承了E32ImageHeader)。下图对它们的关系做了更好的说明:

下面的代码片段展示了 EImageHeader , EImageHeaderComp 和 E32ImageHeaderV 的声明,请注意我删减了部分函数以及注释以便于更清晰的查看:
class E32ImageHeader
{
public :
TUint32 iUid1;
TUint32 iUid2;
TUint32 iUid3;
TUint32 iUidChecksum;
TUint iSignature; // ’EPOC’
TUint32 iHeaderCrc; // CRC-32 of entire header
TUint32 iModuleVersion; // Version number for this executable (used in link resolution)
TUint32 iCompressionType; // Type of compression used (UID or 0 for none)
TVersion iToolsVersion; // Version of PETRAN/ELFTRAN which generated this file
TUint32 iTimeLo;
TUint32 iTimeHi;
TUint iFlags; // 0 = exe, 1 = dll, 2 = fixed address exe
TInt iCodeSize; // size of code, import address table, constant data and export dir
TInt iDataSize; // size of initialised data
TInt iHeapSizeMin;
TInt iHeapSizeMax;
TInt iStackSize;
TInt iBssSize;
TUint iEntryPoint; // offset into code of entry point
TUint iCodeBase; // where the code is linked for
TUint iDataBase; // where the data is linked for
TInt iDllRefTableCount; // filling this in enables E32ROM to leave space for it
TUint iExportDirOffset; // offset into the file of the export address table
TInt iExportDirCount;
TInt iTextSize; // size of just the text section, also doubles as the offset for the
// iat w.r.t. the code section
TUint iCodeOffset; // file offset to code section, also doubles as header size
TUint iDataOffset; // file offset to data section
TUint iImportOffset; // file offset to import section
TUint iCodeRelocOffset; // relocations for code and const
TUint iDataRelocOffset; // relocations for data
TUint16 iProcessPriority; // executables priority
TUint16 iCpuIdentifier; // 0×1000 = X86, 0×2000 = ARM
};
class E32ImageHeaderComp : public E32ImageHeader
{
public :
TUint32 iUncompressedSize; // Uncompressed size of file
// For J format this is file size - sizeof(E32ImageHeader)
// and this is included as part of the compressed data :-(
// For other formats this is file size - total header size
};
class E32ImageHeaderV : public E32ImageHeaderComp
{
public :
SSecurityInfo iS;
// Use iSpare1 as offset to Exception Descriptor
TUint32 iExceptionDescriptor; // Offset in bytes from start of code section to Exception Descriptor,
// bit 0 set if valid
TUint32 iSpare2;
TUint16 iExportDescSize; // size of bitmap section
TUint8 iExportDescType; // type of description of holes in export table
TUint8 iExportDesc[1]; // description of holes in export table - extend
};
我将逐一解释上面这些字段。从下面的列表中,左端的16进制数表示这个字段在文件中的偏移量,例如iUid2的位置是从文件头部开始0×04的位置。换句话说,如果你把可执行文件用二进制编辑器打开,然后找到偏移量0×04的位置你就可以找到iUid2。注意E32Image使用小端格式(little-endian order)。
E32ImageHeader :
0×00: iUid1 ,可执行文件的第一个UID。这个UID可被看作是一个系统级别的标识符,例如Dlls是 0×1000 0079 ,可执行程序是 0×1000 007A 。如果你想更多的了解Symbian OS UID相关信息,可以 访问这里 。
0×04: iUid2 ,可执行文件的第二个UID。当两个对象拥有同一个UID1的时候,就需要用这个UID来区分它们,例如 0×1000 39CE 表示多态接口Dll( polymorphic interface DLLs ), 0×1000 008d 表示静态接口( static interface (shared library) )。
0×08: iUid3 ,可执行文件的第三个UID。 每个程序的UID3都不同。下面这段不翻译了,贴个图看图识字吧^_^。
It is unique for each application. Developers have to request this UID from Symbian Signed service. Symbian OS 9 applications usually have UIDs in the range of 0×200 0000 and 0x2FFF FFFF. Examples from Symbian OS SDKs, like S60 SDK or UIQ SDK, have the UIDs in the range of 0xA000 0000 and 0xAFFF FFFF. There are also some UID available for testing, which can be chosen from the range 0×0100 0000 to 0x0FFF FFFF.

0x0C: iUidChecksum ,校验前面提到的3个UID。Symbian SDK中提供了一个uidcrc.exe工具完成该功能;下面的例子展示了如何生成这三个UID: 0×1000 007A , 0×1000 39CE 和 0xA000 017F 的校验码:
C:\>uidcrc 0x1000007A 0x100039CE 0xA000017F
0x1000007a 0x100039ce 0xa000017f 0x1e7cca07
0×10: iSignature ,E32文件唯一签名( unique signature )。值统一为“EPOC”。图示如下:

0×14: iHeaderCrc ,整个头信息的完整校验,使用 CCITT CRC-32 算法。
0×18: iModuleVersion ,可执行版本号。该信息用于链接过程(linking process)。在S60 3 rd , iModuleVersion 值为10( 0×0000 000A )(Cxt注:大牛这里可能笔误了,iModuleVersion是T u int32,占4个字节,这个值应该是0x000A 0000)。

0x1C: iCompressionType ,一个UID,表示使用哪种压缩算法压缩了可执行文件。如果值为0就说明未压缩。就我目前所看到的,只使用了一种压缩算法:由RFC 1951定义的 Deflate/Huffman 算法。它的UID是 KUidCompressionDeflate ( 0x101F 7AFC )。需要注意的是,未来也许会使用其他压缩算法。

0×20: iToolsVersion ,生成这个可执行文件的 ELFTRAN 工具版本。
0×24: iTimeLo ,时间戳。 the lowest word of the timestamp when the file is created.
0×28: iTimeHi ,时间戳。 the lowest word of the timestamp when the file is created.
0x2C: iFlags ,可执行文件的一个标记,比如 KImageDll , KImageNoCallEntryPoint 等。这些标记定义在f32image.h中。f32image.h中有一些函数定义用来解释这些标记的意思。例如:如果flag值为 0×1200 002A ,我们可以把它看作: 0×1000 0000 + 0×0200 0000 + 0×0000 00020 + 0×0000 0008 + 0×0000 00002 ,结合f32image.h中的常量声明,我们可以发现:
· 0×10000000 = KImageImpFmt_PE ,可执行文件使用ELF-derived入口。
· 0×02000000 = KImageHdrFmt_V ,header的版本支持。
· 0×00000020 = KImageEpt_Eka2 ,EKA2可执行文件。
· 0×00000008 = KImageABI_EABI ,可执行文件为EABI image file。
· 0×00000002 = KimageNoCallEntryPoint ,no call to entry point。
0×30: iCodeSize , is the size of code section, import address table, constant data and export dir.
0×34: iDataSize , size of initialised data.
0×38: iHeapSizeMin , the minimum size of the heap.
0x3C: iHeapSizeMax , the maximum size of the heap.
0×40: iStackSize , the size of the stack.
0×44: iBssSize , the size of the un-initialized data section.
0×48: iEntryPoint , offset into code of entry point.
0x4C: iCodeBase , where the code is linked for.
0×50: iDataBase , where the data is linked for.
0×54: iDllRefTableCount , the number of DLLs imported by this program.
0×58: iExportDirOffset , offset into the file of the export address table.
0x5C: iExportDirCount , the offset of the export address table.
0×60: iTextSize , size of just the text section, also doubles as the offset for the iat w.r.t. the code section.
0×64: iCodeOffset , file offset to code section, also doubles as header size.
0×68: iDataOffset , file offset to data section.
0x6C: iImportOffset , file offset to import section.
0×70: iCodeRelocOffset , relocations for code and const.
0×74: iDataRelocOffset , relocations for data.
0×78: iProcessPriority , executables priority.
0x7A: iCpuIdentifier , the identifier of CPU. Look at the following constant for all possible values:
enum TCpu
{
ECpuUnknown=0,
ECpuX86=0×1000,
ECpuArmV4=0×2000,
ECpuArmV5=0×2001,
ECpuArmV6=0×2002,
ECpuMCore=0×4000
};
E32ImageHeaderComp :
开始之前,我们需要知道2个结构:定义在e32cmn.h的 ScapabilitySet 和 SSSecurityInfo 。Symbian OS 9可以看到它们,它们保存了平台安全相关信息,比如能力(capability)、安全标识符(secure identifier)和厂商标识符(vendor identifier)。
struct SCapabilitySet
{
enum {ENCapW=2};
TUint32 iCaps[ENCapW];
};
struct SSecurityInfo
{
TUint32 iSecureId;
TUint32 iVendorId;
SCapabilitySet iCaps; // Capabilities re. platform security
};
好了,让我们回到 E32ImageHeaderV :
0×80: iS.iSecureId ,可执行文件的安全ID(secure ID)。就是可执行文件的UID3。
0×84: iS.iVendorId ,可执行文件的厂商ID(vendor ID)。对于第三方应用程序,值为0。
0×88: iS.iCaps.iCaps ,运行可执行文件需要的能力。Symbian OS所有的能力定义可以在 e32capability.h 文件中找到。
enum TCapability
{
ECapabilityTCB = 0,
ECapabilityCommDD = 1,
ECapabilityPowerMgmt = 2,
ECapabilityMultimediaDD = 3,
ECapabilityReadDeviceData = 4,
ECapabilityWriteDeviceData = 5,
ECapabilityDRM = 6,
ECapabilityTrustedUI = 7,
ECapabilityProtServ = 8,
ECapabilityDiskAdmin = 9,
ECapabilityNetworkControl = 10,
ECapabilityAllFiles = 11,
ECapabilitySwEvent = 12,
ECapabilityNetworkServices = 13,
ECapabilityLocalServices = 14,
ECapabilityReadUserData = 15,
ECapabilityWriteUserData = 16,
ECapabilityLocation = 17,
ECapabilitySurroundingsDD = 18,
ECapabilityUserEnvironment = 19,
};
能力以bit的形式表示,例如 ECapabilityTCB 意味着最低有效位(LSB),如果设置了最低有效位,可执行文件就具有TCB能力。
0×90: iExceptionDescriptor , is offset in bytes from start of code section to Exception Descriptor, bit 0 set if valid
0×94: iSpare2 , reserved.
0×98: iExportDescSize , size of bitmap section.
0x9A: iExportDescType[1] , type of description of holes in export table.
0x9B: iExportDesc[1] , is description of holes in export table.
Example:
下面我们来看一个例子,来帮助你更好的理解上面说的那些字段。我们将使用标准的Symbian OS build command来编译3.0 SDK提供的Helloworld Basic例子。
C:\Symbian\9.1\S60_3rd\S60Ex\helloworldbasic>bldmake bldfiles
C:\Symbian\9.1\S60_3rd\S60Ex\helloworldbasic>abld build gcce urel
现在切换到 \epoc32 \r elease\gcce\urel 目录,使用 Elf2E32 工具读取E32 image头信息。做法如下:
C:\Symbian\9.1\S60_3rd\S60Ex\helloworldbasic>elf2e32 –e32input=helloworldbasic.exe
然后你将会看到 helloworldbasic.exe 的头信息;输出的过程可能会很长,所以一个比较好的方法是将他转储到文件,便于我们进一步分析:
C:\Symbian\9.1\S60_3rd\S60Ex\helloworldbasic>elf2e32 –e32input=helloworldbasic.exe > helloworldbasic.txt
打开 helloworldbasic.txt ,你将会看到头信息(我已经用绿色的注释标明了 E32ImageHeaderV 的字段):
E32ImageFile ’helloworldbasic.exe’
V2.00(505) Time Stamp: 00e0eb0a,d2525b80 // iTimeStampHi, iTimeStampLo
EPOC Exe for ARMV5 CPU // iCpuIdentifier = 0×20001 (ARMv5)
Flags: 1200002a // iFlags
Priority Foreground
Entry points are not called
Image header is format 2
Image is compressed using the DEFLATE algorithm // iCompressionType
Uncompressed size 0000b788
Image FPU support : Soft VFP
Secure ID: a000017f // iSecureId
Vendor ID: 00000000 // iVendorId
Capabilities: 00000000 00000000 // iSs.iCaps.iCaps
Exception Descriptor Offset: 00002561 // iExceptionDescriptor
Exception Index Table Base: 00012dfc
Exception Index Table Limit: 000130bc
RO Segment Base: 00008001
RO Segment Limit: 0000a77c
Export Description: Size=000, Type=01 // iExportDescSize = 000 iExportDescType = 01
Export description consistent
Module Version: 10.0 // iModuleVersion
Imports are ELF-style
ARM EABI
Built against EKA2
Uids: 1000007a 100039ce a000017f (1e7cca07)
// iUid1 = 1000007a, iUid2 = 100039ce, iUid3 = a000017f, iUidChecksum = 1e7cca07
Header CRC: 023aca0d // iHeaderCrc
File Size: 0000b788 // iUncompressedSize
Code Size: 0000b0bc // iCodeSize
Data Size: 00000000 // iDataSize
Compression: 101f7afc // iCompressionType
Min Heap Size: 00001000 // iHeapSizeMin
Max Heap Size: 00100000 // iHeapSieMax
Stack Size: 00005000 // iStackSize
Code link addr: 00008000 // iCodeBase
Data link addr: 00400000 // iDataBase
Code reloc offset: 0000b650 // iCodeRelocOffset
Data reloc offset: 00000000 // iDataRelocOffset
Dll ref table count: 10 // iDllRefTableCount
Offset Size Relocs #Relocs
Code 00009c 00b0bc 00b650 00007d +002504 (entry pnt)
// iCodeOffset = 00009c iCodeSize = 00b0bc iCodeRelocOffset = 00b650
Data 000000 000000
// iDataOffset iDataSize
Bss 000000 // iBssSize
Import 00b158 // iImportOffset
全都在这了!!希望你能够喜欢这篇文章!
Posted: October 15, 2008 at 1:36 pm | Tags: mtk, 山寨, 秘诀, 蔡明介
“常常有人问我,联发科在过去10年里迅速崛起,有什么秘诀?并且希望这些’秘诀’对正在快速发展中的中国大陆芯片企业有所启发.”给人印象深刻的一副标志性的大眼镜,从外表看,联发科技董事长蔡明介并不具备在商场上拼杀的枭雄造型.然而,他却是台湾赴美引进半导体技术的先驱,被誉为台湾集成电路设计“教父”.

1995年蔡明介领导台湾“联华电子”的集成电路设计部门独立创业,成立了“联发科技”的前 身多媒体小组,联华电子是仅次于台积电的全球第二大流片厂。IC行业流传着一句难以溯源的话———现在的芯片业,每个非大厂都不希望联发科涉及自己的领 域,那样自己就“离死不远了”。
并非危言耸听,经历10余年的发展,目前联发科已成为世界顶尖的IC专业设计公司,位居全球 消费性IC片组的领航地位。产品领域覆盖数码消费、数字电视、光储存、无线通讯等多个系列,是亚洲唯一连续六年蝉联全球前十大IC设计公司唯一的华人企 业,被美国《福布斯》杂志评为“亚洲企业50强”。
没有听说过联发科,只要是对手机产业链稍有了解的人,也会对MTK这三个字母的组合有些印象。MTK是联发科技股份有限公司的英文简称,英文全称叫MediaTek.
「杀手锏」一站式方案
或许有人不太喜欢这家公司,因为从早年的黑手机到现在的山寨机,草莽气息背后是MTK方案被广泛应用。波导、夏新,老牌手机厂商令人堪忧的一份份财务报告中总会附带“受到黑手机、山寨机冲击”的说明,MTK可被视作始作俑者之一。
但你不得不佩服MTK的创新和成功,甚至也找不出更多口诛笔伐的理由。因为MTK的存在,近年来国内手机产业进入了前所未有的蓬勃发展阶段。事实上MTK除了为山寨机提供方案,也同时为正规厂商提供全面解决方案,包括近两年迅速崛起的天语、金立等正规品牌。
“我们有个客户的工程师曾经很形象地打了个比方,他说MTK的解决方案更像是一本”烹饪手册 “,它只能保证厨师不会把鱼香肉丝做成京酱肉丝,至于这道菜做出来的色香味如何,那还是看终端厂商的水准。”联发科首席财务官兼新闻发言人喻铭铎曾向本报 记者表示,MTK提供的是一个把厂商开发过程中可能遇到的问题尽量提前考虑到的参考性的解决方案。厂商在开发过程中如果遇到一些原先技术能力较为薄弱的地 方,可以从这个参考性的解决方案中获得借鉴与补充,从而不断弥补原来的不足。
凭借这种“菜谱”方式,MTK在大陆市场上结结实实地击败了众多国际芯片厂商。操作软件,甚至液晶、摄像头等部件,MTK都可以“一站解决”,大大缩短了手机的生产环节并降低了研发成本。这正是Turnkeysolution(一站式方案)模式。
Turnkeysolution正是MTK手机平台的核心。在这套解决方案中,将手机芯片和 手机软件平台预先整合到一起。这种方案可以使终端厂商节约成本,加速产品上市周期。MTK公司的产品因为集成较多的多媒体功能和较低的价格在大陆手机公司 和手机设计公司得到广泛的应用。加上MTK的完工率较高,基本上在60%以上,这样手机厂商拿到手机平台基本上就是一个半成品,只要稍稍的加工就可上架出 货了。
数年前,德州仪器(TI)的LoCosto、OMAP平台,英飞凌的ULC解决方案,还一度是这些国际知名厂商广泛采用的模式。然而MTKTurnkey方案的巨大成功则证明了在这一领域平台技术不再是TI、英飞凌这些巨头的专属。
「性价比」到底到什么程度
1999年,当时的联发科在台湾科技行业中还仅是一家生产光存储和DVD芯片的二线厂商。然而当时,蔡明介看中了利润更加丰厚的手机芯片业务,恰逢中国手机市场进入第一次高速增长期,他的眼光自然而然地落在了中国大陆市场。
2001年开始,MTK开始在手机行业逐渐渗透Turnkeysolutio模式,这种模式内蕴着极高的性价比。在国内手机制造仍处于朦胧阶段的时刻,这种性价比着实让人难以抗拒。
号称2007年全年销量达到1500万台的天宇朗通便广泛采用了MTK的产品。“感谢 MTK,感谢台湾人。”天宇朗通销售总监卢伟冰在今年天津手机展新闻发布会上曾表示,中国拥有全球配套最完善的手机产业集群。都说手机没有核心技术,都说 在欧美人的手里,大家都觉得很失望。但是我们的台湾人做了很多基础芯片研究,MTK的问世把没有技术、没有解决方案这个历史进行了改写。
天宇朗通是近年来当之无愧的国产手机黑马。在其面向下游的销售模式中,和MTK的高性价比、 低价出牌也有着惊人的相似。本地一位零售商代表向记者表示,天宇朗通完全摒弃了过去手机企业的价保模式,取而代之的是以较低的价格出货给代理商,再由下游 定价。“一款产品我们的进货价若只有300元,定价600元销售也有可能,毕竟同等功能配置的洋品牌还要贵上至少100元。”
300元,只是手机厂商给予渠道的价格,他们从MTK手中获得的方案呢,性价比究竟能高到什 么程度?以行业内最普遍使用的联发科(MTK)低端方案6223为代表。可支持T-flash扩展卡,彩屏,具备自动应答留言机功能,键盘采用动感炫灯。 如量产二十万台,单价在14美金左右,不到人民币100元。
同样是在2001年,联发科在台湾上市,更素有“台湾股王”之称。直至2007年,其营业收 入已达到新台币804.09亿元,较2006年增长51%.根据最新市场资料显示,2007年联发科年手机晶片出货量高达1.5亿颗,全球市场占有率近 14%,仅次于德州仪器及高通。
「声誉」骂名、美名
联发科真正开始在大陆市场上崭露头角,2005年是关键年。在那个还没有取消手机核准制度的 年代,早前依靠贴牌韩国方案而迅速崛起的国产手机在洋品牌的全线反攻下,跌入了全线溃败的谷底。夏新、波导、TCL,大量的民族手机品牌惨遭洗牌,国产手 机也因此背上了“质量不好”的包袱。
然而就在这一时期,具有中国特色的黑手机跃上了手机产业的历史舞台。这些手机主要通过模仿知 名品牌的外形。以及低廉的价格来吸引消费者。黑手机一词诞生于联发科Turnkeysolutio模式广泛进入中国市场之前,但因为MTK的存在,黑手机 发生了“革命性”的变化。MTK也因此背上了“黑手机之父”的骂名。
早期的黑手机,在没有采用MTK方案之前规模并不大,以翻新、通过各种渠道寻找廉价方案为主 要表相。在MTK全面解决方案进入中国市场后,生产方一次过便可以获得包括基带芯片、操作软件,甚至液晶显示屏、摄像头等部件等全套或半套解决方案。一举 将原来的6-9个月甚至是一年的手机研发周期,缩短到了3个月以内。
直至国家取消手机牌照核准制度,黑手机这个称谓已不合时宜,源于MP3行业的“山寨”一词取而代之。不过MTK并未因此而被改称作“山寨机之父”。在国产手机产业发展到目前的规模,讨论MTK的成分变得丝毫没有意义。
可以说,黑手机、山寨机空前的泛滥与MTK有着必然联系,但无论从技术还是道德的范畴,如今 更为理性的观点大都认为不应该由MTK为这种泛滥负责。Turnkeysolutio模式的崛起、MTK的成功,背后更多体现的是手机行业新兴市场飞速发 展的带动和技术的成熟和全球化,技术门槛降低后的必然结果。
至于黑手机、山寨机偷税漏税等问题,更多体现的是法律环境的不健全。在知识产权保护、税收、产品质量、工人权益、生产和市场准入、走私控制等方面所存在的漏洞,而这些实际才是黑手机为生产、流通和销售创造优越环境的根本。
MTK从未为任何有关于自己的报道辩驳,但依然落入了尴尬的境地。这种情况目前随着越来越多的品牌厂商采用其方案而获得改善,MTK的模式更成为不少IC企业效仿的对象。
联发科发展的几个瞬间
1995年,成立……
蔡明介领导台湾“联华电子”的集成电路设计部门独立创业,成立了“联发科技”的前身多媒体小组,初始只有20余人。
2001年,钟情手机芯片
联发科在台湾成功上市,51岁的蔡明介则必须做出选择———创业前4年,联发科必须在CD- ROM、CD-RW以及DVD-ROM等几代芯片的稳定发展后找到下一个拳头产品,这可以说是决定联发科生死的问题。按照蔡明介经验,一定要符合市场足够 大;有一定的技术门槛和别人拉开差距;和联发科原来的开发技术有一定的相关性这三个标准。
经过内部激烈的讨论后,联发科决定投入手机芯片研发。当时台湾手机代工行业逐渐兴起,作为上游,联发科最终决定跟着客户走,杀入手机芯片领域。
2003-2004年,成长的低谷
是联发科颇为难熬的一段日子,手机行业的前景在哪里?当时,处于中游的台湾手机代工企业活得并不好,选定道路的联发科则不得不加大研发费用的投入。
此时,联发科之前的光存储和DVD产品市场已经逐渐饱和,价格开始下滑。手机芯片虽然在 2003年底开发成功,却迟迟无法打开市场。更重要的是,想“跟着”的那些客户并没有预想的成功,联发科必须去寻找新的客户。2004年四季度,代工行业 的连锁反应落在了联发科身上,其毛利率大跌40%%,在投资人会议上,蔡明介甚至亲自拿出采用自家芯片的手机进行演示,希望能够给投资人以信心。
据统计,当年全球IC设计产业总体增长率为27%,而联发科营收仅增长了5.23%.
2004年,猛虎出笼……
最终台湾一家叫达智的手机制造小公司因为无力采购国际IC设计巨头的产品,在实属无奈的情况 下采用了联发科的方案。由于当时手机IC设计领域并没有重视媒体功能的植入,大多仍采用双芯片分别控制通话和多媒体的设计,成本较高。而联发科因为此前做 CD、DVD芯片的开发,有这方面基础,迅速打开了市场。
2008年,跻身世界前三
手机芯片部门的收入已经占到联发科营收的50%以上,联发科也仅次于德州仪器及高通,跻身世界前三大IC手机设计厂商。
文/《南方都市报》
Posted: September 11, 2008 at 1:23 am | Tags: mtk, vxworks, 动态加载
转至:http://www.cnblogs.com/hpunix/articles/355758.html
整个过程为:
创建文件系统–》下载文件–》加载模块–》查找符号地址并执行
以下为演示该过程的一个简易实现文件,有使用或者引用的话,也
打个招呼,或者给评论一下:
==============START OF THE FILE=============
/*********************************************************
* 版权所有 NP系统工作室。
*
* 文件名称: \FilseSystemCreate.c
* 文件标识:
* 内容摘要: 创建文件系统,在系统启动之后保存文件
* 其它说明:
* 当前版本: S 1.0
* 作 者: william
* 完成日期: 2005-10-12 17:04
* 当前责任人-1:william
*
* 修改记录1:
* 修改日期:2006-3-21 12:00
* 版 本 号:S 1.0
* 修 改 人:william
* 修改内容:创建
* 修改记录2:
**********************************************************/
#include <taskLib.h>
#include <vxWorks.h>
#include <stdio.h>
#include <string.h>
#include <ioLib.h >
#include <symLib.h >
#include <loadlib.h >
#include “dosFsLib.h”
#include “ramDrv.h”
#include “usrLib.h”
typedef int STATUS;
#define ERROR -1
#define OK 0
#define DIAG_RAM_DISK_SIZE (0×100000*10) /* 64M */
#define DIAG_RAM_DISK_NAME “/selfdev/”
STATUS FileSystem_Init()
{
BLK_DEV *pBlkDev;
char *pFileSysRamDiskBase = NULL;
ramDrv();
pFileSysRamDiskBase = malloc(DIAG_RAM_DISK_SIZE);
if(NULL == pFileSysRamDiskBase)
return ERROR;
bzero(pFileSysRamDiskBase,DIAG_RAM_DISK_SIZE);
pBlkDev = ramDevCreate( pFileSysRamDiskBase,
/* start address */
512,
/* sector size */
64,
/* sectors per track */
(int)(DIAG_RAM_DISK_SIZE/512),
/* total sectors 64 MBytes */
0);
/* offset */
if(NULL == pBlkDev)
{
free(pFileSysRamDiskBase);
return ERROR;
}
if(NULL == dosFsMkfs (DIAG_RAM_DISK_NAME, pBlkDev))
{
free(pFileSysRamDiskBase);
return ERROR;
}
return OK;
}
extern SYMTAB_ID sysSymTbl ;
void runModule()
{
STATUS status=ERROR;
int fd;
MODULE_ID hModule ;
FUNCPTR taskEntry = NULL ;
SYM_TYPE * pType ;
if ((fd = open(“/selfdev/youown.o”, O_RDONLY, 0)) < 0)
{
printf(“\nCannot open memory device.\n”);
goto done;
}
if ((hModule=loadModule(fd,LOAD_ALL_SYMBOLS))==NULL)
{
printf(“loadModule error = 0x%x.\n”,errno) ;
goto done;
}
status = symFindByName(sysSymTbl,
“willian_test”,
(char **)&taskEntry,pType ) ;
if (status==ERROR)
{
printf(“symFindByName error=%d\\n”, errno) ;
goto done;
}
else
{
printf(“taskEntryr=0x%x, type=%d\n.”,
(int)taskEntry,(int)*pType);
status = taskSpawn(“test1″,
100,
0,
30000,
taskEntry,
0,0,0,0,0,0,0,0,0,0) ;
if (status==ERROR)
{
printf(“taskSpawn error=%d\n”,errno) ;
goto done;
}
}
done:
if (fd >= 0)
close(fd);
}
int downLoadModules(
char *hostName,
char *srcfileName,
char *destfileName,
char *usr,
char *passwd)
{
………
/*实现下载远端PC模块到本地机*/
return (filesize);
}
STATUS test_dynamic_download()
{
STATUE status = OK;
int fileLenth = 0;
status = FileSystem_Init();
if(status == ERROR)
{
printf(“\nerror occured during init file system\n”);
return ERROK;
}
fileLenth = downLoadModules(“winner2″,
“youown.o”,
“/selfdev/youown.o”,
“target”,
“target”);
if(ERROR == fileLenth)
{
printf(“\nSome error occured when download files\n”);
return ERROK;
}
else
{
if(0 == fileLenth)
{
return OK;
}
}
runModule();
}
=============END OF THE FILE==========
几个需要注意的问题:
1:在文件系统初始化中使用的是MALLOC,该部分是使用的实际是
BSP的空间在实际申请的过程中一定要根据自己可能拷贝的文
件大小和实际的BSP的空间
2:在创建文件系统之后,可以查看该目录的文件列表,或者执行
COPY,前提是必须在TORNADO中选择初始化文件系统组件;
3:在下载文件的过程中,有的BSP初始化已经可以直接通过COPY
在远端FTP SERVER直接拷贝文件,比如:
copy “youown.o”,”/selfdev/youown.o”
这种情况没有必要再调用downLoadModules,至于如何使能,
大家关注的话可以在后边对其专门论述。
4:加载模块的过程可以调用如下代码:
if ((hModule=loadModule(fd,LOAD_ALL_SYMBOLS))==NULL)
同样也可以如下实现:
ld(1,0,”/selfdev/youown.o”);
至于各个参数什么意思,参考HELP就可以找到结论了!
5:在 status = symFindByName(sysSymTbl,
“willian_test”,
(char **)&taskEntry,pType ) ;
中,有可能实际返回错误,但是通过lkup 是可以实际找到的,
对于这个问题,我看网上答案比较少,原因是这样的:
假如你在主机运行shell,默认的远端目标机是没有符号表
(symbol table)的,只有在主机的shell上,你运行LKUP的
时候,才能找到这个符号,不信你可以这样尝试一下,打开两
个SHELL,一个通过串口,一个通过TORNADO的网口,你在其中
一个中能够使用LKUP找到,而在另外一个则不能找到,是不是
呀??
接下来继续解释,我们的symFindByName是在目标机器上
执行的,所以自然的就返回错误了,也是没有找到了!
解决方法是这样的:在目标机中包含符号表,同时将其和
主机保持同步。
Wind River told us to include all this defines in the
config files for the target:
#define INCLUDE_SYM_TBL_SYNC
#define INCLUDE_LOADER
/* object module loading */
#define INCLUDE_NET_SYM_TBL
/* load the symbol table by whatever means */
#define INCLUDE_SHELL
/* target-based shell */
#define INCLUDE_SHOW_ROUTINES
/* optional target-based system utilities */
#define INCLUDE_STAT_SYM_TBL
/* optional target error status routines */
#define INCLUDE_SYM_TBL
/* symbol table package */
#define INCLUDE_UNLOADER
/* optional object module unloading */
#define INCLUDE_WDB