Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When calling a function in a DLL or .so why is passing structs reliable when compilers do their own struct layout with alignment and padding?

Tags:

c

struct

AFAIK in c-language structs get laid out, aligned and padded as the compiler sees fit. That is why you cannot rely on one c-program to use structs from another c-program. E.g. you cannot save a struct as a binary file that another c program will read and cast to that same struct. You may be able to use packed structs like that but that's not really good practice.
So I was surprised to learn that .so and DLL files have c functions that take complicated struct's (references thereof) as their parameters. At least my company's products do this. Is this reliable, is it good practice? Is there some new standard for struct layout with sizes, alignment and padding all being the same?

I know a 64-bit program cannot call a 32-bit library, but still I thought struct layout can vary amongst compilers of the same bits.

like image 539
Joe C Avatar asked Aug 03 '21 21:08

Joe C


People also ask

Why is structure padding needed?

The answer to that lies in how a CPU accesses memory. Typically a CPU has alignment constraints, e.g. a CPU will access one word at a time, or a CPU will require data to be 16byte aligned, etc. So to make sure that data is aligned according to the constraints of the CPU, padding is required.

Can we simply rearrange the members of the structure to reduce padding?

Rearranging members to reduce paddingYou can reduce the size of each widget by rearranging the members to reduce the number of padding bytes.


1 Answers

For a given processor type and a given operating system, there is usually a standard ABI (application binary interface) which specifies things such as:

  • The width and endianness of integer types.
  • The width and representation of floating-point types.
  • Alignment constraints, which dictate the presence of padding in structures.
  • How parameters are passed to functions (in registers and on the stack).

For example, on the x86_64 processor architecture (i.e. the processor architecture of 64-bit PC), there are two popular ABIs: the Microsoft x64 calling convention, used on Windows, and the System V amd64 ABI (PDF — the part you're asking about specifically is in §3.1 “Machine interface”), used everywhere else. 32-bit x86 historically had more fragmentation.

So generally, if you use different compilers for the same platform (processor and operating system) in their default mode, they'll produce the same layouts for structs, and they'll generate function calling code that's compatible with how functions compiled by other compilers read their arguments. Problems arise when you mix different platforms, for example writing a struct on an embedded device and trying to read it on a PC.

like image 87
Gilles 'SO- stop being evil' Avatar answered Oct 26 '22 06:10

Gilles 'SO- stop being evil'