Bizarre String-Printing Behavior

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.
Puffy
Member
Member
Posts: 26
Joined: Mon May 26, 2008 7:00 am

Bizarre String-Printing Behavior

Post by Puffy »

(Sorry for making a new thread quite so soon after my last).

I've knocked together a quick function to get the CPU vendor using the CPUID instruction, but a few things about it are a bit strange.

Edit: I don't want the function its self to print the vendor string, I want to return the vendor string so I'm able to print myself elsewhere, that's why the function is as such.

Here's the function:

Code: Select all

char *getCPUVendor(char *rtn)
{
		asm(
		".intel_syntax noprefix;"
		"mov eax,0;"
		"cpuid;"
		"mov [%0],ebx;" 
		"mov [%0+4],edx;"
		"mov [%0+8],ecx;"
		"movb [%0+12],0;"
		".att_syntax;" : "=r" (rtn)
		);
               //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		//int t;
		//for (t = 0; t< 13;t++){
		//	printCharacter(*(rtn+t));
		//}
               //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	return rtn;
}
I call it from my main function like so:

Code: Select all

#include <screen.h>
#include <cpuid.h>

void kmain( void* mbd, unsigned int magic )
{
	initScreen();
	char vendor[13];
	char *ptr = vendor;
	ptr = getCPUVendor(ptr);
	printString("SEPARATOR");
	printString(ptr);
	for(;;);
}
Now, when I boot my kernel with the code set up like this, all that is printed is "SEPARATOR" BUT if I uncomment the section in between the two lines of exclamation marks the correct vendor string is printed twice (once by the loop in the getCPUVendor() function and once by the printString(ptr) call in the main function).

I cannot understand why that section in the getCPUVendor() function makes a difference.

Here's the printString() and printCharacter() functions.

Code: Select all


void printCharacter(unsigned char character)
{
	if (character == '\b'){
		if (pos_x != 0){
			pos_x--;
		}
	}else if (character == '\t'){
		 pos_x = (pos_x + 8) & ~(8 - 1);
	}else if (character == '\r'){
		pos_x = 0;
	}else if (character == '\n'){
		pos_y++;
	}else if (character == '\a'){
	}else{
			short offset = calculateOffset(pos_x,pos_y);
			unsigned short output = constructOutputShort(character);
			buffer[offset] = output;
			pos_x++;
	}
	scroll();
} 

void printString(const char *string)
{
	int stringLength = strlen(string);
	const char *strPointer = (const char *)string;
	for(; stringLength > 0; stringLength--){
		printCharacter(*strPointer++);
	}
}
I cannot see a reason why this behaviour occurs! Can anyone help?

Cheers,

Puff

P.S. I know I'm asking a lot of questions on this forum, but every answer I get really helps me learn. Thank You all very much!
User avatar
Alboin
Member
Member
Posts: 1466
Joined: Thu Jan 04, 2007 3:29 pm
Location: Noricum and Pannonia

Re: Bizarre String-Printing Behavior

Post by Alboin »

Hi,

Try making the array global.

OT:

In C, when you pass a variable to a function, a copy of that variable is passed, not the actual variable. Thus:

Code: Select all

void printString(const char *string)
{
   int stringLength = strlen(string);
   const char *strPointer = (const char *)string;
   for(; stringLength > 0; stringLength--){
      printCharacter(*strPointer++);
   }
}
Could much easily be written as:

Code: Select all

void printString(char *string)
{
   while(*string != '\0') {
      printCharacter(*string++);
   }
}
This is why pointers are used so much in C.

*Note: strlen goes through the string until it encounters a \0. You can save yourself a variable, and an instruction or two, by simply checking yourself.

Toodles,
Alboin
Last edited by Alboin on Wed Jul 23, 2008 9:10 pm, edited 3 times in total.
C8H10N4O2 | #446691 | Trust the nodes.
User avatar
Adek336
Member
Member
Posts: 129
Joined: Thu May 12, 2005 11:00 pm
Location: Kabaty, Warszawa
Contact:

Re: Bizarre String-Printing Behavior

Post by Adek336 »

as a quick debug:
if uncomenting

Code: Select all

               //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      //int t;
      //for (t = 0; t< 13;t++){
      //   printCharacter(*(rtn+t));
      //}
               //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
changes the behaviour of the program, I'd check what is the outcome after changing the loop to things such as

Code: Select all

      int t;
      for (t = 0; t< 13;t++){
      // choose one:
      //   printCharacter(*(rtn+0));
      //   printCharacter('A');
      //   do nothing
      //   *(rtn+t);
      }
Puffy
Member
Member
Posts: 26
Joined: Mon May 26, 2008 7:00 am

Re: Bizarre String-Printing Behavior

Post by Puffy »

