GCC complains about impossible constraints

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Yargh
Member
Member
Posts: 56
Joined: Sat Jun 12, 2010 9:04 pm
Location: Somewhere else.

GCC complains about impossible constraints

Post by Yargh »

Hello, I've recently been attempting to program my kernel to output the CPU's features using CPUID. I'm writing the cpuid-checking code in inline assembly with .intel_syntax noprefix.
The problem with that is, whenever I try to compile it...

Code: Select all

gcc -nostdlib -nostdinc -fno-builtin -fno-stack-protector -I../include -O0 -c cpuid.c -o cpuid.o
cpuid.c: In function ‘cpuid_print_features’:
cpuid.c:32: error: can't find a register in class ‘Q_REGS’ while reloading ‘asm’
cpuid.c:32: error: ‘asm’ operand has impossible constraints
Even though I'm using the -O0 option, it complains about constraints. Is it that using 24 outputs, 0 inputs, and 1 clobbered register is too much? I've done a search and the only relevant post that I found said that -O0 did nothing, and I did not see an answer for this problem.

Here's the code for cpuid.c:

Code: Select all

#include "video.h"
#include "common.h"
void cpuid_print_features(){
	u8int fpu;
	u8int vme;
	u8int de;
	u8int pse;
	u8int tsc;
	u8int msr;
	u8int pae;
	u8int mce;
	u8int cx8;
	u8int apic;
	//Bit 10 is reserved
	u8int sep;
	u8int mtrr;
	u8int pge;
	u8int mca;
	u8int cmov;
	u8int pat;
	u8int pse36;
	//Bits 18 to 22 not used for this purpose
	u8int mmx;
	u8int fxsr;
	u8int sse;
	u8int sse2;
	u8int sse3;
	u8int sse4_1;
	u8int sse4_2;
	
	printf("[INFO]-CPU Features: (");
	__asm__ volatile(".intel_syntax noprefix \
		mov eax, 1 \
		cpuid \
		and edx, 1 \
		cmp edx, 0 \
		jne fpu \
		pop edx \
		\
		push edx \
		shr edx, 1 \
		and edx, 1 \
		cmp edx, 0 \
		jne vme \
		pop edx \
		\
		push edx \
		shr edx, 2 \
		and edx, 1 \
		cmp edx, 0 \
		jne de \
		pop edx \
		\
		push edx \
		shr edx, 3 \
		and edx, 1 \
		cmp edx, 0 \
		jne pse \
		pop edx \
		\
		push edx \
		shr edx, 4 \
		and edx, 1 \
		cmp edx, 0 \
		jne tsc \
		pop edx \
		\
		push edx \
		shr edx, 5 \
		and edx, 1 \
		cmp edx, 0 \
		jne msr \
		pop edx \
		\
		push edx \
		shr edx, 6 \
		and edx, 1 \
		cmp edx, 0 \
		jne pae \
		pop edx \
		\
		push edx \
		shr edx, 7 \
		and edx, 1 \
		cmp edx, 0 \
		jne mce \
		pop edx \
		\
		push edx \
		shr edx, 8 \
		and edx, 1 \
		cmp edx, 0 \
		jne cx8 \
		pop edx \
		\
		push edx \
		shr edx, 9 \
		and edx, 1 \
		cmp edx, 0 \
		jne apic \
		pop edx \
		\
		push edx \
		shr edx, 11 \
		and edx, 1 \
		cmp edx, 0 \
		jne sep \
		pop edx \
		\
		push edx \
		shr edx, 12 \
		and edx, 1 \
		cmp edx, 0 \
		jne mtrr \
		pop edx \
		\
		push edx \
		shr edx, 13 \
		and edx, 1 \
		cmp edx, 0 \
		jne pge \
		pop edx \
		\
		push edx \
		shr edx, 14 \
		and edx, 1 \
		cmp edx, 0 \
		jne mca \
		pop edx \
		\
		push edx \
		shr edx, 15 \
		and edx, 1 \
		cmp edx, 0 \
		jne cmov \
		pop edx \
		\
		push edx \
		shr edx, 16 \
		and edx, 1 \
		cmp edx, 0 \
		jne pat \
		pop edx \
		\
		push edx \
		shr edx, 17 \
		and edx, 1 \
		cmp edx, 0 \
		jne pse36 \
		pop edx \
		\
		push edx \
		shr edx, 23 \
		and edx, 1 \
		cmp edx, 0 \
		jne mmx \
		pop edx \
		\
		push edx \
		shr edx, 24 \
		and edx, 1 \
		cmp edx, 0 \
		jne fxsr \
		pop edx \
		\
		fpu:\
			mov %0, 1\
		\
		vme:\
			mov %1, 1\
		\
		de:\
			mov %2, 1\
		\
		pse:\
			mov %3, 1\
		\
		tsc:\
			mov %4, 1\
		\
		msr:\
			mov %5, 1\
		\
		pae:\
			mov %6, 1\
		\
		mce:\
			mov %7, 1\
		\
		cx8:\
			mov %8, 1\
		\
		apic:\
			mov %9, 1\
		\
		sep:\
			mov %10, 1\
		\
		mtrr:\
			mov %11, 1\
		\
		pge:\
			mov %12, 1\
		\
		mca:\
			mov %13, 1\
		\
		cmov:\
			mov %14, 1\
		\
		pat:\
			mov %15, 1\
		\
		pse36:\
			mov %16, 1\
		\
		mmx:\
			mov %17, 1\
		\
		fxsr:\
			mov %18, 1\
		\
		sse:\
			mov %19, 1\
		\
		sse2:\
			mov %20, 1\
		\
		sse3:\
			mov %21, 1\
		\
		sse4_1:\
			mov %22, 1\
		\
		sse4_2:\
			mov %23, 1\
		\
		.att_syntax prefix\
		" : "=r"(fpu), "=r"(vme), "=r"(de), "=r"(pse), "=r"(tsc), "=r"(msr), "=r"(pae), "=r"(mce), "=r"(cx8),
		"=r"(apic), "=r"(sep), "=r"(mtrr), "=r"(pge), "=r"(mca), "=r"(cmov), "=r"(pat), "=r"(pse36), "=r"(mmx),
		"=r"(fxsr), "=r"(sse), "=r"(sse2), "=r"(sse3), "=r"(sse4_1), "=r"(sse4_2) : : "edx" );
		
		if(fpu == 1){
			printf(" FPU ");
		}
		
		printf(" )");

}

