x86架构的CPU到底有多少个寄存器?
世界杯场地 5907 2025-05-29 20:11:37

这其实是个不明确的问题,问题的主语应该具体到每一颗不同型号的CPU上,而非一类架构的CPU集合。

众说纷纭的个数

刚开始学习计算机的时候看过如下类似的文章:

80X86寄存器详解

x86寄存器总结

英特尔CPU有哪些常用寄存器?

总之是说多少个的都有,14个,16个,32个,40个。后来在学习操作系统的时候,发现操作系统要使用都没听说过的寄存器,那x86上到底有多少寄存器呢?

bochs调试

在自己编写操作系统时,经常要用到bochs这个软件,是一个x86计算机的模拟器。其实在我们没有能力研究硬件本身时,比如我们不能把cpu拆开去数里面寄存器的个数时,研究硬件的模拟器是个非常好的选择。使用bochs的调试功能,有如下调试命令,功能均为查看寄存器状态:

info cpu

r

sreg

creg

我把断点打在0x7c00处,然后分别执行以上四种查看寄存器的命令:

b 0x7c00

c

info cpu

CPU0:

rax: 00000000_0000aa55 rcx: 00000000_00090000

rdx: 00000000_00000000 rbx: 00000000_00000000

rsp: 00000000_0000ffd6 rbp: 00000000_00000000

rsi: 00000000_000e0000 rdi: 00000000_0000ffac

r8 : 00000000_00000000 r9 : 00000000_00000000

r10: 00000000_00000000 r11: 00000000_00000000

r12: 00000000_00000000 r13: 00000000_00000000

r14: 00000000_00000000 r15: 00000000_00000000

rip: 00000000_00007c00

eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf

status word: 0x0000: b c3 TOS0 c2 c1 c0 es sf pe ue oe ze de ie

control word: 0x0040: inf RC_NEAREST PC_32 pm um om zm dm im

tag word: 0x5555

operand: 0x0000

fip: 0x0000000000000000

fcs: 0x0000

fdp: 0x0000000000000000

fds: 0x0000