Thanks for your adivce Alboin, I've updated my printString() function to match your example and I've stopped returning a value from getCPUVendor(). With the updated printString() function the vendor string does not print at all, even after uncommenting the block within getCPUVendor(). That makes me even more confused!

My code now looks like this:

getCPUVendor()

Code: Select all

void getCPUVendor(char *rtn)
{
		asm(
		".intel_syntax noprefix;"
		"mov eax,0;"
		"cpuid;"
		"mov [%0],ebx;" 
		"mov [%0+4],edx;"
		"mov [%0+8],ecx;"
		"movb [%0+12],0;"
		".att_syntax;" : "=r" (rtn)
		);
		//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                //int t;
		//for (t = 0; t<13;t++){
		//	printCharacter(*(rtn+t));
		//}
               //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}
printString()

Code: Select all

void printString(char *string)
{
	while (*string != '\0'){
		printCharacter(*(string++));
	}
}
kmain()

Code: Select all

#include <screen.h>
#include <cpuid.h>

void kmain( void* mbd, unsigned int magic )
{
	initScreen();
	char vendor[13];
	char *ptr = vendor;
	getCPUVendor(ptr);
	printString("SEPERATOR");
	printString(ptr);
	for(;;);
}
As for the debugs suggested by Adek336, nothing else gets the vendor string printed than my original commented block

Edit: Interestingly, if I call printString(rtn); from inside getCPUVendor() then the string continues to print forever (i.e. the null character is never found).

Edit2: More interstingly, if you keep the commented section commented and move the same code to the main function:

Code: Select all

#include <screen.h>
#include <cpuid.h>

void kmain( void* mbd, unsigned int magic )
{
	initScreen();
	if (isCPUIDSupported()){
		printString("CPUID is supported.");
	}else{
		printString("CPUID is not supported.");
	}
	char vendor[13];
	char *ptr = vendor;
	getCPUVendor(ptr);
	printString("SEPERATOR");
	//printString(ptr);
	int t;
	for (t = 0; t<13;t++){
		printCharacter(*(ptr+t));
	}
	for(;;);
}
Nothing is printed there either.
Last edited by Puffy on Wed Jul 23, 2008 9:40 pm, edited 2 times in total.
User avatar
Alboin
Member
Member
Posts: 1466
Joined: Thu Jan 04, 2007 3:29 pm
Location: Noricum and Pannonia

Re: Bizarre String-Printing Behavior

Post by Alboin »

Change your last asm line to ".att_syntax;" :: "r" (rtn)". #-o The register is an input operand, not an output.
C8H10N4O2 | #446691 | Trust the nodes.
Puffy
Member
Member
Posts: 26
Joined: Mon May 26, 2008 7:00 am

Re: Bizarre String-Printing Behavior

Post by Puffy »

Nope, that doesn't help either. The kernel keeps printing nothing forever.
User avatar
Alboin
Member
Member
Posts: 1466
Joined: Thu Jan 04, 2007 3:29 pm
Location: Noricum and Pannonia

Re: Bizarre String-Printing Behavior

Post by Alboin »

Try your old printstring.

I'm not sure what the problem is. This works on my Linux box:

Code: Select all

void getCPUVendor(char *rtn) {
	asm(
	".intel_syntax noprefix;"
	"movb [%0], 'a';"
	"movb [%0+1],'b';"
	"movb [%0+2],'c';"
	"movb [%0+3],0;"
	".att_syntax;" :: "r" (rtn));
}

void printString(char *string) {
	while (*string != '\0')
		printf("%c", *string++);
}

void main() {
	char vendor[13];
	getCPUVendor(vendor);
	printString(vendor);
}
It prints 'abc'.
Last edited by Alboin on Wed Jul 23, 2008 9:45 pm, edited 1 time in total.
C8H10N4O2 | #446691 | Trust the nodes.
Puffy
Member
Member
Posts: 26
Joined: Mon May 26, 2008 7:00 am

Re: Bizarre String-Printing Behavior

Post by Puffy »

Using my original printString():

i. The string is not printed from the kmain() function.
ii. If you try to print rtn from getCPUVendor() then it does print there but still does not print from kmain

Edit: Your code also works on my linux box.
This problem is driving me around the bend.
User avatar
Alboin
Member
Member
Posts: 1466
Joined: Thu Jan 04, 2007 3:29 pm
Location: Noricum and Pannonia

Re: Bizarre String-Printing Behavior

Post by Alboin »

I feel like I'm the blind leading the blind.

Making the variable global doesn't work wither then? It does sound like a local array\stack problem, but I can't put my finger on it...
C8H10N4O2 | #446691 | Trust the nodes.
Puffy
Member
Member
Posts: 26
Joined: Mon May 26, 2008 7:00 am

Re: Bizarre String-Printing Behavior

Post by Puffy »

Edit: I said 'local' when I meant 'global' below, so changed it.

Making vendor global (I put 'char vendor[13]' in cpuid.h) didn't help either. :/
User avatar
thepowersgang
Member
Member
Posts: 734
Joined: Tue Dec 25, 2007 6:03 am
Libera.chat IRC: thePowersGang
Location: Perth, Western Australia
Contact:

Re: Bizarre String-Printing Behavior

Post by thepowersgang »

Just a comment on the code:
The getCPUVendor function need not return the string as the buffer is passed as a pointer.

Also in C arrays and pointers are the same so

Code: Select all

char buf[13];
getCPUVendor(buf);
printString(buf);
should work.

EDIT: putting a global in a header is a bad idea.
Better to put it in a source file and then put

Code: Select all

extern char vendor[];
in the header.
Last edited by thepowersgang on Wed Jul 23, 2008 10:06 pm, edited 1 time in total.
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
Puffy
Member
Member
Posts: 26
Joined: Mon May 26, 2008 7:00 am

Re: Bizarre String-Printing Behavior

Post by Puffy »

Thank you, that has already been pointed out and I've modified the code to reflect the suggestion. It's still all broke and stuff :)