Note that I haven't yet added a check for if CPUID is supported, or support for SSE/2/3/4_1/4_2.

Any help would be appreciated.

EDIT: Adding a "%" before "edx" in the clobbered registers changes nothing.
Wait... What?
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: GCC complains about impossible constraints

Post by pcmattman »

Wouldn't it be a better idea to put the assembly in its own function in an assembly file somewhere, assembled with <assembler of choice that isn't GAS>? My "rule of thumb" is to move to an individual file once I go over 5-6 lines of assembly. There are exceptions where they can be written cleanly.

It'd save you a lot of pain, I think.
Yargh
Member
Member
Posts: 56
Joined: Sat Jun 12, 2010 9:04 pm
Location: Somewhere else.

Re: GCC complains about impossible constraints

Post by Yargh »

I'll try that and see if it works. I would like to know, however, why GCC complains about constraints with no optimization enabled.
Wait... What?
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: GCC complains about impossible constraints

Post by gerryg400 »

Aren't you running GCC out of registers ? I don't think it has 24 registers available.

In addition there are a couple of bugs in your code. Those jne's don't return so the first jne will cause all the flags beneath it to be set. The correct way to do this would be to do the cpuid and have output variables (eax, ebx, ecx and edx). The bit testing could then be done in c code. There is no reason to use assembler for that.
If a trainstation is where trains stop, what is a workstation ?
TylerH
Member
Member
Posts: 285
Joined: Tue Apr 13, 2010 8:00 pm
Contact:

Re: GCC complains about impossible constraints

Post by TylerH »

gerryg400 wrote:Aren't you running GCC out of registers ? I don't think it has 24 registers available.

In addition there are a couple of bugs in your code. Those jne's don't return so the first jne will cause all the flags beneath it to be set.
Why would all 24 outputs have to, or even need to be registers? EDIT: Nvm, I didn't know what "=r" meant.

