StandardCPack

From Axel Public Wiki
Jump to navigation Jump to search

Since LogicLab 6.0.0.x, a new allocation strategy for structures and function blocks called "standardCPack" that strictly follows the C specification is available.

It currently available for x86, x64, ARM, ARM64 architectures only.


To enable it:

  • first of all, "pack" setting must be chosen carefully to match your compiler and architecture (see below). In the following examples will be "8", replace with your setting if needed.
  • a new <processor> in the LLExtConfig.xml must be defined like this
<processor name="x86_pack8" dll="LLCGX86_32bits.dll" standardCPack="8"/>
  • set in the TGT/TGTX of your target the new processor
  • PLC runtime must be recompiled by #defining ALPLC_STANDARDCPACK = 8: this will tipically require a new target release with a different firmware/runtime, that will be incompatible with previous ones


C standard alignment

  • every compiler/architecture has a specific "pack" settting: for example is 8 on Windows x86 and Windows x64, 4 on Linux x86, 8 on Linux x64, 8 on ARM32 and ARM64
  • for VisualStudio and GCC (and maybe also others), #pragma pack(n) directive can be used to change the default setting on specific regions of code
  • every variable (simple or complex) has an "alignment" property, that will be computed by using the following rules
  • every simple variable is aligned to minimum between the pack setting, and the size of variable itself, adding padding/holes if needed, so:
    • with pack=1 every variable is byte-aligned (no padding)
    • with pack=4 every variable is aligned at most to 4 bytes: int16_t aligned to 2 bytes boundary, int32_t aligned to 4 bytes boundary, int64_t aligned to 4 bytes boundary
    • with pack=8 every variable is aligned to its size: int16_t aligned to 2 bytes boundary, int32_t aligned to 4 bytes boundary, int64_t aligned to 8 bytes boundary
  • structure members are internally aligned following the previous rule, by adding padding if needed
  • the structure itself is aligned to the maximum alignment of its members. This is needed to guarantee that all members are always aligned
  • the total size of a structure must be a multiple of its alignment (so the maximum alignment of its member for the previous rule), by adding padding at the end if needed. This is needed to guarantee that arrays of structures are contiguous in memory
  • with nested structures, the previous rules will be combined: the "child" structure will have its alignment property, that will be used to compute the alignment of the "parent" structure


There is obviously lot of online documentation about these topics that explan everything in detail:


Example 1

struct stru1
{
   int8_t a;
   int32_t b;
   int8_t c;
};
  • with pack=1, there will be no padding, so sizeof(stru1)=6 and alignof(stru1)=1
  • with pack=8, result will be sizeof(stru1)=12 and alignof(stru1)=4
struct stru1
{
   int8_t a;
   int8_t padding[3];
   int32_t b;
   int8_t c;
   int8_t padding[3];
};

Example 2

struct stru1
{
   int8_t a;
   int64_t b;
};
struct stru2
{
   int32_t c;
   stru1 d;
   int8_t e;
};
  • with pack=1, there will be no padding, so sizeof(stru1)=9 and alignof(stru1)=1, sizeof(stru2)=14 and alignof(stru2)=1
  • with pack=8, result will be sizeof(stru1)=16 and alignof(stru1)=8, sizeof(stru2)=32 and alignof(stru2)=8
struct stru1
{
   int8_t a;
   int8_t padding[7];
   int64_t b;
};
struct stru2
{
   int32_t c;
   int8_t padding[4];
   stru1 d;
   int8_t e;
   int8_t padding[7];
};