Page 1 of 1
Using retf to flush GDT
Posted: Thu Jun 05, 2008 11:59 pm
by mduft
Hi folks
Just wanted to let everybody know this, since i've been trying quite some time until i got it to work: I'm developing a kernel using Visual C++ 2008 Express Edition, which works well. But when it came to reloading CS with the new GDT, i had a problem:
doesn't work in microsoft's assembler/compiler! i tried everything i could think of with jmp's but didn't succeed (i even thought about switching to GCC again
but since i know the PE/COFF specs very well, i'd like to stick with it). Still there _is_ a solution though it's a bit unesthetic:
Code: Select all
lgdt mygdt
push eax
mov eax, 0x08
push eax
mov eax, [reload]
push eax
retf
reload:
pop eax
note: loading all the other segment registers omitted to save some space
hope this helps somebody else out. Any comments?
Posted: Fri Jun 06, 2008 2:22 am
by Korona
GCC supports the PE file format, too.
You could also use a hack like this:
db 0xEA
dd reload
dw 0x8
Posted: Fri Jun 06, 2008 2:52 am
by skyking
I thought about this method as well (the reason being that I wanted to do an indirect jump instead), but chose not to since I think this exploits an undocumented behaviour in the CPU. During the retf the stack segment selector is being used which according to what I remember you shouldn't rely on the newly loaded segments registers until after the intersegment jump.
Posted: Fri Jun 06, 2008 7:23 am
by mduft
Korona wrote:GCC supports the PE file format, too.
You could also use a hack like this:
db 0xEA
dd reload
dw 0x8
i tried to do something like that, but i didn't manage. there is no db, dd, dw and such i just have "_emit()" which emits one byte. Now how could i emit the address of the label with that? i didn't manage
Re: Using retf to flush GDT
Posted: Fri Jun 06, 2008 8:31 am
by svdmeer
mduft wrote:Hi folks
doesn't work in microsoft's assembler/compiler! i tried everything i could think of with jmp's but didn't succeed (i even thought about switching to GCC again
but since i know the PE/COFF specs very well, i'd like to stick with it). Still there _is_ a solution though it's a bit unesthetic:
Maybe unesthetic, but not a problem to me if you want to use the software you have chosen.
Years ago I used a version of Tasm that couldn't make a fat jump with a normal jmp instruction. I put the raw opcodes in the file with 'db'. You can use that solution too if there is any posibility to put raw coode in your file. Since I switched to Nasm I don't have that kind of problems anymore.
Re: Using retf to flush GDT
Posted: Mon Jun 09, 2008 12:37 am
by mduft
svdmeer wrote:Years ago I used a version of Tasm that couldn't make a fat jump with a normal jmp instruction. I put the raw opcodes in the file with 'db'. You can use that solution too if there is any posibility to put raw coode in your file. Since I switched to Nasm I don't have that kind of problems anymore.
Yeah, the thing is, that i want to avoid using an external assembler, but rather implemented every piece i really require to be assembler as inline assembler in C (and maybe naked functions in some places, where i don't want them to have a prolog/epilog). This way i don't have to take care of external programs (i know ml.exe would have been with the MS compiler, but it doesn't make too much difference if i do inline assembler here...), and i have everything in a bunch of C files - I like it this way
The only drawback so far is, that i can emit only byte wise (ie. db) and not double word wise (which i would need for an address/label) - so i cannot direclty emit the jump target (also because i would need a relocation for the label, since at compile time i don't know the absolute address of course, and just emitting the label's address wouldn't generate a relocation. i think there is no far jump opcode which takes a rel32 offset, which would make it a bit easier)...
Re: Using retf to flush GDT
Posted: Mon Jun 09, 2008 12:48 am
by svdmeer
mduft wrote:
The only drawback so far is, that i can emit only byte wise (ie. db) and not double word wise (which i would need for an address/label) - so i cannot direclty emit the jump target (also because i would need a relocation for the label, since at compile time i don't know the absolute address of course, and just emitting the label's address wouldn't generate a relocation. i think there is no far jump opcode which takes a rel32 offset, which would make it a bit easier)...
If you can use db, you can use for example
db (segment / 256)
db (segment & 255)
or for example:
db label32 & 255
db (label32 / 256) & 255
db (label32 / (256*256)) & 255
db (label32 / (256*256*256)) & 255
(or use bitshifting, don't know which math operations with labels are supported by your assembler)
Re: Using retf to flush GDT
Posted: Mon Jun 09, 2008 1:00 am
by mduft
svdmeer wrote:
If you can use db, you can use for example
db (segment / 256)
db (segment & 255)
or for example:
db label32 & 255
db (label32 / 256) & 255
db (label32 / (256*256)) & 255
db (label32 / (256*256*256)) & 255
(or use bitshifting, don't know which math operations with labels are supported by your assembler)
thanks, i'll have to try this out! although i'm afraid this can't work in my setup. the __asm _emit(x) emits one byte to the .text section of the resulting binary. what would be emitted in this case if i put in the address? i guess it would be some junk, right? the whole thing would only make sense if the compiler knew that it was emitting an address, and generate a relocation for the linker to put in the real address. Otherwise there would be - i don't know - maybe some random bytes? or all zero? have to try.
thanks anyway
a solution different to retf would be better of course.
Re: Using retf to flush GDT
Posted: Mon Jun 09, 2008 1:14 am
by mduft
svdmeer wrote:
If you can use db, you can use for example
db (segment / 256)
db (segment & 255)
or for example:
db label32 & 255
db (label32 / 256) & 255
db (label32 / (256*256)) & 255
db (label32 / (256*256*256)) & 255
(or use bitshifting, don't know which math operations with labels are supported by your assembler)
it's the way i thought: i used this (EMIT_BYTE is a define to _emit()):
Code: Select all
EMIT_BYTE(0xEA);
EMIT_BYTE(reload & 255);
EMIT_BYTE((reload / 256) & 255);
EMIT_BYTE((reload / (256*256)) & 255);
EMIT_BYTE((reload / (256*256*256)) & 255);
EMIT_BYTE(SX_KERNEL_CODE_SELECTOR / 256);
EMIT_BYTE(SX_KERNEL_CODE_SELECTOR & 255);
and i get this:
Code: Select all
1>.\sxSegmentation.c(90) : error C2425: 'AND' : non-constant expression in 'first operand'
1>.\sxSegmentation.c(90) : error C2415: improper operand type
1>.\sxSegmentation.c(91) : error C2425: '/' : non-constant expression in 'first operand'
1>.\sxSegmentation.c(91) : error C2415: improper operand type
1>.\sxSegmentation.c(92) : error C2425: '/' : non-constant expression in 'first operand'
1>.\sxSegmentation.c(92) : error C2415: improper operand type
1>.\sxSegmentation.c(93) : error C2425: '/' : non-constant expression in 'first operand'
1>.\sxSegmentation.c(93) : error C2415: improper operand type
thanks anyway!