world leader in high performance signal processing
Trace: » structs

Working with C structures and GAS

While the Visual DSP assembler provides OFFSETOF() and SIZEOF() builtins for working with C structures in assembly language, the GNU assembler does not. With a little scripting magic, you can generate a file with automatically calculated offsets and sizes.

Method

The scripts work by creating a simple C file which includes the headers and structures you care about to produce a specially formatted assembly file. The assembly file is used to generate a header file with all the offset/sizeof of defines. You can use those defines in your own code.

You can either create the input C file by hand, or use one of the example scripts. The input C file generally has the form like so:

/* Header files needed to declare your structures */
#include "some header.h"
 
/* magic macros -- don't change these */
#undef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define SIZEOF(TYPE, MEMBER) (sizeof(((TYPE *)0)->MEMBER))
 
#define _DEFINE(sym, val) asm volatile("\n-> " #sym " %0 " #val "\n" : : "i" (val))
#define DEFINE(s, m) \
	_DEFINE(offsetof_##s##_##m, offsetof(s, m)); \
	_DEFINE(sizeof_##s##_##m, SIZEOF(s, m));
 
/* function with your structures and members */
foo() {
	DEFINE(struct mystruct, some_member);
	DEFINE(struct mystruct, another_member);
}

Now when you tell gcc to assemble this file, you'll be left with useful lines like so:

$ gcc -S asm-offsets.c -o - | grep '^->'
-> offsetof_struct mystruct_some_member 0 offsetof(struct mystruct, some_member)
-> sizeof_struct mystruct_some_member 4 SIZEOF(struct mystruct, another_member)
-> offsetof_struct mystruct_another_member 4 offsetof(struct mystruct, some_member)
-> sizeof_struct mystruct_another_member 4 SIZEOF(struct mystruct, another_member)

Format that file nicely and you end up with the defines you want:

#define offsetof_struct_mystruct_some_member 0
#define sizeof_struct_mystruct_some_member 4
#define offsetof_struct_mystruct_another_member 4
#define sizeof_struct_mystruct_another_member 4

Examples

dirent

Using the aforementioned method, here's how we would get the offsets/sizes of the standard struct dirent.

Use this as the input file named dirent-asm-offsets.c:

#include <dirent.h>
 
#undef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define SIZEOF(TYPE, MEMBER) (sizeof(((TYPE *)0)->MEMBER))
 
#define _DEFINE(sym, val) asm("\n-> " #sym " %0 " #val "\n" : : "i" (val))
#define DEFINE(s, m) \
	_DEFINE(offsetof_##s##_##m, offsetof(s, m)); \
	_DEFINE(sizeof_##s##_##m, SIZEOF(s, m));
 
main() {
	typedef struct dirent dirent;
	DEFINE(dirent, d_ino);
	DEFINE(dirent, d_off);
	DEFINE(dirent, d_reclen);
	DEFINE(dirent, d_name);
}

Then run it through gcc and add a little script magic:

$ bfin-uclinux-gcc -S dirent-asm-offsets.c -o - | awk '($1 == "->") { print "#define " $2 " " $3 }'
#define offsetof_dirent_d_ino 0
#define sizeof_dirent_d_ino 4
#define offsetof_dirent_d_off 4
#define sizeof_dirent_d_off 4
#define offsetof_dirent_d_reclen 8
#define sizeof_dirent_d_reclen 2
#define offsetof_dirent_d_name 11
#define sizeof_dirent_d_name 256

You can store this output in a header file and then use that in your assembly files.