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.
I'm porting my kernel to x64. In protected mode I used to use C++ features like constructors, virtual methods, exceptions. However in long mode I'm having a problem calling a constructor in the libsupc++.a library, particularly in the eh_alloc.o object file. All the others constructors are executed correctly. Disassembling the code which is going to be executed I found this in the first instructions of the constructor:
Bochs stops at the second one (mov rax, fs:0x28). As far as I read on the wiki, the FS register can't be used in a legacy way, so I didn't bother initializing it among the other segment registers, and it still contains it's protected mode setup, pointing to a data segment from 0x00000000 to 0xffffffff. Why is this eh_alloc.o code using that register? Am I missing something? Should I initialize the register in a particular way?
Thanks...
Please, correct my English...
Motherboard: ASUS Rampage II Extreme
CPU: Core i7 950 @ 3.06 GHz OC at 3.6 GHz
RAM: 4 GB 1600 MHz DDR3
Video: nVidia GeForce 210 GTS... it sucks...
AFAIK, GCC assumes all segment registers being initialized to flat memory mode. I don't know why this specific constructor uses the FS register, but with the above assumption I'd think the GCC maintainers felt safe in doing so.
Every good solution is obvious once you've found it.
GCC only expects DS=ES=SS; FS/GS were the only segmentation registers kept in long mode for thread-local storage purposes. They even added a SWAPGS instruction for convenience.
Since the operand is [FS:low_number], use of TLS seems most likely here. (and setting it FS.base to zero will consequently crash anything that expects TLS to be implemented)
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Just a reminder why you don't want to reuse host toolchains
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
I wasn't successful at compiling libsupc++ and I read that using the host one would have worked. So I end up using the whole toolchain, from compilers to linkers and libraries
Please, correct my English...
Motherboard: ASUS Rampage II Extreme
CPU: Core i7 950 @ 3.06 GHz OC at 3.6 GHz
RAM: 4 GB 1600 MHz DDR3
Video: nVidia GeForce 210 GTS... it sucks...
//Alloc a page
void *tls = valloc(4096);
WriteMsr(0xC0001000, (uint64_t) tls);
The constructor now works as fs is pointing to valid memory.
I don't know if this will cause me problems, but actually it seems to work. I still didn't test exceptions..
Edit:
Exceptions don't work. Exploring the disassembly I found that __cxa_throw_exceptions calls __cxa_get_globals which takes a 64bit pointer at fs:0x0, then decreases it by 16, and since it's 0 it becomes the invalid pointer 0xFFFFFFFFFFF0. Looking in the libsupc++ source code, which now I MUST get to compile, I see preprocessors instructions like "#if _GLIBCXX_HAVE_TLS". I think a compilation is needed unless someone is able to point out how TLS works...
Please, correct my English...
Motherboard: ASUS Rampage II Extreme
CPU: Core i7 950 @ 3.06 GHz OC at 3.6 GHz
RAM: 4 GB 1600 MHz DDR3
Video: nVidia GeForce 210 GTS... it sucks...
Well at this point I have three choices:
1) Remove libsupc++ and say godbye to exceptions
2) Compile or find a 64bit libsupc++ that won't use TLS (if someone is able to provide me one that would be great). But I have to say godbye to multithreading in the kernel
3) Add support for TLS in ELF in the Kernel loader and make everyone happy. Quite difficoult though...
Please, correct my English...
Motherboard: ASUS Rampage II Extreme
CPU: Core i7 950 @ 3.06 GHz OC at 3.6 GHz
RAM: 4 GB 1600 MHz DDR3
Video: nVidia GeForce 210 GTS... it sucks...
For TLS in IA-32, there was need for a register which stored the location of a thread pointer which was specific to each thread. Various data is accessed at positive and negative indices from this pointer. Due to the limited number of GPRs in the IA32 architecture, the GS register was chosen. GS is loaded with a segment which has its base at the address of the thread pointer (so that gs:0x0 is the address of the thread pointer) and a limit of 0xffffffff so that you can access gs:-0x4 without problems.
In x86_64, the mechanism is essentially the same, except that FS is used instead of GS.
The entire mechanism for setting up the TLS structures is specified in the document 'ELF Handling For Thread-Local Storage' as previously mentioned.