#pragma pack(push, PPP) struct XXX { LPVOID m_AAA; ULONG m_BBB; ULONG m_CCC; ULONG m_DDD; }; #pragma pack(pop)
Где PPP я установил в 4 для x86 и в 8 для x64. Другими словами каждое поле начинается со смещения кратного размеру указателя. С другой стороны, в CLR, я определил структуру примерно таким образом:
static mdToken const g_NilImplements[] = {mdTokenNil}; mdTypeDef stk; if (hr = mde->DefineTypeDef(L"XXX", tdNotPublic | tdSequentialLayout | tdClass | tdSealed | tdBeforeFieldInit | tdAnsiClass, valueTypeToken, const_cast<mdtoken *>(g_NilImplements), &stk), FAILED(hr)) throw _hr_error("Can't emit inject structure", hr); if (hr = mde->SetClassLayout(stk, PPP, NULL, 0), FAILED(hr)) throw _hr_error("Can't emit inject structure", hr); static BYTE const g_fblobPtr[] = { IMAGE_CEE_CS_CALLCONV_FIELD, ELEMENT_TYPE_PTR, ELEMENT_TYPE_VOID, }; mdFieldToken ftkAAA; if (hr = mde->DefineField(stk, L"AAA", fdPublic, g_fblobPtr, sizeof(g_fblobPtr) / sizeof(*g_fblobPtr), ELEMENT_TYPE_END, NULL, 0, &ftkAAA), FAILED(hr)) throw _hr_error("Can't emit field structure", hr); static BYTE const g_fblobUInt32[] = { IMAGE_CEE_CS_CALLCONV_FIELD, ELEMENT_TYPE_U4, }; mdFieldToken ftkBBB; if (hr = mde->DefineField(stk, L"BBB", fdPublic, g_fblobUInt32, sizeof(g_fblobUInt32) / sizeof(*g_fblobUInt32), ELEMENT_TYPE_END, NULL, 0, &ftkBBB), FAILED(hr)) throw _hr_error("Can't emit field structure", hr); mdFieldToken ftkCCC; if (hr = mde->DefineField(stk, L"CCC", fdPublic, g_fblobUInt32, sizeof(g_fblobUInt32) / sizeof(*g_fblobUInt32), ELEMENT_TYPE_END, NULL, 0, &ftkCCC), FAILED(hr)) throw _hr_error("Can't emit field structure", hr); mdFieldToken ftkDDD; if (hr = mde->DefineField(stk, L"DDD", fdPublic, g_fblobUInt32, sizeof(g_fblobUInt32) / sizeof(*g_fblobUInt32), ELEMENT_TYPE_END, NULL, 0, &ftkDDD), FAILED(hr)) throw _hr_error("Can't emit field structure", hr);
Мир казался прекрасным под x86, но стоило запуститься под x64 структуры кардинально разъехались. После внимательного изучения документации выяснилось, что в CLR в отличии от C/C++ для выравнивания выбирается меньшее из двух чисел: размер самого поля и установленного через SetClassLayout выравнивания. Для устранения проблемы пришлось установить PPP в 1 для всех платформ. Хотя в принципе есть и другие решения, но я выбрал самое простое.
No comments:
Post a Comment