extern c declarations

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
Candamir

extern c declarations

Post by Candamir »

I've got a little problem with some tutorial code on Bona Fide: I'm looking at the 'Implementing Basic Paging' tutorial and I've integrated the NASM functions, but now I have to declare them in my C file as extern ..... The point is that I'm not very good at assembler and the full code of the tutorial isn't available, so I'm stuck trying to figure out return values and parameters. Here's the memory_asm.asm file:

Code: Select all

[global _read_cr0]
_read_cr0:
   mov eax, cr0
   retn

[global _write_cr0]
_write_cr0:
   push ebp
   mov ebp, esp
   mov eax, [ebp+8]
   mov cr0,  eax
   pop ebp
   retn

[global _read_cr3]
_read_cr3:
   mov eax, cr3
   retn

[global _write_cr3]
_write_cr3:
   push ebp
   mov ebp, esp
   mov eax, [ebp+8]
   mov cr3, eax
   pop ebp
   retn
I just don't know how to figure out the return types and parameters...

Thanks,

Candamir
OZ

Re:extern c declarations

Post by OZ »

hi,
to figure out what you need to declare you need to have a look at which registers are involved.
First of all C expects return Values in eax (I think edx aswell if its 64 bit ?!?) Therefore you got to look how much of the register is involved.
If it's EAX then you will have to declare a type that's 4 byte wide (long or a pointer).
If it was moved in AX then it is 2 Bytes wide (short).
If it is AL then it is just one byte (char).

For passing parameters it's the same. As the assembler just cares about how large the registers are you're working on and not how the stuff in them is interpreted by you, you're done by simply putting data types that are sufficient in size.
(This is definetely a very simplified view so plz it's just to show the point)

Therefore it is up to you if you declare a 4 byte wide return value to be a char* or a [unsigned] long - it's just like reducing casts later on ;)

Code: Select all

extern unsigned long read_cr0(void);
The rest is up to you for practice :)

hope it helps!
Candamir

Re:extern c declarations

Post by Candamir »

Now I use these declarations:

Code: Select all

extern unsigned long read_cr0(void);
extern void write_cr0(unsigned long);
extern unsigned long read_cr3(void);
extern void write_cr3(unsigned long);
The kernel now compiles, but it gives out warnings:

memory.c: In function `enable_paging':
memory.c:45: warning: assignment makes integer from pointer without a cast
memory.c:54: warning: passing arg 1 of `write_cr3' makes integer from pointer without a cast

The code for my function is:

Code: Select all

void enable_paging()
{
   unsigned long *page_directory = (unsigned long *)0x9C00;
   unsigned long *page_table     = (unsigned long *)0x9D00;
   unsigned long address         = 0;
   unsigned int  i;
   
   //Map first 4MB of memory
   for (i = 0; i < 1024; i++)
   {
      page_table[i] = address | 3;
      address = address + 4096;
   };
   
   // fill the first entry of the page directory
!!Line 45:   page_directory[0] = page_table;
   page_directory[0] = page_directory[0] | 3; // supervisor level, read/write, present
   
   // Fill in the other 1023 entries
   for (i = 1; i < 1024; i++)
   {
      page_directory[i] = 0 | 2; // supervisor level, read/write, not present
   };
   
!!Line 54:   write_cr3(page_directory); // page directory address into CR3
   write_cr0(read_cr0() | 0x80000000); // set paging bit in CRO to 1
}
The read_cr0() extern declaration works fine, thanks.

I mean, the arguments *must* be unsigned long, mustn't they? A char * pointer wouldn't make sense at all... I've already tried changing the argument to unsigned long *, but it just produced more warnings than before...

Candamir
Candamir

Re:extern c declarations

Post by Candamir »

Actually, I changed write_cr3(unsigned long) to write_cr3(unsigned long *) and the warning from line 54 disappeared, but warning on line 45 still remains there, I'm now checking if it has anything to do with extern declarations, because when I did the same as above with write_cr0, it produced more warnings... Have to go now, will return in a few hours and write the rest

Candamir
OZ

Re:extern c declarations

Post by OZ »

hi there,
thats the casts I talked about. Look it's like this: You tell the compiler to expect a unsigned long for example, but it gets a pointer. Therefore it complains although it'll work as for the assembler part it doesn't matter if it was a ptr or a long aslong as the correct value gets popped off the stack.