Although I do agree the testing is better done in C.
Last edited by TylerH on Sun Sep 26, 2010 9:30 pm, edited 2 times in total.
froggey
Member
Member
Posts: 38
Joined: Tue Oct 17, 2006 10:21 pm
Location: Hampshire, UK

Re: GCC complains about impossible constraints

Post by froggey »

"=r" means "put this result into a GPR", you have 24 of them and x86 only has 8 GPRs (only 7 if you don't count esp). gcc isn't magic, so it can't fit 24 values into 8 registers. You could use the "=rm" constraint (put this result into either a GPR or a memory location) or you could wrap just the cpuid instruction and rewrite the tests in C, like so:

Code: Select all

void cpuid_print_features(){
   u32int eax, ebx, ecx, edx;
   
   printf("[INFO]-CPU Features: (");
   /* Invoke CPUID level 1 and put the results in the eax/ebx/ecx/edx variables */
   __asm__ volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "0"(1));
   if(edx & 1){
      printf(" FPU ");
   }
    /* etc */
    printf(" )");
}
Yargh
Member
Member
Posts: 56
Joined: Sat Jun 12, 2010 9:04 pm
Location: Somewhere else.

Re: GCC complains about impossible constraints

Post by Yargh »

Thanks. I followed pcmattman's instructions and put all the code into another file, and it actually works! (I did have to fix all the errors in the assembly code, tho)

Here's the code, just incase anyone wants it. It's probably incredibly inefficient, but I don't care at this point.

Code: Select all


[global cpuid_get_features]
[extern cpuid_fpu]
[extern cpuid_vme]
[extern cpuid_de]
[extern cpuid_pse]
[extern cpuid_tsc]
[extern cpuid_msr]
[extern cpuid_pae]
[extern cpuid_mce]
[extern cpuid_cx8]
[extern cpuid_apic]
[extern cpuid_sep]
[extern cpuid_mtrr]
[extern cpuid_pge]
[extern cpuid_mca]
[extern cpuid_cmov]
[extern cpuid_pat]
[extern cpuid_pse36]
[extern cpuid_mmx]
[extern cpuid_fxsr]
[extern cpuid_sse]
[extern cpuid_sse2]
[extern cpuid_sse3]
[extern cpuid_sse4_1]
[extern cpuid_sse4_2]

