近日读到这样一段程序。可以在程序运行时调用另一个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
原译者:陈啸天(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 0×2FFF 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 0×0FFF FFFF.

0×0C: iUidChecksum ,校验前面提到的3个UID。Symbian SDK中提供了一个uidcrc.exe工具完成该功能;下面的例子展示了如何生成这三个UID: 0×1000 007A , 0×1000 39CE 和 0xA000 017F 的校验码:
C:\>uidcrc 0×1000007A 0×100039CE 0xA000017F
0×1000007a 0×100039ce 0xa000017f 0×1e7cca07
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个字节,这个值应该是0×000A 0000)。
![]()
0×1C: iCompressionType ,一个UID,表示使用哪种压缩算法压缩了可执行文件。如果值为0就说明未压缩。就我目前所看到的,只使用了一种压缩算法:由RFC 1951定义的 Deflate/Huffman 算法。它的UID是 KUidCompressionDeflate ( 0×101F 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.
0×2C: 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.
0×3C: 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.
0×4C: 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.
0×5C: 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.
0×6C: 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.
0×7A: 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.
0×9A: iExportDescType[1] , type of description of holes in export table.
0×9B: 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
全都在这了!!希望你能够喜欢这篇文章!
我们PC的Windows操作系统功能是如此的强大,以至于我们可以获得任何一个我们想要的程序,任何一个人都可以为Windows开发应用程序,或者给自己,或者为他人。而这一切源于操作系统的开放性和硬件平台的不断发展,尤其是存储器的发展,使得我们在编写程序的时候不必在意需要多大的存储空间了。

|
FastString.h– 接口声明文件第一版
|
|
#ifndef FASTSTRING_H_
#define FASTSTRING_H_
// 要求使用者不能直接使用此结构体中的内容
typedef struct _IFastString {
char *m_pString; // 指向字符串的指针
} IFastString;
// 创建目标字符串对象
void IFastString_CreateObject(IFastString * pIFastString, char *pStr);
// 释放目标字符串对象
void IFastString_Release(IFastString *pIFastString);
// 获取目标字符串长度
int IFastString_GetLength(IFastString *pIFastString);
// 查找字符串,返回偏移量
int IFastString_Find(IFastString *pIFastString, char *pFindStr);
#endif // FASTSTRING_H_
|
|
FastString.c– 接口实现文件第一版
|
|
#include ”FastString.h”
#include <string.h>
// 创建目标字符串对象
void IFastString_ CreateObject (IFastString * pIFastString, char *pStr)
{
IFastString *pMe = pIFastString;
if(pMe == NULL || pStr == NULL)
{
return;
}
pMe->m_pString = malloc(strlen(pStr) +1);
strcpy(pMe->m_pString,pStr);
}
// 释放目标字符串对象
void IFastString_Release(IFastString *pIFastString)
{
IFastString *pMe = pIFastString;
if(pMe == NULL)
{
return;
}
if(pMe->m_pString)
{
free(pMe->m_pString);
}
}
// 获取目标字符串长度
int IFastString_GetLength(IFastString *pIFastString)
{
IFastString *pMe = pIFastString;
if(pMe == NULL)
{
return;
}
return strlen(pMe->m_pString);
}
// 查找字符串,返回偏移量
int IFastString_Find(IFastString *pIFastString, char *pFindStr)
{
IFastString *pMe = pIFastString;
if(pMe == NULL)
{
return;
}
// 搜索算法省略,因为这里仅仅假设存在这样的一个搜索算法
}
|


|
FastString.h– 接口声明文件第二版
|
|
#ifndef FASTSTRING_H_
#define FASTSTRING_H_
// 要求使用者不能直接使用此结构体中的内容
typedef struct _IFastString {
char *m_pString; // 指向字符串的指针
int m_nLen; // 存储字符串的长度
} IFastString;
#endif // FASTSTRING_H_
|
|
FastString.c– 接口实现文件第二版
|
|
// 创建目标字符串对象
void IFastString_ CreateObject (IFastString * pIFastString, char *pStr)
{
IFastString *pMe = pIFastString;
if(pMe == NULL || pStr == NULL)
{
return;
}
pMe->m_nLen = strlen(pStr);
pMe->m_pString = malloc(pMe->m_nLen +1);
strcpy(pMe->m_pString,pStr);
}
// 获取目标字符串长度
int IFastString_GetLength(IFastString *pIFastString)
{
IFastString *pMe = pIFastString;
if(pMe == NULL)
{
return;
}
return pMe->m_nLen;
}
|
|
FastString.h– 接口声明文件第三版
|
|
#ifndef FASTSTRING_H_
#define FASTSTRING_H_
typedef void IFastString;
// 创建目标字符串对象
void IFastString_CreateObject(IFastString ** ppIFastString, char *pStr);
// 释放目标字符串对象
void IFastString_Release(IFastString *pIFastString);
// 获取目标字符串长度
int IFastString_GetLength(IFastString *pIFastString);
// 查找字符串,返回偏移量
int IFastString_Find(IFastString *pIFastString, char *pFindStr);
#endif // FASTSTRING_H_
|
|
FastString.c– 接口实现文件第三版
|
|
#include ”FastString.h”
#include <string.h>
typedef struct _CFastString {
char *m_pString; // 指向字符串的指针
int m_nLen; // 存储字符串的长度
} CFastString;
// 创建目标字符串对象
void IFastString_CreateObject (IFastString **ppIFastString, char *pStr)
{
CFastString *pMe = malloc(sizeof(CFastString));
if(pMe == NULL || pStr == NULL)
{
return;
}
pMe->m_nLen = strlen(pStr);
pMe->m_pString = malloc(pMe->m_nLen +1);
strcpy(pMe->m_pString,pStr);
* ppIFastString = (IFastString *)pMe;
}
// 释放目标字符串对象
void IFastString_Release(IFastString *pIFastString)
{
CFastString *pMe = (CFastString *)pIFastString;
if(pMe == NULL)
{
return;
}
if(pMe->m_pString)
{
free(pMe->m_pString);
}
free(pMe)
}
// 获取目标字符串长度
int IFastString_GetLength(IFastString *pIFastString)
{
CFastString *pMe = (CFastString *)pIFastString;
if(pMe == NULL)
{
return;
}
return strlen(pMe->m_pString);
}
// 查找字符串,返回偏移量
int IFastString_Find(IFastString *pIFastString, char *pFindStr)
{
CFastString *pMe = (CFastString *)pIFastString;
if(pMe == NULL)
{
return;
}
// 搜索算法省略,因为这里仅仅假设存在这样的一个搜索算法
}
|
|
FastString.h– 接口声明文件第四版
|
|
#ifndef FASTSTRING_H_
#define FASTSTRING_H_
typedef struct _IFastString IFastString;
typedef struct _IFastStringVtbl IFastStringVtbl;
typedef void (*PFNCreateObject)( IFastString **ppIFastString, char *pStr);
struct _IFastString
{
struct IFastStringVtbl *pvt;
};
struct _IFastStringVtbl
{
void (*Release) (IFastString *pIFastString);
int (*GetLength) (IFastString *pIFastString);
int (*Find) (IFastString *pIFastString, char *pFindStr);
};
// 释放目标字符串对象
#define IFASTSTRING_Release(p) ((IFastString*)p->pvt)->Release(p)
// 获取目标字符串长度
#define IFASTSTRING_GetLength(p) ((IFastString*)p->pvt)->GetLength(p)
// 查找字符串,返回偏移量
#define IFASTSTRING_Find(p,s) ((IFastString*)p->pvt)->Find(p,s)
#endif // FASTSTRING_H_
|
|
FastString.c– 接口实现文件第四版
|
|
#include ”FastString.h”
#include <string.h>
typedef struct _CFastString {
IFastStringVtbl *pvt; // 指向虚拟函数表的指针
char *m_pString; // 指向字符串的指针
int m_nLen; // 存储字符串的长度
} CFastString;
// 函数声明
static void IFastString_Release(IFastString *pIFastString);
static int IFastString_GetLength(IFastString *pIFastString)
static int IFastString_Find(IFastString *pIFastString, char *pFindStr);
IFastStringVtbl gvtFastString = { IFastString_Release,
IFastString_GetLength,
IFastString_Find
};
// 创建目标字符串对象
void IFastString_CreateObject (IFastString **ppIFastString, char *pStr)
{
CFastString *pMe = malloc(sizeof(CFastString));
if(pMe == NULL || pStr == NULL)
{
return;
}
pMe->pvt = &gvtFastString;
pMe->m_nLen = strlen(pStr);
pMe->m_pString = malloc(pMe->m_nLen +1);
strcpy(pMe->m_pString,pStr);
* ppIFastString = (IFastString *)pMe;
}
// 释放目标字符串对象
static void IFastString_Release(IFastString *pIFastString)
{
CFastString *pMe = (CFastString *)pIFastString;
if(pMe == NULL)
{
return;
}
if(pMe->m_pString)
{
free(pMe->m_pString);
}
free(pMe)
}
// 获取目标字符串长度
static int IFastString_GetLength(IFastString *pIFastString)
{
CFastString *pMe = (CFastString *)pIFastString;
if(pMe == NULL)
{
return;
}
return strlen(pMe->m_pString);
}
// 查找字符串,返回偏移量
static int IFastString_Find(IFastString *pIFastString, char *pFindStr)
{
CFastString *pMe = (CFastString *)pIFastString;
if(pMe == NULL)
{
return;
}
// 搜索算法省略,因为这里仅仅假设存在这样的一个搜索算法
}
|

|
shell.h– 接口声明文件
|
|
#ifndef SHELL_H_
#define SHELL_H_
#define CLASSID_FASTSTRING 0×00000001
#define CLASSID_FASTNUMBER 0×00000002
typedef struct _IShell IShell;
typedef struct _IShellVtbl IShellVtbl;
struct _IShell
{
struct IShellVtbl *pvt;
};
struct _IShellVtbl
{
void (*CreateInstance) (IShell *pIShell,
int nClassID,
void **ppObj,
unsigned int nUserData);
};
// 释放目标字符串对象
#define ISHELL_CreateInstance(p,c,pp,u) ((IShell*)p->pvt)->CreateInstance(p,c,pp,u)
#endif // SHELL_H_
|
|
Shell.c– 接口实现文件
|
|
#include ”Shell.h”
typedef struct _CShell {
IShellVtbl *pvt; // 指向虚拟函数表的指针
} CShell;
// 函数声明
static void IShell_CreateInstance(IShell *pIShell,
int nClassID,
void **ppObj,
unsigned int nUserData);
IShellVtbl gvtShell = { IShell_CreateInstance };
// 创建Shell对象
void IShell_CreateObject (void**ppObj, unsigned int nUserData)
{
CShell *pMe = malloc(sizeof(CShell));
if(pMe == NULL)
{
return;
}
pMe->pvt = &gvtShell;
* ppObj = (void*)pMe;
}
// 创建由ClsID指定的
static void IShell_CreateInstance(IShell *pIShell,
int nClassID,
void **ppObj,
unsigned int nUserData)
{
CShell *pMe = (CShell *)pIShell;
if(pMe == NULL)
{
return;
}
switch(nClassID){
case CLASSID_FASTSTRING:
break;
case CLASSID_FASTNUMBER:
IFastNumber_CreateObject((IFastNumber **)ppObj, nUserData);
break;
default:
break;
}
}
|
|
typedef struct _IFastString IFastString;
typedef struct _IFastStringVtbl IFastStringVtbl;
struct _IFastString
{
struct IFastStringVtbl *pvt;
};
struct _IFastStringVtbl
{
void (*Release) (IFastString *pIFastString);
int (*GetLength) (IFastString *pIFastString);
int (*Find) (IFastString *pIFastString, char *pFindStr);
};
|
|
typedef struct _IFastString IFastString;
typedef struct _IFastStringVtbl IFastStringVtbl;
struct _IFastString
{
struct IFastStringVtbl *pvt;
};
struct _IFastStringVtbl
{
// 第一版接口
void (*Release) (IFastString *pIFastString);
int (*GetLength) (IFastString *pIFastString);
int (*Find) (IFastString *pIFastString, char *pFindStr);
// 第二版接口
int (*FindN)( IFastString *pIFastString, char *pFindStr, int n);
};
|
|
IFastString *pFastString;
char TargetStr[] = “This is a test example only!”’
ISHELL_CreateInstance(pShell, CLASSID_FASTSTRING, (void **)&pFastString, (unsigned int)TargetStr);
(void)FastString_Test(pFastString);
|
|
int FastString_Test(IFastString *pFastString)
{
int nOffset;
nOffset = IFASTSTRING_Find(pFastString, ”test”);
IFASTSTRING_Release(pFastString);
return nOffset;
}
|
|
FastString.h– 接口声明文件第五版
|
|
#ifndef FASTSTRING_H_
#define FASTSTRING_H_
typedef struct _IFastString IFastString;
typedef struct _IFastStringVtbl IFastStringVtbl;
struct _IFastString
{
struct IFastStringVtbl *pvt;
};
struct _IFastStringVtbl
{
int (*AddRef) (IFastString *pIFastString);
int (*Release) (IFastString *pIFastString);
int (*GetLength) (IFastString *pIFastString);
int (*Find) (IFastString *pIFastString, char *pFindStr);
};
// 增加接口指针的引用计数
#define IFASTSTRING_AddRef(p) ((IFastString*)p->pvt)->AddRef(p)
// 释放目标字符串对象
#define IFASTSTRING_Release(p) ((IFastString*)p->pvt)->Release(p)
// 获取目标字符串长度
#define IFASTSTRING_GetLength(p) ((IFastString*)p->pvt)->GetLength(p)
// 查找字符串,返回偏移量
#define IFASTSTRING_Find(p,s) ((IFastString*)p->pvt)->Find(p,s)
#endif // FASTSTRING_H_
|
|
FastString.c– 接口实现文件第五版
|
|
#include ”FastString.h”
#include <string.h>
typedef struct _CFastString {
IFastStringVtbl *pvt; // 指向虚拟函数表的指针
int m_nRef;
char *m_pString; // 指向字符串的指针
int m_nLen; // 存储字符串的长度
} CFastString;
// 函数声明
static int IFastString_AddRef(IFastString *pIFastString);
static int IFastString_Release(IFastString *pIFastString);
static int IFastString_GetLength(IFastString *pIFastString)
static int IFastString_Find(IFastString *pIFastString, char *pFindStr);
IFastStringVtbl gvtFastString = { IFastString_AddRef,
IFastString_Release,
IFastString_GetLength,
IFastString_Find
};
// 创建目标字符串对象
void IFastString_CreateObject (IFastString **ppIFastString, unsigned int nUserData)
{
CFastString *pMe = malloc(sizeof(CFastString));
char *pStr = (char *)nUserData;
if(pMe == NULL || pStr == NULL)
{
return;
}
pMe->pvt = &gvtFastString;
pMe->m_nLen = strlen(pStr);
pMe->m_pString = malloc(pMe->m_nLen +1);
strcpy(pMe->m_pString,pStr);
pMe->m_nRef = 1;
* ppIFastString = (IFastString *)pMe;
}
// 增加接口指针的引用计数
static int IFastString_AddRef(IFastString *pIFastString)
{
CFastString *pMe = (CFastString *)pIFastString;
return (++pMe->m_nRef);
}
// 释放目标字符串对象
static int IFastString_Release(IFastString *pIFastString)
{
CFastString *pMe = (CFastString *)pIFastString;
if(–pMe->m_nRef >0)
{
return pMe->m_nRef;
}
if(pMe->m_pString)
{
free(pMe->m_pString);
}
free(pMe)
}
// 获取目标字符串长度
static int IFastString_GetLength(IFastString *pIFastString)
{
CFastString *pMe = (CFastString *)pIFastString;
return strlen(pMe->m_pString);
}
// 查找字符串,返回偏移量
static int IFastString_Find(IFastString *pIFastString, char *pFindStr)
{
CFastString *pMe = (CFastString *)pIFastString;
// 搜索算法省略,因为这里仅仅假设存在这样的一个搜索算法
}
|


Tags: brew
转至Gemsea大人的BLOG:http://blog.csdn.net/Gemsea
硬件是软件的运行平台,没有硬件的支撑软件也将不复存在。您能想象没有显示器软件将如何显示图形,没有CPU软件将如何运行吗?反正我想象不到!但是如果把问题反过来问就问到本质了,软件运行需要哪些硬件支持呢?看图1.1:
|
CPU
|
|
RAM
|
|
ROM
|
|
输出设备
|
|
输入设备
|
|
存储设备
|
|
设备
|
PC系统典型硬件设备
|
嵌入式系统典型硬件设备
|
|
CPU
|
任何CPU
|
任何CPU
|
|
RAM
|
任何RAM
|
任何RAM
|
|
ROM
|
BIOS芯片
|
Flash芯片
|
|
存储设备
|
硬盘
|
Flash芯片
|
|
输入设备
|
键盘
|
键盘
|
|
输出设备
|
显示卡+显示器
|
LCD显示屏
|
|
BIOS自检
|
|
显卡BIOS检测
|
|
CPU型号检测、内存测试
|
|
读取硬盘启动扇区
|
|
获取操作系统启动文件
|
|
二进制形态
|
PC系统
|
嵌入式系统
|
|
用户数据
|
存储在文件系统中,典型的设备是硬盘
|
存储在文件系统中,典型的设备是Flash存储芯片
|
|
程序数据
|
可读可写的数据存放在RAM中;只读数据存放在硬盘中,运行时与代码一起读入RAM
|
可读可写的数据存放在RAM中;只读数据存放在Flash中,与代码存储在同一个区域
|
|
代码
|
存储在文件系统中的文件里,运行时读入RAM由CPU执行
|
如果存储在NOR Flash等可随机访问的空间中则CPU直接在芯片中取指令运行;如果存储在NAND Flash等不能随机访问的空间中则需要读入RAM中运行
|
|
1
|
|
2
|
|
3
|
|
A
|
|
B
|
|
C
|
Tags: brew
一直以来对于ARM体系中所描述的RO,RW和ZI数据存在似是而非的理解,这段时间对其仔细了解了一番,发现了一些规律,理解了一些以前书本上有的但是不理解的东西,我想应该有不少人也有和我同样的困惑,因此将我的一些关于RO,RW和ZI的理解写出来,希望能对大家有所帮助。
要了解RO,RW和ZI需要首先了解以下知识:
ARM程序的组成
此处所说的“ARM程序”是指在ARM系统中正在执行的程序,而非保存在ROM中的bin映像(image)文件,这一点清注意区别。
一个ARM程序包含3部分:RO,RW和ZI
RO是程序中的指令和常量
RW是程序中的已初始化变量
ZI是程序中的未初始化的变量
由以上3点说明可以理解为:
RO就是readonly,
RW就是read/write,
ZI就是zero
ARM映像文件的组成
所谓ARM映像文件就是指烧录到ROM中的bin文件,也成为image文件。以下用Image文件来称呼它。
Image文件包含了RO和RW数据。
之所以Image文件不包含ZI数据,是因为ZI数据都是0,没必要包含,只要程序运行之前将ZI数据所在的区域一律清零即可。包含进去反而浪费存储空间。
Q:为什么Image中必须包含RO和RW?
A:因为RO中的指令和常量以及RW中初始化过的变量是不能像ZI那样“无中生有”的。
ARM程序的执行过程
从以上两点可以知道,烧录到ROM中的image文件与实际运行时的ARM程序之间并不是完全一样的。因此就有必要了解ARM程序是如何从ROM中的image到达实际运行状态的。
实际上,RO中的指令至少应该有这样的功能:
1. 将RW从ROM中搬到RAM中,因为RW是变量,变量不能存在ROM中。
2. 将ZI所在的RAM区域全部清零,因为ZI区域并不在Image中,所以需要程序根据编译器给出的ZI地址及大小来将相应得RAM区域清零。ZI中也是变量,同理:变量不能存在ROM中
在程序运行的最初阶段,RO中的指令完成了这两项工作后C程序才能正常访问变量。否则只能运行不含变量的代码。
说了上面的可能还是有些迷糊,RO,RW和ZI到底是什么,下面我将给出几个例子,最直观的来说明RO,RW,ZI在C中是什么意思。
1; RO
看下面两段程序,他们之间差了一条语句,这条语句就是声明一个字符常量。因此按照我们之前说的,他们之间应该只会在RO数据中相差一个字节(字符常量为1字节)。
Prog1:
#include <stdio.h>
void main(void)
{
;
}
Prog2:
#include <stdio.h>
const char a = 5;
void main(void)
{
;
}
Prog1编译出来后的信息如下:
================================================================================
Code RO Data RW Data ZI Data Debug
948 60 0 96 0 Grand Totals
================================================================================
Total RO Size(Code + RO Data) 1008 ( 0.98kB)
Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)
Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)
================================================================================
Prog2编译出来后的信息如下:
================================================================================
Code RO Data RW Data ZI Data Debug
948 61 0 96 0 Grand Totals
================================================================================
Total RO Size(Code + RO Data) 1009 ( 0.99kB)
Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)
Total ROM Size(Code + RO Data + RW Data) 1009 ( 0.99kB)
================================================================================
以上两个程序编译出来后的信息可以看出:
Prog1和Prog2的RO包含了Code和RO Data两类数据。他们的唯一区别就是Prog2的RO Data比Prog1多了1个字节。这正和之前的推测一致。
如果增加的是一条指令而不是一个常量,则结果应该是Code数据大小有差别。
2; RW
同样再看两个程序,他们之间只相差一个“已初始化的变量”,按照之前所讲的,已初始化的变量应该是算在RW中的,所以两个程序之间应该是RW大小有区别。
Prog3:
#include <stdio.h>
void main(void)
{
;
}
Prog4:
#include <stdio.h>
char a = 5;
void main(void)
{
;
}
Prog3编译出来后的信息如下:
================================================================================
Code RO Data RW Data ZI Data Debug
948 60 0 96 0 Grand Totals
================================================================================
Total RO Size(Code + RO Data) 1008 ( 0.98kB)
Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)
Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)
================================================================================
Prog4编译出来后的信息如下:
================================================================================
Code RO Data RW Data ZI Data Debug
948 60 1 96 0 Grand Totals
================================================================================
Total RO Size(Code + RO Data) 1008 ( 0.98kB)
Total RW Size(RW Data + ZI Data) 97 ( 0.09kB)
Total ROM Size(Code + RO Data + RW Data) 1009 ( 0.99kB)
================================================================================
可以看出Prog3和Prog4之间确实只有RW Data之间相差了1个字节,这个字节正是被初始化过的一个字符型变量“a”所引起的。
3; ZI
再看两个程序,他们之间的差别是一个未初始化的变量“a”,从之前的了解中,应该可以推测,这两个程序之间应该只有ZI大小有差别。
Prog3:
#include <stdio.h>
void main(void)
{
;
}
Prog4:
#include <stdio.h>
char a;
void main(void)
{
;
}
Prog3编译出来后的信息如下:
================================================================================
Code RO Data RW Data ZI Data Debug
948 60 0 96 0 Grand Totals
================================================================================
Total RO Size(Code + RO Data) 1008 ( 0.98kB)
Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)
Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)
================================================================================
Prog4编译出来后的信息如下:
================================================================================
Code RO Data RW Data ZI Data Debug
948 60 0 97 0 Grand Totals
================================================================================
Total RO Size(Code + RO Data) 1008 ( 0.98kB)
Total RW Size(RW Data + ZI Data) 97 ( 0.09kB)
Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)
================================================================================
编译的结果完全符合推测,只有ZI数据相差了1个字节。这个字节正是未初始化的一个字符型变量“a”所引起的。
注意:如果一个变量被初始化为0,则该变量的处理方法与未初始化华变量一样放在ZI区域。
即:ARM C程序中,所有的未初始化变量都会被自动初始化为0。
总结:
1; C中的指令以及常量被编译后是RO类型数据。
2; C中的未被初始化或初始化为0的变量编译后是ZI类型数据。
3; C中的已被初始化成非0值的变量编译后市RW类型数据。
附:
程序的编译命令(假定C程序名为tst.c):
armcc -c -o tst.o tst.c
armlink -noremove -elf -nodebug -info totals -info sizes -map -list aa.map -o tst.elf tst.o
编译后的信息就在aa.map文件中。
ROM主要指:NAND Flash,Nor Flash
RAM主要指:PSRAM,SDRAM,SRAM,DDRAM
转载自http://android.hk.cn
本文将用老谋深算的Symbian平台、历史悠久的Windows Mobile平台、玲珑剔透的Mac OS X平台、前景光明的Android平台四个章节对目前市面上主流手机操作系统的优势和特色做一个详细的介绍。
老谋深算的Symbian平台
随着科技和信息技术的发展,人们对手机功能的要求也越来越高。现在,很多人对手机已不仅仅满足于打电话和发短信等基本功能,而是要求它能够播放音乐、上网聊天、安排日程甚至进行GPS导航。因此,很多人已经逐步抛弃传统固化软件的手机,改投智能手机的怀抱。目前,在智能手机市场上,销量最大的平台有三种,分别是Symbian、Windows Mobile和Mac OS X,其中前两种都有一种以上的手机品牌在使用,而Mac OS X仅为苹果iPhone和iPhone 3G独占使用。现在,基于Google Android平台的新一代智能手机T-Mobile G1马上就要上市,它几乎无可非议的会受到人们的追捧。这样一来,市场上便形成了四大智能手机操作平台鼎立的局面。
Symbian(塞班)
首先要提到的当然是Symbian(塞班)系统。使用在智能手机上的Symbian系统分为S60和UIQ两种用户界面,其中前者现已发展到v3版本。得益于世界手机老大诺基亚的大力支持,安装了Symbian S60系统的手机已经广为人们使用。而UIQ的主推者是索尼爱立信,虽然UIQ的界面更加华丽,但由于索尼爱立信自身和手机市场的原因,Symbian UIQ一直没有能够得到很好的发展。
由于Symbian由多家传统手机厂商联合研发,因此无论在运行速度还是易用性上跟其它的系统相比都有很大的优势,而且对移动通信协议,如GSM、GPRS、WCDMA和蓝牙等的支持要优于其它系统。由于发布时间较早,其第三方软件经过几年的发展数量已经非常之多,可以实现人们的大多数需求。
但遗憾的是,由于系统的先天限制,Symbian系统的多媒体性能并不突出。刷固件较为困难、内存紧张等问题是一直是人们所诟病的几大缺憾。S60 v3发布后诺基亚开始推行的签名策略也浇灭了很多人开发第三方软件的热情。而且,Symbian系统实现触摸操作相当困难,好在诺基亚拥有强大的研发实力。相信继5800 XpressMusic之后,诺基亚还会继续推出触摸屏机型。不过尽管如此,Symbian平台凭着强大的电话功能和较强的易用性,仍然博得了很多人的青睐。
历史悠久的Windows Mobile平台
Windows Mobile
作为微软下了血本研发的一个操作平台,Windows Mobile系统自然丝毫不能被轻视。Windows Mobile的前身是Windows CE,一个微软专为PDA和掌上电脑开发的嵌入式系统。后来随着智能手机的出现,Windows CE演变成了Windows Pocket PC。2003年,微软又开发了Pocket Phone Edition和Windows Powered Smart Phone操作系统,而这两者的融合,才是严格意义上的Windows Mobile。
目前,Windows Mobile最高版本为6.1。它最大的优势在于其PDA(个人数字助理)功能非常强大,并可通过ActiveSync或Windows Mobile Center和计算机中Outlook等程序保持同步,商务人士可使用该系统随时处理文件、邮件或进行日程安排。由于这个系统的历史非常悠久,和桌面版Windows系统也有异曲同工之处,其第三方软件的数量已经多到了一个令人难以想象的地步。通过各种第三方软件,安装了Windows Mobile系统的手机可以发挥几乎无限的用途。对于软件开发者来说,由于Windows Mobile系统的软件开发较为简单,再加上新版系统中增加了对.Net Framework的支持,使软件的开发相当便利。而对于最终用户来说,Windows Mobile系统的操作方式跟桌面版Windows非常类似,都有开始菜单等人们所熟悉的组件,熟悉计算机的人可以很快上手使用。
但Windows Mobile系统的缺陷也是显而易见的。按照通常的说法,它有着三大缺陷。其一是系统运行速度太慢。或许是微软往小小的系统中塞了很多东西,Windows Mobile也延续了Windows系统庞大臃肿的毛病,几乎可以算得上是反应最慢的智能手机操作系统。其二是支持的颜色数仅为65000色。关于这个问题很多年前人们就开始抱怨,到现在还是如此。不知道微软为什么不听听群众们的呼声。其三是系统操作过于复杂。它的很多设置都隐藏在层层菜单和选项下,有时甚至还需动用注册表修改器,仍然继承了桌面版Windows的传统。虽然这可能正好满足了少数人的“变态”控制欲。
但是总的来说,Windows Mobile以其强大的功能、便捷的信息管理以及第三方软件众多等优势,一直以来都为世人所喜爱。当然,更重要的是它还有微软这样一个重量级的后盾。可以说,只要微软不倒,Windows Mobile也将一直生存下去。
玲珑剔透的Mac OS X平台
Mac OS X
苹果的iPhone手机自从公布的那天起便一直受到人们的关注,现在的iPhone 3G也是如此。iPhone使用的操作系统为精简过的Mac OS X,最高版本为2.1,其很多特性与完整版的Mac OS X相类似。该系统使用的内核基于BSD Unix,具有抢占式多任务处理(pre-emptive multitasking)的特性。其内存管理功能非常优秀,具有强烈的Unix风格,允许同时运行很多软件,并从实质上消除了一个程序崩溃导致其它程序崩溃的可能性。
iPhone的Mac OS X系统更多的优势来自于与iTunes服务的紧密紧密。iTunes原先仅是一个媒体播放软件,后来当iPod和iPhone发布后,iTunes逐渐演变为苹果在Mac和Windows系统上的一个无穷无尽的媒体源。人们可以通过iTunes登录到苹果的在线商店,购买各种音乐、视频或程序。这也成为苹果的一个新的盈利增长点。
虽然iPhone和iPhone 3G的Mac OS X系统已被大大精简,但在苹果计算机的Mac OS X系统中广为人们熟知的Dock和Aqua等关键元素仍然存在。更重要的是,人们可以在安装特定程序后进入Unix命令行进行各种操作,并对系统底层进行控制。此时iPhone已不再是一台手机,它更像是台超便携的苹果电脑,能够处理很多普通人所意想不到的事情。
不久以前,苹果为iPhone和iPod Touch开放了App Store应用程序商店。手机用户可通过信用卡在商店中购买自己喜欢的程序,而开发者也能通过App Store发布自己编写的程序,其收益与苹果七三分成。苹果的这个创新构思马上得到了人们的响应,短短几个月的时间App Store中的程序便达到了惊人的数量。
前景光明的Android平台
Android
文章最后要提到的当然是本专题的主角——Google Android平台。Android 是一个真正意义上的开放性移动设备平台。它包括操作系统、用户界面和应用程序等移动电话工作所需的全部组件,而且不存在任何以往阻碍移动产业创新的专有权障碍。
说到Android,便不能不提OHA(Open Handset Alliance)开放手机联盟。去年,Google与包括中国移动、英特尔、摩托罗拉、高通在内的33家业内巨头成立了该组织,这个联盟将共同推动Google手机平台Android的发展。Android作为Google企业战略的重要组成部分,将进一步推进“随时随地为每个人提供信息”这一企业目标的实现。
跟iPhone相比,Android平台同样也拥有自己的在线应用程序商店,名为Android Market。这个在线商店仅需进行简单的注册后便可以自由上传程序。虽然这可能导致一些安全问题,但总的来说这种开放式的平台非常有利于第三方软件的发展。而Google在对这些软件进行幕后审查的同时,也采取了多项措施,最大限度的保证了软件开发者的利益。
Android与前面三种系统相比最大的特点在于其开放性。这里所指的开放性包括两个方面,其一是Android以开源Linux系统为基础,对于开源爱好者而言,他们会觉得Android平台更能满足自己的使用需求。其二是Android对第三方软件的开放程度。Google不会对Android系统的第三方应用程序像苹果那样严格把关,而仅是在用户自行发布之后进行审查。这样一来必将极大的促进该系统第三方软件的发展。
而就基于Android的第一款手机T-Mobile G1来说,其最不能令人忍受的缺陷恐怕就是没有3.5mm耳机插孔了。另外,由于T-Mobile背后使下的“阴招”,用户在用完1GB流量后带宽便会自动下降为50Kbps,这将大大影响人们的购买欲望。而且,Android系统目前还没有桌面同步软件,也不支持Exchange同步。虽然Google的很多在线服务都可以满足人们的需要,但总有上不了网的时候。况且,很多信息保存在计算机中要安全得多。
四款主流或将要成为主流的智能手机操作平台到这里就介绍完了。俗话说的好,尺有所短,寸有所长,每个平台都有其各自的优点和不足。大家在选择智能手机的时候,需要关注的重点是各种平台的侧重点,这样在今后的使用中才会得心应手。至于该如何选择,相信大家心中都已经有数了吧。
Tags: andriod, Mac OS, mobile, Symbian, 平台, 手机
转载自http://android.hk.cn
现在有很多网友不停询问t-mobile G1 这款Android手机有关在国内购买使用的问题,GPhone-cn将一一作答。
1 G1能破解么?
答:可以破解,因为是开源操作,因此软破的几率比iPhone高很多。
2 G1操作系统界面可以汉化么?
答:可以,但是要稍等一段时间。
3 G1有什么配件?
答:目前看来有旅行冲,电池一块,耳机线孔,皮套一个,USB线一条
4 G1支持国内TD 3G网络么?
答:当然不支持。
5 G1有视频通话功能么?
答:没有。
6 G1在国内网络能用么?
答:能用,支持GSM网络。
7 G1在国内售价预计是多少呢?
答:目前看来是3090-4999元这个区间里。
8 国内G1大概多久能到货呢?
答:至少在10.25日以后。
9 G1有网络锁么?
答:签约机器有90天网络锁,90天后自动解除,零售机器没有网络锁。
10 G1有储存卡么?
答:原配没有,支持最高16GB的TF储存卡
LRC概述
LRC 歌词是一种包含着“[*:*]”形式的“标签(tag)”的、基于纯文本的歌词专用格式。最早由郭祥祥先生(Djohan)提出并在其程序中得到应用。这种歌词文件既可以用来实现卡拉OK功能(需要专门程序),又能以普通的文字处理软件查看、编辑。当然,实际操作时通常是用专门的LRC歌词编辑软件进行高效编辑的。以下具体介绍LRC格式中的“标签”。
时间标签(Time-tag)
形式为”[mm:ss]“或”[mm:ss.fff]“(分钟数:秒数)。数字须为非负整数, 比如”[12:34.5]“是有效的,而”[0x0C:-34.5]“无效。
它可以位于某行歌词中的任意位置。一行歌词可以包含多个时间标签(比如歌词中的迭句部分)。根据这些时间标签,用户端程序会按顺序依次高亮显示歌词,从而实现卡拉OK功能。另外,标签无须排序。
(如果我们的网站不错,请把“九九Lrc歌词网 =>www.99lrc.net”网址推荐给你的朋友使用,谢谢!)
标识标签(ID-tags)
其格式为”[标识名:值]“。大小写等价。以下是预定义的标签。
[ar:艺人名]
[ti:曲名]
[al:专辑名]
[by:编者(指编辑LRC歌词的人)]
[offset:时间补偿值] 其单位是毫秒,正值表示整体提前,负值相反。这是用于总体调整显示快慢的。
样例
[ar:unknown]
[ti:sample]
[al:none]
[by:me]
[01:02.355][00:00]This line should be sung twice
[00:05.7]And this one… once only.
开发标准(供程序员阅读参考)
以下列出了开发支持LRC格式的软件时应遵守的一些标准。
无论是否在行首,行内凡具有“[*:*]”形式的都应认为是标签。(注意:其中的冒号并非全角字符“:”)
“常常有人问我,联发科在过去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手机设计厂商。
文/《南方都市报》
以400RMB从中关村某JS那入手一部铁三角AD300, 属于Hifi耳机中入门级别的。
缺点很多,第一是太重,第二是声音有点混人声不太好(不过比之前PHILIPS的好多了),看下官方介绍吧。
ATH-AD300 空气动圈耳机
·三维翼支撑提供更大的舒适性并更加贴服
·强大的钕磁体确保声音具有强劲效果
·耳垫使用柔软顺滑的布织物
·舒适、完全适耳的设计可减轻紧固感
·40mm直径驱动器专为开放式耳机设计,提供强劲的声音
·高纯度OFC输入耳线 (3.0m)
·玻璃钢强化外壳
型号类别 开放空气动圈型
单元直径 Ø40 mm
驱动单元 钕磁铁
频率响应 20 ~ 25,000Hz
最大功率 300 mW
灵敏度 96 dB/mW
阻抗 32 ohms
重量 250 g
连接端 Ø6.3 / Ø3.5 mm 镀金立体声插头
导线 OFC/ 3.0 m (单侧导线)
再来张图,外型还凑合,能虎虎不识货的(包括我在内)~

Tags: 耳机