Edit: Implemented the global as above - the string still wasn't printed, but my kernel didn't print nothing forever.

Edit2:

Maybe it's to do with my compiler flags?

gcc Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o

Edit3:

Earlier Alboin posted the following code:

Code: Select all

void getCPUVendor(char *rtn) {
   asm(
   ".intel_syntax noprefix;"
   "movb [%0], 'a';"
   "movb [%0+1],'b';"
   "movb [%0+2],'c';"
   "movb [%0+3],0;"
   ".att_syntax;" :: "r" (rtn));
}

void printString(char *string) {
   while (*string != '\0')
      printf("%c", *string++);
}

void main() {
   char vendor[13];
   getCPUVendor(vendor);
   printString(vendor);
}
I compiled it as a stand-alone project and it worked. I just tried replacing his test getCPUVendor() function with mine and the code failed. Thus there is a problem with my implementation of getCPUVender() although I still don't know what it is.
User avatar
Alboin
Member
Member
Posts: 1466
Joined: Thu Jan 04, 2007 3:29 pm
Location: Noricum and Pannonia

Re: Bizarre String-Printing Behavior

Post by Alboin »

I compiled it as a stand-alone project and it worked. I just tried replacing his test getCPUVendor() function with mine and the code failed. Thus there is a problem with my implementation of getCPUVender() although I still don't know what it is.
Do you mean my getCPUVendor failed when you switched it in? If mine failed, your problem is elsewhere. (Considering it works on a normal box.)
C8H10N4O2 | #446691 | Trust the nodes.
Puffy
Member
Member
Posts: 26
Joined: Mon May 26, 2008 7:00 am

Re: Bizarre String-Printing Behavior

Post by Puffy »

To clarify:

I copy/pasted your code exactly and compiled it on its own (I used stdio.h) and it ran perfectly. I then replaced the dummy getCPUVendor() function that you wrote (the one that puts abc into the char array) with my own, recompiled, and the code failed (nothing was printed).

Edit:

I've knocked together the following test code. If you uncomment the getCPUVendor() line in the main() function nothing gets printed to the screen at all.

This bug is one of the strangest I have ever encountered. :/

Code: Select all

#include <stdio.h>

void test(char *rtn)
{
	unsigned int input = 0;
	unsigned int first, second, third;
	asm volatile("cpuid;" : "=b"(first),"=d"(second),"=c"(third): "a"(input));
	rtn[0] = first;
	rtn[1] = first >> 8;
	rtn[2] = first >> 16;
	rtn[3] = first >> 24;
	rtn[4] = second >> 0;
	rtn[5] = second >> 8;
	rtn[6] = second >> 16;
	rtn[7] = second >> 24;
	rtn[8] = third >> 0;
	rtn[9] = third >> 8;
	rtn[10] = third >> 16;
	rtn[11] = third >> 24;
	rtn[12] = '\0';
	
}

void getCPUVendor(char *rtn)
{
		asm volatile(
		".intel_syntax noprefix;"
		"mov eax,0;"
		"cpuid;"
		"mov [%0],ebx;" 
		"mov [%0+4],edx;"
		"mov [%0+8],ecx;"
		"movb [%0+12],0;"
		".att_syntax;" : "=r" (rtn)
		);
}

void printString(char *string) {
   while (*string != '\0')
      printf("%c", *string++);
}

void main() {
   char vendor[13];
   test(vendor);
   printString(vendor);
   //getCPUVendor(vendor);
   //printf(vendor);
}

jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: Bizarre String-Printing Behavior

Post by jnc100 »

Perhaps its a problem with you not specifying the clobber list?

Code: Select all

...
".att_syntax;" : : "r" (rtn) : "a", "b", "c", "d" );
Regards,
John.
Post Reply