Page 1 of 1
C functions and far pointers
Posted: Fri Feb 15, 2008 9:07 am
by dumaisp
Hi,
When compiling a c function such as:
void test(){
char* buf = 0x0000B800;
int *n;
}
the code generated uses the segment register "ds" to access to these buffers. But what if the descriptor used by "ds" cannot access 0xB800 (physical)? I would like the compiler to use "es" when accessing "buf" and "ds" when accessing "n".
Does anyone have a suggestion for such a situation? is there a way to create a far pointer for buf like 0x0010:0x0000B800 (0x0010 corresponding to the third descriptor in the GDT)
Thank you,
Patrick dumais
Posted: Fri Feb 15, 2008 9:11 am
by AJ
Hi,
What compiler are you using? If it is GCC, I think the answer is no, because GCC assumes a non-segmented (flat) memory model. Of course, you could write all your functions that use different segments in assembly, but that will be a pain in the arse.
There may be compilers about which will allow segmentation. Have you got any good reason to be using this memory model specifically?
Cheers,
Adam
Posted: Fri Feb 15, 2008 9:12 am
by 01000101
I'm probably wrong, but, wouldn't you have to flush the GDT by reloading the segment registers with the segment descriptor of choice (0x10, etc) and then perform a far jump to hard-code that into the descriptors? then you could use that descriptor.
Posted: Fri Feb 15, 2008 9:19 am
by AJ
No, as long as you are changing selector to the same or a higher DPL, you can simply change the descriptor and use it. You only have to far jump when you first enter PMode or do an LGDT to clear the old instruction pipe.
The only way to change CS, however is via a far instruction transfer (JMP/CALL/RET etc..).
Cheers,
Adam
Posted: Fri Feb 15, 2008 9:43 am
by dumaisp
Yes, I am using GCC.
Well the reason I wanted to do that is because everyone keeps telling to start writing in C instead of using assembly language. I guess I have one more reason not to use C for coding my kernel.
The function I was trying to code was a printf() function to use in my kernel (for debug purposes). I guess I'll have to write every of those in asm. Unless my conception is wrong and that there would be a way to use the correct descriptor with "ds". I'll look into it.
Thank you for the fast replies.
Posted: Fri Feb 15, 2008 10:42 am
by AJ
Hi,
'Everyone keeps telling me to use C' is not the best reason I have heard to use C. If you are more comfortable with ASM, by all means use ASM - as long as it fits in with your design goals.
If one of your goals is portability, however, stick with a higher level language. Note that by relying on segmentation, you are instantly reducing ease of portability anyway.
If your goal is an IA-32 OS which is never going to support 64 bit modes, you may as well use your most proficient language.
Cheers
Adam
Odd thing then
Posted: Sun Feb 17, 2008 5:23 pm
by dumaisp
Something is odd then.
if I compile:
...
d++;
if (d==1){
}
....
it gives me something like:
9a: 8d 45 fc lea 0xfffffffc(%ebp),%eax
9d: ff 00 incl (%eax)
a1: 83 7d fc 01 cmpl $0x1,0xfffffffc(%ebp)
but that is wrong! the second instruction uses "ds" as the default segment register, and the third uses "ss".
ss and ds are not the same, and they shouldn't be! does this mean that gcc assumes that all segment registers are the same? there is no way I can use intel's segmentation mechanism in C with gcc?
Posted: Sun Feb 17, 2008 5:52 pm
by pcmattman
GCC requires the flat memory model, so DS=ES=FS=GS=SS. These segments should have a base of 0 and a 4 GB limit too.
Posted: Sun Feb 17, 2008 6:01 pm
by dumaisp
This is shocking. isn't segmentation a good thing?
I would like to use the benefits of having a stack segment that has a limit. And an exception would be raised if an overflow would occur so I could handle it before overwriting important data
is there another compiler in linux that I could use for this?
Posted: Sun Feb 17, 2008 6:39 pm
by iammisc
segmentation can be a good thing but it reduces portability. GCC is supposed to be a portable compiler and really has no business doing anything so platform-specific as segmentation.
I personally protect my stack by leaving non-present pages around the stack.
Posted: Mon Feb 18, 2008 5:44 am
by JamesM
dumaisp wrote:This is shocking. isn't segmentation a good thing?
I would like to use the benefits of having a stack segment that has a limit. And an exception would be raised if an overflow would occur so I could handle it before overwriting important data
is there another compiler in linux that I could use for this?
While it may be "shocking", it does allow for many perfomance hints and optimisations.
Unfortunately C was designed to *abstract away* low level details, so as to enable easy porting cross-platform. Therefore, GCC treats all segments as equal, and assumes a linear address space. What you do with these linear addresses to convert them to physical addresses (paging/segmentation) is up to you.
Segmentation is really deprecated as a form of memory protection. 64-bit long mode assumes a flat memory model, so segmentation is pretty much useless there (except for switching ring levels).
Posted: Mon Feb 18, 2008 6:51 am
by Ready4Dis
dumaisp wrote:Yes, I am using GCC.
Well the reason I wanted to do that is because everyone keeps telling to start writing in C instead of using assembly language. I guess I have one more reason not to use C for coding my kernel.
The function I was trying to code was a printf() function to use in my kernel (for debug purposes). I guess I'll have to write every of those in asm. Unless my conception is wrong and that there would be a way to use the correct descriptor with "ds". I'll look into it.
Thank you for the fast replies.
So, what do you need multiple segments to write a printf function for? If you want protection and exceptions to be raised if an application leaves it's area, use paging. Anyways, to write a printf function in C is very easy, the hardest part is figuring out the multiple parameters, which isn't really that hard. Segmentation isn't suppoted by many cpu's outisde the x86 family, so if you're using C for portability, you pretty much kill portability by using segmentation. A flat memory model is much simpler to work on, since accessing all variables is identical, a lot of optimizations can take place.
Posted: Mon Feb 18, 2008 8:53 am
by Solar
dumaisp wrote:is there another compiler in linux that I could use for this?
There have been very few C compilers
at all that allow for a segmented memory model, simply because the language C has no room for segment-related stuff. Consider comparing pointers that have the same value, but in different segments - C has no primitives for a case like this, it would require sweeping changes in the compiler core.
Anything to do with segments is, basically, an incompatible extension of the language. You'd no longer write C (portable, generic, well-understood by many a developer), you would write C-with-segments.
That being said, I don't know of a segment-supporting Linux compiler (which might be because memory under Linux isn't segmented). IMHO, segmentation
might have been a nice idea at its time, but passed into history over a decade ago.
Posted: Mon Feb 18, 2008 11:31 am
by Combuster
pcmattman wrote:GCC requires the flat memory model, so DS=ES=FS=GS=SS. These segments should have a base of 0 and a 4 GB limit too.
The only assumption is that DS, ES and SS map to the same memory (for position-independent code, you have to be careful about CS too). You can very well have segments smaller than 4GB as long as you link all the addresses to low enough values. FS and GS are commonly used
because they don't necessarily point to the same location as DS, ES, etc (look up thread-local storage)