ARM Technical Support Knowledge Articles

What is C$$ddtorvec and are there any related issues?

Applies to: ARM Developer Suite (ADS)

Answer

C$$ddtorvec is used by the ADS 1.2 (and earlier) C++ compiler, to reserve zero-initialized space (ZI) for recording the destruction of static objects that are local to functions in C++ code.  For example:

struct T {
  T() {}
 ~T() {}
};

void f() {
  static T t;
}

The destructor is added to C$$ddtorvec at construction time, i.e., when the function is first executed.  Each occurrence of a function-local static object causes a call to  "__push_ddtor__FPFv_v", which adds the destructor to the C$$ddtorvec list.  The destructors are called when "__cpp_finalise_ddtors" is executed from within "__cpp_finalise", normally at the end of the program.

C$$ddtorvec must be placed in RAM, because it is written at run-time.  C$$ddtorvec must also be placed on a 4-byte aligned address in memory.

Be aware that the C++ initialisation, construction and destruction mechanisms have changed in later toolkit releases.  RVCT no longer uses C$$ddtorvec, C$$pi_ctorvec or C$$pi_dtorvec.  If you have user code that relies on them, then it is advisable to try and isolate such code to allow for easier transition in the future.


Known issue with C$$ddtorvec

There is a known issue with C$$ddtorvec in ADS 1.2 (and ADS 1.1, not ADS 1.0.1).  C$$ddtorvec must be placed on a 4-byte aligned address in memory, but the C$$ddtorvec section is not marked as alignment 4.  Issues can occur if the address of the C$$ddtorvec area does not have alignment 4 when linking.

If the example above is expanded to:

---test.cpp---
struct T {
  T() {}
 ~T() {}
};

void f() {
  static T t;
}

#pragma arm section zidata="A"
char y;

int main() {
  f();
  return y;
}

then C$$ddtorvec will be mis-aligned because the global variable 'y' is a one byte ZI object.
(The '#pragma arm section zidata="A"' is used in this example to provoke misalignment after any aligned .bss from the C library).

Executing:
armcpp -c test.cpp
armlink -map test.o
gives:
:
  Execution Region ER_ZI (Base: 0x000084ac, Size: 0x00000074, Max: 0xffffffff, ABSOLUTE)

  Base Addr    Size         Type   Attr  Idx  E Section Name        Object

  0x000084ac   0x0000000c   Zero   RW     3     .bss                test.o
  0x000084b8   0x00000060   Zero   RW    19     .bss                libspace.o(c_a__un.l)
  0x00008518   0x00000001   Zero   RW     4     A                   test.o
  0x00008519   0x00000004   Zero   RW     5     C$$ddtorvec         test.o
:

The address 0x00008519 is not align 4 which reveals the issue.  This code is likely to fail at run-time.


Work-arounds

1.  Adding an area with alignment 4 that will be placed by the linker just before C$$ddtorvec will work-around the issue.  To do this create a new assembler file ensure_ddtorvec_alignment.s:

    ; a zero-length, 4-byte aligned area,
    ; named so that it sorts just before C$$ddtorvec

    AREA |C$$ddtorvebzzzzz|, DATA, NOINIT, ALIGN=2
    EXPORT Ensure_ddtorvec_alignment
Ensure_ddtorvec_alignment
    END

To ensure the above assembler is included in the final image, use one of the following methods:

a) add the following to any one of your c/c++ source files:

// in example, add this to test.cpp
#if __ARMCC_VERSION < 200000
#pragma import (Ensure_ddtorvec_alignment)
#endif

or

b) add to the link line:

-keep Ensure_ddtorvec_alignment

Executing:
armcpp -c test.cpp
armasm ensure_ddtorvec_alignment.s
armlink -map test.o ensure_ddtorvec_alignment.o
gives:
:
  Execution Region ER_ZI (Base: 0x000084ac, Size: 0x00000074, Max: 0xffffffff, ABSOLUTE)

  Base Addr    Size         Type   Attr  Idx  E Section Name        Object

  0x000084ac   0x0000000c   Zero   RW     3     .bss                test.o
  0x000084b8   0x00000060   Zero   RW    20     .bss                libspace.o(c_a__un.l)
  0x00008518   0x00000001   Zero   RW     4     A                   test.o
  0x00008519   0x00000003   PAD
  0x0000851c   0x00000000   Zero   RW     8     C$$ddtorvebzzzzz    ensure_ddtorvec_alignment.o
  0x0000851c   0x00000004   Zero   RW     5     C$$ddtorvec         test.o
:

From the above memory map, it can be seen that the C$$ddtorvec is now aligned properly to a 4 byte address.


2.  Alternatively, another workaround is to place C$$ddtorvec at the start of a new RAM execution region in a scatterfile, e.g:

LOAD_REGION 0x...
{
:
    EXEC_REG_RAM 0x...
    {
        * (+RW)         ; your RW data
    }
    EXEC_REG_RAM1 0x... ; an aligned 4 address
    {
        * (C$$ddtorvec, +FIRST)
        * (+ZI)         ; your other ZI data
    }
:
}

or

LOAD_REGION 0x....
{
:
    EXEC_REG_RAM 0x...
    {
        * (+RW, +ZI)    ; your RW and/or ZI data
    }
    EXEC_REG_RAM1 +0    ; execution regions start on 4-byte
                        ; aligned addresses, even if they are +0
    {
        * (C$$ddtorvec)
    }
:
}

Note that C$$ddtorvec is ZI data, so to comply with the linker's default within-region sorting order (RO then RW then ZI), C$$ddtorvec cannot be placed +FIRST within an execution region containing RO or RW sections.

Article last edited on: 2008-09-09 15:47:54

Rate this article

[Bad]
|
|
[Good]
Disagree? Move your mouse over the bar and click

Did you find this article helpful? Yes No

How can we improve this article?

Link to this article
Copyright © 2011 ARM Limited. All rights reserved. External (Open), Non-Confidential