diff options
3 files changed, 183 insertions, 117 deletions
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp index e7ae1f721ef..b60feffb0a6 100755 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp @@ -20,6 +20,8 @@  #include "Plugins/Process/Utility/RegisterContextLinux_i386.h"  #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" +#include <cpuid.h> +  using namespace lldb_private;  using namespace lldb_private::process_linux; @@ -218,6 +220,23 @@ static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = {  #define NT_PRXFPREG 0x46e62b7f  #endif +// ---------------------------------------------------------------------------- +// Required MPX define. +// ---------------------------------------------------------------------------- + +// Support MPX extensions also if compiled with compiler without MPX support. +#ifndef bit_MPX +#define bit_MPX 0x4000 +#endif + +// ---------------------------------------------------------------------------- +// XCR0 extended register sets masks. +// ---------------------------------------------------------------------------- +#define mask_XSTATE_AVX (1ULL << 2) +#define mask_XSTATE_BNDREGS (1ULL << 3) +#define mask_XSTATE_BNDCFG (1ULL << 4) +#define mask_XSTATE_MPX (mask_XSTATE_BNDREGS | mask_XSTATE_BNDCFG) +  NativeRegisterContextLinux *  NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(      const ArchSpec &target_arch, NativeThreadProtocol &native_thread, @@ -249,7 +268,7 @@ NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64(      uint32_t concrete_frame_idx)      : NativeRegisterContextLinux(native_thread, concrete_frame_idx,                                   CreateRegisterInfoInterface(target_arch)), -      m_fpr_type(eFPRTypeNotValid), m_fpr(), m_iovec(), m_ymm_set(), +      m_xstate_type(eXStateTypeNotValid), m_fpr(), m_iovec(), m_ymm_set(),        m_mpx_set(), m_reg_info(), m_gpr_x86_64() {    // Set up data about ranges of valid registers.    switch (target_arch.GetMachine()) { @@ -379,7 +398,7 @@ Error NativeRegisterContextLinux_x86_64::ReadRegister(      return error;    } -  if (IsFPR(reg, GetFPRType())) { +  if (IsFPR(reg) || IsAVX(reg) || IsMPX(reg)) {      error = ReadFPR();      if (error.Fail())        return error; @@ -428,7 +447,7 @@ Error NativeRegisterContextLinux_x86_64::ReadRegister(              reg_info->byte_size, byte_order);        if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) {          // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes -        if (GetFPRType() == eFPRTypeXSAVE && CopyXSTATEtoYMM(reg, byte_order)) +        if (CopyXSTATEtoYMM(reg, byte_order))            reg_value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,                               reg_info->byte_size, byte_order);          else { @@ -437,7 +456,7 @@ Error NativeRegisterContextLinux_x86_64::ReadRegister(          }        }        if (reg >= m_reg_info.first_mpxr && reg <= m_reg_info.last_mpxr) { -        if (GetFPRType() == eFPRTypeXSAVE && CopyXSTATEtoMPX(reg)) +        if (CopyXSTATEtoMPX(reg))            reg_value.SetBytes(m_mpx_set.mpxr[reg - m_reg_info.first_mpxr].bytes,                               reg_info->byte_size, byte_order);          else { @@ -446,7 +465,7 @@ Error NativeRegisterContextLinux_x86_64::ReadRegister(          }        }        if (reg >= m_reg_info.first_mpxc && reg <= m_reg_info.last_mpxc) { -        if (GetFPRType() == eFPRTypeXSAVE && CopyXSTATEtoMPX(reg)) +        if (CopyXSTATEtoMPX(reg))            reg_value.SetBytes(m_mpx_set.mpxc[reg - m_reg_info.first_mpxc].bytes,                               reg_info->byte_size, byte_order);          else { @@ -517,7 +536,7 @@ Error NativeRegisterContextLinux_x86_64::WriteRegister(    if (IsGPR(reg_index))      return WriteRegisterRaw(reg_index, reg_value); -  if (IsFPR(reg_index, GetFPRType())) { +  if (IsFPR(reg_index) || IsAVX(reg_index) || IsMPX(reg_index)) {      if (reg_info->encoding == lldb::eEncodingVector) {        if (reg_index >= m_reg_info.first_st && reg_index <= m_reg_info.last_st)          ::memcpy( @@ -536,9 +555,6 @@ Error NativeRegisterContextLinux_x86_64::WriteRegister(        if (reg_index >= m_reg_info.first_ymm &&            reg_index <= m_reg_info.last_ymm) { -        if (GetFPRType() != eFPRTypeXSAVE) -          return Error("target processor does not support AVX"); -          // Store ymm register content, and split into the register halves in          // xmm.bytes and ymmh.bytes          ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes, @@ -549,9 +565,6 @@ Error NativeRegisterContextLinux_x86_64::WriteRegister(        if (reg_index >= m_reg_info.first_mpxr &&            reg_index <= m_reg_info.last_mpxr) { -        if (GetFPRType() != eFPRTypeXSAVE) -          return Error("target processor does not support MPX"); -          ::memcpy(m_mpx_set.mpxr[reg_index - m_reg_info.first_mpxr].bytes,                   reg_value.GetBytes(), reg_value.GetByteSize());          if (!CopyMPXtoXSTATE(reg_index)) @@ -560,9 +573,6 @@ Error NativeRegisterContextLinux_x86_64::WriteRegister(        if (reg_index >= m_reg_info.first_mpxc &&            reg_index <= m_reg_info.last_mpxc) { -        if (GetFPRType() != eFPRTypeXSAVE) -          return Error("target processor does not support MPX"); -          ::memcpy(m_mpx_set.mpxc[reg_index - m_reg_info.first_mpxc].bytes,                   reg_value.GetBytes(), reg_value.GetByteSize());          if (!CopyMPXtoXSTATE(reg_index)) @@ -654,31 +664,37 @@ Error NativeRegisterContextLinux_x86_64::ReadAllRegisterValues(    ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize());    dst += GetRegisterInfoInterface().GetGPRSize(); -  if (GetFPRType() == eFPRTypeFXSAVE) +  if (GetXStateType() == eXStateTypeFXSAVE)      ::memcpy(dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); -  else if (GetFPRType() == eFPRTypeXSAVE) { +  else if (GetXStateType() == eXStateTypeXSAVE) {      lldb::ByteOrder byte_order = GetByteOrder(); -    // Assemble the YMM register content from the register halves. -    for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; -         ++reg) { -      if (!CopyXSTATEtoYMM(reg, byte_order)) { -        error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " -                                       "CopyXSTATEtoYMM() failed for reg num " -                                       "%" PRIu32, -                                       __FUNCTION__, reg); -        return error; +    if (IsCPUFeatureAvailable(avx)) { +      // Assemble the YMM register content from the register halves. +      for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; +           ++reg) { +        if (!CopyXSTATEtoYMM(reg, byte_order)) { +          error.SetErrorStringWithFormat( +              "NativeRegisterContextLinux_x86_64::%s " +              "CopyXSTATEtoYMM() failed for reg num " +              "%" PRIu32, +              __FUNCTION__, reg); +          return error; +        }        }      } -    for (uint32_t reg = m_reg_info.first_mpxr; reg <= m_reg_info.last_mpxc; -         ++reg) { -      if (!CopyXSTATEtoMPX(reg)) { -        error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " -                                       "CopyXSTATEtoMPX() failed for reg num " -                                       "%" PRIu32, -                                       __FUNCTION__, reg); -        return error; +    if (IsCPUFeatureAvailable(mpx)) { +      for (uint32_t reg = m_reg_info.first_mpxr; reg <= m_reg_info.last_mpxc; +           ++reg) { +        if (!CopyXSTATEtoMPX(reg)) { +          error.SetErrorStringWithFormat( +              "NativeRegisterContextLinux_x86_64::%s " +              "CopyXSTATEtoMPX() failed for reg num " +              "%" PRIu32, +              __FUNCTION__, reg); +          return error; +        }        }      }      // Copy the extended register state including the assembled ymm registers. @@ -740,38 +756,44 @@ Error NativeRegisterContextLinux_x86_64::WriteAllRegisterValues(      return error;    src += GetRegisterInfoInterface().GetGPRSize(); -  if (GetFPRType() == eFPRTypeFXSAVE) +  if (GetXStateType() == eXStateTypeFXSAVE)      ::memcpy(&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave)); -  else if (GetFPRType() == eFPRTypeXSAVE) +  else if (GetXStateType() == eXStateTypeXSAVE)      ::memcpy(&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave));    error = WriteFPR();    if (error.Fail())      return error; -  if (GetFPRType() == eFPRTypeXSAVE) { +  if (GetXStateType() == eXStateTypeXSAVE) {      lldb::ByteOrder byte_order = GetByteOrder(); -    // Parse the YMM register content from the register halves. -    for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; -         ++reg) { -      if (!CopyYMMtoXSTATE(reg, byte_order)) { -        error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " -                                       "CopyYMMtoXSTATE() failed for reg num " -                                       "%" PRIu32, -                                       __FUNCTION__, reg); -        return error; +    if (IsCPUFeatureAvailable(avx)) { +      // Parse the YMM register content from the register halves. +      for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; +           ++reg) { +        if (!CopyYMMtoXSTATE(reg, byte_order)) { +          error.SetErrorStringWithFormat( +              "NativeRegisterContextLinux_x86_64::%s " +              "CopyYMMtoXSTATE() failed for reg num " +              "%" PRIu32, +              __FUNCTION__, reg); +          return error; +        }        }      } -    for (uint32_t reg = m_reg_info.first_mpxr; reg <= m_reg_info.last_mpxc; -         ++reg) { -      if (!CopyMPXtoXSTATE(reg)) { -        error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " -                                         "CopyMPXtoXSTATE() failed for reg num " -                                         "%" PRIu32, -                                         __FUNCTION__, reg); -        return error; +    if (IsCPUFeatureAvailable(mpx)) { +      for (uint32_t reg = m_reg_info.first_mpxr; reg <= m_reg_info.last_mpxc; +           ++reg) { +        if (!CopyMPXtoXSTATE(reg)) { +          error.SetErrorStringWithFormat( +              "NativeRegisterContextLinux_x86_64::%s " +              "CopyMPXtoXSTATE() failed for reg num " +              "%" PRIu32, +              __FUNCTION__, reg); +          return error; +        }        }      }    } @@ -779,16 +801,75 @@ Error NativeRegisterContextLinux_x86_64::WriteAllRegisterValues(    return error;  } +bool NativeRegisterContextLinux_x86_64::HasFXSAVE() const { +  unsigned int rax, rbx, rcx, rdx; + +  // Check if FXSAVE is enabled. +  if (!__get_cpuid(1, &rax, &rbx, &rcx, &rdx)) +    return false; +  if ((rdx & bit_FXSAVE) == bit_FXSAVE) { +    m_xstate_type = eXStateTypeFXSAVE; +    if (const_cast<NativeRegisterContextLinux_x86_64 *>(this)->ReadFPR().Fail()) +      return false; +    return true; +  } +  return false; +} + +bool NativeRegisterContextLinux_x86_64::HasXSAVE() const { +  unsigned int rax, rbx, rcx, rdx; + +  // Check if XSAVE is enabled. +  if (!__get_cpuid(1, &rax, &rbx, &rcx, &rdx)) +    return false; +  if ((rcx & bit_OSXSAVE) == bit_OSXSAVE) { +    m_xstate_type = eXStateTypeXSAVE; +    if (const_cast<NativeRegisterContextLinux_x86_64 *>(this)->ReadFPR().Fail()) +      return false; +    return true; +  } +  return false; +} + +bool NativeRegisterContextLinux_x86_64::IsCPUFeatureAvailable( +    RegSet feature_code) const { +  unsigned int rax, rbx, rcx, rdx; + +  // Check if XSAVE is enabled. +  if (!HasXSAVE()) +    return false; + +  __get_cpuid(1, &rax, &rbx, &rcx, &rdx); +  switch (feature_code) { +  case avx: // Check if CPU has AVX and if there is kernel support, by reading in the XCR0 area of XSAVE. +    if (((rcx & bit_AVX) != 0) && ((m_fpr.xstate.xsave.i387.xcr0 & mask_XSTATE_AVX) == mask_XSTATE_AVX)) +      return true; +  case mpx: // Check if CPU has MPX and if there is kernel support, by reading in the XCR0 area of XSAVE. +    if (__get_cpuid_max(0, NULL) > 7) { +      __cpuid_count(7, 0, rax, rbx, rcx, rdx); +      if (((rbx & bit_MPX) != 0) && ((m_fpr.xstate.xsave.i387.xcr0 & mask_XSTATE_MPX) == mask_XSTATE_MPX)) +        return true; +    } +  default: +    return false; +  } +} +  bool NativeRegisterContextLinux_x86_64::IsRegisterSetAvailable(      uint32_t set_index) const { -  // Note: Extended register sets are assumed to be at the end of g_reg_sets.    uint32_t num_sets = k_num_register_sets - k_num_extended_register_sets; -  if (GetFPRType() == eFPRTypeXSAVE) { -    // AVX is the first extended register set. -    num_sets += 2; +  switch (set_index) { +  case gpr: +  case fpu: +    return (set_index < num_sets); +  case avx: +    return IsCPUFeatureAvailable(avx); +  case mpx: +    return IsCPUFeatureAvailable(mpx); +  default: +    return false;    } -  return (set_index < num_sets);  }  bool NativeRegisterContextLinux_x86_64::IsGPR(uint32_t reg_index) const { @@ -796,32 +877,15 @@ bool NativeRegisterContextLinux_x86_64::IsGPR(uint32_t reg_index) const {    return reg_index <= m_reg_info.last_gpr;  } -NativeRegisterContextLinux_x86_64::FPRType -NativeRegisterContextLinux_x86_64::GetFPRType() const { -  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); -  if (m_fpr_type == eFPRTypeNotValid) { -    // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx. - -    // Try and see if AVX register retrieval works. -    m_fpr_type = eFPRTypeXSAVE; -    if (const_cast<NativeRegisterContextLinux_x86_64 *>(this) -            ->ReadFPR() -            .Fail()) { -      // Fall back to general floating point with no AVX support. -      m_fpr_type = eFPRTypeFXSAVE; - -      // Check if FXSAVE area can be read. -      if (const_cast<NativeRegisterContextLinux_x86_64 *>(this) -              ->ReadFPR() -              .Fail()) { -        if (log) -          log->Printf("NativeRegisterContextLinux_x86_64::%s ptrace APIs " -                      "failed to read XSAVE/FXSAVE area", -                      __FUNCTION__); -      } -    } +NativeRegisterContextLinux_x86_64::XStateType +NativeRegisterContextLinux_x86_64::GetXStateType() const { +  if (m_xstate_type == eXStateTypeNotValid) { +    if (HasXSAVE()) +      m_xstate_type = eXStateTypeXSAVE; +    else if (HasFXSAVE()) +      m_xstate_type = eXStateTypeFXSAVE;    } -  return m_fpr_type; +  return m_xstate_type;  }  bool NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index) const { @@ -829,21 +893,12 @@ bool NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index) const {            reg_index <= m_reg_info.last_fpr);  } -bool NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index, -                                              FPRType fpr_type) const { -  bool generic_fpr = IsFPR(reg_index); - -  if (fpr_type == eFPRTypeXSAVE) -    return generic_fpr || IsAVX(reg_index) || IsMPX(reg_index); -  return generic_fpr; -} -  Error NativeRegisterContextLinux_x86_64::WriteFPR() { -  const FPRType fpr_type = GetFPRType(); +  const XStateType fpr_type = GetXStateType();    const lldb_private::ArchSpec &target_arch =        GetRegisterInfoInterface().GetTargetArchitecture();    switch (fpr_type) { -  case FPRType::eFPRTypeFXSAVE: +  case XStateType::eXStateTypeFXSAVE:      // For 32-bit inferiors on x86_32/x86_64 architectures,      // FXSAVE area can be written using PTRACE_SETREGSET ptrace api      // For 64-bit inferiors on x86_64 architectures, @@ -858,7 +913,7 @@ Error NativeRegisterContextLinux_x86_64::WriteFPR() {        assert(false && "Unhandled target architecture.");        break;      } -  case FPRType::eFPRTypeXSAVE: +  case XStateType::eXStateTypeXSAVE:      return WriteRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave),                              NT_X86_XSTATE);    default: @@ -867,6 +922,8 @@ Error NativeRegisterContextLinux_x86_64::WriteFPR() {  }  bool NativeRegisterContextLinux_x86_64::IsAVX(uint32_t reg_index) const { +  if (!IsCPUFeatureAvailable(avx)) +    return false;    return (m_reg_info.first_ymm <= reg_index &&            reg_index <= m_reg_info.last_ymm);  } @@ -926,11 +983,11 @@ bool NativeRegisterContextLinux_x86_64::CopyYMMtoXSTATE(  }  void *NativeRegisterContextLinux_x86_64::GetFPRBuffer() { -  const FPRType fpr_type = GetFPRType(); -  switch (fpr_type) { -  case FPRType::eFPRTypeFXSAVE: +  const XStateType xstate_type = GetXStateType(); +  switch (xstate_type) { +  case XStateType::eXStateTypeFXSAVE:      return &m_fpr.xstate.fxsave; -  case FPRType::eFPRTypeXSAVE: +  case XStateType::eXStateTypeXSAVE:      return &m_iovec;    default:      return nullptr; @@ -938,11 +995,11 @@ void *NativeRegisterContextLinux_x86_64::GetFPRBuffer() {  }  size_t NativeRegisterContextLinux_x86_64::GetFPRSize() { -  const FPRType fpr_type = GetFPRType(); -  switch (fpr_type) { -  case FPRType::eFPRTypeFXSAVE: +  const XStateType xstate_type = GetXStateType(); +  switch (xstate_type) { +  case XStateType::eXStateTypeFXSAVE:      return sizeof(m_fpr.xstate.fxsave); -  case FPRType::eFPRTypeXSAVE: +  case XStateType::eXStateTypeXSAVE:      return sizeof(m_iovec);    default:      return 0; @@ -950,11 +1007,11 @@ size_t NativeRegisterContextLinux_x86_64::GetFPRSize() {  }  Error NativeRegisterContextLinux_x86_64::ReadFPR() { -  const FPRType fpr_type = GetFPRType(); +  const XStateType xstate_type = GetXStateType();    const lldb_private::ArchSpec &target_arch =        GetRegisterInfoInterface().GetTargetArchitecture(); -  switch (fpr_type) { -  case FPRType::eFPRTypeFXSAVE: +  switch (xstate_type) { +  case XStateType::eXStateTypeFXSAVE:      // For 32-bit inferiors on x86_32/x86_64 architectures,      // FXSAVE area can be read using PTRACE_GETREGSET ptrace api      // For 64-bit inferiors on x86_64 architectures, @@ -968,7 +1025,7 @@ Error NativeRegisterContextLinux_x86_64::ReadFPR() {        assert(false && "Unhandled target architecture.");        break;      } -  case FPRType::eFPRTypeXSAVE: +  case XStateType::eXStateTypeXSAVE:      return ReadRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);    default:      return Error("Unrecognized FPR type"); @@ -976,8 +1033,10 @@ Error NativeRegisterContextLinux_x86_64::ReadFPR() {  }  bool NativeRegisterContextLinux_x86_64::IsMPX(uint32_t reg_index) const { -    return (m_reg_info.first_mpxr <= reg_index && -            reg_index <= m_reg_info.last_mpxc); +  if (!IsCPUFeatureAvailable(mpx)) +    return false; +  return (m_reg_info.first_mpxr <= reg_index && +          reg_index <= m_reg_info.last_mpxc);  }  bool NativeRegisterContextLinux_x86_64::CopyXSTATEtoMPX(uint32_t reg) { diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h index 21f548a95de..02f6d54b7e2 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h @@ -77,7 +77,8 @@ protected:  private:    // Private member types. -  enum FPRType { eFPRTypeNotValid = 0, eFPRTypeFXSAVE, eFPRTypeXSAVE }; +  enum XStateType { eXStateTypeNotValid = 0, eXStateTypeFXSAVE, eXStateTypeXSAVE }; +  enum RegSet { gpr, fpu, avx, mpx };    // Info about register ranges.    struct RegInfo { @@ -106,8 +107,8 @@ private:    };    // Private member variables. -  mutable FPRType m_fpr_type; -  FPR m_fpr; +  mutable XStateType m_xstate_type; +  FPR m_fpr; // Extended States Area, named FPR for historical reasons.    IOVEC m_iovec;    YMM m_ymm_set;    MPX m_mpx_set; @@ -116,16 +117,20 @@ private:    uint32_t m_fctrl_offset_in_userarea;    // Private member methods. +  bool HasFXSAVE() const; + +  bool HasXSAVE() const; + +  bool IsCPUFeatureAvailable(RegSet feature_code) const; +    bool IsRegisterSetAvailable(uint32_t set_index) const;    bool IsGPR(uint32_t reg_index) const; -  FPRType GetFPRType() const; +  XStateType GetXStateType() const;    bool IsFPR(uint32_t reg_index) const; -  bool IsFPR(uint32_t reg_index, FPRType fpr_type) const; -    bool CopyXSTATEtoYMM(uint32_t reg_index, lldb::ByteOrder byte_order);    bool CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order); diff --git a/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h b/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h index 2dcc43ed4fc..ab2ca2bb6c2 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h @@ -277,7 +277,9 @@ struct FXSAVE {    uint32_t mxcsrmask; // MXCSR Mask    MMSReg stmm[8];     // 8*16 bytes for each FP-reg = 128 bytes    XMMReg xmm[16];     // 16*16 bytes for each XMM-reg = 256 bytes -  uint32_t padding[24]; +  uint8_t padding1[48]; +  uint64_t xcr0; +  uint8_t padding2[40];  };  //---------------------------------------------------------------------------  | 

