The x86-64 architecture has quite a few such control registers. Most of them cannot be read without elevated privileges, those that can are marked. You might want to read this article for a detailed description on the bits in each register.
On Linux, you can obtain the relevant elevated privileges using the iopl system call. iopl(3) gives you all privileges you need.
- The flags register contains information about recent arithmetic operations as well as some configuration. It can be read with the
pushf instruction without special permissions. Read this article for more details.
- The segment registers
cs, ds, es, ss, fs, and gs contain segment selectors. On modern operating systems, these are usually fixed for all processes and can be read using mov r16,segr without elevated privileges.
- The cr0 register contains configuration pertaining memory protection. Its low 16 bits can be read by any process using the
rmsw instruction, the remaining bits can be read with elevated privileges using mov r32,cr0 as can all other control registers.
- The cr2 register contains the address of the last page fault.
- The cr3 register contains the address of the page directory.
- The cr4 register contains additional CPU configuration.
- The cr8 register contains information about task priority
There are also a bunch of model-specific registers which can be read with the rmsr instructions.
To read these registers, use inline assembly. Here is inline assembly for all registers previously mentioned. For reading the rflags register, also look at this question for some caveats.
/* read rflags */
uint64_t rflags;
asm("pushf; popf %0" : "=rm"(rflags));
/* read segment register, replace sr with the segment you want */
uint16_t seg;
asm("mov %sr,%0" : "=rm"(seg));
/* read low bits of cr0 */
/* on some CPUs, only the low 16 bits are correct,
/* on others all 32 bit are correct */
uint32_t cr0;
asm("smsw %0" : "=r"(cr0));
/* everything below here requires elevated privileges */
/* read control register, replace cr with register name */
uint64_t cr;
asm("mov %cr,%0" : "=rm"(cr));
/* read model specific register. msr contains register number */
uint32_t msr_no = 0xC0000080, msr_hi, msr_lo;
asm("rdmsr" : "=a"(msr_lo), "=d"(msr_hi) : "c"(msr_no));
uint64_t msr_val = (uint64_)msr_hi << 32 | msr_lo;