Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get starting address of a memory page in Linux

In my code, I need to keep track of some pages which are being modified. Initially I give only read access to them, but on the signal handler I give them both read and write access (I am not going to explain what is the purpose for all that and there is actually more code in the signal handler, which I've not shown).

Now my question is how to get the starting address of a page from a memory address which resides in that page. So basically I need to implement the get_page_start_addr shown here in the code. Up till now, I was only doing it for a single page, whose starting address my program knew. But now, since I need to do it for multiple pages, I need to get the starting address of the page from any arbitrary memory address, because mprotect only accepts starting page address as valid argument.

static void memory_change_handler(int sig, siginfo_t *si, void *unused)
{
  long addr = (long)si->si_addr;
  long page_start_addr = get_page_start_addr( addr );

  if (mprotect((void*)page_start_addr, pagesize, PROT_READ | PROT_WRITE) == -1)
  {
    print_error();
    handle_error("mprotect");
  }
}
like image 861
MetallicPriest Avatar asked Nov 18 '25 14:11

MetallicPriest


2 Answers

In Linux (in other OSes too, I guess), pages are aligned at page boundaries. Thus, if you know your PAGE_SIZE, then you can simply get the start of the page by masking the lower address bits.

page_start = addr & ~(PAGE_SIZE-1);
like image 162
Didier Trosset Avatar answered Nov 20 '25 05:11

Didier Trosset


To portably know your pagesize, use sysconf(_SC_PAGESIZE).

like image 30
ninjalj Avatar answered Nov 20 '25 04:11

ninjalj