Martin Martin - 1 month ago 14
C++ Question

standard way to put static objects together

I want to put some objects with static linkage together, without any other data interleaved. The objects are defined in separate source files. The order doesn't matter, as long as they're contiguous (excepting minimal/standard padding).

In gcc I can achieve this with

__attribute__((section("mydata")))
, but
AFAIK
that's
GCC
specific and only many compilers support it (gcc, llvm and a few others, but I think not msvc), for many targets (elf yes, others I'm not sure, I doubt it).

Q1: is there a standard way to achieve this?

Q2: does
GCC
guarantee that the objects will be contiguous with padding? i.e. the objects can be enumerated by a linear scan with a constant stride.

Q3: is there a difference in behavior between
GCC
and other compilers that support this attribute?

Q4: which targets and major compilers wouldn't support this?

Answer

It sounds like you're trying to produce platform independent code (hence the need for a standard mechanism) and while you have access to the source, you only want to make limited changes to it. The solution you are proposing involves accessing datastructures defined in multiple translation units as though they were elments of a single array.

Q1. Neither the C standard nor the C++ standard contain the concept of linker sections, so, no, there is no truly platform independent way to specify output section names.

You would need to check for each compiler that you want to target. You have already found the incantation for GCC and Clang. Visual C++ has #pragma section and __declspec(allocate) which together can achieve the same thing.

Q2. GCC uses the platform's linker to build an executable. Assuming a GNU environment, then that linker will be the binutils ld or gold. With these linkers, each output section is contiguous, and alignment of the input sections within the output section can be specified or allowed to default. According to the documentation the default will work for you assuming all of your object files were compiled with the same version of GCC, using the same compiler options. Different compiler options may result in different default alignments.

Q3. Regarding differences in behavior on platforms: your use of the linker is fairly unusual. You ought to carefully test each platform you target. I'd suggest building a small binary that puts object files together in the way you want and (programatically) checks that the datastructures are accessible in the way you desire.

Q4. It looks like your approach will work for GCC/Clang/binutils on Linux and for Visual C++/LINK on Windows. It would take quite some effort to learn each platform's idosyncracies, but I think you could make your approach work on just about any post-1995 platform with a real keyboard. You may have difficulty on older machines and smaller embedded systems. You can probably get it going on Android. I'm not sure about iOS.

By way of general advice, accessing datastructures by assuming they are contiguous across translation unit boundaries is unusual. You are likely to run into strange problems and find it difficult to get help. Here are some alternate mechansims that might get you what you want, with less per-platform effort:

  1. Put the source files together before compilation and compile them as one unit. If it's not possible to do by hand, consider using the pre-processor or building a small Perl or Python script to do it for you at build time.

  2. At run-time, dynamically allocate a contiguous section of memory and copy the datastructures to it. If the datastructures are small, this won't use much extra memory. If the datastructures are large, the memory containing the original structures will be paged out and this won't use much extra memory.

  3. Use indirection: have your program access the datastructures through an array of pointers to the data.

Comments