=>FP0 ST0(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

FP1 ST1(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

FP2 ST2(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

FP3 ST3(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

FP4 ST4(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

FP5 ST5(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

FP6 ST6(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

FP7 ST7(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

MM[0]: 00000000_00000000

MM[1]: 00000000_00000000

MM[2]: 00000000_00000000

MM[3]: 00000000_00000000

MM[4]: 00000000_00000000

MM[5]: 00000000_00000000

MM[6]: 00000000_00000000

MM[7]: 00000000_00000000

The CPU doesn t support AVX state !

r

CPU0:

rax: 00000000_0000aa55 rcx: 00000000_00090000

rdx: 00000000_00000000 rbx: 00000000_00000000

rsp: 00000000_0000ffd6 rbp: 00000000_00000000

rsi: 00000000_000e0000 rdi: 00000000_0000ffac

r8 : 00000000_00000000 r9 : 00000000_00000000

r10: 00000000_00000000 r11: 00000000_00000000

r12: 00000000_00000000 r13: 00000000_00000000

r14: 00000000_00000000 r15: 00000000_00000000

rip: 00000000_00007c00

eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf

sreg

es:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1

Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed

cs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1

Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed

ss:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7

Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed

ds:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1

Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed

fs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1

Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed

gs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1

Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed

ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1

tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1

gdtr:base=0x00000000000f9a37, limit=0x30

idtr:base=0x0000000000000000, limit=0x3ff

creg

CR0=0x60000010: pg CD NW ac wp ne ET ts em mp pe

CR2=page fault laddr=0x0000000000000000

CR3=0x000000000000

PCD=page-level cache disable=0

PWT=page-level write-through=0

CR4=0x00000000: pke smap smep osxsave pcid fsgsbase smx vmx osxmmexcpt umip osfxsr pce pge mce pae pse de tsd pvi vme

CR8: 0x0

EFER=0x00000000: ffxsr nxe lma lme sce

原来有这么多的寄存器呀!除了r命令的结果是info cpu命令结果的前面部分,剩下的都是不同的,去重整理如下:

CPU0:

rax: 00000000_0000aa55 rcx: 00000000_00090000

rdx: 00000000_00000000 rbx: 00000000_00000000

rsp: 00000000_0000ffd6 rbp: 00000000_00000000

rsi: 00000000_000e0000 rdi: 00000000_0000ffac

r8 : 00000000_00000000 r9 : 00000000_00000000

r10: 00000000_00000000 r11: 00000000_00000000

r12: 00000000_00000000 r13: 00000000_00000000

r14: 00000000_00000000 r15: 00000000_00000000

rip: 00000000_00007c00

eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf

status word: 0x0000: b c3 TOS0 c2 c1 c0 es sf pe ue oe ze de ie

control word: 0x0040: inf RC_NEAREST PC_32 pm um om zm dm im

tag word: 0x5555

operand: 0x0000

fip: 0x0000000000000000

fcs: 0x0000

fdp: 0x0000000000000000

fds: 0x0000

=>FP0 ST0(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

FP1 ST1(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

FP2 ST2(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

FP3 ST3(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

FP4 ST4(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

FP5 ST5(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

FP6 ST6(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

FP7 ST7(0): raw 0x0000:0000000000000000 (0.0000000000) (ZERO)

MM[0]: 00000000_00000000

MM[1]: 00000000_00000000

MM[2]: 00000000_00000000

MM[3]: 00000000_00000000

MM[4]: 00000000_00000000

MM[5]: 00000000_00000000

MM[6]: 00000000_00000000

MM[7]: 00000000_00000000

The CPU doesn t support AVX state !

es:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1

Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed

cs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1

Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed

ss:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7

Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed

ds:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1

Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed

fs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1

Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed

gs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1

Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed

ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1

tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1

gdtr:base=0x00000000000f9a37, limit=0x30

idtr:base=0x0000000000000000, limit=0x3ff

CR0=0x60000010: pg CD NW ac wp ne ET ts em mp pe

CR2=page fault laddr=0x0000000000000000

CR3=0x000000000000

PCD=page-level cache disable=0

PWT=page-level write-through=0

CR4=0x00000000: pke smap smep osxsave pcid fsgsbase smx vmx osxmmexcpt umip osfxsr pce pge mce pae pse de tsd pvi vme

CR8: 0x0

EFER=0x00000000: ffxsr nxe lma lme sce

当然可以看到这里的寄存器是x86_64下的,这里查出来是58个。

qemu的结构体

既然说模拟器,那肯定少不了qemu!是这篇文章给我启发:Qemu对内部寄存器的模拟,去找了CPUX86State这个结构体:

https://github.com/qemu/qemu/blob/master/target/i386/cpu.h

typedef struct CPUX86State {

/* standard registers */

target_ulong regs[CPU_NB_REGS];

target_ulong eip;

target_ulong eflags; /* eflags register. During CPU emulation, CC

flags and DF are set to zero because they are

stored elsewhere */

/* emulator internal eflags handling */

target_ulong cc_dst;

target_ulong cc_src;

target_ulong cc_src2;

uint32_t cc_op;

int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */

uint32_t hflags; /* TB flags, see HF_xxx constants. These flags

are known at translation time. */

uint32_t hflags2; /* various other flags, see HF2_xxx constants. */

/* segments */

SegmentCache segs[6]; /* selector values */

SegmentCache ldt;

SegmentCache tr;

SegmentCache gdt; /* only base and limit are used */

SegmentCache idt; /* only base and limit are used */

target_ulong cr[5]; /* NOTE: cr1 is unused */

int32_t a20_mask;

BNDReg bnd_regs[4];

BNDCSReg bndcs_regs;

uint64_t msr_bndcfgs;

uint64_t efer;

/* Beginning of state preserved by INIT (dummy marker). */

struct {} start_init_save;

/* FPU state */

unsigned int fpstt; /* top of stack index */

uint16_t fpus;

uint16_t fpuc;

uint8_t fptags[8]; /* 0 = valid, 1 = empty */

FPReg fpregs[8];

/* KVM-only so far */

uint16_t fpop;

uint64_t fpip;

uint64_t fpdp;

/* emulator internal variables */

float_status fp_status;

floatx80 ft0;

float_status mmx_status; /* for 3DNow! float ops */

float_status sse_status;

uint32_t mxcsr;

ZMMReg xmm_regs[CPU_NB_REGS == 8 ? 8 : 32];

ZMMReg xmm_t0;

MMXReg mmx_t0;

XMMReg ymmh_regs[CPU_NB_REGS];

uint64_t opmask_regs[NB_OPMASK_REGS];

YMMReg zmmh_regs[CPU_NB_REGS];

ZMMReg hi16_zmm_regs[CPU_NB_REGS];

/* sysenter registers */

uint32_t sysenter_cs;

target_ulong sysenter_esp;

target_ulong sysenter_eip;

uint64_t star;

uint64_t vm_hsave;

#ifdef TARGET_X86_64

target_ulong lstar;

target_ulong cstar;

target_ulong fmask;

target_ulong kernelgsbase;

#endif

uint64_t tsc;

uint64_t tsc_adjust;

uint64_t tsc_deadline;

uint64_t tsc_aux;

uint64_t xcr0;

uint64_t mcg_status;

uint64_t msr_ia32_misc_enable;

uint64_t msr_ia32_feature_control;

uint64_t msr_fixed_ctr_ctrl;

uint64_t msr_global_ctrl;

uint64_t msr_global_status;

uint64_t msr_global_ovf_ctrl;

uint64_t msr_fixed_counters[MAX_FIXED_COUNTERS];

uint64_t msr_gp_counters[MAX_GP_COUNTERS];

uint64_t msr_gp_evtsel[MAX_GP_COUNTERS];

uint64_t pat;

uint32_t smbase;

uint64_t msr_smi_count;

uint32_t pkru;

uint32_t tsx_ctrl;

uint64_t spec_ctrl;

uint64_t virt_ssbd;

/* End of state preserved by INIT (dummy marker). */

struct {} end_init_save;

uint64_t system_time_msr;

uint64_t wall_clock_msr;

uint64_t steal_time_msr;

uint64_t async_pf_en_msr;

uint64_t pv_eoi_en_msr;

uint64_t poll_control_msr;

/* Partition-wide HV MSRs, will be updated only on the first vcpu */

uint64_t msr_hv_hypercall;

uint64_t msr_hv_guest_os_id;

uint64_t msr_hv_tsc;

/* Per-VCPU HV MSRs */

uint64_t msr_hv_vapic;

uint64_t msr_hv_crash_params[HV_CRASH_PARAMS];

uint64_t msr_hv_runtime;

uint64_t msr_hv_synic_control;

uint64_t msr_hv_synic_evt_page;

uint64_t msr_hv_synic_msg_page;

uint64_t msr_hv_synic_sint[HV_SINT_COUNT];

uint64_t msr_hv_stimer_config[HV_STIMER_COUNT];

uint64_t msr_hv_stimer_count[HV_STIMER_COUNT];

uint64_t msr_hv_reenlightenment_control;

uint64_t msr_hv_tsc_emulation_control;

uint64_t msr_hv_tsc_emulation_status;

uint64_t msr_rtit_ctrl;

uint64_t msr_rtit_status;

uint64_t msr_rtit_output_base;

uint64_t msr_rtit_output_mask;

uint64_t msr_rtit_cr3_match;

uint64_t msr_rtit_addrs[MAX_RTIT_ADDRS];

/* exception/interrupt handling */

int error_code;

int exception_is_int;

target_ulong exception_next_eip;

target_ulong dr[8]; /* debug registers; note dr4 and dr5 are unused */

union {

struct CPUBreakpoint *cpu_breakpoint[4];

struct CPUWatchpoint *cpu_watchpoint[4];

}; /* break/watchpoints for dr[0..3] */

int old_exception; /* exception in flight */

uint64_t vm_vmcb;

uint64_t tsc_offset;

uint64_t intercept;

uint16_t intercept_cr_read;

uint16_t intercept_cr_write;

uint16_t intercept_dr_read;

uint16_t intercept_dr_write;

uint32_t intercept_exceptions;

uint64_t nested_cr3;

uint32_t nested_pg_mode;

uint8_t v_tpr;

/* KVM states, automatically cleared on reset */

uint8_t nmi_injected;

uint8_t nmi_pending;

uintptr_t retaddr;

/* Fields up to this point are cleared by a CPU reset */

struct {} end_reset_fields;

/* Fields after this point are preserved across CPU reset. */

/* processor features (e.g. for CPUID insn) */

/* Minimum cpuid leaf 7 value */

uint32_t cpuid_level_func7;

/* Actual cpuid leaf 7 value */

uint32_t cpuid_min_level_func7;

/* Minimum level/xlevel/xlevel2, based on CPU model + features */

uint32_t cpuid_min_level, cpuid_min_xlevel, cpuid_min_xlevel2;

/* Maximum level/xlevel/xlevel2 value for auto-assignment: */

uint32_t cpuid_max_level, cpuid_max_xlevel, cpuid_max_xlevel2;

/* Actual level/xlevel/xlevel2 value: */

uint32_t cpuid_level, cpuid_xlevel, cpuid_xlevel2;

uint32_t cpuid_vendor1;

uint32_t cpuid_vendor2;

uint32_t cpuid_vendor3;

uint32_t cpuid_version;

FeatureWordArray features;

/* Features that were explicitly enabled/disabled */

FeatureWordArray user_features;

uint32_t cpuid_model[12];

/* Cache information for CPUID. When legacy-cache=on, the cache data

* on each CPUID leaf will be different, because we keep compatibility

* with old QEMU versions.

*/

CPUCaches cache_info_cpuid2, cache_info_cpuid4, cache_info_amd;

/* MTRRs */

uint64_t mtrr_fixed[11];

uint64_t mtrr_deftype;

MTRRVar mtrr_var[MSR_MTRRcap_VCNT];

/* For KVM */

uint32_t mp_state;

int32_t exception_nr;

int32_t interrupt_injected;

uint8_t soft_interrupt;

uint8_t exception_pending;

uint8_t exception_injected;

uint8_t has_error_code;

uint8_t exception_has_payload;

uint64_t exception_payload;

uint32_t ins_len;

uint32_t sipi_vector;

bool tsc_valid;

int64_t tsc_khz;

int64_t user_tsc_khz; /* for sanity check only */

#if defined(CONFIG_KVM) || defined(CONFIG_HVF)

void *xsave_buf;

#endif

#if defined(CONFIG_KVM)

struct kvm_nested_state *nested_state;

#endif

#if defined(CONFIG_HVF)

HVFX86EmulatorState *hvf_emul;

#endif

uint64_t mcg_cap;

uint64_t mcg_ctl;

uint64_t mcg_ext_ctl;

uint64_t mce_banks[MCE_BANKS_DEF*4];

uint64_t xstate_bv;

/* vmstate */

uint16_t fpus_vmstate;

uint16_t fptag_vmstate;

uint16_t fpregs_format_vmstate;

uint64_t xss;

uint32_t umwait;

TPRAccess tpr_access_type;

unsigned nr_dies;

} CPUX86State;

查不过来,反正很多…不过可以看出,对于x86架构的CPU,具体到每一颗CPU上,功能不同,其所拥有的寄存器也不同。

不止我问

还是得查英文资料,有人问,也有人答:

How many registers does an x86_64 CPU actually have?

https://en.wikipedia.org/wiki/X86#x86_registers

就像如上回答所说,已知寄存器的个数实际很多,而且的确存在没有公开的寄存器。那他们在做着什么不为人知的事呢?

Copyright © 2022 98世界杯_乌拉圭世界杯 - cy078.com All Rights Reserved.