Hart Thomson
Hart Thomson

Reputation: 33

Struct packing for multi processor data communication

On our ASIC we have two processors, which means two different compilers that behave slightly differently. We pass structs full of data between the two for communication, this happens quite often per second so we don't have much time to burn here.

The problem is that both compilers treat padding differently. So when we go to copy data from one domain to the other, we get values that don't align correctly. Our initial solution was to put attribute((packed)) on everything inside the struct. While this seems to work most of the time, it is by no means portable. As we are moving the code to different platforms, I'm noticing that not all compilers understand attribute((packed)) and I'd like to keep our code portable.

Has anyone here dealt with this kind of issue? What would you recommend?

Thanks in advance!

Upvotes: 3

Views: 153

Answers (3)

Lundin
Lundin

Reputation: 213872

This is the reason why you shouldn't use structs for data protocols. It might seem like a harsh thing to say, but structs are unfortunately non-portable and therefore dangerous. You could consider doing something like this (pseudo code):

typedef struct
{
  uint32_t x;
  uint16_t y;
  ...
} my_struct_t;  // some custom struct

#define PROTOCOL_SIZE ( sizeof(uint32_t) + sizeof(uint16_t) + ... )


void pack (uint8_t raw_data[PROTOCOL_SIZE], 
           const my_struct_t* ms)
{
  uint16_t i=0;

  memcpy(&raw_data[i], ms->x, sizeof(ms->x));
  i += sizeof(ms->x);

  memcpy(&raw_data[i], ms->y, sizeof(ms->y));
  i += sizeof(ms->y);

  ...
}

And then make a similar unpack() function which copies raw data into the struct.

Advantages of this is: 100% portable. And if the protocol specifies a particular endianess, this function could also handle that conversion (which you would have to do anyhow.)

Disadvantages are one extra memory buffer and some extra data copying.

Upvotes: 0

DaveR
DaveR

Reputation: 9640

Fundamentally struct arrangement in C isn't portable, and so __attribute__((packed)) or similar is generally the typical way to impose a fixed layout on a struct.

The other option is to manually add pad fields in appropriate places and be aware of each platforms' alignment constraints to ensure that across your two platforms the two structures match - but this is essentially manual attribute((packed)).

Note that the pahole utility from dwarves (announcement, paper) is a great tool to check and view the alignment of structures, assuming your compiler emits ELF files.

Upvotes: 2

Arun
Arun

Reputation: 20383

I would manually pack such structures, so that there is no padding issue with any compiler, present or future.

It is tedious, but it is a portable future-proof solution, worth the effort.

Upvotes: 3

Related Questions