ECompXL
Epoc Compressed
eXecutable Loader
version 1.2.1
Table of Contents
Understanding ECompXL's license
What is it
ECompXL is a development tool that allows you to compress applications
(.app) and executables (.exe) for Symbian OS 7. Applications and
executables
built with ECompXL run as any other on a target device but, when
started,
will first decompress themselves on-the-fly before their actual
execution.
ECompXL uses the standard gzip
utility for compression and the zlib
library for decompression; a port of zlib is part of the standard
Symbian OS 7 SDK.
Once installed, ECompXL is integrated in the standard tool chain and
will transparently compress those applications and executables for
which you've configured compression support. The compressed
applications and executables generated by ECompXL behave exactly the
same as their uncompressed counterparts, with the one difference that
the first decompress themselves on-the-fly when
run on a target device. ECompXL supports all standard target builds,
including
ARMI, ARM4 and THUMB. As a bonus, ECompXL
allows your application (.app) to have
global modifiable data and even global C++ objects, something that
standard Symbian OS applications are not
allowed to.
What ECompXL can not do is compress existing Symbian OS applications
or executables; you have to use ECompXL as part of building your
application
or executable. For an explanation on why this is, read the section on how ECompXL works. ECompXL also does not
support static interface dlls (i.e., dlls with numerous exported
methods).
ECompXL is released under a MIT-style license, see the file copying for more information.
What's new in this version
Version 1.2.1:
- patch-pattern problem with
2.95.3 from "Symbian GCC Improvement Project": Updated
ForceCompilerToIncludeVariablesPatch() because the previous
implementation
got optimised away. Thanks to Grazvydas "notaz" Ignotas for pointing
this out.
- vma fixup bug: Fixed bug
resulting in incorrect relocations which can cause crashes when run on
a
device. Many thank to Thanks to Grazvydas "notaz" Ignotas for reporting
and providing a patch for the fix.
Version 1.2:
- dll name-mangling bug:
Fixed app + exe loader to allow for linking against dlls not using UIDs
(resulting in dll names in the import section without name mangling).
- E32Dll fix-up bug: For
dlls, the relocated address of E32Dll is used by the Symbian OS kernel
as a unique key for the loaded dll. However, when using ECompXL, the
kernel now knows the dll by the ECompXL's loader E32Dll address. This
causes methods in class Dll to fail, particularly Dll::FileName(). This
is solved by fixing-up all references to the .dll's E32Dll to ECompXL's
loader E32Dll address.
- Checksum bug: Updated
win32 tools to patch the code section in loader and recalculate the
checksum over the code section. Without this fix only 1 instance of the
loader code can be running at any given point in time. If two apps a1
and a2 use ECompXL than either a1 can run or a2 but not both. Because
of the interoperability issuses, developers using
ECompXL are strongly advised to update their apps to ECompXL 1.2.
Version 1.1:
- Search for dlls if they cannot be loaded in \system\libs
on all drives and the directory from which the app/exe is run.
- Changed license from GPL to a MIT-style license.
Version 1.0:
Initial version
Installation
Installing ECompXL requires the following three steps:
- Unzip ECompXLbin.zip
(preserving the directory structure) in the top
level directory of your Symbian OS development environment. For
example, on my
machine that directory is q:\,
so Symbian OS' standard include directory is q:\epoc32\include
and, after unzipping, the binaries for ECompXL are in q:\ECompXL\bin.
- Add the ECompXL-bin directory to your PATH. On my machine that would
be: q:\ECompXL\bin.
- Rename the Symbian tool chain component epoc32\tools\petran.exe to petran_symbian.exe. Don't
rename it to anything else than petran_symbian.exe,
ECompXL still uses Symbian's petran.exe
and relies on this name.
After installation, ECompXL is part of the standard Symbian OS tool
chain; you never have to invoke any of the ECompXL executables
directly.
Now read the section on building compressed
applications and executables to enable compression for your
components.
Note that the default behaviour of ECompXL is to not compress
applications
or executables. If you only have installed ECompXL, all the components
that
you built (exes, apps, dlls etc.) result in the exact same binary as if
ECompXL
had never been installed.
Verifying the installation
After installing ECompXL, you can do the following to verify all works
ok: open a DOS box , change directory to say the root directory of your
development
environment (q:\ on my
machine) and run petran.exe.
If things work correctly
you should see this:
ECompXL:
EPOC Compressed Executable Loader, version xxx
Copyright (c) 2002, Peter van
Sebille, www.yipton.net
PETRAN - PE file preprocessor V01.00 (Build xxx)
Copyright (c) 1996-2001 Symbian Ltd.
Syntax: petran_symbian.exe [options] pefile output file
petran_symbian.exe
[options] e32imagefile
option: [-v] [[-no]call[entrypoint]] [-priority <priority>]
[-stack <size>]
[-heap <min> <max>] [-uid<n> <uid>]
[-allowdlldata]
[-datalinkaddress <base>] [-fixed] [-moving]
[-align-const-section] [-const-section-address-mask <mask>]
Comments:
- If you don't see the ECompXL banner in this output then either
the
ECompXL-bin directory is not in your PATH or you have not renamed
Symbian's petran.exe in epoc32\tools.
- If you don't see the standard Symbian petran banner then you have
renamed
Symbian's petran.exe but
you have not correctly renamed it to petran_symbian.exe.
Building compressed applications and
executables
For each .exe or .app that you want ECompXL to compress, you have to
add the following statement to your component's .mmp file:
EPOCSTACKSIZE
0x80000000
If your component already had an EPOCSTACKSIZE
statement then add 0x80000000
to that value. For example:
EPOCSTACKSIZE
0x10000
EPOCSTACKSIZE 0x80010000
Now rebuild your component as you normally would. The resulting .exe or
.app
is in the exact same location you would normally find it but should now
be
reduced approximately 50% in size.
Comments:
- Note that ECompXL never actually sets the stack size for your
component
to 0x80000000. This is
just used as the trigger for ECompXL to enable compression
for this component.
- If you set the EPOCSTACKSIZE
to 0x80000000, ECompXL
sets the stack
size to what ever the default is (as if you hadn't specified this
statement
in first place). If you had set if to (0x80000000 + X) then ECompXL
sets it to X.
Support for
global data and global C++ objects in applications
Symbian OS executables (.exes) already have full support for global
modifiable data
and global C++ objects, and ECompXL allows you to have them in your
applications
(.apps) as well. If you have built your application as described in the
previous
section, support for global modifiable data in your application comes
for free. If you want support for global C++ objects as well, then you
have
to perform one additional step to ensure that constructors for such
objects
are called on start-up and destructors are called when your application
exits. The simplest
way is to do what ECompXL's test app (ECompXL\test\app\hello.cpp in
the source distribution) does:
- In your application's .mmp file add an USERINCLUDE statement to the ECompXL\inc directory.
- In the source file that defines your CApaApplication-derived class,
add:
#include "ECompXL.h"
- In the class definition for your your CApaApplication-derived class,
add an object of type TECompXL.
For example, hello.cpp
defines it as:
class CHelloApplication : public CEikApplication
{
private: // from CApaApplication
CApaDocument* CreateDocumentL();
TUid AppDllUid() const;
TECompXL
iECompXL; // support for global
C++ objects
};
Constructors for your application's global C++ objects are called from
the constructor of the TECompXL object
and their destructors are called from this object's destructor. Note
that this behaviour only applies for target
builds; the behaviour in the emulator relies on the host OS to
call global C++
objects' constructors when the app dll gets loaded and to call their
destructors when it gets unloaded.
Comments:
- Be careful what methods your global C++ objects' constructors
call.
Essentially these constructors are called as part of the application's
single exported
method:
EXPORT_C
CApaApplication* NewApplication();
where you create your CApaApplication-derived
application object. At that point some of the Application Framework's
objects already exists
(such as the EikonEnv object) but are not yet fully set-up.
- Once you've taken the route to include global modifiable data
and/or
global C++ objects in your application (.app) you've passed the point
of no return.
From that moment onwards your application can only be built using
ECompXL;
building it using the standard Symbian OS tool chain will fail
with
errors that can only be resolved by removing all global modifiable data.
- If you implement a Symbian
OS application (.app) from scratch I would never
recommend to just add global modifiable data or global C++ objects in
this
application and thus relying on ECompXL to build and run it. ECompXL
currently only works for Symbian OS 7 and may not work in future
versions
of Symbian OS. I'd only recommend this option if you are porting legacy
source
code to Symbian OS and the cost of removing global modifiable data
outweighs the
(potential) downside of future incompatibility.
Verifying that
ECompXL has compressed your .app or .exe
When building your component, you should see the ECompXL banner fly by
with
a comment that it has successfully created your compressed .exe or .app.
For example, the source distribution for ECompXL comes with a test
executable
and application project. You can build the test executable from the
command
line like this:
cd
\ECompXL\test\exe
makmake hello armi
make -f hello.armi
At the end of the output you see something like this:
ECompXL: EPOC
Compressed Executable Loader, version xxx
Copyright
(c) 2002, Peter van Sebille, www.yipton.net
Running PE2ECompXL.exe to create HELLO.bin.gz
Running EPOC Petran on loader image ECompXL.exe
PETRAN - PE file preprocessor
V01.00 (Build xxx)
Copyright (c) 1996-2001 Symbian
Ltd.
ECompXL:
glueing HELLO.bin.gz to loader image ECompXL.exe
Successfully
created compressed executable HELLO.EXE (compressed 50%)
Performance
I've successfully used ECompXL in two projects.
Below is a summary of some benchmarks I've performed on a fairly recent
SonyEricsson
P800 prototype. Ratios in green
are better, red are
worse.
Start time is the difference measured in the parent process just before
starting
the executable under test and the first statement in the the executable
under
test (using RDebug::Print()
with the value from User::TickCount()).
Each run was performed 3 times and their average is listed in the
table; the variance between each 3 runs was less than 3%.
|
File
size (KB)
|
Start
time in seconds
(Memory Stick - drive D:)
|
Start
time in seconds
(Internal flash - drive C:)
|
EMame uncompressed
|
3989
|
6.45
|
1.13
|
EMame ECompXL-compressed
|
1047
|
3.50
|
2.02
|
Ratio
|
74%
|
46%
|
179%
|
|
File
size (KB)
|
Start
time in seconds
(Memory Stick - Drive D:)
|
Start
time in seconds
(Internal flash - Drive C:)
|
EDoom uncompressed
|
693
|
1.23
|
0.27
|
EDoom ECompXL-compressed
|
319
|
1.33
|
0.83
|
Ratio
|
54%
|
109%
|
307%
|
How ECompXL works
Symbian
OS tool chain
In order to understand how ECompXL works, you first need to know how
the
standard Symbian OS tool chain for target builds works. In a nutshell
(skipping
details not relevant for the discussion), it goes like this:
- The GNU compiler (gcc.exe)
compiles your source files into object (.o) files.
- The GNU linker (ld.exe)
links the object files into an intermediate executable file. The format
of
this executable file is called PE-COFF which is short for Portable Executable - Common Object File
Format.
COFF is a file format originating from certain UN*X platforms and Microsoft
has derived its WIN32 executable file format PE-COFF from it.
- The Symbian OS tool petran.exe
transforms the executable file generated by the GNU linker into an E32
executable
file and this is the resulting .exe or .app file you can run on a
target
device.
The bad news is that Symbian's E32 executable file format is
proprietary
and not described in any public Symbian OS SDK. The good news is that
Microsoft's
PE-COFF file format is well documented and all source
code for the standard GNU tools (gcc, ld etc) are freely available, see
references below.
ECompXL
tool chain
Rather than using the E32 executable file (whose file format is
proprietary), ECompXL uses the intermediate PE-COFF executable file
generated by the GNU
linker as the basis for generating a compressed executable. In order to
decompress
this executable at run time, the decompression code needs to be in a
normal
E32 executable file that can be run as per normal on the target device.
The
ECompXL solution is to "glue" a compressed ECompXL executable file
(derived
from the PE-COFF executable file) to a standard E32 executable file
containing the ECompXL loader code (which will load and
decompress the actual executable).
Building compressed executables and applications using ECompXL goes
like this:
- The build process works as normal up to the point where petran.exe is called. During
installation, Symbian's petran.exe
was renamed to petran_symbian.exe,
so rather than the original pertran.exe,
ECompXL's petran.exe is
called.
- ECompXL's petran.exe
examines the -stack
parameter to see if the most significant bit in this 32 bit value is
set. If not, then it simply runs petran_symbian.exe
with the parameters that were passed to petran.exe and the resulting
executable file (.app or .exe) is the same as if ECompXL had not been
installed. If this bit is set, ECompXLTran.exe
is run.
- ECompXLTran.exe starts by running PE2ECompXL.exe to generate a
compressed ECompXL executable file.
- PE2ECompXL.exe
reads
the intermediate PE-COFF executable file, extracts various file headers
and
sections, and creates an ECompXL executable file consisting of:
- A single header describing all the relevant parameters for
this executable
(the virtual address this executable was linked for, the virtual
addresses
of the code, data, bss, import and relocation sections and their sizes,
and
the virtual address of the executable's entry point), immediately
followed
by;
- the code section, immediately followed by;
- the data section, immediately followed by;
- the import section, immediately followed by;
- the relocation section.
- PE2ECompXL.exe
uses gzip to compress the ECompXL executable file generated in the
previous step and then exits.
- ECompXLTran.exe
continues and copies the ECompXL loader image ( ECompXL\bin\ECompXL.exe or ECompXL\bin\ECompXL.app for
respectively .exes and .apps) to the target directory, renames it to
the target executable file name and runs petran_symbian.exe on it to
ensure that parameters like UIDs, stack sizes etc are set
according to what was specified in the mmp file. ECompXL's petran.exe
has passed all its parameters to ECompXLTran.exe
and the exact same parameters are passed to petran_symbian.exe. Before
doing so, the
most significant bit in the -stack
parameter is removed; if the stack
size is 0 the -stack
parameter is removed all together to let Symbian's petran.exe
choose the appropriate default size. Since the ECompXL
loader is a normal E32 executable file, Symbian's petran.exe works as expected.
- ECompXLTran.exe
"glues" the compressed ECompXL executable file to the ECompXL loader
executable file.
Glueing is done by literally appending the contents of the compressed
ECompXL executable file to the ECompXL loader executable file.
- Finally, ECompXLTran.exe
appends the file offset of where the compressed ECompXL executable file
got appended to the executable file.
Running a compressed
executable (.exe) on a target device
When you start an ECompXL compressed .exe on target, the following
happens:
- The Symbian OS System Loader:
- Reads the E32 image header from the executable file.
- Loads
parts of the E32 executable file containing code, data, import, export
and
relocation sections based on information in the E32 header. Note that
the
Symbian OS loader doesn't just load the entire file. It only loads
those
parts as specified in the E32 header, which corresponds to the loader
executable
(roughly 10KB in size); the glued compressed executable gets completely
ignored.
- Dynamically links the E32 image in memory against dlls
specified in the import section, loading dlls if needed.
- Relocates the E32 image according to where it has been loaded
into
memory by applying the so called "fix-ups" from the relocation section.
- Starts execution of the executable at its entry point, which is
normally _E32Main(). _E32Main()
contains Symbian OS specific start-up code such as calling constructors
for
global C++ objects and gets automatically included into an E32
executable
file as part of the Symbian OS tool chain. _E32Main() then calls the
executable's actual entry point E32Main().
- After the previous step, the System Loader has finished its job
and as far as it is concerned the executable is up and running. E32Main() of ECompXL's loader
is now executing and does the following:
- Opens its own executable file.
- Seeks to the end of this file and retrieves the last 32-bit
integer
value; this is the file offset at which the compressed ECompXL
executable
file is stored.
- Seeks to that offset and reads the GZIP header.
- Reads the ECompXL file header and uses the ZLIB library to decompress it.
- Creates a chunk (RChunk)
for code and a chunk for data of sizes determined by information in the
ECompXL file header.
- Loads the compressed code section from file, decompresses it
and stores it in the code chunk.
- Loads the compressed data and import section from file,
decompresses them and stores them in the data chunk.
- Loads the compressed relocation section from file, decompresses
it and stores it in the heap.
- Dynamically links the executable image against libraries as
specified in the import section.
- Relocates the executable image according to where it has been
loaded into memory
by applying the so called "fix-ups" from the relocation section.
- Cleans up unnecessary data structures (such as the relocation
section
in the heap) and calls the executable's entry point, which will
normally be _E32Main(). _E32Main() performs the normal
start-up code for this executable and then calls E32Main().
Almost the exact same happens for compressed ECompXL applications with
the following differences:
- The ECompXL loader code is an E32 .app rather than an E32 .exe.
- The loader code therefor starts from its first exported method (NewApplication()) which gets
called by the Application Framework when the latter loads the
application dll as part of application start-up.
- The loader code, after decompressing, dynamically linking and
relocating
the glued compressed application, calls the first exported method in
that application
and returns that value from its NewApplication()
entry point.
- There is no Symbian OS start-up code in applications and therefor
there
is no automatic support for global C++ objects (calling their
constructors
and destructors). Applications created with ECompXL should therefor
ensure
they call constructors and destructors for global C++ objects
themselves.
Read the section "Support
for global data and global C++ objects in applications" on how to
do that.
References:
Portable
Executable Common Object File Format
Source
code for GNU tool used by Symbian OS
Understanding
ECompXL's license
Starting from version 1.1, ECompXL is released under an MIT-style license.