DoneVII CET & CPPLITE

[转] Symbian OS 9 可执行文件格式

原译者:陈啸天(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

    全都在这了!!希望你能够喜欢这篇文章!

Leave a comment for: "[转] Symbian OS 9 可执行文件格式"

Tag Cloud