cpuid_get_features:
		mov eax, 1 
		cpuid 
		and edx, 1 
		cmp edx, 0 
		je NEXT1
		fpu: mov BYTE [cpuid_fpu], 1
		
		NEXT1:
		
		
		mov eax, 1 
		cpuid  
		shr edx, 1 
		and edx, 1 
		cmp edx, 0 
		je NEXT2 
		vme: mov BYTE [cpuid_vme], 1
		
		NEXT2:
		
		
		mov eax, 1 
		cpuid  
		shr edx, 2 
		and edx, 1 
		cmp edx, 0 
		je NEXT3
		de: mov BYTE [cpuid_de], 1

		NEXT3:
		
		
		mov eax, 1 
		cpuid  
		shr edx, 3 
		and edx, 1 
		cmp edx, 0 
		je NEXT4 
		pse: mov BYTE [cpuid_pse], 1

		NEXT4:
		

		mov eax, 1 
		cpuid  
		shr edx, 4 
		and edx, 1 
		cmp edx, 0 
		je NEXT5
		tsc: mov BYTE [cpuid_tsc], 1

		NEXT5:
		
		
		
		mov eax, 1 
		cpuid  
		shr edx, 5 
		and edx, 1 
		cmp edx, 0 
		je NEXT6 
		msr: mov BYTE [cpuid_msr], 1
		
		NEXT6:
		
		
		mov eax, 1 
		cpuid  
		shr edx, 6 
		and edx, 1 
		cmp edx, 0 
		je NEXT7
		pae: mov BYTE [cpuid_pae], 1
		
		NEXT7:
		
		
		mov eax, 1 
		cpuid  
		shr edx, 7 
		and edx, 1 
		cmp edx, 0 
		jne NEXT8
		mce: mov BYTE [cpuid_mce], 1
		
		NEXT8:
		
		
		
		mov eax, 1 
		cpuid  
		shr edx, 8 
		and edx, 1 
		cmp edx, 0 
		je NEXT9
		cx8: mov BYTE [cpuid_cx8], 1
		
		NEXT9:
		
		
		mov eax, 1 
		cpuid  
		shr edx, 9 
		and edx, 1 
		cmp edx, 0 
		je NEXT10
		apic: mov BYTE [cpuid_apic], 1
		
		NEXT10:
		
		
		mov eax, 1 
		cpuid  
		shr edx, 11 
		and edx, 1 
		cmp edx, 0 
		je NEXT11
		sep: mov BYTE [cpuid_sep], 1
		
		NEXT11:
		
		
		mov eax, 1 
		cpuid  
		shr edx, 12 
		and edx, 1 
		cmp edx, 0 
		je NEXT12
		mtrr: mov BYTE [cpuid_mtrr], 1
		
		NEXT12:
		
		
		mov eax, 1 
		cpuid  
		shr edx, 13 
		and edx, 1 
		cmp edx, 0 
		je NEXT13
		pge: mov BYTE [cpuid_pge], 1
		
		NEXT13:
		 
		
		mov eax, 1 
		cpuid  
		shr edx, 14 
		and edx, 1 
		cmp edx, 0 
		je NEXT14
		mca: mov BYTE [cpuid_mca], 1
		
		NEXT14:
		 
		
		mov eax, 1 
		cpuid  
		shr edx, 15 
		and edx, 1 
		cmp edx, 0 
		je NEXT15
		cmov: mov BYTE [cpuid_cmov], 1
		
		NEXT15:
		
		
		mov eax, 1 
		cpuid  
		shr edx, 16 
		and edx, 1 
		cmp edx, 0 
		je NEXT16
		pat: mov BYTE [cpuid_pat], 1
		
		NEXT16:
		
		
		mov eax, 1 
		cpuid  
		shr edx, 17 
		and edx, 1 
		cmp edx, 0 
		je NEXT17
		pse36: mov BYTE [cpuid_pse36], 1
		
		NEXT17:
		
		
		mov eax, 1 
		cpuid  
		shr edx, 23 
		and edx, 1 
		cmp edx, 0 
		je NEXT18
		mmx: mov BYTE [cpuid_mmx], 1
		
		NEXT18:
		
		
		mov eax, 1 
		cpuid  
		shr edx, 24 
		and edx, 1 
		cmp edx, 0 
		je NEXT19
		fxsr: mov BYTE [cpuid_fxsr], 1
		 
		NEXT19:
		
		
		mov eax, 1 
		cpuid 
		shr edx, 25
		and edx, 1
		cmp edx, 0
		je NEXT20
		sse: mov BYTE [cpuid_sse], 1
		
		NEXT20:
		
		
		mov eax, 1 
		cpuid 
		shr edx, 26
		and edx, 1
		cmp edx, 0
		je NEXT21
		sse2: mov BYTE [cpuid_sse2], 1
		
		NEXT21:
		
		
		mov eax, 1 
		cpuid 
		and ecx, 1
		cmp ecx, 0
		je NEXT22
		sse3: mov BYTE [cpuid_sse3], 1
		
		NEXT22:
		
		
		mov eax, 1 
		cpuid 
		shr ecx, 19
		and ecx, 1
		cmp ecx, 0
		je NEXT23
		sse4_1: mov BYTE [cpuid_sse4_1], 1
		
		NEXT23:
		
		
		mov eax, 1 
		cpuid 
		shr ecx, 20
		and ecx, 1
		cmp ecx, 0
		je NEXT24
		sse4_2: mov BYTE [cpuid_sse4_2], 1
		
		NEXT24:
		
		
	ret
Wait... What?
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: GCC complains about impossible constraints

Post by gerryg400 »

You're right, it's a bit inefficient. Do you know about the 'test' instruction ? It can test a bit without overwriting the operand. That means that edx/ecx won't be destroyed by the test and you won't need to keep calling cpuid. Also after a 'test' (or an 'and' for that matter) it's not necessary to do a 'cmp'. The zf is set or cleared already.
If a trainstation is where trains stop, what is a workstation ?
Post Reply