zl程序教程

您现在的位置是:首页 >  系统

当前栏目

Windows 32、64位系统编译器各数据类型大小和字节对齐关系

Windows字节系统编译器 关系 大小 数据类型 64
2023-09-11 14:15:13 时间

何为32位64位?

32位64位其实就是32bit 64bit ,32位cpu单次处理指令4字节,64位8字节,因为1字节=1byte=8bit(32/8=4字节,64/8=8字节)

32位编译器:32位系统下指针占用4字节

64位编译器:64位系统下指针占用8字节

struct结构体成员中对齐关系:

字节对齐的细节和具体编译器实现相关,但一般而言,需满足以下四个准则:

1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;

2) 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;

3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。

4)结构体作为数据成员的对齐规则:在一个struct中包含另一个struct,内部struct应该以它的最大数据成员大小的整数倍开始存储

随便贴几个32/64相同结构体字节对齐填充示例:

{32位}  
_UNICODE_STRING = packed record
    Length : USHORT;
    MaximumLength : USHORT;
    Buffer : PWideChar;
  end;
  UNICODE_STRING = _UNICODE_STRING;
  PUNICODE_STRING =^_UNICODE_STRING;

{64位}
  _UNICODE_STRING64 = packed record
    Length : USHORT;   //USHORT=2字节
    MaximumLength : USHORT;
    Fill : DWORD;   //填充4字节对齐
    Buffer : ULONG64;//ULONG64; //PVOID64
  end;
  UNICODE_STRING64 = _UNICODE_STRING64;
  PUNICODE_STRING64 =^_UNICODE_STRING64;


{32位} 
  PLDR_DATA_TABLE_ENTRY = ^LDR_DATA_TABLE_ENTRY;
  LDR_DATA_TABLE_ENTRY = packed Record
    InLoadOrderModuleList:LIST_ENTRY;
    InMemoryOrderModuleList:LIST_ENTRY;
    InInitializationOrderModuleList:LIST_ENTRY;
    BaseAddress:Cardinal;
    EntryPoint:Cardinal;
    SizeOfImage:Cardinal;
    FullDllName:UNICODE_STRING;
    BaseDllName:UNICODE_STRING;
    Flags:Cardinal;
    LoadCount:Word;
    TlsIndex:Word;
    SectionHandle:Cardinal;
    CheckSum:Cardinal;
    TimeDateStamp:Cardinal;
  end;


{64位}
  PLDR_DATA_TABLE_ENTRY64= ^LDR_DATA_TABLE_ENTRY64;
  LDR_DATA_TABLE_ENTRY64 = packed record
    InLoadOrderModuleList:LIST_ENTRY64;//PVOID64;//LIST_ENTRY;
    InMemoryOrderModuleList:LIST_ENTRY64;//PVOID64;//LIST_ENTRY;
    InInitializationOrderModuleList:LIST_ENTRY64;//PVOID64;//LIST_ENTRY;
    BaseAddress:ULONG64;
    EntryPoint:ULONG64;
    SizeOfImage:ULONG64;//ULONG;  //8字节对齐 
    FullDllName:UNICODE_STRING64;
    BaseDllName:UNICODE_STRING64;
    Flags:ULONG;
    LoadCount:USHORT;
    TlsIndex:USHORT;
  end;

{32位}
  PPEB_LDR_DATA =^PEB_LDR_DATA;
  PEB_LDR_DATA = packed record
    Len:Cardinal;
    Initialized:Bool;
    SsHandle:PPointer;
    InLoadOrderModuleList:LIST_ENTRY;
    InMemoryOrderModuleList:LIST_ENTRY;
    InInitializationOrderModuleList:LIST_ENTRY;
  end;

{64位}
  PPEB_LDR_DATA64= ^PEB_LDR_DATA64;
  PEB_LDR_DATA64 = packed record
    Length:ULONG;    //4Byte
    Initialized:BOOLEAN;  //1Byte
    Reserved1: array [0..2] of Byte;  //3Byte   补3字节填充跟前面一起凑成8字节
    SsHandle:ULONG64;     //8Byte
    InLoadOrderModuleList:LIST_ENTRY64; // PVOID64
    InMemoryOrderModuleList:LIST_ENTRY64;
    InInitializationOrderModuleList:LIST_ENTRY64;
    EntryInProgress:ULONG64;
  end;

{32位}
  PPEB = ^PEB;
  PEB = packed record
    Reserved1: array[0..1] of Byte;
    BeingDebugged: ByteBool;
    Reserved2: Byte;
    Reserved3: array[0..1] of Pointer;
    Ldr: PPEB_LDR_DATA; //Pointer
    ProcessParameters: PRTL_USER_PROCESS_PARAMETERS;
    Reserved4: array[0..103] of Byte;
    Reserved5: array[0..51] of Pointer;
  end;

{64位}
  PPEB64 = ^PEB64;
  PEB64 = packed record
      InheritedAddressSpace : UCHAR;   //1 Byte
      ReadImageFileExecOptions : UCHAR;
      BeingDebugged: UCHAR;
      BitField: UCHAR;
      Reserved1:DWORD; //因为64位系统是8字节对齐,所以补4位,跟前面4个uchar一起凑成8字节 
      Mutant:ULONG64; //编译器问题,VC++不用补位,实测VS2017,VS2015中编译器貌似会自动填充对齐
      ImageBaseAddress: ULONG64;
      Ldr:PVOID64;  //PPEB_LDR_DATA64; //ULONG64;
      ProcessParameters:PVOID64;//PRTL_USER_PROCESS_PARAMETERS64; // ULONG64;
      SubSystemData: ULONG64;
      ProcessHeap: ULONG64;
      FastPebLock: ULONG64;
      AtlThunkSListPtr:ULONG64;
      IFEOKey: ULONG64;
      CrossProcessFlags: ULONG64;
      UserSharedInfoPtr: ULONG64;
      SystemReserved: ULONG;
      AtlThunkSListPtr32:ULONG;
      ApiSetMap: ULONG64;
  end;

Delphi中32位64位程序在64位系统下各数据类型占用字节统计如下:

具体字节对齐填充原理可以参考此连接:

32位源码编译64位程序时的字节对齐问题

原创文章,转载请注明出处!谢谢