mirror of
https://github.com/lifting-bits/remill
synced 2026-06-21 13:56:07 +00:00
873 lines
23 KiB
C
873 lines
23 KiB
C
/*
|
|
* Copyright (c) 2017 Trail of Bits, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
// !!! RULES FOR STATE STRUCTURE TYPES !!!
|
|
//
|
|
// (1) Never use a type that has a different allocation size on a different
|
|
// architecture. This includes things like pointers or architecture-
|
|
// specific floating point types (e.g. `long double`).
|
|
//
|
|
// (2) Never depend on implicit padding or alignment, even if you explicitly
|
|
// specify it. Always "fill" structures to the desired alignment with
|
|
// explicit structure fields.
|
|
//
|
|
// (3) Trust but verify the `static_assert`s that try to verify the sizes of
|
|
// structures. Clang will LIE to you! This happens if you compile a file
|
|
// to bitcode for one architecture, then change its `DataLayout` to
|
|
// match another architecture.
|
|
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic fatal "-Wpadded"
|
|
|
|
#include "remill/Arch/Runtime/State.h"
|
|
#include "remill/Arch/Runtime/Types.h"
|
|
|
|
#ifndef HAS_FEATURE_AVX
|
|
# define HAS_FEATURE_AVX 1
|
|
#endif
|
|
|
|
#ifndef HAS_FEATURE_AVX512
|
|
# define HAS_FEATURE_AVX512 1
|
|
#endif
|
|
|
|
#if HAS_FEATURE_AVX
|
|
# define IF_AVX(...) __VA_ARGS__
|
|
# define IF_AVX_ELSE(a, b) a
|
|
#else
|
|
# define IF_AVX(...)
|
|
# define IF_AVX_ELSE(a, b) b
|
|
#endif
|
|
|
|
#if HAS_FEATURE_AVX && HAS_FEATURE_AVX512
|
|
# define IF_AVX512(...) __VA_ARGS__
|
|
# define IF_AVX512_ELSE(a, b) a
|
|
#else
|
|
# define IF_AVX512(...)
|
|
# define IF_AVX512_ELSE(a, b) b
|
|
#endif
|
|
|
|
enum RequestPrivilegeLevel : uint16_t {
|
|
kRPLRingZero = 0,
|
|
kRPLRingOne = 1,
|
|
kRPLRingTwo = 2,
|
|
kRPLRingThree = 3
|
|
};
|
|
|
|
enum TableIndicator : uint16_t {
|
|
kGlobalDescriptorTable = 0,
|
|
kLocalDescriptorTable = 1
|
|
};
|
|
|
|
#ifndef __clang__
|
|
# define RequestPrivilegeLevel uint16_t
|
|
# define TableIndicator uint16_t
|
|
#endif
|
|
|
|
union SegmentSelector final {
|
|
uint16_t flat;
|
|
struct {
|
|
RequestPrivilegeLevel rpi : 2;
|
|
TableIndicator ti : 1;
|
|
uint16_t index : 13;
|
|
} __attribute__((packed));
|
|
} __attribute__((packed));
|
|
|
|
static_assert(sizeof(SegmentSelector) == 2,
|
|
"Invalid packing of `union SegmentSelector`.");
|
|
|
|
struct SegmentShadow final {
|
|
union {
|
|
uint32_t dword;
|
|
uint64_t qword;
|
|
} base;
|
|
uint32_t limit;
|
|
uint32_t flags;
|
|
} __attribute__((packed));
|
|
|
|
static_assert(sizeof(SegmentShadow) == 16,
|
|
"Invalid packing of `struct SegmentShadow`.");
|
|
|
|
union FPUStatusWord final {
|
|
uint16_t flat;
|
|
struct {
|
|
uint16_t ie : 1; // Invalid operation.
|
|
uint16_t de : 1; // Denormal operand.
|
|
uint16_t ze : 1; // Zero divide.
|
|
uint16_t oe : 1; // Overflow.
|
|
uint16_t ue : 1; // Underflow.
|
|
uint16_t pe : 1; // Precision.
|
|
uint16_t sf : 1; // Stack fault.
|
|
uint16_t es : 1; // Error summary status.
|
|
uint16_t c0 : 1; // Part of condition code.
|
|
uint16_t c1 : 1; // Used for a whole lot of stuff.
|
|
uint16_t c2 : 1; // Part of condition code.
|
|
uint16_t top : 3; // Stack pointer.
|
|
uint16_t c3 : 1; // Part of condition code.
|
|
uint16_t b : 1; // Busy.
|
|
} __attribute__((packed));
|
|
} __attribute__((packed));
|
|
|
|
static_assert(2 == sizeof(FPUStatusWord),
|
|
"Invalid structure packing of `FPUFlags`.");
|
|
|
|
enum FPUPrecisionControl : uint16_t {
|
|
kPrecisionSingle = 0,
|
|
kPrecisionReserved = 1,
|
|
kPrecisionDouble = 2,
|
|
kPrecisionExtended = 3,
|
|
};
|
|
|
|
enum FPURoundingControl : uint16_t {
|
|
kFPURoundToNearestEven = 0,
|
|
kFPURoundDownNegInf = 1,
|
|
kFPURoundUpInf = 2,
|
|
kFPURoundToZero = 3,
|
|
};
|
|
|
|
enum FPUInfinityControl : uint16_t {
|
|
kInfinityProjective = 0,
|
|
kInfinityAffine = 1,
|
|
};
|
|
|
|
enum FPUExceptionFlag : uint16_t {
|
|
kFPUExceptionInvalid = (1 << 0), // FSW.ie, bit 0 - Invalid Operation (FE_INVALID)
|
|
kFPUExceptionDenormal = (1 << 1), // FSW.de, bit 1 - Denormal Operand (FE_DENORMAL)
|
|
kFPUExceptionDivByZero = (1 << 2), // FSW.ze, bit 2 - Zero Divide (FE_DIVBYZERO)
|
|
kFPUExceptionOverflow = (1 << 3), // FSW.oe, bit 3 - Overflow (FE_OVERFLOW)
|
|
kFPUExceptionUnderflow = (1 << 4), // FSW.ue, bit 4 - Underflow (FE_UNDERFLOW)
|
|
kFPUExceptionPrecision = (1 << 5), // FSW.pe, bit 5 - Precision/Inexact (FE_INEXACT)
|
|
kFPUExceptionStackFault = (1 << 6), // FSW.sf, bit 6 - Stack Fault (no FE_ equivalent, x87-specific)
|
|
kFPUExceptionAll = 0x7F // All exception flags (bits 0-6)
|
|
};
|
|
|
|
union FPUControlWord final {
|
|
uint16_t flat;
|
|
struct {
|
|
uint16_t im : 1; // Invalid Operation.
|
|
uint16_t dm : 1; // Denormalized Operand.
|
|
uint16_t zm : 1; // Zero Divide.
|
|
uint16_t om : 1; // Overflow.
|
|
uint16_t um : 1; // Underflow.
|
|
uint16_t pm : 1; // Precision.
|
|
uint16_t _rsvd0 : 2;
|
|
FPUPrecisionControl pc : 2; // bit 8
|
|
FPURoundingControl rc : 2;
|
|
FPUInfinityControl x : 1;
|
|
uint16_t _rsvd1 : 3;
|
|
} __attribute__((packed));
|
|
} __attribute__((packed));
|
|
|
|
static_assert(2 == sizeof(FPUControlWord),
|
|
"Invalid structure packing of `FPUControl`.");
|
|
|
|
struct FPUStackElem final {
|
|
FPUStackElem() {}
|
|
union {
|
|
float80_t st;
|
|
struct {
|
|
uint64_t mmx;
|
|
uint16_t infinity; // When an MMX register is used, this is all 1s.
|
|
} __attribute__((packed));
|
|
} __attribute__((packed));
|
|
uint8_t _rsvd[6];
|
|
} __attribute__((packed));
|
|
|
|
static_assert(0 == __builtin_offsetof(FPUStackElem, st),
|
|
"Invalid structure packing of `FPUStackElem::st`.");
|
|
|
|
static_assert(0 == __builtin_offsetof(FPUStackElem, mmx),
|
|
"Invalid structure packing of `FPUStackElem::mmx`.");
|
|
|
|
static_assert(8 == __builtin_offsetof(FPUStackElem, infinity),
|
|
"Invalid structure packing of `FPUStackElem::st`.");
|
|
|
|
static_assert(10 == __builtin_offsetof(FPUStackElem, _rsvd[0]),
|
|
"Invalid structure packing of `FPUStackElem::st`.");
|
|
|
|
static_assert(16 == sizeof(FPUStackElem),
|
|
"Invalid structure packing of `FPUStackElem`.");
|
|
|
|
union FPUControlStatus {
|
|
uint32_t flat;
|
|
struct {
|
|
uint32_t ie : 1; // Invalid operation.
|
|
uint32_t de : 1; // Denormal flag.
|
|
uint32_t ze : 1; // Divide by zero.
|
|
uint32_t oe : 1; // Overflow.
|
|
uint32_t ue : 1; // Underflow.
|
|
uint32_t pe : 1; // Precision.
|
|
uint32_t daz : 1; // Denormals are zero.
|
|
uint32_t im : 1; // Invalid operation.
|
|
uint32_t dm : 1; // Denormal mask.
|
|
uint32_t zm : 1; // Divide by zero mask.
|
|
uint32_t om : 1; // Overflow mask.
|
|
uint32_t um : 1; // Underflow mask.
|
|
uint32_t pm : 1; // Precision mask.
|
|
uint32_t rn : 1; // Round negative.
|
|
uint32_t rp : 1; // Round positive.
|
|
uint32_t fz : 1; // Flush to zero.
|
|
uint32_t _rsvd : 16;
|
|
} __attribute__((packed));
|
|
} __attribute__((packed));
|
|
|
|
static_assert(4 == sizeof(FPUControlStatus),
|
|
"Invalid structure packing of `SSEControlStatus`.");
|
|
|
|
enum FPUTag : uint16_t {
|
|
kFPUTagNonZero,
|
|
kFPUTagZero,
|
|
kFPUTagSpecial, // Invalid (NaN, unsupported), infinity, denormal.
|
|
kFPUTagEmpty
|
|
};
|
|
|
|
enum FPUAbridgedTag : uint8_t { kFPUAbridgedTagEmpty, kFPUAbridgedTagValid };
|
|
|
|
#ifndef __clang__
|
|
# define FPUTag uint16_t
|
|
# define FPUAbridgedTag uint8_t
|
|
#endif
|
|
|
|
// Note: Stored in top-of-stack order.
|
|
union FPUTagWord final {
|
|
uint16_t flat;
|
|
struct {
|
|
FPUTag tag0 : 2;
|
|
FPUTag tag1 : 2;
|
|
FPUTag tag2 : 2;
|
|
FPUTag tag3 : 2;
|
|
FPUTag tag4 : 2;
|
|
FPUTag tag5 : 2;
|
|
FPUTag tag6 : 2;
|
|
FPUTag tag7 : 2;
|
|
} __attribute__((packed));
|
|
} __attribute__((packed));
|
|
|
|
static_assert(sizeof(FPUTagWord) == 2,
|
|
"Invalid structure packing of `TagWord`.");
|
|
|
|
// Note: Stored in physical order.
|
|
union FPUAbridgedTagWord final {
|
|
uint8_t flat;
|
|
struct {
|
|
FPUAbridgedTag r0 : 1;
|
|
FPUAbridgedTag r1 : 1;
|
|
FPUAbridgedTag r2 : 1;
|
|
FPUAbridgedTag r3 : 1;
|
|
FPUAbridgedTag r4 : 1;
|
|
FPUAbridgedTag r5 : 1;
|
|
FPUAbridgedTag r6 : 1;
|
|
FPUAbridgedTag r7 : 1;
|
|
} __attribute__((packed));
|
|
} __attribute__((packed));
|
|
|
|
static_assert(sizeof(FPUAbridgedTagWord) == 1,
|
|
"Invalid structure packing of `FPUAbridgedTagWord`.");
|
|
|
|
// FPU register state that conforms with `FSAVE` and `FRSTOR`.
|
|
struct FpuFSAVE {
|
|
FPUControlWord cwd;
|
|
uint16_t _rsvd0;
|
|
FPUStatusWord swd;
|
|
uint16_t _rsvd1;
|
|
FPUTagWord ftw;
|
|
uint16_t fop; // Last instruction opcode.
|
|
uint32_t ip; // Offset in segment of last non-control FPU instruction.
|
|
SegmentSelector cs; // Code segment associated with `ip`.
|
|
uint16_t _rsvd2;
|
|
uint32_t dp; // Operand address.
|
|
SegmentSelector ds; // Data segment associated with `dp`.
|
|
uint16_t _rsvd3;
|
|
FPUStackElem st[8];
|
|
} __attribute__((packed));
|
|
|
|
// FPU register state that conforms with `FXSAVE` and `FXRSTOR`.
|
|
struct FpuFXSAVE {
|
|
FPUControlWord cwd;
|
|
FPUStatusWord swd;
|
|
FPUAbridgedTagWord ftw;
|
|
uint8_t _rsvd0;
|
|
uint16_t fop; // Last instruction opcode.
|
|
uint32_t ip; // Offset in segment of last non-control FPU instruction.
|
|
SegmentSelector cs; // Code segment associated with `ip`.
|
|
uint16_t _rsvd1;
|
|
uint32_t dp; // Operand address.
|
|
SegmentSelector ds; // Data segment associated with `dp`.
|
|
uint16_t _rsvd2;
|
|
FPUControlStatus mxcsr;
|
|
FPUControlStatus mxcsr_mask;
|
|
FPUStackElem st[8];
|
|
vec128_t xmm[16];
|
|
} __attribute__((packed));
|
|
|
|
// FPU register state that conforms with `FXSAVE64` and `FXRSTOR64`.
|
|
struct FpuFXSAVE64 {
|
|
FPUControlWord cwd;
|
|
FPUStatusWord swd;
|
|
FPUAbridgedTagWord ftw;
|
|
uint8_t _rsvd0;
|
|
uint16_t fop; // Last instruction opcode.
|
|
uint64_t ip; // Offset in segment of last non-control FPU instruction.
|
|
uint64_t dp; // Operand address.
|
|
FPUControlStatus mxcsr;
|
|
FPUControlStatus mxcsr_mask;
|
|
FPUStackElem st[8];
|
|
vec128_t xmm[16];
|
|
} __attribute__((packed));
|
|
|
|
// FP register state that conforms with `FXSAVE` and `FXSAVE64`.
|
|
union alignas(16) FPU final {
|
|
FPU() {}
|
|
struct : public FpuFSAVE {
|
|
uint8_t _padding0[512 - sizeof(FpuFSAVE)];
|
|
} __attribute__((packed)) fsave;
|
|
|
|
struct : public FpuFXSAVE {
|
|
uint8_t _padding0[512 - sizeof(FpuFXSAVE)];
|
|
} __attribute__((packed)) fxsave32;
|
|
|
|
struct : public FpuFXSAVE64 {
|
|
uint8_t _padding0[512 - sizeof(FpuFXSAVE64)];
|
|
} __attribute__((packed)) fxsave64;
|
|
} __attribute__((packed));
|
|
|
|
#define fxsave IF_64BIT_ELSE(fxsave64, fxsave32)
|
|
|
|
static_assert(512 == sizeof(FPU), "Invalid structure packing of `FPU`.");
|
|
|
|
struct FPUStatusFlags final {
|
|
uint8_t _0;
|
|
uint8_t c0;
|
|
uint8_t _1;
|
|
uint8_t c1;
|
|
uint8_t _2;
|
|
uint8_t c2;
|
|
uint8_t _3;
|
|
uint8_t c3;
|
|
|
|
uint8_t _4;
|
|
uint8_t pe; // Precision.
|
|
|
|
uint8_t _5;
|
|
uint8_t ue; // Underflow.
|
|
|
|
uint8_t _6;
|
|
uint8_t oe; // Overflow.
|
|
|
|
uint8_t _7;
|
|
uint8_t ze; // Divide by zero.
|
|
|
|
uint8_t _8;
|
|
uint8_t de; // Denormal operand.
|
|
|
|
uint8_t _9;
|
|
uint8_t ie; // Invalid operation.
|
|
|
|
uint8_t _10;
|
|
uint8_t sf; // Stack overflow.
|
|
|
|
uint8_t _padding[2];
|
|
} __attribute__((packed));
|
|
|
|
static_assert(24 == sizeof(FPUStatusFlags),
|
|
"Invalid packing of `FPUStatusFlags`.");
|
|
|
|
union alignas(8) Flags final {
|
|
uint64_t flat;
|
|
struct {
|
|
uint32_t cf : 1; // bit 0.
|
|
uint32_t must_be_1 : 1;
|
|
uint32_t pf : 1;
|
|
uint32_t must_be_0a : 1;
|
|
|
|
uint32_t af : 1; // bit 4.
|
|
uint32_t must_be_0b : 1;
|
|
uint32_t zf : 1;
|
|
uint32_t sf : 1;
|
|
|
|
uint32_t tf : 1; // bit 8.
|
|
uint32_t _if : 1; // underscore to avoid token clash.
|
|
uint32_t df : 1;
|
|
uint32_t of : 1;
|
|
|
|
uint32_t iopl : 2; // A 2-bit field, bits 12-13.
|
|
uint32_t nt : 1;
|
|
uint32_t must_be_0c : 1;
|
|
|
|
uint32_t rf : 1; // bit 16.
|
|
uint32_t vm : 1;
|
|
uint32_t ac : 1; // Alignment check.
|
|
uint32_t vif : 1;
|
|
|
|
uint32_t vip : 1; // bit 20.
|
|
uint32_t id : 1; // bit 21.
|
|
uint32_t reserved_eflags : 10; // bits 22-31.
|
|
uint32_t reserved_rflags; // bits 32-63.
|
|
} __attribute__((packed));
|
|
} __attribute__((packed));
|
|
|
|
static_assert(8 == sizeof(Flags), "Invalid structure packing of `Flags`.");
|
|
|
|
struct alignas(8) ArithFlags final {
|
|
|
|
// Prevents LLVM from casting and `ArithFlags` into an `i8` to access `cf`.
|
|
volatile uint8_t _0;
|
|
uint8_t cf; // Prevents load/store coalescing.
|
|
volatile uint8_t _1;
|
|
uint8_t pf;
|
|
volatile uint8_t _2;
|
|
uint8_t af;
|
|
volatile uint8_t _3;
|
|
uint8_t zf;
|
|
volatile uint8_t _4;
|
|
uint8_t sf;
|
|
volatile uint8_t _5;
|
|
uint8_t df;
|
|
volatile uint8_t _6;
|
|
uint8_t of;
|
|
volatile uint8_t _7;
|
|
volatile uint8_t _8;
|
|
} __attribute__((packed));
|
|
|
|
static_assert(16 == sizeof(ArithFlags), "Invalid packing of `ArithFlags`.");
|
|
|
|
struct alignas(8) Segments final {
|
|
volatile uint16_t _0;
|
|
SegmentSelector ss;
|
|
volatile uint16_t _1;
|
|
SegmentSelector es;
|
|
volatile uint16_t _2;
|
|
SegmentSelector gs;
|
|
volatile uint16_t _3;
|
|
SegmentSelector fs;
|
|
volatile uint16_t _4;
|
|
SegmentSelector ds;
|
|
volatile uint16_t _5;
|
|
SegmentSelector cs;
|
|
} __attribute__((packed));
|
|
|
|
static_assert(24 == sizeof(Segments), "Invalid packing of `struct Segments`.");
|
|
|
|
struct alignas(8) SegmentCaches final {
|
|
SegmentShadow cs;
|
|
SegmentShadow ss;
|
|
SegmentShadow ds;
|
|
SegmentShadow es;
|
|
SegmentShadow fs;
|
|
SegmentShadow gs;
|
|
} __attribute__((packed));
|
|
|
|
static_assert(96 == sizeof(SegmentCaches),
|
|
"Invalid packing of `struct SegmentCaches`.");
|
|
|
|
enum DescriptorPrivilegeLevel : uint64_t {
|
|
kDPLRingZero = 0,
|
|
kDPLRingOne = 1,
|
|
kDPLRingTwo = 2,
|
|
kDPLRingThree = 3
|
|
};
|
|
|
|
enum DescriptorClass : uint64_t {
|
|
kDataSegmentDescriptor,
|
|
kCodeSegmentDescriptor,
|
|
kSystemSegmentDescriptor,
|
|
kGateDescriptor,
|
|
kNotPresentDescriptor
|
|
};
|
|
|
|
enum SegmentGranularity : uint64_t {
|
|
kSegmentGranularityNotScaled,
|
|
kSegmentGranularityScaled
|
|
};
|
|
|
|
enum SegmentDefaultOperandSize : uint64_t {
|
|
kSegmentDefaultOperandSize16,
|
|
kSegmentDefaultOperandSize32
|
|
};
|
|
|
|
enum SegmentPresentStatus : uint64_t { kSegmentNotPresent, kSegmentPresent };
|
|
|
|
enum SystemDescriptorType : uint64_t {
|
|
kSystemTypeIllegal0,
|
|
kSystemTypeIllegal1,
|
|
kSystemTypeLDT,
|
|
kSystemTypeIllegal2,
|
|
kSystemTypeIllegal3,
|
|
kSystemTypeIllegal4,
|
|
kSystemTypeIllegal5,
|
|
kSystemTypeIllegal6,
|
|
kSystemTypeIllegal7,
|
|
kSystemTypeAvailableTSS,
|
|
kSystemTypeIllegal8,
|
|
kSystemTypeBusyTSS,
|
|
kSystemTypeCallGate,
|
|
kSystemTypeIllegal9,
|
|
kSystemTypeInterruptGate,
|
|
kSystemTypeTrapGate
|
|
};
|
|
|
|
enum CodeSegmentMode : uint64_t {
|
|
kSegmentCompatibilityMode,
|
|
kSegment64BitMode
|
|
};
|
|
|
|
enum SegmentSystemBit : uint64_t { kSegmentBitSystem, kSegmentBitUser };
|
|
|
|
#ifndef __clang__
|
|
# define DescriptorPrivilegeLevel uint64_t
|
|
# define DescriptorClass uint64_t
|
|
# define SegmentGranularity uint64_t
|
|
# define SegmentDefaultOperandSize uint64_t
|
|
# define SegmentPresentStatus uint64_t
|
|
# define SystemDescriptorType uint64_t
|
|
# define CodeSegmentMode uint64_t
|
|
# define SegmentSystemBit uint64_t
|
|
#endif
|
|
|
|
struct GenericDescriptor {
|
|
uint64_t unused : 44;
|
|
uint64_t sbit : 1;
|
|
uint64_t dpl : 2;
|
|
uint64_t present : 1;
|
|
uint64_t unused3 : 16;
|
|
} __attribute__((packed));
|
|
|
|
static_assert(8U == sizeof(GenericDescriptor),
|
|
"Invalid packing of `struct GenericDescriptor`.");
|
|
|
|
union SegmentDescriptor {
|
|
uint64_t flat;
|
|
struct {
|
|
uint16_t limit_low : 16;
|
|
uint16_t base_low : 16;
|
|
uint16_t base_middle : 8;
|
|
uint16_t system_type : 4;
|
|
uint16_t system_access : 4;
|
|
uint16_t limit_high : 4;
|
|
uint16_t available : 1;
|
|
|
|
/* Only valid for kCodeSegmentDescriptor */
|
|
uint16_t code_mode : 1; // Only valid for code segments.
|
|
|
|
/* Only valid for kCodeSegmentDescriptor, kDataSegmentDescriptor */
|
|
uint16_t default_operand_size : 1;
|
|
uint16_t granularity : 1;
|
|
|
|
uint16_t base_high : 8;
|
|
} __attribute__((packed));
|
|
} __attribute__((packed));
|
|
|
|
static_assert(8U == sizeof(SegmentDescriptor),
|
|
"Invalid packing of `struct SegmentDescriptor`.");
|
|
|
|
struct GateDescriptor {
|
|
uint64_t target_offset_low : 16;
|
|
uint64_t target_selector : 16;
|
|
/* Only valid for interrupt gates. */
|
|
uint64_t interrupt_stack_table_index : 3;
|
|
uint64_t reserved : 5;
|
|
uint64_t system_type : 4;
|
|
uint64_t access : 4;
|
|
uint64_t target_offset_middle : 16;
|
|
} __attribute__((packed));
|
|
|
|
static_assert(8U == sizeof(GateDescriptor),
|
|
"Invalid packing of `struct GateDescriptor`.");
|
|
|
|
struct ExtensionDescriptor {
|
|
uint64_t higher_addr : 32;
|
|
uint64_t reserved : 32;
|
|
} __attribute__((packed));
|
|
|
|
static_assert(8U == sizeof(ExtensionDescriptor),
|
|
"Invalid packing of `struct DescritorExtension`.");
|
|
|
|
union Descriptor {
|
|
GenericDescriptor generic;
|
|
SegmentDescriptor segment;
|
|
GateDescriptor gate;
|
|
ExtensionDescriptor extension;
|
|
} __attribute__((packed));
|
|
|
|
static_assert(8U == sizeof(Descriptor),
|
|
"Invalid packing of `struct SystemDescriptorExtra`.");
|
|
|
|
// We don't want 32-bit lifted code to look like operations on 64-bit
|
|
// registers, because then every (bitcasted from 64 bit) store of a 32-bit
|
|
// value will look like a false- dependency on the (bitcasted from 64 bit)
|
|
// full 64-bit quantity.
|
|
struct Reg final {
|
|
union {
|
|
alignas(1) struct {
|
|
uint8_t low;
|
|
uint8_t high;
|
|
} byte;
|
|
alignas(2) uint16_t word;
|
|
alignas(4) uint32_t dword;
|
|
IF_64BIT(alignas(8) uint64_t qword;)
|
|
} __attribute__((packed));
|
|
IF_32BIT(volatile uint32_t _padding0;)
|
|
} __attribute__((packed));
|
|
|
|
static_assert(sizeof(uint64_t) == sizeof(Reg), "Invalid packing of `Reg`.");
|
|
|
|
static_assert(0 == __builtin_offsetof(Reg, byte.low),
|
|
"Invalid packing of `Reg::low`.");
|
|
static_assert(1 == __builtin_offsetof(Reg, byte.high),
|
|
"Invalid packing of `Reg::high`.");
|
|
static_assert(0 == __builtin_offsetof(Reg, word),
|
|
"Invalid packing of `Reg::word`.");
|
|
static_assert(0 == __builtin_offsetof(Reg, dword),
|
|
"Invalid packing of `Reg::dword`.");
|
|
IF_64BIT(static_assert(0 == __builtin_offsetof(Reg, qword),
|
|
"Invalid packing of `Reg::qword`.");)
|
|
|
|
union alignas(16) VectorReg final {
|
|
alignas(16) vec128_t xmm;
|
|
alignas(16) vec256_t ymm;
|
|
alignas(16) vec512_t zmm;
|
|
} __attribute__((packed));
|
|
|
|
static_assert(0 == __builtin_offsetof(VectorReg, xmm),
|
|
"Invalid packing of `VectorReg::xmm`.");
|
|
|
|
static_assert(0 == __builtin_offsetof(VectorReg, ymm),
|
|
"Invalid packing of `VectorReg::ymm`.");
|
|
|
|
static_assert(0 == __builtin_offsetof(VectorReg, zmm),
|
|
"Invalid packing of `VectorReg::zmm`.");
|
|
|
|
static_assert(64 == sizeof(VectorReg),
|
|
"Invalid packing of `struct VectorReg`.");
|
|
|
|
struct alignas(8) AddressSpace final {
|
|
volatile uint64_t _0;
|
|
Reg ss_base;
|
|
volatile uint64_t _1;
|
|
Reg es_base;
|
|
volatile uint64_t _2;
|
|
Reg gs_base;
|
|
volatile uint64_t _3;
|
|
Reg fs_base;
|
|
volatile uint64_t _4;
|
|
Reg ds_base;
|
|
volatile uint64_t _5;
|
|
Reg cs_base;
|
|
} __attribute__((packed));
|
|
|
|
static_assert(96 == sizeof(AddressSpace),
|
|
"Invalid packing of `struct AddressSpace`.");
|
|
|
|
// Named the same way as the 64-bit version to keep names the same
|
|
// across architectures. All registers are here, even the 64-bit ones. The
|
|
// 64-bit ones are not used in lifted 32-bit code.
|
|
struct alignas(8) GPR final {
|
|
|
|
// Prevents LLVM from casting a `GPR` into an `i64` to access `rax`.
|
|
volatile uint64_t _0;
|
|
Reg rax;
|
|
volatile uint64_t _1;
|
|
Reg rbx;
|
|
volatile uint64_t _2;
|
|
Reg rcx;
|
|
volatile uint64_t _3;
|
|
Reg rdx;
|
|
volatile uint64_t _4;
|
|
Reg rsi;
|
|
volatile uint64_t _5;
|
|
Reg rdi;
|
|
volatile uint64_t _6;
|
|
Reg rsp;
|
|
volatile uint64_t _7;
|
|
Reg rbp;
|
|
volatile uint64_t _8;
|
|
Reg r8;
|
|
volatile uint64_t _9;
|
|
Reg r9;
|
|
volatile uint64_t _10;
|
|
Reg r10;
|
|
volatile uint64_t _11;
|
|
Reg r11;
|
|
volatile uint64_t _12;
|
|
Reg r12;
|
|
volatile uint64_t _13;
|
|
Reg r13;
|
|
volatile uint64_t _14;
|
|
Reg r14;
|
|
volatile uint64_t _15;
|
|
Reg r15;
|
|
volatile uint64_t _16;
|
|
|
|
// Program counter of the CURRENT instruction!
|
|
Reg rip;
|
|
} __attribute__((packed));
|
|
|
|
static_assert(272 == sizeof(GPR), "Invalid structure packing of `GPR`.");
|
|
|
|
// Declare val as float80_t
|
|
struct alignas(16) X87Stack final {
|
|
struct alignas(16) {
|
|
uint8_t _[6];
|
|
float80_t val;
|
|
} __attribute__((packed)) elems[8];
|
|
};
|
|
|
|
|
|
static_assert(128 == sizeof(X87Stack),
|
|
"Invalid structure packing of `X87Stack`.");
|
|
|
|
struct alignas(8) MMX final {
|
|
struct alignas(8) {
|
|
uint64_t _0;
|
|
vec64_t val;
|
|
} __attribute__((packed)) elems[8];
|
|
};
|
|
|
|
struct alignas(8) K_REG final {
|
|
struct alignas(8) {
|
|
uint64_t _0;
|
|
uint64_t val;
|
|
} __attribute__((packed)) elems[8];
|
|
};
|
|
|
|
static_assert(128 == sizeof(MMX), "Invalid structure packing of `MMX`.");
|
|
|
|
enum : size_t { kNumVecRegisters = 32 };
|
|
|
|
struct alignas(16) X86State : public ArchState {
|
|
|
|
// ArchState occupies 16 bytes.
|
|
|
|
// AVX512 has 32 vector registers, so we always include them all here for
|
|
// consistency across the various state structures.
|
|
VectorReg vec[kNumVecRegisters]; // 2048 bytes.
|
|
|
|
// Two representations of flags. Makes it easy to convert from native-to-
|
|
// lifted, as well as improved the optimizability of the aflags themselves.
|
|
ArithFlags aflag; // 16 bytes.
|
|
Flags rflag; // 8 bytes.
|
|
Segments seg; // 24 bytes.
|
|
AddressSpace addr; // 96 bytes.
|
|
GPR gpr; // 272 bytes.
|
|
X87Stack st; // 128 bytes.
|
|
MMX mmx; // 128 bytes.
|
|
FPUStatusFlags sw; // 24 bytes
|
|
uint8_t _padding[8]; // 8 bytes
|
|
FPU x87; // 512 bytes
|
|
SegmentCaches seg_caches; // 96 bytes
|
|
K_REG k_reg; // 128 bytes.
|
|
} __attribute__((packed));
|
|
|
|
static_assert((96 + 3264 + 16 + 128) == sizeof(X86State),
|
|
"Invalid packing of `struct State`");
|
|
|
|
struct State : public X86State {};
|
|
|
|
union CR0Reg {
|
|
uint64_t flat;
|
|
struct {
|
|
uint64_t pe : 1;
|
|
uint64_t mp : 1;
|
|
uint64_t em : 1;
|
|
uint64_t ts : 1;
|
|
uint64_t et : 1;
|
|
uint64_t ne : 1;
|
|
uint64_t _rsvd0 : 10;
|
|
uint64_t wp : 1;
|
|
uint64_t _rsvd1 : 1;
|
|
uint64_t am : 1;
|
|
uint64_t _rsvd2 : 10;
|
|
uint64_t nw : 1;
|
|
uint64_t cd : 1;
|
|
uint64_t pg : 1;
|
|
uint64_t _rsvd3 : 32;
|
|
} __attribute__((packed));
|
|
} __attribute__((packed));
|
|
|
|
static_assert(8 == sizeof(CR0Reg), "Invalid packing of CR0Reg");
|
|
|
|
union CR1Reg {
|
|
uint64_t flat;
|
|
} __attribute__((packed));
|
|
|
|
static_assert(8 == sizeof(CR1Reg), "Invalid packing of CR1Reg");
|
|
|
|
union CR2Reg {
|
|
uint64_t flat;
|
|
addr_t linear_address;
|
|
} __attribute__((packed));
|
|
|
|
static_assert(8 == sizeof(CR2Reg), "Invalid packing of CR2Reg");
|
|
|
|
union CR3Reg {
|
|
uint64_t flat;
|
|
struct {
|
|
uint64_t _rsvd0 : 3;
|
|
uint64_t pwt : 1;
|
|
uint64_t pcd : 1;
|
|
uint64_t _rsvd1 : 7;
|
|
uint64_t page_dir_base : 52;
|
|
} __attribute__((packed));
|
|
} __attribute__((packed));
|
|
|
|
static_assert(8 == sizeof(CR3Reg), "Invalid packing of CR3Reg");
|
|
|
|
union CR4Reg {
|
|
uint64_t flat;
|
|
struct {
|
|
uint64_t vme : 1;
|
|
uint64_t pvi : 1;
|
|
uint64_t tsd : 1;
|
|
uint64_t de : 1;
|
|
uint64_t pse : 1;
|
|
uint64_t pae : 1;
|
|
uint64_t mce : 1;
|
|
uint64_t pge : 1;
|
|
uint64_t pce : 1;
|
|
uint64_t osfxsr : 1;
|
|
uint64_t osxmmexcpt : 1;
|
|
uint64_t umip : 1;
|
|
uint64_t _rsvd0 : 1;
|
|
uint64_t vmxe : 1;
|
|
uint64_t smxe : 1;
|
|
uint64_t _rsvd1 : 1;
|
|
uint64_t fsgsbase : 1;
|
|
uint64_t pcide : 1;
|
|
uint64_t osxsave : 1;
|
|
uint64_t _rsvd2 : 1;
|
|
uint64_t smep : 1;
|
|
uint64_t smap : 1;
|
|
uint64_t pke : 1;
|
|
uint64_t _rsvd3 : 9;
|
|
uint64_t _rsvd4 : 32;
|
|
} __attribute__((packed));
|
|
} __attribute__((packed));
|
|
|
|
static_assert(8 == sizeof(CR4Reg), "Invalid packing of CR4Reg");
|
|
|
|
union CR8Reg {
|
|
uint64_t flat;
|
|
struct {
|
|
uint64_t tpr : 4;
|
|
uint64_t _rsvd0 : 60;
|
|
} __attribute__((packed));
|
|
} __attribute__((packed));
|
|
|
|
static_assert(8 == sizeof(CR8Reg), "Invalid packing of CR8Reg");
|
|
|
|
#pragma clang diagnostic pop
|