Page 1 of 2
Purpose of eh_frame section?
Posted: Mon Jan 28, 2019 3:00 pm
by DevNoteHQ
Hi guys!
I had a problem switching from mapping the whole memory to mapping the sections that i provide by linker-symboles.
When calling some functions under certain circumstances, i got a triple-fault.
Then i looked through my section-sizes and found that there were like 0x2000 missing between .rodata and .bss.
So i did an objdump -h of my kernel and found three extra sections: .eh_frame, .rodata.str1.1 and .rodata.str1.8
I added them to .rodata like so:
Code: Select all
.rodata ALIGN(0x1000) : AT(ADDR(.rodata) - HVMA)
{
_rodata_start = .;
*(.rodata)
*(.eh_frame)
*(.rodata.str1.1)
*(.rodata.str1.8)
_rodata_end = .;
}
Now i read online that .eh_frame contains stuff like C++ Exception-Handling. So .eh_frame needs to go to .text?
And what are the other two .rodata-sections?
Thanks for your help!
EDIT: And why do i get a triple-fault when adding the NX-Bit to .data and .bss?
EDIT2: I think i found the problem for .data... I'm calling start_dtors in the .data-section, aren't i?
For reference, the whole linker-file:
Code: Select all
OUTPUT_FORMAT(elf64-x86-64)
ENTRY(start)
HVMA = 0xFFFFFF0000000000;
SECTIONS
{
. = 1M;
_start = . + HVMA;
_bin_start = . + HVMA;
.init :
{
*(.initl)
}
. += HVMA;
.text ALIGN(0x1000) : AT(ADDR(.text) - HVMA)
{
*(.inith)
*(.text)
}
_bin_end = .;
.data ALIGN(0x1000) : AT(ADDR(.data) - HVMA)
{
_data_start = .;
start_ctors = .;
*(.ctor*)
end_ctors = .;
start_dtors = .;
*(.dtor*)
end_dtors = .;
*(.data)
_data_end = .;
}
.rodata ALIGN(0x1000) : AT(ADDR(.rodata) - HVMA)
{
_rodata_start = .;
*(.rodata)
*(.eh_frame)
*(.rodata.str1.1)
*(.rodata.str1.8)
_rodata_end = .;
}
.bss ALIGN(0x1000) : AT(ADDR(.bss) - HVMA)
{
_bss_start = .;
*(COMMON)
*(.bss)
_bss_end = .;
}
_end = .;
}
Re: Purpose of eh_frame section?
Posted: Tue Jan 29, 2019 1:51 pm
by nullplan
First of all, might I suggest moving the .rodata section behind the .text section? This would allow the linker to create a single non-writable segment in the output file (and then a single non-executable one). Makes for easier loading, is all.
Second, compilers sometimes add things to the ends of section names. Which you took care of in the ctors sections but not anywhere else.
So, your linker script needs stuff like
Code: Select all
.text : {
*(.inith)
*(.text)
*(.text.*)
}
Why do you always go for page alignment? That's unnecessary except for the break between code and data.
And finally, .eh_frame is indeed for exception handling. However, unless you are using C++, and have a lib capable of handling exceptions, you can just discard it. It is data, and usually read-only as well. Basically contains an exception table.
Re: Purpose of eh_frame section?
Posted: Tue Jan 29, 2019 3:05 pm
by DevNoteHQ
Yeah i saw that on the "Creating a 64-bit kernel"-Tutorial. In the "Bare Bones"-Tutorial they put .rodata in a seperate section, which is probably why i did that too. Is that because of the old section-system in the gdt?
I thought it would be a security-issue to put .rodata into .text because you could then execute stuff in .rodata, but i mean what would execute some random non-writable data do for a potential hacker?
Is it also enough to just add the * after each section without the dot? I did something like this for everything and it seems to work just fine:
Code: Select all
.text ALIGN(0x1000) : AT(ADDR(.text) - HVMA)
{
*(.inith)
*(.text*)
*(.eh_frame)
*(.rodata*)
}
That would make sence, will do
Well my current issue is that i can add the NX-Bit to .data, but not to .bss; Does .bss also contain function-pointers? Because i do call function-pointers sometimes...
So i could just put .bss and COMMON into .data if i get the NX-Bit to work?
Yeah I'm writing in C++, but i don't have a lib for exception-handling (yet). Would those be the unwind-libs?
To further simplify my linker-script: Can i put . += HVMA into .text between .initl and .inith? So that i could delete the seperate .init-section?
EDIT: Or do assembly-portions end up in .bss if you don't specify a section?
Re: Purpose of eh_frame section?
Posted: Wed Jan 30, 2019 3:23 am
by tabz
DevNoteHQ wrote:
Yeah I'm writing in C++, but i don't have a lib for exception-handling (yet). Would those be the unwind-libs?
Yeah the unwinder is the part of your runtime that finds the appropriate exception handler for an exception when it's thrown.
Re: Purpose of eh_frame section?
Posted: Wed Jan 30, 2019 8:28 am
by DevNoteHQ
tabz wrote:Yeah the unwinder is the part of your runtime that finds the appropriate exception handler for an exception when it's thrown.
But i would need to support C++-Exceptions in my ISRs too, don't I?
Re: Purpose of eh_frame section?
Posted: Wed Jan 30, 2019 12:05 pm
by nullplan
DevNoteHQ wrote:But i would need to support C++-Exceptions in my ISRs too, don't I?
If you were to use exceptions, take good care not to throw anything into the assembly code. I mean, what would be the meaning of throwing an exception out of an ISR? That would be an error. And while throwing out of a syscall arguably has a meaning, there is no ABI for exception unwinding through a context switch. Nor is one simple to create.
So, no, your assembly stubs to enter the C++ code would not need to support exceptions, as long as that C++ code ensures no exceptions ever reach the assembly code.
Alternatively, you can study the Itanium ABI to generate an exception trampoline for all your assembly stubs. Which seems a lot of work for something so easily prevented.
Re: Purpose of eh_frame section?
Posted: Wed Jan 30, 2019 12:16 pm
by DevNoteHQ
nullplan wrote:If you were to use exceptions, take good care not to throw anything into the assembly code. I mean, what would be the meaning of throwing an exception out of an ISR? That would be an error. And while throwing out of a syscall arguably has a meaning, there is no ABI for exception unwinding through a context switch. Nor is one simple to create.
So, no, your assembly stubs to enter the C++ code would not need to support exceptions, as long as that C++ code ensures no exceptions ever reach the assembly code.
Alternatively, you can study the Itanium ABI to generate an exception trampoline for all your assembly stubs. Which seems a lot of work for something so easily prevented.
No i meant for example that when i cause a "divide-by-zero" fault i need to forward it from the ISR to the exception-handler, don't i?
Re: Purpose of eh_frame section?
Posted: Wed Jan 30, 2019 12:47 pm
by Korona
nullplan wrote:DevNoteHQ wrote:But i would need to support C++-Exceptions in my ISRs too, don't I?
If you were to use exceptions, take good care not to throw anything into the assembly code. I mean, what would be the meaning of throwing an exception out of an ISR? That would be an error. And while throwing out of a syscall arguably has a meaning, there is no ABI for exception unwinding through a context switch. Nor is one simple to create.
That is not quite true - you can add CFI directives to allow throwing exceptions through stack switches (e.g. iret, if you know that the interrupted stack also belongs to the kernel). Not that it's a good idea, but it is certainly possible. I considered doing this to generate EFAULT in the kernel (together with -fnon-call-exceptions). This method works but has other problems (like producing a lot of bloat in the exception tables).
Re: Purpose of eh_frame section?
Posted: Wed Jan 30, 2019 1:28 pm
by tabz
DevNoteHQ wrote:nullplan wrote:If you were to use exceptions, take good care not to throw anything into the assembly code. I mean, what would be the meaning of throwing an exception out of an ISR? That would be an error. And while throwing out of a syscall arguably has a meaning, there is no ABI for exception unwinding through a context switch. Nor is one simple to create.
So, no, your assembly stubs to enter the C++ code would not need to support exceptions, as long as that C++ code ensures no exceptions ever reach the assembly code.
Alternatively, you can study the Itanium ABI to generate an exception trampoline for all your assembly stubs. Which seems a lot of work for something so easily prevented.
No i meant for example that when i cause a "divide-by-zero" fault i need to forward it from the ISR to the exception-handler, don't i?
I think we're a bit confused by the term exception. By "exception", I mean a C++ exception that is thrown with a "throw" statement and caught in a "try { ... } catch(...) { ... }". These (AFAIK) are entirely managed by the C++ runtime and don't touch your ISRs. Your ISRs receive CPU exceptions which are different to C++ exceptions. Someone can correct me if I'm wrong.
Re: Purpose of eh_frame section?
Posted: Wed Jan 30, 2019 2:53 pm
by DevNoteHQ
tabz wrote:I think we're a bit confused by the term exception. By "exception", I mean a C++ exception that is thrown with a "throw" statement and caught in a "try { ... } catch(...) { ... }". These (AFAIK) are entirely managed by the C++ runtime and don't touch your ISRs. Your ISRs receive CPU exceptions which are different to C++ exceptions. Someone can correct me if I'm wrong.
Well I thought that they would be handled through the ISRs. So what kind of exceptions are handled by the C++ runtime? Coming from C# I find it difficult to differentiate language features. So for example if you declare a new object in C#, but don't give it a address through 'new', you would get an exception by the .net-Framework if you try to use it. But that seems impossible in C++ without ISR-Support?
EDIT: But my most important question remains: Why can't i disable execution of instructions in my .bss-Section?
Re: Purpose of eh_frame section?
Posted: Thu Jan 31, 2019 9:22 am
by nullplan
DevNoteHQ wrote:Well I thought that they would be handled through the ISRs. So what kind of exceptions are handled by the C++ runtime? Coming from C# I find it difficult to differentiate language features. So for example if you declare a new object in C#, but don't give it a address through 'new', you would get an exception by the .net-Framework if you try to use it. But that seems impossible in C++ without ISR-Support?
I presume this is because C# initializes all uninitialized variables to NULL, and accessing that causes a fault.
C++ exception handling is, as has been stated, about C++ exceptions, i.e. whatever happens if a function notices it cannot deliver on its promises and executes a throw statement. CPU exceptions are something entirely different. You could try to throw out of an exception handler, sure, but I'm not sure if the ABI allows that. Alternatively you could try to bend the return IP to a function that throws, but I'm not sure if that works, either. Frankly, I don't use C++ in kernel space. If I have a fault in kernel space, I have my own exception tables to handle them. If that doesn't work, there is only the panic() function.
EDIT: But my most important question remains: Why can't i disable execution of instructions in my .bss-Section?
What are you trying to execute there? If it is the ctors list, then you are probably doing it wrong. Inspect those sections yourself, but aren't those usually just lists of pointers to functions? In that case you should execute the pointed-to functions, not the list.
Re: Purpose of eh_frame section?
Posted: Thu Jan 31, 2019 12:35 pm
by DevNoteHQ
nullplan wrote:I presume this is because C# initializes all uninitialized variables to NULL, and accessing that causes a fault.
C++ exception handling is, as has been stated, about C++ exceptions, i.e. whatever happens if a function notices it cannot deliver on its promises and executes a throw statement. CPU exceptions are something entirely different. You could try to throw out of an exception handler, sure, but I'm not sure if the ABI allows that. Alternatively you could try to bend the return IP to a function that throws, but I'm not sure if that works, either. Frankly, I don't use C++ in kernel space. If I have a fault in kernel space, I have my own exception tables to handle them. If that doesn't work, there is only the panic() function.
Oh okay. Was just a bit confused by languages
nullplan wrote:What are you trying to execute there? If it is the ctors list, then you are probably doing it wrong. Inspect those sections yourself, but aren't those usually just lists of pointers to functions? In that case you should execute the pointed-to functions, not the list.
Well the ctors list is in .data, which works just fine with the NX-Bit. As far as I'm aware, I don't use any function pointers except in my simple keyboard-driver. But i guess debugging it with the NX-Bit set would probably answer some questions...
Re: Purpose of eh_frame section?
Posted: Thu Jan 31, 2019 2:09 pm
by kzinti
DevNoteHQ wrote:Well the ctors list is in .data, which works just fine with the NX-Bit. As far as I'm aware, I don't use any function pointers except in my simple keyboard-driver. But i guess debugging it with the NX-Bit set would probably answer some questions...
It doesn't matter if the function pointers are in an NX-protected page in the data section. Pointers are not executed, the functions that they point to are. The functions themselves need to be in non-NX pages.
Re: Purpose of eh_frame section?
Posted: Fri Feb 01, 2019 4:16 am
by DevNoteHQ
kzinti wrote:It doesn't matter if the function pointers are in an NX-protected page in the data section. Pointers are not executed, the functions that they point to are. The functions themselves need to be in non-NX pages.
Yeah thats clear, but how would i put a function into the .bss section in C/C++? Because I'm pretty sure i don't have a assembly file with section .bss except the bootup-code, where I create the stack in .bss... So there shouldn't be a single function outside .text...
Re: Purpose of eh_frame section?
Posted: Fri Feb 01, 2019 4:48 am
by xenos
Have you had a look at running objdump on your output file? What does your .bss section contain? What is at the address from which you get the fault when NX is enabled? Is that address in the .bss section?