Page fault when accessing global c++ object method

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
heavyweight87
Posts: 22
Joined: Sun Apr 28, 2019 7:39 am

Page fault when accessing global c++ object method

Post by heavyweight87 »

Hi,

I have an issue with kernel space c++ objects that are global i.e. declared at the top of the file.
When I access a method inside the object, a call to another method causes a page fault.
The pagefault error code is 0 and CR2 is something that it shouldnt be which is definately not mapped, which is probably why the page fault happens.

The strange thing is that if the object is delacred inside a function (even as static) then it works great.
reating the object dynamically using new also works fine.

I followed the gudie here https://wiki.osdev.org/C%2B%2B#Introduction
The fact that its only global objects is some kind of hint but im not sure what exactly it could be

Can anyone point me in the right direction on what im missing?

Thanks
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: Page fault when accessing global c++ object method

Post by kzinti »

An object declared in a function will be stored on the stack. Thus its memory will most likely be mapped.

An object declared globally will be stored somewhere else (BSS or DATA section). Check where that object is in your binary image (make sure it exists) and see where it is loaded.
Last edited by kzinti on Fri Jul 17, 2020 11:02 am, edited 1 time in total.
heavyweight87
Posts: 22
Joined: Sun Apr 28, 2019 7:39 am

Re: Page fault when accessing global c++ object method

Post by heavyweight87 »

I've identity mapped the entire kernel space according to the multiboot structure so it shouldnt't be a probme.
I also checked with qemu using tbl command and the page is mapped to the same address in physical memory

The problem is that one method calls another, which then causes the page fault.
The first method that is caused sits very close to the method that causes the page fault - they are in the same page.
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: Page fault when accessing global c++ object method

Post by kzinti »

Where/when/did you call the constructor for that global object? Perhaps you are crashing when trying to call a virtual function...

Using a C++ object that is not properly initialized is undefined behaviour.
heavyweight87
Posts: 22
Joined: Sun Apr 28, 2019 7:39 am

Re: Page fault when accessing global c++ object method

Post by heavyweight87 »

Ah how stupid of me the particular object that was causing the problem is declared as virtual.
Thanks for giving me a nudge in the right direction

The object is declared as a global so if I understand correctly the constructor should be called before my kernel main?

I can see that when its declared globally the constructor doesn't get called

I guess im missing something...
nullplan
Member
Member
Posts: 1917
Joined: Wed Aug 30, 2017 8:24 am

Re: Page fault when accessing global c++ object method

Post by nullplan »

Normally, ELF constructors are run by the ELF loader (if you are using ELF, that is). However, in case of a kernel, that doesn't happen. The bootloader usually dumps your binary into memory, and then maybe clears BSS, and then that's your lot, then it jumps to your start symbol. If you do require constructors to run, you have to call them yourself. I'm going to continue guessing you use ELF, as I have no idea how exactly this works for PE. You can run all constructors just by running this code:

Code: Select all

extern void (*__init_array_start[])(void) __attribute__((weak));
extern void (*__init_array_end[])(void) __attribute__((weak));
static void dummy(void) {}
extern void _init(void) __attribute((weak, alias("dummy")));

void run_constructors(void) {
  for (void (**it)(void) = __init_array_start; (uintptr_t)it < (uintptr_t)__init_array_end; it++)
    (*it)();
  _init();
}
Since I literally just came up with this code, you might want to check it for bugs. All these symbols should be declared by the linker. If you ever switch to a higher-half memory model, you can only run this code after the switching on paging. As for the constructors themselves, those are emitted by the compiler.
Carpe diem!
heavyweight87
Posts: 22
Joined: Sun Apr 28, 2019 7:39 am

Re: Page fault when accessing global c++ object method

Post by heavyweight87 »

Thanks its now working...that was pretty painless. BTW...can I add the below code to the wiki? Is it editable by anyone?
I had to use nullplans answer with some stuff on the wiki. It explains a bit in https://wiki.osdev.org/index.php?title= ... ldid=14651 how to do it

Add this to your linker

Code: Select all

.rodata ALIGN(0x1000) :
    {
        start_ctors = .;
        *(SORT(.ctors*))  /* Note the "SORT" */
        end_ctors = .;

        start_dtors = .;
        *(SORT(.dtors*))
        end_dtors = .;

        *(.rodata*)
        *(.gnu.linkonce.r*)
    }
Then somewhere in your main you can call

Code: Select all


extern void (*start_ctors)(void) __attribute__((weak));
extern void (*end_ctors)(void) __attribute__((weak));

// Constructor list is defined in the linker script.
// The .ctors section is just an array of function pointers.
// iterate through, calling each in turn.
uintptr_t *iterator = reinterpret_cast<uintptr_t*>(&start_ctors);
while (iterator < reinterpret_cast<uintptr_t*>(&end_ctors))
 {
    void (*fp)(void) = reinterpret_cast<void (*)(void)>(*iterator);
    fp();
    iterator++;
 }
Post Reply