With only two caveats, really:
64-bit integers usually have alignment 8 on 64-bit architectures, but alignment 4 on 32-bit architectures. There, they behave like a struct of two 32-bit integers.
just a clear proof it's tricky. because you are wrong here. ironically, just a few days ago, I stumbled upon this question, on the example of one UEFI structure and was wondering - really, would a 64 bit field in a structure require 8-byte alignment on a 32 bit architecture? after all, the native word is 32 bit and that field would be accessed as 2 32 bit words. the structure in question:
Code: Select all
typedef struct _EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE{
UINT32 MaxMode;
UINT32 Mode;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
UINTN SizeOfInfo;
EFI_PHYSICAL_ADDRESS FrameBufferBase;
UINTN FrameBufferSize;
}EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE, *PEFI_GRAPHICS_OUTPUT_PROTOCOL_MODE;
this is why I said it's tricky. this struct is properly layed out for 64 bit arch and at the first glance, looks such on 32 bit. but, EFI_PHYSICAL_ADDRESS type is always 64 bit and despite it still resides 8-byte aligned if the whole structure is put 8-byte aligned, it won't be if it's an array of these structures.
because UINTN behind it resolves into UINT32 on 32 bits, and, as a result, the second element of the array gets its FramebufferBase resided only 4-byte aligned, even if the whole array has been put 8-byte aligned. Now yet imagine nested structures, what if struct A has only 32 bit words, but also has structure B, holding a 64 bit word. the structure A needs thus be 8-byte multiple and aligned, but looking at it, one may easily overlook this. this all is not a concern for a C coder, since compilers take care of this burden, but our OP wants be all assembly. hehe.
back to the above structure. I went and checked it by compiling a simple program, since I am not a guru of the C standard subtleties. guess what? the struture got its 4-byte trailing padding. its size is 32 byte instead of 28. then I added the padding manually and got the same size and field offsets.
Yes it's true. I understand the purpose of alignement, but i have problem how alignement works. And where do you have found into UEFI documentation data need to be aligned ? I don't remember i have read that.
In the UEFI data structures, there is a lot of places, where dudes, devising them, introduced misaligned layout, see the example above. this especially important for you, - one, that wants to program in assembly, since you need to calculate offsets to the fields manually. unlike C programmers. Got it? if the structure were layed out without the need for the compiler to add padding, it would be easier - you would look at it and straight calculate offsets adding sizes of the previous elements. now, you need to thouroughly analyze and see where the compiler has put padding and take that into account. let me show you one the most f&cked up structures in the UEFI regarding this, yet it's a very used one by OS loaders:
Code: Select all
struct _EFI_LOADED_IMAGE_PROTOCOL{
UINT32 Revision;
EFI_HANDLE ParentHandle;
EFI_SYSTEM_TABLE *SystemTable;
/* Source location of the image */
EFI_HANDLE DeviceHandle;
EFI_DEVICE_PATH_PROTOCOL *FilePath;
VOID *Reserved;
/* Image’s load options */
UINT32 LoadOptionsSize;
VOID *LoadOptions;
/* Location where image was loaded */
VOID *ImageBase;
UINT64 ImageSize;
EFI_MEMORY_TYPE ImageCodeType;
EFI_MEMORY_TYPE ImageDataType;
EFI_IMAGE_UNLOAD Unload;
};
this structure is so wrecked, that it's hard to make it worse. it needs two paddings for 32 bits and two paddings for 64 bits all in different places!
now imagine, writing in assembly, you would need to get the offsets right, by yourself! here, the structure with the paddings added explicitly:
Code: Select all
struct _EFI_LOADED_IMAGE_PROTOCOL{
UINT32 Revision;
#if TARGET_BITNESS == 0x40
UINT32 _Pad_64_0;
#endif
EFI_HANDLE ParentHandle;
EFI_SYSTEM_TABLE *SystemTable;
/* Source location of the image */
EFI_HANDLE DeviceHandle;
EFI_DEVICE_PATH_PROTOCOL *FilePath;
VOID *Reserved;
/* Image’s load options */
UINT32 LoadOptionsSize;
#if TARGET_BITNESS == 0x40
UINT32 _Pad_64_1;
#endif
VOID *LoadOptions;
/* Location where image was loaded */
VOID *ImageBase;
#if TARGET_BITNESS == 0x20
UINT32 _Pad_32_0;
#endif
UINT64 ImageSize;
EFI_MEMORY_TYPE ImageCodeType;
EFI_MEMORY_TYPE ImageDataType;
EFI_IMAGE_UNLOAD Unload;
#if TARGET_BITNESS == 0x20
UINT32 _Pad_32_1;
#endif
};
I mean, you need to take into account every possibility, - aligned inside, aligned being in the array, plus, EFI_MEMORY_TYPE is enumeration,
it's 4 byte always. EFI_IMAGE_UNLOAD is a function pointer, whereas staring at it, you may not guess this instantly.
PS. Funny, they were greedy to make Revision and LoadOptionSize UINTN, that would instantly eliminate both misalignment on 64 bits, but made ImageSize always 64 bit, what introduced 2 misalignments on 32 bits. did they think that one day a UEFI executable won't fit 4GB? well, maybe if made as the modern "web technology", then it's not that infeasible. after all, Chrome now eats up 100MB of RAM for every web page, even containing just a moderate amount of text and a few of tiny icons.