Instead of rearranging the whole code to avoid this warning, you should learn about casts. (I'm no C guru so my explanation may be imprecise but you will get the point)
By casting types you can tell the compiler that you want to convert to a certain type.

For line 45:
page_directory is a long pointer. But if you use an index it is like you're referencing the pointer. That means it is expecting a long.
Therefore you've got to cast page_table to be a long, as it is normally declared to be a ptr type aswell.

Code: Select all

page_directory[0] = (unsigned long)page_table;
Therefore you put the desired target type in a bracket before the variable you wish to cast.

Now line 54 is again up to you as training ;D

btw.: plz mind the addresses you use for your page_dirs and tables. I don't have a clue about the whole cmos mem map but your addresses there might be reserved already. (looks like you missed one zero from original tutorial)

hope it helps
hendric

Re:extern c declarations

Post by hendric »

Is it well linked?I've been told that the underscore prefix is something specific to M$'s compiler.
Candamir

Re:extern c declarations

Post by Candamir »

Thank you all.

Hendric, yes, gcc (djgpp) does use underscores. Thank you anyway.
OZ, thank you again. I've fixed line 54 already before, now my function declarations are:

Code: Select all

extern unsigned long read_cr0(void);
extern void write_cr0(unsigned long);
extern unsigned long read_cr3(void);
extern void write_cr3(unsigned long *);
If I added * also to write_cr0, the compiler would again tell me that something's wrong (well, it's only warnings, actually). I did knew about casts before, but I didn't knew I could just use them without any further preparation, that is, modifying data, etc.

And yes, to the addresses, I've already noticed that... I added the function to the initialisation process and the computer reset, although I had ISR's installed and they did work for division by 0... Anyone knows why? But thank you, you saved quite a bit of my time by giving me the hint. I'll try it out in a few minutes.

Thank you,

Candamir
Candamir

Final post

Post by Candamir »

In order to finish this post (although there's still the question: why does the isr didn't work), I'm placing all my code here:

Code: Select all

extern unsigned long read_cr0(void);
extern void write_cr0(unsigned long);
extern unsigned long read_cr3(void);
extern void write_cr3(unsigned long *);

void enable_paging()
{
   unsigned long *page_directory = (unsigned long *)0x9C000;
   unsigned long *page_table     = (unsigned long *)0x9D000;
   unsigned long address         = 0;
   unsigned int  i;
   
   //Map first 4MB of memory
   for (i = 0; i < 1024; i++)
   {
      page_table[i] = address | 3;
      address = address + 4096;
   };
   
   // fill the first entry of the page directory
   page_directory[0] = (unsigned long)page_table;
   page_directory[0] = page_directory[0] | 3; // supervisor level, read/write, present
   
   // Fill in the other 1023 entries
   for (i = 1; i < 1024; i++)
   {
      page_directory[i] = 0 | 2; // supervisor level, read/write, not present
   };
   
   write_cr3(page_directory); // page directory address into CR3
   write_cr0(read_cr0() | 0x80000000); // set paging bit in CRO to 1
}
Hope it helps, there's also another post about missing sources of this specific tutorial, here it is.

Please note that there still is much to do, with the mapping, the work isn't done at all. I myself am exactly at this point and I'm now reading Memory Management 1 & 2 from Tim Robinson.

Candamir
OZ

Re:extern c declarations

Post by OZ »

one last thing ...
I don't know why you don't seem to get an error on this.
But why can you declare functions with a parameter type but no name for the parameter itself? I just tested it myself and I get a 'parameter name omitted'.
should be ...

Code: Select all

extern unsigned long read_cr0(void);
extern void write_cr0(unsigned long cr0);
extern unsigned long read_cr3(void);
extern void write_cr3(unsigned long *cr3);
For the isr - did you test it with division through zero and stuff like that before?
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:extern c declarations

Post by Solar »

OZ wrote: one last thing ...
I don't know why you don't seem to get an error on this.
But why can you declare functions with a parameter type but no name for the parameter itself? I just tested it myself and I get a 'parameter name omitted'.
Actually, it's your error message that has me confused. Think about what is happening: The declaration tells the compiler how many items of what size to push on the stack. The name of the parameter is not important at all. The only point where you worry about the actual names is in the definition, because you have to address the actual arguments in some way (their names).

Declaring a function without stating the parameter names is common practice.
Every good solution is obvious once you've found it.
OZ

Re:extern c declarations

Post by OZ »

yeah, you're right that makes sense.
Just thought that at first sight, because actually I never saw that before and was used to 'normal' declarations with names.

The question is why I got an error then, but declaring without a name should be allowed for all declarations then not only extern, right? So it should have been not an issue that I didn't declare it as extern while testing?
Candamir

Re:extern c declarations

Post by Candamir »

For the isr - did you test it with division through zero and stuff like that before?
Actually, yes. But I'll test it again and then tell you.

By the way, should I initialise paging before the GDT and such things?

Candamir

EDIT: BTW, I did add the variable names in the extern declarations... I think the whole code becomes more readable.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:extern c declarations

Post by Solar »

Candamir wrote: BTW, I did add the variable names in the extern declarations... I think the whole code becomes more readable.
I wholeheartedly agree. ;-)
Every good solution is obvious once you've found it.
Candamir

Re:extern c declarations

Post by Candamir »

OK. Now I've got paging enabled. But can I use this directory for the kernel heap or also for user programs running?
Post Reply