Page 1 of 1

Question about __attribute__((packed))

Posted: Sat Jan 30, 2016 3:35 pm
by psychobeagle12
Hey guys, I have a question. I am writing a FAT16 filesystem for my OS right now, and the structure I created to hold the filesystem information obviously did not work correctly without __attribute__((packed)). So I started reading into what this statement actually does since I realized I really didn't understand it well. As I was looking, I found lots of information that said that __attribute__((packed)) actually causes code to slow down due to misaligned accesses. So the question is, how do I know which structs I can pack, and which I can't? Also, does anyone have a suggestion how I may implement the filesystem driver without the packing attribute? I am basically using a FAT16-formatted ramdisk loaded by GRUB for loading the drivers necessary to start the system, and so I did something like this:

Code: Select all

static uint8_t *ramdisk_data;
struct fat16_bpb bios_blk;

initrd_initialize (void *ramfs) {

	ramdisk_data = (uint8_t *) ramfs;
	struct fat16_bpb *bios_blk_ptr = (&bios_blk);

	memcpy ((void *)bios_blk_ptr, (void *) ramdisk_data, sizeof (struct fat16_bpb));
}
I guess if I was going to ask OS-specific questions I should have posted in the OS Development thread... if that causes a problem, can this be moved? This is just a genuine curiosity for me. Thanks!

Re: Question about __attribute__((packed))

Posted: Sat Jan 30, 2016 5:45 pm
by shmx
psychobeagle12 wrote:__attribute__((packed))
better use pragma pack
psychobeagle12 wrote:So the question is, how do I know which structs I can pack, and which I can't?
I did not understand the question.
psychobeagle12 wrote:Also, does anyone have a suggestion how I may implement the filesystem driver without the packing attribute?
Manually calculate offset and use typecast.

Re: Question about __attribute__((packed))

Posted: Sat Jan 30, 2016 6:06 pm
by b.zaar
psychobeagle12 wrote: how do I know which structs I can pack, and which I can't?
You always need to pack a structure when the bytes are written in a set size and order. This almost always applies to file systems because the structure in memory is exactly the same as the structure on the disk. It will also apply to any structures you use with BIOS or VBE functions.

You don't need to pack a structure if it's optimised for speed and byte alignment, this could be for a structure used by a page/memory allocator. You can use unpacked structures if you don't plan to save the structures to long term storage.

Re: Question about __attribute__((packed))

Posted: Sat Jan 30, 2016 6:18 pm
by psychobeagle12
how do I know which structs I can pack, and which I can't?
Sorry, this question should have read "Which structs I SHOULD pack and which I SHOULDN'T pack." I would suppose that, as I am developing OS code, that anything architecture-dependent is safe to be a packed struct. But... I have read that unaligned data access causes issues on SPARC machines. Not that I ever plan to develop for one, but if I wrote my fat16 driver with packed structs on such a machine, would I not cause myself headaches? That is mostly my question; when is it ok to use packed structs and when should I avoid them like the plague?

Re: Question about __attribute__((packed))

Posted: Sat Jan 30, 2016 6:24 pm
by FallenAvatar
shmx wrote:
psychobeagle12 wrote:__attribute__((packed))
better use pragma pack
#pragma pack is a MSVC specific preprocessor macro. One that GCC happens to support for compatibility, but for gcc you should use their specific macros. Please don't post unles you actually know/understand what you are saying.

- Monk

Re: Question about __attribute__((packed))

Posted: Sun Jan 31, 2016 9:01 am
by Combuster
psychobeagle12 wrote:when is it ok to use packed structs and when should I avoid them like the plague?
If you want to be platform independent, never use packing and never read directly into a structure in the first place. Instead do proper endian (and float format) conversion from an uint8_t array. This is the obviously also the purist's way.

CPU structures are platform-specific by their very name, so you have a legitimate excuse to use packing here. If you want to cheat like most people, you can use packing for I/O only if you know you're never going to run into platform-specifics or don't care about that. If neither is the case, packing is always the worse solution.

Re: Question about __attribute__((packed))

Posted: Sun Jan 31, 2016 12:10 pm
by shmx
tjmonk15 wrote:#pragma pack is a MSVC specific preprocessor macro.
__attribute__((packed)) is only supported by GCC. :)

Re: Question about __attribute__((packed))

Posted: Sun Jan 31, 2016 1:46 pm
by Roman
Who cares about MSVC? Meanwhile they couldn't even support modern C themselves and decided to use clang for it. If portability is wanted, it's possible to use something like this:

Code: Select all

#ifdef _MSC_VER
#define PACKED_STRUCT(n, c) __pragma(pack(push)) struct n {c} __pragma(pack(pop))
#elif defined(__GNUC__)
#define PACKED_STRUCT(n, c) struct n __attribute__((packed)) {c}
#else
#error "This compiler is not supported."
#endif

Re: Question about __attribute__((packed))

Posted: Sun Jan 31, 2016 3:40 pm
by onlyonemac
It's generally best to leave structures un-packed unless it is important that the fields do not have any padding in-between them. In this case, you're using a structure to represent a FAT filesystem node, so you don't want padding added to the structure because then won't match the layout of the data that has been read from disk.

Short answer: structures that are used internally by your operating system usually don't need packing because the exact layout of the fields doesn't matter; structures that are used to refer to formatted data obtained from or intended to be used by external entities (CPU page tables, filesystems, etc.) should be packed because the exact layout of the fields is important.