The Symbian OS architecture does not allow DLLs to have a data segment (static data, either initialized or uninitialized). There are problems with deciding what such a data segment would mean:
Do all users of the DLL share it?
Should it be copied for each process that attaches to the DLL?
In addition, there are significant run-time overheads in implementing any of the possible answers.
However, because the WINS/WINSCW
emulator uses
the underlying Windows DLL mechanisms, it can provide per-process DLL data
using "copy-on-write" semantics. This is why the problem goes undetected until
the code is built for an actual Symbian OS device.
Consider this section of C++ code, added to a file QSORT.CPP,
which
is part of ESTLIB.DLL
// variables struct div_t uninitialised1; // in .DATA static struct div_t uninitialised2; // in .BSS struct div_t initialised1 = {1,1};// in .DATA static struct div_t initialised2 = {2,2};// in .DATA // constants const struct div_t const1 = {3,3}; const static struct div_t const2 = {4,4}; const TPoint none(-1,-1); static const TText* plpPduName[12] = { _S("Invalid"), _S("DataFlowOff"), _S("DataFlowOn"), _S("ConnectRequest"), _S("ConnectResponse"), _S("ChannelClose"), _S("Info"), _S("ChannelDisconnect"), _S("End"), _S("Delta"), _S("EndOfWrite"), _S("PartialWrite") };
When this code is built, the messages from PETRAN look something like:
PETRAN - PE file preprocessor V01.00 (Build 170) WARNING: Dll 'ESTLIB[10003B0B].DLL' has initialised data. WARNING: Dll 'ESTLIB[100002C3].DLL' has uninitialised data.
The associated .map
file contains information that
helps to track down the source file involved.
Look in Symbian OS\release\arm4\urel\dllname.map
Search for .data
or .bss
In this example, we find:
.data 0x10017000 0x200 0x10017000 __data_start__=. *(.data) .data 0x10017000 0x40 ..\..\Symbian OS\BUILD\STDLIB\BMMP\ESTLIB\ARM4\UREL\ESTLIB.in(QSORT.o) 0x10017000 initialised1 *(.data2) *(SORT(.data$*)) 0x10017040 __data_end__=. *(.data_cygwin_nocopy) .bss 0x10018000 0x18 0x10018000 __bss_start__=. *(.bss) .bss 0x10018000 0x18 ..\..\Symbian OS\BUILD\STDLIB\BMMP\ESTLIB\ARM4\UREL\ESTLIB.in(QSORT.o) 0x10018008 uninitialised1 *(COMMON) 0x10018018 __bss_end__=.
So the DLL has 0 x 18 bytes of uninitialized data (.bss
)
and 0 x 40 bytes of initialized data (.data
), all of
which comes from qsort.o
The variables initialised1
and uninitialised1
both
have global scope, so the .map
file lists them by name
(and puts them both in the initialized data). The static variables do not
get named in the .map
file.
Removing the first four lines of code shown above leaves just variables
that are declared as const
, but only reduces .bss
to 0x08
bytes,
and .data
to 0x30
bytes. There are
two problems remaining:
Declaring
C++ objects as const
does not help if they have a constructor.
The 8 bytes of uninitialized data are allocated to hold the TPoint
object,
but it will not become const
until after the constructor
has completed.
The declaration const
TText*
says that the TText
values may not
be altered, but it does not make the pointer a constant as well. The 48 bytes
of initialized data are the 12 pointers in the plpPduName
array.
To make the pointers constant as well as the values they point to, the declaration
needs an additional const
after the TText*
static const TText* const plpPduName[12] = { _S("Invalid"), _S("DataFlowOff"), _S("DataFlowOn"), _S("ConnectRequest"), _S("ConnectResponse"), _S("ChannelClose"), _S("Info"), _S("ChannelDisconnect"), _S("End"), _S("Delta"), _S("EndOfWrite"), _S("PartialWrite") };
Removing the TPoint
global variable and adding
the extra const
to the plpPduName
array
finally removes the last of the offending .bss
and .data