C++: Fix calculation of alignment for some structs
This commit is contained in:
@@ -239,23 +239,50 @@ namespace Il2CppInspector.Cpp
|
|||||||
// Unions and bitfields can have more than one field at the same offset
|
// Unions and bitfields can have more than one field at the same offset
|
||||||
public SortedDictionary<int, List<CppField>> Fields { get; internal set; } = new SortedDictionary<int, List<CppField>>();
|
public SortedDictionary<int, List<CppField>> Fields { get; internal set; } = new SortedDictionary<int, List<CppField>>();
|
||||||
|
|
||||||
public CppComplexType(ComplexValueType complexValueType) : base("", 0) => ComplexValueType = complexValueType;
|
public CppComplexType(ComplexValueType complexValueType) : base("", 0) {
|
||||||
|
ComplexValueType = complexValueType;
|
||||||
|
|
||||||
|
// An empty class shall always have sizeof() >= 1
|
||||||
|
// This will get overwritten the first time a field is added
|
||||||
|
Size = 8;
|
||||||
|
}
|
||||||
|
|
||||||
// Add a field to the type. Returns the offset of the field in the type
|
// Add a field to the type. Returns the offset of the field in the type
|
||||||
public int AddField(CppField field, int alignmentBytes = 0) {
|
public int AddField(CppField field, int alignmentBytes = 0) {
|
||||||
// Unions and enums always have an offset of zero
|
// Unions and enums always have an offset of zero
|
||||||
field.Offset = ComplexValueType == ComplexValueType.Struct ? Size : 0;
|
// An empty struct has a Size (bits) of 8 so the first field must also be set to zero offset
|
||||||
|
field.Offset = ComplexValueType == ComplexValueType.Struct ? (Fields.Any()? Size : 0) : 0;
|
||||||
|
|
||||||
// If we just came out of a bitfield, move to the next byte if necessary
|
// If we just came out of a bitfield, move to the next byte if necessary
|
||||||
if (field.BitfieldSize == 0 && field.Offset % 8 != 0)
|
if (field.BitfieldSize == 0 && field.Offset % 8 != 0)
|
||||||
field.Offset = (field.Offset / 8) * 8 + 8;
|
field.Offset = (field.Offset / 8) * 8 + 8;
|
||||||
|
|
||||||
// A struct or union must be aligned on a word boundary for the architecture bit width
|
|
||||||
//if (field.Type is CppComplexType &&
|
|
||||||
|
|
||||||
// A 2, 4 or 8-byte value etc. must be aligned on an equivalent boundary
|
// A 2, 4 or 8-byte value etc. must be aligned on an equivalent boundary
|
||||||
if (!(field.Type is CppComplexType) && field.OffsetBytes % field.SizeBytes != 0)
|
// The same goes for the first entry in a struct, union or array
|
||||||
field.Offset += (field.SizeBytes - field.OffsetBytes % field.SizeBytes) * 8;
|
// This block searches depth-first for the first field or element in any child types to find the required alignment boundary
|
||||||
|
// https://en.wikipedia.org/wiki/Data_structure_alignment
|
||||||
|
if (field.BitfieldSize == 0) {
|
||||||
|
var firstSimpleType = field.Type;
|
||||||
|
var foundType = false;
|
||||||
|
while (!foundType) {
|
||||||
|
var simpleType = firstSimpleType switch {
|
||||||
|
CppAlias alias => alias.ElementType,
|
||||||
|
CppComplexType { ComplexValueType: ComplexValueType.Struct } complex => complex.Fields.FirstOrDefault().Value?.First().Type,
|
||||||
|
CppArrayType array => array.ElementType,
|
||||||
|
_ => firstSimpleType
|
||||||
|
};
|
||||||
|
if (simpleType == firstSimpleType)
|
||||||
|
foundType = true;
|
||||||
|
firstSimpleType = simpleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty classes shall always have sizeof() >= 1 and alignment doesn't matter
|
||||||
|
// Empty classes will be returned as null by the above code (complex? null conditional operator)
|
||||||
|
// https://www.stroustrup.com/bs_faq2.html#sizeof-empty
|
||||||
|
if (firstSimpleType != null)
|
||||||
|
if (field.OffsetBytes % firstSimpleType.SizeBytes != 0)
|
||||||
|
field.Offset += (firstSimpleType.SizeBytes - field.OffsetBytes % firstSimpleType.SizeBytes) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
// Respect alignment directives
|
// Respect alignment directives
|
||||||
if (alignmentBytes > 0 && field.OffsetBytes % alignmentBytes != 0)
|
if (alignmentBytes > 0 && field.OffsetBytes % alignmentBytes != 0)
|
||||||
|
|||||||
Reference in New Issue
Block a user