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:
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!
My i386-based kernel: https://github.com/bmelikant/missy-kernel Picking a name for my kernel was harder than picking my wife, so I just used her name until I decide!
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.
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?
My i386-based kernel: https://github.com/bmelikant/missy-kernel Picking a name for my kernel was harder than picking my wife, so I just used her name until I decide!
#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.
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.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
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:
#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
"If you don't fail at least 90 percent of the time, you're not aiming high enough."
- Alan Kay
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.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.